随手记——在Linux下如何测试代码执行时间

在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习。我的使命就是过滤掉大量的无效信息,将知识体系化,以短平快的方式直达问题本质,把大家从大海捞针的痛苦中解脱出来。

1 什么情况下需要测试代码执行时间

一般情况下我们写完代码之后是不会去测试它的执行时间的。除非,你的代码运行有实时性要求;或者,你是一个追求代码执行效率的程序员。

下面,主要介绍两种精度较高的方式——RDTSC方式和clock_gettime()方式。

虽然使用jiffies和gettimeofday()方式也可以达到测试代码执行时间的目的,但是精度比较低,这里就不介绍了。

2 RDTSC方式

RDTSC是read time stamp counter的缩写。CPU开始工作之后,该值就开始累加,存储在时间戳寄存器中,单位是CPU时钟cycle数目。

如果想通过TSC获取CPU工作之后流逝的时间,还需要获取一个常量——CPU时钟频率(Freq)。

# 获取指定CPU(cpu?)核当前的时钟频率
cat /sys/devices/system/cpu/cpu?/cpufreq/cpuinfo_cur_freq

然后根据以下公式即可获取CPU工作之后流逝的时间(Time)。

T i m e = T S C F r e q ( s ) \mathbf{Time} = \frac{TSC}{Freq} (s) Time=FreqTSC(s)
虽然公式中单位是秒,但是现在处理器的主频一般都非常高,所以时间统计的精度可以到达纳秒级别。

下面,给出一个比较简单的例子。

#include <stdio.h>

#define uint32_t unsigned int
#define uint64_t unsigned long long

#define CPU_FREQUENCE_HZ        (1319534 * 1000.0) /*CPU时钟频率*/
//ReaD Time-Stamp Counter
/* 使用inline函数,减少函数调用开销 */
static inline __attribute__((always_inline)) uint64_t get_rdtsc(void) 
{
         union {
                   unsigned long long tsc_64;
                   struct {
                            uint32_t lo_32;
                            uint32_t hi_32;
                   };
         } tsc;
    	/* C语言中嵌入汇编指令;rdtsc为读取TSC的指令,x86和ARM均支持该指令 */
         __asm__ __volatile__("rdtsc" :
                        "=a" (tsc.lo_32),
                        "=d" (tsc.hi_32));
#if 0
    	/*rdtscp指令为rdtsc替代指令(保序指令,可以防止CPU乱序执行)*/
         __asm__ __volatile__("rdtscp" : 
                        "=a" (tsc.lo_32),
                        "=d" (tsc.hi_32));
#endif    
         return tsc.tsc_64;
}

int main(void)
{
        uint64_t c1 = 0;
        uint64_t c2 = 0;
        float deltatime_ns = 0.0;
        int i = 0;

        /*test code*/
        c1 = get_rdtsc();
        for (i = 0; i < 1000; i++);
        c2 = get_rdtsc();
    	/* 计算代码耗时 */
        deltatime_ns = (c2 - c1) / CPU_FREQUENCE_HZ * 1000 * 1000 * 1000; 

        printf("c2 = %lld , c1 = %lld .\n", c2, c1);
        printf("Delta cycle is %lld .\n", c2-c1);
        printf("Delta time is %f ns.\n", deltatime_ns);

        return 0;
}

3 clock_gettime方式

RDTSC的方式比较简单直接,下面介绍一种功能更强大的接口——clock_gettime()。

原型如下:

int clock_gettime(clockid_t clk_id, struct timespec *tp);

struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};

其中,clk_id的取值和含义如下表:

clk_id含义
CLOCK_REALTIME真实时间(墙上时间,自1970年1月1日0时0分0秒)
CLOCK_REALTIME_COARSECLOCK_REALTIME的高性能低精度版本
CLOCK_MONOTONIC从系统启动开始计时的时间(注意不计算休眠时间)
CLOCK_MONOTONIC_COARSECLOCK_MONOTONIC的高性能低精度版本
CLOCK_MONOTONIC_RAWCLOCK_MONOTONIC的未加工数据。基于原始硬件数据,不受adjtime(3) 和 NTP的影响。
CLOCK_BOOTTIME设备启动后的时间(计算休眠时间)
CLOCK_PROCESS_CPUTIME_ID本进程执行到当前代码时CPU花费的时间
CLOCK_THREAD_CPUTIME_ID本线程执行到当前代码时CPU花费的时间

下面给出一个示例:

#include <stdio.h>
#include <time.h>

#define uint32_t unsigned int
#define uint64_t unsigned long long

int main(void)
{
        float deltatime_ns = 0.0;
        int i = 0;
        struct timespec t1, t2;

        /*test code*/
        clock_gettime(CLOCK_REALTIME, &t1);
        for (i = 0; i < 1000; i++);
        clock_gettime(CLOCK_REALTIME, &t2);
        deltatime_ns = (t2.tv_sec - t1.tv_sen) * 1000000000 + (t2.tv_nsec - t1.tv_nsec);

        printf("Delta time is %f ns.\n", deltatime_ns);

        return 0;
}

这个例子比较简单,就不多说了。

至于应该选取哪种方式来进行代码执行时间的测量,我觉得你可以都试试,哈哈。。。

如果是简单场景,个人推荐第一种就可以了~~


恭喜你又坚持看完了一篇博客,又进步了一点点!如果感觉还不错就点个赞再走吧,你的点赞和关注将是我持续输出的哒哒哒动力~~

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穿越临界点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值