【问题标题】:How to Calculate Execution Time of a Code Snippet in C++如何在 C++ 中计算代码片段的执行时间
【发布时间】:2010-12-24 02:16:47
【问题描述】:

我必须以秒为单位计算 C++ 代码 sn-p 的执行时间。它必须在 Windows 或 Unix 机器上运行。

我使用以下代码来执行此操作。 (之前导入)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

但是,对于小的输入或简短的语句,例如 a = a + 1,我得到“0 秒”的结果。我认为它必须是 0.0000001 秒或类似的东西。

我记得 Java 中的 System.nanoTime() 在这种情况下工作得很好。但是我无法从 C++ 的 clock() 函数中获得完全相同的功能。

你有解决办法吗?

【问题讨论】:

  • 请记住,任何基于时差的比较都可能不准确,因为操作系统可能不会从头到尾运行您的线程。它可能会中断它并运行与您的线程交错的其他线程,这将对完成您的操作所花费的实际时间产生重大影响。您可以运行多次,并平均结果;您可以最大限度地减少正在运行的其他进程的数量。但是这些都不能完全消除线程暂停的影响。
  • Mordachi,你为什么要消灭它?你想看看你的函数在真实世界环境中是如何执行的,而不是在线程永远不会被中断的神奇领域。只要多跑几次,取一个平均值,就会非常准确。
  • 是的,我运行了几次并平均了结果。
  • Andreas,Mordachai 的评论是相关的,如果 OP 想将他的代码的性能与不同的算法进行比较。例如,如果他今天下午运行了几个时钟测试,然后明天早上测试了不同的算法,那么他的比较可能不可靠,因为他可能在下午与比早上更多的进程共享资源。或者也许一组代码会导致操作系统给它更少的处理时间。如果他想进行基于时间的比较,这种类型的性能测量不可靠的原因有很多。
  • @Mordachai 我知道我正在回复一条旧评论,但是对于像我一样偶然发现这一点的人 - 要计算算法的性能,您希望最少运行几次,而不是平均运行次数。这是操作系统中断最少的一个,因此主要是为您的代码计时。

标签: c++ benchmarking


【解决方案1】:

你可以使用我写的这个函数。你调用GetTimeMs64(),它使用系统时钟返回自Unix纪元以来经过的毫秒数——就像time(NULL)一样,除了以毫秒为单位。

它适用于 windows 和 linux;它是线程安全的。

注意,windows 上的粒度是 15 毫秒;在 linux 上,它取决于实现,但通常也是 15 毫秒。

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64 GetTimeMs64()
{
#ifdef _WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}

【讨论】:

  • 供以后参考:我只是把它扔到一个头文件中并使用它。很高兴拥有它。
  • 我相信gettimeofday的方法如果系统时钟发生变化会产生意想不到的结果。如果这对您来说是个问题,您可能需要查看clock_gettime
  • 这种适用于Windows的方法比GetTickCount有什么优势吗?
  • 不使用gcc -std=c99进行编译
  • @MicroVirus:是的,GetTickCount 是自系统启动以来经过的时间,而我的函数返回自 UNIX 纪元以来的时间,这意味着您可以将其用于日期和时间。如果您只对两个事件之间经过的时间感兴趣,我的仍然是更好的选择,因为它是 int64; GetTickCount 是一个 int32,每 50 天溢出一次,这意味着如果您注册的两个事件介于溢出之间,您可能会得到奇怪的结果。
【解决方案2】:

我有另一个使用微秒的工作示例(UNIX、POSIX 等)。

    #include <sys/time.h>
    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

这是我们编写代码的文件:

https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c

【讨论】:

  • 您应该在示例开头添加#include &lt;sys/time.h&gt;
【解决方案3】:

这里有一个简单的 C++11 解决方案,它可以为您提供令人满意的解决方案。

#include <iostream>
#include <chrono>

class Timer
{
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }

private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

或者在 *nix 上,对于 c++03

#include <iostream>
#include <ctime>

class Timer
{
public:
    Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }

    double elapsed() {
        clock_gettime(CLOCK_REALTIME, &end_);
        return end_.tv_sec - beg_.tv_sec +
            (end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
    }

    void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }

private:
    timespec beg_, end_;
};

