匹配开始/结束分析调用
Matching Start / End Profiling Calls
我目前正在一个应用程序中实现一个分析系统。
我有两个宏函数,它们是基于编译器标志(NDEBUG)定义的。当没有定义NDEBUG时,这两个函数(profilingStart/profilingEnd)生成分析报告,其中显示调用profilingStart的时间和调用profilingEnd的时间。
关注的是发生不匹配的可能性——即,当profilingStart被调用,但profilingEnd没有被调用(反之亦然)的场景。我的代码已经在运行时识别了这些情况,但如果在编译时由于这种不匹配而导致错误,则更可取。
建议使用do{…}while();构造以确保分析函数正确配对。开始宏函数将包含do{,结束宏将包含}while()。如果缺少一个,我们将在编译时得到一个错误。然而,这有一些问题——你只能在被分析的函数的开始和结束时使用profilingStart()和profilingEnd()调用,因为在函数中使用它们可能会影响局部变量的作用域(因为它们可能由于do{…}while()调用而超出作用域)。
我的另一个想法是在profilingStart函数中声明一个变量,然后尝试在profilingEnd函数中修改该变量的内容。这可以防止作用域问题,如果从未声明过变量,则会生成编译器错误。但是,我永远不会有任何方法来验证变量的内容是否在end函数中被修改了。这只解决了一半的问题,因为它没有验证profilingEnd函数的调用。
一如既往,欢迎任何评论。提前谢谢。
EDIT:关于我关于范围的评论可能会有一些混淆。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
}
在c++中,一个解决方案是使用"RAII"习语。像这样:
class Profiler {
public:
Profiler() { profilingStart(); }
~Profiler() { profilingEnd(); }
}
然后像这样使用:
{ // start of block you want to profile
Profiler prof;
...
}
这将确保即使在存在异常、早期返回、break
等情况下也会调用profilingEnd
。也就是说,它绝对保证调用是成对的。
它确实需要把你想要分析的代码放在一个块中。
[编辑]我错过了你想把profilingEnd
和profilingStart
放在不同的块中。
看看下面@Roddy的评论,看看如何处理这个问题;例如,通过析构函数检查来确保分析器在对象被析构时已经停止。虽然这不会在编译时捕获问题,但它会在运行时"接近"问题时捕获它。
为什么不直接创建一个对象,在构造函数中启动概要文件事件,并在析构函数中结束它,然后使用类似于scoped_lock的类,您可以确保启动总是配对的。可以创建任意作用域,可以在任意位置
对于你的问题,我推荐@Nemo的答案。使用c++调用析构函数的能力,并坚持基本的词法作用域。
我希望你意识到测量执行时间有它自己的用途,但这是一种寻找"瓶颈"的非常间接的方法。(我更喜欢"浪费时间"。程序之所以慢,不是因为它们的位置狭窄,而是因为它们随意地做了比必须做的更多的事情。
- 当调用switch语句中的函数时(即使函数不包含循环),似乎是永不结束的循环的问题
- 钩/绕道 d3d9 (现在/结束场景) - 似乎调用我的函数然后崩溃
- 防止我的向量在调用它的函数结束时被删除
- 在新作用域中使用unique_lock是否等效于在使用共享资源的工作结束时解锁调用
- 如何在动画结束后调用函数
- 将数组作为函数参数传递,并在其上调用开始/结束方法
- 如何从另一个函数中调用的函数结束程序 (C++)
- 嵌套asio调用在__throw_bad_function_call()中结束
- 被调用的函数究竟什么时候结束
- C++ 指针上的开始/结束 (arr) - 调用 'begin(int**&)' 没有匹配函数
- SkipLastField 调用了结束组标签.GoogleProtobuf(C#和C++)
- mfc应用程序结束后,CMainFrame的析构函数调用发生访问冲突
- 加密++异常调用消息结束
- 为什么析构函数在对象引用作为参数传递时函数范围结束后调用
- C++ - 如果在循环中声明对象,是否在循环结束时调用其析构函数
- 通过 using-指令调用开始和结束
- 如何确定调用堆栈的结束
- 在不调用析构函数的情况下结束STL容器的生存期
- OBJ 应该在函数调用结束时被销毁'f'
- 为什么方法调用结束复制构造函数