1,如何度量时间差,如何比较时间;
a,时间表示:
一> HZ,系统硬件定时器以一定的间隔周期性的产生时钟中断,这个间隔周期用HZ的值来表示,这个值是和体系结构相关的,x86体系结构中默认设置为1000,HZ被定义在linux/param.h头文件中,可以根据需要修改HZ的值,并重新编译内核;
HZ值得获取,通过获取/proc/interrupts 及 /proc/uptime 中从内核空间中导出的值来计算HZ,两者相除即为HZ;
二> 内核计数器,1》用途:内核计数器记录系统引导以来的硬件定时器产生的时钟中断的次数即时钟滴答数,在每次系统引导的时候初始化为0;
2》存储:内核计数器的值用u64(无符号64位)类型的变量 jiffies_64存储,无论在32位还是64位架构上均是64位,需要注意的是内核计数器的内存溢出问题;
3》编程使用:在内核开发中可以简单的读取unsigned long jiffies变量的值;
4》内核计数器读取:在64位架构上jiffies与jiffies_64位同一个值,而在32位架构上高位和低位读取不是原子的,读取高位低位可能变化,读取低位高位可能变化,所以可能读取错误的值,为了避免错误读取,内核提供的辅助函数:unsigned long get_jiffies_64(void);来读取内核计数器的值;
三> HZ与内核计数器jiffies_64之间的联系:内核计数器/HZ=当前时间(jiffies/HZ=当前时间);
四> 为了得到更加精确的时间分辨率,使用与体系结构相关的cpu计数寄存器,例如Inter x86架构cpu的 计数寄存器tsc寄存器;
内核提供了原子的读取tsc寄存器值的宏:unsigned long rdtsc(h32,l32) unsigned long rdtscl(l32) long long rdtsdll(var64)
五> 用户空间时间表示:毫秒级别 struct timeval{ /*???*/}; 纳秒级别 struct timespec{/*?????*/};
为了实现用户空间时间表示与内核空间时间表示的转换,内核提供了辅助函数(用户空间结构体与内核空间内核计数器的转换):
b,时间差及时间比较:
一> 时间比较;
通过内核提供的内核宏来比较时间:
time_after(a,b); ——a 在 b之后则返回true;
time_before(a,b);——a 在 b之前则返回true;
time_after_eq(a,b);——a 在 b之后或a与b相等则返回true;
time_before_eq(a,b);——a 在 b之前或a与b相等则返回true;
上述宏函数的实现原理是:首先检查内核计数器是否溢出,typecheck(unsigned long,a); 其次,将内核计数器值转换为signed long类型,然后做差比较大小;
二> 时间差:
时间差的计算可以用上述时间比较的实现原理,将内核计数器值转换为signed long类型的数据然后进行减法运算;
2,获取当前时间;
一> 获取系统引导以来的时钟滴答数jiffies的值:jiffies/HZ = 当前时间(单位s)-- 计算时间间隔
二> 墙钟,内核函数:
将年月日转换为时钟中断次数;
unsigned long mktime(unsigned long year,unsigned long month,unsigned long day,unsigned long hour,unsigned long minis , unsigned long seconds);
获取当前墙钟时间:
void do_gettimeofday(struct timeval *);
获取当前内核时间:
struct timespec current_kernel_time();(分辨率是纳秒级,当时实际上达不到)