Python代码中的捕捉性能-CPU分析(解释器)

在这篇文章中,我将介绍一些工具和方法,可以在运行Python脚本时对剖析器进行剖析。

就像在我们之前的文章中一样,CPU分析的含义是一样的,但是现在我们不是针对Python脚本的。相反,我们想知道Python解释器是如何工作的,以及在运行我们的Python脚本时花费多少时间。

接下来我们将看到如何跟踪CPU使用情况,并找到解释器中的热点。

系列索引

一旦帖子发布,下面的链接将会生效:

  1. 建立
  2. 内存分析
  3. CPU分析 - Python脚本
  4. CPU分析 - Python解释器

测量CPU使用率

对于这篇文章,我将主要使用与内存分析和脚本CPU使用相同的脚本,您可以在下面或在这里看到它

import time


def primes(n):
    if n == 2:
        return [2]
    elif n < 2:
        return []
    s = []
    for i in range(3, n+1):
        if i % 2 != 0:
            s.append(i)
    mroot = n ** 0.5
    half = (n + 1) / 2 - 1
    i = 0
    m = 3
    while m <= mroot:
        if s[i]:
            j = (m * m - 3) / 2
            s[j] = 0
            while j < half:
                s[j] = 0
                j += m
        i = i + 1
        m = 2 * i + 3
    l = [2]
    for x in s:
        if x:
            l.append(x)
    return l


def benchmark():
        start = time.time()
        for _ in xrange(40):
                count = len(primes(1000000))
        end = time.time()
        print "Benchmark duration: %r seconds" % (end-start)


benchmark()


优化后的版本是bellow或here:

import time


def primes(n):
    if n==2:
        return [2]
    elif n<2:
        return []
    s=range(3,n+1,2)
    mroot = n ** 0.5
    half=(n+1)/2-1
    i=0
    m=3
    while m <= mroot:
        if s[i]:
            j=(m*m-3)/2
            s[j]=0
            while j<half:
                s[j]=0
                j+=m
        i=i+1
        m=2*i+3
    return [2]+[x for x in s if x]


def benchmark():
        start = time.time()
        for _ in xrange(40):
                count = len(primes(1000000))
        end = time.time()
        print "Benchmark duration: %r seconds" % (end-start)


benchmark()


CPython

CPython是多功能的,完全用C编写,因此更容易测量和/或配置文件。您可以在这里找到在GitHub上托管的CPython的源代码默认情况下,你会看到最新的分支,在写这个的时候是3.7+,但是所有其他的分支都可以下到2.7。

在我们的帖子中,我们将重点介绍CPython 2,但同样的步骤可以成功应用到最新的3版本。

代码覆盖工具

查看正在运行的C代码部分的最简单方法之一是使用代码覆盖率工具。

我们首先克隆回购:

git clone  https://github.com/python/cpython / 
cd cpython 
git checkout 2.7 
./configure

复制目录中的脚本并运行以下命令:

make coverage
./python 04.primes-v1.py
make coverage-lcov

第一行将编译GCOV支持的解释器,第二行将运行工作负载并收集.gcda文件中的分析数据,第三行解析包含分析数据的文件,并在名为的文件夹中创建一堆HTML文件lcov-report

如果我们index.html在浏览器中打开,我们可以看到解释器源代码中被执行的位置来运行我们的Python脚本。你会看到像下面的东西:


在顶层,我们可以看到构成源代码的每个目录以及覆盖的代码量。例如,我们打开Objects 目录,  listobject.c.gcov.html文件。虽然我们不会完全解读,但我们分析一部分。看下面的部分。



如何阅读?在黄色的列上,你可以看到来自C文件代码的行号。在下一列中,您可以看到特定行被执行的次数。在最右边的列中,您可以看到实际的C源代码。

在这个例子中,这个方法listiter_next被称为6000万次。

我们是如何得到这个功能的?如果我们仔细看看我们的Python脚本,我们观察到它使用了很多列表迭代并追加。(另一点可以导致脚本优化首先

让我们继续其他一些专用工具。

PERF

有关更多信息,我们可以使用perfLinux系统上提供工具。官方文档可以在这里阅读

我们(重新)使用以下内容构建CPython解释器。如果你没有在同一个目录中下载Python脚本,你应该这样做。另外,请确保perf 已安装在您的系统上。

make clean
./configure --with-pydebug
make

运行perf 如下。Brendan Gregg写的这个优秀的页面可以看到更多的使用perf的方法

sudo perf record ./python 04.primes-v1.py

运行脚本之后,您将看到如下所示的内容:

Benchmark duration: 32.03910684585571 seconds
[21868 refs]
 perf record: Woken up 20 times to write data ]
[ perf record: Captured and wrote 4.914 MB perf.data (125364 samples) ]

要查看结果,运行`sudo ​perf report` 以获得度量。


只有最有趣的电话才能被保存。在上面的屏幕中,我们看到花费的时间最多PyEval_EvalFrameEx这是主要的解释器循环,我们对这个例子不感兴趣。相反,我们感兴趣的是下一个耗时的功能 -   listiter_next占用10.70%的时间。

运行优化版本后,我们看到以下内容:



经过我们的优化,该listiter_next 功能只消耗了2.11%的时间。读者可以根据口译员的情况做进一步的优化。

Valgrind的/ Callgrind

另一个可以用来查找瓶颈的工具是Valgrind,它的一个叫做callgrind的插件。更多细节可以在这里阅读

如果尚未完成,我们(重新)使用以下内容构建CPython解释器。如果你没有在同一个目录中下载Python脚本,你应该这样做。另外,请确保valgrind 已安装在您的系统上。

make clean 
./configure --with-pydebug 
make

运行valgrind 如下:

valgrind --tool=callgrind --dump-instr=yes \
--collect-jumps=yes --collect-systime=yes \
--callgrind-out-file=callgrind-%p.out -- ./python 04.primes-v1.py

结果是:

Benchmark duration: 1109.4096319675446 seconds
[21868 refs]
==24152== 
==24152== Events : Ir sysCount sysTime
==24152== Collected : 115949791666 942 208
==24152== 
==24152== I refs: 115,949,791,666

为了可视化,我们将使用KCacheGrind

kcachegrind callgrind-2327.out

PyPy

在PyPy上,可以成功使用的配置文件是非常有限的,恢复到vmprof,一个由开发PyPy的人写的工具。

首先,从这里下载PyPy 在此之后,启用pip 对它的支持

bin/pypy -m ensurepip

安装vmprof很简单,只需运行:

bin/pypy -m pip install vmprof

运行工作量为:

bin/pypy -m vmprof --web 04.primes-v1.py


并在浏览器中打开控制台中显示的链接(以http://vmprof.com/#/开头  




作者:Alecsandru Patrascu,alecsandru.patrascu [at] rinftech [dot] com

原文:https://pythonfiles.wordpress.com/2017/08/24/hunting-performance-in-python-code-part-4/




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值