在linux内核中获得比jiffies精度更高的时间值【转】

转自:http://blog.chinaunix.net/uid-20672257-id-2831219.html

内核一般通过jiffies值来获取当前时间。尽管该数值表示的是自上次系统启动到当前的时间间隔,但因为驱动程序的生命期只限于系统的运行期 (uptime),所以也是可行的。驱动程序利用jiffies的当前值来计算不同事件间的时间间隔。 硬件给内核提供一个系统定时器用以计算和管理时间,内核通过编程预设系统定时器的频率,即节拍率(tick rate),每一个周期称作一个tick(节拍)。Linux内核从2.5版内核开始把频率从100调高到1000(当然带来了很多优点,
也有一些缺点)。jiffies是内核中的一个全局变量,用来记录自系统启动一来产生的节拍数。譬如,如果计算系统运行了多长时间,可以用 jiffies/tick rate 来计算。

jiffies定义在文件

如果您需要更精确的时间来测量或者记录某些事情的话,内核中有个xtime全局变量,类型是struct timespec {time_t tv_sec; long tv_nsec;}按照这个数据结构,它是ns级的。

而且还有一个current_kernel_time函数,通过它就可以获取xtime的值。但是xtime是在时钟中断里更新的,而一个tick往往是 10ms或者100ms,它只能保证在时钟中断ISR调用时刻,它返回的值是精确到ns级,并不能保证任何一个调用这个函数的时刻都能这样,原因是xtime的更新速度比它差几个数量级。

如果需要精确到微妙级别,可以使用do_gettimeofday函数。该函数并不返回今天是本周的星期几或类似的信息;它是用微秒值来填充一个指向struct timeval的指针变量。相应的原型如下:

#include

void do_gettimeofday(struct timeval *tv);

源码中声明的do_gettimeofday在Alpha和Sparc之外的体系结构上有“接近微秒级的分辨率” ,在Alpha和Sparc上和jiffies值的分辨率一样。Sparc的移植版本在2.1.34版的内核中升级了,可以支持更细粒度的时间度量。

void do_gettimeofday(struct timeval *tv)
{
 unsigned long flags;
 unsigned long seq;
 unsigned long nsec, sec, lost;

do {
  seq = read_seqbegin_irqsave(&xtime_lock, flags);
  usec = system_timer->offset();

lost = jiffies - wall_jiffies;
  if (lost)
  usec += lost * USECS_PER_JIFFY;

sec = xtime.tv_sec;
  nsec += xtime.tv_nsec;
 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));

/* usec may have gone up a lot: be safe */
 while (nsec >= 1000000000) {
  nsec -= 1000000000;
  sec++;
 }

tv->tv_sec = sec;
 tv->tv_usec = usec;
}

从中可以发现,我们只要稍微的修改一下代码就可以达到纳秒的精确度了

void do_gettimeofday_nsec(struct timespec *tv)
{
 unsigned long flags;
 unsigned long seq;
 unsigned long usec, sec, lost;

do {
  seq = read_seqbegin_irqsave(&xtime_lock, flags);
  usec = system_timer->offset();

lost = jiffies - wall_jiffies;
  if (lost)
  usec += lost * USECS_PER_JIFFY;

sec = xtime.tv_sec;
  usec += xtime.tv_nsec / 1000;
 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));

/* usec may have gone up a lot: be safe */
 while (usec >= 1000000) {
  usec -= 1000000;
  sec++;
 }

tv->tv_sec = sec;
 tv->tv_usec = usec;
}

注意这里使用了不同的时间结构。

时间: 2024-10-01 06:41:32

在linux内核中获得比jiffies精度更高的时间值【转】的相关文章

Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构struct timeval{time_t tv_sec; /***second***/susecond_t tv_usec;/***microsecond***/}到底microsecond是毫秒还是微秒?? 1秒=1000毫秒(3个零),1秒=1000 000微秒(6个零),1秒=1000 000 000纳秒(9个零),1秒=1000 000 000

