如何计算一段代码的执行时间C ++如何计算一段代码的执行时间C ++(How to Calculat

2019-05-08 18:59发布

我必须计算以秒为C ++代码段的执行时间。 必须在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,I得到“0秒”的结果。 我想它一定是这样0.0000001秒或类似的东西。

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

你有解决方案吗?

Answer 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
}


Answer 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



Answer 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



Answer 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超出范围就会打印出自创建以来经过的时间。

更新 :我做了一个简单的独立更换(OSX / iOS版,但很容易地移植): https://github.com/catnapgames/TestTimerScoped



Answer 5:

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



Answer 6:

在一些程序中,我写了我曾经主任小组作该用途。 RDTSC不是关于时间,但来自与处理器起动周期数。 你必须进行校准系统,以获得第二结果上,但是当你要评估性能是非常方便,它甚至更好用的循环次数的情况下直接试图改变他们回到秒。

(以上是链接到法语维基百科页,但是它有C ++代码示例,英文版本是在这里 )



Answer 7:

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

如果你想更精细的分辨率,执行更多的迭代执行。 相反,一旦运行该程序,并获取样本,运行1000次以上。



Answer 8:

最好是通过将内部循环重复,而不是运行整个事情(环+性能计时)几次,平均运行内多次循环的表现时间只有一次,平均。 这将减少的性能计时码VS实际成型部件的开销。

总结了相应的系统的计时器调用。 对于Windows,QueryPerformanceCounter的相当快,“安全”来使用。

您可以使用“RDTSC”任何现代X86 PC上很好,但可能会有一些多核机器的问题(核跳跃可能改变定时器),或者如果你有某种速度步开启。



Answer 9:

(窗口具体的解决方案)的电流(大约2017年)的方式来获得windows下准确的计时是用“QueryPerformanceCounter的”。 这种方法在为非常准确的结果的利益,并通过MS建议。 只是扑通代码BLOB到一个新的控制台应用程序,以获取工作示例。 有一个长时间的讨论在这里: 获取高分辨率的时间戳

#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;
}


Answer 10:

一个完整的经久不衰解决线程调度,这应该产生完全相同的时间每个测试,是编译程序是独立于操作系统和启动您的计算机,以便运行在无操作系统的环境节目。 然而,这是基本上是不切实际的充其量是困难的。 一个很好的替代品去OS-自由仅仅是当前线程的亲和力设置为1层的核心和优先级为最高。 泰斯替代应该提供一致的,足够的结果。 还应该关闭这将与调试,这对于G ++或GCC手段干涉优化加入-Og到命令行 ,以防止码是从被优化了测试。 不应该被使用的标志-O0因为它引入了将被包括在所述计时结果的额外开销不需要的,因而倾斜的代码的定时速度。 相反,无论是假设你使用-Ofast (或者,至少是, -O3最终生产版本)和忽略的“死”代码消除,问题-Og进行比较,很少优化-Ofast ; 因此-Og可以歪曲代码的实际速度在最终产品中。 此外,所有测试的速度(在某种程度上)作伪证:在编译时最终生产产品-Ofast ,每个代码段/部分/功能不分离; 相反,每个代码段连续地流动到下一个,从而允许编译器对潜在的加入,合并,并从所有的地方的代码段优化在一起。 同时,如果你是基准的代码片段,这使得大量使用realloc ,然后将代码段可能具有足够高内存碎片运行在生产产品的速度较慢。 因此,表达“整体大于部分之和”适用于这种情况,因为在最终生产版本的代码可能会明显比单个片段,你是测试速度更快或更慢运行。 可以减轻不协调的部分解决方案是使用-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;
}

此外,信贷迈克·贾维斯他的定时器。

请注意(这很重要),如果你要运行更大的代码片段,那么你真的必须拒绝的迭代次数,以防止您的计算机冻结起来。



Answer 11:

对于要时间的代码相同的拉伸每次被执行时间的情况下(例如,对于剖析,你认为可能是瓶颈码),这里是一个包装器(略有修改)安德烈亚斯博尼尼的功能,我觉得非常有用:

#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;
};


Answer 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;
}


Answer 13:

提高::计时器可能会给你尽可能多的准确性,您需要。 这是隔靴搔痒准确地告诉你多久a = a+1; 将采取,但你必须要时间的东西,花费几纳秒我是什么原因?



Answer 14:

我创建了一个调用你的函数调用N次,并返回的平均拉姆达。

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

你可以找到C ++ 11头在这里 。



Answer 15:

我创建了一个简单的工具,用于测量的代码块的性能,采用计时图书馆的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;
}


Answer 16:

您还可以看看[cxx-rtimers][1]在GitHub上,这对于任何代码块,你可以创建一个局部变量的运行时收集统计数据提供了一些仅标头例程。 那些计时器具有使用std ::上C ++ 11计时,或计时器从Boost库,或标准POSIX定时器功能的版本。 这些定时器将报告功能中所花费的平均,最高及最低期限,以及次它叫号。 它们可以被用来作为简单如下:

#include <rtimers/cxx11.hpp>

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


文章来源: How to Calculate Execution Time of a Code Snippet in C++