我该如何解释OProfile输出?

我最近试图用OProfile来分析我的应用程序。 收集到的数据对我来说已经很有价值了,但是我的确切解释还是有困难的。 运行我的应用程序与oprofile设置和运行后,我生成的报告,并得到:

root @ se7xeon:src#opreport image:test -l -t 1
溢出统计信息不可用
CPU:带有2个超线程的P4 / Xeon,速度3191.66 MHz(估计)
计数GLOBAL_POWER_EVENTS事件(处理器未停止的时间),单位掩码为0x01(必需)count 750000
样本%符号名称
215522 84.9954 cci :: Image :: interpolate(unsigned char *,cci :: Matrix const&)const
17998 7.0979 cci :: Calc :: diff(unsigned char const *,unsigned char const *)
13171 5.1942 cci :: Image :: getIRect(unsigned char *,int,int)const
5519 2.1765 cci :: Image :: getFRect(unsigned char *,double,double)const

好的,所以我的插值函数负责84%的应用程序(太长)的执行时间。 似乎是一个好主意,然后看看它:

root @ se7xeon:src#opannotate image:test –source
[…]

/* cci::Image::interpolate(unsigned char*, cci::Matrix<cci::Point2DF> const&) const total: 215522 84.9954 */ 1392 0.5529 :void Image::interpolate(CCIPixel *output, const Matrix<Point2DF> &inputPoints) const throw() 4 0.0016 :{ [...] : col0 = static_cast<int>(point[idx].x); 3 0.0012 : col1 = col0+1; 629 0.2498 : row0 = static_cast<int>(point[idx].y); 385 0.1529 : row1 = row0+1; 56214 22.3266 : if (col0 < 0 || col1 >= m_width || row0 < 0 || row1 >= m_height) : { : col0 = row0 = col1 = row1 = 0; : } 

如果我理解正确,if条件是超过22%的程序执行时间的责任。 大括号和函数声明似乎需要时间,是否应该对应于函数调用开销(“堆栈,跳转,popup参数”序列上的推参数)?

我改变了源代码中的一些东西(涉及到后来的瓶颈,因为我不知道如何优化if),重新编译,再次运行oprofile(不要忘记opcontrol –reset)。 现在注释的代码看起来像这样在同一个地方:

 6 0.0024 : curPx = point[idx].x; 628 0.2477 : curPy = point[idx].y; 410 0.1617 : col0 = static_cast<int>(curPx); 57910 22.8380 : col1 = col0+1; : row0 = static_cast<int>(curPy); : row1 = row0+1; : if (col0 < 0 || col1 >= m_width || row0 < 0 || row1 >= m_height) : { : col0 = row0 = col1 = row1 = 0; : } 

这次如果基本没有时间(?),最昂贵的指令是“col1 = col0 + 1”,整个计时块似乎向上移动。 怎么会这样? 这是否值得信任,以查明来源的瓶颈?

另一个值得怀疑的是,当我设置opcontrol的时候,我以GLOBAL_POWER_EVENTS的formsinput了跟踪事件,样本数是750k。 在输出中,插值函数似乎需要84%,但其内部logging的采样数量只有200k以上的一点点。 这甚至不是要求数量的50%。 我能理解剩下的〜500k个样本是否被输出(kernel,Xorg等)中未列出的应用程序占用?

分析优化的代码时,您确实无法依赖准确的源代码行。 编译器移动的东西太多了。

要获得准确的图片,您需要查看代码反汇编器输出。

OProfile可以(他们告诉我)在挂钟时间(而不是CPU)上获取堆栈样本,并且可以为您提供行级别的百分比。 你正在寻找的是大量的堆栈样本中包含的行。

在我完成手动调整代码之前,我不会打开编译器优化,因为它只是隐藏了一些东西。

当你说内插程序使用84%的时间,这触发了一个问题。 整个程序需要一些总时间,对吧? 这需要100%的时间。 如果你把计划的时间减半,或者如果你加倍,它仍然会占用100%的时间。 插值的84%是否过多取决于是否超出必要的范围。

所以我建议你不要问一个例程的百分比是否太多。 而是你寻找需要大量时间的代码行,并询问是否可以优化。 看到不同? 在优化代码之后,它可以大大减少整体运行时间,但是它可能仍然是一个很大的百分比,总的来说还是很小的。 代码不是最佳的时候没有什么需要大量的百分比。 代码是最好的,当所有的东西占用很大的百分比,没有一个是可以改进的。

我不在乎只给数字的东西。 我想要的是洞察力。 例如,如果这个例程占了84%的时间,那么如果你拿了10个样本的话 ,那么就是8.4 个样本 。 确切的数字并不重要。 重要的是要明白为什么在那里。 真的有必要这么做吗? 这就是看堆栈样本可以告诉你。 也许你实际上需要两次插值? 通常人们通过分析原因 ,发现他们试图加速的程序并不需要被调用得差不多,也许根本就没有。 我不能猜测你的情况。 只有从检查程序状态的洞察力可以告诉你。