[pypy-svn] r24582 - pypy/dist/pypy/doc
arigo at codespeak.net
arigo at codespeak.net
Mon Mar 20 13:57:34 CET 2006
Author: arigo
Date: Mon Mar 20 13:57:20 2006
New Revision: 24582
Modified:
pypy/dist/pypy/doc/jit.txt
Log:
JIT Doc: some notes about the merging/bookkeeping done by the
compilers produced by the hint-rtyper. Wrote down a possible
approach, to be reviewed :-)
Modified: pypy/dist/pypy/doc/jit.txt
==============================================================================
--- pypy/dist/pypy/doc/jit.txt (original)
+++ pypy/dist/pypy/doc/jit.txt Mon Mar 20 13:57:20 2006
@@ -106,4 +106,132 @@
helpers; when the graph of the now-compiler is running, these helpers
will produce new ``int_add`` and ``int_sub`` operations.
-(Extra merging/bookkeeping blocks are actually inserted; XXX explain...)
+Merging and bookkeeping
+-----------------------
+
+XXX the following is not the way it works currently, but rather a
+proposal for how it might work -- although it's all open to changes. It
+is a mix of how Psyco and the Flow Object Space work.
+
+Unlike ll_plus_minus() above, any realistic interpreter needs to handle
+two complications:
+
+1. Jumping or looping opcodes. When looping back to a previous bytecode
+ position, the now-compiler must not continue to compile again and again;
+ it must generate a loop in the residual graph as well, and stop
+ compiling.
+
+2. Conditional branches. Unless the condition is known at compile time,
+ the compiler must generate a branch in the residual graph and compile
+ both paths.
+
+Keep in mind that this is all about how the interpreter is transformed
+to become a compiler. Unless explicitly specified, I don't speak about
+the interpreted user program here.
+
+As a reminder, this is handled in the Flow Space as follows:
+
+1. When a residual operation is about to be generated, we check if the
+ bytecode position closed back to an already-seen position. To do so,
+ for each bytecode position we save a "state". The state remembers
+ the bytecode interpreter's frame state, as a pattern of Variables and
+ Constants; in addition, the state points to the residual block that
+ corresponded to that position.
+
+2. A branch forces the current block to fork in two "EggBlocks". This
+ makes a tree with a "SpamBlock" at the root and two EggBlock children,
+ which themselves might again have two EggBlock children, and so on.
+ The Flow Space resumes its analysis from the start of the root
+ SpamBlock and explores each branch of this tree in turn. Unexplored
+ branches are remembered for later.
+
+In Psyco:
+
+1. A state is saved at the beginning of each bytecode, as in the Flow
+ Space. (There are actually memory-saving tricks to avoid saving a
+ state for each and every bytecode.) We close a loop in the residual
+ graph as soon as we reach an already-seen bytecode position, but
+ only if the states are "compatible enough". Indeed, as in the PyPy
+ JIT, Psyco states store more than just Variable/Constant: they store
+ "blue" containers detailing individual field's content. Blue
+ containers of too-different shapes are not "compatible enough". In
+ addition, some Constants can be marked as "fixed" to prevent them
+ from being merged with different Constants and becoming Variables.
+
+2. Branching in Psyco work as in the Flow Space, with the exception that
+ each condition has got a "likely" and a "less likely" outcome. The
+ compilation follows the "likely" path only. The "unlikely" paths
+ are only explored if at run-time the execution actually reaches them.
+ (When it does, the same trick as in the Flow Space is used:
+ compilation restarts from the root SpamBlock and follows the complete
+ branch of the EggBlock tree.)
+
+3. A different kind of branching that doesn't occur in the Flow Space:
+ promoting a value from Variable to Constant. This is used e.g. when
+ an indirect function call is about to be performed. A typical
+ example is to call a PyTypeObject's slot based on the type of a
+ PyObject instance. In this case, Psyco considers the PyObject's
+ ob_type field as a Variable, which it turns into a Constant.
+ Conceptually, the current residual block is ended with a "switch"
+ and every time a different run-time value reaches this point, a new
+ case is compiled and added to the switch. (As in 2., the compilation
+ is restarted from the root SpamBlock until it reaches that point
+ again.)
+
+The "tree of EggBlocks" approach doesn't work too well in general. For
+example, it unrolls loops infinitely if they are not loops in the
+bytecode but loops in the implementation of a single opcode (we had this
+problem working on the annotator in Vilnius).
+
+The current preliminary work on the hint-rtyper turns the interpreter
+into a compiler that saves its state all the time everywhere. This
+makes sure that loops are not unexpectedly unrolled, and that the code
+that follows an if/else is not duplicated (as it would be in the
+tree-of-EggBlocks approach). It is also extremely inefficient and
+perfect to explode the memory usage.
+
+I think we could try to target the following model -- which also has the
+advantage that simple calls in the interpreter are still simple calls in
+the compiler, as in Psyco:
+
+1. We only save the state at one point. We probably need a hint to
+ specify where this point is -- at the beginning of the bytecode
+ interpreter loop. It is easy to know in advance which information
+ needs to be stored in each state: the tuple of green variables is used
+ as a key in a global dict; the content of the red variables is stored
+ as a state under this key. Several states can be stored under the same
+ key if they are not "compatible enough".
+
+2. Branching: a possible approach would be to try to have the compiler
+ produce a residual graph that has the same shape as the original
+ graph in the interpreter, at least as far as the conditions are
+ unknown at compile-time. (This would remove the branches whose
+ conditions are known at compile time, and unroll all-green loops
+ like the bytecode interpreter loop itself.)
+
+3. Promoting a Variable to a Constant, or, in colored terms, a red
+ variable to a green one (using a hint which we have not implemented
+ so far): this is the case where we have no choice but suspend the
+ compilation, and wait for execution to provide real values. We will
+ implement this case later, but I mention it now because it seems that
+ there are solutions compatible with this model, including Psyco's
+ (see 3. above).
+
+The motivation to do point 2. differently than in Psyco is that it is
+both more powerful (no extra unrolling/duplication of code) and closer
+to what we have already now: the bookkeeping code inserted by the
+hint-rtyper in the compiler's graphs. In Psyco it would have been a
+mess to write that bookkeeping code everywhere by hand, not to mention
+changing it to experiment with other ideas.
+
+Random notes
+-----------------
+
+An idea to consider: red variables in the compiler could come with
+a concrete value attached too, which represents a real execution-time
+value. The compiler would perform concrete operations on it in addition
+to generating residual operations. In other words, the compiler would
+also perform directly some interpretation as it goes along. In this
+way, we can avoid some of the recompilation by using this attached value
+e.g. as the first switch case in the red-to-green promotions, or as a
+hint about which outcome of a run-time condition is more likely.
More information about the Pypy-commit
mailing list