Python profiling
I wrote a couple of modules in Python for generating factorials and I want to test the running time. I found an example of profiling here and I used that template to profile m开发者_运维技巧y modules:
import profile #fact
def main():
x = raw_input("Enter number: ")
profile.run('fact(int(x)); print')
profile.run('factMemoized(int(x)); print')
def fact(x):
if x == 0: return 1
elif x < 2: return x
else:
return x * fact(x-1)
def factMemoized(x):
if x == 0: return 1
elif x < 2: return x
dict1 = dict()
dict1[0] = 1
dict1[1] = 1
for i in range (0, x+1):
if dict1.has_key(i): pass
else: dict1[i] = i * dict1[i-1]
return dict1[x]
if __name__ == "__main__":
main()
However, I get the following error:
Enter number: 10
Traceback (most recent call last):
File "fact.py", line 32, in <module>
main()
File "fact.py", line 7, in main
profile.run('fact(int(x)); x')
File "C:\Python27\lib\profile.py", line 70, in run
prof = prof.run(statement)
File "C:\Python27\lib\profile.py", line 447, in run
return self.runctx(cmd, dict, dict)
File "C:\Python27\lib\profile.py", line 453, in runctx
exec cmd in globals, locals
File "<string>", line 1, in <module>
NameError: name 'x' is not defined
Any idea what I'm doing wrong here? TIA! ~craig
As John Gaines Jr. said, profile.run()
has some scoping problems. However, you can just use runctx
with globals() and locals() and provide the context explicitly:
profile.runctx('fact(int(x)); print', globals(), locals())
Explicit is better than implicit :)
The profiler receives a string, which he tries to interpret. Your string is profile.run('fact(int(x)); print')
and the x
variable inside is just part of the string and cannot be resolved to a variable. You have to copy its value into the string to make this work. Try this:
profile.run('fact(int(%s)); print' % x)
profile.run('factMemoized(int(%s)); print' % x)
Edit (removed my "answer" as Petr Viktorin's makes much better sense). But leaving the explanation as to why it didn't work as OP expected.
Looking at the code in profile.py (Python 2.7.2) I see the following for the methods of class Profile:
def run(self, cmd):
import __main__
dict = __main__.__dict__
return self.runctx(cmd, dict, dict)
def runctx(self, cmd, globals, locals):
self.set_cmd(cmd)
sys.setprofile(self.dispatcher)
try:
exec cmd in globals, locals
finally:
sys.setprofile(None)
return self
The exec statement in runctx() is being fed __main__.__dict__
for both global and local dictionaries so profile.run() will only be able to resolve variables which are defined at the top level dictionary of the running app.
You can directly profile your code with Region Profiler. Your code snippet would look like this:
import region_profiler as rp # pip install region-profiler
rp.install()
def main():
x = raw_input("Enter number: ")
fact(int(x)) # note: direct call
factMemoized(int(x))
@rp.func(asglobal=True)
def fact(x):
if x == 0: return 1
elif x < 2: return x
else:
return x * fact(x-1)
@rp.func(asglobal=True)
def factMemoized(x):
if x == 0: return 1
elif x < 2: return x
dict1 = dict()
dict1[0] = 1
dict1[1] = 1
for i in range (0, x+1):
if dict1.has_key(i): pass
else: dict1[i] = i * dict1[i-1]
return dict1[x]
if __name__ == "__main__":
main()
Sample output:
name total % of total count min average max
---------------- -------- ---------- ----- -------- -------- --------
<main> 3.601 s 100.00% 1 3.601 s 3.601 s 3.601 s
. fact() 863 us 0.02% 1 863 us 863 us 863 us
. factMemoized() 73.12 us 0.00% 1 73.12 us 73.12 us 73.12 us
精彩评论