【问题标题】:Testing the performance of a C++ app测试 C++ 应用程序的性能
【发布时间】:2010-10-22 04:52:06
【问题描述】:

我正在尝试寻找一种方法来测试运行一段 C++ 代码需要多长时间。我用它来比较不同算法和不同语言的代码,所以理想情况下我想要一个以秒/毫秒为单位的时间。在 Java 中,我使用的是这样的:

long startTime = System.currentTimeMillis();

function();

long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime; 

有没有像在 C++ 中那样获得准确时间的好方法(或者我应该使用其他一些基准测试方法)?

【问题讨论】:

  • 我将继续回答我自己的问题,说Andy White 发布的评论中的链接 (*.com/questions/275004/…) 就是我要找的。​​span>
  • 时间取决于平台。您应该列出您正在使用的平台。
  • 令人沮丧的是,这里的答案都没有统计成分。

标签: c++ performance testing


【解决方案1】:

执行该函数几千次以获得准确的测量结果。

单次测量可能会受到操作系统事件或其他随机噪声的支配。

【讨论】:

    【解决方案2】:

    您可以使用time() 函数获取分辨率为一秒的计时器。如果您需要更多分辨率,可以使用gettimeofday()。解决方案取决于您的操作系统和运行时库。

    【讨论】:

      【解决方案3】:

      在 Windows 中,您可以使用高性能计数器来获得更准确的结果:

      您可以使用QueryPerformanceFrequency()函数获取每秒的高频滴答数和用户您要计时的函数前后的QueryPerformanceCounter()

      当然,这种方法是不可移植的……

      【讨论】:

      • 小心高频计数器。多处理器系统有时会使用它们……很有趣。它们与特定于处理器的计数器一起使用,因此如果您最终将代码放在不同的 CPU 上,则计数器可以关闭(当然取决于您的确切硬件)。
      • 在基准测试期间将线程关联设置为单个 CPU 将消除与 SMP 相关的时间扭曲。由于电源管理也可能会出现时钟斜坡,如果 CPU 因基准代码休眠或 I/O 阻塞而变得空闲,这将很重要。对于 AMD 系统,安装 AMD 处理器驱动程序将显着改善 QPC() 同步。 Windows Vista 和 Windows 7 使用 HPET 计时器(如果可用)而不是 TSC,因此 TSC 问题最终可能会消失(当/如果 Windows XP 消失)。
      【解决方案4】:

      您是否考虑过实际使用分析器? Visual Studio Team System 内置了一个,但也有其他可用的,例如 VTune 和 GlowCode。

      另见What's the best free C++ profiler for Windows?

      【讨论】:

      • 啊!他们有那些不那么贵的吗?
      • Profilers 可以很好地回答“我的程序中最慢的部分是什么?”这个问题。但通常不太擅长回答“我的程序有多慢?”的问题。准确。
      【解决方案5】:

      您只需在代码中使用time() 即可在几秒内准确测量。彻底的基准测试应该运行多次迭代以确保准确性,因此秒数应该足够大。如果您使用的是 linux,则可以使用命令行提供的时间实用程序,如下所示:

      [john@awesome]$time ./loops.sh
      
      real    0m3.026s
      user    0m4.000s
      sys     0m0.020s
      

      【讨论】:

        【解决方案6】:

        在 unix 系统(Linux、Mac 等)上,您可以像这样使用 time 实用程序:

        $ time ./my_app
        

        【讨论】:

          【解决方案7】:

          如果您的函数非常快,一个好的做法是将函数计时在一个循环中,然后减去循环开销。

          类似这样的:

          int i;
          int limit=1000000;
          int t0=getTime();
          for(i=0; i < limit; ++i)
             ;
          int t1=getTime();
          int loopoverhead = t1-t0;
          t0=getTime();
          for(i=0; i < limit; ++i)
              function();
          t1=getTime();
          double tfunction = (1.0/limit)*((t1-t0)-loopoverhead);
          

          【讨论】:

            【解决方案8】:

            我总是使用boost::timerboost::progress_timer

            伪代码:

            #include <boost/timer.hpp>
            
            boost::timer t;
            
            func1();
            cout << "fun1: " << t.elapsed();
            
            t.restart();
            func2();
            cout << "func2(): " << t.elapsed();
            

            【讨论】:

              【解决方案9】:

              使用您平台上可用的最佳计数器,回退到 time() 以获得可移植性。 我正在使用 QueryPerformanceCounter,但请参阅其他回复中的 cmets。

              一般建议:

              内循环应至少运行时钟分辨率的 20 倍左右,以使分辨率误差

              重复这些测量,看看它们是否一致。

              我使用了一个额外的外循环,运行了十次,并忽略了计算平均值和偏差的最快和最慢测量。比较两种实现时,偏差很方便:如果您有一种算法采用 2.0ms +/- .5,而另一种算法采用 2.2 +/- .5,则将其中一种称为“更快”的差异并不显着。 (最大值和最小值仍应显示)。所以恕我直言,一个有效的性能测量应该是这样的:

              10000 x 2.0 +/- 0.2 ms (min = 1.2, , max=12.6), 10 repetitions
              

              如果您知道自己在做什么,那么清除缓存和设置线程关联可以使您的测量更加稳健。

              然而,这并非没有缺陷。测量越“稳定”,它也就越不真实。任何实现都会随时间发生很大变化,具体取决于数据和指令缓存的状态。我这里比较懒,使用 max= 值来判断首次运行惩罚,这对于某些场景可能还不够。

              【讨论】:

                【解决方案10】:

                如果您想检查自己的性能,您应该考虑测量使用的处理器时间,而不是您现在尝试测量的实际时间。否则,如果在后台运行的其他应用程序决定同时进行一些繁重的计算,您可能会得到非常不准确的时间。 您想要的函数在 Windows 上是 GetProcessTimes,在 Linux 上是 getrusage

                您还应该考虑使用分析器,正如其他人建议的那样。

                【讨论】:

                  【解决方案11】:

                  以 100 次迭代 * 10 次迭代运行 1000 次,展开内部循环以最大限度地减少开销。然后秒转换为毫秒。

                  正如其他人所指出的,这是衡量所需时间的好方法。

                  但是,如果您还想让它花费更少的时间,那就是不同的目标,需要不同的技术。 My favorite is this.

                  【讨论】:

                    【解决方案12】:

                    clock()CLOCKS_PER_SEC 有什么问题?它们是标准 C89。

                    类似(来自 MSDN)的东西:

                       long i = 6000000L;
                       clock_t start, finish;
                       double  duration;
                    
                       // Measure the duration of an event.
                       printf( "Time to do %ld empty loops is ", i );
                       start = clock();
                       while( i-- ) 
                          ;
                       finish = clock();
                       duration = (double)(finish - start) / CLOCKS_PER_SEC;
                       printf( "%2.1f seconds\n", duration );
                    

                    【讨论】:

                      【解决方案13】:

                      您的部署平台可能会对您的时钟精度产生严重影响。如果您在虚拟机内部进行采样,那么所有的赌注都没有了。 VM 中的系统时钟相对于物理时钟浮动,并且必须偶尔重新同步。考虑到 Murphy 先生在软件领域的淘气本性,这几乎可以肯定会发生

                      【讨论】:

                        【解决方案14】:

                        概览

                        我为此编写了一个简单的语义破解。

                        • 易于使用
                        • 代码看起来很整洁。

                        #include <time.h>
                        
                        #ifndef SYSOUT_F
                        #define SYSOUT_F(f, ...)      _RPT1( 0, f, __VA_ARGS__ ) // For Visual studio
                        #endif
                        
                        #ifndef speedtest__             
                        #define speedtest__(data)   for (long blockTime = NULL; (blockTime == NULL ? (blockTime = clock()) != NULL : false); SYSOUT_F(data "%.9fs", (double) (clock() - blockTime) / CLOCKS_PER_SEC))
                        #endif
                        

                        用法

                        speedtest__("Block Speed: ")
                        {
                            // The code goes here
                        }
                        

                        输出

                        Block Speed: 0.127000000s
                        

                        【讨论】:

                          最近更新 更多