我希望计算出API返回值所花费的时间。
执行此操作所花费的时间在纳秒级的空间内。由于API是C ++类/函数,因此我使用timer.h进行了计算:
  #include <ctime>
  #include <iostream>

  using namespace std;

  int main(int argc, char** argv) {

      clock_t start;
      double diff;
      start = clock();
      diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
      cout<<"printf: "<< diff <<'\n';

      return 0;
  }

上面的代码给出了以秒为单位的时间。如何在十亿分之一秒的精度内获得相同的结果?

评论

上面的代码以秒为单位计算,我想以纳秒为单位得到答案...

需要将平台添加到问题中(最好也添加到标题中)以获得良好的答案。

除了获取时间之外,还需要查找与微基准测试相关的问题(这非常复杂)-仅执行一次,并获取开始和结束的时间就不可能提供足够的精度。

@Blaisorblade:特别是因为我在一些测试中发现,clock()并没有我想象的那么快。

#1 楼

其他人发表的关于在循环中重复运行该函数的信息是正确的。

对于Linux(和BSD),您要使用clock_gettime()。

#include <sys/time.h>

int main()
{
   timespec ts;
   // clock_gettime(CLOCK_MONOTONIC, &ts); // Works on FreeBSD
   clock_gettime(CLOCK_REALTIME, &ts); // Works on Linux
}


对于Windows,您想使用QueryPerformanceCounter。关于QPC的更多信息

显然,某些芯片组上存在QPC的已知问题,因此您可能要确保没有这些芯片组。此外,某些双核AMD也可能会引起问题。参见sebbbi的第二篇文章,他指出:


QueryPerformanceCounter()和
QueryPerformanceFrequency()提供了更好的解析度,但具有
不同的问题。例如,在Windows XP中,所有AMD Athlon X2双核处理器都“随机”返回任一核的PC(有时PC有时会向后跳),除非您
专门安装AMD双核驱动程序
软件包以解决此问题。我们没有
注意到任何其他具有类似问题的双核+双核CPU(p4双核,p4 ht,
core2双核,core2四核,现象四核)。


EDIT 2013/07/16:

在http://msdn.microsoft.com/zh-CN所述的某些情况下,对于QPC的功效似乎存在一些争议/library/windows/desktop/ee417693(v=vs.85).aspx


...虽然QueryPerformanceCounter和QueryPerformanceFrequency通常针对
多个处理器进行调整,但BIOS中的错误或驱动程序可能会导致这些例程在线程从一个处理器移至另一个处理器时返回不同的值...



但是此StackOverflow答案https://stackoverflow.com/ a / 4588605/34329指出,在Win XP Service Pack 2之后,QPC应该可以在任何MS OS上正常运行。

本文显示Windows 7可以确定处理器是否具有不变的TSC,如果没有,则使用外部计时器。 http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html跨处理器同步仍然是一个问题。

与计时器有关的其他相关读物:


https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks
http://lwn.net/Articles/209101/
http:/ /performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html
QueryPerformanceCounter状态?

查看注释以了解更多详细信息。

评论


我已经在较旧的双Xeon PC上看到TSC时钟偏斜,但不及在启用C1时钟斜波的Athlon X2上差。随着C1时钟的斜升,执行HLT指令会减慢时钟速度,从而导致空闲内核上的TSC的增加速度比活动内核上的TSC慢。

– bk1e
08年9月9日在5:33

CLOCK_MONOTONIC适用于我拥有的Linux版本。

–伯纳德
09年2月15日在23:14

@Bernard-自从我上次查看此内容以来,必须重新添加该内容。感谢您的注意。

–悲伤
09年2月26日在21:15

实际上,您必须使用CLOCK_MONOTONIC_RAW(如果可用),以获取不受NTP调整的硬件时间。

–user405725
2012年3月1日,0:51

如此处所述,至少在已知不可靠的地方,QPC的正确实现不使用TSC计数器:stackoverflow.com/q/510462/53974

–布莱布莱德
2012年4月30日在16:25

#2 楼

