28

I'm trying to profile an instance method, so I've done something like:

import cProfile
class Test():
 def __init__(self):
 pass
 def method(self):
 cProfile.runctx("self.method_actual()", globals(), locals())
 def method_actual(self):
 print "Run"
if __name__ == "__main__":
 Test().method()

But now problems arise when I want "method" to return a value that is computed by "method_actual". I don't really want to call "method_actual" twice.

Is there another way, something that can be thread safe? (In my application, the cProfile data are saved to datafiles named by one of the args, so they don't get clobbered and I can combine them later.)

asked Oct 18, 2009 at 9:04

5 Answers 5

37

I discovered that you can do this:

prof = cProfile.Profile()
retval = prof.runcall(self.method_actual, *args, **kwargs)
prof.dump_stats(datafn)

The downside is that it's undocumented.

answered Oct 18, 2009 at 9:39
Sign up to request clarification or add additional context in comments.

5 Comments

Brilliant! This looks perfect - but what is 'datafn'?
@JonathanHartley - The filename for the data file IIRC.
Ah, thanks. I thought 'fn' meant function, not filename.
@Ngoral it's just a file name. You can put whatever name you like there.
@Ngoral no worries, I should clarify in the answer
32

An option for any arbitrary code:

import cProfile, pstats, sys
pr = cProfile.Profile()
pr.enable()
my_return_val = my_func(my_arg)
pr.disable()
ps = pstats.Stats(pr, stream=sys.stdout)
ps.print_stats()

Taken from https://docs.python.org/2/library/profile.html#profile.Profile

wordsforthewise
16.1k6 gold badges96 silver badges126 bronze badges
answered Jun 23, 2013 at 9:35

5 Comments

You could even make a little context manager for that using contextlibs contextmanager decorator.
I get Random listing order was used - how can I specify listing order ?
ps.sort_stats('cumulative')
how do I generate a valid profile file with this method so that I can use it with SnakeViz
I would only add something like: ps.dump_stats('my_dumpfile.dmp') so one can use snakeviz or similar to view the results, otherwise this worked great for me! I was having a heckuva time getting my return values before this.
8

I was struggling with the same problem and used a wrapper function to get over direct return values. Instead of

cP.runctx("a=foo()", globals(), locales())

I create a wrapper function

def wrapper(b):
 b.append(foo())

and profile the call to the wrapper function

b = []
cP.runctx("wrapper(b)", globals(), locals())
a = b[0]

extracting the result of foo's computation from the out param (b) afterwards.

Scott Stafford
45.1k31 gold badges138 silver badges188 bronze badges
answered Oct 1, 2010 at 15:34

Comments

4

I created a decorator:

import cProfile
import functools
import pstats
def profile(func):
 @functools.wraps(func)
 def inner(*args, **kwargs):
 profiler = cProfile.Profile()
 profiler.enable()
 try:
 retval = func(*args, **kwargs)
 finally:
 profiler.disable()
 with open('profile.out', 'w') as profile_file:
 stats = pstats.Stats(profiler, stream=profile_file)
 stats.print_stats()
 return retval
 return inner

Decorate your function or method with it:

@profile
def somefunc(...):
 ...

Now that function will be profiled.

Alternatively, if you'd like the raw, unprocessed profile data (e.g. because you want to run the excellent graphical viewer RunSnakeRun on it), then:

import cProfile
import functools
import pstats
def profile(func):
 @functools.wraps(func)
 def inner(*args, **kwargs):
 profiler = cProfile.Profile()
 profiler.enable()
 try:
 retval = func(*args, **kwargs)
 finally:
 profiler.disable()
 profiler.dump_stats('profile.out')
 return retval
 return inner

This is a minor improvement on several of the other answers on this page.

answered Sep 22, 2015 at 11:02

Comments

2

I think @detly the .runcall() is basically the best answer, but for completeness, I just wanted to take @ThomasH 's answer to be function independent:

def wrapper(b, f, *myargs, **mykwargs):
 try:
 b.append(f(*myargs, **mykwargs))
 except TypeError:
 print 'bad args passed to func.'
# Example run
def func(a, n):
 return n*a + 1
b = []
cProfile.runctx("wrapper(b, func, 3, n=1)", globals(), locals())
a = b[0]
print 'a, ', a
answered Feb 12, 2014 at 17:16

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.