随手记——在Linux下如何测试代码执行时间
Posted 穿越临界点
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随手记——在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_COARSE | CLOCK_REALTIME的高性能低精度版本 |
CLOCK_MONOTONIC | 从系统启动开始计时的时间(注意不计算休眠时间) |
CLOCK_MONOTONIC_COARSE | CLOCK_MONOTONIC的高性能低精度版本 |
CLOCK_MONOTONIC_RAW | CLOCK_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_nsec - t1.tv_nsec;
printf("Delta time is %f ns.\\n", deltatime_ns);
return 0;
}
这个例子比较简单,就不多说了。
至于应该选取哪种方式来进行代码执行时间的测量,我觉得你可以都试试,哈哈。。。
如果是简单场景,个人推荐第一种就可以了~~
恭喜你又坚持看完了一篇博客,又进步了一点点!如果感觉还不错就点个赞再走吧,你的点赞和关注将是我持续输出的哒哒哒动力~~
以上是关于随手记——在Linux下如何测试代码执行时间的主要内容,如果未能解决你的问题,请参考以下文章