On Tue, Nov 09, 2010 at 01:21:00AM +0200, Marius Gedminas wrote: > On Mon, Nov 08, 2010 at 03:35:09PM +0100, Brian Sutherland wrote: > > I've committed 2 patches to a "jinty-mem" branch of zope.interface. > > Together these patches reduce the startup memory use of my ZTK based > > application by 3%. Is that enough to justify their risk/complexity? > > > > https://mail.zope.org/pipermail/checkins/2010-November/052516.html > > https://mail.zope.org/pipermail/checkins/2010-November/052517.html > > > > If no-one replies, I'll assume that 3% is just not enough to be > > interesting and do nothing;) > > It's so interesting I'm going to ask for even more numbers: how much is > that 3% in kilobytes, or objects?
Ok, you asked for it ;) The 3% was in kilobytes as measured using /bin/ps on OSX leopard with python2.6 from MacPorts. The app I measured is a ZTK 1.0 based web application. My application without the changes: Objects: 245614 RSS memory (kb): 59116 My application with the changes: Objects: 227147 RSS memory (kb): 57180 I also did a micro-benchmark (more below) which indicate that when creating an interface with 5 attributes and 5 methods you save 41% in kilobytes and 34% in objects. > Is there any measurable speed impact > for application startup or test runs (faster/slower)? My app doesn't startup measurably faster or slower. The ZTK tests seem to run a little faster, but the error is high on my laptop: Without patches: ./bin/test-ztk 71.93s ./bin/test-ztk 70.49s ./bin/test-ztk 70.31s With patches: ./bin/test-ztk 70.28s ./bin/test-ztk 70.00s ./bin/test-ztk 69.98s I also did some micro-benchmarking (script is attached). There were repeatable results which indicate that startup will be faster and runtime only probably faster: Without patches: Performance bench ----------------- one interface, 5 methods, 5 functions: 181.00 usec/pass five inheriting interfaces: 355.76 usec/pass one interface: 59.79 usec/pass query uninitialized tagged value: 1.26 usec/pass query initialized tagged value: 1.27 usec/pass Memory bench ------------ Memory before (kb): RSS VSZ 33684 109780 objects created: 150001 Memory after (kb): RSS VSZ 47856 124116 With patches: Performance bench ----------------- one interface, 5 methods, 5 functions: 165.97 usec/pass five inheriting interfaces: 341.22 usec/pass one interface: 53.03 usec/pass query uninitialized tagged value: 0.75 usec/pass query initialized tagged value: 1.37 usec/pass Memory bench ------------ Memory before (kb): RSS VSZ 33328 109524 objects created: 99001 Memory after (kb): RSS VSZ 41728 117972 > Otherwise I'm +1, assuming this doesn't somehow make the code 10% > slower. > > Marius Gedminas > -- > http://pov.lt/ -- Zope 3/BlueBream consulting and development > _______________________________________________ > Zope-Dev maillist - Zope-Dev@zope.org > https://mail.zope.org/mailman/listinfo/zope-dev > ** No cross posts or HTML encoding! ** > (Related lists - > https://mail.zope.org/mailman/listinfo/zope-announce > https://mail.zope.org/mailman/listinfo/zope ) -- Brian Sutherland
# # Perdormance Benchmark # import os import timeit import subprocess from zope.interface import Interface, Attribute print "Performance bench" print "-----------------" s1 = """\ class I1(Interface): a1 = Attribute('one') a2 = Attribute('two') a3 = Attribute('thee') a4 = Attribute('four') a5 = Attribute('five') def f1(arg): pass def f2(arg): pass def f3(arg): pass def f4(arg): pass def f5(arg): pass """ t = timeit.Timer(stmt=s1, setup="from zope.interface import Interface, Attribute") print "one interface, 5 methods, 5 functions: %.2f usec/pass" % (1000000 * t.timeit(number=10000)/10000) s1 = """\ class I1(Interface): pass class I2(I1): pass class I3(I2): pass class I4(I3): pass class I5(I4): pass """ t = timeit.Timer(stmt=s1, setup="from zope.interface import Interface, Attribute") print "five inheriting interfaces: %.2f usec/pass" % (1000000 * t.timeit(number=10000)/10000) s1 = """\ class I1(Interface): pass """ t = timeit.Timer(stmt=s1, setup="from zope.interface import Interface, Attribute") print "one interface: %.2f usec/pass" % (1000000 * t.timeit(number=10000)/10000) setup = """\ from zope.interface import Interface, Attribute class I1(Interface): pass """ s1 = """\ I1.queryTaggedValue('bob') """ t = timeit.Timer(stmt=s1, setup=setup) print "query uninitialized tagged value: %.2f usec/pass" % (1000000 * t.timeit(number=50000)/50000) setup = """\ from zope.interface import Interface, Attribute class I1(Interface): pass I1.setTaggedValue('bob', 'bobby') """ s1 = """\ I1.queryTaggedValue('bob') """ t = timeit.Timer(stmt=s1, setup=setup) print "query initialized tagged value: %.2f usec/pass" % (1000000 * t.timeit(number=50000)/50000) print print "Memory bench" print "------------" pid = os.getpid() import gc gc.collect() gc.collect() gc.collect() print 'Memory before (kb):' subprocess.call(['/bin/ps', '-o', 'rss,vsize', str(pid)]) before_objects = len(gc.get_objects()) log = [] for i in range(3000): class I1(Interface): a1 = Attribute('one') a2 = Attribute('two') a3 = Attribute('thee') a4 = Attribute('four') a5 = Attribute('five') def f1(arg): pass def f2(arg): pass def f3(arg): pass def f4(arg): pass def f5(arg): pass log.append(I1) gc.collect() gc.collect() gc.collect() print "objects created: %s" % (len(gc.get_objects()) - before_objects) print 'Memory after (kb):' subprocess.call(['/bin/ps', '-o', 'rss,vsize', str(pid)])
_______________________________________________ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )