Python Profiler测量的CPU时间与实际,用户和系统时间之间的关系是什么?

时间:2012-03-02 12:20:29

标签: python time profiling profiler cprofile

在一个处理器中使用python内置探查器和脚本runninng(并且没有多线程)

time python -m cProfile myscript.py

分析器报告的CPU时间为345.710 CPU秒

24184348 function calls (24183732 primitive calls) in 345.710 CPU seconds

真实的用户 sys 时间是:

real    5m45.926s
user    1m59.340s
sys     0m39.452s

正如您所看到的,CPU时间几乎是实时(345.710 = 5m45.710s)。

因此,考虑到结果,是否可以假设分析器报告的CPU时间包括其他进程使用的时间片以及进程花费的时间?即,探查器CPU时间不是处理时间(用户+系统),而是如下所述的挂钟时间 What do 'real', 'user' and 'sys' mean in the output of time(1)?

非常感谢提前

3 个答案:

答案 0 :(得分:13)

This answers关于真实,用户和系统时间含义的精美细节。引用:

  • 'Real'是挂钟时间 - 从通话开始到结束的时间。这个 是所有经过的时间,包括其他进程使用的时间片和 进程花费的时间被阻止(例如,如果它正在等待I / O. 完成)。

  • '用户'是用户模式代码中花费的CPU时间(在...之外) 内核)在这个过程中。这只是实际使用的CPU时间 执行过程。流程花费的其他流程和时间 被阻止不计入这个数字。

  • 'Sys'是进程内核中花费的CPU时间。 这意味着执行在系统调用中花费的CPU时间 内核,而不是仍在运行的库代码 用户空间。与“用户”一样,这只是流程使用的CPU时间。

从上面的解释看,User + Sys时间应该等于CPU秒。相反,它更接近'真实'时间。奇怪!

对此有一个公平的解释。 “用户”时间包括在进程内的I / O操作上花费的CPU秒数。它只测量在内存中花费在用户模式代码上的CPU时间。经验法则是:

  

实时=用户+ sys + I / O时间+解释器启动时间+字节码编译时间

为了验证这一点,我进行了urllib2.urlopen(urllib2.Request(url))调用,进行密集的I / O.结果如下:

         100792 function calls (98867 primitive calls) in 2.076 CPU seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      512    0.719    0.001    0.719    0.001 {method 'recv' of '_socket.socket' objects}
        1    0.464    0.464    0.473    0.473 {_socket.getaddrinfo}
        1    0.352    0.352    0.352    0.352 <string>:1(connect)
        1    0.248    0.248    0.348    0.348 common_functions.py:1(<module>)
        1    0.022    0.022    0.075    0.075 __init__.py:2(<module>)
        1    0.017    0.017    0.030    0.030 urllib.py:1442(getproxies_macosx_sysconf)
   330/67    0.012    0.000    0.031    0.000 sre_parse.py:385(_parse)


real    0m2.255s
user    0m0.352s
sys 0m0.093s

此处,I / O操作(主要是_socket.socket_socket.getaddrinfo)消耗了2.076-(0.352 + 0.093),即1.631 CPU秒。其余的时间,2.255-2.076,用于冷启动代码。

希望这很有用。

更新:在多个核心系统中,多个CPU并行工作,情况略有不同。 cProfile报告的总CPU秒数是所有CPU单独花费的时间总和。例如:在2核系统中,如果一个CPU工作10秒。同时,另一个CPU工作15秒。报告的总CPU秒数为25秒。虽然实际流逝的时间可能只有15秒。因此,在多核系统中, CPU时间可能超过实时。由于CPU正在并行工作

答案 1 :(得分:7)

我对同样的问题感到困惑。

答案是cProfile使用挂钟时间。它的输出在历史上是错误的,但现在已经修复('CPU秒'中的'CPU'已被删除)。我不确切知道什么时候,但Debian 6.0中的Python 2.6.6有bug,而Debian 7.0中的Python 2.7.3则没问题。

这很令人费解,因为大多数分析器会占用CPU上的时间,而不是占用时钟。但这是一个“廉价”的探测器。

文档http://docs.python.org/2/library/profile.html#limitations解释 - 不清楚 - 时间是基于滴答作响的挂钟,而不是getrusage()或ptrace技术。

如果您检查代码(http://hg.python.org/cpython/file/44f455e6163d/Modules/_lsprof.c),则可以验证它是否为QueryPerformanceFrequency / gettimeofday。

Jerrymouse关于“时间”和cProfile时间不能重合的事实是正确的,因为cProfile只在代码编译后才开始运行。但除此之外,它的“实​​时”方程式也是假的。

wallclock和user + sys之间的区别可能在于许多不同的因素,例如代表您的进程的I / O或代表任何其他进程(包括内核本身(交换,日记等))或CPU时间花在其他进程上,或代表您的进程等待任何无法计算的进程,因为它是远程资源(网络,或通过NFS或iSCSI间接),等等。您可以命名。

答案 2 :(得分:6)

Python分析器默认测量墙上时间,但可以使用自定义计时器功能测量CPU时间。以下工作在Linux下工作,但不适用于Windows(因为time.clock测量Windows上的挂起时间):

import cProfile
import time


def idleWait():
    time.sleep(10)

def busyWait():
    t = time.time() + 10
    while time.time() < t: pass

def target():
    idleWait()
    busyWait()


print "Wall time:"
p = cProfile.Profile()
p.runcall(target)
p.print_stats()

print "CPU time:"
p = cProfile.Profile(time.clock)
p.runcall(target)
p.print_stats()

第一次配置文件运行将显示20秒,其中约一半用于time.sleep。第二个显示已过去10秒,其中没有一个花费在time.sleep