[PATCH v3 03/12] sched/fair: Change the variable to hold the number of periods to 32bit
From: Yuyang Du
Date: Tue May 03 2016  23:47:11 EST
In sched average update, a period is about 1ms, so a 32bit unsigned
integer can approximately hold a maximum of 49 (=2^32/1000/3600/24)
days.
For usual cases, 32bit is big enough and 64bit is needless. But if
a task sleeps longer than it, there can be two outcomes:
Consider a task sleeps whatever m milliseconds, then n = (u32)m.
1. If n >= 32*64, then the task's sched avgs will be surely decayed
to 0. In this case, it really doesn't matter that the 32bit is not
big enough to hold m. In other words, a task sleeps 2 secs or sleeps
50 days are the same from sched average point of view.
2. If m < 32*64, the chance to be here is very very low, but if so,
the task's sched avgs MAY NOT be decayed to 0, depending on how
big its sums are, and the chance to 0 is still good as load_sum
is way less than ~0ULL and util_sum way less than ~0U.
Nevertheless, what really maters is what happens in the worstcase
scenario, which is when (u32)m = 0? So in that case, it would be like
after so long a sleep, we treat the task as it never slept, and has the
same sched averages as before it slept. That is actually not bad or
nothing to worry about, and think of it as the same as how we treat
a new born task.
Signedoffby: Yuyang Du <yuyang.du@xxxxxxxxx>

kernel/sched/fair.c  27 +++++++++++++
1 file changed, 13 insertions(+), 14 deletions()
diff git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 2b83b4c..34ccaa3 100644
 a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ 2619,18 +2619,13 @@ static const u32 __accumulated_sum_N32[] = {
* n is the number of periods past; a period is ~1ms
* m is called halflife in exponential decay; here it is SCHED_AVG_HALFLIFE=32.
*/
static __always_inline u64 __decay_sum(u64 val, u64 n)
+static __always_inline u64 __decay_sum(u64 val, u32 n)
{
 unsigned int local_n;

if (!n)
return val;
else if (unlikely(n > SCHED_AVG_HALFLIFE * 63))
return 0;
 /* after bounds checking we can collapse to 32bit */
 local_n = n;

/*
* As y^PERIOD = 1/2, we can combine
* y^n = 1/2^(n/PERIOD) * y^(n%PERIOD)
@@ 2638,12 +2633,12 @@ static __always_inline u64 __decay_sum(u64 val, u64 n)
*
* To achieve constant time decay_load.
*/
 if (unlikely(local_n >= SCHED_AVG_HALFLIFE)) {
 val >>= local_n / SCHED_AVG_HALFLIFE;
 local_n %= SCHED_AVG_HALFLIFE;
+ if (unlikely(n >= SCHED_AVG_HALFLIFE)) {
+ val >>= n / SCHED_AVG_HALFLIFE;
+ n %= SCHED_AVG_HALFLIFE;
}
 val = mul_u64_u32_shr(val, __decay_inv_multiply_N[local_n], 32);
+ val = mul_u64_u32_shr(val, __decay_inv_multiply_N[n], 32);
return val;
}
@@ 2654,7 +2649,7 @@ static __always_inline u64 __decay_sum(u64 val, u64 n)
* We can compute this efficiently by combining:
* y^32 = 1/2 with precomputed \Sum 1024*y^n (where n < 32)
*/
static u32 __accumulate_sum(u64 n)
+static u32 __accumulate_sum(u32 n)
{
u32 contrib = 0;
@@ 2708,8 +2703,8 @@ static __always_inline int
__update_sched_avg(u64 now, int cpu, struct sched_avg *sa,
unsigned long weight, int running, struct cfs_rq *cfs_rq)
{
 u64 delta, scaled_delta, periods;
 u32 contrib;
+ u64 delta, scaled_delta;
+ u32 contrib, periods;
unsigned int delta_w, scaled_delta_w, decayed = 0;
unsigned long scale_freq, scale_cpu;
@@ 2762,7 +2757,11 @@ __update_sched_avg(u64 now, int cpu, struct sched_avg *sa,
delta = delta_w;
 /* Figure out how many additional periods this update spans */
+ /*
+ * Figure out how many additional periods this update spans.
+ * A period is 1024*1024ns or ~1ms, so a 32bit integer can hold
+ * approximately a maximum of 49 (=2^32/1000/3600/24) days.
+ */
periods = delta / 1024;
delta %= 1024;

1.7.9.5