在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(),但其精度只有微秒 如果这是为了性能基准

我想用C计算函数调用过程中经过的时间,精确到1纳秒

在C语言中是否有定时器功能可以实现这一点

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

伪代码

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__