* [PATCH] xen: idle_loop: either deal with tasklets or go idle
@ 2017-06-14 16:53 Dario Faggioli
2017-06-14 16:53 ` Dario Faggioli
0 siblings, 1 reply; 9+ messages in thread
From: Dario Faggioli @ 2017-06-14 16:53 UTC (permalink / raw)
To: xen-devel
Cc: Andrew Cooper, Julien Grall, Stefano Stabellini, Boris Ostrovsky,
Jan Beulich
Hi,
following up on this:
https://lists.xen.org/archives/html/xen-devel/2017-06/msg01260.html
I did make a patch that moves do_tasklet() up a bit, within idle_loop().
While there, I did a bit more than that... let's see what you guys think. :-D
I've verified that this builds on ARM too, but have not run it (while I did
that, for x86):
https://travis-ci.org/fdario/xen/builds/242888986
Thanks and Regards,
Dario
---
Dario Faggioli (1):
xen: idle_loop: either deal with tasklets or go idle
xen/arch/arm/domain.c | 21 ++++++++++++++-------
xen/arch/x86/domain.c | 12 +++++++++---
xen/common/tasklet.c | 10 +---------
xen/include/xen/tasklet.h | 12 +++++++++++-
4 files changed, 35 insertions(+), 20 deletions(-)
--
<<This happens because I choose it to happen!>> (Raistlin Majere)
-----------------------------------------------------------------
Dario Faggioli, Ph.D, http://about.me/dario.faggioli
Senior Software Engineer, Citrix Systems R&D Ltd., Cambridge (UK)
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-14 16:53 [PATCH] xen: idle_loop: either deal with tasklets or go idle Dario Faggioli @ 2017-06-14 16:53 ` Dario Faggioli 2017-06-16 8:54 ` Jan Beulich 0 siblings, 1 reply; 9+ messages in thread From: Dario Faggioli @ 2017-06-14 16:53 UTC (permalink / raw) To: xen-devel Cc: Andrew Cooper, Julien Grall, Stefano Stabellini, Boris Ostrovsky, Jan Beulich In fact, there exists two kind of tasklets: vCPU and softirq context tasklets. When we want to do vCPU context tasklet work, we force the idle vCPU (of a particular pCPU) into execution, and run it from there. This means there are two possible reasons for choosing to run the idle vCPU: 1) we want a pCPU to go idle, 2) wa want to run some vCPU context tasklet work. If we're in case 2), it does not make sense to try to see whether we can go idle, and only afterwords (as the check _will_ fail), go processing tasklets. This patch rearranges the code of the body of the idle vCPUs, so that we actually check whether we are in case 1) or 2), and act accordingly. As a matter of fact, this also means that we do not check for any tasklet work to be done, after waking up from idle. This is not a problem, because: a) for softirq context tasklets, if any is queued "during" wakeup from idle, TASKLET_SOFTIRQ is raised, and the call to do_softirq() (which is still happening *after* the wakeup) will take care of it; b) for vCPU context tasklets, if any is queued "during" wakeup from idle, SCHEDULE_SOFTIRQ is raised and do_softirq() (happening after the wakeup) calls the scheduler. The scheduler sees that there is tasklet work pending and confirms the idle vCPU in execution, which then will get to execute do_tasklet(). Signed-off-by: Dario Faggioli <dario.faggioli@citrix.com> --- Cc: Stefano Stabellini <sstabellini@kernel.org> Cc: Julien Grall <julien.grall@arm.com> Cc: Jan Beulich <jbeulich@suse.com> Cc: Andrew Cooper <andrew.cooper3@citrix.com> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> --- xen/arch/arm/domain.c | 21 ++++++++++++++------- xen/arch/x86/domain.c | 12 +++++++++--- xen/common/tasklet.c | 10 +--------- xen/include/xen/tasklet.h | 12 +++++++++++- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 76310ed..0ceeb5b 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -41,20 +41,27 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu); void idle_loop(void) { + unsigned int cpu = smp_processor_id(); + for ( ; ; ) { - if ( cpu_is_offline(smp_processor_id()) ) + if ( cpu_is_offline(cpu) ) stop_cpu(); - local_irq_disable(); - if ( cpu_is_haltable(smp_processor_id()) ) + /* Are we here for running vcpu context tasklets, or for idling? */ + if ( unlikely(tasklet_work_to_do(cpu)) ) + do_tasklet(cpu); + else { - dsb(sy); - wfi(); + local_irq_disable(); + if ( cpu_is_haltable(cpu) ) + { + dsb(sy); + wfi(); + } + local_irq_enable(); } - local_irq_enable(); - do_tasklet(); do_softirq(); /* * We MUST be last (or before dsb, wfi). Otherwise after we get the diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 49388f4..d06700d 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -112,12 +112,18 @@ static void play_dead(void) static void idle_loop(void) { + unsigned int cpu = smp_processor_id(); + for ( ; ; ) { - if ( cpu_is_offline(smp_processor_id()) ) + if ( cpu_is_offline(cpu) ) play_dead(); - (*pm_idle)(); - do_tasklet(); + + /* Are we here for running vcpu context tasklets, or for idling? */ + if ( unlikely(tasklet_work_to_do(cpu)) ) + do_tasklet(cpu); + else + (*pm_idle)(); do_softirq(); /* * We MUST be last (or before pm_idle). Otherwise after we get the diff --git a/xen/common/tasklet.c b/xen/common/tasklet.c index 365a777..0465751 100644 --- a/xen/common/tasklet.c +++ b/xen/common/tasklet.c @@ -104,19 +104,11 @@ static void do_tasklet_work(unsigned int cpu, struct list_head *list) } /* VCPU context work */ -void do_tasklet(void) +void do_tasklet(unsigned int cpu) { - unsigned int cpu = smp_processor_id(); unsigned long *work_to_do = &per_cpu(tasklet_work_to_do, cpu); struct list_head *list = &per_cpu(tasklet_list, cpu); - /* - * Work must be enqueued *and* scheduled. Otherwise there is no work to - * do, and/or scheduler needs to run to update idle vcpu priority. - */ - if ( likely(*work_to_do != (TASKLET_enqueued|TASKLET_scheduled)) ) - return; - spin_lock_irq(&tasklet_lock); do_tasklet_work(cpu, list); diff --git a/xen/include/xen/tasklet.h b/xen/include/xen/tasklet.h index 8c3de7e..1a3f861 100644 --- a/xen/include/xen/tasklet.h +++ b/xen/include/xen/tasklet.h @@ -40,9 +40,19 @@ DECLARE_PER_CPU(unsigned long, tasklet_work_to_do); #define TASKLET_enqueued (1ul << _TASKLET_enqueued) #define TASKLET_scheduled (1ul << _TASKLET_scheduled) +static inline bool tasklet_work_to_do(unsigned int cpu) +{ + /* + * Work must be enqueued *and* scheduled. Otherwise there is no work to + * do, and/or scheduler needs to run to update idle vcpu priority. + */ + return per_cpu(tasklet_work_to_do, cpu) == (TASKLET_enqueued| + TASKLET_scheduled); +} + void tasklet_schedule_on_cpu(struct tasklet *t, unsigned int cpu); void tasklet_schedule(struct tasklet *t); -void do_tasklet(void); +void do_tasklet(unsigned int cpu); void tasklet_kill(struct tasklet *t); void tasklet_init( struct tasklet *t, void (*func)(unsigned long), unsigned long data); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-14 16:53 ` Dario Faggioli @ 2017-06-16 8:54 ` Jan Beulich 2017-06-16 10:44 ` Dario Faggioli 0 siblings, 1 reply; 9+ messages in thread From: Jan Beulich @ 2017-06-16 8:54 UTC (permalink / raw) To: Dario Faggioli Cc: Andrew Cooper, Julien Grall, Stefano Stabellini, Boris Ostrovsky, xen-devel >>> On 14.06.17 at 18:53, <dario.faggioli@citrix.com> wrote: > --- a/xen/arch/x86/domain.c > +++ b/xen/arch/x86/domain.c > @@ -112,12 +112,18 @@ static void play_dead(void) > > static void idle_loop(void) > { > + unsigned int cpu = smp_processor_id(); > + > for ( ; ; ) > { > - if ( cpu_is_offline(smp_processor_id()) ) > + if ( cpu_is_offline(cpu) ) > play_dead(); > - (*pm_idle)(); > - do_tasklet(); > + > + /* Are we here for running vcpu context tasklets, or for idling? */ > + if ( unlikely(tasklet_work_to_do(cpu)) ) I'm not really sure about the "unlikely()" here. > + do_tasklet(cpu); > + else > + (*pm_idle)(); Please take the opportunity and drop the pointless parentheses and indirection. > --- a/xen/common/tasklet.c > +++ b/xen/common/tasklet.c > @@ -104,19 +104,11 @@ static void do_tasklet_work(unsigned int cpu, struct list_head *list) > } > > /* VCPU context work */ > -void do_tasklet(void) > +void do_tasklet(unsigned int cpu) > { > - unsigned int cpu = smp_processor_id(); I'm not convinced it is a good idea to have the caller pass in the CPU number. In any event, if you do it this way, we will want an ASSERT() to replace the initialization above. > unsigned long *work_to_do = &per_cpu(tasklet_work_to_do, cpu); > struct list_head *list = &per_cpu(tasklet_list, cpu); > > - /* > - * Work must be enqueued *and* scheduled. Otherwise there is no work to > - * do, and/or scheduler needs to run to update idle vcpu priority. > - */ > - if ( likely(*work_to_do != (TASKLET_enqueued|TASKLET_scheduled)) ) > - return; Perhaps it also wouldn't hurt to convert this to an ASSERT() too. > --- a/xen/include/xen/tasklet.h > +++ b/xen/include/xen/tasklet.h > @@ -40,9 +40,19 @@ DECLARE_PER_CPU(unsigned long, tasklet_work_to_do); > #define TASKLET_enqueued (1ul << _TASKLET_enqueued) > #define TASKLET_scheduled (1ul << _TASKLET_scheduled) > > +static inline bool tasklet_work_to_do(unsigned int cpu) > +{ > + /* > + * Work must be enqueued *and* scheduled. Otherwise there is no work to > + * do, and/or scheduler needs to run to update idle vcpu priority. > + */ > + return per_cpu(tasklet_work_to_do, cpu) == (TASKLET_enqueued| > + TASKLET_scheduled); > +} Wouldn't cpu_is_haltable() then also better use this new function? Jan _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-16 8:54 ` Jan Beulich @ 2017-06-16 10:44 ` Dario Faggioli 2017-06-16 11:47 ` Jan Beulich 2017-06-16 17:41 ` Stefano Stabellini 0 siblings, 2 replies; 9+ messages in thread From: Dario Faggioli @ 2017-06-16 10:44 UTC (permalink / raw) To: Jan Beulich Cc: Andrew Cooper, Julien Grall, Stefano Stabellini, Boris Ostrovsky, xen-devel [-- Attachment #1.1: Type: text/plain, Size: 7253 bytes --] On Fri, 2017-06-16 at 02:54 -0600, Jan Beulich wrote: > > > > On 14.06.17 at 18:53, <dario.faggioli@citrix.com> wrote: > > > > --- a/xen/arch/x86/domain.c > > +++ b/xen/arch/x86/domain.c > > @@ -112,12 +112,18 @@ static void play_dead(void) > > > > static void idle_loop(void) > > { > > + unsigned int cpu = smp_processor_id(); > > + > > for ( ; ; ) > > { > > - if ( cpu_is_offline(smp_processor_id()) ) > > + if ( cpu_is_offline(cpu) ) > > play_dead(); > > - (*pm_idle)(); > > - do_tasklet(); > > + > > + /* Are we here for running vcpu context tasklets, or for > > idling? */ > > + if ( unlikely(tasklet_work_to_do(cpu)) ) > > I'm not really sure about the "unlikely()" here. > It's basically already there, without this patch, at the very beginning of do_tasklet(): if ( likely(*work_to_do != (TASKLET_enqueued|TASKLET_scheduled)) ) return; Which is right the check that I moved in tasklet_work_to_do(), and as you can see, it has the likely. So, I fundamentally kept it for consistency with old code. I actually think it does make sense, but I don't have a too strong opinion about this. > > + do_tasklet(cpu); > > + else > > + (*pm_idle)(); > > Please take the opportunity and drop the pointless parentheses > and indirection. > Ok. > > --- a/xen/common/tasklet.c > > +++ b/xen/common/tasklet.c > > @@ -104,19 +104,11 @@ static void do_tasklet_work(unsigned int cpu, > > struct list_head *list) > > } > > > > /* VCPU context work */ > > -void do_tasklet(void) > > +void do_tasklet(unsigned int cpu) > > { > > - unsigned int cpu = smp_processor_id(); > > I'm not convinced it is a good idea to have the caller pass in the > CPU > number. > Yes, I know. I couldn't make up my mind about it either. I guess I get get rid of this aspect of the patch. > > unsigned long *work_to_do = &per_cpu(tasklet_work_to_do, cpu); > > struct list_head *list = &per_cpu(tasklet_list, cpu); > > > > - /* > > - * Work must be enqueued *and* scheduled. Otherwise there is > > no work to > > - * do, and/or scheduler needs to run to update idle vcpu > > priority. > > - */ > > - if ( likely(*work_to_do != > > (TASKLET_enqueued|TASKLET_scheduled)) ) > > - return; > > Perhaps it also wouldn't hurt to convert this to an ASSERT() too. > Nope, I can't. It's a best effort check, and *work_to_do (which is per_cpu(tasklet_work_to_do,cpu)) can change, and the assert may fail. The code is, of course, safe, because, if we think that there's work but there's not, the list of pending tasklets will be empty (and we check that after taking the tasklet lock). > > --- a/xen/include/xen/tasklet.h > > +++ b/xen/include/xen/tasklet.h > > @@ -40,9 +40,19 @@ DECLARE_PER_CPU(unsigned long, > > tasklet_work_to_do); > > #define TASKLET_enqueued (1ul << _TASKLET_enqueued) > > #define TASKLET_scheduled (1ul << _TASKLET_scheduled) > > > > +static inline bool tasklet_work_to_do(unsigned int cpu) > > +{ > > + /* > > + * Work must be enqueued *and* scheduled. Otherwise there is > > no work to > > + * do, and/or scheduler needs to run to update idle vcpu > > priority. > > + */ > > + return per_cpu(tasklet_work_to_do, cpu) == (TASKLET_enqueued| > > + TASKLET_scheduled) > > ; > > +} > > Wouldn't cpu_is_haltable() then also better use this new function? > Mmm... Perhaps. It's certainly less code chrun. ARM code would then contain two invocations of cpu_is_haltable() (the first happens with IRQ enabled, so a second one with IRQ disabled is necessary). But that is *exactly* the same thing we do on x86 (they're just in different functions in that case). So, I reworked the patch according to these suggestions, and you can look at it below. If you like it better, I'm ok re-submitting it properly in this shape. Other thoughts anyone else? Thanks and Regards, Dario --- NOTE that, since we call do_tasklet() after having checked cpu_is_haltable(), the if in there is not likely any longer. --- diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 76310ed..86cd612 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -41,20 +41,28 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu); void idle_loop(void) { + unsigned int cpu = smp_processor_id(); + for ( ; ; ) { - if ( cpu_is_offline(smp_processor_id()) ) + if ( cpu_is_offline(cpu) ) stop_cpu(); - local_irq_disable(); - if ( cpu_is_haltable(smp_processor_id()) ) + /* Are we here for running vcpu context tasklets, or for idling? */ + if ( cpu_is_haltable(cpu) ) { - dsb(sy); - wfi(); + local_irq_disable(); + /* We need to check again, with IRQ disabled */ + if ( cpu_is_haltable(cpu) ) + { + dsb(sy); + wfi(); + } + local_irq_enable(); } - local_irq_enable(); + else + do_tasklet(); - do_tasklet(); do_softirq(); /* * We MUST be last (or before dsb, wfi). Otherwise after we get the diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 49388f4..c520fdd 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -112,12 +112,18 @@ static void play_dead(void) static void idle_loop(void) { + unsigned int cpu = smp_processor_id(); + for ( ; ; ) { - if ( cpu_is_offline(smp_processor_id()) ) + if ( cpu_is_offline(cpu) ) play_dead(); - (*pm_idle)(); - do_tasklet(); + + /* Are we here for idling, or for running vcpu context tasklets? */ + if ( cpu_is_haltable(cpu) ) + pm_idle(); + else + do_tasklet(); do_softirq(); /* * We MUST be last (or before pm_idle). Otherwise after we get the diff --git a/xen/common/tasklet.c b/xen/common/tasklet.c index 365a777..ebdce12 100644 --- a/xen/common/tasklet.c +++ b/xen/common/tasklet.c @@ -114,7 +114,7 @@ void do_tasklet(void) * Work must be enqueued *and* scheduled. Otherwise there is no work to * do, and/or scheduler needs to run to update idle vcpu priority. */ - if ( likely(*work_to_do != (TASKLET_enqueued|TASKLET_scheduled)) ) + if ( *work_to_do != (TASKLET_enqueued|TASKLET_scheduled) ) return; spin_lock_irq(&tasklet_lock); -- <<This happens because I choose it to happen!>> (Raistlin Majere) ----------------------------------------------------------------- Dario Faggioli, Ph.D, http://about.me/dario.faggioli Senior Software Engineer, Citrix Systems R&D Ltd., Cambridge (UK) [-- Attachment #1.2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 819 bytes --] [-- Attachment #2: Type: text/plain, Size: 127 bytes --] _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-16 10:44 ` Dario Faggioli @ 2017-06-16 11:47 ` Jan Beulich 2017-06-16 13:34 ` Dario Faggioli 2017-06-16 17:41 ` Stefano Stabellini 1 sibling, 1 reply; 9+ messages in thread From: Jan Beulich @ 2017-06-16 11:47 UTC (permalink / raw) To: Dario Faggioli Cc: Andrew Cooper, Julien Grall, Stefano Stabellini, BorisOstrovsky, xen-devel >>> On 16.06.17 at 12:44, <dario.faggioli@citrix.com> wrote: > On Fri, 2017-06-16 at 02:54 -0600, Jan Beulich wrote: >> > > > On 14.06.17 at 18:53, <dario.faggioli@citrix.com> wrote: >> > >> > --- a/xen/arch/x86/domain.c >> > +++ b/xen/arch/x86/domain.c >> > @@ -112,12 +112,18 @@ static void play_dead(void) >> > >> > static void idle_loop(void) >> > { >> > + unsigned int cpu = smp_processor_id(); >> > + >> > for ( ; ; ) >> > { >> > - if ( cpu_is_offline(smp_processor_id()) ) >> > + if ( cpu_is_offline(cpu) ) >> > play_dead(); >> > - (*pm_idle)(); >> > - do_tasklet(); >> > + >> > + /* Are we here for running vcpu context tasklets, or for >> > idling? */ >> > + if ( unlikely(tasklet_work_to_do(cpu)) ) >> >> I'm not really sure about the "unlikely()" here. >> > It's basically already there, without this patch, at the very beginning > of do_tasklet(): > > if ( likely(*work_to_do != (TASKLET_enqueued|TASKLET_scheduled)) ) > return; > > Which is right the check that I moved in tasklet_work_to_do(), and as > you can see, it has the likely. > > So, I fundamentally kept it for consistency with old code. I actually > think it does make sense, but I don't have a too strong opinion about > this. Okay then. >> > unsigned long *work_to_do = &per_cpu(tasklet_work_to_do, cpu); >> > struct list_head *list = &per_cpu(tasklet_list, cpu); >> > >> > - /* >> > - * Work must be enqueued *and* scheduled. Otherwise there is >> > no work to >> > - * do, and/or scheduler needs to run to update idle vcpu >> > priority. >> > - */ >> > - if ( likely(*work_to_do != >> > (TASKLET_enqueued|TASKLET_scheduled)) ) >> > - return; >> >> Perhaps it also wouldn't hurt to convert this to an ASSERT() too. >> > Nope, I can't. It's a best effort check, and *work_to_do (which is > per_cpu(tasklet_work_to_do,cpu)) can change, and the assert may fail. How that? TASKLET_enqueued can only be cleared by do_tasklet() itself, and I don't think nesting invocations of the function can or should occur. TASKLET_scheduled is only being cleared when schedule() observes that bit set without TASKLET_enqueued also set. IOW there may be races in setting of the bits, but since we expect the caller to have done this check already, I think an ASSERT() would be quite fine here. >> > --- a/xen/include/xen/tasklet.h >> > +++ b/xen/include/xen/tasklet.h >> > @@ -40,9 +40,19 @@ DECLARE_PER_CPU(unsigned long, >> > tasklet_work_to_do); >> > #define TASKLET_enqueued (1ul << _TASKLET_enqueued) >> > #define TASKLET_scheduled (1ul << _TASKLET_scheduled) >> > >> > +static inline bool tasklet_work_to_do(unsigned int cpu) >> > +{ >> > + /* >> > + * Work must be enqueued *and* scheduled. Otherwise there is >> > no work to >> > + * do, and/or scheduler needs to run to update idle vcpu >> > priority. >> > + */ >> > + return per_cpu(tasklet_work_to_do, cpu) == (TASKLET_enqueued| >> > + TASKLET_scheduled) >> > ; >> > +} >> >> Wouldn't cpu_is_haltable() then also better use this new function? >> > Mmm... Perhaps. It's certainly less code chrun. > > ARM code would then contain two invocations of cpu_is_haltable() (the > first happens with IRQ enabled, so a second one with IRQ disabled is > necessary). But that is *exactly* the same thing we do on x86 (they're > just in different functions in that case). > > So, I reworked the patch according to these suggestions, and you can > look at it below. I'm confused: You've added further uses of cpu_is_haltable() where the cheaper tasklet_work_to_do() would do. That's sort of the opposite of what I've suggested. Of course that suggestion of mine was more than 1:1 replacement - the implied question was whether cpu_is_haltable() simply checking tasklet_work_to_do to be non-zero isn't too lax (and wouldn't better be !tasklet_work_to_do()). Jan _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-16 11:47 ` Jan Beulich @ 2017-06-16 13:34 ` Dario Faggioli 2017-06-16 14:09 ` Jan Beulich 0 siblings, 1 reply; 9+ messages in thread From: Dario Faggioli @ 2017-06-16 13:34 UTC (permalink / raw) To: Jan Beulich Cc: Andrew Cooper, Julien Grall, Stefano Stabellini, BorisOstrovsky, xen-devel [-- Attachment #1.1: Type: text/plain, Size: 5245 bytes --] On Fri, 2017-06-16 at 05:47 -0600, Jan Beulich wrote: > > On Fri, 2017-06-16 at 02:54 -0600, Jan Beulich wrote: > > > > > > On 14.06.17 at 18:53, <dario.faggioli@citrix.com> wrote: > > > > unsigned long *work_to_do = &per_cpu(tasklet_work_to_do, > > > > cpu); > > > > struct list_head *list = &per_cpu(tasklet_list, cpu); > > > > > > > > - /* > > > > - * Work must be enqueued *and* scheduled. Otherwise there > > > > is > > > > no work to > > > > - * do, and/or scheduler needs to run to update idle vcpu > > > > priority. > > > > - */ > > > > - if ( likely(*work_to_do != > > > > (TASKLET_enqueued|TASKLET_scheduled)) ) > > > > - return; > > > > > > Perhaps it also wouldn't hurt to convert this to an ASSERT() too. > > > > > > > Nope, I can't. It's a best effort check, and *work_to_do (which is > > per_cpu(tasklet_work_to_do,cpu)) can change, and the assert may > > fail. > > How that? TASKLET_enqueued can only be cleared by do_tasklet() > itself, and I don't think nesting invocations of the function can or > should occur. TASKLET_scheduled is only being cleared when > schedule() observes that bit set without TASKLET_enqueued also > set. IOW there may be races in setting of the bits, but since we > expect the caller to have done this check already, I think an > ASSERT() would be quite fine here. > Ok, makes sense. I will add the ASSERT() (with something like what you wrote here as a comment). > > > Wouldn't cpu_is_haltable() then also better use this new > > > function? > > > > > > > Mmm... Perhaps. It's certainly less code chrun. > > > > ARM code would then contain two invocations of cpu_is_haltable() > > (the > > first happens with IRQ enabled, so a second one with IRQ disabled > > is > > necessary). But that is *exactly* the same thing we do on x86 > > (they're > > just in different functions in that case). > > > > So, I reworked the patch according to these suggestions, and you > > can > > look at it below. > > I'm confused: You've added further uses of cpu_is_haltable() > where the cheaper tasklet_work_to_do() would do. > Indeed. Sorry! Fact is, I've read your comment backwards, i.e., as you were saying something like "wouldn't cpu_is_haltable() better be used here, instead of this new function?" And it's not that your wording is ambiguous, it's me that, apparently, can't read English! :-/ I'll rework the patch again... > Of course that suggestion > of mine was more than 1:1 replacement - the implied question was > whether cpu_is_haltable() simply checking tasklet_work_to_do to > be non-zero isn't too lax (and wouldn't better be > !tasklet_work_to_do()). > Now, to try to answer the real question... Let's assume that, on cpu x, we are about to check cpu_is_haltable(), while, on cpu y, tasklet_schedule_on_cpu(x) is being called, and manages to set _TASKLET_enqueued in *work_to_do. I.e., in current code: CPU x CPU y | | cpu_is_haltable(x) tasklet_schedule_on_cpu(x) |!softirq_pending(x) == true tasklet_enqueue() |cpu_online(x) == true test_and_set(TASKLET_enqueued, | work_to_do) |!work_to_do == FALSE So we don't go to sleep, and we stay in the idle loop for the next iteration. At which point, CPU y will have raised SCHEDULE_SOFTIRQ on x, schedule (still on x) will set TASKLET_scheduled, and we'll call do_tasklet(). Basically, right now, we risk spinning for the time that passes between TASKLET_enqueued being set and SCHEDULE_SOFTIRQ being raised and reaching cpu x. This should be a very short window, and, considering how the TASKLET_* flags are handled, this looks the correct behavior to me. If we use !tasklet_work_to_do() in cpu_is_haltable(): CPU x CPU y | | cpu_is_haltable(x) tasklet_schedule_on_cpu(x) |!softirq_pending(x) == true tasklet_enqueue() |cpu_online(x) == true test_and_set(TASKLET_enqueued, | work_to_do) |!(work_to_do == TASKLET_enqueued+ TASKLET_scheduled) == TRUE Which means we'd go to sleep... just for (most likely) be woken up very very soon by SCHEDULE_SOFTIRQ being thrown at us (cpu x) by cpu y. Am I overlooking anything? And is this (this time) what you were asking? Assuming answers are 'no' and 'yes', I think I'd leave cpu_is_haltable() as it is (perhaps adding a brief comment on why it's ok/better to check work_to_do directly, instead than calling tasklet_work_to_do()). Sorry again for the misunderstanding, Dario -- <<This happens because I choose it to happen!>> (Raistlin Majere) ----------------------------------------------------------------- Dario Faggioli, Ph.D, http://about.me/dario.faggioli Senior Software Engineer, Citrix Systems R&D Ltd., Cambridge (UK) [-- Attachment #1.2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 819 bytes --] [-- Attachment #2: Type: text/plain, Size: 127 bytes --] _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-16 13:34 ` Dario Faggioli @ 2017-06-16 14:09 ` Jan Beulich 0 siblings, 0 replies; 9+ messages in thread From: Jan Beulich @ 2017-06-16 14:09 UTC (permalink / raw) To: Dario Faggioli Cc: Andrew Cooper, Julien Grall, Stefano Stabellini, BorisOstrovsky, xen-devel >>> On 16.06.17 at 15:34, <dario.faggioli@citrix.com> wrote: > Assuming answers are 'no' and 'yes', I think I'd leave > cpu_is_haltable() as it is Agreed, you analysis was quite helpful. Jan _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-16 10:44 ` Dario Faggioli 2017-06-16 11:47 ` Jan Beulich @ 2017-06-16 17:41 ` Stefano Stabellini 2017-06-16 20:06 ` Dario Faggioli 1 sibling, 1 reply; 9+ messages in thread From: Stefano Stabellini @ 2017-06-16 17:41 UTC (permalink / raw) To: Dario Faggioli Cc: Stefano Stabellini, Andrew Cooper, Julien Grall, Jan Beulich, xen-devel, Boris Ostrovsky [-- Attachment #1: Type: TEXT/PLAIN, Size: 5882 bytes --] On Fri, 16 Jun 2017, Dario Faggioli wrote: > On Fri, 2017-06-16 at 02:54 -0600, Jan Beulich wrote: > > > > > On 14.06.17 at 18:53, <dario.faggioli@citrix.com> wrote: > > > > > > --- a/xen/arch/x86/domain.c > > > +++ b/xen/arch/x86/domain.c > > > @@ -112,12 +112,18 @@ static void play_dead(void) > > > > > > static void idle_loop(void) > > > { > > > + unsigned int cpu = smp_processor_id(); > > > + > > > for ( ; ; ) > > > { > > > - if ( cpu_is_offline(smp_processor_id()) ) > > > + if ( cpu_is_offline(cpu) ) > > > play_dead(); > > > - (*pm_idle)(); > > > - do_tasklet(); > > > + > > > + /* Are we here for running vcpu context tasklets, or for > > > idling? */ > > > + if ( unlikely(tasklet_work_to_do(cpu)) ) > > > > I'm not really sure about the "unlikely()" here. > > > It's basically already there, without this patch, at the very beginning > of do_tasklet(): > > if ( likely(*work_to_do != (TASKLET_enqueued|TASKLET_scheduled)) ) > return; > > Which is right the check that I moved in tasklet_work_to_do(), and as > you can see, it has the likely. > > So, I fundamentally kept it for consistency with old code. I actually > think it does make sense, but I don't have a too strong opinion about > this. > > > > + do_tasklet(cpu); > > > + else > > > + (*pm_idle)(); > > > > Please take the opportunity and drop the pointless parentheses > > and indirection. > > > Ok. > > > > --- a/xen/common/tasklet.c > > > +++ b/xen/common/tasklet.c > > > @@ -104,19 +104,11 @@ static void do_tasklet_work(unsigned int cpu, > > > struct list_head *list) > > > } > > > > > > /* VCPU context work */ > > > -void do_tasklet(void) > > > +void do_tasklet(unsigned int cpu) > > > { > > > - unsigned int cpu = smp_processor_id(); > > > > I'm not convinced it is a good idea to have the caller pass in the > > CPU > > number. > > > Yes, I know. I couldn't make up my mind about it either. I guess I get > get rid of this aspect of the patch. > > > > unsigned long *work_to_do = &per_cpu(tasklet_work_to_do, cpu); > > > struct list_head *list = &per_cpu(tasklet_list, cpu); > > > > > > - /* > > > - * Work must be enqueued *and* scheduled. Otherwise there is > > > no work to > > > - * do, and/or scheduler needs to run to update idle vcpu > > > priority. > > > - */ > > > - if ( likely(*work_to_do != > > > (TASKLET_enqueued|TASKLET_scheduled)) ) > > > - return; > > > > Perhaps it also wouldn't hurt to convert this to an ASSERT() too. > > > Nope, I can't. It's a best effort check, and *work_to_do (which is > per_cpu(tasklet_work_to_do,cpu)) can change, and the assert may fail. > > The code is, of course, safe, because, if we think that there's work > but there's not, the list of pending tasklets will be empty (and we > check that after taking the tasklet lock). > > > > --- a/xen/include/xen/tasklet.h > > > +++ b/xen/include/xen/tasklet.h > > > @@ -40,9 +40,19 @@ DECLARE_PER_CPU(unsigned long, > > > tasklet_work_to_do); > > > #define TASKLET_enqueued (1ul << _TASKLET_enqueued) > > > #define TASKLET_scheduled (1ul << _TASKLET_scheduled) > > > > > > +static inline bool tasklet_work_to_do(unsigned int cpu) > > > +{ > > > + /* > > > + * Work must be enqueued *and* scheduled. Otherwise there is > > > no work to > > > + * do, and/or scheduler needs to run to update idle vcpu > > > priority. > > > + */ > > > + return per_cpu(tasklet_work_to_do, cpu) == (TASKLET_enqueued| > > > + TASKLET_scheduled) > > > ; > > > +} > > > > Wouldn't cpu_is_haltable() then also better use this new function? > > > Mmm... Perhaps. It's certainly less code chrun. > > ARM code would then contain two invocations of cpu_is_haltable() (the > first happens with IRQ enabled, so a second one with IRQ disabled is > necessary). But that is *exactly* the same thing we do on x86 (they're > just in different functions in that case). > > So, I reworked the patch according to these suggestions, and you can > look at it below. > > If you like it better, I'm ok re-submitting it properly in this shape. > Other thoughts anyone else? > > Thanks and Regards, > Dario > --- > NOTE that, since we call do_tasklet() after having checked > cpu_is_haltable(), the if in there is not likely any longer. > --- > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c > index 76310ed..86cd612 100644 > --- a/xen/arch/arm/domain.c > +++ b/xen/arch/arm/domain.c > @@ -41,20 +41,28 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu); > > void idle_loop(void) > { > + unsigned int cpu = smp_processor_id(); > + > for ( ; ; ) > { > - if ( cpu_is_offline(smp_processor_id()) ) > + if ( cpu_is_offline(cpu) ) > stop_cpu(); > > - local_irq_disable(); > - if ( cpu_is_haltable(smp_processor_id()) ) > + /* Are we here for running vcpu context tasklets, or for idling? */ > + if ( cpu_is_haltable(cpu) ) > { > - dsb(sy); > - wfi(); > + local_irq_disable(); > + /* We need to check again, with IRQ disabled */ > + if ( cpu_is_haltable(cpu) ) > + { > + dsb(sy); > + wfi(); > + } > + local_irq_enable(); > } > - local_irq_enable(); > + else > + do_tasklet(); > > - do_tasklet(); > do_softirq(); Are you sure you want to check that cpu_is_haltable twice? It doesn't make sense to me. [-- Attachment #2: Type: text/plain, Size: 127 bytes --] _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] xen: idle_loop: either deal with tasklets or go idle 2017-06-16 17:41 ` Stefano Stabellini @ 2017-06-16 20:06 ` Dario Faggioli 0 siblings, 0 replies; 9+ messages in thread From: Dario Faggioli @ 2017-06-16 20:06 UTC (permalink / raw) To: Stefano Stabellini Cc: Andrew Cooper, Julien Grall, Boris Ostrovsky, Jan Beulich, xen-devel [-- Attachment #1.1: Type: text/plain, Size: 2180 bytes --] On Fri, 2017-06-16 at 10:41 -0700, Stefano Stabellini wrote: > On Fri, 16 Jun 2017, Dario Faggioli wrote: > > > > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c > > index 76310ed..86cd612 100644 > > --- a/xen/arch/arm/domain.c > > +++ b/xen/arch/arm/domain.c > > @@ -41,20 +41,28 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu); > > > > void idle_loop(void) > > { > > + unsigned int cpu = smp_processor_id(); > > + > > for ( ; ; ) > > { > > - if ( cpu_is_offline(smp_processor_id()) ) > > + if ( cpu_is_offline(cpu) ) > > stop_cpu(); > > > > - local_irq_disable(); > > - if ( cpu_is_haltable(smp_processor_id()) ) > > + /* Are we here for running vcpu context tasklets, or for > > idling? */ > > + if ( cpu_is_haltable(cpu) ) > > { > > - dsb(sy); > > - wfi(); > > + local_irq_disable(); > > + /* We need to check again, with IRQ disabled */ > > + if ( cpu_is_haltable(cpu) ) > > + { > > + dsb(sy); > > + wfi(); > > + } > > + local_irq_enable(); > > } > > - local_irq_enable(); > > + else > > + do_tasklet(); > > > > - do_tasklet(); > > do_softirq(); > > Are you sure you want to check that cpu_is_haltable twice? It doesn't > make sense to me. > It's because of IRQ being disabled the first time. But anyway, discard this patch. I'll go back to (a slightly modified version of) the first one I sent, which defines a tasklet specific helper function. I'll send it on Monday. Regards, Dario -- <<This happens because I choose it to happen!>> (Raistlin Majere) ----------------------------------------------------------------- Dario Faggioli, Ph.D, http://about.me/dario.faggioli Senior Software Engineer, Citrix Systems R&D Ltd., Cambridge (UK) [-- Attachment #1.2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 819 bytes --] [-- Attachment #2: Type: text/plain, Size: 127 bytes --] _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2017-06-16 20:06 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-06-14 16:53 [PATCH] xen: idle_loop: either deal with tasklets or go idle Dario Faggioli 2017-06-14 16:53 ` Dario Faggioli 2017-06-16 8:54 ` Jan Beulich 2017-06-16 10:44 ` Dario Faggioli 2017-06-16 11:47 ` Jan Beulich 2017-06-16 13:34 ` Dario Faggioli 2017-06-16 14:09 ` Jan Beulich 2017-06-16 17:41 ` Stefano Stabellini 2017-06-16 20:06 ` Dario Faggioli
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.