当我们的多线程程序遇到性能问题时,通常我们会下意识地觉得这是由于上下文切换、cpu 迁移等因素导致的。那么,如何更进一步地分析究竟是哪一部分语句造成了什么样的影响呢?这篇分享将从计算机体系结构的角度,结合非常典型的代码案例,为你解惑。
在进入正题之前,如果对缓存还不了解的读者,可以先看看这篇分享。
DeepRoute Lab | 【C++性能】CPU Cache Serial 1
01
引子
1.1 第一个代码片段
(点击查看大图)
1.2 第二个代码片段
(点击查看大图)
1.3 转置
代码片段一里面,GoodWorker的效率(计算的耗时)
是 BadWorker 的 10 倍左右(取决于具体硬件条件和其他相关因素)。
在不知道其他背景知识的前提下,我们怎么来定位这个问题呢?
-
加耗时的打印?
- 不好意思,面对这种已经只剩大量基本操作的代码,没法做到更细粒度的耗时打印了。
-
看火焰图?
(点击查看大图)
可以看到,除了 GoodWorker 在整个 workload 上的占比(83%)比 BadWorker (96%) 略低以外(也不能提供其他进一步的指导意义了), 两个函数在火焰图上都可谓是“一马平川”,火焰图在这种情况下也失去了指导意义。
难道就没有任何办法了吗?
开什么玩笑,如果没有办法,这篇文章也就写不下去了!
那么答案是什么呢!
02
Perf Events 初探
2.1 代码片段一的性能数据
在详细介绍 perf events 之前,让我们直观地通过数据来体会一下它在分析这类问题上的强大之处。
下面所有类似的结果均采用 perf events 生成。
(点击查看大图)
以上分别是 BadWorker 和 GoodWorker 使用 Perf Events 诊断的结果,可以看到已经有大量的差异巨大的数值和比例了。