正如 Öö Tiib 建议的那样,只需在调试器中中断程序即可。我这样做的方法是让程序运行,切换到输出窗口,键入 Ctrl-C 中断程序,切换回 GDB 窗口,键入“线程 1”以便在主程序的上下文中,并键入“bt”以查看堆栈跟踪。
现在,查看堆栈跟踪并理解它,因为虽然程序计数器处的指令负责所花费的特定周期,但堆栈上的每个调用也是如此。
如果您这样做几次,您将确切地看到哪条线路是造成瓶颈的原因。只要您在两 (2) 个样品上看到它,您就已经掌握了它。然后修复它并再次执行所有操作,找到下一个瓶颈,依此类推。你可以很容易地发现你通过这种方式获得了巨大的加速。
<火焰>
有人说这正是分析器所做的,只是他们做得更好。这就是您在演讲厅和博客上听到的内容,但事实是这样:有一些方法可以加速您的代码,这些方法不会显示为“慢函数”或“热路径”,例如 - 重新组织数据结构。每个函数看起来或多或少是无辜的,即使它具有很高的包容时间百分比。
如果您实际查看堆栈样本,它们确实会显露出来。因此,好的分析器的问题不在于样本的收集,而在于结果的呈现。统计和测量无法告诉您经过仔细检查的一小部分样本能告诉您什么。
小样本与大量样本的问题呢?不是更好吗?好的,假设你有一个无限循环,或者如果不是无限循环,它只是运行的时间比你知道的要长得多?1000 个堆栈样本会比单个样本更好吗?(不。)如果你在调试器下查看它,你就会知道你在循环中,因为它基本上需要 100% 的时间。它在某处的堆栈上 - 只需向上扫描堆栈直到找到它。即使循环只占用 50% 或 20% 的时间,这也是每个样本看到它的概率。因此,如果您看到只需两个样本就可以摆脱的东西,那么值得这样做。那么,这 1000 个样品能给你带来什么?
也许有人会想:“那如果我们错过一两个问题怎么办?也许已经足够了。” 嗯,是吗?假设代码有三个问题,P 占 50%,Q 占 25%,R 占 12.5%。好东西被称为 A。这显示了如果你修复其中一个、两个或三个都得到的加速。
PRPQPQPAPQPAPRPQ original time with avoidable code P, Q, and R all mixed together
RQQAQARQ fix P - 2 x speedup
PRPPPAPPAPRP fix Q - 1.3 x "
PPQPQPAPQPAPPQ fix R - 1.14 x "
RAAR fix P and Q - 4 x "
QQAQAQ fix P and R - 2.7 x "
PPPPAPPAPP fix Q and R - 1.6 x "
AA fix P, Q, and R - 8 x speedup
这是否说明了为什么“逃跑”的人真的很受伤?如果你错过任何一个,你能做的最好的就是慢两倍。
如果您检查样品,它们很容易找到。P 在一半的样本上。如果您修复 P 并再次执行此操作,则 Q 在一半的样本上。一旦你修复了 Q,R 就在一半的样本上。修复 R,你的加速是 8 倍。你不必停在那里。你可以继续前进,直到你真的找不到任何可以修复的东西。
问题越多,潜在的加速就越高,但你不能错过任何一个。剖析器(即使是好的剖析器)的问题在于,通过剥夺您查看和研究单个样本的机会,它们隐藏了您需要发现的问题。
更多关于这一切。
对于统计倾向,这是它的工作原理。
有很好的分析器。最好的是墙上时间堆栈采样器,它可以报告各个行的包含百分比,让您可以使用热键打开和关闭采样。
Zoom ( wiki ) 就是这样一个分析器。
但即使是那些假设你需要大量样本的错误。你没有,你为它们付出的代价是你实际上看不到任何东西,所以你看不到为什么要花费时间,所以你不能轻易判断它是否有必要,而且你不能摆脱一些东西,除非你知道你不需要它。结果是你错过了瓶颈,它们最终阻碍了你的加速。
</火焰>