一、使用ARMv8提供的独立定时器CNTVCT_EL0
System counter是Arm64下独立于CPU core的计数器,在系统上电时,会给此计数器设置固定的频率。一个映射System counter计数器内容的寄存器为CNTVCT_EL0,可在用户态下读取此寄存器获取counter值。而CNTFRQ_EL0保存的是counter的频率值(详细内容参考《【ARMv8】通用定时器总结》)。通过下面的函数实现获取counter值及频率值:
static inline uint64_t
arm64_cntvct(void)
{
uint64_t tsc;
asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));
return tsc;
}static inline uint64_t
arm64_cntfrq(void)
{
uint64_t freq;
asm volatile("mrs %0, cntfrq_el0" : "=r" (freq));
return freq;
}static inline uint64_t
rdtsc(void)
{
return arm64_cntvct();
}
arm64_cntvct 这个函数需要进行换算的,读取寄存器 cntvct_el0,只是获取了固定频率下的寄存器的值,这个值仅仅是单调自增,代表“晶振”几次,并不是生活中时间单位秒 或者ns;
代码修改如下:
uint64_t gettscns() {
uint64_t io_tsc_ns;
uint64_t tsc;
__asm__ __volatile__("mrs %0, cntvct_el0" : "=r" (tsc));
io_tsc_ns = tsc * 32;
return io_tsc_ns;
}
io_tsc_ns = tsc * 32; 读出的值,需要在换算成ns;
那么 32是怎么获取的?
通过 dmesg |grep clock ,获取时钟的分辨率,即晶振一次多长时间;
通过上面的截图,可以看到 resolution 32 ns,就是这个分辨率。
对于这个时间的获取和换算,分析结束;
使用方式;
int main ()
{
start = gettscns();
syscall(SYS_clock_gettime, CLOCK_REALTIME, &sys);
stop = gettscns();printf("tsc: %ld ns ,stop - start);
}