以下是示例用法:

int main()
{
    Timer tmr;
    double t = tmr.elapsed();
    std::cout << t << std::endl;

    tmr.reset();
    t = tmr.elapsed();
    std::cout << t << std::endl;

    return 0;
}

来自https://gist.github.com/gongzhitaao/7062087

【讨论】:

  • 您的 c++11 解决方案出现此错误:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
  • @julianromera 你用的是什么平台?你安装了 libstdc++ 库和 g++ 吗?
  • 它是 Linux ubuntu 12 的 Slurm 网格。我刚刚修复了它。我在链接器的末尾添加了 -static-libstdc++。谢谢@gongzhitaao 提问
【解决方案4】:
#include <boost/progress.hpp>

using namespace boost;

int main (int argc, const char * argv[])
{
  progress_timer timer;

  // do stuff, preferably in a 100x loop to make it take longer.

  return 0;
}

progress_timer 超出范围时,它将打印出自创建以来经过的时间。

更新:这是一个不使用 Boost 的版本(在 macOS/iOS 上测试):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

int main(int argc, const char * argv[]) {

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}

【讨论】:

  • 这可行,但请注意,progress_timer 已被弃用(有时在 boost 1.50 之前)- auto_cpu_timer 可能更合适。
  • @meowsqueak 嗯,auto_cpu_timer 似乎需要链接 Boost 系统库,所以它不再是一个只有头文件的解决方案。太糟糕了……突然间让其他选项更具吸引力。
  • 是的,这是一个很好的观点,如果你还没有链接 Boost,那么麻烦大于它的价值。但如果你已经这样做了,它会很好地工作。
  • @meowsqueak 是的,或者对于一些快速的基准测试,只需获取旧版本的 Boost。
  • @TomasAndrle 该链接已不存在。
【解决方案5】:

Windows 提供 QueryPerformanceCounter() 函数,Unix 有 gettimeofday() 两个函数都可以测量至少 1 微秒的差异。

【讨论】:

  • 但是使用 windows.h 是有限制的。相同的编译源必须在 Windows 和 Unix 上运行。如何处理这个问题?
  • 然后寻找一些包装库stackoverflow.com/questions/1487695/…
  • 相同的编译源听起来您想在两个系统上运行相同的二进制文件,但似乎并非如此。如果您的意思是相同的来源,那么#ifdef 一定没问题(从您接受的答案来看),然后我看不出问题:#ifdef WIN32 #include &lt;windows.h&gt; ... #else ... #endif。跨度>
【解决方案6】:

在我写的一些程序中,我使用RDTS 来达到这个目的。 RDTSC 与时间无关,而是与处理器启动后的周期数有关。您必须在系统上对其进行校准才能在秒内获得结果,但是当您想要评估性能时它真的很方便,最好直接使用周期数而不用尝试将它们改回秒数。

