最近被内核时钟精度弄的很是郁闷。具体情况如下:

扫盲:1秒=1000毫秒=1000000微妙=1000000000纳秒

首先:linux有一个很重要的概念——节拍,它的单位是(次/秒)。2.6内核这个值是1000,系统中用一个HZ的宏表征这个值。同时有全局的jiffies变量,表征从开机以来经过的节拍次数(这里面还有故事,后面说,先记住这个)。当然还有wall_jiffies的墙上jiffies来表示从 07-01-1970 到现在的节拍数。每个节拍里面执行一次时钟中断。就是说,它的精度是毫秒。

接着:内核中还有一个变量xtime表征系统的实际时间(墙上时间),定义如下。其中xtime.tv_sec以秒为单位,存放从Unix祖宗定的纪元时间(19700701)到现在的秒数。xtime.tv_nsec以纳秒为单位,记录从上一秒开始经过的纳秒数。就是说,它的精度是纳秒。

C

struct timespec xtime;

struct timespec{

time_t tv_sec; //秒

long tv_nsec; //纳秒

};

1

2

3

4

5

6

structtimespecxtime;

structtimespec{

time_ttv_sec;//秒

longtv_nsec;//纳秒

};

最后:linux提供一个gettimeofday的系统调用,它会返回一个timeval的结构体,定义如下。解释同上,tv_sec代表墙上时间的秒,tv_usec表示从上一秒到现在经过的微秒数。就是说,它的精度是微妙。

C

struct timeval{

long tv_sec; //秒

long tv_usec; //微妙

};

1

2

3

4

structtimeval{

longtv_sec;//秒

longtv_usec;//微妙

};

精彩的来了:

1. 内核中的xtime会在每个时钟中断的时候被更新一次,也就是每个节拍更新一次。你妹!!每毫秒更新一次怎么能冒出来纳秒的精度??而且,内核还有可能丢失节拍。怎么能是纳秒??

2. 各种书上说,gettimeofday系统调用是读取的xtime的值。日,为啥读出来之后精度丢了?变成微妙了?

寻寻觅觅终于理清了故事:

针对问题1:在linux启动的时候,一个节拍的时间长度还会以纳秒为单位初始化到tick_nsec中,初始化值为999848ns,坑爹啊!不到一毫秒!节拍大约为1000.15Hz。靠!实际的节拍竟然不是准确的1000!所以在每个时钟中断通过wall_jiffies去更新xtime的时候得到的就是一个以纳秒为最小单位的的值。所以!xtime的粒度应该是不到1毫秒,也就是精度是不到1毫秒。

针对问题2:gettimeday系统调用的读xtime代码部分如下:

C

do{

unsigned long lost;

seq = read_seqbegin(&xtime_lock);

usec = timer->get_offset(); //在计时器中取从上一次时钟中断到现在的微秒数

lost = jiffies - wall_jiffies;

if(lost)

usec += lost*(1000000/HZ); //HZ是节拍宏,值1000

sec = xtime.tv_sec;

usec += (xtime.tv_nsec/1000); //由纳秒转为微妙

}while(read_seqretry(&xtime_lock, seq))

1

2

3

4

5

6

7

8

9

10

11

12

do{

unsignedlonglost;

seq=read_seqbegin(&xtime_lock);

usec=timer->get_offset();//在计时器中取从上一次时钟中断到现在的微秒数

lost=jiffies-wall_jiffies;

if(lost)

usec+=lost*(1000000/HZ);//HZ是节拍宏,值1000

sec=xtime.tv_sec;

usec+=(xtime.tv_nsec/1000);//由纳秒转为微妙

}while(read_seqretry(&xtime_lock,seq))

while部分使用了seg锁,只看中间的就好了。加了注释之后就很清晰了。由于节拍可能会丢失,所以lost是丢失的节拍数(不会很多)。至于计时器就比较麻烦了,timer可能有下面四种情况。

a. 如果cur_timer指向timer_hpet对象,该方法使用HPET定时器——Inter与Microsoft开发的高精度定时器频率至少10MHz,也就是说此时可提供真正的微妙级精度。

b. 如果cur_timer指向timer_pmtmr对象,该方法使用ACPI PMT计时器(电源管理定时器)平率大约3.58MHz,也就是说也可以提供真正的微妙级精度。

c. 如果cur_timer指向timer_tsc对象,该方法使用时间戳计数器,内置在所有8086处理器,每个CPU时钟,计数器增加一次,频率就是CPU频率,所以timer精度最高。完全可以胜任微妙级的精度。

d. 如果cur_timer指向timer_pit对象,该方法使用PIT计数器,也即是最开始提到的节拍计数,频率大概是1000Hz,此时显然不能提供精度达到微妙的时间。所以只有这种情况是假毫秒精度!

综上:如果使用gettimeofday系统调用,只要不要使用节拍计数器就可以保证达到微妙精度的时间(刨除进程上下文时间误差)。至于网上说的可以拿到纳秒精度的时间,看起来都是错的。除非通过修改内核,使用时间戳计数器实现。Over!

最后最后说一个事情:jiffies的定义的是4字节,你可能猜想它初始值是0。实际上,事实并非如此!linux中jiffies被初始化为0xfffb6c20,它是一个32位有符号数,正好等于-300 000。因此,计数器会在系统启动5分钟内溢出。这是为了使对jiffies溢出处理有缺陷的内核代码在开发阶段被发现,避免此类问题出现在稳定版本中。

