关于hrtimer_forward小段代码的分析【转】

转自:http://blog.csdn.net/wowuyinglingluan/article/details/45720151

版权声明:本文为博主原创文章,未经博主允许不得转载。

 

目录(?)[-]

  1. 整段代码
  2. 关于无效的forward
  3. 关于定时精度问题
  4. 精确调整和overrun问题
  5. 存疑

 

随着各种嵌入式设备上采用linux,特别是Android系统的广泛应用,linux的hrtimer高精度模式开始被广泛支持。当然,虽说可以支持到ns精度,具体实现依赖于硬件定时器和内核编译条件,不过,一般情况下,几十us的定时精度都是支持的。这给编写驱动带来了很大的方便。 
之前有一篇非常强大的博文 Linux时间子系统之六:高精度定时器(HRTIMER)的原理和实现,已经将hrtimer的基本原理和hrtimer的应用方法做了清晰详尽的剖析,这里针对在应用hrtimer时,往往导致定时器没有按照设计精度执行的问题,分析一下hrtimer_forword的内部的小段代码。

整段代码

817 u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
818 {
819         u64 orun = 1;
820         ktime_t delta;
821
822         delta = ktime_sub(now, hrtimer_get_expires(timer));
823
824         if (delta.tv64 < 0)
825                 return 0;
826
827         if (interval.tv64 < timer->base->resolution.tv64)
828                 interval.tv64 = timer->base->resolution.tv64;
829
830         if (unlikely(delta.tv64 >= interval.tv64)) {
831                 s64 incr = ktime_to_ns(interval);
832
833                 orun = ktime_divns(delta, incr);
834                 hrtimer_add_expires_ns(timer, incr * orun);
835                 if (hrtimer_get_expires_tv64(timer) > now.tv64)
836                         return orun;
837                 /*
838                  * This (and the ktime_add() below) is the
839                  * correction for exact:
840                  */
841                 orun++;
842         }
843         hrtimer_add_expires(timer, interval);
844
845         return orun;
846 }

关于无效的forward

以上是3.4版本内核中的hrtimer_forward的实现,我们来分析一下这里面的几个关键环节: 
首先时给出的now,这个时间很重要,

822         delta = ktime_sub(now, hrtimer_get_expires(timer));
823
824         if (delta.tv64 < 0)
825                 return 0;

因为如上我们可以看到,如果当前时间比定时器到期时间要早,说明定时器上还有一个工作需要在当前时间完成,因此,不会进行任何操作。直接返回,也就是说,如果我们希望这次hrtimer_forward起作用,那么实际上,不会起任何作用。

关于定时精度问题

接下来看看定时精度,如果我们看一下针对某一嵌入式系统的linux源码中hrtimer的实现,我们就会看到,良好的实现均准确地设置了resolution,这个resolution是定时器能够实现的最高精度,当然这一般不是硬件决定的(一个主频48Mhz的MCU,其硬件定时器的定时精度都在20ns),而是嵌入式系统设计者根据系统的整体性能考虑权衡的结果。

827         if (interval.tv64 < timer->base->resolution.tv64)
828                 interval.tv64 = timer->base->resolution.tv64;

因此我们看到,如果我们给出的interval如果比这个精度要高,那么,我们只能得到最短等于该精度的定时。

精确调整和overrun问题

接下去的代码,还有点儿让对gcc不太了解的人糊涂,就是