这个新答案使用C ++ 11的<chrono>工具。虽然还有其他答案显示了如何使用<chrono>,但没有一个答案显示如何将<chrono>与此处其他几个答案中提到的RDTSC工具一起使用。所以我想我将展示如何将RDTSC<chrono>一起使用。另外,我将演示如何在时钟上对测试代码进行模板化,以便您可以在RDTSC和系统的内置时钟工具(可能基于clock()clock_gettime()和/或QueryPerformanceCounter)之间快速切换。

请注意,RDTSC指令是特定于x86的指令。QueryPerformanceCounter仅适用于Windows; clock_gettime()仅适用于POSIX。下面我介绍两个新的时钟:std::chrono::high_resolution_clockstd::chrono::system_clock,如果可以假设使用C ++ 11,它们现在可以交叉使用-platform。

首先,这是从Intel rdtsc汇编指令中创建与C ++ 11兼容的时钟的方法,我将其称为x::clock

#include <chrono>

namespace x
{

struct clock
{
    typedef unsigned long long                 rep;
    typedef std::ratio<1, 2'800'000'000>       period; // My machine is 2.8 GHz
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<clock>     time_point;
    static const bool is_steady =              true;

    static time_point now() noexcept
    {
        unsigned lo, hi;
        asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
        return time_point(duration(static_cast<rep>(hi) << 32 | lo));
    }
};

}  // x


所有这些时钟所做的只是计数CPU周期并将其存储在无符号的64位整数中。您可能需要调整编译器的汇编语言语法,否则您的编译器可能会提供可使用的内在函数相反(例如now() {return __rdtsc();})。

要构建时钟,您必须为其提供表示形式(存储类型)。您还必须提供时钟周期,该时钟周期必须是编译时间常数,即使您的机器在不同的电源模式下可能会更改时钟速度。然后,您可以根据这些基本原理轻松定义时钟的“本机”持续时间和时间点。

如果您要做的只是输出时钟滴答数,那么在时钟周期内给出多少就没有关系了。仅当您想要将时钟滴答数转换为某些实时单位(例如纳秒)时,此常数才起作用。在这种情况下,提供时钟速度的精度越高,转换到纳秒(毫秒)的精度就越高。

下面的示例代码显示了如何使用x::clock。实际上,我已经在时钟上模板化了代码,因为我想展示如何使用完全相同的语法使用许多不同的时钟。此特定测试显示了在循环下运行要计时的时间时的循环开销:

#include <iostream>

template <class clock>
void
test_empty_loop()
{
    // Define real time units
    typedef std::chrono::duration<unsigned long long, std::pico> picoseconds;
    // or:
    // typedef std::chrono::nanoseconds nanoseconds;
    // Define double-based unit of clock tick
    typedef std::chrono::duration<double, typename clock::period> Cycle;
    using std::chrono::duration_cast;
    const int N = 100000000;
    // Do it
    auto t0 = clock::now();
    for (int j = 0; j < N; ++j)
        asm volatile("");
    auto t1 = clock::now();
    // Get the clock ticks per iteration
    auto ticks_per_iter = Cycle(t1-t0)/N;
    std::cout << ticks_per_iter.count() << " clock ticks per iteration\n";
    // Convert to real time units
    std::cout << duration_cast<picoseconds>(ticks_per_iter).count()
              << "ps per iteration\n";
}


该代码要做的第一件事是创建“实时”以显示结果的单位。我选择了皮秒,但您可以选择任何所需的单位,基于整数或浮点。作为示例,我可以使用一个预制的std::chrono::nanoseconds单元。

作为另一个示例,我要打印出每次迭代的平均时钟周期数作为浮点,因此我创建了另一个持续时间,基于double,具有与时钟的刻度相同的单位(在代码中称为Cycle)。

循环的定时在任一侧调用clock::now()。如果要命名此函数返回的类型,则为:

typename clock::time_point t0 = clock::now();


(如x::clock示例中清楚显示的那样,并且系统提供的时钟也是如此)。

要获得一个以浮点时钟刻度为单位的持续时间,只需将两个时间点相减,并获得每个迭代值,就将该持续时间除以迭代次数即可。

