在发布版本中与OutputDebugString关联的开销

Can*_*pus 18 windows performance winapi logging

在发布版本中调用OutputDebugString会产生很大的开销吗?

sha*_*oth 15

测量--10M通话大约需要50秒.我认为这对未使用的功能来说是一个巨大的开销.

使用宏可以帮助在发布版本中摆脱这个:

#ifdef _DEBUG
    #define LOGMESSAGE( str ) OutputDebugString( str );
#else
    #define LOGMESSAGE( str )
#endif
Run Code Online (Sandbox Code Playgroud)

不仅删除了调用,而且还完全删除了参数评估和文本字符串,您将不会在二进制文件中看到它们.


era*_*ran 12

在这个问题得到解答之后,我写这篇文章很久了,但给定的答案错过了某个方面:

当没有人正在监听其输出时,OutputDebugString可以非常快.然而,其在后台运行的监听器(无论是DBGVIEW,DBWin32时,Visual Studio等)可以使其超过10倍慢(在MT环境更多).原因是这些侦听器挂钩了报表事件,并且它们对事件的处理是在OutputDebugString调用的范围内完成的.此外,如果多个线程同时调用OutputDebugString,它们将被同步.有关更多信息,请参阅注意:DebugView(OutputDebugString)和性能.

作为旁注,我认为除非您正在运行实时应用程序,否则您不应该担心需要50秒才能运行10M呼叫的设施.如果您的日志包含10M条目,那么浪费的50秒是您遇到的问题中最少的,现在您必须以某种方式分析该野兽.一个10K的日志听起来更合理,根据sharptooth的测量创建只需0.05秒.

因此,如果您的输出在合理的大小范围内,使用OutputDebugString不会对您造成太大伤害.但是,请记住,一旦系统上有人开始收听此输出,就会发生减速.


aJ.*_*aJ. 9

我在一篇文章中读到OutPutDebugString内部做了一些有趣的事情:

  1. 创建\打开互斥锁并无限等待直到获取互斥锁.
  2. 在应用程序和调试器之间传递数据是通过一个4kbyte的共享内存块完成的,Mutex和两个Event对象保护对它的访问.

即使没有附加调试器(在发布模式下),使用OutputDebugstring和使用各种内核对象也会产生很大的成本.

如果您编写示例代码并进行测试,性能影响非常明显.


Bob*_*ore 8

多年来,我没有在数十个服务器端发布模式应用程序中看到任何问题,所有这些应用程序都具有内置指标.你可以得到它很慢的印象,因为你可以找到的大多数调试捕获器应用程序(DBWIN32等)在将数据投放到屏幕上的速度非常慢,这给人一种滞后的印象.

当然,我们的所有应用程序默认都禁用此输出,但是能够在该字段中打开它很有用的,因为您可以查看来自多个应用程序的调试输出,这些应用程序在DBWin32之类的序列化中.对于涉及通信应用程序的错误,这可能是一种非常有用的调试技术.


Ste*_*fan 6

永远不要在发布版本中留下OutputDebugString()调用.始终使用#ifdef语句删除它们,或者提供另一个开关以关闭它们.

如果您将它们保留,请将它们默认禁用,并仅在请求时激活它们,否则您的应用程序将难以调试其他行为良好的应用程序(即,仅根据请求输出调试数据).

Theres DebugView用于捕获应用程序的输出,但当然,如果不是每个应用程序都没有充分的理由,那就是好的.


小智 5

为什么不自己测量呢?编译以下代码,运行它并计时。然后删除对 OutputDebugString 的调用,重新编译并重新运行。应该花大约三分钟的时间。

   #include <windows.h>

    int main() {
        const int COUNT = 1000000;
        int z = 0;    
        for ( unsigned int i = 0; i < COUNT; i++ ) {
            z += i;
            OutputDebugString( "foo" );
        }
        return z;
    }
Run Code Online (Sandbox Code Playgroud)

  • 请注意,仅运行此代码并不是全部。性能将在很大程度上取决于监视调试输出的内容(DebugView、Visual Studio 调试器等),并且可能因您运行的 Windows 版本而异,因此您需要在许多不同的情况下进行测试。这将花费超过三分钟的时间。 (5认同)
  • 我已经使用穷人的时间(NULL)测试了上面的代码片段 - 开始。如果打开OutputDebugString,1000,000次需要13秒,但没有附加调试器,如果打开DbgViewer捕获输出,时间为169秒。如果关闭OutputDebugString,则测量时间为0 秒。 (2认同)

Tho*_*ler 5

现有的答案可以追溯到 2009 / 2010 年。

\n

虽然被遗忘的 OutputDebugString() 的性能可能没有太大变化,但我可以看出该工具产生了巨大的差异。

\n
    \n
  • 无工具: 30 \xc2\xb5s/call (x86) 10 \xc2\xb5s/call (x64)
  • \n
  • 调试视图(完全禁用): 64 \xc2\xb5s/call (x86) 37 \xc2\xb5s/call (x64)
  • \n
  • 调试视图++(已暂停):67 \xc2\xb5s (x86)
  • \n
  • DebugView(自动滚动已停用): 735 \xc2\xb5s/call (x86) 703 \xc2\xb5s/call (x64)
  • \n
  • DebugView++(自动滚动已停用):67 \xc2\xb5s/call
  • \n
  • DebugView(自动滚动活动):936 \xc2\xb5s (x86) 799 \xc2\xb5s/call (x64)
  • \n
  • DebugView++(自动滚动活动):67\xc2\xb5s/call
  • \n
  • VS 2019:81 \xc2\xb5s/调用
  • \n
  • DebugView(同步2个实例):最多1736 \xc2\xb5s/call
  • \n
  • DebugView++(同步2个实例):最多102\xc2\xb5s/调用
  • \n
\n

结论:

\n

原来的 DebugView 太慢了,我减少了样本数量,以便在某个时候真正完成。

\n

DebugView++ 做得非常出色。

\n

VS 2019 似乎比旧版 Visual Studio 做得更好,在这个答案中提到。我无法比较自己,但它与 DebugView++ 非常接近,我认为它非常好。

\n
\n

测量结果:在单个 for 循环中调用 OutPutDebugStringW 100.000 次。所有构建都在发布模式下进行。Intel i7-6820HQ,2.7 GHz,限制为 99% 以防止睿频加速。使用std::chrono::high_resolution_clock::now()100.000 次调用之前和之后的测量。

\n

  • Debugview++的作者在这里;感谢托马斯的赞美;)OutputDebugString 导致速度变慢的主要原因是是否有人正在侦听消息(例如,如果调试器已连接或 debugview++ 正在运行和侦听)。发送方的线程实际上被阻塞,直到收到确认为止已阅读该消息。Debugview++ 经过专门优化以快速完成此操作,但大多数其他工具无法做到这一点。 (5认同)
  • @JanWilmans:感谢您编写 DebugView++。我能够用它解决一个错误。由于时间问题,调试和 DebugView 不是一个选项。 (2认同)