VC6 Profiler 问题:虚假函数调用
我在 VC6 下分析应用程序时遇到以下问题。当我分析应用程序时,分析器指示类似于以下内容的简单 getter 方法被调用了数十万次:
int SomeClass::getId() const
{
return m_iId;
};
问题是,此方法在测试应用程序中的任何位置都没有被调用 。当我将代码更改为以下内容时:
int SomeClass::getId() const
{
std::cout << "Is this method REALLY being called?" << std::endl;
return m_iId;
};
探查器从不将 getId
包含在调用的函数列表中。注释掉 cout
,我就回到了开始的地方,130 多个调用!为了确保它不是某些缓存的分析器数据或损坏的函数查找表,我在每次测试之间进行清理和重建。结果还是一样!
有什么想法吗?
I am running into the following issue while profiling an application under VC6. When I profile the application, the profiler is indicating that a simple getter method similar to the following is being called many hundreds of thousands of times:
int SomeClass::getId() const
{
return m_iId;
};
The problem is, this method is not called anywhere in the test app. When I change the code to the following:
int SomeClass::getId() const
{
std::cout << "Is this method REALLY being called?" << std::endl;
return m_iId;
};
The profiler never includes getId
in the list of invoked functions. Comment out the cout
and I'm right back to where I started, 130+ thousand calls! Just to be sure it wasn't some cached profiler data or corrupted function lookup table, I'm doing a clean and rebuild between each test. Still the same results!
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我假设您正在进行分析,因为您想了解是否有方法可以使程序花费更少的时间,对吧?您进行分析不仅仅是因为您喜欢查看数字。
有一种简单、老式、行之有效的方法来查找性能问题。当程序运行时,只需点击“暂停”按钮并查看调用堆栈。这样做几次,比如 5 到 20 次。问题越大,找到它所需的样本就越少。
有人问这是否基本上不是分析器所做的事情,答案是很少。 大多数分析器都会陷入一个或多个常见误区,导致加速效果有限因为他们没有发现所有问题:
某些程序在“热点”上花费了不必要的时间。在这种情况下,您将看到堆栈“末尾”(程序计数器所在的位置)的代码正在执行不必要的工作。
某些程序执行的 I/O 数量超出必要范围。如果是这样,您将看到它们正在执行该 I/O。
大型程序通常很慢,因为它们的调用树不必要地茂密,并且需要修剪。如果是这样,您将在堆栈中间看到不必要的函数调用。
您在一定百分比的堆栈上看到的任何代码如果被删除,都将节省该百分比的执行时间(或多或少)。你不会出错的。 这是一个示例,经过多次迭代,节省了超过 97 %。
I assume you are profiling because you want to find out if there are ways to make the program take less time, right? You're not just profiling because you like to see numbers.
There's a simple, old-fashioned, tried-and-true way to find performance problems. While the program is running, just hit the "pause" button and look at the call stack. Do this several times, like from 5 to 20 times. The bigger a problem is, the fewer samples you need to find it.
Some people ask if this isn't basically what profilers do, and the answer is only very few. Most profilers fall for one or more common myths, with the result that your speedup is limited because they don't find all problems:
Some programs are spending unnecessary time in "hotspots". When that is the case, you will see that the code at the "end" of the stack (where the program counter is) is doing needless work.
Some programs do more I/O than necessary. If so, you will see that they are in the process of doing that I/O.
Large programs are often slow because their call trees are needlessly bushy, and need pruning. If so, you will see the unnecessary function calls mid-stack.
Any code you see on some percentage of stacks will, if removed, save that percentage of execution time (more or less). You can't go wrong. Here's an example, over several iterations, of saving over 97%.
我猜想发生的事情是编译器和/或链接器将这个非常简单的函数“合并”到一个或多个相同的其他函数(为
return m_iId
生成的代码可能正是与许多其他碰巧返回具有相同偏移量的成员的 getter 相同)。本质上,一堆恰好具有相同机器代码实现的不同函数都被解析到相同的地址,这使得探查器感到困惑。
您可以通过关闭优化来阻止这种情况发生(如果这是问题所在)。
I'd guess that what's happening is that the compiler and/or the linker is 'coalescing' this very simple function to one or more other functions that are identical (the code generated for
return m_iId
is likely exactly the same as many other getters that happen to return a member that's at the same offset).essentially, a bunch of different functions that happen to have identical machine code implementations are all resolved to the same address, confusing the profiler.
You may be able to stop this from happening (if this is the problem) by turning off optimizations.