* [MIPS]clocks_calc_mult_shift() may gen a too big mult value @ 2011-10-31 9:00 Chen Jie 2011-10-31 9:20 ` Yong Zhang 0 siblings, 1 reply; 8+ messages in thread From: Chen Jie @ 2011-10-31 9:00 UTC (permalink / raw) To: linux-mips, LKML Cc: johnstul, tglx, yanhua, 项宇, zhangfx, 孙海勇 [-- Attachment #1: Type: text/plain, Size: 965 bytes --] Hi all, On MIPS, with maxsec=4, clocks_calc_mult_shift() may generate a very big mult, which may easily cause timekeeper.mult overflow within timekeeping jobs. e.g. when clock freq was 250000500(i.e. mips_hpt_frequency=250000500, and the CPU Freq will be 250000500*2=500001000), mult will be 0xffffde72 Attachment is a script that calculates mult values for CPU Freq between 400050000 and 500050000, with 1KHz step. It outputs mult values greater than 0xf0000000: CPU Freq:500001000, mult:0xffffde72, shift:30 CPU Freq:500002000, mult:0xffffbce4, shift:30 CPU Freq:500003000, mult:0xffff9b56, shift:30 CPU Freq:500004000, mult:0xffff79c9, shift:30 ... The peak value appears around CPU_freq=500001000. To avoid this, it may need: 1. Supply a bigger maxsec value? 2. In clocks_calc_mult_shift(), pick next mult/shift pair if mult is too big? Then maxsec will not be strictly obeyed. 3. Change timekeeper.mult to u64? 4. ... Any idea? -- Regards, - Chen Jie [-- Attachment #2: mult-test.py --] [-- Type: text/x-python, Size: 511 bytes --] #!/bin/env python def clocks_calc_mult_shift(from_, to_, maxsec): sftacc = 32; tmp = maxsec * from_ >> 32; while tmp: tmp >>= 1 sftacc -= 1 for sft in xrange(32, 0, -1): tmp = to_ << sft; tmp += (from_ / 2) tmp /= from_ if ((tmp >> sftacc) == 0): break mult = tmp shift = sft return mult, shift for i in xrange(400050000, 500050000, 1000): mult, shift = clocks_calc_mult_shift(i/2, 1000000000, 4) if mult > 0xf0000000: print "CPU Freq:%d, mult:0x%x, shift:%d" % (i, mult, shift) ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [MIPS]clocks_calc_mult_shift() may gen a too big mult value 2011-10-31 9:00 [MIPS]clocks_calc_mult_shift() may gen a too big mult value Chen Jie @ 2011-10-31 9:20 ` Yong Zhang 2011-10-31 10:48 ` Chen Jie 0 siblings, 1 reply; 8+ messages in thread From: Yong Zhang @ 2011-10-31 9:20 UTC (permalink / raw) To: Chen Jie Cc: linux-mips, LKML, johnstul, tglx, yanhua, 项宇, zhangfx, 孙海勇 On Mon, Oct 31, 2011 at 5:00 PM, Chen Jie <chenj@lemote.com> wrote: > Hi all, > > On MIPS, with maxsec=4, clocks_calc_mult_shift() may generate a very > big mult, which may easily cause timekeeper.mult overflow within > timekeeping jobs. Hmmm, why not use clocksource_register_hz()/clocksource_register_khz() instead? it's more convenient. Thanks, Yong > > e.g. when clock freq was 250000500(i.e. mips_hpt_frequency=250000500, > and the CPU Freq will be 250000500*2=500001000), mult will be > 0xffffde72 > > Attachment is a script that calculates mult values for CPU Freq > between 400050000 and 500050000, with 1KHz step. It outputs mult > values greater than 0xf0000000: > CPU Freq:500001000, mult:0xffffde72, shift:30 > CPU Freq:500002000, mult:0xffffbce4, shift:30 > CPU Freq:500003000, mult:0xffff9b56, shift:30 > CPU Freq:500004000, mult:0xffff79c9, shift:30 > ... > > The peak value appears around CPU_freq=500001000. > > To avoid this, it may need: > 1. Supply a bigger maxsec value? > 2. In clocks_calc_mult_shift(), pick next mult/shift pair if mult is > too big? Then maxsec will not be strictly obeyed. > 3. Change timekeeper.mult to u64? > 4. ... > > Any idea? > > > > -- > Regards, > - Chen Jie > -- Only stand for myself ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [MIPS]clocks_calc_mult_shift() may gen a too big mult value 2011-10-31 9:20 ` Yong Zhang @ 2011-10-31 10:48 ` Chen Jie 2011-10-31 13:03 ` John Stultz 0 siblings, 1 reply; 8+ messages in thread From: Chen Jie @ 2011-10-31 10:48 UTC (permalink / raw) To: Yong Zhang Cc: linux-mips, LKML, johnstul, tglx, yanhua, 项宇, zhangfx, 孙海勇 Hi, 2011/10/31 Yong Zhang <yong.zhang0@gmail.com>: > On Mon, Oct 31, 2011 at 5:00 PM, Chen Jie <chenj@lemote.com> wrote: >> Hi all, >> >> On MIPS, with maxsec=4, clocks_calc_mult_shift() may generate a very >> big mult, which may easily cause timekeeper.mult overflow within >> timekeeping jobs. > > Hmmm, why not use clocksource_register_hz()/clocksource_register_khz() > instead? it's more convenient. Thanks for the suggestion. And sorry for I didn't notice the upstream code has already hooked to clocksource_register_hz() in csrc-r4k.c (We're using r4000 clock source) I'm afraid this still doesn't fix my case. Through clocksource_register_hz()->__clocksource_register_scale()->__clocksource_updatefreq_scale, I got a calculated maxsec = (0xffffffff - (0xffffffff>>5))/250000500 = 16 # assume mips_hpt_frequency=250000500 With this maxsec, I got a mult of 0xffffde72, still too big. Regards, -- Chen Jie ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [MIPS]clocks_calc_mult_shift() may gen a too big mult value 2011-10-31 10:48 ` Chen Jie @ 2011-10-31 13:03 ` John Stultz 2011-10-31 13:59 ` zhangfx 0 siblings, 1 reply; 8+ messages in thread From: John Stultz @ 2011-10-31 13:03 UTC (permalink / raw) To: Chen Jie Cc: Yong Zhang, linux-mips, LKML, tglx, yanhua, 项宇, zhangfx, 孙海勇 On Mon, 2011-10-31 at 18:48 +0800, Chen Jie wrote: > Hi, > > 2011/10/31 Yong Zhang <yong.zhang0@gmail.com>: > > On Mon, Oct 31, 2011 at 5:00 PM, Chen Jie <chenj@lemote.com> wrote: > >> Hi all, > >> > >> On MIPS, with maxsec=4, clocks_calc_mult_shift() may generate a very > >> big mult, which may easily cause timekeeper.mult overflow within > >> timekeeping jobs. > > > > Hmmm, why not use clocksource_register_hz()/clocksource_register_khz() > > instead? it's more convenient. > > Thanks for the suggestion. And sorry for I didn't notice the upstream > code has already hooked to clocksource_register_hz() in csrc-r4k.c > (We're using r4000 clock source) > > I'm afraid this still doesn't fix my case. Through > clocksource_register_hz()->__clocksource_register_scale()->__clocksource_updatefreq_scale, > I got a calculated maxsec = (0xffffffff - (0xffffffff>>5))/250000500 = > 16 # assume mips_hpt_frequency=250000500 > > With this maxsec, I got a mult of 0xffffde72, still too big. Hrmm. Yong Zang is right to suggest clocksource_register_hz(), as the intention of that code is to try to avoid these sorts of issues. What is the corresponding shift value you're getting for the value above? Could you annotate clocks_calc_mult_shift() a little bit to see where things might be going wrong? thanks -john ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [MIPS]clocks_calc_mult_shift() may gen a too big mult value 2011-10-31 13:03 ` John Stultz @ 2011-10-31 13:59 ` zhangfx 2011-10-31 18:12 ` John Stultz 0 siblings, 1 reply; 8+ messages in thread From: zhangfx @ 2011-10-31 13:59 UTC (permalink / raw) To: John Stultz Cc: Chen Jie, Yong Zhang, linux-mips, LKML, tglx, yanhua, 项宇, 孙海勇 Dear Sirs, >> Thanks for the suggestion. And sorry for I didn't notice the upstream >> code has already hooked to clocksource_register_hz() in csrc-r4k.c >> (We're using r4000 clock source) >> >> I'm afraid this still doesn't fix my case. Through >> clocksource_register_hz()->__clocksource_register_scale()->__clocksource_updatefreq_scale, >> I got a calculated maxsec = (0xffffffff - (0xffffffff>>5))/250000500 = >> 16 # assume mips_hpt_frequency=250000500 >> >> With this maxsec, I got a mult of 0xffffde72, still too big. > Hrmm. Yong Zang is right to suggest clocksource_register_hz(), as the > intention of that code is to try to avoid these sorts of issues. > > What is the corresponding shift value you're getting for the value > above? > > Could you annotate clocks_calc_mult_shift() a little bit to see where > things might be going wrong? Let me give some real world data: in one machine with 500MHz freq, the calculated freq = 500084016, and clocks_calc_mult_shift() give mult = 4294245725 shift = 30 but in the 1785th call to update_wall_time, due to error correction algorithm, the mult become 4293964632, in next update_wall_time, the ntp_error is 0x301c93b7927c, which lead to an adj of 20, then mult is overflow: mult = 4293964632 + (1<<20) = 45912 with this mult, if anyone call timekeeping_get_ns or others using mult, the time concept will be extremely wrong, so some sleep will (almost)never return => virtually hang We are not abosulately sure that the error source is normal, but anyway it is a possible for the code to overflow, and it will cause hang. For this case, the timekeeping_bigadjust should be able to control adj to a maximum of around 20 with the lookahead for any error. So if the mult is chosen at shift = 29, then mult becomes 4294245725/2, it will not be possible to be overflowed. In short, choosing a mult close to 2^32 is dangerous. But I don't know what's the best way to avoid it for general cases, because I don't know how big error can be and the adj can be for different systems. Regards Yours Fuxin Zhang > > thanks > -john > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [MIPS]clocks_calc_mult_shift() may gen a too big mult value 2011-10-31 13:59 ` zhangfx @ 2011-10-31 18:12 ` John Stultz 2011-10-31 18:30 ` David Daney 0 siblings, 1 reply; 8+ messages in thread From: John Stultz @ 2011-10-31 18:12 UTC (permalink / raw) To: zhangfx Cc: Chen Jie, Yong Zhang, linux-mips, LKML, tglx, yanhua, 项宇, 孙海勇 On Mon, 2011-10-31 at 21:59 +0800, zhangfx wrote: > > Could you annotate clocks_calc_mult_shift() a little bit to see where > > things might be going wrong? > Let me give some real world data: > in one machine with 500MHz freq, > the calculated freq = 500084016, and clocks_calc_mult_shift() give > mult = 4294245725 > shift = 30 > > but in the 1785th call to update_wall_time, due to error correction > algorithm, the mult become 4293964632, > in next update_wall_time, the ntp_error is 0x301c93b7927c, which lead to > an adj of 20, then mult is overflow: > mult = 4293964632 + (1<<20) = 45912 > with this mult, if anyone call timekeeping_get_ns or others using mult, > the time concept will be extremely wrong, so some sleep will > (almost)never return => virtually hang > > We are not abosulately sure that the error source is normal, but anyway > it is a possible for the code to overflow, and it will cause hang. > > For this case, the timekeeping_bigadjust should be able to control adj > to a maximum of around 20 with the lookahead for any error. So if the > mult is chosen at shift = 29, then mult becomes 4294245725/2, it will > not be possible to be overflowed. > > In short, choosing a mult close to 2^32 is dangerous. But I don't know > what's the best way to avoid it for general cases, because I don't know > how big error can be and the adj can be for different systems. Ah. Ok, sorry for being so slow to understand. So yea, I think you're right that the issue seems to be that for certain feq values, the resulting mult,shift pair is optimized a little too far, and we don't leave enough room for ntp adjustments to mult, without the possibility of overflowing mult. The following patch should handle it (although I'm at a conf right now, so I couldn't test it), although I might be trying to be too smart here. Rather then just checking if mult is larger then 0xf0000000, we try to quantify the largest valid mult adjustment, and then make sure mult + that value doesn't overflow. NTP limits adjustments to 500ppm, but the kernel might have to deal with larger internal adjustments. Probably we could be safe ruling out larger then 5% adjustments. So then its just a matter of 1/2^4. So the largest mult adjustment should be 1 << (cs->shift - 4) Does this seem reasonable? Let me know if this seems to work for you. Thomas: does this fix look like its in a reasonable spot? I don't want to clutter up the calc_mult_shift() code up since this really only applies to clocksources and not clockevents. NOT TESTED & NOT FOR INCLUSION (YET) Signed-off-by: John Stultz <john.stultz@linaro.org> diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index cf52fda..73518d2 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -640,7 +640,7 @@ static void clocksource_enqueue(struct clocksource *cs) void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) { u64 sec; - + u32 maxadj; /* * Calc the maximum number of seconds which we can run before * wrapping around. For clocksources which have a mask > 32bit @@ -661,6 +661,22 @@ void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, NSEC_PER_SEC / scale, sec * scale); + + /* + * Since mult may be adjusted by ntp, add an extra saftey margin + * for clocksources that have large mults, to avoid overflow. + * + * Assume we won't try to correct for more then 5% adjustments + * (50,000 ppm), which approximates to 1/16 or 1/2^4. + * Thus 1 << (shift - 4) is the largest mult adjustment we'll + * support. + */ + maxadj = 1 << (shift-4); + if ((cs->mult + maxadj < cs->mult) || (cs->mult - maxadj > cs->mult)) { + cs->mult >>= 1; + cs->shift--; + } + cs->max_idle_ns = clocksource_max_deferment(cs); } EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [MIPS]clocks_calc_mult_shift() may gen a too big mult value 2011-10-31 18:12 ` John Stultz @ 2011-10-31 18:30 ` David Daney 2011-10-31 19:51 ` John Stultz 0 siblings, 1 reply; 8+ messages in thread From: David Daney @ 2011-10-31 18:30 UTC (permalink / raw) To: John Stultz, tglx@linutronix.de Cc: zhangfx, Chen Jie, Yong Zhang, linux-mips@linux-mips.org, LKML, yanhua, 项宇, 孙海勇 On 10/31/2011 11:12 AM, John Stultz wrote: > On Mon, 2011-10-31 at 21:59 +0800, zhangfx wrote: [...] >> >> In short, choosing a mult close to 2^32 is dangerous. But I don't know >> what's the best way to avoid it for general cases, because I don't know >> how big error can be and the adj can be for different systems. > > Ah. Ok, sorry for being so slow to understand. > > So yea, I think you're right that the issue seems to be that for certain > feq values, the resulting mult,shift pair is optimized a little too far, > and we don't leave enough room for ntp adjustments to mult, without the > possibility of overflowing mult. > > The following patch should handle it (although I'm at a conf right now, > so I couldn't test it), although I might be trying to be too smart here. > Rather then just checking if mult is larger then 0xf0000000, we try to > quantify the largest valid mult adjustment, and then make sure mult + > that value doesn't overflow. NTP limits adjustments to 500ppm, but the > kernel might have to deal with larger internal adjustments. Probably we > could be safe ruling out larger then 5% adjustments. > > So then its just a matter of 1/2^4. So the largest mult adjustment > should be 1<< (cs->shift - 4) > > Does this seem reasonable? Let me know if this seems to work for you. > > Thomas: does this fix look like its in a reasonable spot? I don't want > to clutter up the calc_mult_shift() code up since this really only > applies to clocksources and not clockevents. > > NOT TESTED& NOT FOR INCLUSION (YET) > Signed-off-by: John Stultz<john.stultz@linaro.org> > diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c > index cf52fda..73518d2 100644 > --- a/kernel/time/clocksource.c > +++ b/kernel/time/clocksource.c > @@ -640,7 +640,7 @@ static void clocksource_enqueue(struct clocksource *cs) > void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) > { > u64 sec; > - > + u32 maxadj; > /* > * Calc the maximum number of seconds which we can run before > * wrapping around. For clocksources which have a mask> 32bit > @@ -661,6 +661,22 @@ void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) > > clocks_calc_mult_shift(&cs->mult,&cs->shift, freq, > NSEC_PER_SEC / scale, sec * scale); > + > + /* > + * Since mult may be adjusted by ntp, add an extra saftey margin > + * for clocksources that have large mults, to avoid overflow. > + * > + * Assume we won't try to correct for more then 5% adjustments Can we do any better than making assumptions about this? The current assumption appears to be that only very small adjustments will be made, and that didn't workout so well. Is it possible to put hard constraints on these things, so that it will always work? David Daney > + * (50,000 ppm), which approximates to 1/16 or 1/2^4. > + * Thus 1<< (shift - 4) is the largest mult adjustment we'll > + * support. > + */ > + maxadj = 1<< (shift-4); > + if ((cs->mult + maxadj< cs->mult) || (cs->mult - maxadj> cs->mult)) { > + cs->mult>>= 1; > + cs->shift--; > + } > + > cs->max_idle_ns = clocksource_max_deferment(cs); > } > EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [MIPS]clocks_calc_mult_shift() may gen a too big mult value 2011-10-31 18:30 ` David Daney @ 2011-10-31 19:51 ` John Stultz 0 siblings, 0 replies; 8+ messages in thread From: John Stultz @ 2011-10-31 19:51 UTC (permalink / raw) To: David Daney Cc: tglx@linutronix.de, zhangfx, Chen Jie, Yong Zhang, linux-mips@linux-mips.org, LKML, yanhua, 项宇, 孙海勇 On Mon, 2011-10-31 at 11:30 -0700, David Daney wrote: > On 10/31/2011 11:12 AM, John Stultz wrote: > > + /* > > + * Since mult may be adjusted by ntp, add an extra saftey margin > > + * for clocksources that have large mults, to avoid overflow. > > + * > > + * Assume we won't try to correct for more then 5% adjustments > > Can we do any better than making assumptions about this? > > The current assumption appears to be that only very small adjustments > will be made, and that didn't workout so well. s/only very small/no/ The calc_mult_shift function doesn't take any adjustments into account. > Is it possible to put hard constraints on these things, so that it will > always work? Fair enough. The patch was a bit off the cuff, and you're right that the assumption is broken: ntp limits the freq adjustment to 500ppm, but the kernel limits tick adjustments to 10%. Thus 11% adjustments (easier to remember then 10.05%) would be the hard limit of adjustments from external interfaces. So I'll need to rework the patch to adapt for that. The harder part, once we put a hard constraint on the adjustment, is to enforce that the timekeeping_bigadjust() doesn't push it beyond that, since its logic uses relative adjustments and doesn't consider the original mult value. Further, since its fairly opaque code, proving the constraint itself won't break in edge cases is also needed, and will take some time. So yea, you're point is fair. Its just going to take a bit of thoughtful review before implementing such a hard constraint universally. So making a good adversary constraint first (11%), and then iteratively hardening the code it impacts might be a good approach to get there. thanks -john ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-10-31 19:59 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-10-31 9:00 [MIPS]clocks_calc_mult_shift() may gen a too big mult value Chen Jie 2011-10-31 9:20 ` Yong Zhang 2011-10-31 10:48 ` Chen Jie 2011-10-31 13:03 ` John Stultz 2011-10-31 13:59 ` zhangfx 2011-10-31 18:12 ` John Stultz 2011-10-31 18:30 ` David Daney 2011-10-31 19:51 ` John Stultz
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox