Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1471979 > unrolled thread
| Started by | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| First post | 2016-08-29 18:40 +0200 |
| Last post | 2016-09-02 18:50 +0200 |
| Articles | 10 — 2 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [PATCH v15 04/13] task_isolation: add initial support Peter Zijlstra <peterz@infradead.org> - 2016-08-29 18:40 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Peter Zijlstra <peterz@infradead.org> - 2016-08-29 18:50 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Peter Zijlstra <peterz@infradead.org> - 2016-08-30 10:10 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Peter Zijlstra <peterz@infradead.org> - 2016-08-30 10:00 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Andy Lutomirski <luto@amacapital.net> - 2016-08-30 18:40 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Andy Lutomirski <luto@amacapital.net> - 2016-08-30 20:50 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Andy Lutomirski <luto@amacapital.net> - 2016-08-30 22:00 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Andy Lutomirski <luto@amacapital.net> - 2016-09-02 19:30 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Peter Zijlstra <peterz@infradead.org> - 2016-09-01 12:10 +0200
Re: [PATCH v15 04/13] task_isolation: add initial support Peter Zijlstra <peterz@infradead.org> - 2016-09-02 18:50 +0200
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-08-29 18:40 +0200 |
| Subject | Re: [PATCH v15 04/13] task_isolation: add initial support |
| Message-ID | <sbxLk-1cg-33@gated-at.bofh.it> |
On Tue, Aug 16, 2016 at 05:19:27PM -0400, Chris Metcalf wrote: > + /* > + * Request rescheduling unless we are in full dynticks mode. > + * We would eventually get pre-empted without this, and if > + * there's another task waiting, it would run; but by > + * explicitly requesting the reschedule, we may reduce the > + * latency. We could directly call schedule() here as well, > + * but since our caller is the standard place where schedule() > + * is called, we defer to the caller. > + * > + * A more substantive approach here would be to use a struct > + * completion here explicitly, and complete it when we shut > + * down dynticks, but since we presumably have nothing better > + * to do on this core anyway, just spinning seems plausible. > + */ > + if (!tick_nohz_tick_stopped()) > + set_tsk_need_resched(current); This is broken.. and it would be really good if you don't actually need to do this.
[toc] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-08-29 18:50 +0200 |
| Message-ID | <sbxV0-1fP-43@gated-at.bofh.it> |
| In reply to | #1471979 |
On Mon, Aug 29, 2016 at 12:40:32PM -0400, Chris Metcalf wrote: > On 8/29/2016 12:33 PM, Peter Zijlstra wrote: > >On Tue, Aug 16, 2016 at 05:19:27PM -0400, Chris Metcalf wrote: > >>+ /* > >>+ * Request rescheduling unless we are in full dynticks mode. > >>+ * We would eventually get pre-empted without this, and if > >>+ * there's another task waiting, it would run; but by > >>+ * explicitly requesting the reschedule, we may reduce the > >>+ * latency. We could directly call schedule() here as well, > >>+ * but since our caller is the standard place where schedule() > >>+ * is called, we defer to the caller. > >>+ * > >>+ * A more substantive approach here would be to use a struct > >>+ * completion here explicitly, and complete it when we shut > >>+ * down dynticks, but since we presumably have nothing better > >>+ * to do on this core anyway, just spinning seems plausible. > >>+ */ > >>+ if (!tick_nohz_tick_stopped()) > >>+ set_tsk_need_resched(current); > >This is broken.. and it would be really good if you don't actually need > >to do this. > > Can you elaborate? Naked use of TIF_NEED_RESCHED like this is busted. There is more state that needs to be poked to keep things consistent / working.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-08-30 10:10 +0200 |
| Message-ID | <sbMhk-2cK-9@gated-at.bofh.it> |
| In reply to | #1471985 |
On Mon, Aug 29, 2016 at 12:53:30PM -0400, Chris Metcalf wrote: > Would it be cleaner to just replace the set_tsk_need_resched() call > with something like: > > set_current_state(TASK_INTERRUPTIBLE); > schedule(); > __set_current_state(TASK_RUNNING); > > or what would you recommend? That'll just get you to sleep _forever_... > Or, as I said, just doing a busy loop here while testing to see > if need_resched or signal had been set? Why do you care about need_resched() and or signals? How is that related to the tick being stopped or not?
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-08-30 10:00 +0200 |
| Message-ID | <sbM7D-1Ul-35@gated-at.bofh.it> |
| In reply to | #1471979 |
On Mon, Aug 29, 2016 at 12:40:32PM -0400, Chris Metcalf wrote: > On 8/29/2016 12:33 PM, Peter Zijlstra wrote: > >On Tue, Aug 16, 2016 at 05:19:27PM -0400, Chris Metcalf wrote: > >>+ /* > >>+ * Request rescheduling unless we are in full dynticks mode. > >>+ * We would eventually get pre-empted without this, and if > >>+ * there's another task waiting, it would run; but by > >>+ * explicitly requesting the reschedule, we may reduce the > >>+ * latency. We could directly call schedule() here as well, > >>+ * but since our caller is the standard place where schedule() > >>+ * is called, we defer to the caller. > >>+ * > >>+ * A more substantive approach here would be to use a struct > >>+ * completion here explicitly, and complete it when we shut > >>+ * down dynticks, but since we presumably have nothing better > >>+ * to do on this core anyway, just spinning seems plausible. > >>+ */ > >>+ if (!tick_nohz_tick_stopped()) > >>+ set_tsk_need_resched(current); > >This is broken.. and it would be really good if you don't actually need > >to do this. > > Can you elaborate? We clearly do want to wait until we are in full > dynticks mode before we return to userspace. > > We could do it just in the prctl() syscall only, but then we lose the > ability to implement the NOSIG mode, which can be a convenience. So this isn't spelled out anywhere. Why does this need to be in the return to user path? > Even without that consideration, we really can't be sure we stay in > dynticks mode if we disable the dynamic tick, but then enable interrupts, > and end up taking an interrupt on the way back to userspace, and > it turns the tick back on. That's why we do it here, where we know > interrupts will stay disabled until we get to userspace. But but but.. task_isolation_enter() is explicitly ran with IRQs _enabled_!! It even WARNs if they're disabled. > So if we are doing it here, what else can/should we do? There really > shouldn't be any other tasks waiting to run at this point, so there's > not a heck of a lot else to do on this core. We could just spin and > check need_resched and signal status manually instead, but that > seems kind of duplicative of code already done in our caller here. What !? I really don't get this, what are you waiting for? Why is rescheduling making things better.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-08-30 18:40 +0200 |
| Message-ID | <sbUeS-7ka-15@gated-at.bofh.it> |
| In reply to | #1472291 |
On Tue, Aug 30, 2016 at 8:32 AM, Chris Metcalf <cmetcalf@mellanox.com> wrote: > On 8/30/2016 3:58 AM, Peter Zijlstra wrote: >> >> On Mon, Aug 29, 2016 at 12:40:32PM -0400, Chris Metcalf wrote: >>> >>> On 8/29/2016 12:33 PM, Peter Zijlstra wrote: >>>> >>>> On Tue, Aug 16, 2016 at 05:19:27PM -0400, Chris Metcalf wrote: >>>>> >>>>> + /* >>>>> + * Request rescheduling unless we are in full dynticks mode. >>>>> + * We would eventually get pre-empted without this, and if >>>>> + * there's another task waiting, it would run; but by >>>>> + * explicitly requesting the reschedule, we may reduce the >>>>> + * latency. We could directly call schedule() here as well, >>>>> + * but since our caller is the standard place where schedule() >>>>> + * is called, we defer to the caller. >>>>> + * >>>>> + * A more substantive approach here would be to use a struct >>>>> + * completion here explicitly, and complete it when we shut >>>>> + * down dynticks, but since we presumably have nothing better >>>>> + * to do on this core anyway, just spinning seems plausible. >>>>> + */ >>>>> + if (!tick_nohz_tick_stopped()) >>>>> + set_tsk_need_resched(current); >>>> >>>> This is broken.. and it would be really good if you don't actually need >>>> to do this. >>> >>> Can you elaborate? We clearly do want to wait until we are in full >>> dynticks mode before we return to userspace. >>> >>> We could do it just in the prctl() syscall only, but then we lose the >>> ability to implement the NOSIG mode, which can be a convenience. >> >> So this isn't spelled out anywhere. Why does this need to be in the >> return to user path? > > > I'm not sure where this should be spelled out, to be honest. I guess > I can add some commentary to the commit message explaining this part. > > The basic idea is just that we don't want to be at risk from the > dyntick getting enabled. Similarly, we don't want to be at risk of a > later global IPI due to lru_add_drain stuff, for example. And, we may > want to add additional stuff, like catching kernel TLB flushes and > deferring them when a remote core is in userspace. To do all of this > kind of stuff, we need to run in the return to user path so we are > late enough to guarantee no further kernel things will happen to > perturb our carefully-arranged isolation state that includes dyntick > off, per-cpu lru cache empty, etc etc. None of the above should need to *loop*, though, AFAIK.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-08-30 20:50 +0200 |
| Message-ID | <sbWgF-7T-13@gated-at.bofh.it> |
| In reply to | #1472630 |
On Aug 30, 2016 10:02 AM, "Chris Metcalf" <cmetcalf@mellanox.com> wrote: > > On 8/30/2016 12:30 PM, Andy Lutomirski wrote: >> >> On Tue, Aug 30, 2016 at 8:32 AM, Chris Metcalf <cmetcalf@mellanox.com> wrote: >>> >>> On 8/30/2016 3:58 AM, Peter Zijlstra wrote: >>>> >>>> On Mon, Aug 29, 2016 at 12:40:32PM -0400, Chris Metcalf wrote: >>>>> >>>>> On 8/29/2016 12:33 PM, Peter Zijlstra wrote: >>>>>> >>>>>> On Tue, Aug 16, 2016 at 05:19:27PM -0400, Chris Metcalf wrote: >>>>>>> >>>>>>> + /* >>>>>>> + * Request rescheduling unless we are in full dynticks mode. >>>>>>> + * We would eventually get pre-empted without this, and if >>>>>>> + * there's another task waiting, it would run; but by >>>>>>> + * explicitly requesting the reschedule, we may reduce the >>>>>>> + * latency. We could directly call schedule() here as well, >>>>>>> + * but since our caller is the standard place where schedule() >>>>>>> + * is called, we defer to the caller. >>>>>>> + * >>>>>>> + * A more substantive approach here would be to use a struct >>>>>>> + * completion here explicitly, and complete it when we shut >>>>>>> + * down dynticks, but since we presumably have nothing better >>>>>>> + * to do on this core anyway, just spinning seems plausible. >>>>>>> + */ >>>>>>> + if (!tick_nohz_tick_stopped()) >>>>>>> + set_tsk_need_resched(current); >>>>>> >>>>>> This is broken.. and it would be really good if you don't actually need >>>>>> to do this. >>>>> >>>>> Can you elaborate? We clearly do want to wait until we are in full >>>>> dynticks mode before we return to userspace. >>>>> >>>>> We could do it just in the prctl() syscall only, but then we lose the >>>>> ability to implement the NOSIG mode, which can be a convenience. >>>> >>>> So this isn't spelled out anywhere. Why does this need to be in the >>>> return to user path? >>> >>> >>> I'm not sure where this should be spelled out, to be honest. I guess >>> I can add some commentary to the commit message explaining this part. >>> >>> The basic idea is just that we don't want to be at risk from the >>> dyntick getting enabled. Similarly, we don't want to be at risk of a >>> later global IPI due to lru_add_drain stuff, for example. And, we may >>> want to add additional stuff, like catching kernel TLB flushes and >>> deferring them when a remote core is in userspace. To do all of this >>> kind of stuff, we need to run in the return to user path so we are >>> late enough to guarantee no further kernel things will happen to >>> perturb our carefully-arranged isolation state that includes dyntick >>> off, per-cpu lru cache empty, etc etc. >> >> None of the above should need to *loop*, though, AFAIK. > > > Ordering is a problem, though. > > We really want to run task isolation last, so we can guarantee that > all the isolation prerequisites are met (dynticks stopped, per-cpu lru > cache empty, etc). But achieving that state can require enabling > interrupts - most obviously if we have to schedule, e.g. for vmstat > clearing or whatnot (see the cond_resched in refresh_cpu_vm_stats), or > just while waiting for that last dyntick interrupt to occur. I'm also > not sure that even something as simple as draining the per-cpu lru > cache can be done holding interrupts disabled throughout - certainly > there's a !SMP code path there that just re-enables interrupts > unconditionally, which gives me pause. > > At any rate at that point you need to retest for signals, resched, > etc, all as usual, and then you need to recheck the task isolation > prerequisites once more. > > I may be missing something here, but it's really not obvious to me > that there's a way to do this without having task isolation integrated > into the usual return-to-userspace loop. > What if we did it the other way around: set a percpu flag saying "going quiescent; disallow new deferred work", then finish all existing work and return to userspace. Then, on the next entry, clear that flag. With the flag set, vmstat would just flush anything that it accumulates immediately, nothing would be added to the LRU list, etc. Also, this cond_resched stuff doesn't worry me too much at a fundamental level -- if we're really going quiescent, shouldn't we be able to arrange that there are no other schedulable tasks on the CPU in question? --Andy
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-08-30 22:00 +0200 |
| Message-ID | <sbXmq-Og-39@gated-at.bofh.it> |
| In reply to | #1472763 |
On Tue, Aug 30, 2016 at 12:37 PM, Chris Metcalf <cmetcalf@mellanox.com> wrote: > On 8/30/2016 2:43 PM, Andy Lutomirski wrote: >> >> On Aug 30, 2016 10:02 AM, "Chris Metcalf" <cmetcalf@mellanox.com> wrote: >>> >>> On 8/30/2016 12:30 PM, Andy Lutomirski wrote: >>>> >>>> On Tue, Aug 30, 2016 at 8:32 AM, Chris Metcalf <cmetcalf@mellanox.com> >>>> wrote: >>>>> >>>>> The basic idea is just that we don't want to be at risk from the >>>>> dyntick getting enabled. Similarly, we don't want to be at risk of a >>>>> later global IPI due to lru_add_drain stuff, for example. And, we may >>>>> want to add additional stuff, like catching kernel TLB flushes and >>>>> deferring them when a remote core is in userspace. To do all of this >>>>> kind of stuff, we need to run in the return to user path so we are >>>>> late enough to guarantee no further kernel things will happen to >>>>> perturb our carefully-arranged isolation state that includes dyntick >>>>> off, per-cpu lru cache empty, etc etc. >>>> >>>> None of the above should need to *loop*, though, AFAIK. >>> >>> Ordering is a problem, though. >>> >>> We really want to run task isolation last, so we can guarantee that >>> all the isolation prerequisites are met (dynticks stopped, per-cpu lru >>> cache empty, etc). But achieving that state can require enabling >>> interrupts - most obviously if we have to schedule, e.g. for vmstat >>> clearing or whatnot (see the cond_resched in refresh_cpu_vm_stats), or >>> just while waiting for that last dyntick interrupt to occur. I'm also >>> not sure that even something as simple as draining the per-cpu lru >>> cache can be done holding interrupts disabled throughout - certainly >>> there's a !SMP code path there that just re-enables interrupts >>> unconditionally, which gives me pause. >>> >>> At any rate at that point you need to retest for signals, resched, >>> etc, all as usual, and then you need to recheck the task isolation >>> prerequisites once more. >>> >>> I may be missing something here, but it's really not obvious to me >>> that there's a way to do this without having task isolation integrated >>> into the usual return-to-userspace loop. >>> >> What if we did it the other way around: set a percpu flag saying >> "going quiescent; disallow new deferred work", then finish all >> existing work and return to userspace. Then, on the next entry, clear >> that flag. With the flag set, vmstat would just flush anything that >> it accumulates immediately, nothing would be added to the LRU list, >> etc. > > > This is an interesting idea! > > However, there are a number of implementation ideas that make me > worry that it might be a trickier approach overall. > > First, "on the next entry" hides a world of hurt in four simple words. > Some platforms (arm64 and tile, that I'm familiar with) have a common > chunk of code that always runs on every entry to the kernel. It would > not be too hard to poke at the assembly and make those platforms > always run some task-isolation specific code on entry. But x86 scares > me - there seem to be a whole lot of ways to get into the kernel, and > I'm not convinced there is a lot of shared macrology or whatever that > would make it straightforward to intercept all of them. Just use the context tracking entry hook. It's 100% reliable. The relevant x86 function is enter_from_user_mode(), but I would just hook into user_exit() in the common code. (This code is had better be reliable, because context tracking depends on it, and, if context tracking doesn't work on a given arch, then isolation isn't going to work regardless. > > Then, there are the two actual subsystems in question. It looks like > we could intercept LRU reasonably cleanly by hooking pagevec_add() > is to return zero when we are in this "going quiescent" mode, and that > would keep the per-cpu vectors empty. The vmstat stuff is a little > trickier since all the existing code is built around updating the per-cpu > stuff and then only later copying it off to the global state. I suppose > we could add a test-and-flush at the end of every public API and not > worry about the implementation cost. Seems reasonable to me. If anyone cares about the performance hit, they can fix it. > > But it does seem like we are adding noticeable maintenance cost on > the mainline kernel to support task isolation by doing this. My guess > is that it is easier to support the kind of "are you clean?" / "get clean" > APIs for subsystems, rather than weaving a whole set of "stay clean" > mechanism into each subsystem. My intuition is that it's the other way around. For the mainline kernel, having a nice clean well-integrated implementation is nicer than having a bolted-on implementation that interacts in potentially complicated ways. Once quiescence support is in mainline, the size of the diff or the degree to which it's scattered around is irrelevant because it's not a diff any more. > > So to pop up a level, what is your actual concern about the existing > "do it in a loop" model? The macrology currently in use means there > is zero cost if you don't configure TASK_ISOLATION, and the software > maintenance cost seems low since the idioms used for task isolation > in the loop are generally familiar to people reading that code. My concern is that it's not obvious to readers of the code that the loop ever terminates. It really ought to, but it's doing something very odd. Normally we can loop because we get scheduled out, but actually blocking in the return-to-userspace path, especially blocking on a condition that doesn't have a wakeup associated with it, is odd. > >> Also, this cond_resched stuff doesn't worry me too much at a >> fundamental level -- if we're really going quiescent, shouldn't we be >> able to arrange that there are no other schedulable tasks on the CPU >> in question? > > > We aren't currently planning to enforce things in the scheduler, so if > the application affinitizes another task on top of an existing task > isolation task, by default the task isolation task just dies. (Unless > it's using NOSIG mode, in which case it just ends up stuck in the > kernel trying to wait out the dyntick until you either kill it, or > re-affinitize the offending task.) But I'm reluctant to guarantee > every possible way that you might (perhaps briefly) have some > schedulable task, and the current approach seems pretty robust if that > sort of thing happens. > This kind of waiting out the dyntick scares me. Why is there ever a dyntick that you're waiting out? If quiescence is to be a supported mainline feature, shouldn't the scheduler be integrated well enough with it that you don't need to wait like this?
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-09-02 19:30 +0200 |
| Message-ID | <sd0rT-2lN-25@gated-at.bofh.it> |
| In reply to | #1472830 |
On Sep 2, 2016 7:04 AM, "Chris Metcalf" <cmetcalf@mellanox.com> wrote:
>
> On 8/30/2016 3:50 PM, Andy Lutomirski wrote:
>>
>> On Tue, Aug 30, 2016 at 12:37 PM, Chris Metcalf <cmetcalf@mellanox.com> wrote:
>>>
>>> On 8/30/2016 2:43 PM, Andy Lutomirski wrote:
>>>>
>>>> What if we did it the other way around: set a percpu flag saying
>>>> "going quiescent; disallow new deferred work", then finish all
>>>> existing work and return to userspace. Then, on the next entry, clear
>>>> that flag. With the flag set, vmstat would just flush anything that
>>>> it accumulates immediately, nothing would be added to the LRU list,
>>>> etc.
>>>
>>>
>>> This is an interesting idea!
>>>
>>> However, there are a number of implementation ideas that make me
>>> worry that it might be a trickier approach overall.
>>>
>>> First, "on the next entry" hides a world of hurt in four simple words.
>>> Some platforms (arm64 and tile, that I'm familiar with) have a common
>>> chunk of code that always runs on every entry to the kernel. It would
>>> not be too hard to poke at the assembly and make those platforms
>>> always run some task-isolation specific code on entry. But x86 scares
>>> me - there seem to be a whole lot of ways to get into the kernel, and
>>> I'm not convinced there is a lot of shared macrology or whatever that
>>> would make it straightforward to intercept all of them.
>>
>> Just use the context tracking entry hook. It's 100% reliable. The
>> relevant x86 function is enter_from_user_mode(), but I would just hook
>> into user_exit() in the common code. (This code is had better be
>> reliable, because context tracking depends on it, and, if context
>> tracking doesn't work on a given arch, then isolation isn't going to
>> work regardless.
>
>
> This looks a lot cleaner than last time I looked at the x86 code. So yes, I think
> we could do an entry-point approach plausibly now.
>
> This is also good for when we want to look at deferring the kernel TLB flush,
> since it's the same mechanism that would be required for that.
>
>
There's at least one gotcha for the latter: NMIs aren't currently
guaranteed to go through context tracking. Instead they use their own
RCU hooks. Deferred TLB flushes can still be made to work, but a bit
more care will be needed. I would probably approach it with an
additional NMI hook in the same places as rcu_nmi_enter() that does,
more or less:
if (need_tlb_flush) flush();
and then make sure that the normal exit hook looks like:
if (need_tlb_flush) {
flush();
barrier(); /* An NMI must not see !need_tlb_flush if the TLB hasn't
been flushed */
flush the TLB;
}
>>> But it does seem like we are adding noticeable maintenance cost on
>>> the mainline kernel to support task isolation by doing this. My guess
>>> is that it is easier to support the kind of "are you clean?" / "get clean"
>>> APIs for subsystems, rather than weaving a whole set of "stay clean"
>>> mechanism into each subsystem.
>>
>> My intuition is that it's the other way around. For the mainline
>> kernel, having a nice clean well-integrated implementation is nicer
>> than having a bolted-on implementation that interacts in potentially
>> complicated ways. Once quiescence support is in mainline, the size of
>> the diff or the degree to which it's scattered around is irrelevant
>> because it's not a diff any more.
>
>
> I'm not concerned with the size of the diff, just with the intrusiveness into
> the various subsystems.
>
> That said, code talks, so let me take a swing at doing it the way you suggest
> for vmstat/lru and we'll see what it looks like.
Thanks :)
>
>
>>> So to pop up a level, what is your actual concern about the existing
>>> "do it in a loop" model? The macrology currently in use means there
>>> is zero cost if you don't configure TASK_ISOLATION, and the software
>>> maintenance cost seems low since the idioms used for task isolation
>>> in the loop are generally familiar to people reading that code.
>>
>> My concern is that it's not obvious to readers of the code that the
>> loop ever terminates. It really ought to, but it's doing something
>> very odd. Normally we can loop because we get scheduled out, but
>> actually blocking in the return-to-userspace path, especially blocking
>> on a condition that doesn't have a wakeup associated with it, is odd.
>
>
> True, although, comments :-)
>
> Regardless, though, this doesn't seem at all weird to me in the
> context of the vmstat and lru stuff, though. It's exactly parallel to
> the fact that we loop around on checking need_resched and signal, and
> in some cases you could imagine multiple loops around when we schedule
> out and get a signal, so loop around again, and then another
> reschedule event happens during signal processing so we go around
> again, etc. Eventually it settles down. It's the same with the
> vmstat/lru stuff.
Only kind of.
When we say, effectively, while (need_resched()) schedule();, we're
not waiting for an event or condition per se. We're runnable (in the
sense that userspace wants to run and we're not blocked on anything)
the entire time -- we're simply yielding to some other thread that is
also runnable. So if that loop runs forever, it either means that
we're at low priority and we genuinely shouldn't be running or that
there's a scheduler bug.
If, on the other hand, we say while (not quiesced) schedule(); (or
equivalent), we're saying that we're *not* really ready to run and
that we're waiting for some condition to change. The condition in
question is fairly complicated and won't wake us when we are ready. I
can also imagine the scheduler getting rather confused, since, as far
as the scheduler knows, we are runnable and we are supposed to be
running.
>
>
>>>> Also, this cond_resched stuff doesn't worry me too much at a
>>>> fundamental level -- if we're really going quiescent, shouldn't we be
>>>> able to arrange that there are no other schedulable tasks on the CPU
>>>> in question?
>>>
>>> We aren't currently planning to enforce things in the scheduler, so if
>>> the application affinitizes another task on top of an existing task
>>> isolation task, by default the task isolation task just dies. (Unless
>>> it's using NOSIG mode, in which case it just ends up stuck in the
>>> kernel trying to wait out the dyntick until you either kill it, or
>>> re-affinitize the offending task.) But I'm reluctant to guarantee
>>> every possible way that you might (perhaps briefly) have some
>>> schedulable task, and the current approach seems pretty robust if that
>>> sort of thing happens.
>>
>> This kind of waiting out the dyntick scares me. Why is there ever a
>> dyntick that you're waiting out? If quiescence is to be a supported
>> mainline feature, shouldn't the scheduler be integrated well enough
>> with it that you don't need to wait like this?
>
>
> Well, this is certainly the funkiest piece of the task isolation
> stuff. The problem is that the dyntick stuff may, for example, need
> one more tick 4us from now (or whatever) just to close out the current
> RCU period. We can't return to userspace until that happens. So what
> else can we do when the task is ready to return to userspace? We
> could punt into the idle task instead of waiting in this task, which
> was my earlier schedule_time() suggestion. Do you think that's cleaner?
>
Unless I'm missing something (which is reasonably likely), couldn't
the isolation code just force or require rcu_nocbs on the isolated
CPUs to avoid this problem entirely.
I admit I still don't understand why the RCU context tracking code
can't just run the callback right away instead of waiting however many
microseconds in general. I feel like paulmck has explained it to me
at least once, but that doesn't mean I remember the answer.
--Andy
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-09-01 12:10 +0200 |
| Message-ID | <scx6x-nV-19@gated-at.bofh.it> |
| In reply to | #1472291 |
On Tue, Aug 30, 2016 at 11:32:16AM -0400, Chris Metcalf wrote: > On 8/30/2016 3:58 AM, Peter Zijlstra wrote: > >What !? I really don't get this, what are you waiting for? Why is > >rescheduling making things better. > > We need to wait for the last dyntick to fire before we can return to > userspace. There are plenty of options as to what we can do in the > meanwhile. Why not keep your _TIF_TASK_ISOLATION_FOO flag set and re-enter the loop? I really don't see how setting TIF_NEED_RESCHED is helping anything.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-09-02 18:50 +0200 |
| Message-ID | <scZPb-1TH-29@gated-at.bofh.it> |
| In reply to | #1474245 |
On Fri, Sep 02, 2016 at 10:03:52AM -0400, Chris Metcalf wrote: > Any thoughts on the question of "just re-enter the loop" vs. schedule_timeout()? schedule_timeout() should only be used for things you do not have control over, like things outside of the machine. If you want to actually block running, use that completion you were talking of.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web