3 import sys, os, tempfile, subprocess, gc, cProfile
4 from time import time, sleep
7 from pylab import math, linspace, loadtxt
9 os.chdir(os.path.dirname(sys.argv[0]))
10 sys.path.insert(0, '..')
14 start_measurement = -1
19 def run_test(testfunction, profile=None):
21 testfunction must be a generator (using yield)
27 assert res == start_measurement, res
28 def run_function_under_test():
30 assert res == stop_measurement
33 profile.runcall(run_function_under_test)
35 run_function_under_test()
36 time_total += time() - t0
39 print 'result =', time_total
41 pass # test did not make time measurements, it will print its own result (eg. memory)
44 "decorator for test functions that require no gui"
45 all_tests[f.__name__] = f
48 "decorator for test functions that require no gui"
50 gui = guicontrol.GUI()
53 all_tests[f.__name__] = f2
59 yield start_measurement
61 yield stop_measurement
66 Paint with a constant number of frames per recorded second.
67 Not entirely realistic, but gives good and stable measurements.
71 dw = gui.app.drawWindow
75 b = gui.app.brushmanager.get_brush_by_name('redbrush')
76 assert b, 'brush not found'
80 gui.app.brushmanager.select_brush(b)
81 gui.wait_for_duration(1.5) # fullscreen seems to take some time to get through...
84 events = loadtxt('painting30sec.dat.gz')
86 yield start_measurement
89 for t, x, y, pressure in events:
90 if t > t_last_redraw + 1.0/FPS:
95 cr = tdw.get_model_coordinates_cairo_context()
96 x, y = cr.device_to_user(x, y)
97 gui_doc.model.stroke_to(dtime, x, y, pressure, 0.0, 0.0)
98 yield stop_measurement
101 def paint_zoomed_out_5x(gui):
103 gui_doc = gui.app.doc
105 gui_doc.zoom('ZoomOut')
106 for res in paint(gui):
110 def layerpaint_nozoom(gui):
112 gui.app.filehandler.open_file('bigimage.ora')
113 gui_doc = gui.app.doc
114 gui_doc.model.select_layer(len(gui_doc.model.layers)/2)
115 for res in paint(gui):
119 def layerpaint_zoomed_out_5x(gui):
121 gui_doc = gui.app.doc
122 gui.app.filehandler.open_file('bigimage.ora')
123 gui_doc.tdw.scroll(800, 1000)
124 gui_doc.model.select_layer(len(gui_doc.model.layers)/3)
126 gui_doc.zoom('ZoomOut')
127 for res in paint(gui):
131 def paint_rotated(gui):
133 gui.app.doc.tdw.rotate(46.0/360*2*math.pi)
134 for res in paint(gui):
139 from lib import document
140 d = document.Document()
141 yield start_measurement
142 d.load('bigimage.ora')
143 yield stop_measurement
147 from lib import document
148 d = document.Document()
149 d.load('bigimage.ora')
150 yield start_measurement
151 d.save('test_save.ora')
152 yield stop_measurement
155 def save_ora_again():
156 from lib import document
157 d = document.Document()
158 d.load('bigimage.ora')
159 d.save('test_save.ora')
160 yield start_measurement
161 d.save('test_save.ora')
162 yield stop_measurement
166 from lib import document
167 d = document.Document()
168 d.load('bigimage.ora')
169 yield start_measurement
170 d.save('test_save.png')
171 yield stop_measurement
174 def save_png_layer():
175 from lib import document
176 d = document.Document()
177 d.load('biglayer.png')
178 yield start_measurement
179 d.layer.save_as_png('test_save.png')
180 yield stop_measurement
184 def brushengine_paint_hires():
185 from lib import tiledsurface, brush
186 s = tiledsurface.Surface()
187 bi = brush.BrushInfo(open('brushes/watercolor.myb').read())
190 events = loadtxt('painting30sec.dat.gz')
193 yield start_measurement
194 for t, x, y, pressure in events:
197 b.stroke_to (s, x*5, y*5, pressure, 0.0, 0.0, dtime)
198 yield stop_measurement
200 #s.save('test_paint_hires.png') # approx. 3000x3000
203 def scroll_nozoom(gui):
205 dw = gui.app.drawWindow
207 gui.app.filehandler.open_file('bigimage.ora')
209 yield start_measurement
211 yield stop_measurement
214 def scroll_nozoom_onelayer(gui):
216 dw = gui.app.drawWindow
218 gui.app.filehandler.open_file('biglayer.png')
220 yield start_measurement
222 yield stop_measurement
225 def scroll_zoomed_out_1x_onelayer(gui):
227 dw = gui.app.drawWindow
229 gui.app.filehandler.open_file('biglayer.png')
231 gui.app.doc.zoom('ZoomOut')
233 yield start_measurement
235 yield stop_measurement
238 def scroll_zoomed_out_2x_onelayer(gui):
240 dw = gui.app.drawWindow
242 gui.app.filehandler.open_file('biglayer.png')
244 gui.app.doc.zoom('ZoomOut')
246 yield start_measurement
248 yield stop_measurement
251 def scroll_zoomed_out_5x(gui):
253 dw = gui.app.drawWindow
255 gui.app.filehandler.open_file('bigimage.ora')
257 gui.app.doc.zoom('ZoomOut')
259 yield start_measurement
261 yield stop_measurement
264 def memory_zoomed_out_5x(gui):
266 dw = gui.app.drawWindow
268 gui.app.filehandler.open_file('bigimage.ora')
270 gui.app.doc.zoom('ZoomOut')
273 print 'result =', open('/proc/self/statm').read().split()[0]
275 yield None # just to make this function iterator
278 def memory_after_startup(gui):
284 print 'result =', open('/proc/self/statm').read().split()[0]
286 yield None # just to make this function iterator
288 if __name__ == '__main__':
289 if len(sys.argv) == 4 and sys.argv[1] == 'SINGLE_TEST_RUN':
290 func = all_tests[sys.argv[2]]
291 if sys.argv[3] == 'NONE':
294 profile = cProfile.Profile()
295 run_test(func, profile)
296 profile.dump_stats(sys.argv[3])
299 from optparse import OptionParser
300 parser = OptionParser('usage: %prog [options] [test1 test2 test3 ...]')
301 parser.add_option('-a', '--all', action='store_true', default=False,
302 help='run all tests')
303 parser.add_option('-l', '--list', action='store_true', default=False,
304 help='list all available tests')
305 parser.add_option('-c', '--count', metavar='N', type='int', default=3,
306 help='number of repetitions (default: 3)')
307 parser.add_option('-p', '--profile', metavar='PREFIX',
308 help='dump cProfile info to PREFIX_TESTNAME_N.pstats')
309 parser.add_option('-s', '--show-profile', action='store_true', default=False,
310 help='run cProfile, gprof2dot.py and show last result')
311 options, tests = parser.parse_args()
314 for name in sorted(all_tests.keys()):
320 tests = list(all_tests)
326 if t not in all_tests:
327 print 'Unknown test:', t
333 for i in range(options.count):
335 print 'running test "%s" (run %d of %d)' % (t, i+1, options.count)
337 # spawn a new process for each test, to ensure proper cleanup
338 args = ['./test_performance.py', 'SINGLE_TEST_RUN', t, 'NONE']
339 if options.profile or options.show_profile:
340 if options.show_profile:
343 fname = '%s_%s_%d.pstats' % (options.profile, t, i)
345 child = subprocess.Popen(args, stdout=subprocess.PIPE)
346 output, junk = child.communicate()
347 if child.returncode != 0:
353 value = float(output.split('result = ')[-1].strip())
355 print 'FAILED to find result in test output.'
360 # some time to press ctrl-c
364 results.append(result)
366 print '=== DETAILS ==='
367 print 'tests =', repr(tests)
368 print 'results =', repr(results)
370 print '=== SUMMARY ==='
372 for t, result in zip(tests, results):
377 print '%s %.3f' % (t, min(result))
381 if options.show_profile:
382 os.system('gprof2dot.py -f pstats tmp.pstats | dot -Tpng -o tmp.png && feh tmp.png')