开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