Re: psyco
Pierre-Frédéric Caillaud <[email protected]>
| Newsgroups | gmane.comp.web.skunkweb |
|---|---|
| Organization | La Boutique Numérique |
| Message-ID | <opsarw1ji3cq72hf@musicbox> |
Okay, so let's go.
Comments on STML compilation :
***************************************
* Problem :
In Python, Global variables are slow, and locals are fast. I see all stml
compiled code is put straight into the top level of a code object. I don't
know if this behaves like a function or like a module, but the variables
are probably considered global (thus slow). Besides, Psyco does not
accelerate code in the top level of a module.
***************************************
Proposed solution :
Generate functions instead of modules.
Calling a component looks a lot like a function call anyway ; why not
make it a function call ? You could use **kwargs for parameter passing,
etc. The important part is that all code in a component should be in a
function to make the variables local. Besides, the component namespace is
not connected to the caller's namespace, so a function is suitable.
For include's, it could be a little more difficult to implement, but that
is not really a problem ; the components are where most of the processing
time is spent.
***************************************
Here is an example program :
It just increments a variable 1000.000 times.
import time
import psyco
test_len = 1000000
# test globals
t = time.time()
r = 0
for i in xrange(test_len):
r = r+1
print 'globals : ', time.time() - t
# test locals
def test():
r = 0
for i in xrange(test_len):
r = r+1
t = time.time()
test()
print 'locals : ', time.time() - t
# test psyco
psyco.full()
t = time.time()
test()
print 'psyco : ', time.time() - t
And here are the timings :
globals : 0.571024894714
locals : 0.261034011841
psyco : 0.00352907180786
As you can see locals are a lot faster than globals... and yes, the psyco
figure is real, but this really is an extreme case, using only integers.
Usually Psyco accelerates between nothing and 2-3x
***************************************
* About <:val:> tag
In the generated sources, I see :
__d.CURRENT_TAG = "<:val '`title`':>"
__d.CURRENT_LINENO = '/webadmin/comps/products_list.comp:21'
__t.val = title
if __t.val is None:
__t.val = ""
else:
__t.val = str(__t.val)
__h.OUTPUT.write(__t.val)
del __t.val
***************************************
Comments :
- I think it would be more appropriate to use a function for the
following code :
__t.val = title
if __t.val is None:
__t.val = ""
else:
__t.val = str(__t.val)
__h.OUTPUT.write(__t.val)
del __t.val
Even if inlining looks faster, I guess it's much slower here, due to
unoptimized globals, temp variable creation, and del. There is probably a
reason you did it that way, though. It could also be a method in the
OUTPUT object.
And generally, I think it would be a good idea to use functions more
often in the compiled templates (for argument extraction, too). This would
make the code smaller (faster to compile, to load, takes less memory,
better locality of reference in cache, etc.)
You could also save a few lookups by putting __h.OUTPUT.write in a
variable.
***************************************
* About debug info and generated sources size
In the generated sources, I see :
__d.CURRENT_TAG = '<:val "`(\'Non\',
\'Oui\')[prod.products_ready_to_ship]`":>'
__d.CURRENT_LINENO = '/webadmin/comps/products_list.comp:136'
This is nice for debugging, however it causes code bloat.
Same thing for including the sources in the compiled files.
I think it would be better to create a file with only the compiled python
bytecode (this is the file which is loaded all the time by SkunkWeb), and
another file with the source and tag reference.
Then, the compiled template would only contain lines like :
__d.CURRENT_POSITION = (1, 10, 20)
the tuple being : file id, tag id, line id (or something like that).
One tuple = one assignment (instead of two)
The tag, file, etc. would be retrieved from these ID's when an error
occurs.
***************************************
* Other notes :
In the generated sources, I see :
__d.CURRENT_TAG = "<:for '`prod.images`' 'image':>"
__t.temp5 = prod.images
if __t.temp5:
for image in __t.temp5:
You could use instead :
for image in (prod.images or []):
That's all I can think about right now. I hope it helps !
Thanks a lot !
-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 -
digital self defense, top technical experts, no vendor pitches,
unmatched networking opportunities. Visit www.blackhat.com