diff options
author | Andrew Hunter <ahh@google.com> | 2014-09-04 17:17:16 -0400 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2014-09-12 16:59:03 -0400 |
commit | d78c9300c51d6ceed9f6d078d4e9366f259de28c (patch) | |
tree | e35f28f9046d9688a9870d254b5bfba28eb70a3c /kernel | |
parent | 9bf2419fa7bffa16ce58a4d5c20399eff8c970c9 (diff) |
jiffies: Fix timeval conversion to jiffies
timeval_to_jiffies tried to round a timeval up to an integral number
of jiffies, but the logic for doing so was incorrect: intervals
corresponding to exactly N jiffies would become N+1. This manifested
itself particularly repeatedly stopping/starting an itimer:
setitimer(ITIMER_PROF, &val, NULL);
setitimer(ITIMER_PROF, NULL, &val);
would add a full tick to val, _even if it was exactly representable in
terms of jiffies_ (say, the result of a previous rounding.) Doing
this repeatedly would cause unbounded growth in val. So fix the math.
Here's what was wrong with the conversion: we essentially computed
(eliding seconds)
jiffies = usec * (NSEC_PER_USEC/TICK_NSEC)
by using scaling arithmetic, which took the best approximation of
NSEC_PER_USEC/TICK_NSEC with denominator of 2^USEC_JIFFIE_SC =
x/(2^USEC_JIFFIE_SC), and computed:
jiffies = (usec * x) >> USEC_JIFFIE_SC
and rounded this calculation up in the intermediate form (since we
can't necessarily exactly represent TICK_NSEC in usec.) But the
scaling arithmetic is a (very slight) *over*approximation of the true
value; that is, instead of dividing by (1 usec/ 1 jiffie), we
effectively divided by (1 usec/1 jiffie)-epsilon (rounding
down). This would normally be fine, but we want to round timeouts up,
and we did so by adding 2^USEC_JIFFIE_SC - 1 before the shift; this
would be fine if our division was exact, but dividing this by the
slightly smaller factor was equivalent to adding just _over_ 1 to the
final result (instead of just _under_ 1, as desired.)
In particular, with HZ=1000, we consistently computed that 10000 usec
was 11 jiffies; the same was true for any exact multiple of
TICK_NSEC.
We could possibly still round in the intermediate form, adding
something less than 2^USEC_JIFFIE_SC - 1, but easier still is to
convert usec->nsec, round in nanoseconds, and then convert using
time*spec*_to_jiffies. This adds one constant multiplication, and is
not observably slower in microbenchmarks on recent x86 hardware.
Tested: the following program:
int main() {
struct itimerval zero = {{0, 0}, {0, 0}};
/* Initially set to 10 ms. */
struct itimerval initial = zero;
initial.it_interval.tv_usec = 10000;
setitimer(ITIMER_PROF, &initial, NULL);
/* Save and restore several times. */
for (size_t i = 0; i < 10; ++i) {
struct itimerval prev;
setitimer(ITIMER_PROF, &zero, &prev);
/* on old kernels, this goes up by TICK_USEC every iteration */
printf("previous value: %ld %ld %ld %ld\n",
prev.it_interval.tv_sec, prev.it_interval.tv_usec,
prev.it_value.tv_sec, prev.it_value.tv_usec);
setitimer(ITIMER_PROF, &prev, NULL);
}
return 0;
}
Cc: stable@vger.kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Paul Turner <pjt@google.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Prarit Bhargava <prarit@redhat.com>
Reviewed-by: Paul Turner <pjt@google.com>
Reported-by: Aaron Jacobs <jacobsa@google.com>
Signed-off-by: Andrew Hunter <ahh@google.com>
[jstultz: Tweaked to apply to 3.17-rc]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/time/time.c | 56 |
1 files changed, 31 insertions, 25 deletions
diff --git a/kernel/time/time.c b/kernel/time/time.c index f0294ba14634..a9ae20fb0b11 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c | |||
@@ -559,17 +559,20 @@ EXPORT_SYMBOL(usecs_to_jiffies); | |||
559 | * that a remainder subtract here would not do the right thing as the | 559 | * that a remainder subtract here would not do the right thing as the |
560 | * resolution values don't fall on second boundries. I.e. the line: | 560 | * resolution values don't fall on second boundries. I.e. the line: |
561 | * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. | 561 | * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. |
562 | * Note that due to the small error in the multiplier here, this | ||
563 | * rounding is incorrect for sufficiently large values of tv_nsec, but | ||
564 | * well formed timespecs should have tv_nsec < NSEC_PER_SEC, so we're | ||
565 | * OK. | ||
562 | * | 566 | * |
563 | * Rather, we just shift the bits off the right. | 567 | * Rather, we just shift the bits off the right. |
564 | * | 568 | * |
565 | * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec | 569 | * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec |
566 | * value to a scaled second value. | 570 | * value to a scaled second value. |
567 | */ | 571 | */ |
568 | unsigned long | 572 | static unsigned long |
569 | timespec_to_jiffies(const struct timespec *value) | 573 | __timespec_to_jiffies(unsigned long sec, long nsec) |
570 | { | 574 | { |
571 | unsigned long sec = value->tv_sec; | 575 | nsec = nsec + TICK_NSEC - 1; |
572 | long nsec = value->tv_nsec + TICK_NSEC - 1; | ||
573 | 576 | ||
574 | if (sec >= MAX_SEC_IN_JIFFIES){ | 577 | if (sec >= MAX_SEC_IN_JIFFIES){ |
575 | sec = MAX_SEC_IN_JIFFIES; | 578 | sec = MAX_SEC_IN_JIFFIES; |
@@ -580,6 +583,13 @@ timespec_to_jiffies(const struct timespec *value) | |||
580 | (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; | 583 | (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; |
581 | 584 | ||
582 | } | 585 | } |
586 | |||
587 | unsigned long | ||
588 | timespec_to_jiffies(const struct timespec *value) | ||
589 | { | ||
590 | return __timespec_to_jiffies(value->tv_sec, value->tv_nsec); | ||
591 | } | ||
592 | |||
583 | EXPORT_SYMBOL(timespec_to_jiffies); | 593 | EXPORT_SYMBOL(timespec_to_jiffies); |
584 | 594 | ||
585 | void | 595 | void |
@@ -596,31 +606,27 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) | |||
596 | } | 606 | } |
597 | EXPORT_SYMBOL(jiffies_to_timespec); | 607 | EXPORT_SYMBOL(jiffies_to_timespec); |
598 | 608 | ||
599 | /* Same for "timeval" | 609 | /* |
600 | * | 610 | * We could use a similar algorithm to timespec_to_jiffies (with a |
601 | * Well, almost. The problem here is that the real system resolution is | 611 | * different multiplier for usec instead of nsec). But this has a |
602 | * in nanoseconds and the value being converted is in micro seconds. | 612 | * problem with rounding: we can't exactly add TICK_NSEC - 1 to the |
603 | * Also for some machines (those that use HZ = 1024, in-particular), | 613 | * usec value, since it's not necessarily integral. |
604 | * there is a LARGE error in the tick size in microseconds. | 614 | * |
605 | 615 | * We could instead round in the intermediate scaled representation | |
606 | * The solution we use is to do the rounding AFTER we convert the | 616 | * (i.e. in units of 1/2^(large scale) jiffies) but that's also |
607 | * microsecond part. Thus the USEC_ROUND, the bits to be shifted off. | 617 | * perilous: the scaling introduces a small positive error, which |
608 | * Instruction wise, this should cost only an additional add with carry | 618 | * combined with a division-rounding-upward (i.e. adding 2^(scale) - 1 |
609 | * instruction above the way it was done above. | 619 | * units to the intermediate before shifting) leads to accidental |
620 | * overflow and overestimates. | ||
621 | * | ||
622 | * At the cost of one additional multiplication by a constant, just | ||
623 | * use the timespec implementation. | ||
610 | */ | 624 | */ |
611 | unsigned long | 625 | unsigned long |
612 | timeval_to_jiffies(const struct timeval *value) | 626 | timeval_to_jiffies(const struct timeval *value) |
613 | { | 627 | { |
614 | unsigned long sec = value->tv_sec; | 628 | return __timespec_to_jiffies(value->tv_sec, |
615 | long usec = value->tv_usec; | 629 | value->tv_usec * NSEC_PER_USEC); |
616 | |||
617 | if (sec >= MAX_SEC_IN_JIFFIES){ | ||
618 | sec = MAX_SEC_IN_JIFFIES; | ||
619 | usec = 0; | ||
620 | } | ||
621 | return (((u64)sec * SEC_CONVERSION) + | ||
622 | (((u64)usec * USEC_CONVERSION + USEC_ROUND) >> | ||
623 | (USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; | ||
624 | } | 630 | } |
625 | EXPORT_SYMBOL(timeval_to_jiffies); | 631 | EXPORT_SYMBOL(timeval_to_jiffies); |
626 | 632 | ||