返回介绍

6.6 告诫故事:验证你的优化(scipy)

发布于 2024-01-25 21:44:08 字数 2371 浏览 0 评论 0 收藏 0

重要的是记住我们在本章中对每一次优化使用的一套方法:首先对代码进行性能分析来感知问题可能出在哪,提出一个可能的解决方案来修改慢的那部分,然后再次进行性能分析来确保我们的修改可行。虽然这听上去十分简单直接,但事情很快会变得复杂,比如我们看到numexpr的性能是如何受到矩阵大小影响的。

当然我们提出的方案并不总是可行。在为本章写代码时,有一次作者看到laplacian函数最慢并假设scipy的函数会明显更快。这一想法来自于一个事实,那就是laplacian在图像分析这一行是一个常见操作,可能已经有一个非常优化的库加速了其运行的速度。scipy正好有一个图像子模块,我们一定会得到幸运的眷顾!

用scipy实现起来很简单(例6-21)且不需要考虑实现周期边界的复杂度(因为scipy的wrap模式会帮我们搞定)。

例6-21 使用scipy的laplace滤波

from scipy.ndimage.filters import laplace

def laplacian(grid, out):
  laplace(grid, out, mode='wrap')

能够简单实现这一点相当重要,且绝对为这个函数赢得了一些分数,在我们考查性能之前。然而一旦我们对scipy代码进行性能对比(例6-22),我们才发觉:这个函数跟之前的相比(例6-14)并没有带来大量的速度提升。事实上,当我们增加矩阵大小时,这个函数甚至开始变得性能下降了(见本章最后的图6-4)。

例6-22 使用scipy的laplacian函数的扩散代码性能指标

$ perf stat -e cycles,stalled-cycles-frontend,stalled-cycles-backend,instructions,\ cache-references,cache-misses,branches,branch-misses,task-clock,faults,\ minor-faults,cs,migrations -r 3 python diffusion_scipy.py Performance counter stats for 'python diffusion_scipy.py' (3 runs): 6,573,168,470 cycles # 2.929 GHz 3,574,258,872 stalled-cycles-frontend # 54.38% frontend cycles idle 2,357,614,687 stalled-cycles-backend # 35.87% backend cycles idle 9,850,025,585 instructions # 1.50 insns per cycle # 0.36 stalled cycles per insn 415,930,123 cache-references # 185.361 M/sec 3,188,390 cache-misses # 0.767 % of all cache refs 1,608,887,891 branches # 717.006 M/sec 4,017,205 branch-misses # 0.25% of all branches 2243.897843 task-clock # 0.994 CPUs utilized 7,319 page-faults # 0.003 M/sec 7,319 minor-faults # 0.003 M/sec 12 context-switche # 0.005 K/sec 1 CPU-migrations # 0.000 K/sec 2.258396667 seconds time elapsed

对比scipy版本和我们自己的laplacian函数性能指标(例6-18),我们可以得到一些提示,为什么没有从这次重写中得到期待的性能提升。

指标中最突出的是page-faults和instructions。scipy版本的指标中两者的值都明显更大。page-faults的增加显示出scipy的laplace函数虽然支持就地操作,但它依然分配了很多内存。事实上scipy版本的page-faults的次数比我们第一次用numpy重写的版本还要多(例6-15)。

但更严重的还是instructions指标。它告诉我们scipy代码比我们的laplacian函数让CPU多做了超过两倍的工作。即使这些指令都是更加优化的(因为我们可以看到更高的insns per cycle计数,也就是CPU在一个时钟周期内能完成多少条指令),额外的优化并没有能胜过指令数的猛增。这可能部分是因为scipy代码写得非常通用,以使它可以处理具有不同边界条件的各种输入(所以需要额外的代码也就是更多的指令数)。事实上这一点我们也可以通过scipy代码拥有更多的branches指标看出。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文