通过使用count()成员函数,您可以随时获取计数。这将返回内部表示。最后,我使用std::chrono::duration_cast将持续时间Cycle转换为持续时间picoseconds并打印出来。

使用此代码很简单:上面,我使用自制的x::clock进行了测试,并使用两个系统提供的时钟比较了这些结果: std::chrono::high_resolution_clockstd::chrono::system_clock。对我来说,这是打印出来的:

 Using rdtsc:
1.72632 clock ticks per iteration
616ps per iteration

Using std::chrono::high_resolution_clock:
0.620105 clock ticks per iteration
620ps per iteration

Using std::chrono::system_clock:
0.00062457 clock ticks per iteration
624ps per iteration
 


这表明每个时钟都有不同的周期,因为每个时钟的每次迭代周期差异很大。但是,当转换为已知的时间单位(例如皮秒)时,每个时钟得到的结果大致相同(您的里程可能会有所不同)。

请注意,我的代码如何完全没有“魔术转换常数” ”。实际上,整个示例中只有两个幻数:


为了定义x::clock我的机器的时钟速度。要测试的迭代次数。如果更改此数字会使结果相差很大,则可能应该增加迭代次数,或者在测试时清空竞争进程的计算机。


评论


通过“ RDTSC仅用于Intel”,您实际上是在指x86体系结构及其派生产品,不是吗? AMD,Cyrix,Transmeta x86芯片具有该指令,而Intel RISC和ARM处理器则没有。

– Ben Voigt
2012年10月17日15:44



@BenVoigt:+1是,您的更正是正确的,谢谢。

– Howard Hinnant
2012-10-18 2:12

CPU节流将如何影响这一点?时钟速度不会根据cpu负载而变化吗?

– Tejas Kale
16 Apr 25'6:45

@TejasKale:这在连续两个段落的答案中都有描述,以“为您建立时钟...”开头。通常,时序代码无法衡量阻塞线程的工作(但可以)。因此,通常您的CPU不会节流。但是,如果您要测量涉及睡眠,互斥锁,condition_variable等待等的代码,则rdtsc时钟可能无法正确转换为其他单位。设置您的测量值是一个好主意,以便您可以轻松更改和比较时钟(如本答案所示)。

– Howard Hinnant
16年4月25日在14:23

#3 楼

有了这样的准确性,最好在CPU滴答声中进行推理,而不是像clock()这样的系统调用中进行推理。并且不要忘记,如果执行一条指令需要花费多于一纳秒的时间...具有纳秒级的精度几乎是不可能的。

还是这样,这只是一个开始:

这里是检索自上次启动CPU以来经过的80x86 CPU时钟滴答数的实际代码。它将在Pentium及更高版本上运行(不支持386/486)。这段代码实际上是MS Visual C ++特有的,但是只要它支持内联汇编,就可以很容易地移植到其他代码。

inline __int64 GetCpuClocks()
{

    // Counter
    struct { int32 low, high; } counter;

    // Use RDTSC instruction to get clocks count
    __asm push EAX
    __asm push EDX
    __asm __emit 0fh __asm __emit 031h // RDTSC
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    // Return result
    return *(__int64 *)(&counter);

}


此函数还具有极快的优势-执行通常不超过50个cpu周期。

使用时序图:
如果需要将时钟计数转换为真实的经过时间,则将结果除以芯片的时钟速度。请记住,“额定” GHz可能与芯片的实际速度略有不同。要检查芯片的真实速度,可以使用几个非常好的实用程序或Win32调用QueryPerformanceFrequency()。

评论


感谢您提供的信息,这很有用。我没有想到要计算时间的cpu周期,我想记住这一点非常好:-)

– gagneet
08年9月9日在3:29

使用QueryPerformanceFrequency()将TSC计数转换为经过的时间可能不起作用。可用时,QueryPerformanceCounter()在Vista上使用HPET(高精度事件计时器)。如果用户将/ USEPMTIMER添加到boot.ini,它将使用ACPI电源管理计时器。

– bk1e
08年9月9日在5:21

#4 楼

