[Python-Dev] Re: Bytecode idea

Damien Morton newsgroups1@bitfurnace.com
Wed, 26 Feb 2003 02:14:19 -0500


> Christian Tismer wrote:
> So what I would like to try is to merge all opcodes
> which have exactly the same pattern into one case,
> which then does the common preparation stuff and
> postprocessing including error handling, but internally
> dispatches on the function to be called.

I tried this on the 2.3a2 source, modifying it to implement your idea.

This was implemented on top of the LOAD_FAST_n, etc, changes.

No luck - it makes the code slower by nearly 5%, decreasing a base 22300
PyStones to 21100 PyStones. That is, the idea of using function pointers. I
imagine that a case statement would be even slower.

I didnt implement the table of function pointers as one monolithic table, as
the unary and binary functions have different signatures.

static binaryfunc binop[] = {
 PyNumber_Multiply,
 PyNumber_TrueDivide,
 PyNumber_TrueDivide,
 PyNumber_FloorDivide,
 PyNumber_Remainder,
 PyNumber_Lshift,
 PyNumber_Rshift,
 PyNumber_And,
 PyNumber_Xor,
 PyNumber_Or,
 PyNumber_InPlaceMultiply,
 PyNumber_InPlaceTrueDivide,
 PyNumber_InPlaceTrueDivide,
 PyNumber_InPlaceFloorDivide,
 PyNumber_InPlaceRemainder,
 PyNumber_InPlaceLshift,
 PyNumber_InPlaceRshift,
 PyNumber_InPlaceAnd,
 PyNumber_InPlaceXor,
 PyNumber_InPlaceOr
};


  switch (opcode) {
...
  case BINARY_MULTIPLY:
  case BINARY_DIVIDE:
  case BINARY_TRUE_DIVIDE:
  case BINARY_FLOOR_DIVIDE:
  case BINARY_MODULO:
  case BINARY_LSHIFT:
  case BINARY_RSHIFT:
  case BINARY_AND:
  case BINARY_XOR:
  case BINARY_OR:
  case INPLACE_MULTIPLY:
  case INPLACE_DIVIDE:
  case INPLACE_TRUE_DIVIDE:
  case INPLACE_FLOOR_DIVIDE:
  case INPLACE_MODULO:
  case INPLACE_LSHIFT:
  case INPLACE_RSHIFT:
  case INPLACE_AND:
  case INPLACE_XOR:
  case INPLACE_OR:
   w = POP();
   v = TOP();
   x = binop[opcode-BINARY_MULTIPLY](v, w);
   Py_DECREF(v);
   Py_DECREF(w);
   SET_TOP(x);
   if (x != NULL) continue;
   break;
...




"Christian Tismer" <tismer@tismer.com> wrote in message
news:3E5C3915.6070600@tismer.com...
> Christian Tismer wrote:
> [much about bytecode, folding, ...]
>
> Well, to stop myself blathering about bytecode and
> how to make it different, which I'm expected to do
> other things or at least sleep, I can't resist
> to throw this rigorous idea into py-dev, which
> struck me at 4:30 in the morning:
>
> WHat would happen if we re-structured the ceval
> loop this way:
> We look at every similar pattern and group together
> all the opcodes which have a similar pattern.
> By "pattern" I mean the surrounding calls of simple
> things like stack operations before and after, and
> error handling.
>
> So what I would like to try is to merge all opcodes
> which have exactly the same pattern into one case,
> which then does the common preparation stuff and
> postprocessing including error handling, but internally
> dispatches on the function to be called.
>
> No idea if it may be an improvement, but just let me throw
> it in.
> Example:
>
> case UNARY_POSITIVE:
> v = POP();
> x = PyNumber_Positive(v);
> Py_DECREF(v);
> PUSH(x);
> if (x != NULL) continue;
> break;
>
> case UNARY_NEGATIVE:
> v = POP();
> x = PyNumber_Negative(v);
> Py_DECREF(v);
> PUSH(x);
> if (x != NULL) continue;
> break;
> ...
> case UNARY_CONVERT:
> v = POP();
> x = PyObject_Repr(v);
> Py_DECREF(v);
> PUSH(x);
> if (x != NULL) continue;
> break;
>
> case UNARY_INVERT:
> v = POP();
> x = PyNumber_Invert(v);
> Py_DECREF(v);
> PUSH(x);
> if (x != NULL) continue;
> break;
>
> is converted into
>
> case UNARY_POSITIVE:
> case UNARY_NEGATIVE:
> case UNARY_CONVERT:
> case UNARY_INVERT:
> v = POP();
> switch (opcode) {
> case UNARY_POSITIVE:
> x = PyNumber_Positive(v); break;
> case UNARY_NEGATIVE:
> x = PyNumber_Negative(v); break;
> case UNARY_CONVERT:
> x = PyObject_Repr(v); break;
> case UNARY_INVERT:
> x = PyNumber_Invert(v);
> }
> Py_DECREF(v);
> PUSH(x);
> if (x != NULL) continue;
> break;
>
> Maybe it also makes sense to use indexing into a static
> array, instead of the case construct. Note that there
> can be one single such table for all opcodes and all cases,
> since opcodes are still disjoint. It depends where this
> table is stored and if this can get in the cache.
>
> While I don't know if this really makes the interpreter
> more efficient, at least it makes it shorter to read
> and maybe easier to maintain.
>
> Ok ok, I will sleep now :-)
>
> cheers - chris
>
> --
> Christian Tismer             :^)   <mailto:tismer@tismer.com>
> Mission Impossible 5oftware  :     Have a break! Take a ride on Python's
> Johannes-Niemeyer-Weg 9a     :    *Starship* http://starship.python.net/
> 14109 Berlin                 :     PGP key -> http://wwwkeys.pgp.net/
> work +49 30 89 09 53 34  home +49 30 802 86 56  pager +49 173 24 18 776
> PGP 0x57F3BF04       9064 F4E1 D754 C2FF 1619  305B C09C 5A3B 57F3 BF04
>       whom do you want to sponsor today?   http://www.stackless.com/