参考《深入理解linux内核》

原文链接

linux内核纳秒精度时间,Linux时钟精度:毫秒?微妙?纳秒?相关推荐

  1. linux内核下获取系统时间,linux内核获取当前系统时间

    转载自:http://blog.csdn.net/heanyu/article/details/6552578 7.2. 获知当前时间 内核代码能一直获取一个当前时间的表示, 通过查看 jifies ...

  2. 移植linux内核-映像文件,移植Linux内核-映像文件

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://tigerwang202.blogbus.com/logs/43927976.html 首先从Blackfin uCli ...

  3. linux 内核 课程,Linux内核分析课程-全面剖析Linux内核技术 揭开Linux内核的面纱 Linux内核学习视频教 ......

    课程名称 Linux内核分析课程-全面剖析Linux内核技术 揭开Linux内核的面纱 Linux内核学习视频 课程目录 (1)\1, 计算机是如何工作的?:目录中文件数:0个 (2)\2, 操作系统 ...

  4. 【Linux 内核】编译 Linux 内核 ① ( 下载指定版本的 Linux 内核源码 | Linux 内核版本号含义 | 主版本号 | 次版本号 | 小版本号 | 稳定版本 )

    文章目录 一.下载 Linux 内核 1.下载最新版本 Linux 内核 2.下载指定版本 Linux 内核 二.Linux 内核版本号含义 一.下载 Linux 内核 1.下载最新版本 Linux ...

  5. linux内核分为四个子系统,linux操作系统的内核有哪几个子系统构成,简要说明各子系统的作用...

    Linux是一个一体化内核(monolithic kernel)系统."内核"指的是一个提供硬件抽象层.磁盘及文件系统控制.多任务等功能的系统软件.一个内核不是一套完整的操作系统. ...

  6. Linux内核态之间进程通信,Linux 系统内核空间与用户空间通信的实现与分析[转载]...

    [https://www.ibm.com/developerworks/cn/linux/l-netlink/index.html] 多数的 Linux 内核态程序都需要和用户空间的进程交换数据,但 ...

  7. Linux 编译时查找错误字符,编译Linux内核时出现“fatal error: linux/netfilter/xt_dscp: No such file or directory”...

    编译Linux内核时出现"fatal error: linux/netfilter/xt_dscp: No such file or directory".下面开始查找原因. 第一 ...

  8. linux内核编译最详细,Linux内核编译详细教程,linux内核编译

    Linux内核编译详细教程,linux内核编译 尝试编译下Linux-kernel 4.14.14,使用Ubuntu 16.04 64位 系统. kernel-4.14.14 内核文件约96MB,解压 ...

  9. 升级 Ubuntu Linux 内核的几种不同方法 | Linux 中国

    转载自:升级 Ubuntu Linux 内核的几种不同方法 | Linux 中国 升级 Ubuntu Linux 内核的几种不同方法 | Linux 中国 译者/Ping Yang  Linux  2 ...

  10. Linux内核编程(二)-----------Linux内核初探

    写在前面:本篇主要介绍Linux内核的开发模式.linux代码的组成.vmlinux  zImage  uImage的区别,以及编译下内核. 正文: 一.Linux内核的开发模式 1.git:是一个分 ...

最新文章

  1. 微服务拆分,选型与演进
  2. secureCRT常用设置
  3. BSP for good 3d engine
  4. Java 给编译器看的注释--Annotation
  5. 一文详解微服务架构的数据设计
  6. LNK2019 无法解析的外部符号 __imp_CommandLineToArgvW,该符号在函数 WinMain 中被引用
  7. hadoop3.1.1 HA高可用分布式集群安装部署
  8. 电商购物APP UI 模板素材,充满时尚感的设计
  9. 软件架构设计的六大原则
  10. sizeo(结构体)的问题
  11. 26个字母与ASCII值对照表
  12. python 微信自动发图片,批量发送
  13. Mysql 计算年龄函数
  14. Python开发微信公众号
  15. VSCODE也可以进行gtest细粒度测试
  16. (七)DAC0832 数模转换芯片的应用 以及运算放大器的学习 01
  17. 佛蒙特大学给机器人口述「形态学」,使其「理解」人类指令
  18. Failed to decode response: zlib_decode(): data error Retrying with degraded;
  19. 获取UNIX系统时间
  20. 学生免费领取阿里云ECS云服务器并使用全过程(部署个人博客项目)

热门文章

  1. sdkman 安装使用教程
  2. 如何听广播来学计算机,MAC使用技巧之苹果itunes如何收听国内的广播?
  3. 每日一练20210706
  4. 如何运行PHP文件 /创建PHP项目【基于VScode、XAMPP】超级详细,亲测有效,这一篇就够了
  5. 天载配资解析天赐材料:目标180
  6. 企业应该怎么运营微信公众号?
  7. 图片在线去水印-一键图片去除水印工具
  8. mysql的sleep线程多久_MySQL数据库sleep线程过多,怎么办?
  9. 菜鸡哈屠教你合并果子
  10. java用于选择结构的关键字_Java结构