要正确地执行此操作,可以使用两种方法之一,或者与RDTSC一起使用,或者与clock_gettime()一起使用。
第二种方法快大约2倍,并且具有提供正确的绝对时间的优势。请注意,要使RDTSC正常工作,您需要按指示使用它(此页面上的其他注释有错误,并且在某些处理器上可能会产生不正确的时序值)。

inline uint64_t rdtsc()
{
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx" );
    return (uint64_t)hi << 32 | lo;
}


并且对于clock_gettime :(我任意选择了微秒分辨率)

#include <time.h>
#include <sys/timeb.h>
// needs -lrt (real-time lib)
// 1970-01-01 epoch UTC time, 1 mcs resolution (divide by 1M to get time_t)
uint64_t ClockGetTime()
{
    timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return (uint64_t)ts.tv_sec * 1000000LL + (uint64_t)ts.tv_nsec / 1000LL;
}


产生的时间和值:

Absolute values:
rdtsc           = 4571567254267600
clock_gettime   = 1278605535506855

Processing time: (10000000 runs)
rdtsc           = 2292547353
clock_gettime   = 1031119636


#5 楼

我正在使用以下方法获得所需的结果:

#include <time.h>
#include <iostream>
using namespace std;

int main (int argc, char** argv)
{
    // reset the clock
    timespec tS;
    tS.tv_sec = 0;
    tS.tv_nsec = 0;
    clock_settime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    ...
    ... <code to check for the time to be put here>
    ...
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    cout << "Time taken is: " << tS.tv_sec << " " << tS.tv_nsec << endl;

    return 0;
}


评论


我之所以投票,是因为尝试应用此代码,我必须先去Google为什么未定义时间规格。然后,我不得不用Google搜索什么是POSIX ...,据我所知,此代码与那些坚持使用标准库的Windows用户无关。

–丹尼尔·卡兹(Daniel Katz)
15年5月16日在19:31



#6 楼

对于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,

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

#7 楼

通常,为了定时调用一个函数需要多长时间,您希望执行一次以上。如果只调用一次函数,并且运行时间很短,则仍然有实际调用计时器函数的开销,并且您不知道需要花费多长时间。

例如,如果您估计函数可能需要800 ns的时间运行,请在循环中调用它一千万次(然后将花费大约8秒钟)。将总时间除以一千万,即可获得每次通话的时间。

评论


实际上,我正在尝试获取特定调用的api性能。对于每次运行,它可能会给出不同的时间,这可能会影响我为提高性能而制作的图形……因此时间以纳秒为单位。是的,这是个好主意,会考虑的。

– gagneet
08年11月8日在18:56

#8 楼

您可以在x86处理器下运行的gcc上使用以下功能:

unsigned long long rdtsc()
{
  #define rdtsc(low, high) \
         __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))

  unsigned int low, high;
  rdtsc(low, high);
  return ((ulonglong)high << 32) | low;
}

与Digital Mars C ++一起使用:

unsigned long long rdtsc()
{
   _asm
   {
        rdtsc
   }
}


读取芯片上的高性能计时器。我在进行分析时会使用它。

评论


这很有用,我将检查处理器是否为x86,因为我正在使用苹果mac机进行实验...谢谢:-)

– gagneet
08年9月9日在3:26

用户应该为高值和低值给出什么值?为什么要在函数体内定义宏?另外,ulonglong(可能是类型定义为unsigned long long的类型)也不是标准类型。我想用这个但是我不确定如何;)

–约瑟夫·加文
09年6月11日在21:07

在Linux下使用unsigned long不是正确的选择。您可能要考虑使用int,因为long和long long在64位Linux上均为64位。

–马里乌斯(Marius)
2010年7月8日15:37

如今,TSC计数器通常不可靠:当频率改变时,它会在许多处理器上改变其速度,并且在不同内核之间不一致,因此TSC并不总是会增长。

–布莱布莱德
2012年4月30日在16:30

@Marius:我使用unsigned int作为内部类型实现了您的注释。

–布莱布莱德
2012年4月30日在16:34

#9 楼

如果需要亚秒精度,则需要使用特定于系统的扩展名,并且必须与操作系统的文档进行核对。 POSIX的gettimeofday最多支持微秒,但由于计算机的频率不高于1GHz,因此没有什么比这更精确的了。

