不知何故与这个问题有关,你会推荐哪个工具来评估用 callgrind 创建的分析数据?
它不必有图形界面,但它应该以简洁、清晰和易于解释的方式准备结果。我知道 eg kcachegrind
,但是这个程序缺少一些功能,例如显示的表格的数据导出或简单地从显示中复制行。
不知何故与这个问题有关,你会推荐哪个工具来评估用 callgrind 创建的分析数据?
它不必有图形界面,但它应该以简洁、清晰和易于解释的方式准备结果。我知道 eg kcachegrind
,但是这个程序缺少一些功能,例如显示的表格的数据导出或简单地从显示中复制行。
有一些 CLI 工具可用于处理 callgrind 数据:
callgrind_annotate
和 cachegrind 工具,它可以显示来自 callgrind.out 的一些信息
cg_annotate
几年前,我写了一个分析器来在 DOS 下运行。
如果您使用的是 KCacheGrind,这就是我要做的。编写它可能不会太难,或者您可以手动完成。
KCacheGrind 有一个工具栏按钮“强制转储”,您可以使用它在随机时间手动触发转储。在等待程序的时间间隔内随机或伪随机时间捕获堆栈跟踪是该技术的核心。
需要的样本并不多——通常 20 个就足够了。如果一个瓶颈成本很高,比如超过 50%,5 个样本可能就足够了。
样品的处理非常简单。每个堆栈跟踪都由一系列代码行(实际上是地址)组成,其中除了最后一行之外都是函数/方法调用。
收集样本上出现的所有代码行的列表,并消除重复项。
对于每一行代码,计算它出现在样本中的比例。例如,如果您取 20 个样本,并且代码行出现在其中 3 个样本上,即使它在某个样本中出现多次(由于递归),计数也是 3/20 或 15%。这是对每个语句成本的直接衡量。
显示成本最高的 100 行左右的代码。您的瓶颈在该列表中。
我通常用这些信息做的是选择一条成本很高的行,然后手动获取堆栈样本直到它出现(或查看我已经得到的那些),然后问自己“为什么要执行那行代码,不仅在局部意义上,而且在全球意义上。” 另一种说法是“在全局意义上,程序在采样时试图在时间片上完成什么”。我问这个的原因是因为这告诉我是否真的有必要花费这条线的成本。
我不想批评人们开发分析器所做的所有伟大工作,但遗憾的是,关于这个主题有很多根深蒂固的神话,包括:
使用大量样品进行精确测量很重要。相反,重点应该放在寻找瓶颈上。精确测量不是这样做的先决条件。对于成本在 10% 到 90% 之间的典型瓶颈,测量可能非常粗略。
功能比代码行更重要。如果你找到一个代价高昂的函数,你仍然需要在其中搜索成为瓶颈的行。该信息就在堆栈跟踪中 - 无需寻找它。
您需要将 CPU 与挂钟时间区分开来。如果你在等它,那就是挂钟时间(手表时间?)。例如,如果您有一个由无关 I/O 组成的瓶颈,您是否想忽略它,因为它不是 CPU 时间?
独占时间和包含时间之间的区别是有用的。仅当您正在计时功能并且您想知道时间是否花在被调用者上时才有意义。如果您查看代码行,唯一重要的是包含时间。另一种说法是,每条指令都是一条调用指令,即使它只调用微码。
递归很重要。这是无关紧要的,因为它不会影响线路所在的样本分数,因此是负责的。
行或函数的调用计数很重要。无论是快速调用太多次,还是慢速调用一次,成本都是它使用的时间百分比,这就是堆栈样本估计的值。
采样的性能很重要。我不介意获取堆栈样本并在继续之前查看几分钟,假设这不会使瓶颈移动。
这是一个更完整的解释。