#!/usr/bin/env python """ Profile a script using hotshot and kcachegrind. This program runs a script under the control of the Python hotshot profiler and converts the hotshot results into the Kcachegrind format. It finally calls kcachegrind to visualize the output. Usage: pycachegrind.py script.py [script args] Any arguments after your script name are passed directly to the script in sys.argv. This program leaves two files on disk: - script.py.prof: hotshot profile results. - script.py.cgrind: hotshot results converted to cachegrind format. Requirements: - kcachegrind. Used to visualize the results. It includes hotshot2calltree, the default converter from hotshot to cachegrind format. Optional: - hotshot2cachegrind.py. This is hotshot2calltree's ancestor, and if you experience any problems with h2ctree, you may want to test this script instead (I'm not sure, but I've seen a few minor problems that /might/ be bugs in h2ctree). I've put up a copy of hotshot2cachegrind on the net, since it is not easy to find: http://amath.colorado.edu/faculty/fperez/python/profiling You'll need to modify a global constant in the source if you wish to use hotshot2cachegrind instead of hotshot2calltree. Acknowledgements: This code is heavily inspired in scripts written by Arnd Baecker and Nikolai Hlubek, and posted to the SciPy mailing lists. """ #***************************************************************************** # Copyright (C) 2006 Fernando Perez. <Fernando.Perez@colorado.edu> # # Distributed under the terms of the BSD License. # #***************************************************************************** __author__ = 'Fernando Perez <Fernando.Perez@colorado.edu>' __url__ = 'http://amath.colorado.edu/faculty/fperez/python/profiling' __license__ = 'BSD' # Tweak any constants you may want here # Select the converter from hotshot format to callgrind format HOTSHOT2CG = 'hotshot2calltree' #HOTSHOT2CG = 'hotshot2cachegrind.py' ############################################################################# # No user-serviceable parts below. ############################################################################# # Stdlib imports import hotshot import os import sys # Main code starts. The run() routine is as simple as possible so that it # produces the least amount of extraneous information in the profile results. def run(code): loc = locals() loc['__name__'] = '__main__' loc['__file__'] = sys.argv[0] exec code in loc def main(): # Simple args processing try: fname = sys.argv[1] except IndexError: print __doc__ sys.exit(1) # Read and compile source f = file(fname,'r') source = f.read() f.close() # Precompile the source so we don't see compilation times in the profile. # Let any generated exceptions propagate out. code = compile(source,fname,'exec') # Build filenames for outputs base_fname = os.path.basename(fname) prof_fname = base_fname+'.prof' cgr_fname = base_fname+'.cgrind' # Build the profiler object prof = hotshot.Profile(prof_fname, lineevents=1) # Modify sys.argv so the executed code sees it as if it were running # standalone sys.argv[:] = sys.argv[1:] try: prof.runcall(run,code) finally: prof.close() # Post-process the hotshot output so it can be read by kcachegrind os.system('%s -o %s %s' % (HOTSHOT2CG,cgr_fname,prof_fname)) os.system('kcachegrind %s &' % cgr_fname) if __name__ == '__main__': main()