830         if (unlikely(delta.tv64 >= interval.tv64)) {

这句话的关节在于unlikely宏,其实这是在提醒gcc编译器,一般情况下,delta.tv64 >= interval.tv64的条件按是不成立的,这可以让gcc编译出更加高效的代码。并不影响if内部的判断,我们可以直接理解为:

if (delta.tv64 >= interval.tv64) {

而在这个条件为真的时候,会对expires作较为精密的外科手术。delta是一个由于hrtimer自身遍历以及我们callback函数内部的业务处理,耗费了一定时间,已经超过了 interval,那么则认为出现了overrun现象,即下一次定时已经被覆盖掉了。这时,内核希望做一些补救工作,不过也做不了多少,就是告诉你按照你给出interval,已经超时了几次了,并且看看是否可以根据这个来微调后续的定时时间。这里的代码挺有意思,我们连起来看一下

/*这是delta怎么来的*/
822         delta = ktime_sub(now, hrtimer_get_expires(timer));
831                 s64 incr = ktime_to_ns(interval);
832 /*这是一个将当前的expires加上detal所能包含的interval整数倍的时间的计算
833                 orun = ktime_divns(delta, incr);
834                 hrtimer_add_expires_ns(timer, incr * orun);

那么,如果hrtimer的处理,是在硬件中断上的原子性操作,且ktime_divns只是简单的整数除法,以下的代码绝对不可能成立:

835                 if (hrtimer_get_expires_tv64(timer) > now.tv64)
836                         return orun;

那么,实际上,它是一个通过损失精度来完成计算的除法,如果除数大于32位,那么除数与被除数一起损失精度到除数小于等于32位为止,以下是其函数定义:

u64 ktime_divns(const ktime_t kt, s64 div)
313 {
314         u64 dclc;
315         int sft = 0;
316
317         dclc = ktime_to_ns(kt);
318         /* Make sure the divisor is less than 2^32: */
319         while (div >> 32) {
320                 sft++;
321                 div >>= 1;
322         }
323         dclc >>= sft;
324         do_div(dclc, (unsigned long) div);
325
326         return dclc;
327 }

因此,如果inteval是一个大于2^32的大数的时候,还真有可能让条件成立滴^_^。这是返回值和加载expires上的值都对,没有什么要讲的了。 
如果不成立,则

841                 orun++;
842         }
843         hrtimer_add_expires(timer, interval);

存疑

那么在这样的一个状态下,很不幸,expires被加上了(incr * orun+interval)这么多的时间,我们可以理解为,此时,内核认为你希望得到的定时时间为interval给定定时时间的整数倍,然后你还知道有几次overrun,这个主意不坏,但是我们带入实际的数值,就会感觉比较好玩了。 
假设: 
delta=5ns,interval=4ns 
则: 
行833计算结果:orrun=1 
行834在原expires上加上了4ns 
那么,由于行835此时条件不会为真那么在: 
行841,orrun变成了2 
然后在行843,expires的值加上了4ns 
至此,expires一共加上了8ns,如果所有其他操作瞬间完成的话,将在3ns后得到下一次callback的机会。 
如果按照这样的逻辑,我们看到返回的结果凌乱了,明明overrun了一次,结果会返回2。如果我没有理解错误的话,此时的overrun不能反应实际的情况了

时间: 2024-09-16 03:01:04

关于hrtimer_forward小段代码的分析【转】的相关文章

android adb-查看adb 源码有小段代码不理解

问题描述 查看adb 源码有小段代码不理解 在查看adb源码的时候,在system/core/adb/adb_client.c下的int adb_connect(const char *service)中有如下代码 if (_adb_server_name) 191 fd = socket_network_client(__adb_server_name, adb_server_port,SOCK_STREAM); 192 else 193 fd = socket_loopback_client

悠然乱弹:从一段代码讲开去

序言 今天偶然看到一框架,在框架的里面有一段这样的描述: ? 1 2 xxx并不愿意其他人来直接修改YYY框架的代码,因为XXX致力于将它打造为完美的作品,其他人写的代码,实在没有加入进来的意义. 但是您可以当小白鼠,提意见,提bug,好的idea我还是愿意接受的. 这里解释一下,其中xxx是作者名字,YYY是框架名称,这么OSC上牛人众多,牛到这个程度的还是第一次见到,于是就想去速度学习一下.其实框架好不好,看例子代码就可以看出一二,去找了找,果然找到了示例代码,我摘了两个方法: ? 1 2

