From: Nicolai Stange <nicstange@gmail.com>
To: Thomas Gleixner <tglx@linutronix.de>
Cc: Nicolai Stange <nicstange@gmail.com>,
John Stultz <john.stultz@linaro.org>,
linux-kernel@vger.kernel.org
Subject: Re: [RFC v4 13/22] clockevents: check a programmed delta's bounds in terms of cycles
Date: Wed, 31 Aug 2016 10:31:13 +0200 [thread overview]
Message-ID: <87a8ftqqzy.fsf@gmail.com> (raw)
In-Reply-To: <874m66z1aa.fsf@gmail.com> (Nicolai Stange's message of "Sat, 27 Aug 2016 17:20:29 +0200")
Nicolai Stange <nicstange@gmail.com> writes:
> Nicolai Stange <nicstange@gmail.com> writes:
>
>> @@ -332,10 +337,10 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
>> if (delta <= 0)
>> return force ? clockevents_program_min_delta(dev) : -ETIME;
>>
>> - delta = min(delta, (int64_t) dev->max_delta_ns);
>> - delta = max(delta, (int64_t) dev->min_delta_ns);
>> -
>> clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
>> + clc = min_t(unsigned long, clc, dev->max_delta_ticks);
>> + clc = max_t(unsigned long, clc, dev->min_delta_ticks_adjusted);
>> +
>> rc = dev->set_next_event((unsigned long) clc, dev);
>>
>> return (rc && force) ? clockevents_program_min_delta(dev) : rc;
>
> This is broken :(
>
> I failed to recognize that ->max_delta_ns serves not only one, but
> three purposes actually:
> 1. It prevents the ced to get programmed with too large values. Still
> works with this patch.
> 2. It prevents the multiplication by dev->mult from overflowing 64 bits,
> i.e. it clamps the input delta to a range valid for the given
> ->mult. Ouch.
> 3. On 32 bit archs, it prevents the cast of clc to unsigned long from
> overflowing. Ouch here as well.
>
>
> The 3.) can be restored by doing
> clc = min_t(unsigned long long, clc, dev->max_delta_ticks);
> rather than min_t(unsigned long, ...)
> because dev->max_delta_ticks is of type unsigned long and thus,
> <= ULONG_MAX.
>
>
> Unfortunately, fixing up 2.) is not so straight forward: I'll certainly
> have to resort to ->max_delta_ns again. But then, there will be the
> issue with non-atomic updates from timekeeping -- at least if
> ->max_delta_ns continues to represent ->max_delta_ticks as it did
> before.
>
> In order to get rid of the requirement to update ->max_delta_ns whenever
> the ->mult changes, would it be Ok to decouple ->max_delta_ns from
> ->max_delta_ticks by
> a. setting
> dev->max_delta_ns = (1 << (64 - ilog2(dev->mult))) - 1
> once and for all at device registration (and from clockevents_update_freq()),
> b. and introducing an *additional* comparison
> delta = min(delta, (int64_t) dev->max_delta_ns);
> right before the multiplication in clockevents_program_event()?
>
> In this setting, ->max_delta_ns would be a function of the original
> ->mult only -- more precisely, of ilog2(dev->mult).
>
> Altogether, we'd have
>
> delta = min(delta, (int64_t) dev->max_delta_ns);
> clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
> clc = min_t(unsigned long long, clc, dev->max_delta_ticks);
> clc = max_t(unsigned long long, clc, dev->min_delta_ticks_adjusted);
>
> rc = dev->set_next_event((unsigned long) clc, dev);
>
> in clockevents_program_event() then.
>
> So, purposes 1.) and 3.) would get served by the second min() while the
> first one would make sure that the multiplication will never overflow.
>
> The downside would be the additional comparison + conditional move in
> the ced programming path. The ->max_delta_ns and ->max_delta_ticks can
> both be moved to struct clock_event_device's first cacheline
> simultaneously without affecting any of its remaining hot members though
> (on 64 bit archs with a cacheline size of 64 bytes).
>
>
> Now, to quote your objections to [22/22] ("timekeeping: inform
> clockevents about freq adjustments"):
>
>> What makes sure that the resulting shift/mult pair is still valid after this
>> adjustment? The non adjusted mult/shift pair might be right at the border of
>> potential overflows and the adjustment might just put it over the edge....
>> We need at least sanity checks here.
>
> The updated ->mult_adjusted could get restricted to never grow beyond
> (1 << fls(dev->mult)) - 1
> where dev->mult is the never changing, non-adjusted mult value. That is,
> the mult adjustment would simply stop at the point where it could
> possibly introduce overflows for some deltas smaller than the now fixed
> ->max_delta_ns.
>
>
> I have to admit that checking both, ->max_delta_ticks and ->max_delta_ns
> from clockevents_program_event() is a little bit messy. As is the
> cut-off point for the mult adjustments...
I thought a little bit more about this: having that cut-off point for
the adjusted mult is probably the right thing to do. Reasoning: In order
to avoid the overflows, the sum
ilog2(max_delta_ns) + ilog2(mult_adjusted)
should be kept bounded from above by some fixed value (this is how
clockevents_config() calculates the proper ->shift value).
Now, if mult_adjusted crossed the cut-off point,
i.e. ilog2(mult_adjusted) increased by one, then I would have no choice
other than setting ->max_delta_ns >>= 1.
Given that the whole purpose of this series is to avoid too early timer
interrupts for large deltas, this would be a strange thing to do.
>
> Maybe I should just try to schedule the necessary updates from
> timekeeping on each CPU instead? If this worked out, I could probably
> recalculate appropriate values of ->*_delta_ns and store these
> racelessly along with the adjusted mult while not touching
> clockevents_program_event() at all. That is, I would schedule something
> similar to clockevents_update_freq() on each CPU.
>
Since the "cut-off point of mult_adjusted is messy" argument is gone
now, I won't do this. So, if you don't object in the meanwhile, v5 will
have both, ->max_delta_ns *and* ->max_delta_ticks. This trades the
reduced complexity of not having to schedule the update everywhere
against an extra min() in the ced programming path.
Thanks,
Nicolai Stange
next prev parent reply other threads:[~2016-08-31 8:31 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-22 23:32 [RFC v4 00/22] adapt clockevents frequencies to mono clock Nicolai Stange
2016-08-22 23:32 ` [RFC v4 01/22] clocksource: sh_cmt: compute rate before registration again Nicolai Stange
2016-08-22 23:33 ` [RFC v4 02/22] clocksource: sh_tmu: " Nicolai Stange
2016-08-22 23:33 ` [RFC v4 03/22] clocksource: em_sti: split clock prepare and enable steps Nicolai Stange
2016-08-22 23:33 ` [RFC v4 04/22] clocksource: em_sti: compute rate before registration Nicolai Stange
2016-08-22 23:33 ` [RFC v4 05/22] clocksource: h8300_timer8: don't reset rate in ->set_state_oneshot() Nicolai Stange
2016-08-22 23:33 ` [RFC v4 06/22] clockevents: make clockevents_config() static Nicolai Stange
2016-08-22 23:33 ` [RFC v4 07/22] many clockevent drivers: set ->min_delta_ticks and ->max_delta_ticks Nicolai Stange
2016-08-22 23:33 ` [RFC v4 08/22] arch/s390/kernel/time: " Nicolai Stange
2016-08-22 23:33 ` [RFC v4 09/22] arch/x86/platform/uv/uv_time: " Nicolai Stange
2016-08-22 23:33 ` [RFC v4 10/22] arch/tile/kernel/time: " Nicolai Stange
2016-09-06 19:19 ` Chris Metcalf
2016-09-08 11:21 ` Nicolai Stange
2016-09-09 16:25 ` Chris Metcalf
2016-08-22 23:33 ` [RFC v4 11/22] clockevents: always initialize ->min_delta_ns and ->max_delta_ns Nicolai Stange
2016-08-22 23:33 ` [RFC v4 12/22] many clockevent drivers: don't set " Nicolai Stange
2016-08-22 23:33 ` [RFC v4 13/22] clockevents: check a programmed delta's bounds in terms of cycles Nicolai Stange
2016-08-27 15:20 ` Nicolai Stange
2016-08-31 8:31 ` Nicolai Stange [this message]
2016-08-22 23:33 ` [RFC v4 14/22] clockevents: clockevents_program_event(): turn clc into unsigned long Nicolai Stange
2016-08-25 13:20 ` Thomas Gleixner
2016-08-27 15:23 ` Nicolai Stange
2016-08-22 23:33 ` [RFC v4 15/22] clockevents: clockevents_program_min_delta(): don't set ->next_event Nicolai Stange
2016-08-22 23:33 ` [RFC v4 16/22] clockevents: use ->min_delta_ticks_adjusted to program minimum delta Nicolai Stange
2016-08-24 9:28 ` Nicolai Stange
2016-08-22 23:33 ` [RFC v4 17/22] clockevents: min delta increment: calculate min_delta_ns from ticks Nicolai Stange
2016-08-22 23:33 ` [RFC v4 18/22] timer_list: print_tickdevice(): calculate ->*_delta_ns dynamically Nicolai Stange
2016-08-22 23:33 ` [RFC v4 19/22] clockevents: purge ->min_delta_ns and ->max_delta_ns Nicolai Stange
2016-08-22 23:33 ` [RFC v4 20/22] clockevents: initial support for mono to raw time conversion Nicolai Stange
2016-08-22 23:33 ` [RFC v4 21/22] clockevents: make setting of ->mult and ->mult_adjusted atomic Nicolai Stange
2016-08-22 23:33 ` [RFC v4 22/22] timekeeping: inform clockevents about freq adjustments Nicolai Stange
2016-08-24 9:40 ` Nicolai Stange
2016-08-25 14:56 ` Thomas Gleixner
2016-08-25 15:25 ` Thomas Gleixner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87a8ftqqzy.fsf@gmail.com \
--to=nicstange@gmail.com \
--cc=john.stultz@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).