zoukankan      html  css  js  c++  java
  • Linux设备驱动程序 之 度量时间差

    概述

    内核通过定时器中断来跟踪事件流;

    时钟中断由系统定时硬件以及周期性的间隔产生,这个间隔由内核根据HZ的值设定,HZ是一个细节结构有关的常数;作为一般性规则,即使知道对应平台上的确切HZ值,也不应该在编程时依赖该HZ值;

    如果想改变系统时钟中断发生的频率,可以通过修改HZ值来进行,但是,如果修改了头文件中的HZ值,则必须使用新的值重新编译内核以及所有模块;

    每当时钟中断发生时,内核内部计数器的值增加一;这个计数器的值在系统引导值初始化为0,因此,它的值就是上次操作系统引导以来的时钟滴答数;这个计数器是一个64位变量(即使在32位架构上也是64位),称为jiffies_64;但是驱动程序发开者通常访问的是jiffies变量,它是unsigned long类型的变量,要么和jiffies_64相同,要么仅仅是jiffies_64的低23位,根据架构是64位还是32位而定;通常首选使用jiffies,因为对它的访问很快,从而对于64位jiffies_64值的访问并不需要在所有架构上都是原子的;

    使用jiffies计数器

    该计数器和读取计数器的工具函数包含在<linux/jiffies.h>中,但是通常只需要包含<linux/sched.h>文件,后者会自动包含jiffies.h;

    需要说明的是,jiffies和jiffies_64均应该被看成只读变量;

    在代码中需要记录jiffies的当前值时,可简单的访问上面说的unsigned long变量;该变量被声明为volatile,这样可以避免编译器对访问该变量的语句的优化;在代码需要计算未来的时间戳时,必须读取当前的计数器;

    1 #incldue <linux/jiffies.h>
    2 
    3 unsigned long j, stamp_1, stamp_half, stamp_n;
    4 
    5 j = jiffies;
    6 
    7 stamp_1 = j + HZ;
    8 stamp_half = j + HZ/2;
    9 stamp_n = j + n * HZ / 1000;
    时间比较

    只要采用正确的方式来比较不同的值,上述代码不会因为jiffies的溢出而出现问题;比较缓存时间和当前时间,应该使用下面宏:

     1 #define time_after(a,b)        
     2     (typecheck(unsigned long, a) && 
     3      typecheck(unsigned long, b) && 
     4      ((long)((b) - (a)) < 0))
     5 #define time_before(a,b)    time_after(b,a)
     6 
     7 #define time_after_eq(a,b)    
     8     (typecheck(unsigned long, a) && 
     9      typecheck(unsigned long, b) && 
    10      ((long)((a) - (b)) >= 0))
    11 #define time_before_eq(a,b)    time_after_eq(b,a)
    用户空间时间与内核时间的转换

    用户空间的时间使用struct timeval和struct timespec来表示,为了在用户空间时间和内核时间之间进行转换,内核提供了下面的四个辅助函数:包含在<linux/jiffies.h>中

    1 unsigned long timespec_to_jiffies(const struct timespec *value)
    2 void jiffies_to_timespec(const unsigned long jiffies,
    3                        struct timespec *value)
    4 
    5 unsigned long timeval_to_jiffies(const struct timeval *value)
    6 void jiffies_to_timeval(const unsigned long jiffies,
    7                    struct timeval *value)
    访问jiffies_64

    对jiffies_64的访问不像对jiffies的访问那么直接,在64位架构上,两个变量其实是同一个变量;但是在32位架构上,对64位的访问不是原子的,必须借助一个辅助函数,该函数完成了适当的锁定:

    1 #if (BITS_PER_LONG < 64)
    2 u64 get_jiffies_64(void);
    3 #else
    4 static inline u64 get_jiffies_64(void)
    5 {
    6     return (u64)jiffies;
    7 }
    8 #endif
  • 相关阅读:
    2017中国大学生程序设计竞赛
    [POJ3667]Hotel(线段树,区间合并,重写)
    [HDOJ3308]LCIS(线段树,区间合并,新的代码)
    [HDOJ5091]Beam Cannon(贪心,线段树,扫描线,矩形内覆盖最多点)
    HDU 5128.The E-pang Palace-计算几何
    HDU 5127.Dogs' Candies-STL(vector)神奇的题,set过不了 (2014ACM/ICPC亚洲区广州站-重现赛(感谢华工和北大))
    洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
    hihoCoder #1831 : 80 Days-RMQ (ACM/ICPC 2018亚洲区预选赛北京赛站网络赛)
    ACM竞赛常用头文件模板-备忘
    C++-二维vector初始化大小方法-备忘
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11760846.html
Copyright © 2011-2022 走看看