c++ - 在没有分析器的情况下在 C++ 中测试代码速度的最佳方法,或者尝试没有意义?

标签 c++ profiling performance timer

关于SO,有很多关于性能分析的问题,但我似乎没有找到全貌。涉及的问题很多,大多数问答一次都忽略了几个问题,或者没有证明他们的建议是合理的。

我在想什么。如果我有两个功能做同样的事情,并且我对速度上的差异感到好奇,那么在没有外部工具、使用计时器的情况下测试它是否有意义,或者在测试中编译会不会对结果产生很大影响?

我问这个是因为如果它是明智的,作为一个 C++ 程序员,我想知道它应该如何最好地完成,因为它们比使用外部工具简单得多。如果有道理,让我们继续处理所有可能的陷阱:

考虑这个例子。以下代码显示了执行同一操作的两种方法:

#include <algorithm>
#include <ctime>
#include <iostream>

typedef unsigned char byte;

inline
void
swapBytes( void* in, size_t n )
{
   for( size_t lo=0, hi=n-1; hi>lo; ++lo, --hi )

      in[lo] ^= in[hi]
   ,  in[hi] ^= in[lo]
   ,  in[lo] ^= in[hi] ;
}

int
main()
{
         byte    arr[9]     = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
   const int     iterations = 100000000;
         clock_t begin      = clock();

   for( int i=iterations; i!=0; --i ) 

      swapBytes( arr, 8 );

   clock_t middle = clock();

   for( int i=iterations; i!=0; --i ) 

      std::reverse( arr, arr+8 );

   clock_t end = clock();

   double secSwap = (double) ( middle-begin ) / CLOCKS_PER_SEC;
   double secReve = (double) ( end-middle   ) / CLOCKS_PER_SEC;


   std::cout << "swapBytes,    for:    "   << iterations << " times takes: " << middle-begin
             << " clock ticks, which is: " << secSwap    << "sec."           << std::endl;

   std::cout << "std::reverse, for:    "   << iterations << " times takes: " << end-middle
             << " clock ticks, which is: " << secReve    << "sec."           << std::endl;

   std::cin.get();
   return 0;
}

// Output:

// Release:
//  swapBytes,    for: 100000000 times takes: 3000 clock ticks, which is: 3sec.
//  std::reverse, for: 100000000 times takes: 1437 clock ticks, which is: 1.437sec.

// Debug:
//  swapBytes,    for: 10000000 times takes: 1781  clock ticks, which is: 1.781sec.
//  std::reverse, for: 10000000 times takes: 12781 clock ticks, which is: 12.781sec.

问题:

  1. 要使用哪些计时器以及如何获取相关代码实际消耗的 CPU 时间?
  2. 编译器优化的效果如何(因为这些函数只是来回交换字节,最有效的做法显然是什么都不做)?
  3. 考虑到此处显示的结果,您认为它们准确吗(我可以向您保证,多次运行给出的结果非常相似)?如果是,考虑到自定义函数的简单性,您能否解释一下 std::reverse 如何变得如此之快。我没有用于此测试的 vc++ 版本的源代码,但是 here is the implementation来自 GNU。它归结为函数 iter_swap ,这对我来说是完全无法理解的。这是否也有望比该自定义函数的运行速度快两倍?如果是,为什么?

思考:

  1. 似乎正在提议两个高精度计时器:clock()QueryPerformanceCounter (在 window 上)。显然我们想测量我们代码的 cpu 时间而不是实时,但据我了解,这些函数不提供该功能,因此系统上的其他进程会干扰测量。 This page在 gnu c 库上似乎与此相矛盾,但是当我在 vc++ 中放置一个断点时,调试的进程即使被挂起也会得到很多时钟滴答声(我没有在 gnu 下测试过)。我是否缺少替代计数器,或者我们至少需要特殊的库或类吗?如果不是,时钟在此示例中是否足够好,或者是否有理由使用 QueryPerformanceCounter?

  2. 如果没有调试、反汇编和分析工具,我们能确定什么?真的有什么事情发生吗?函数调用是否被内联?在调试器中检查时,字节确实被交换了,但我宁愿从理论上知道为什么,而不是通过测试。

感谢任何指示。

更新

感谢hint来自 tojas swapBytes 函数现在运行速度与 std::reverse 一样快。我没有意识到字节的临时拷贝必须只是一个寄存器,因此非常快。优雅会让你盲目。

inline
void
swapBytes( byte* in, size_t n )
{
   byte t;

   for( int i=0; i<7-i; ++i )
    {
        t       = in[i];
        in[i]   = in[7-i];
        in[7-i] = t;
    }
}

感谢tip来自 ChrisW我发现在 Windows 上,您可以通过 Windows Management Instrumentation 获得(阅读:您的)进程消耗的实际 CPU 时间。 .这看起来肯定比高精度计数器更有趣。

最佳答案

Obviously we would like to measure the cpu time of our code and not the real time, but as far as I understand, these functions don't give that functionality, so other processes on the system would interfere with measurements.

我做了两件事,以确保挂钟时间和 CPU 时间大致相同:

  • 测试相当长的时间,即几秒钟(例如,通过测试包含数千次迭代的循环)

  • 测试机器何时或多或少相对空闲,除了我正在测试的内容。

或者,如果您只想/更准确地测量每个线程的 CPU 时间,可以将其用作性能计数器(参见例如 perfmon.exe)。

What can we know for certain without debugging, dissassembling and profiling tools?

几乎没有(除了 I/O 往往相对较慢)。

关于c++ - 在没有分析器的情况下在 C++ 中测试代码速度的最佳方法,或者尝试没有意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3128095/

相关文章:

c++ - 有没有办法制作静态链接到 Qt 运行时的 Qt DLL?

C++ 程序不适用于某些输入

python - Yappi 返回奇怪的结果

java - 在 servlet 的 init 参数中进行 JNDI 查找是个好主意吗?

mysql - 如果主键是字符串(varchar)或整数,在 MySQL 中检索行是否更快?

c++ - 如何使一个线程按预期顺序多次等待另一个线程

c++ - 传递 Lambda 时,Visual Studio 2017 中的什么扩展消除了 "bool"与 "std::function"的歧义?

c++ - 以纳秒为单位测量精确时间 C++

python - 逐行分析 Django View

performance - AS3瓦片 map 渲染(包含1000 block 瓦片)