|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 5/5] xen: RCU: avoid busy waiting until the end of grace period.
On Thu, 27 Jul 2017, Dario Faggioli wrote:
> Instead of having the CPU where a callback is queued, busy
> looping on rcu_pending(), use a timer.
>
> In fact, we let the CPU go idla,e but we program a timer
^ idle,
> that will periodically wake it up, for checking whether the
> grace period has actually ended.
>
> It is kind of similar to introducing a periodic tick, but
> with a much more limited scope, and a lot less overhead. In
> fact, this timer is:
> - only active for the CPU(s) that have callbacks queued,
> waiting for the end of a grace period;
> - only active when those CPU(s) are idle (and stopped as
> soon as they resume execution).
>
> Signed-off-by: Dario Faggioli <dario.faggioli@xxxxxxxxxx>
> ---
> Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
> Cc: Julien Grall <julien.grall@xxxxxxx>
> Cc: Jan Beulich <jbeulich@xxxxxxxx>
> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> ---
> xen/arch/arm/domain.c | 4 ++-
> xen/arch/x86/acpi/cpu_idle.c | 6 +++--
> xen/arch/x86/cpu/mwait-idle.c | 6 +++--
> xen/common/rcupdate.c | 52
> ++++++++++++++++++++++++++++++++++++++++-
> xen/include/xen/rcupdate.h | 3 ++
> 5 files changed, 65 insertions(+), 6 deletions(-)
>
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 666b7ef..01da96e 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -43,8 +43,9 @@ static void do_idle(void)
> {
> unsigned int cpu = smp_processor_id();
>
> + rcu_idle_timer_start();
> sched_tick_suspend();
> - /* sched_tick_suspend() can raise TIMER_SOFTIRQ. Process it now. */
> + /* Timer related operations can raise TIMER_SOFTIRQ. Process it now. */
> process_pending_softirqs();
>
> local_irq_disable();
> @@ -58,6 +59,7 @@ static void do_idle(void)
> local_irq_enable();
>
> sched_tick_resume();
> + rcu_idle_timer_stop();
> }
>
> void idle_loop(void)
> diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c
> index 04c52e8..b97986f 100644
> --- a/xen/arch/x86/acpi/cpu_idle.c
> +++ b/xen/arch/x86/acpi/cpu_idle.c
> @@ -576,10 +576,10 @@ static void acpi_processor_idle(void)
> return;
> }
>
> + rcu_idle_timer_start();
> cpufreq_dbs_timer_suspend();
> -
> sched_tick_suspend();
> - /* sched_tick_suspend() can raise TIMER_SOFTIRQ. Process it now. */
> + /* Timer related operations can raise TIMER_SOFTIRQ. Process it now. */
> process_pending_softirqs();
>
> /*
> @@ -593,6 +593,7 @@ static void acpi_processor_idle(void)
> local_irq_enable();
> sched_tick_resume();
> cpufreq_dbs_timer_resume();
> + rcu_idle_timer_stop();
> return;
> }
>
> @@ -726,6 +727,7 @@ static void acpi_processor_idle(void)
>
> sched_tick_resume();
> cpufreq_dbs_timer_resume();
> + rcu_idle_timer_stop();
>
> if ( cpuidle_current_governor->reflect )
> cpuidle_current_governor->reflect(power);
> diff --git a/xen/arch/x86/cpu/mwait-idle.c b/xen/arch/x86/cpu/mwait-idle.c
> index ae9e92b..c426e41 100644
> --- a/xen/arch/x86/cpu/mwait-idle.c
> +++ b/xen/arch/x86/cpu/mwait-idle.c
> @@ -743,10 +743,10 @@ static void mwait_idle(void)
> return;
> }
>
> + rcu_idle_timer_start();
> cpufreq_dbs_timer_suspend();
> -
> sched_tick_suspend();
> - /* sched_tick_suspend() can raise TIMER_SOFTIRQ. Process it now. */
> + /* Timer related operations can raise TIMER_SOFTIRQ. Process it now. */
> process_pending_softirqs();
>
> /* Interrupts must be disabled for C2 and higher transitions. */
> @@ -756,6 +756,7 @@ static void mwait_idle(void)
> local_irq_enable();
> sched_tick_resume();
> cpufreq_dbs_timer_resume();
> + rcu_idle_timer_stop();
> return;
> }
>
> @@ -802,6 +803,7 @@ static void mwait_idle(void)
>
> sched_tick_resume();
> cpufreq_dbs_timer_resume();
> + rcu_idle_timer_stop();
>
> if ( cpuidle_current_governor->reflect )
> cpuidle_current_governor->reflect(power);
> diff --git a/xen/common/rcupdate.c b/xen/common/rcupdate.c
> index f0fdc87..4586f2a 100644
> --- a/xen/common/rcupdate.c
> +++ b/xen/common/rcupdate.c
> @@ -84,8 +84,14 @@ struct rcu_data {
> int cpu;
> struct rcu_head barrier;
> long last_rs_qlen; /* qlen during the last resched */
> +
> + /* 3) idle CPUs handling */
> + struct timer idle_timer;
> + bool idle_timer_active;
> };
>
> +#define RCU_IDLE_TIMER_PERIOD MILLISECS(10)
Isn't this a bit too short? How is it chosen?
> static DEFINE_PER_CPU(struct rcu_data, rcu_data);
>
> static int blimit = 10;
> @@ -402,7 +408,48 @@ int rcu_needs_cpu(int cpu)
> {
> struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
>
> - return (!!rdp->curlist || rcu_pending(cpu));
> + return (!!rdp->curlist || rcu_pending(cpu)) && !rdp->idle_timer_active;
> +}
> +
> +/*
> + * Timer for making sure the CPU where a callback is queued does
> + * periodically poke rcu_pedning(), so that it will invoke the callback
> + * not too late after the end of the grace period.
> + */
> +void rcu_idle_timer_start()
> +{
> + struct rcu_data *rdp = &this_cpu(rcu_data);
> +
> + if (likely(!rdp->curlist))
> + return;
> +
> + set_timer(&rdp->idle_timer, NOW() + RCU_IDLE_TIMER_PERIOD);
> + rdp->idle_timer_active = true;
> +}
> +
> +void rcu_idle_timer_stop()
> +{
> + struct rcu_data *rdp = &this_cpu(rcu_data);
> +
> + if (likely(!rdp->idle_timer_active))
> + return;
> +
> + rdp->idle_timer_active = false;
> + stop_timer(&rdp->idle_timer);
> +}
> +
> +static void rcu_idle_timer_handler(void* data)
> +{
> + /*
> + * Nothing, really... And in fact, we don't expect to ever get in here,
> + * as rcu_idle_timer_stop(), called while waking from idle, prevent that
> + * to happen by stopping the timer before the TIMER_SOFTIRQ handler has
> + * a chance to run.
> + *
> + * But that's fine, because all we want is the CPU that needs to execute
> + * the callback to be periodically woken up and check rcu_pending().
> + */
> + ASSERT_UNREACHABLE();
> }
>
> void rcu_check_callbacks(int cpu)
> @@ -423,6 +470,8 @@ static void rcu_move_batch(struct rcu_data *this_rdp,
> struct rcu_head *list,
> static void rcu_offline_cpu(struct rcu_data *this_rdp,
> struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
> {
> + kill_timer(&rdp->idle_timer);
> +
> /* If the cpu going offline owns the grace period we can block
> * indefinitely waiting for it, so flush it here.
> */
> @@ -451,6 +500,7 @@ static void rcu_init_percpu_data(int cpu, struct
> rcu_ctrlblk *rcp,
> rdp->qs_pending = 0;
> rdp->cpu = cpu;
> rdp->blimit = blimit;
> + init_timer(&rdp->idle_timer, rcu_idle_timer_handler, (void*) rdp, cpu);
> }
>
> static int cpu_callback(
> diff --git a/xen/include/xen/rcupdate.h b/xen/include/xen/rcupdate.h
> index 561ac43..3402eb5 100644
> --- a/xen/include/xen/rcupdate.h
> +++ b/xen/include/xen/rcupdate.h
> @@ -149,4 +149,7 @@ int rcu_barrier(void);
> void rcu_idle_enter(unsigned int cpu);
> void rcu_idle_exit(unsigned int cpu);
>
> +void rcu_idle_timer_start(void);
> +void rcu_idle_timer_stop(void);
> +
> #endif /* __XEN_RCUPDATE_H */
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |