About the analysis of Hrtimer_forward small segment code "go"

Source: Internet
Author: User
Tags integer division

Transferred from: http://blog.csdn.net/wowuyinglingluan/article/details/45720151

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Directory (?) [-]

    1. Whole piece of code
    2. About the invalid forward
    3. On timing accuracy problems
    4. Precise adjustment and overrun problems
    5. Doubt

With the widespread use of Linux on a variety of embedded devices, especially Android, the Hrtimer high-precision model of Linux has been widely supported. Of course, although the NS accuracy can be supported, the implementation relies on hardware timers and kernel compilation conditions, however, in general, the timing accuracy of dozens of us is supported. This has brought great convenience to the writing drive.
There was a very powerful blog. Six of the Linux time subsystem: the principle and implementation of the high-precision timer (Hrtimer), which has already made a clear and detailed analysis of the basic principles of Hrtimer and the application of Hrtimer, for the application of Hrtimer, Often lead to the timer does not follow the design accuracy of the implementation of the problem, analysis of the Hrtimer_forword inside the small section code.

Whole piece of code
817 U64 Hrtimer_forward (struct Hrtimer *Timer, ktime_tNow, ktime_t interval)818 {819 U64 Orun =1;820 ktime_t Delta;821822 Delta = ktime_sub (Now, Hrtimer_get_expires (timer));823824if (Delta.tv64 <0)825 return0;826827if (Interval.tv64 <TIMER-&GT;BASE-&GT;RESOLUTION.TV64)828 interval.tv64 =timer->base->resolution.tv64;829830if (Unlikely (delta.tv64 >= interval.tv64)) {831 S64 incr = Ktime_to_ns (interval);832833 Orun = Ktime_divns (delta, INCR);834 Hrtimer_add_expires_ns (timer, incr * orun); 835 if (hrtimer_get_expires_tv64 (timer) > Span class= "hljs-built_in" >now.tv64) 836 return orun; 837/*838 * This (and the Ktime_add () below) is the839 * correction for exact:840 */841 orun++; 842}843 hrtimer_add_expires (timer, interval); 844 845 return orun; 846}                 
About the invalid forward

The above is the implementation of the Hrtimer_forward in the 3.4 kernel, let's analyze a few key links:
First given by now, this time is very important,

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

Because as we can see above, if the current time is earlier than the timer expiry time, it means that there is a job on the timer that needs to be done at the current time, so no action is done. Direct return, that is to say, if we want this hrtimer_forward to work, then in fact, it will not play any role.

On timing accuracy problems

Next look at the timing accuracy, if we look at the Linux source code for an embedded system Hrtimer implementation, we will see that a good implementation is precisely set the resolution, this resolution is the highest precision timer can achieve , of course, this is not usually hardware-based ( a 48Mhz MCU, the timing accuracy of its hardware timers in 20ns), but the embedded system designers to consider the overall performance of the system as a result of the tradeoff.

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

So we see that if we give the interval a higher precision than this, then we can only get the shortest time equal to the accuracy of the timing.

Precise adjustment and overrun problems

The next code is a bit confusing to people who don't know much about GCC,

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

The joint of this sentence is unlikely macro, in fact this is to remind the GCC compiler, in general, delta.tv64 >= interval.tv64 conditions are not established, which allows GCC to compile more efficient code. does not affect if internal judgments, which we can directly understand as:

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

And when this condition is true, the expires will be more sophisticated surgical procedures. Delta is a result of the Hrtimer itself traversal and our callback function inside the business processing, took a certain amount of time, has exceeded the interval, then we think there is a overrun phenomenon, That is, the next time the timer has been overwritten. At this point, the kernel would like to do some remedial work, but also do not do much, is to tell you that according to you give interval, has timed out several times, and see if can be based on this to fine-tune the subsequent timing time. The code here is interesting, so let's take a look.

/*这是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);

So, if Hrtimer's processing is an atomic operation on a hardware interrupt, and KTIME_DIVNS is just a simple integer division, the following code is absolutely impossible to set up:

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

So, in fact, it is a division of computation by loss of precision, if the divisor is greater than 32 bits, then the divisor with the dividend loss of precision to the divisor is less than or equal to 32 bits, the following is its function definition:

U64 Ktime_divns (const ktime_t KT, S64Div313 {314 U64 DCLC;315int sft =0; 316 317 DCLC = Ktime_to_ns (kt); /* make sure the divisor are 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}                 

Therefore, if Inteval is a large number larger than 2^32, it is really possible to let the condition set up a drop of ^_^. This is the return value and the value on the load expires is right, there's nothing to talk about.
If this is not true, then

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

So in such a state, unfortunately, expires was added (INCR * orun+interval) so much time, we can understand that, at this time, the kernel thinks you want to get the timing time for the interval given timing time of the integer times, Then you know how many times overrun, this idea is not bad, but we bring into the actual value, it will feel more fun.
Assume:
Delta=5ns,interval=4ns
The
Line 833 calculation result: orrun=1
Line 834 adds 4ns to the original expires.
Well, because line 835 at this time the condition will not be true so in:
Line 841,orrun becomes 2.
Then the value of the line 843,expires is added to the 4ns
At this point, expires a total of 8ns, if all other operations instantaneous completion, will be in 3ns after the next callback opportunity.
If we follow this logic, we can see that the result of the return is messy, obviously overrun once, the result will return 2. If I don't understand the mistake, the overrun can't reflect the actual situation at this time.

About the analysis of Hrtimer_forward small segment code "go"

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.