(上面的链接是一个法语维基百科页面,但它有 C++ 代码示例,英文版是here

【讨论】:

    【解决方案7】:

    我建议使用标准库函数从系统中获取时间信息。

    如果您想要更精细的分辨率,请执行更多的执行迭代。与其运行程序一次并获取样本,不如运行它 1000 次或更多次。

    【讨论】:

      【解决方案8】:

      最好多次运行内部循环,性能计时只运行一次,然后通过除内循环重复进行平均,而不是运行整个事情(循环+性能计时)几次并平均。这将减少性能时序代码与实际分析部分的开销。

      为适当的系统包装您的计时器调用。对于 Windows,QueryPerformanceCounter 使用起来非常快速且“安全”。

      您也可以在任何现代 X86 PC 上使用“rdtsc”,但在某些多核机器上可能会出现问题(核心跳跃可能会改变计时器)或者如果您打开了某种速度步长。

      【讨论】:

        【解决方案9】:

        (windows特定解决方案) 当前(大约 2017 年)在 Windows 下获得准确计时的方法是使用“QueryPerformanceCounter”。这种方法的好处是可以提供非常准确的结果,并被 MS 推荐。只需将代码 blob 放入新的控制台应用程序即可获得工作示例。这里有一个冗长的讨论:Acquiring High resolution time stamps

        #include <iostream>
        #include <tchar.h>
        #include <windows.h>
        
        int main()
        {
        constexpr int MAX_ITER{ 10000 };
        constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
        constexpr __int64 us_per_min{ 60000000ull };
        constexpr __int64 us_per_sec{ 1000000ull };
        constexpr __int64 us_per_ms{ 1000ull };
        
        // easy to work with
        __int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;
        
        QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);
        
        for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
            QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
            // code to be timed
            std::cout << "cur_tick = " << iter << "\n";
            QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
            totalTicks += endTick - startTick; // accumulate time taken
        }
        
        // convert to elapsed microseconds
        __int64 totalMicroSeconds =  (totalTicks * 1000000ull)/ ticksPerSecond;
        
        __int64 hours = totalMicroSeconds / us_per_hour;
        totalMicroSeconds %= us_per_hour;
        __int64 minutes = totalMicroSeconds / us_per_min;
        totalMicroSeconds %= us_per_min;
        __int64 seconds = totalMicroSeconds / us_per_sec;
        totalMicroSeconds %= us_per_sec;
        __int64 milliseconds = totalMicroSeconds / us_per_ms;
        totalMicroSeconds %= us_per_ms;
        
        
        std::cout << "Total time: " << hours << "h ";
        std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
        std::cout << totalMicroSeconds << "us\n";
        
        return 0;
        }
        

        【讨论】:

          【解决方案10】:

          线程调度的完整可靠解决方案(每次测试应产生完全相同的时间)是将您的程序编译为独立于操作系统并启动您的计算机,以便在无操作系统的环境中运行程序。然而,这在很大程度上是不切实际的,而且充其量也很困难。

          无操作系统的一个很好的替代方法是将当前线程的亲和性设置为 1 个核心并将优先级设置为最高。这种替代方案应该提供足够一致的结果。

          假设您在最终生产版本中使用-Ofast(或至少-O3)并忽略“死”代码消除问题,与-Ofast 相比,-Og 执行的优化很少;因此-Og 可能会歪曲最终产品中代码的真实速度。

          进一步,所有速度测试(在某种程度上)伪证:在使用-Ofast编译的最终生产产品中,代码的每个sn-p/section/function不是孤立的;相反,每个 sn-p 代码都不断流入下一个,从而允许编译器潜在地连接、合并和优化来自各地的代码片段。

          同时,如果您正在对大量使用realloc() 的代码进行基准测试,那么在内存碎片足够高的生产产品中,代码的 sn-p 可能会运行得更慢。因此,“整体大于部分之和”这一表述适用于这种情况,因为最终生产构建中的代码可能比您正在速度测试的单个 sn-p 运行得更快或更慢。

          可以减少不协调的部分解决方案是使用-Ofast 进行速度测试,并将asm volatile("" :: "r"(var)) 添加到测试中涉及的变量以防止死代码/循环消除。

          这是一个如何在 Windows 计算机上对平方根函数进行基准测试的示例。

          // set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
          // set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
          #define USE_ASM_TO_PREVENT_ELIMINATION 1
          
          #include <iostream>
          #include <iomanip>
          #include <cstdio>
          #include <chrono>
          #include <cmath>
          #include <windows.h>
          #include <intrin.h>
          #pragma intrinsic(__rdtsc)
          #include <cstdint>
          
          class Timer {
          public:
              Timer() : beg_(clock_::now()) {}
              void reset() { beg_ = clock_::now(); }
              double elapsed() const { 
                  return std::chrono::duration_cast<second_>
                      (clock_::now() - beg_).count(); }
          private:
              typedef std::chrono::high_resolution_clock clock_;
              typedef std::chrono::duration<double, std::ratio<1> > second_;
              std::chrono::time_point<clock_> beg_;
          };
          
          unsigned int guess_sqrt32(register unsigned int n) {
              register unsigned int g = 0x8000;
              if(g*g > n) {
                  g ^= 0x8000;
              }
              g |= 0x4000;
              if(g*g > n) {
                  g ^= 0x4000;
              }
              g |= 0x2000;
              if(g*g > n) {
                  g ^= 0x2000;
              }
              g |= 0x1000;
              if(g*g > n) {
                  g ^= 0x1000;
              }
              g |= 0x0800;
              if(g*g > n) {
                  g ^= 0x0800;
              }
              g |= 0x0400;
              if(g*g > n) {
                  g ^= 0x0400;
              }
              g |= 0x0200;
              if(g*g > n) {
                  g ^= 0x0200;
              }
              g |= 0x0100;
              if(g*g > n) {
                  g ^= 0x0100;
              }
              g |= 0x0080;
              if(g*g > n) {
                  g ^= 0x0080;
              }
              g |= 0x0040;
              if(g*g > n) {
                  g ^= 0x0040;
              }
              g |= 0x0020;
              if(g*g > n) {
                  g ^= 0x0020;
              }
              g |= 0x0010;
              if(g*g > n) {
                  g ^= 0x0010;
              }
              g |= 0x0008;
              if(g*g > n) {
                  g ^= 0x0008;
              }
              g |= 0x0004;
              if(g*g > n) {
                  g ^= 0x0004;
              }
              g |= 0x0002;
              if(g*g > n) {
                  g ^= 0x0002;
              }
              g |= 0x0001;
              if(g*g > n) {
                  g ^= 0x0001;
              }
              return g;
          }
          
          unsigned int empty_function( unsigned int _input ) {
              return _input;
          }
          
          unsigned long long empty_ticks=0;
          double empty_seconds=0;
          Timer my_time;
          
          template<unsigned int benchmark_repetitions>
          void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
              register unsigned int i=benchmark_repetitions;
              register unsigned long long start=0;
              my_time.reset();
              start=__rdtsc();
              while ( i-- ) {
                  auto result = (*function_to_do)( i << 7 );
                  #if USE_ASM_TO_PREVENT_ELIMINATION == 1
                      asm volatile("" :: "r"(
                          // There is no data type in C++ that is smaller than a char, so it will
                          //  not throw a segmentation fault error to reinterpret any arbitrary
                          //  data type as a char. Although, the compiler might not like it.
                          result
                      ));
                  #endif
              }
              if ( function_name == nullptr ) {
                  empty_ticks = (__rdtsc()-start);
                  empty_seconds = my_time.elapsed();
                  std::cout<< "Empty:\n" << empty_ticks
                        << " ticks\n" << benchmark_repetitions << " repetitions\n"
                         << std::setprecision(15) << empty_seconds
                          << " seconds\n\n";
              } else {
                  std::cout<< function_name<<":\n" << (__rdtsc()-start-empty_ticks)
                        << " ticks\n" << benchmark_repetitions << " repetitions\n"
                         << std::setprecision(15) << (my_time.elapsed()-empty_seconds)
                          << " seconds\n\n";
              }
          }
          
          
          int main( void ) {
              void* Cur_Thread=   GetCurrentThread();
              void* Cur_Process=  GetCurrentProcess();
              unsigned long long  Current_Affinity;
              unsigned long long  System_Affinity;
              unsigned long long furthest_affinity;
              unsigned long long nearest_affinity;
              
              if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
                  SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
              }
              if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
                  SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
              }
              GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
              furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
              nearest_affinity  = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
              SetProcessAffinityMask( Cur_Process, furthest_affinity );
              SetThreadAffinityMask( Cur_Thread, furthest_affinity );
              
              const int repetitions=524288;
              
              benchmark<repetitions>( nullptr, empty_function );
              benchmark<repetitions>( "Standard Square Root", standard_sqrt );
              benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
              benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );
              
              
              SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
              SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
              SetProcessAffinityMask( Cur_Process, nearest_affinity );
              SetThreadAffinityMask( Cur_Thread, nearest_affinity );
              for (;;) { getchar(); }
              
              return 0;
          }
          

          另外,感谢 Mike Jarvis 的计时器。

          请注意(这非常重要),如果您要运行更大的代码 sn-ps,那么您确实必须降低迭代次数以防止计算机死机。

          【讨论】:

          • 很好的答案,除了禁用优化。对-O0 代码进行基准测试非常浪费时间,因为-O0 而不是普通的-O2-O3 -march=native 的开销会因代码和工作负载而非常变化。例如额外命名的 tmp vars 在-O0 花费时间。还有其他避免优化的方法,例如使用 volatile、非内联函数或空的内联 asm 语句对优化器隐藏内容。 -O0 甚至还没有接近可用,因为代码在-O0不同瓶颈,不一样但更糟。
          • 呃,-Og 仍然不太现实,具体取决于代码。至少-O2,最好是-O3更真实。使用asm volatile("" ::: "+r"(var)) 或其他东西使编译器在寄存器中实现一个值,并阻止通过它的常量传播。
          • @PeterCordes 再次感谢您的见解。我用-O3更新了内容,用asm volatile("" ::: "+r"(var))更新了代码sn-p。
          • asm volatile("" ::: "+r"( i )); 似乎没有必要。在优化的代码中,没有理由强制编译器在循环内实现ii&lt;&lt;7。您正在阻止它优化到tmp -= 128,而不是每次都转移。但是,如果它不是void,则使用函数调用的结果是好的。喜欢int result = (*function_to_do)( i &lt;&lt; 7 );。您可以对该结果使用asm 语句。
          • @PeterCordes 再次非常感谢您或您的见解。我的帖子现在包含对来自function_to_do 的返回值的更正,以便function_to_do 可以内联而不会被消除。如果您有任何进一步的建议,请告诉我。
          【解决方案11】:

          对于您希望每次执行同一段代码时都对其进行计时的情况(例如,对于您认为可能是瓶颈的分析代码),这里有一个包装器(对 Andreas Bonini 的函数进行了轻微修改),我觉得有用:

          #ifdef _WIN32
          #include <Windows.h>
          #else
          #include <sys/time.h>
          #endif
          
          /*
           *  A simple timer class to see how long a piece of code takes. 
           *  Usage:
           *
           *  {
           *      static Timer timer("name");
           *
           *      ...
           *
           *      timer.start()
           *      [ The code you want timed ]
           *      timer.stop()
           *
           *      ...
           *  }
           *
           *  At the end of execution, you will get output:
           *
           *  Time for name: XXX seconds
           */
          class Timer
          {
          public:
              Timer(std::string name, bool start_running=false) : 
                  _name(name), _accum(0), _running(false)
              {
                  if (start_running) start();
              }
          
              ~Timer() { stop(); report(); }
          
              void start() {
                  if (!_running) {
                      _start_time = GetTimeMicroseconds();
                      _running = true;
                  }
              }
              void stop() {
                  if (_running) {
                      unsigned long long stop_time = GetTimeMicroseconds();
                      _accum += stop_time - _start_time;
                      _running = false;
                  }
              }
              void report() { 
                  std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds\n"; 
              }
          private:
              // cf. http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
              unsigned long long GetTimeMicroseconds()
              {
          #ifdef _WIN32
                  /* Windows */
                  FILETIME ft;
                  LARGE_INTEGER li;
          
                  /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
                   *   * to a LARGE_INTEGER structure. */
                  GetSystemTimeAsFileTime(&ft);
                  li.LowPart = ft.dwLowDateTime;
                  li.HighPart = ft.dwHighDateTime;
          
                  unsigned long long ret = li.QuadPart;
                  ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
                  ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
          #else
                  /* Linux */
                  struct timeval tv;
          
                  gettimeofday(&tv, NULL);
          
                  unsigned long long ret = tv.tv_usec;
                  /* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
                  ret += (tv.tv_sec * 1000000);
          #endif
                  return ret;
              }
              std::string _name;
              long long _accum;
              unsigned long long _start_time;
              bool _running;
          };
          

          【讨论】:

            【解决方案12】:

            只是一个对代码块进行基准测试的简单类:

            using namespace std::chrono;
            
            class benchmark {
              public:
              time_point<high_resolution_clock>  t0, t1;
              unsigned int *d;
              benchmark(unsigned int *res) : d(res) { 
                             t0 = high_resolution_clock::now();
              }
              ~benchmark() { t1 = high_resolution_clock::now();
                              milliseconds dur = duration_cast<milliseconds>(t1 - t0);
                              *d = dur.count();
              }
            };
            // simple usage 
            // unsigned int t;
            // { // put the code in a block
            //  benchmark bench(&t);
            //  // ...
            //  // code to benchmark
            // }
            // HERE the t contains time in milliseconds
            
            // one way to use it can be :
            #define BENCH(TITLE,CODEBLOCK) \
              unsigned int __time__##__LINE__ = 0;  \
              { benchmark bench(&__time__##__LINE__); \
                  CODEBLOCK \
              } \
              printf("%s took %d ms\n",(TITLE),__time__##__LINE__);
            
            
            int main(void) {
              BENCH("TITLE",{
                for(int n = 0; n < testcount; n++ )
                  int a = n % 3;
              });
              return 0;
            }
            

            【讨论】:

              【解决方案13】:

              boost::timer 可能会为您提供所需的准确度。它远不足以准确地告诉您a = a+1; 需要多长时间,但我有什么理由需要为需要几纳秒的事情计时?

              【讨论】:

              • 它依赖于 C++ 标准头文件中的 clock() 函数。
              【解决方案14】:

              我创建了一个 lambda,它调用你的函数调用 N 次并返回平均值。

              double c = BENCHMARK_CNT(25, fillVectorDeque(variable));
              

              可以找到c++11的头文件here

              【讨论】:

                【解决方案15】:

                我使用 chrono 库的 high_resolution_clock 创建了一个简单的实用程序来测量代码块的性能:https://github.com/nfergu/codetimer

                可以针对不同的按键记录时间,并且可以显示每个按键的时间汇总视图。

                用法如下:

                #include <chrono>
                #include <iostream>
                #include "codetimer.h"
                
                int main () {
                    auto start = std::chrono::high_resolution_clock::now();
                    // some code here
                    CodeTimer::record("mykey", start);
                    CodeTimer::printStats();
                    return 0;
                }
                

                【讨论】:

                  【解决方案16】:

                  您还可以查看 GitHub 上的 [cxx-rtimers][1],它提供了一些仅标头例程,用于收集任何代码块的运行时统计信息,您可以在其中创建局部变量。这些计时器的版本在 C++11 上使用 std::chrono,或来自 Boost 库的计时器,或标准 POSIX 计时器函数。这些计时器将报告函数中花费的平均、最大和最小持续时间,以及调用它的次数。它们可以简单地使用如下:

                  #include <rtimers/cxx11.hpp>
                  
                  void expensiveFunction() {
                      static rtimers::cxx11::DefaultTimer timer("expensive");
                      auto scopedStartStop = timer.scopedStart();
                      // Do something costly...
                  }
                  

                  【讨论】:

                    【解决方案17】:

                    我就是这样做的,代码不多,通俗易懂,符合我的需要:

                    void bench(std::function<void()> fnBench, std::string name, size_t iterations)
                    {
                        if (iterations == 0)
                            return;
                        if (fnBench == nullptr)
                            return;
                        std::chrono::high_resolution_clock::time_point start, end;
                        if (iterations == 1)
                        {
                            start = std::chrono::high_resolution_clock::now();
                            fnBench();
                            end = std::chrono::high_resolution_clock::now();
                        }
                        else
                        {
                            start = std::chrono::high_resolution_clock::now();
                            for (size_t i = 0; i < iterations; ++i)
                                fnBench();
                            end = std::chrono::high_resolution_clock::now();
                        }
                        printf
                        (
                            "bench(*, \"%s\", %u) = %4.6lfs\r\n",
                            name.c_str(),
                            iterations,
                            std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
                        );
                    }
                    

                    用法:

                    bench
                    (
                        []() -> void // function
                        {
                            // Put your code here
                        },
                        "the name of this", // name
                        1000000 // iterations
                    );
                    

                    【讨论】:

                      【解决方案18】:
                      #include <omp.h>
                      
                      double start = omp_get_wtime();
                      
                      // code 
                      
                      double finish = omp_get_wtime();
                      
                      double total_time = finish - start;
                      

                      【讨论】:

                      • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。
                      猜你喜欢
                      • 2023-03-16
                      • 2014-08-25
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-10-26
                      • 1970-01-01
                      相关资源
                      最近更新 更多