定时器在C中查找函数调用中的已用时间

我想计算在C中函数调用期间经过的时间,精度为1纳秒。

C中是否有可用的定时器function?

如果是,请提供示例代码段。

伪代码

Timer.Start() foo(); Timer.Stop() Display time elapsed in execution of foo() 

环境细节: – 在RHEL机器上使用gcc 3.4编译器

请问您使用的是哪种处理器? 如果您使用的是x86处理器,则可以查看时间戳计数器( tsc )。 此代码段:

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

将把CPU运行的周期数分别设置为lowhigh (它需要2 long s;你可以将结果存储在long long int ),如下所示:

 inline void getcycles (long long int * cycles) { unsigned long low; long high; rdtsc(low,high); *cycles = high; *cycles <<= 32; *cycles |= low; } 

请注意,这将返回CPU执行的周期数。 您需要获得CPU速度,然后计算每ns的循环次数,以获得经过的ns数。

为了做到这一点,我已经解析了/proc/cpuinfo的“cpu MHz”字符串,并将其转换为小数。 在那之后,它只是一点数学,并记住1MHz =每秒1,000,000个周期,并且有10亿ns /秒。

在Intel和兼容的处理器上,您可以使用rdtsc指令,该指令可以轻松地包装到asm()C代码块中。 它返回内置处理器周期计数器的值,该计数器在每个周期递增。 你获得高分辨率,这样的时间非常快。

要确定您需要校准的增量有多快 – 在固定的时间段(如5秒)内调用此指令两次。 如果在将频率转换为较低功耗的处理器上执行此操作,则可能会出现校准问题。

使用clock_gettime(3) 。 有关更多信息,请键入man 3 clock_gettime 。 话虽这么说,纳秒精度很少是必要的。

任何计时器function都必须是特定于平台的,特别是在具有该精度要求的情况下。

POSIX系统中的标准解决方案是gettimeofday() ,但它只有几微秒的精度。

如果这是用于性能基准测试,则标准方法是使测试中的代码花费足够的时间来降低精度要求。 换句话说,运行测试代码一秒钟(或更长时间)。

c中没有定时器,保证1纳秒的精度。 您可能想要查看clock()或更好的POSIX gettimeofday()

我不知道你是否会找到任何提供单纳秒分辨率的定时器 – 这取决于系统时钟的分辨率 – 但你可能想看看http://code.google.com/ p /高分辨率计时器/ 。 他们表示,他们可以在大多数Linux系统上提供微秒级别的分辨率,在Sun系统上提供纳秒级的分辨率。

在这种规模上制定基准并不是一个好主意。 你有足够的时间来获得最少的时间,如果你在纳秒上工作,这会导致你的结果不可靠。 您可以使用平台系统调用或更大规模的boost :: Date_Time [首选]。

你可以运行10 ^ 9次并秒表吗?

您可以使用标准系统调用,如gettimeofday,如果您确定您的进程在CPU时间内获得100%。 我可以想到很多情况,当你执行foo()时,其他线程和进程可能会窃取CPU时间。

你要求的是这种方式不可能的东西。 您需要硬件级别支持才能达到该级别的精度,甚至可以非常仔细地控制变量。 如果在运行代码时遇到中断会怎样? 如果操作系统决定运行其他一些代码怎么办?

你的代码做了什么? 它是否使用RAM内存? 如果您的代码和/或数据是否在缓存中,该怎么办?

在某些环境中,只要您控制这些变量,就可以将HW级别计数器用于此作业。 但是如何防止Linux中的上下文切换?

例如,在德州仪器的DSP工具(Code Composer Studio)中,您可以非常准确地分析代码,因为整个调试环境的设置使得仿真器(例如Blackhawk)接收有关每个操作运行的信息。 您还可以在某些处理器中设置直接编码到芯片内部HW块中的观察点。 这是有效的,因为内存通道也被路由到此调试块。

它们确实在CSL(芯片支持库)中提供了function,这些function是您要求的,其时序开销是几个周期。 但这仅适用于其处理器,完全取决于从HW寄存器读取定时器值。