评论


想要保持代码的可移植性,将看到boost库并检查是否可以将其与代码捆绑在一起。谢谢 :-)

– gagneet
08年9月9日在3:28

#10 楼

我使用的是Borland代码,这里的代码ti_hund有时会给我一个负数,但计时相当不错。

#include <dos.h>

void main() 
{
struct  time t;
int Hour,Min,Sec,Hun;
gettime(&t);
Hour=t.ti_hour;
Min=t.ti_min;
Sec=t.ti_sec;
Hun=t.ti_hund;
printf("Start time is: %2d:%02d:%02d.%02d\n",
   t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);
....
your code to time
...

// read the time here remove Hours and min if the time is in sec

gettime(&t);
printf("\nTid Hour:%d Min:%d Sec:%d  Hundreds:%d\n",t.ti_hour-Hour,
                             t.ti_min-Min,t.ti_sec-Sec,t.ti_hund-Hun);
printf("\n\nAlt Ferdig Press a Key\n\n");
getch();
} // end main


#11 楼

使用Brock Adams的方法,并具有一个简单的类:

int get_cpu_ticks()
{
    LARGE_INTEGER ticks;
    QueryPerformanceFrequency(&ticks);
    return ticks.LowPart;
}

__int64 get_cpu_clocks()
{
    struct { int32 low, high; } counter;

    __asm cpuid
    __asm push EDX
    __asm rdtsc
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    return *(__int64 *)(&counter);
}

class cbench
{
public:
    cbench(const char *desc_in) 
         : desc(strdup(desc_in)), start(get_cpu_clocks()) { }
    ~cbench()
    {
        printf("%s took: %.4f ms\n", desc, (float)(get_cpu_clocks()-start)/get_cpu_ticks());
        if(desc) free(desc);
    }
private:
    char *desc;
    __int64 start;
};


用法示例:

int main()
{
    {
        cbench c("test");
        ... code ...
    }
    return 0;
}


结果:

测试花费了:0.0002 ms

有一些函数调用开销,但应该还足够快:)

#12 楼

您可以使用Embedded Profiler(对于Windows和Linux是免费的),它具有与多平台计时器的接口(以处理器周期计数),并且可以为您提供每秒的周期数:

EProfilerTimer timer;
timer.Start();

... // Your code here

const uint64_t number_of_elapsed_cycles = timer.Stop();
const uint64_t nano_seconds_elapsed =
    mumber_of_elapsed_cycles / (double) timer.GetCyclesPerSecond() * 1000000000;


将循环计数重新计算为时间可能对于现代处理器来说是危险的操作,在这些处理器中,CPU频率可以动态更改。因此,为确保转换时间正确,必须在性能分析之前固定处理器频率。

#13 楼

如果这是针对Linux,则我一直在使用函数“ gettimeofday”,该函数返回一个结构,该结构给出自大纪元以来的秒数和微秒数。然后,您可以使用timersub将两者相减以获得时间差,并将其转换为所需的任意时间精度。但是,您指定了纳秒,看起来像函数clock_gettime()就是您想要的。它将时间(以秒和纳秒为单位)放入传递给它的结构中。

评论


clock_gettime()现在应该可以解决问题。会尝试使用相同的目的...

– gagneet
08年9月9日,下午3:27

#14 楼

您对此有何看法:

    int iceu_system_GetTimeNow(long long int *res)
    {
      static struct timespec buffer;
      // 
    #ifdef __CYGWIN__
      if (clock_gettime(CLOCK_REALTIME, &buffer))
        return 1;
    #else
      if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &buffer))
        return 1;
    #endif
      *res=(long long int)buffer.tv_sec * 1000000000LL + (long long int)buffer.tv_nsec;
      return 0;
    }


#15 楼

这是一个很好的Boost计时器,可以很好地工作:

//Stopwatch.hpp

#ifndef STOPWATCH_HPP
#define STOPWATCH_HPP

//Boost
#include <boost/chrono.hpp>
//Std
#include <cstdint>

