我目前正在将应用程序分析系统实现到应用程序中。
我有两个基于编译器标志(NDEBUG)定义的宏函数。当未定义NDEBUG时,这两个函数(profilingStart / profilingEnd)生成分析报告,显示调用profilingStart的时间,以及调用profilingEnd的时间。
关注的是可能发生不匹配 - 即,调用profilingStart时的情况,但profilingEnd没有(或反之亦然)。我的代码已经在运行时识别出这些情况,但如果在编译期间由于这种不匹配而导致错误,则会更好。
一个建议是使用do {...} while();构造以确保分析功能正确配对。 start宏函数将包含do {,而end macro将包含} while()。如果缺少一个,我们会在编译时遇到错误。但是,这有一些问题 - 您只能在正在分析的函数的开头和结尾使用profilingStart()和profilingEnd()调用,因为在函数中使用它们可能会影响局部变量的范围(因为do {...} while()调用可能会超出范围。
我的另一个想法是在profilingStart函数中声明一个变量,然后尝试在profilingEnd函数中修改该变量的内容。这可以防止范围问题,如果从未声明变量,则会生成编译器错误。但是,我永远不会有任何方法来验证在end函数中修改变量的内容。这只会解决问题的一半,因为它不会验证profilingEnd函数的调用。
任何评论都会一如既往地受到赞赏。提前谢谢。
编辑:关于范围我的评论可能存在一些混淆。 profilingStart()和profilingEnd()将始终在同一个函数中调用。它们可能只是在函数的开头/结尾处被调用。这是我的意思的一个例子:
int DoSomething(void)
{
profilingStart();
int a;
DoMath(a);
profilingStop();
return a; // a is out of scope here, as the do{...}while(0) construct has gone out of scope
}
答案 0 :(得分:3)
在C ++中,一种解决方案是使用“RAII”习语。像这样:
class Profiler {
public:
Profiler() { profilingStart(); }
~Profiler() { profilingEnd(); }
}
然后你就这样使用它:
{ // start of block you want to profile
Profiler prof;
...
}
即使存在异常,提前返回,profilingEnd
等,这也将确保break
被调用。也就是说,它绝对保证呼叫已配对。
但它确实需要在块中放置您想要分析的代码。
[编辑]
我错过了您希望能够将profilingEnd
放在与profilingStart
不同的块中。
请参阅下面@ Roddy的评论,了解如何处理此问题;例如通过对析构函数进行检查以确保在对象被销毁时已经停止了剖析器。虽然这不会在编译时遇到问题,但它会在运行时“接近”问题。
答案 1 :(得分:0)
为什么不创建一个在构造函数中启动配置文件事件的对象,并在析构函数中结束它,然后使用类似于scoped_lock的类,您可以确保始终配对。看到你可以创建任意范围,你可以在任何地方做到这一点
答案 2 :(得分:0)
对于你提出的问题,我推荐@ Nemo的回答。 使用C ++的能力来调用析构函数,并坚持基本的词法范围。
我希望您知道测量执行时间有其自身的效用, 但这是找到“瓶颈”的一种非常间接的方式。 (我更喜欢“时间流失”。节目不是很慢,因为它们有狭窄的地方,它们很慢,因为它们随意做的比它们要多得多。)