Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull scheduler fixes from Ingo Molnar:
"This fixes the cputime scaling overflow problems for good without
having bad 32-bit overhead, and gets rid of the div64_u64_rem() helper
as well."

* 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
Revert "math64: New div64_u64_rem helper"
sched: Avoid prev->stime underflow
sched: Do not account bogus utime
sched: Avoid cputime scaling overflow

+58 -60
+1 -18
include/linux/math64.h
··· 30 30 } 31 31 32 32 /** 33 - * div64_u64_rem - unsigned 64bit divide with 64bit divisor 34 - */ 35 - static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) 36 - { 37 - *remainder = dividend % divisor; 38 - return dividend / divisor; 39 - } 40 - 41 - /** 42 33 * div64_u64 - unsigned 64bit divide with 64bit divisor 43 34 */ 44 35 static inline u64 div64_u64(u64 dividend, u64 divisor) ··· 61 70 extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder); 62 71 #endif 63 72 64 - #ifndef div64_u64_rem 65 - extern u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder); 66 - #endif 67 - 68 73 #ifndef div64_u64 69 - static inline u64 div64_u64(u64 dividend, u64 divisor) 70 - { 71 - u64 remainder; 72 - return div64_u64_rem(dividend, divisor, &remainder); 73 - } 74 + extern u64 div64_u64(u64 dividend, u64 divisor); 74 75 #endif 75 76 76 77 #ifndef div64_s64
+51 -29
kernel/sched/cputime.c
··· 506 506 } 507 507 508 508 /* 509 - * Perform (stime * rtime) / total with reduced chances 510 - * of multiplication overflows by using smaller factors 511 - * like quotient and remainders of divisions between 512 - * rtime and total. 509 + * Perform (stime * rtime) / total, but avoid multiplication overflow by 510 + * loosing precision when the numbers are big. 513 511 */ 514 512 static cputime_t scale_stime(u64 stime, u64 rtime, u64 total) 515 513 { 516 - u64 rem, res, scaled; 514 + u64 scaled; 517 515 518 - if (rtime >= total) { 519 - /* 520 - * Scale up to rtime / total then add 521 - * the remainder scaled to stime / total. 522 - */ 523 - res = div64_u64_rem(rtime, total, &rem); 524 - scaled = stime * res; 525 - scaled += div64_u64(stime * rem, total); 526 - } else { 527 - /* 528 - * Same in reverse: scale down to total / rtime 529 - * then substract that result scaled to 530 - * to the remaining part. 531 - */ 532 - res = div64_u64_rem(total, rtime, &rem); 533 - scaled = div64_u64(stime, res); 534 - scaled -= div64_u64(scaled * rem, total); 516 + for (;;) { 517 + /* Make sure "rtime" is the bigger of stime/rtime */ 518 + if (stime > rtime) { 519 + u64 tmp = rtime; rtime = stime; stime = tmp; 520 + } 521 + 522 + /* Make sure 'total' fits in 32 bits */ 523 + if (total >> 32) 524 + goto drop_precision; 525 + 526 + /* Does rtime (and thus stime) fit in 32 bits? */ 527 + if (!(rtime >> 32)) 528 + break; 529 + 530 + /* Can we just balance rtime/stime rather than dropping bits? */ 531 + if (stime >> 31) 532 + goto drop_precision; 533 + 534 + /* We can grow stime and shrink rtime and try to make them both fit */ 535 + stime <<= 1; 536 + rtime >>= 1; 537 + continue; 538 + 539 + drop_precision: 540 + /* We drop from rtime, it has more bits than stime */ 541 + rtime >>= 1; 542 + total >>= 1; 535 543 } 536 544 545 + /* 546 + * Make sure gcc understands that this is a 32x32->64 multiply, 547 + * followed by a 64/32->64 divide. 548 + */ 549 + scaled = div_u64((u64) (u32) stime * (u64) (u32) rtime, (u32)total); 537 550 return (__force cputime_t) scaled; 538 551 } 539 552 ··· 558 545 struct cputime *prev, 559 546 cputime_t *ut, cputime_t *st) 560 547 { 561 - cputime_t rtime, stime, total; 548 + cputime_t rtime, stime, utime, total; 562 549 563 550 if (vtime_accounting_enabled()) { 564 551 *ut = curr->utime; ··· 581 568 */ 582 569 rtime = nsecs_to_cputime(curr->sum_exec_runtime); 583 570 584 - if (!rtime) { 585 - stime = 0; 586 - } else if (!total) { 587 - stime = rtime; 588 - } else { 571 + /* 572 + * Update userspace visible utime/stime values only if actual execution 573 + * time is bigger than already exported. Note that can happen, that we 574 + * provided bigger values due to scaling inaccuracy on big numbers. 575 + */ 576 + if (prev->stime + prev->utime >= rtime) 577 + goto out; 578 + 579 + if (total) { 589 580 stime = scale_stime((__force u64)stime, 590 581 (__force u64)rtime, (__force u64)total); 582 + utime = rtime - stime; 583 + } else { 584 + stime = rtime; 585 + utime = 0; 591 586 } 592 587 593 588 /* ··· 604 583 * Let's enforce monotonicity. 605 584 */ 606 585 prev->stime = max(prev->stime, stime); 607 - prev->utime = max(prev->utime, rtime - prev->stime); 586 + prev->utime = max(prev->utime, utime); 608 587 588 + out: 609 589 *ut = prev->utime; 610 590 *st = prev->stime; 611 591 }
+6 -13
lib/div64.c
··· 79 79 #endif 80 80 81 81 /** 82 - * div64_u64_rem - unsigned 64bit divide with 64bit divisor and 64bit remainder 82 + * div64_u64 - unsigned 64bit divide with 64bit divisor 83 83 * @dividend: 64bit dividend 84 84 * @divisor: 64bit divisor 85 - * @remainder: 64bit remainder 86 85 * 87 86 * This implementation is a modified version of the algorithm proposed 88 87 * by the book 'Hacker's Delight'. The original source and full proof ··· 89 90 * 90 91 * 'http://www.hackersdelight.org/HDcode/newCode/divDouble.c.txt' 91 92 */ 92 - #ifndef div64_u64_rem 93 - u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) 93 + #ifndef div64_u64 94 + u64 div64_u64(u64 dividend, u64 divisor) 94 95 { 95 96 u32 high = divisor >> 32; 96 97 u64 quot; 97 98 98 99 if (high == 0) { 99 - u32 rem32; 100 - quot = div_u64_rem(dividend, divisor, &rem32); 101 - *remainder = rem32; 100 + quot = div_u64(dividend, divisor); 102 101 } else { 103 102 int n = 1 + fls(high); 104 103 quot = div_u64(dividend >> n, divisor >> n); 105 104 106 105 if (quot != 0) 107 106 quot--; 108 - 109 - *remainder = dividend - quot * divisor; 110 - if (*remainder >= divisor) { 107 + if ((dividend - quot * divisor) >= divisor) 111 108 quot++; 112 - *remainder -= divisor; 113 - } 114 109 } 115 110 116 111 return quot; 117 112 } 118 - EXPORT_SYMBOL(div64_u64_rem); 113 + EXPORT_SYMBOL(div64_u64); 119 114 #endif 120 115 121 116 /**