Stoke
STOKE: A stochastic superoptimizer and program synthesizer
Install / Use
/learn @StanfordPL/StokeREADME
STOKE
STOKE is a stochastic optimizer and program synthesizer for the x86-64 instruction set. STOKE uses random search to explore the extremely high-dimensional space of all possible program transformations. Although any one random transformation is unlikely to produce a code sequence that is desirable, the repeated application of millions of transformations is sufficient to produce novel and non-obvious code sequences. STOKE can be used in many different scenarios, such as optimizing code for performance or size, synthesizing an implementation from scratch or to trade accuracy of floating point computations for performance. As a superoptimizer, STOKE has been shown to outperform the code produced by general-purpose and domain-specific compilers, and in some cases expert hand-written code.
In addition to searching over programs, STOKE contains verification infrastructure to show the equivalence between x86-64 programs. STOKE can consider test-cases, perform bounded verification all the way to fully formal verification that shows the equivalence for all possible inputs.
STOKE has appeared in a number of publications. For a thorough introduction to the design of STOKE, see:
- Stochastic Superoptimization -- ASPLOS 2013
- Data-Driven Equivalence Checking -- OOPSLA 2013
- Stochastic Optimization of Floating-Point Programs with Tunable Precision -- PLDI 2014
- Conditionally Correct Superoptimization -- OOPSLA 2015
- Stochastic Program Optimization -- CACM 2016
- Stratified Synthesis: Automatically Learning the x86-64 Instruction Set -- PLDI 2016
- Sound Loop Superoptimization for Google Native Client -- ASPLOS 2017
- A Complete Formal Semantics of x86-64 User-Level Instruction Set Architecture -- PLDI 2019
Additionally, the work Semantic Program Alignment for Equivalence Checking (PLDI 2019), was developed from this codebase. The fork is available here.
Status of this Work
STOKE isn't production ready. It's a research prototype that demonstrates the viability of superoptimization techniques in various domains. It's not a general-purpose tool. The papers above describe specific areas where successes have been shown beyond the state of the art: in optimizing straight line code, code where correctness can be relaxed (e.g. floating point), synthesizing sematic specifications for an instruction set, and in optimizing code containing loops with special compilation requirements (e.g. Google Native Client). We're not quite at the point where we can take a generic loop and expect to improve gcc/llvm -O3 code. In part, this is because these compilers have decades of work behind them to make them really great.
At this point, nobody is actively working on this code base. This repository now serves as an artifact for several of the above research papers. We will accept pull requests and answer inquiries as time permits.
Table of Contents
- Hardware Prerequisites
- Using Docker
- Downloading and Building STOKE
- Using STOKE
- Additional Features
- User FAQ
- Developer FAQ
- Extending STOKE
- Contact
Hardware Prerequisites
STOKE will run on modern 64-bit x86 processors. It will run best on Haswell or newer machines, but it can also run okay on Sandy Bridge. With Sandy Bridge processors, there won't be support for AVX2 instructions.
It should run on newer architectures, but we haven't tested it. However, stoke only supports a subset of instructions that were widely available when it was initially developed. As a result, targets generated by newer compilers might not work with STOKE. (Adding support for an instruction mostly involves adding a spreadsheet entry in the x64asm project, and optionally adding validator support).
Using Docker
STOKE has many dependencies and we think the best way to get up-and-running with a development environment is to use docker. Simply:
$ sudo docker pull stanfordpl/stoke:latest
These docker images run an SSH server. We recommend starting the image like so:
$ sudo docker run -d -P --name stoke stanfordpl/stoke:ARCH
then one can SSH as follows:
$ sudo docker port stoke 22
0.0.0.0:XXXXX
$ ssh -pXXXXX stoke@127.0.0.1
(password is 'stoke')
./configure.sh
make
Note that there are other docker images from other travis-ci builds available in the stanfordpl/stoke-test repository. These should be available for recent branches and pull requests, for example.
You can build your own docker images by running docker build . in
the top level of this repository. These are built upon the
stanfordpl/stoke-base:latest image, which contains compiled versions of Z3
and CVC4. If you want to upgrade Z3 or CVC4, it will require rebuilding these
imsages. The Dockerfile.base dockerfile may be used for this purpose (but
it's not part of continuous integration, so it may require some manual work to
get it to happen).
Downloading and Building STOKE
STOKE should work on Ubuntu 14.04 and Ubuntu 16.04. Regardless of distribution, the key to making stoke right is using gcc version 4.9. Below that, the compiler doesn't support enough features to build our code. Above that, there are some issues with an ABI change in gcc-5.
$ sudo apt-get install bison ccache cmake doxygen exuberant-ctags flex g++-4.9 g++-multilib gcc-4.9 ghc git libantlr3c-dev libboost-dev libboost-filesystem-dev libboost-thread-dev libcln-dev libghc-regex-compat-dev libghc-regex-tdfa-dev libghc-split-dev libjsoncpp-dev python subversion libiml-dev libgmp-dev libboost-regex-dev autoconf libtool antlr pccts pkg-config
Note that your distribution might not have g++-4.9 by default. You may consider installing a PPA as described here: https://askubuntu.com/questions/466651/how-do-i-use-the-latest-gcc-4-9-on-ubuntu-14-04
The rest of the dependencies will be fetched automatically as part of the build process.
The entire STOKE code base is available on GitHub under the Apache Software License version 2.0 at github.com/StanfordPL/stoke. To check it out, type:
$ git clone https://github.com/StanfordPL/stoke
This will check out the default develop branch. Unless you are looking for a
specific version or modification of STOKE, this is the branch to use. It
contains all the latest changes and is reasonably stable. This branch is
supposed to always pass all tests.
See the previous sections on how to download STOKE, a list of dependencies, and to check your hardware support level. The remainder of STOKE's software dependencies are available on GitHub and will be downloaded automatically the first time that STOKE is built. When you build STOKE the first time, run
$ ./configure.sh
This will figure out the correct build parameters (such as the platform). To build STOKE, run
$ make
To add STOKE and its related components to your path, type:
$ export PATH=$PATH:/<path_to_stoke>/bin
To run the tests, choose the appropriate command:
$ make test
The files generated during the build process can be deleted by typing:
$ make clean
To delete STOKE's dependencies as well (this is useful if an error occurs during the first build), type:
$ make dist_clean
Using STOKE
The following toy example shows a typical workflow for using STOKE. All of the
following code can be found in the examples/tutorial/ directory. As this
code is tested using our continuous integration system, the code there will
always be up-to-date, but this README can fall behind.
Running Example
Consider a
C++ program that repeatedly counts the number of bits (population count) in the
64-bit representation of an integer. (Keeping track of a running sum prevents
g++ from eliminating the calls to popcnt() altogether.)
// main.cc
#include <cstdlib>
#include <stddef.h>
#include <stdint.h>
using namespace std;
size_t popcnt(uint64_t x) {
int res = 0;
for ( ; x > 0; x >>= 1 ) {
res += x & 0x1ull;
}
return res;
}
int main(int argc, char** argv) {
const auto itr = atoi(argv[
