[Python-Dev] Optimization idea

Guido van Rossum guido@CNRI.Reston.VA.US
Thu, 19 Aug 1999 10:15:28 -0400


> I just had yet another idea for optimizing Python that looks so
> plausible that I guess someone else must have looked into it already
> (and, hence, probably rejected it:-):
> 
> We add to the type structure a "type identifier" number, a small integer for 
> the common types (int=1, float=2, string=3, etc) and 0 for everything else.
> 
> When eval_code2 sees, for instance, a MULTIPLY operation it does something 
> like the following:
>    case BINARY_MULTIPLY:
> 	w = POP();
> 	v = POP();
> 	code = (BINARY_MULTIPLY << 8) |
> 		((v->ob_type->tp_typeid) << 4) |
> 		((w->ob_type->tp_typeid);
> 	x = (binopfuncs[code])(v, w);
> 	.... etc ...
> 
> The idea is that all the 256 BINARY_MULTIPLY entries would be filled with 
> PyNumber_Multiply, except for a few common cases. The int*int field could 
> point straight to int_mul(), etc.
> 
> Assuming the common cases are really more common than the uncommon cases the 
> fact that they jump straight out to the implementation function in stead of 
> mucking around in PyNumber_Multiply and PyNumber_Coerce should easily offset 
> the added overhead of shifts, ors and indexing.

You're assuming that arithmetic operations are a major time sink.  I
doubt that; much of my code contains hardly any arithmetic these days.

Of course, if you *do* have a piece of code that does a lot of basic
arithmetic, it might pay off -- but even then I would guess that the
majority of opcodes are things like list accessors and variable.

But we needn't speculate.  It's easy enough to measure the speedup:
you can use tp_xxx5 in the type structure and plug a typecode into it
for the int and float types.  

(Note that you would need a separate table of binopfuncs per
operator.)

--Guido van Rossum (home page: http://www.python.org/~guido/)