How can you profile a Python script? How can you profile a Python script? python python

How can you profile a Python script?


Python includes a profiler called cProfile. It not only gives the total running time, but also times each function separately, and tells you how many times each function was called, making it easy to determine where you should make optimizations.

You can call it from within your code, or from the interpreter, like this:

import cProfilecProfile.run('foo()')

Even more usefully, you can invoke the cProfile when running a script:

python -m cProfile myscript.py

To make it even easier, I made a little batch file called 'profile.bat':

python -m cProfile %1

So all I have to do is run:

profile euler048.py

And I get this:

1007 function calls in 0.061 CPU secondsOrdered by: standard namencalls  tottime  percall  cumtime  percall filename:lineno(function)    1    0.000    0.000    0.061    0.061 <string>:1(<module>) 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)    1    0.000    0.000    0.061    0.061 {execfile}    1    0.002    0.002    0.053    0.053 {map}    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}    1    0.000    0.000    0.000    0.000 {range}    1    0.003    0.003    0.003    0.003 {sum}

EDIT: Updated link to a good video resource from PyCon 2013 titled Python Profiling
Also via YouTube.


A while ago I made pycallgraph which generates a visualisation from your Python code. Edit: I've updated the example to work with 3.3, the latest release as of this writing.

After a pip install pycallgraph and installing GraphViz you can run it from the command line:

pycallgraph graphviz -- ./mypythonscript.py

Or, you can profile particular parts of your code:

from pycallgraph import PyCallGraphfrom pycallgraph.output import GraphvizOutputwith PyCallGraph(output=GraphvizOutput()):    code_to_profile()

Either of these will generate a pycallgraph.png file similar to the image below:

enter image description here


It's worth pointing out that using the profiler only works (by default) on the main thread, and you won't get any information from other threads if you use them. This can be a bit of a gotcha as it is completely unmentioned in the profiler documentation.

If you also want to profile threads, you'll want to look at the threading.setprofile() function in the docs.

You could also create your own threading.Thread subclass to do it:

class ProfiledThread(threading.Thread):    # Overrides threading.Thread.run()    def run(self):        profiler = cProfile.Profile()        try:            return profiler.runcall(threading.Thread.run, self)        finally:            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

and use that ProfiledThread class instead of the standard one. It might give you more flexibility, but I'm not sure it's worth it, especially if you are using third-party code which wouldn't use your class.