在C中查找函数调用中经过的时间的计时器
我想用C计算函数调用过程中经过的时间,精确到1纳秒 在C语言中是否有定时器功能可以实现这一点 如果是,请提供示例代码段 伪代码在C中查找函数调用中经过的时间的计时器,c,profiling,timer,C,Profiling,Timer,我想用C计算函数调用过程中经过的时间,精确到1纳秒 在C语言中是否有定时器功能可以实现这一点 如果是,请提供示例代码段 伪代码 Timer.Start() foo(); Timer.Stop() Display time elapsed in execution of foo() 环境详细信息:-在RHEL机器上使用gcc 3.4编译器任何计时器功能都必须是特定于平台的,特别是在精度要求方面 POSIX系统中的标准解决方案是gettimeofday(),但其精度只有微秒 如果这是为了性能基准
Timer.Start()
foo();
Timer.Stop()
Display time elapsed in execution of foo()
环境详细信息:-在RHEL机器上使用gcc 3.4编译器任何计时器功能都必须是特定于平台的,特别是在精度要求方面 POSIX系统中的标准解决方案是
gettimeofday()
,但其精度只有微秒
如果这是为了性能基准测试,标准方法是让测试中的代码花费足够的时间来降低精度要求。换句话说,运行测试代码一整秒钟(或更长时间)。c中没有保证1纳秒精度的计时器。您可能想查看一下POSIX
gettimeofday()
我不知道您是否会找到任何可以提供一纳秒分辨率的计时器——这取决于系统时钟的分辨率——但您可能想看看。它们表明,它们可以在大多数Linux系统上提供微秒级的分辨率,在Sun系统上提供纳秒级的分辨率。在Intel和兼容处理器上,您可以使用rdtsc指令,该指令可以轻松封装到asm()C代码块中。它返回在每个周期递增的内置处理器周期计数器的值。你可以获得很高的分辨率,这样的时间非常快
要想知道这个增量有多快,你需要校准——在固定的时间段(比如5秒)内调用这个指令两次。如果在将频率转换为较低功耗的处理器上执行此操作,则可能会遇到校准问题。在这种规模上进行基准测试不是一个好主意。至少在获取时间方面会有开销,如果以纳秒为单位工作,则可能会导致结果不可靠。您可以使用平台系统调用,也可以使用更大范围的系统调用。请问您使用的是哪种处理器?如果您使用的是x86处理器,则可以查看时间戳计数器(
tsc
)。此代码段:
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
将CPU运行的周期数分别设置为低
和高
(需要2个长
s;您可以将结果存储在长整型
)中,如下所示:
inline void getcycles (long long int * cycles)
{
unsigned long low;
long high;
rdtsc(low,high);
*cycles = high;
*cycles <<= 32;
*cycles |= low;
}
inline void getcycles(长整型*周期)
{
无符号长低位;
长高;
rdtsc(低、高);
*周期=高;
*周期你能把它运行10^9次然后秒表吗?使用clock\u gettime(3)
。有关更多信息,请键入man 3 clock\u gettime
。也就是说,纳秒精度很少是必需的。如果您确信您的进程获得100%的CPU时间,您可以使用标准的系统调用,如gettimeofday。我可以想到许多情况,在执行foo()其他线程和进程可能会占用CPU时间。您要求的是以这种方式不可能实现的事情。您需要硬件级别的支持才能达到该级别的精度,甚至可以非常小心地控制变量。如果您在运行代码时遇到中断,会发生什么情况?如果操作系统决定运行其他部分co,该怎么办德
你的代码是做什么的?它使用RAM内存吗?如果你的代码和/或数据在缓存中或不在缓存中怎么办
在某些环境中,只要控制这些变量,就可以使用硬件级计数器执行此任务。但在Linux中如何防止上下文切换
例如,在Texas Instruments的DSP工具(Code Composer Studio)中,您可以非常精确地分析代码,因为整个调试环境的设置使得仿真器(例如Blackhawk)接收有关每个操作运行的信息。您还可以设置观察点,这些观察点直接编码到某些处理器芯片内的HW块中。这是有效的,因为内存通道也路由到此调试块
他们在CSL(芯片支持库)中提供功能这就是你所要求的,时间开销只有几个周期。但这只适用于他们的处理器,完全依赖于从硬件寄存器读取计时器值。我们都在浪费时间重新创建这个测试样本。为什么不发布一些编译就绪的东西呢?总之,这是我的结果
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 <time.h>
#include <cstdio>
#include <string>
#include <iostream>
#include <chrono>
#include <thread>
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;
}
CLOCK\u进程\u CPUTIME\u ID分辨率:0秒1纳米
时钟时间4194304次迭代:459.427311毫秒0.110微秒/次
时钟分辨率:0秒1纳米
时钟时间4194304次迭代:64.498347毫秒0.015微秒/次
时钟实时分辨率:0秒1纳米
时钟时间4194304次迭代:65.494828毫秒0.016微秒/次
时钟线程CPU时间ID分辨率:0秒1纳米
时钟时间4194304次迭代:427.133157毫秒0.102微秒/次
rdtsc 4194304迭代次数:115.427895毫秒0.028微秒/次
假人16110479703957395943
rdtsc(毫秒)4194304次迭代:197.259866毫秒0.047微秒/次
假人4.84682e+08 UltraHRTimerMs 197 HRTimerMs 197.26
#包括
#包括
#包括
#包括
#包括
#包括
枚举{TESTRUNS=1024*1024*4};
类计数器
{
私人:
timespec启动,tmp;
公众:
hr计数器(bool init=true)
{
if(init)
SetStart();
}
void SetStart()
{
时钟获取时间(时钟单调和开始);
}
双GetElapsedMs()
{
时钟获取时间(时钟单调,&tmp);
返回(双倍)(tmp.tv\u nsec-start.tv\u nsec)/1000000+(tmp.tv\u sec-start.tv\u sec)*1000;
}
};
__内联rdtsc(无效){
uint32_t lo,hi;
__asm\uuuuuuuuuuuuuuuuuuuuuuuu volatile\uuuuuuu(//序列化
xorl%%eax,%%eax\n cpuid
:%rax、%rbx、%rcx、%rdx);
/*我们不能使用“=A”,因为这将在x86_64上使用%rax,并且只返回TSC的较低32位*/
__asm__