我们都浪费时间重新创建这个测试样本。 为什么不发布编译就绪? 无论如何,这是我的结果。

 CLOCK_PROCESS_CPUTIME_ID resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 459.427311 msec 0.110 microsec / call CLOCK_MONOTONIC resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 64.498347 msec 0.015 microsec / call CLOCK_REALTIME resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 65.494828 msec 0.016 microsec / call CLOCK_THREAD_CPUTIME_ID resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 427.133157 msec 0.102 microsec / call rdtsc 4194304 iterations : 115.427895 msec 0.028 microsec / call Dummy 16110479703957395943 rdtsc in milliseconds 4194304 iterations : 197.259866 msec 0.047 microsec / call Dummy 4.84682e+08 UltraHRTimerMs 197 HRTimerMs 197.26 #include  #include  #include  #include  #include  #include  enum { TESTRUNS = 1024*1024*4 }; class HRCounter { private: timespec start, tmp; public: HRCounter(bool init = true) { if(init) SetStart(); } void SetStart() { clock_gettime(CLOCK_MONOTONIC, &start); } double GetElapsedMs() { clock_gettime(CLOCK_MONOTONIC, &tmp); return (double)(tmp.tv_nsec - start.tv_nsec) / 1000000 + (tmp.tv_sec - start.tv_sec) * 1000; } }; __inline__ uint64_t rdtsc(void) { uint32_t lo, hi; __asm__ __volatile__ ( // serialize "xorl %%eax,%%eax \n cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx"); /* We cannot use "=A", since this would use %rax on x86_64 and return only the lower 32bits of the TSC */ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); return (uint64_t)hi << 32 | lo; } inline uint64_t GetCyclesPerMillisecondImpl() { uint64_t start_cyles = rdtsc(); HRCounter counter; std::this_thread::sleep_for (std::chrono::seconds(3)); uint64_t end_cyles = rdtsc(); double elapsed_ms = counter.GetElapsedMs(); return (end_cyles - start_cyles) / elapsed_ms; } inline uint64_t GetCyclesPerMillisecond() { static uint64_t cycles_in_millisecond = GetCyclesPerMillisecondImpl(); return cycles_in_millisecond; } class UltraHRCounter { private: uint64_t start_cyles; public: UltraHRCounter(bool init = true) { GetCyclesPerMillisecond(); if(init) SetStart(); } void SetStart() { start_cyles = rdtsc(); } double GetElapsedMs() { uint64_t end_cyles = rdtsc(); return (end_cyles - start_cyles) / GetCyclesPerMillisecond(); } }; int main() { auto Run = [](std::string const& clock_name, clockid_t clock_id) { HRCounter counter(false); timespec spec; clock_getres( clock_id, &spec ); printf("%s resolution: %ld sec %ld nano\n", clock_name.c_str(), spec.tv_sec, spec.tv_nsec ); counter.SetStart(); for ( int i = 0 ; i < TESTRUNS ; ++ i ) { clock_gettime( clock_id, &spec ); } double fb = counter.GetElapsedMs(); printf( "clock_gettime %d iterations : %.6f msec %.3f microsec / call\n", TESTRUNS, ( fb ), (( fb ) * 1000) / TESTRUNS ); }; Run("CLOCK_PROCESS_CPUTIME_ID",CLOCK_PROCESS_CPUTIME_ID); Run("CLOCK_MONOTONIC",CLOCK_MONOTONIC); Run("CLOCK_REALTIME",CLOCK_REALTIME); Run("CLOCK_THREAD_CPUTIME_ID",CLOCK_THREAD_CPUTIME_ID); { HRCounter counter(false); uint64_t dummy; counter.SetStart(); for ( int i = 0 ; i < TESTRUNS ; ++ i ) { dummy += rdtsc(); } double fb = counter.GetElapsedMs(); printf( "rdtsc %d iterations : %.6f msec %.3f microsec / call\n", TESTRUNS, ( fb ), (( fb ) * 1000) / TESTRUNS ); std::cout << "Dummy " << dummy << std::endl; } { double dummy; UltraHRCounter ultra_hr_counter; HRCounter counter; for ( int i = 0 ; i < TESTRUNS ; ++ i ) { dummy += ultra_hr_counter.GetElapsedMs(); } double fb = counter.GetElapsedMs(); double final = ultra_hr_counter.GetElapsedMs(); printf( "rdtsc in milliseconds %d iterations : %.6f msec %.3f microsec / call\n", TESTRUNS, ( fb ), (( fb ) * 1000) / TESTRUNS ); std::cout << "Dummy " << dummy << " UltraHRTimerMs " << final << " HRTimerMs " << fb << std::endl; } return 0; }