class Stopwatch
{
public:
    Stopwatch();
    virtual         ~Stopwatch();
    void            Restart();
    std::uint64_t   Get_elapsed_ns();
    std::uint64_t   Get_elapsed_us();
    std::uint64_t   Get_elapsed_ms();
    std::uint64_t   Get_elapsed_s();
private:
    boost::chrono::high_resolution_clock::time_point _start_time;
};

#endif // STOPWATCH_HPP


//Stopwatch.cpp

#include "Stopwatch.hpp"

Stopwatch::Stopwatch():
    _start_time(boost::chrono::high_resolution_clock::now()) {}

Stopwatch::~Stopwatch() {}

void Stopwatch::Restart()
{
    _start_time = boost::chrono::high_resolution_clock::now();
}

std::uint64_t Stopwatch::Get_elapsed_ns()
{
    boost::chrono::nanoseconds nano_s = boost::chrono::duration_cast<boost::chrono::nanoseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(nano_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_us()
{
    boost::chrono::microseconds micro_s = boost::chrono::duration_cast<boost::chrono::microseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(micro_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_ms()
{
    boost::chrono::milliseconds milli_s = boost::chrono::duration_cast<boost::chrono::milliseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(milli_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_s()
{
    boost::chrono::seconds sec = boost::chrono::duration_cast<boost::chrono::seconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(sec.count());
}


#16 楼

简约的复制粘贴结构+懒惰用法

如果您的想法是要有一个可以用于快速测试的简约结构,那么我建议您在#include之后立即将其复制并粘贴到C ++文件中的任何位置s。这是我牺牲Allman样式格式的唯一实例。

您可以轻松地在结构的第一行中调整精度。可能的值为:nanosecondsmicrosecondsmillisecondssecondsminuteshours

#include <chrono>
struct MeasureTime
{
    using precision = std::chrono::microseconds;
    std::vector<std::chrono::steady_clock::time_point> times;
    std::chrono::steady_clock::time_point oneLast;
    void p() {
        std::cout << "Mark " 
                << times.size()/2
                << ": " 
                << std::chrono::duration_cast<precision>(times.back() - oneLast).count() 
                << std::endl;
    }
    void m() {
        oneLast = times.back();
        times.push_back(std::chrono::steady_clock::now());
    }
    void t() {
        m();
        p();
        m();
    }
    MeasureTime() {
        times.push_back(std::chrono::steady_clock::now());
    }
};


用法

MeasureTime m; // first time is already in memory
doFnc1();
m.t(); // Mark 1: next time, and print difference with previous mark
doFnc2();
m.t(); // Mark 2: next time, and print difference with previous mark
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.t(); // prints 'Mark 3: 123123' etc...


标准输出结果

Mark 1: 123
Mark 2: 32
Mark 3: 433234


如果要在执行后进行汇总

如果要在事后生成报告,例如因为您的代码介于两者之间也写入标准输出。然后将以下函数添加到struct中(在MeasureTime()之前):

void s() { // summary
    int i = 0;
    std::chrono::steady_clock::time_point tprev;
    for(auto tcur : times)
    {
        if(i > 0)
        {
            std::cout << "Mark " << i << ": "
                    << std::chrono::duration_cast<precision>(tprev - tcur).count()
                    << std::endl;
        }
        tprev = tcur;
        ++i;
    }
}


因此,您可以使用:

MeasureTime m;
doFnc1();
m.m();
doFnc2();
m.m();
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.m();
m.s();


它将像以前一样列出所有标记,但是在其他代码执行之后列出。请注意,您不应同时使用m.s()m.t()

评论


与Ubuntu 16.04上的OpenMP完美配合。非常感谢,这应该是IMO的最佳答案!

–ÍhorMé
16年8月6日在20:56

#17 楼

plf :: nanotimer是为此提供的轻量级选项,可在Windows,Linux,Mac和BSD等环境下使用。根据操作系统的不同,精度约为〜微秒:
  #include "plf_nanotimer.h"
  #include <iostream>

  int main(int argc, char** argv)
  {
      plf::nanotimer timer;

      timer.start()

      // Do something here

      double results = timer.get_elapsed_ns();
      std::cout << "Timing: " << results << " nanoseconds." << std::endl;    
      return 0;
  }