网上一小段代码不会用,求帮忙~

问题描述 Link:http://dzone.com/snippets/get-all-classes-within-package我的目的是想从一个指定的package里边获取所有的class的名字,用了下这段代码,然后发现不行.代码是:Class[]result=getClasses("rest");System.out.println(result.length);这里边rest是我的一个包的名字,返回结果是0,说明没有检测到class.求哪位大侠花个五分钟跑一下这小段代码 解决

c++-怎样把一段C++代码(小游戏代码)跟Xtinon pro 联系起来.

问题描述 怎样把一段C++代码(小游戏代码)跟Xtinon pro 联系起来. 怎样把一段C++代码(小游戏代码)跟Xtinon pro 联系起来,想弄一个小游戏,也是一份暑假作业来的...大神们,求救,谢谢! 解决方案 Xtinon pro应该是Xtion PRO吧,一个体感应用. 1.下载部署Xtion PRO SDK:2.游戏代码中调用Xtion PRO API,读取体感设备的输入控制游戏进程. 解决方案二: 用vs2010..配置了openNI和opencv能用么

求解-分析俩段代码else的最后两句是干什么?求大神指点

问题描述 分析俩段代码else的最后两句是干什么?求大神指点 下边俩段代码,else里的最后两句为什么他俩不一样啊?第一段代码else的最后两句是干什么? 第二段代码else的最后两句是干什么? public String getList() throws Exception { quZhengGuiZeList = dao.getList(TrainingOrCompetitionID); if(quZhengGuiZeList.size()>0){ quZhengGuiZe=quZhengG

c++-C++模板,我不太懂里面&amp;amp;amp; 字符啥意思(能帮忙分析这段代码吗?)

问题描述 C++模板,我不太懂里面& 字符啥意思(能帮忙分析这段代码吗?) 下面是我在<软件技术基础>里面看到的一部分内容,其中我不明白的地方就是 & 字符所在的地方 比如: Matrix& Matrix:: operator– (Matrix& x) 在此先谢谢大家帮忙解答了 8.2.2 矢量和矩阵的模板 由上述定义可知,矢量就是数的线性排列,序列就是它们最自然的表示方式.矩阵又可视为矢量的线性集合,所以可用序列的数组表示.下面就是矢量和矩阵的模板: 矢量模板

当程序员说“这代码写的可真烂”,他们的意思是“这烂代码不是我写的”。而当他们说这段代码有些“小问题”时,很可能这代码是他们自己写的

英文原文:What Programmers Say vs. What They Mean 你是否听到过同事说"这段代码不言自明"?你的同事的这句话的实际意思是这段代码不需要写注释. 你也许注意到了,很多时候,程序员所说的话的字面意思和其真实的意思是完全不同的.不用惊异,下面你将很快知道这些暧昧的短语和其深层次的意思都是什么. 最近 Imgur 上出现了一张图片,里面列举的程序员的一些专业术语和其含义,它能很好的帮助你理解这些话的真实意思.这里是对其中的精华进行的总结. 典型的程序员之间

PHP常用的小程序代码段_php技巧

本文实例讲述了PHP常用的小程序代码段.分享给大家供大家参考,具体如下: 1.计算两个时间的相差几天 $startdate=strtotime("2009-12-09"); $enddate=strtotime("2009-12-05"); 上面的php时间日期函数strtotime已经把字符串日期变成了时间戳,这样只要让两数值相减,然后把秒变成天就可以了,比较的简单,如下: $days=round(($enddate-$startdate)/3600/24) ;

如何自定义异常,下面这段代码怎么分解成几个小功能

问题描述 如何自定义异常,下面这段代码怎么分解成几个小功能 下面这段代码我想分解成更小的几个功能,意思就是分成几个功能更加单一的方法,这段代码是基于面对对象写的,应该怎么写. private byte[] getData() { try { FileInputStream qu = new FileInputStream(""); FileOutputStream chu = new FileOutputStream(""); this.data = new byt