moo*_*dow 3 c++ gcc profiling gprof
我正在尝试对支持不佳的原型嵌入式平台进行一些性能分析.
我注意到GCC的-pg标志导致__gnu_mcount_nc在每个函数的入口处插入thunk .没有__gnu_mcount_nc可用的实现(并且供应商对协助不感兴趣),但是因为编写一个简单记录堆栈帧和当前循环计数的操作是微不足道的,所以我已经这样做了; 这工作正常,并且在调用者/被调用者图和最常被称为函数方面产生有用的结果.
我真的想获得有关在函数体中花费的时间的信息,但是我很难理解如何只使用条目而不是退出来解决这个问题,每个函数都被钩住了:你可以确切地知道每个函数的确切时间输入,但没有挂钩退出点,你不知道多少时间,直到你收到下一条信息属于被叫者和呼叫者多少.
尽管如此,GNU概要分析工具实际上可以在许多平台上收集函数的运行时信息,因此可能开发人员在实现这一目标时需要考虑一些方案.
我已经看到一些现有的实现,它们执行诸如维护阴影调用堆栈并将入口处的返回地址旋转到__gnu_mcount_nc,以便在被调用者返回时再次调用__gnu_mcount_nc; 然后,它可以将调用者/被调用者/ sp三元组与影子调用堆栈的顶部进行匹配,从而将此案例与条目调用区分开来,记录退出时间并正确返回调用者.
这种方法还有很多不足之处:
是否有一些明显更好的方法来实现__gnu_mcount_nc,以便-pg构建能够捕获函数退出以及我缺少的入口时间?
Mik*_*vey 14
gprof不使用该函数进行计时,进入或退出,而是对函数A的调用计数调用任何函数B.相反,它使用通过计算每个例程中的PC样本收集的自身时间,然后使用函数 -到功能呼叫计数,以估计应该向呼叫者收取多少自助时间.
例如,如果A调用C 10次,B调用C 20次,并且C具有1000ms的自身时间(即100个PC样本),则gprof知道C已被调用30次,并且33个样本可以被调用到A,而另一个67可以充电到B.同样,样本计数在呼叫层次结构中向上传播.
所以你看,它没有时间函数进入和退出.它所获得的测量非常粗糙,因为它不区分短呼叫和长呼叫.此外,如果在I/O期间或未使用-pg编译的库例程中发生PC样本,则根本不计算.并且,正如您所指出的,它在递归的情况下非常脆弱,并且可能在短函数上引入显着的开销.
另一种方法是堆栈采样,而不是PC采样.当然,捕获堆栈样本比PC样本更昂贵,但需要更少的样本.例如,如果函数,代码行或任何描述想要在N个样本的总和中得到明显的分数F,那么您就知道它所花费的时间部分是F,具有标准偏差sqrt(NF(1-F)).因此,例如,如果您采用100个样本,并且其中50个样本出现一行代码,那么您可以在50%的时间内估算行成本,并且不确定性为sqrt(100*.5*.5)= +/- 5个样本或45%到55%之间.如果您采用100倍的样本,则可以将不确定性降低10倍.(递归无关紧要.如果函数或代码行在单个样本中出现3次,则计为1个样本,而不是3个样本如果函数调用很短也没关系 - 如果它们被调用足够多次以花费很大一部分,它们将被捕获.)
请注意,当您正在寻找可以修复以获得加速的东西时,确切的百分比并不重要.重要的是找到它.(事实上,你只需要看两次问题就知道它足够大了.)
这就是这种技术.
PS不要被称为呼叫图,热路径或热点.这是一个典型的呼叫图鼠巢.黄色是热路,红色是热点.

这表明在这些地方没有多少加速机会是多么容易:

最值得关注的是十几个随机原始堆栈样本,并将它们与源代码相关联.(这意味着绕过探查器的后端.)
补充:为了表明我的意思,我从上面的调用图中模拟了10个堆栈样本,这就是我发现的内容
class_exists,一个用于获取类名,另外两个用于设置本地配置.class_exists呼叫autoload哪些呼叫requireFile,以及其中两个呼叫adminpanel.如果这可以更直接地完成,它可以节省大约30%.determineId,这些呼叫呼叫fetch_the_id哪个呼叫getPageAndRootlineWithDomain,它们呼叫另外三个级别,终止于sql_fetch_assoc.获得一个ID似乎很麻烦,并且它花费了大约20%的时间,并且不计算I/O.因此,堆栈样本不仅告诉您函数或代码行的成本占用时间,它们告诉您为什么要完成它,以及完成它所需的愚蠢.我经常看到这种 - 疾驰的普遍性 - 用锤子拍打苍蝇,不是故意的,而只是遵循良好的模块化设计.
补充:另一件不被吸引的是火焰图.例如,这里是来自上面调用图的十个模拟堆栈样本的火焰图(向右旋转90度).例程都是编号,而不是命名,但每个例程都有自己的颜色.

注意我们上面确定的问题,其中class_exists(例程219)在30%的样本上,通过查看火焰图并不明显.更多样本和不同颜色会使图形看起来更像"火焰状",但不会暴露通过从不同位置多次调用而花费大量时间的例程.
这是按功能而不是按时间排序的相同数据.这有点帮助,但不会聚集来自不同地方的相似性:

再一次,目标是找到隐藏在你身上的问题.任何人都可以找到容易的东西,但隐藏的问题是那些让一切变得不同的问题.
添加:另一种眼睛糖果是这一个:
黑色概述的例程可能都是相同的,只是从不同的地方调用.该图表不会为您聚合它们.如果例程具有较高的包含百分比,则通过从不同位置多次调用它,它将不会被暴露.
| 归档时间: |
|
| 查看次数: |
2836 次 |
| 最近记录: |