我该如何解释OProfile输出?

我最近尝试使用OProfile分析我的应用程序。收集的数据对我来说已经非常有价值,但我对它的精确解释有困难。运行我的应用程序并设置并运行oprofile之后,我生成了报告并获得:   root @ se7xeon:src#opreport image:test -l -t 1   溢出统计数据不可用   CPU:P4 / Xeon,带2个超线程,速度3191.66 MHz(估计)   计算GLOBAL_POWER_EVENTS事件(处理器未停止的时间),单位掩码为0x01(强制)计数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%以上。开括号和函数声明似乎需要时间,是否应该对应于函数调用开销(“在堆栈上跳过参数,跳转,弹出参数”序列)? 我改变了源代码中的一些东西(与后来的瓶颈相关,因为我不知道如何优化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;  
:               }  
这次if基本上没有时间(?),最昂贵的指令是“col1 = col0 + 1”,整个时间块似乎已向上移动。怎么会这样?是否可以信任来查明源代码中的瓶颈? 另一个值得怀疑的是,当我设置opcontrol时,我以GLOBAL_POWER_EVENTS的形式输入了跟踪事件,样本数为750k。在输出中,插值函数似乎占84%,但其中记录的样本数量仅略高于200k。这甚至不是所要求数量的50%。我是否理解剩余的~500k样本是由未在输出中列出的应用程序(内核,Xorg等)获取的?     
已邀请:
在分析优化代码时,您实际上无法依赖准确的源代码行。编译器移动的东西太多了。 要获得准确的图片,您需要查看代码反汇编程序输出。     
OProfile可以(他们告诉我)在挂钟时间(而非CPU)上获取堆栈样本,它可以为您提供行级别百分比。您正在寻找的是大量堆栈样本中包含的行。 在我完成手动调整代码之前,我不打开编译器优化,因为它只是隐藏了一些东西。 当你说插值例程使用84%的时间时,会触发一个问题。整个程序需要一些时间,对吗?这需要100%的时间。如果你将程序的时间缩短一半,或者你把它加倍,它仍然需要100%的时间。插值的84%是否过多取决于它是否超出必要的范围。 所以我建议你不要问一个例程的百分比是否过多。相反,你会寻找占用大量时间的代码行,并询问它们是否可以进行优化。看到不同?在优化代码之后,它可以大大减少总体运行时间,但它可能仍然是一个很大的百分比,总数较小。 当没有什么需要很大的代码时,代码不是最佳的。 代码是最佳的,当所有的事情占很大比例,没有一个可以改善。 我不关心只提供数字的事情。我想要的是洞察力。例如,如果该例程占84%的时间,那么如果您采用堆栈的10个样本,那么它将是8.4个。确切的数字并不重要。重要的是理解为什么它在那里。真的有必要在那里吗?这就是看堆栈样本可以告诉你的。也许你实际上在必要时经常进行插值两次?人们常常通过分析原因找出他们试图加速的例程并不需要被调用,也许根本不需要调用。在你的情况下,我无法猜测。只有检查程序状态的见解才能告诉你。     

要回复问题请先登录注册