向linux内核中添加外部中断驱动模块

本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内核中添加外部中断驱动模块.7.完整驱动程序代码.linux的内核版本为linux2.6.32.2. 一.linux模块的框架以及混杂设备相关知识 1.内核模块的框架如下图所示,其中module_init()(图中有误,不是modules_init)只有在使用insmod命令手动加载模块时才会被调用,

Linux内核中常用String库函数实现

//只列举了部分常用的strcpy,strcmp,strcat,strchr,strstr,strpbrk...  char *strcpy(char *dest, const char *src) { char *tmp = dest; while ((*dest++ = *src++) != '\0') /* nothing */; return tmp; } char *strncpy(char *dest, const char *src, size_t count) { char *t

route-显示并设置Linux内核中的网络路由表

route命令 网络配置 route命令用来显示并设置Linux内核中的网络路由表,route命令设置的路由主要是静态路由.要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现. 语法 route(选项)(参数) 选项 -A:设置地址类型: -C:打印将Linux核心的路由缓存: -v:详细信息模式: -n:不执行DNS反向查找,直接显示数字形式的IP地址: -e:netstat格式显示路由表: -net:到一个网络的路由表: -host:到一个主机的路

C语言在linux内核中do while(0)妙用之法

为什么说do while(0) 妙?因为它的确就是妙,而且在linux内核中实现是相当的妙,我们来看看内核中的相关代码: #define db_error(fmt, ...) do { fprintf(stderr, "(error): "); fprintf(stderr, fmt, ##__VA_ARGS__); } while (0) 这只是个普通的调试信息的输出,有人便会认为,你这不是多此一举吗?去掉do while(0)不一样也实现了吗?其实不然,我们看看例子就清楚了,尽管很

Linux内核中的中断栈与内核栈的补充说明【转】

转自:http://blog.chinaunix.net/uid-12461657-id-3487463.html 原文地址:Linux内核中的中断栈与内核栈的补充说明 作者:MagicBoy2010 中断栈与内核栈的话题更多地属于内核的范畴,所以在<深入Linux设备驱动程序内核机制>第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题. 本贴在这个基础上对内核栈与中断栈的话题做些补充,讨论基于x86 32位系统,因为64位系

Linux内核中的软中断、tasklet和工作队列详解

[TOC] 本文基于Linux2.6.32内核版本. 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的"下半部"(bottom half)演变而来.下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任务队列的函数都消失了,只剩下了前三者. 介绍这三种下半部实现之前,有必要说一下上半部与下半部的区别. 上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务.举个例子:在网络传输中,网卡接收到数据包这

Linux内核中namespace之PID namespace

前面看了LInux PCI设备初始化,看得有点晕,就转手整理下之前写的笔记,同时休息一下!!~(@^_^@)~ 这片文章是之前写的,其中参考了某些大牛们的博客!! PID框架的设计 一个框架的设计会考虑很多因素,相信分析过Linux内核的读者来说会发现,内核的大量数据结构被哈希表和链表链接起来,最最主要的目的就是在于查找.可想而知一个好的框架,应该要考虑到检索速度,还有考虑功能的划分.那么在PID框架中,需要考虑以下几个因素. 如何通过task_struct快速找到对应的pid 如何通过pid快

linux内核计算时间差以及jiffies溢出

jiffies是每个时钟中断,都会加1,这就导致一个问题,无论jiffies(一般来说是unsigned long类型)多少个字节,总有溢出的时候. 更极端的时候,当期jiffies是0xffffffff,下一个时刻就是0x0 这样,当你计算延时/时差 的时候0x0 - 0xffffffff结果是 0xffffffff,实际上只是过了一个时钟周期,这种差别是巨大的. 那么如何防止这种情况发生呢? 很简单 假设t1是之前记录的jiffies,t2是当年的jiffies,你想要计算两者差值: (lo