1

我目前正在将分析系统实施到应用程序中。

我有两个基于编译器标志(NDEBUG)定义的宏函数。当未定义 NDEBUG 时,这两个函数(profilingStart / profilingEnd)会生成分析报告,显示调用 profilingStart 的时间与调用 profilingEnd 的时间。

问题是可能发生不匹配——即,当 profilingStart 被调用但 profilingEnd 没有被调用时(反之亦然)。我的代码已经在运行时识别出这些情况,但如果在编译时由于这种不匹配而导致错误会更好。

一个建议是使用 do{...}while(); 构造以确保分析功能正确配对。开始宏函数将包含 do{,而结束宏将包含 }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
}
4

3 回答 3

3

在 C++ 中,一种解决方案是使用“RAII”习语。像这样的东西:

class Profiler {
  public:
    Profiler() { profilingStart(); }
    ~Profiler() { profilingEnd(); }
}

然后你像这样使用它:

{ // start of block you want to profile
    Profiler prof;
    ...
}

这将确保profilingEnd即使在存在异常、提前返回break等情况下也会调用它。也就是说,它绝对保证调用是成对的。

不过,它确实需要将您想要分析的代码放在一个块中。

[编辑]

我错过了您希望能够放入profilingEndprofilingStart.

有关如何处理此问题的想法,请参阅下面的@Roddy 评论;例如,通过析构函数检查以确保分析器在对象被析构时已停止。虽然这不会在编译时捕捉到问题,但它会在运行时捕捉到它“接近”问题。

于 2011-07-06T19:36:13.730 回答
0

为什么不直接在构造函数中创建一个对象,在构造函数中启动profile事件,在析构函数中结束,然后使用类似于scoped_lock的类,可以确保启动总是成对的。并且看到您可以创建任意范围,您可以在任何地方执行此操作

于 2011-07-06T19:36:55.427 回答
0

对于您提出的问题,我推荐@Nemo 的回答。使用 C++ 调用析构函数的能力,并坚持基本的词法作用域。

我希望你知道测量执行时间有它自己的效用,但它是一种非常间接的方法来找到“瓶颈”。(我更喜欢“时间消耗”。程序并不慢,因为它们有狭窄的地方,它们很慢,因为它们随意地做的比他们必须做的多得多。)

这里有更多关于这些问题的内容。

于 2011-07-06T21:39:50.727 回答