Re: optimizations ( was: invertible id() )

Tim Peters (tim@ksr.com)
Thu, 07 Apr 94 01:46:17 -0400

> [lessons learned from the byte-code disassembler]

The most egregious inefficiency I've come across while doing that is the
one you originally posted, namely that in explicit multiple assignments
like
x, y, z = 1, 2, 3

there's a "BUILD_TUPLE 3"/"UNPACK_TUPLE 3" pair sitting "in the middle".

An astonishingly counter-intuitive consequence is that timing shows that

def ugly_gcd(a,b):
while b:
acopy = a
a = b
b = acopy % b
return a

actually runs faster than

def cute_gcd(a,b):
while b:
a, b = b, a%b
return a

today.

This is something that _could_ be-- & always --safely optimized away, in
which case cute_gcd would have the edge it "obviously" should have. Your
byte-code optimizer could do this if it's careful about not slobbering
over basic block boundaries; or I could take a stab at doing it in
codegen (it offends me <grin>!).

Caution: it may be the case that the build/unpack pair has as a side-
effect inverting the order of the top N stack entries; in which case just
deleting the pair would be disastrous, and repairing that could be
difficult at the byte-code level (but should be easy enough at codegen
time).

> ...
> One thing that CAN'T be source optimized is :
> thing[index] = thing[index] + somthing
> or thing.attrib = thing.attrib + something
> because you want a reference on the LHS and a value on the RHS,
> and there is not way to express that reference in Python.

Alas, can't be (reasonably easily) optimized at compile time, or at the
byte-code level, either, for the reason you give later (namely that sick
coding practices _could_ change the meanings of "thing[index]" and
"thing.attrib" as a side-effect of evaluating the RHS expressions).

> I took this as an argument in favor of adding C-like assignment
> operators ( +=, *=, etc. ) to Python.

Well, I hope this makes you happy <wink>! That's the one thing I always
would have added to Python but never talked Guido into. Augmented
assignments win on readability, writability, and optimizability. Plus it
would only take a few months of Guido's time to do it right <smile>.

> ...
> Anyway: THAT's the argument I *would* have made a while ago, if I
> hadn't come around to NOW thinking that the big win just might be
> in *improving* lookup, functions and classes, rather that avoiding
> them.

How about we call all of those "name resolution"? I'm sure that you're
right, that cutting name-resolution time (say) in half would yield a much
nicer speed payoff than getting rid of all redundant LHS/RHS resolutions.

> ... the sort of pointers that Python would require - reference counting
> pointers that keep the object alive while there are existing references.

When you get to my reply to Jim you'll see I've already blessed you with
a class that does exactly that -- written in vanilla Python <wink>. To
be more precise, it doesn't do all the painful by-hand reference-counting
mucking that C++ "smart pointers" do, cuz that would be silly (since
Python is already counting references, all a "smart pointer" object needs
to do in Python is point once at the pointee -- then Python won't kill
the pointee until (at earliest) all the pointers to it are killed).

> ...
> ( I'm still feeling chastened by Tim from the last Change-To-Python
> I ventured, ...

Chastened!? Just because I'm writing Python msgs a dozen hours a day now
in a doomed attempt to put off working on my stinking taxes doesn't mean
anyone should take it personally -- and least of all you, Steve <0.9 grin>.

death-and-taxes-are-the-root-of-all-evil-...-or-something-like-that-ly
y'rs - tim

Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp