Stochastic Superoptimization [pdf]
theory.stanford.edu
theory.stanford.edu
We formulate the loop-free binary superoptimization task as a stochastic search problem. The competing constraints of transformation correctness and performance improvement are encoded as terms in a cost function, and a Markov Chain Monte Carlo sampler is used to rapidly explore the space of all possible programs to find one that is an optimization of a given target program. Although our method sacrifices completeness, the scope of programs we are able to consider, and the resulting quality of the programs that we produce, far exceed those of existing superoptimizers. Beginning from binaries compiled by llvm -O0 for 64-bit x86, our prototype implementation, STOKE, is able to produce programs which either match or outperform the code produced by gcc -O3, icc -O3, and in some cases, expert handwritten assembly.
http://blog.regehr.org/archives/923
edit: oops, the above link describes what a stochastic-superoptimizer is. however, if you read through the whole thing, it may give an inkling what the authors have done...
That said, their approach does not actually give you the superoptimal solution, since it is a stochastic search.
(Obviously search and sampling problems have different definitions.)
This seems unlikely to me. The Metropolis algorithm is just simulated annealing with a constant temperature. Which means that simulated annealing includes Metropolis MCMC as a special case.
Also, while simulated annealing is guaranteed to find the global optimum given infinite time (almost sure convergence), I'm not aware of any such guarantees for Metropolis.
Where do you see that? Searching the document for "annealing" brings up 0 results. They don't do a comparison with hill climbing either.
Also, from a technical point of view, it seems like they started out with an optimization problem on a hard domain, and then made their problem even harder by using a sampling algorithm with stochastic moves (i.e., MCMC). The particular usefulness of MCMC is sampling, not optimization, and for this problem, you don't really want to sample.
Like I said, I've used MCMC for loosely-structured inference problems (but more structured than the one treated in the paper). I was doing MAP estimation (i.e., maximizing the objective function), just as in the paper.
When speaking about my work, I was once asked "Why MCMC on such a hard problem if you're really just maximizing?" It's still a good question.
This is why it is important that the code is loop free, because otherwise you couldn't use SMT and essentially would have to solve the halting problem. However, SMT, like SAT, is a NP-complete problem, but the good thing is that in most cases (according to the paper) solving the SMT problems generated is quick as they weren't designed to be diabolical.
[1] http://en.wikipedia.org/wiki/Satisfiability_Modulo_Theories
[1]: http://en.wikipedia.org/wiki/Verification_and_validation_(so...
It's interesting to observe that "brute force" approaches to optimisation are yielding very good results, but I've always believed (and in this case, the "in some cases, expert handwritten assembly" phrase somewhat seems to support this) that making compilers more intelligent is the way to go -- make them "think" more like a human Asm programmer would.
For example, using their first sequence, 3 out of 11 instructions are moves that do nothing more than unproductive "register shuffling", which suggests to me that there's still room for improvement. As the saying goes, "the fastest way to do something is to not do it at all." That shuffling is only there because they constrained their register usage, and if I was implementing this, I'd arrange the code that came before such that the right operands are naturally in the right registers when instructions that require them e.g. mul are used. To my knowledge, this technique is not implemented in any compiler and none of the existing research on register allocation or optimisation mentions anything like that; instead they all seem to suggest "introduce extra moves and hope we can somehow remove them"... which doesn't work as well as planning ahead so you don't ever need them in the first place. Moves should only be used for making copies of values, since instructions that do other operations can implicitly "move" data as part of their operation anyway. Applying this principle to their first example eliminates two moves and yields this sequence:
shlq 32, rcx
movl edx, eax <-- move + zero-extend
xorq rcx, rax <-- why xor? or probably works too
mulq rsi
addq r8, rdi
adcq 0, rdx
addq rax, rdi <-- we want result in rdi anyway
adcq 0, rdx
movq rdx, r8 <-- this is still "room for improvement"
I think the same goes for optimisation as a separate pass - the idea of generating horribly inefficient code (gcc -O0 is a great example) and then trying to optimise it just doesn't make much sense to me; in my mind, if I tell a compiler to do max size or speed optimisation, it should be selecting and generating instructions that are pretty close to optimal already. I wonder if this is a result of that famous "premature optimisation" quote..."Fastest" is also something that can be highly dependent on the processor model, so this is also important to keep in mind if you're compiling on one machine but executing on another. If anyone would like to, I'd be really interested in seeing the performance of my two-moves-less sequence above vs the one in the paper (don't have a 64-bit machine to test this on at the moment.)
Given that STOKE takes tens of minutes to optimize a couple dozen lines of assembly, you probably wouldn't want to include it as a general compiler optimization. If you want the performance badly enough to use this tool, you are probably willing to run a profiler to find the hotspots and focus the tool on those specifically (which is how this tool is meant to be run).
That said, there are alternatives which are able to run at closer to normal compiler speeds, such as the peephole superoptimizer:
http://theory.stanford.edu/~aiken/publications/papers/osdi08...