Dynticks updates for 4.11
cover Dynticks updates for 4.11
Hello!
This series provides dynticks updates:
1-4. Abstract access to the dyntick counter, replacing the current
open-coding of atomic operations.
5. Check cond_resched_rcu_qs() state less often to reduce GP overhead.
6. Adjust FQS offline checks for exact online-CPU detection.
Thanx, Paul
------------------------------------------------------------------------
include/linux/rcutiny.h | 6 + include/trace/events/rcu.h | 10 - kernel/rcu/tree.c | 245 +++++++++++++++++++++++++++++++-------------- kernel/rcu/tree.h | 2 kernel/rcu/tree_exp.h | 12 -- kernel/rcu/tree_plugin.h | 2 kernel/rcu/tree_trace.c | 2 7 files changed, 190 insertions(+), 89 deletions(-)
PATCH 1/6 rcu: Abstract the dynticks momentary-idle operation
This commit is the first step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of two in a new rcu_dynticks_momentary_idle() function. This abstraction will ease changes to the ->dynticks counter operation.
--- kernel/rcu/tree.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
kernel/rcu/tree.c +14 -5
@@ -281,6 +281,19 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ }; +/* +* Do a double-increment of the ->dynticks counter to emulate a +* momentary idle-CPU quiescent state. +*/ +static void rcu_dynticks_momentary_idle (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special =atomic_add_return (2 , &rdtp->dynticks); + +/* It is illegal to call this from idle state. */ +WARN_ON_ONCE (!(special &0x1 )); +} + DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, rcu_qs_ctr);EXPORT_PER_CPU_SYMBOL_GPL (rcu_qs_ctr);
@@ -300,7 +313,6 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);static void rcu_momentary_dyntick_idle (void ) {struct rcu_data *rdp; -struct rcu_dynticks *rdtp;int resched_mask;struct rcu_state *rsp;
@@ -327,10 +339,7 @@ static void rcu_momentary_dyntick_idle(void)* quiescent state, with no need for this CPU to do anything * further. */ - rdtp =this_cpu_ptr (&rcu_dynticks); -smp_mb__before_atomic ();/* Earlier stuff before QS. */ -atomic_add (2 , &rdtp->dynticks);/* QS. */ -smp_mb__after_atomic ();/* Later stuff after QS. */ +rcu_dynticks_momentary_idle ();break ; } }
Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 1/6] rcu: Abstract the dynticks momentary-idle operation
Quoted 6 lines · Paul E. McKenney
This commit is the first step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of two in a new
rcu_dynticks_momentary_idle()function. This abstraction will ease changes to the ->dynticks counter operation.Signed-off-by Paul E. McKenney <[email protected]>
This change has an additional effect not documented in the commit
message: it eliminates the smp_mb__before_atomic and smp_mb__after_atomic calls. Can you please document that in the commit message, and explain why that doesn't cause a problem?
Quoted 45 lines
kernel/rcu/tree.c +14
-5@@ -281,6 +281,19 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ }; +/* +* Do a double-increment of the ->dynticks counter to emulate a +* momentary idle-CPU quiescent state. +*/ +static void rcu_dynticks_momentary_idle (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special =atomic_add_return (2 , &rdtp->dynticks); + +/* It is illegal to call this from idle state. */ +WARN_ON_ONCE (!(special &0x1 )); +} + DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, rcu_qs_ctr);EXPORT_PER_CPU_SYMBOL_GPL (rcu_qs_ctr);@@ -300,7 +313,6 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);static void rcu_momentary_dyntick_idle (void ) {struct rcu_data *rdp; -struct rcu_dynticks *rdtp;int resched_mask;struct rcu_state *rsp;@@ -327,10 +339,7 @@ static void rcu_momentary_dyntick_idle(void)* quiescent state, with no need for this CPU to do anything * further. */ - rdtp =this_cpu_ptr (&rcu_dynticks); -smp_mb__before_atomic ();/* Earlier stuff before QS. */ -atomic_add (2 , &rdtp->dynticks);/* QS. */ -smp_mb__after_atomic ();/* Later stuff after QS. */ +rcu_dynticks_momentary_idle ();break ; } }Signature · 1 line
2.5.2
Re: [PATCH tip/core/rcu 1/6] rcu: Abstract the dynticks momentary-idle operation
Quoted 6 lines · Josh Triplett
Quoted 5 lines · Paul E. McKenney
This commit is the first step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of two in a new
rcu_dynticks_momentary_idle()function. This abstraction will ease changes to the ->dynticks counter operation.
Quoted 6 lines
Quoted 1 line
Signed-off-by Paul E. McKenney <[email protected]>This change has an additional effect not documented in the commit
message: it eliminates thesmp_mb__before_atomicandsmp_mb__after_atomiccalls. Can you please document that in the commit message, and explain why that doesn't cause a problem?
The trick is that the old code used the non-value-returning atomic_add(), which does not imply ordering, hence the smp_mb__before_atomic() and smp_mb__after_atomic() calls. The new code uses atomic_add_return(), which does return a value, and therefore implies full ordering in and of itself.
How would you like me to proceed?
Thanx, Paul
Quoted 46 lines
Quoted 45 lines
kernel/rcu/tree.c +14
-5@@ -281,6 +281,19 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ }; +/* +* Do a double-increment of the ->dynticks counter to emulate a +* momentary idle-CPU quiescent state. +*/ +static void rcu_dynticks_momentary_idle (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special =atomic_add_return (2 , &rdtp->dynticks); + +/* It is illegal to call this from idle state. */ +WARN_ON_ONCE (!(special &0x1 )); +} + DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, rcu_qs_ctr);EXPORT_PER_CPU_SYMBOL_GPL (rcu_qs_ctr);@@ -300,7 +313,6 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);static void rcu_momentary_dyntick_idle (void ) {struct rcu_data *rdp; -struct rcu_dynticks *rdtp;int resched_mask;struct rcu_state *rsp;@@ -327,10 +339,7 @@ static void rcu_momentary_dyntick_idle(void)* quiescent state, with no need for this CPU to do anything * further. */ - rdtp =this_cpu_ptr (&rcu_dynticks); -smp_mb__before_atomic ();/* Earlier stuff before QS. */ -atomic_add (2 , &rdtp->dynticks);/* QS. */ -smp_mb__after_atomic ();/* Later stuff after QS. */ +rcu_dynticks_momentary_idle ();break ; } }Signature · 1 line
2.5.2
Re: [PATCH tip/core/rcu 1/6] rcu: Abstract the dynticks momentary-idle operation
Quoted 14 lines · Paul E. McKenney
Quoted 6 lines · Josh Triplett
Quoted 5 lines · Paul E. McKenney
This commit is the first step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of two in a new
rcu_dynticks_momentary_idle()function. This abstraction will ease changes to the ->dynticks counter operation.Quoted 6 lines
Quoted 1 line
Signed-off-by Paul E. McKenney <[email protected]>This change has an additional effect not documented in the commit
message: it eliminates thesmp_mb__before_atomicandsmp_mb__after_atomiccalls. Can you please document that in the commit message, and explain why that doesn't cause a problem?
Quoted 7 lines
The trick is that the old code used the non-value-returning
atomic_add(), which does not imply ordering, hence thesmp_mb__before_atomic()andsmp_mb__after_atomic()calls. The new code usesatomic_add_return(), which does return a value, and therefore implies full ordering in and of itself.How would you like me to proceed?
With the above explanation added to the commit message:
Re: [PATCH tip/core/rcu 1/6] rcu: Abstract the dynticks momentary-idle operation
Quoted 21 lines · Josh Triplett
Quoted 20 lines · Paul E. McKenney
Quoted 6 lines · Josh Triplett
Quoted 5 lines · Paul E. McKenney
This commit is the first step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of two in a new
rcu_dynticks_momentary_idle()function. This abstraction will ease changes to the ->dynticks counter operation.Quoted 6 lines
Quoted 1 line
Signed-off-by Paul E. McKenney <[email protected]>This change has an additional effect not documented in the commit
message: it eliminates thesmp_mb__before_atomicandsmp_mb__after_atomiccalls. Can you please document that in the commit message, and explain why that doesn't cause a problem?The trick is that the old code used the non-value-returning
atomic_add(), which does not imply ordering, hence thesmp_mb__before_atomic()andsmp_mb__after_atomic()calls. The new code usesatomic_add_return(), which does return a value, and therefore implies full ordering in and of itself.
Quoted 5 lines
Quoted 1 line
How would you like me to proceed?
With the above explanation added to the commit message:
Reviewed-by Josh Triplett <[email protected]>
Done, thank you!
Thanx, Paul
PATCH 2/6 rcu: Abstract the dynticks snapshot operation
In reply to Paul E. McKenneyThis commit is the second step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of zero in a new rcu_dynticks_snap() function. This abstraction will ease changes o the ->dynticks counter operation.
--- kernel/rcu/tree.c | 19 ++++++++++++++++--- kernel/rcu/tree_exp.h | 6 ++---- 2 files changed, 18 insertions(+), 7 deletions(-)
kernel/rcu/tree.c +16 -3
@@ -282,6 +282,17 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Snapshot the ->dynticks counter with full ordering so as to allow +* stable comparison of this counter with past and future snapshots. +*/ +static int rcu_dynticks_snap (struct rcu_dynticks *rdtp) +{ +int snap =atomic_add_return (0 , &rdtp->dynticks); + +return snap; +} + +/* * Do a double-increment of the ->dynticks counter to emulate a * momentary idle-CPU quiescent state. */
@@ -1049,7 +1060,9 @@ void rcu_nmi_exit(void)*/ bool notrace __rcu_is_watching(void) { -return atomic_read (this_cpu_ptr (&rcu_dynticks.dynticks)) &0x1 ; +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +return atomic_read (&rdtp->dynticks) &0x1 ; }/**
@@ -1132,7 +1145,7 @@ static int rcu_is_cpu_rrupt_from_idle(void)static int dyntick_save_progress_counter (struct rcu_data *rdp,bool *isidle,unsigned long *maxj) { - rdp->dynticks_snap =atomic_add_return (0 , &rdp->dynticks->dynticks); + rdp->dynticks_snap =rcu_dynticks_snap (rdp->dynticks);rcu_sysidle_check_cpu (rdp, isidle, maxj);if ((rdp->dynticks_snap &0x1 ) ==0 ) {trace_rcu_fqs (rdp->rsp->name, rdp->gpnum, rdp->cpu,TPS ("dti" ));
@@ -1157,7 +1170,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,int *rcrmp;unsigned int snap; - curr = (unsigned int )atomic_add_return (0 , &rdp->dynticks->dynticks); + curr = (unsigned int )rcu_dynticks_snap (rdp->dynticks); snap = (unsigned int )rdp->dynticks_snap;/*
kernel/rcu/tree_exp.h +2 -4
@@ -356,10 +356,9 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, mask_ofl_test =0 ;for_each_leaf_node_possible_cpu (rnp, cpu) {struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu); -struct rcu_dynticks *rdtp = &per_cpu (rcu_dynticks, cpu); rdp->exp_dynticks_snap = -atomic_add_return (0 , &rdtp->dynticks); +rcu_dynticks_snap (rdp->dynticks);if (raw_smp_processor_id () == cpu || !(rdp->exp_dynticks_snap &0x1 ) || !(rnp->qsmaskinitnext & rdp->grpmask))
@@ -380,12 +379,11 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,for_each_leaf_node_possible_cpu (rnp, cpu) {unsigned long mask =leaf_node_cpu_bit (rnp, cpu);struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu); -struct rcu_dynticks *rdtp = &per_cpu (rcu_dynticks, cpu);if (!(mask_ofl_ipi & mask))continue ; retry_ipi: -if (atomic_add_return (0 , &rdtp->dynticks) != +if (rcu_dynticks_snap (rdp->dynticks) != rdp->exp_dynticks_snap) { mask_ofl_test |= mask;continue ;
Signature · 1 line
2.5.2
PATCH 3/6 rcu: Abstract dynticks extended quiescent state enter/exit operations
In reply to Paul E. McKenneyThis commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new rcu_dynticks_eqs_enter() function, and the same but with exit checks in a new rcu_dynticks_eqs_exit() function. This abstraction will ease changes to the ->dynticks counter operation.
--- kernel/rcu/tree.c | 92 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 26 deletions(-)
kernel/rcu/tree.c +66 -26
@@ -282,6 +282,65 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior RCU read-side critical +* sections, and we also must force ordering with the next idle +* sojourn. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && +atomic_read (&rdtp->dynticks) &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && + !(atomic_read (&rdtp->dynticks) &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */
@@ -693,7 +752,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -712,12 +771,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/*
@@ -846,15 +900,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -1001,11 +1050,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;
@@ -1043,11 +1088,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/**
@@ -3800,8 +3841,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /*
Signature · 1 line
2.5.2
Re: [PATCH tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 7 lines · Paul E. McKenney
This commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new
rcu_dynticks_eqs_enter()function, and the same but with exit checks in a newrcu_dynticks_eqs_exit()function. This abstraction will ease changes to the ->dynticks counter operation.Signed-off-by Paul E. McKenney <[email protected]>
A couple of comments below. With those addressed:
Quoted 74 lines
kernel/rcu/tree.c | 92 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 26 deletions(-)kernel/rcu/tree.c +59
-0@@ -282,6 +282,65 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior RCU read-side critical +* sections, and we also must force ordering with the next idle +* sojourn. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && +atomic_read (&rdtp->dynticks) &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && + !(atomic_read (&rdtp->dynticks) &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */
kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 755
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -693,7 +752,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);
Rather than marking a local variable as __maybe_unused (such that the compiler can no longer help detect it as unused), could you move it into the portion of the function that uses it, so that if reached, it'll always get used?
Quoted 17 lines
kernel/rcu/tree.c +1
-6trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -712,12 +771,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/*
kernel/rcu/tree.c void rcu_irq_exit_irqson(void) · line 903
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -846,15 +900,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);
Same comment as above.
Quoted 50 lines
kernel/rcu/tree.c +4
-18rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -1001,11 +1050,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;@@ -1043,11 +1088,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/** @@ -3800,8 +3841,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /* Signature · 1 line
2.5.2
Re: [PATCH tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 88 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney
This commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new
rcu_dynticks_eqs_enter()function, and the same but with exit checks in a newrcu_dynticks_eqs_exit()function. This abstraction will ease changes to the ->dynticks counter operation.Signed-off-by Paul E. McKenney <[email protected]>A couple of comments below. With those addressed:
Reviewed-by Josh Triplett <[email protected]>Quoted 76 lines
kernel/rcu/tree.c | 92 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 26 deletions(-)kernel/rcu/tree.c +59
-0@@ -282,6 +282,65 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior RCU read-side critical +* sections, and we also must force ordering with the next idle +* sojourn. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && +atomic_read (&rdtp->dynticks) &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && + !(atomic_read (&rdtp->dynticks) &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */ @@ -693,7 +752,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;
Quoted 10 lines
kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 755
Quoted 3 lines
kernel/rcu/tree.c +1
-1struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);Rather than marking a local variable as
__maybe_unused(such that the compiler can no longer help detect it as unused), could you move it into the portion of the function that uses it, so that if reached, it'll always get used?Quoted 1 line
kernel/rcu/tree.c +0
-0trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting);
Its only use is in the above event trace, which can be disabled via CONFIG_RCU_TRACE=n. I could put the definition of rdtp under #ifdef, but this seems ugly. I could eliminate the variable, substituting the initialization for rdtp in the event trace, but that would make for a very long line, or an odd line break.
Or am I missing something here?
Quoted 24 lines
Quoted 16 lines
kernel/rcu/tree.c +1
-6if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -712,12 +771,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/* kernel/rcu/tree.c void rcu_irq_exit_irqson(void) · line 903
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -846,15 +900,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);Same comment as above.
Quoted 10 lines
kernel/rcu/tree.c void rcu_irq_exit_irqson(void) · line 908
Quoted 10 lines
kernel/rcu/tree.c +1
-6rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting);
This one is used here, at the top level of the function, and a few lines down. I see the same options available. Thoughts?
Thanx, Paul
Quoted 41 lines
Quoted 40 lines
kernel/rcu/tree.c +3
-12if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -1001,11 +1050,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;@@ -1043,11 +1088,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/** @@ -3800,8 +3841,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /* Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 98 lines · Paul E. McKenney
Quoted 97 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney
This commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new
rcu_dynticks_eqs_enter()function, and the same but with exit checks in a newrcu_dynticks_eqs_exit()function. This abstraction will ease changes to the ->dynticks counter operation.Signed-off-by Paul E. McKenney <[email protected]>A couple of comments below. With those addressed:
Reviewed-by Josh Triplett <[email protected]>Quoted 74 lines
kernel/rcu/tree.c | 92 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 26 deletions(-)kernel/rcu/tree.c +59
-0@@ -282,6 +282,65 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior RCU read-side critical +* sections, and we also must force ordering with the next idle +* sojourn. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && +atomic_read (&rdtp->dynticks) &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && + !(atomic_read (&rdtp->dynticks) &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */ kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 755
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -693,7 +752,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);Rather than marking a local variable as
__maybe_unused(such that the compiler can no longer help detect it as unused), could you move it into the portion of the function that uses it, so that if reached, it'll always get used?
Quoted 7 lines
Quoted 1 line
kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 757
Quoted 1 line
kernel/rcu/tree.c +0
-0trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting);Its only use is in the above event trace, which can be disabled via
CONFIG_RCU_TRACE=n. I could put the definition of rdtp under #ifdef, but this seems ugly. I could eliminate the variable, substituting the initialization for rdtp in the event trace, but that would make for a very long line, or an odd line break.
For the trace_rcu_dyntick calls, you could create a small static inline helper to do the tracing, eliminating the third argument. Or you could create a helper that returns this_cpu_ptr(&rcu_dynticks)->dynticks_nesting. Either way would work.
Or, if you prefer, you could wrap the variable declaration/initialization in RCU_TRACE() rather than adding __maybe_unused.
Quoted 24 lines
Quoted 24 lines
Quoted 16 lines
kernel/rcu/tree.c +1
-6if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -712,12 +771,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/* kernel/rcu/tree.c void rcu_irq_exit_irqson(void) · line 903
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -846,15 +900,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);Same comment as above.
Quoted 13 lines
Quoted 10 lines
kernel/rcu/tree.c void rcu_irq_exit_irqson(void) · line 908
Quoted 10 lines
kernel/rcu/tree.c +1
-6rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting);This one is used here, at the top level of the function, and a few lines down. I see the same options available. Thoughts?
In the fourth patch, you introduce a helper that replaces the use in atomic_read below. That leaves only the tracing use, where the same helper as above would apply.
Quoted 44 lines
Thanx, Paul
Quoted 41 lines
Quoted 40 lines
kernel/rcu/tree.c +3
-12if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -1001,11 +1050,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;@@ -1043,11 +1088,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/** @@ -3800,8 +3841,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /* Signature · 1 line
2.5.2
Re: [PATCH tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 3 lines · Josh Triplett
Quoted 2 lines · Paul E. McKenney
Quoted 1 line · Josh Triplett
On Sat, Jan 14, 2017 at 12:54:42AM -0800, Paul E. McKenney wrote:
[ . . . ]
Quoted 20 lines
Quoted 12 lines
Quoted 12 lines
kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 755
Quoted 6 lines
kernel/rcu/tree.c +1
-1@@ -693,7 +752,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +struct rcu_dynticks __maybe_unused *rdtp =this_cpu_ptr (&rcu_dynticks);Rather than marking a local variable as
__maybe_unused(such that the compiler can no longer help detect it as unused), could you move it into the portion of the function that uses it, so that if reached, it'll always get used?Quoted 7 lines
Quoted 1 line
kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 757
Quoted 1 line
kernel/rcu/tree.c +0
-0trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting);Its only use is in the above event trace, which can be disabled via
CONFIG_RCU_TRACE=n. I could put the definition of rdtp under #ifdef, but this seems ugly. I could eliminate the variable, substituting the initialization for rdtp in the event trace, but that would make for a very long line, or an odd line break.
Quoted 8 lines
For the
trace_rcu_dyntickcalls, you could create a small static inline helper to do the tracing, eliminating the third argument. Or you could create a helper that returns this_cpu_ptr(&rcu_dynticks)->dynticks_nesting. Either way would work.Or, if you prefer, you could wrap the variable declaration/initialization in
RCU_TRACE()rather than adding__maybe_unused.
RCU_TRACE() it is in both cases, thank you! (You would think I would remember the code that I wrote...)
Thanx, Paul
Re: [PATCH tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
In reply to Paul E. McKenneyQuoted 9 lines · Paul E. McKenney
/*
+ * Record entry into an extended quiescent state. This is only to be
+ * called when not already in an extended quiescent state.
+ */kernel/rcu/tree.c +5
-0+static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/*
kernel/rcu/tree.c static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { · line 302
Quoted 10 lines
kernel/rcu/tree.c +10
-0+* CPUs seeing atomic_inc() must see prior RCU read-side critical +* sections, and we also must force ordering with the next idle +* sojourn. +*/ +smp_mb__before_atomic ();/* See above. */ +atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && +atomic_read (&rdtp->dynticks) &0x1 ); +}
In an earlier patch you replaced things with atomic_add_return(), why not use atomic_inc_return() here?
Re: [PATCH tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 15 lines · Peter Zijlstra
Quoted 14 lines · Paul E. McKenney
/*
+ * Record entry into an extended quiescent state. This is only to be
+ * called when not already in an extended quiescent state.
+ */kernel/rcu/tree.c +10
-0+static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior RCU read-side critical +* sections, and we also must force ordering with the next idle +* sojourn. +*/ +smp_mb__before_atomic ();/* See above. */
Quoted 8 lines
kernel/rcu/tree.c static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { · line 302
Quoted 5 lines
kernel/rcu/tree.c +5
-0+atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && +atomic_read (&rdtp->dynticks) &0x1 ); +}In an earlier patch you replaced things with
atomic_add_return(), why not useatomic_inc_return()here?
The rationale is that the earlier patch uses the return value unconditionally, while at this site, the return value would be used only if CONFIG_RCU_EQS_DEBUG. But mostly inertia.
Thanx, Paul
Re: [PATCH tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 25 lines · Paul E. McKenney
Quoted 15 lines · Peter Zijlstra
Quoted 14 lines · Paul E. McKenney
/*
+ * Record entry into an extended quiescent state. This is only to be
+ * called when not already in an extended quiescent state.
+ */kernel/rcu/tree.c +10
-0+static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +/* +* CPUs seeing atomic_inc() must see prior RCU read-side critical +* sections, and we also must force ordering with the next idle +* sojourn. +*/ +smp_mb__before_atomic ();/* See above. */ Quoted 8 lines
kernel/rcu/tree.c static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { · line 302
Quoted 5 lines
kernel/rcu/tree.c +5
-0+atomic_inc (&rdtp->dynticks); +smp_mb__after_atomic ();/* See above. */ +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && +atomic_read (&rdtp->dynticks) &0x1 ); +}In an earlier patch you replaced things with
atomic_add_return(), why not useatomic_inc_return()here?
Quoted 3 lines
The rationale is that the earlier patch uses the return value unconditionally, while at this site, the return value would be used only if
CONFIG_RCU_EQS_DEBUG. But mostly inertia.
But saving two lines is saving two lines. Changed to atomic_inc_return().
Thanx, Paul
PATCH 4/6 rcu: Abstract extended quiescent state determination
In reply to Paul E. McKenneyThis commit is the fourth step towards full abstraction of all accesses to the ->dynticks counter, implementing previously open-coded checks and comparisons in new rcu_dynticks_in_eqs() and rcu_dynticks_in_eqs_since() functions. This abstraction will ease changes to the ->dynticks counter operation.
--- include/linux/rcutiny.h | 6 ++++++ kernel/rcu/tree.c | 52 +++++++++++++++++++++++++++++++++++------------- kernel/rcu/tree.h | 2 ++ kernel/rcu/tree_exp.h | 6 +++--- kernel/rcu/tree_plugin.h | 2 +- kernel/rcu/tree_trace.c | 2 +- 6 files changed, 51 insertions(+), 19 deletions(-)
include/linux/rcutiny.h +6 -0
@@ -27,6 +27,12 @@#include <linux/cache.h> +struct rcu_dynticks ; +static inline int rcu_dynticks_snap (struct rcu_dynticks *rdtp) +{ +return 0 ; +} +static inline unsigned long get_state_synchronize_rcu (void ) {return 0 ;
kernel/rcu/tree.c +38 -14
110 lines not on this page · raw message
kernel/rcu/tree.h +2 -0
@@ -595,6 +595,8 @@ extern struct rcu_state rcu_bh_state;extern struct rcu_state rcu_preempt_state;#endif /* #ifdef CONFIG_PREEMPT_RCU */ +int rcu_dynticks_snap (struct rcu_dynticks *rdtp); +#ifdef CONFIG_RCU_BOOST DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);DECLARE_PER_CPU (int, rcu_cpu_kthread_cpu);
kernel/rcu/tree_exp.h +3 -3
@@ -360,7 +360,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, rdp->exp_dynticks_snap =rcu_dynticks_snap (rdp->dynticks);if (raw_smp_processor_id () == cpu || - !(rdp->exp_dynticks_snap &0x1 ) || +rcu_dynticks_in_eqs (rdp->exp_dynticks_snap) || !(rnp->qsmaskinitnext & rdp->grpmask)) mask_ofl_test |= rdp->grpmask; }
@@ -383,8 +383,8 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,if (!(mask_ofl_ipi & mask))continue ; retry_ipi: -if (rcu_dynticks_snap (rdp->dynticks) != - rdp->exp_dynticks_snap) { +if (rcu_dynticks_in_eqs_since (rdp->dynticks, + rdp->exp_dynticks_snap)) { mask_ofl_test |= mask;continue ; }
kernel/rcu/tree_plugin.h +1 -1
@@ -1643,7 +1643,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)"o." [!!(rdp->grpmask & rdp->mynode->qsmaskinit)],"N." [!!(rdp->grpmask & rdp->mynode->qsmaskinitnext)], ticks_value, ticks_title, -atomic_read (&rdtp->dynticks) &0xfff , +rcu_dynticks_snap (rdtp) &0xfff , rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting, rdp->softirq_snap,kstat_softirqs_cpu (RCU_SOFTIRQ , cpu), READ_ONCE(rsp->n_force_qs) - rsp->n_force_qs_gpstart,
kernel/rcu/tree_trace.c +1 -1
@@ -124,7 +124,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->rcu_qs_ctr_snap ==per_cpu (rcu_qs_ctr, rdp->cpu), rdp->core_needs_qs);seq_printf (m," dt=%d/%llx/%d df=%lu" , -atomic_read (&rdp->dynticks->dynticks), +rcu_dynticks_snap (rdp->dynticks), rdp->dynticks->dynticks_nesting, rdp->dynticks->dynticks_nmi_nesting, rdp->dynticks_fqs);
Signature · 1 line
2.5.2
PATCH 5/6 rcu: Check cond_resched_rcu_qs() state less often to reduce GP overhead
In reply to Paul E. McKenneyCommit 4a81e8328d37 ("rcu: Reduce overhead of cond_resched() checks for RCU") moved quiescent-state generation out of cond_resched() and commit bde6c3aa9930 ("rcu: Provide cond_resched_rcu_qs() to force quiescent states in long loops") introduced cond_resched_rcu_qs(), and commit 5cd37193ce85 ("rcu: Make cond_resched_rcu_qs() apply to normal RCU flavors") introduced the per-CPU rcu_qs_ctr variable, which is frequently polled by the RCU core state machine.
This frequent polling can increase grace-period rate, which in turn increases grace-period overhead, which is visible in some benchmarks (for example, the "open1" benchmark in Anton Blanchard's "will it scale" suite). This commit therefore reduces the rate at which rcu_qs_ctr is polled by moving that polling into the force-quiescent-state (FQS) machinery, and by further polling it only after the grace period has been in effect for at least jiffies_till_sched_qs jiffies.
--- include/trace/events/rcu.h | 10 +++++----- kernel/rcu/tree.c | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 17 deletions(-)
include/trace/events/rcu.h +5 -5
@@ -385,11 +385,11 @@ TRACE_EVENT(rcu_quiescent_state_report,/* * Tracepoint for quiescent states detected by force_quiescent_state(). -* These trace events include the type of RCU, the grace-period number -* that was blocked by the CPU, the CPU itself, and the type of quiescent -* state, which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, -* or "kick" when kicking a CPU that has been in dyntick-idle mode for -* too long. +* These trace events include the type of RCU, the grace-period number that +* was blocked by the CPU, the CPU itself, and the type of quiescent state, +* which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, "kick" +* when kicking a CPU that has been in dyntick-idle mode for too long, or +* "rqc" if the CPU got a quiescent state via its rcu_qs_ctr. */ TRACE_EVENT(rcu_fqs,
kernel/rcu/tree.c +34 -12
83 lines not on this page · raw message
Signature · 1 line
2.5.2
PATCH 6/6 rcu: Adjust FQS offline checks for exact online-CPU detection
In reply to Paul E. McKenneyCommit 7ec99de36f40 ("rcu: Provide exact CPU-online tracking for RCU"), as its title suggests, got rid of RCU's remaining CPU-hotplug timing guesswork. This commit therefore removes the one-jiffy kludge that was used to paper over this guesswork.
--- kernel/rcu/tree.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-)
kernel/rcu/tree.c +2 -15
@@ -1280,21 +1280,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,return 1 ; } -/* -* Check for the CPU being offline, but only if the grace period -* is old enough. We don't need to worry about the CPU changing -* state: If we see it offline even once, it has been through a -* quiescent state. -* -* The reason for insisting that the grace period be at least -* one jiffy old is that CPUs that are not quite online and that -* have just gone offline can still execute RCU read-side critical -* sections. -*/ -if (ULONG_CMP_GE (rdp->rsp->gp_start +2 , jiffies)) -return 0 ;/* Grace period is not old enough. */ -barrier (); -if (cpu_is_offline (rdp->cpu)) { +/* Check for the CPU being offline. */ +if (!(rdp->grpmask &rcu_rnp_online_cpus (rnp))) {trace_rcu_fqs (rdp->rsp->name, rdp->gpnum, rdp->cpu,TPS ("ofl" )); rdp->offline_fqs++;return 1 ;
Signature · 1 line
2.5.2
Quoted 10 lines · Paul E. McKenney
Hello!
This series provides dynticks updates:
1-4. Abstract access to the dyntick counter, replacing the current
open-coding of atomic operations.5. Check
cond_resched_rcu_qs()state less often to reduce GP overhead.6. Adjust FQS offline checks for exact online-CPU detection.
I replied to patches 1 and 3 with feedback. For patches 2 and 4-6:
Quoted 13 lines
Thanx, Paul
------------------------------------------------------------------------
include/linux/rcutiny.h | 6 + include/trace/events/rcu.h | 10 - kernel/rcu/tree.c | 245 +++++++++++++++++++++++++++++++-------------- kernel/rcu/tree.h | 2 kernel/rcu/tree_exp.h | 12 -- kernel/rcu/tree_plugin.h | 2 kernel/rcu/tree_trace.c | 2 7 files changed, 190 insertions(+), 89 deletions(-)
Hello!
This series provides v2 of the dynticks updates:
1-4. Abstract access to the dyntick counter, replacing the current
open-coding of atomic operations.
5. Check cond_resched_rcu_qs() state less often to reduce GP overhead.
6. Adjust FQS offline checks for exact online-CPU detection.
Changes since v1:
o Apply feedback from Josh Triplett and Peter Zijlstra.
Thanx, Paul
------------------------------------------------------------------------
include/linux/rcutiny.h | 6 + include/trace/events/rcu.h | 10 - kernel/rcu/tree.c | 241 ++++++++++++++++++++++++++++++--------------- kernel/rcu/tree.h | 2 kernel/rcu/tree_exp.h | 12 -- kernel/rcu/tree_plugin.h | 2 kernel/rcu/tree_trace.c | 2 7 files changed, 186 insertions(+), 89 deletions(-)
PATCH v2 1/6 rcu: Abstract the dynticks momentary-idle operation
This commit is the first step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of two in a new rcu_dynticks_momentary_idle() function. This abstraction will ease changes to the ->dynticks counter operation.
Note that this commit gets rid of the smp_mb__before_atomic() and the smp_mb__after_atomic() calls that were previously present. The reason that this is OK from a memory-ordering perspective is that the atomic operation is now atomic_add_return(), which, as a value-returning atomic, guarantees full ordering.
--- kernel/rcu/tree.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
kernel/rcu/tree.c +14 -5
@@ -281,6 +281,19 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ }; +/* +* Do a double-increment of the ->dynticks counter to emulate a +* momentary idle-CPU quiescent state. +*/ +static void rcu_dynticks_momentary_idle (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special =atomic_add_return (2 , &rdtp->dynticks); + +/* It is illegal to call this from idle state. */ +WARN_ON_ONCE (!(special &0x1 )); +} + DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, rcu_qs_ctr);EXPORT_PER_CPU_SYMBOL_GPL (rcu_qs_ctr);
@@ -300,7 +313,6 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);static void rcu_momentary_dyntick_idle (void ) {struct rcu_data *rdp; -struct rcu_dynticks *rdtp;int resched_mask;struct rcu_state *rsp;
@@ -327,10 +339,7 @@ static void rcu_momentary_dyntick_idle(void)* quiescent state, with no need for this CPU to do anything * further. */ - rdtp =this_cpu_ptr (&rcu_dynticks); -smp_mb__before_atomic ();/* Earlier stuff before QS. */ -atomic_add (2 , &rdtp->dynticks);/* QS. */ -smp_mb__after_atomic ();/* Later stuff after QS. */ +rcu_dynticks_momentary_idle ();break ; } }
Signature · 1 line
2.5.2
PATCH v2 2/6 rcu: Abstract the dynticks snapshot operation
In reply to Paul E. McKenneyThis commit is the second step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of zero in a new rcu_dynticks_snap() function. This abstraction will ease changes o the ->dynticks counter operation.
--- kernel/rcu/tree.c | 19 ++++++++++++++++--- kernel/rcu/tree_exp.h | 6 ++---- 2 files changed, 18 insertions(+), 7 deletions(-)
kernel/rcu/tree.c +16 -3
@@ -282,6 +282,17 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Snapshot the ->dynticks counter with full ordering so as to allow +* stable comparison of this counter with past and future snapshots. +*/ +static int rcu_dynticks_snap (struct rcu_dynticks *rdtp) +{ +int snap =atomic_add_return (0 , &rdtp->dynticks); + +return snap; +} + +/* * Do a double-increment of the ->dynticks counter to emulate a * momentary idle-CPU quiescent state. */
@@ -1049,7 +1060,9 @@ void rcu_nmi_exit(void)*/ bool notrace __rcu_is_watching(void) { -return atomic_read (this_cpu_ptr (&rcu_dynticks.dynticks)) &0x1 ; +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +return atomic_read (&rdtp->dynticks) &0x1 ; }/**
@@ -1132,7 +1145,7 @@ static int rcu_is_cpu_rrupt_from_idle(void)static int dyntick_save_progress_counter (struct rcu_data *rdp,bool *isidle,unsigned long *maxj) { - rdp->dynticks_snap =atomic_add_return (0 , &rdp->dynticks->dynticks); + rdp->dynticks_snap =rcu_dynticks_snap (rdp->dynticks);rcu_sysidle_check_cpu (rdp, isidle, maxj);if ((rdp->dynticks_snap &0x1 ) ==0 ) {trace_rcu_fqs (rdp->rsp->name, rdp->gpnum, rdp->cpu,TPS ("dti" ));
@@ -1157,7 +1170,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,int *rcrmp;unsigned int snap; - curr = (unsigned int )atomic_add_return (0 , &rdp->dynticks->dynticks); + curr = (unsigned int )rcu_dynticks_snap (rdp->dynticks); snap = (unsigned int )rdp->dynticks_snap;/*
kernel/rcu/tree_exp.h +2 -4
@@ -356,10 +356,9 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, mask_ofl_test =0 ;for_each_leaf_node_possible_cpu (rnp, cpu) {struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu); -struct rcu_dynticks *rdtp = &per_cpu (rcu_dynticks, cpu); rdp->exp_dynticks_snap = -atomic_add_return (0 , &rdtp->dynticks); +rcu_dynticks_snap (rdp->dynticks);if (raw_smp_processor_id () == cpu || !(rdp->exp_dynticks_snap &0x1 ) || !(rnp->qsmaskinitnext & rdp->grpmask))
@@ -380,12 +379,11 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,for_each_leaf_node_possible_cpu (rnp, cpu) {unsigned long mask =leaf_node_cpu_bit (rnp, cpu);struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu); -struct rcu_dynticks *rdtp = &per_cpu (rcu_dynticks, cpu);if (!(mask_ofl_ipi & mask))continue ; retry_ipi: -if (atomic_add_return (0 , &rdtp->dynticks) != +if (rcu_dynticks_snap (rdp->dynticks) != rdp->exp_dynticks_snap) { mask_ofl_test |= mask;continue ;
Signature · 1 line
2.5.2
PATCH v2 3/6 rcu: Abstract dynticks extended quiescent state enter/exit operations
In reply to Paul E. McKenneyThis commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new rcu_dynticks_eqs_enter() function, and the same but with exit checks in a new rcu_dynticks_eqs_exit() function. This abstraction will ease changes to the ->dynticks counter operation.
Note that this commit gets rid of the smp_mb__before_atomic() and the smp_mb__after_atomic() calls that were previously present. The reason that this is OK from a memory-ordering perspective is that the atomic operation is now atomic_add_return(), which, as a value-returning atomic, guarantees full ordering.
--- kernel/rcu/tree.c | 88 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 26 deletions(-)
kernel/rcu/tree.c +62 -26
@@ -282,6 +282,61 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior RCU read-side +* critical sections, and we also must force ordering with the +* next idle sojourn. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && special &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && !(special &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */
@@ -693,7 +748,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks));trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -712,12 +767,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/*
@@ -846,15 +896,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks));rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -1001,11 +1046,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;
@@ -1043,11 +1084,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/**
@@ -3800,8 +3837,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /*
Signature · 1 line
2.5.2
Re: [PATCH v2 tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 6 lines · Paul E. McKenney
This commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new
rcu_dynticks_eqs_enter()function, and the same but with exit checks in a newrcu_dynticks_eqs_exit()function. This abstraction will ease changes to the ->dynticks counter operation.
Quoted 7 lines
Note that this commit gets rid of the
smp_mb__before_atomic()and thesmp_mb__after_atomic()calls that were previously present. The reason that this is OK from a memory-ordering perspective is that the atomic operation is nowatomic_add_return(), which, as a value-returning atomic, guarantees full ordering.Signed-off-by Paul E. McKenney <[email protected]>
A couple of issues with RCU_TRACE usage noted below. With those fixed:
Quoted 70 lines
kernel/rcu/tree.c | 88 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 26 deletions(-)kernel/rcu/tree.c +55
-0@@ -282,6 +282,61 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior RCU read-side +* critical sections, and we also must force ordering with the +* next idle sojourn. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && special &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && !(special &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */
kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 751
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -693,7 +748,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks));
RCU_TRACE doesn't act like a statement, and doesn't take a semicolon; it just acts like a shorthand for an #ifdef. The semicolon belongs inside the macro parentheses, since it goes with the declaration. Otherwise, this compiles to the empty statement ';' without tracing. Among other things, that would lead to surprises for anyone who added a subsequent declaration, because ';' followed by a declaration will produce a -Wdeclaration-after-statement warning.
Quoted 17 lines
kernel/rcu/tree.c +1
-6trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -712,12 +767,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/*
kernel/rcu/tree.c void rcu_irq_exit_irqson(void) · line 899
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -846,15 +896,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks));
As above.
Quoted 50 lines
kernel/rcu/tree.c +4
-18rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -1001,11 +1046,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;@@ -1043,11 +1084,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/** @@ -3800,8 +3837,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /* Signature · 1 line
2.5.2
Re: [PATCH v2 tip/core/rcu 3/6] rcu: Abstract dynticks extended quiescent state enter/exit operations
Quoted 94 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney
This commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new
rcu_dynticks_eqs_enter()function, and the same but with exit checks in a newrcu_dynticks_eqs_exit()function. This abstraction will ease changes to the ->dynticks counter operation.Quoted 7 lines
Note that this commit gets rid of the
smp_mb__before_atomic()and thesmp_mb__after_atomic()calls that were previously present. The reason that this is OK from a memory-ordering perspective is that the atomic operation is nowatomic_add_return(), which, as a value-returning atomic, guarantees full ordering.Signed-off-by Paul E. McKenney <[email protected]>A couple of issues with
RCU_TRACEusage noted below. With those fixed:Reviewed-by Josh Triplett <[email protected]>.Quoted 70 lines
kernel/rcu/tree.c | 88 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 26 deletions(-)kernel/rcu/tree.c +55
-0@@ -282,6 +282,61 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior RCU read-side +* critical sections, and we also must force ordering with the +* next idle sojourn. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && special &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && !(special &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */ kernel/rcu/tree.c static void rcu_eqs_enter_common(long long oldval, bool user) · line 751
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -693,7 +748,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks));
Quoted 7 lines
RCU_TRACEdoesn't act like a statement, and doesn't take a semicolon; it just acts like a shorthand for an #ifdef. The semicolon belongs inside the macro parentheses, since it goes with the declaration. Otherwise, this compiles to the empty statement ';' without tracing. Among other things, that would lead to surprises for anyone who added a subsequent declaration, because ';' followed by a declaration will produce a -Wdeclaration-after-statement warning.
I do need the ";" inside the RCU_TRACE(), don't I? And I have this bug well-represented in the RCU code. I am fixing these two in this commit and will queue commits to fix the others. I also added your Reviewed-by, thank you!
And good catch!!!
Thanx, Paul
Quoted 76 lines
Quoted 17 lines
kernel/rcu/tree.c +1
-6trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -712,12 +767,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/* kernel/rcu/tree.c void rcu_irq_exit_irqson(void) · line 899
Quoted 5 lines
kernel/rcu/tree.c +1
-1@@ -846,15 +896,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks));As above.
Quoted 50 lines
kernel/rcu/tree.c +4
-18rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&@@ -1001,11 +1046,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;@@ -1043,11 +1084,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/** @@ -3800,8 +3837,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /* Signature · 1 line
2.5.2
PATCH v2 4/6 rcu: Abstract extended quiescent state determination
In reply to Paul E. McKenneyThis commit is the fourth step towards full abstraction of all accesses to the ->dynticks counter, implementing previously open-coded checks and comparisons in new rcu_dynticks_in_eqs() and rcu_dynticks_in_eqs_since() functions. This abstraction will ease changes to the ->dynticks counter operation.
--- include/linux/rcutiny.h | 6 ++++++ kernel/rcu/tree.c | 52 +++++++++++++++++++++++++++++++++++------------- kernel/rcu/tree.h | 2 ++ kernel/rcu/tree_exp.h | 6 +++--- kernel/rcu/tree_plugin.h | 2 +- kernel/rcu/tree_trace.c | 2 +- 6 files changed, 51 insertions(+), 19 deletions(-)
include/linux/rcutiny.h +6 -0
@@ -27,6 +27,12 @@#include <linux/cache.h> +struct rcu_dynticks ; +static inline int rcu_dynticks_snap (struct rcu_dynticks *rdtp) +{ +return 0 ; +} +static inline unsigned long get_state_synchronize_rcu (void ) {return 0 ;
kernel/rcu/tree.c +38 -14
110 lines not on this page · raw message
kernel/rcu/tree.h +2 -0
@@ -595,6 +595,8 @@ extern struct rcu_state rcu_bh_state;extern struct rcu_state rcu_preempt_state;#endif /* #ifdef CONFIG_PREEMPT_RCU */ +int rcu_dynticks_snap (struct rcu_dynticks *rdtp); +#ifdef CONFIG_RCU_BOOST DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);DECLARE_PER_CPU (int, rcu_cpu_kthread_cpu);
kernel/rcu/tree_exp.h +3 -3
@@ -360,7 +360,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, rdp->exp_dynticks_snap =rcu_dynticks_snap (rdp->dynticks);if (raw_smp_processor_id () == cpu || - !(rdp->exp_dynticks_snap &0x1 ) || +rcu_dynticks_in_eqs (rdp->exp_dynticks_snap) || !(rnp->qsmaskinitnext & rdp->grpmask)) mask_ofl_test |= rdp->grpmask; }
@@ -383,8 +383,8 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,if (!(mask_ofl_ipi & mask))continue ; retry_ipi: -if (rcu_dynticks_snap (rdp->dynticks) != - rdp->exp_dynticks_snap) { +if (rcu_dynticks_in_eqs_since (rdp->dynticks, + rdp->exp_dynticks_snap)) { mask_ofl_test |= mask;continue ; }
kernel/rcu/tree_plugin.h +1 -1
@@ -1643,7 +1643,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)"o." [!!(rdp->grpmask & rdp->mynode->qsmaskinit)],"N." [!!(rdp->grpmask & rdp->mynode->qsmaskinitnext)], ticks_value, ticks_title, -atomic_read (&rdtp->dynticks) &0xfff , +rcu_dynticks_snap (rdtp) &0xfff , rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting, rdp->softirq_snap,kstat_softirqs_cpu (RCU_SOFTIRQ , cpu), READ_ONCE(rsp->n_force_qs) - rsp->n_force_qs_gpstart,
kernel/rcu/tree_trace.c +1 -1
@@ -124,7 +124,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->rcu_qs_ctr_snap ==per_cpu (rcu_qs_ctr, rdp->cpu), rdp->core_needs_qs);seq_printf (m," dt=%d/%llx/%d df=%lu" , -atomic_read (&rdp->dynticks->dynticks), +rcu_dynticks_snap (rdp->dynticks), rdp->dynticks->dynticks_nesting, rdp->dynticks->dynticks_nmi_nesting, rdp->dynticks_fqs);
Signature · 1 line
2.5.2
PATCH v2 5/6 rcu: Check cond_resched_rcu_qs() state less often to reduce GP overhead
In reply to Paul E. McKenneyCommit 4a81e8328d37 ("rcu: Reduce overhead of cond_resched() checks for RCU") moved quiescent-state generation out of cond_resched() and commit bde6c3aa9930 ("rcu: Provide cond_resched_rcu_qs() to force quiescent states in long loops") introduced cond_resched_rcu_qs(), and commit 5cd37193ce85 ("rcu: Make cond_resched_rcu_qs() apply to normal RCU flavors") introduced the per-CPU rcu_qs_ctr variable, which is frequently polled by the RCU core state machine.
This frequent polling can increase grace-period rate, which in turn increases grace-period overhead, which is visible in some benchmarks (for example, the "open1" benchmark in Anton Blanchard's "will it scale" suite). This commit therefore reduces the rate at which rcu_qs_ctr is polled by moving that polling into the force-quiescent-state (FQS) machinery, and by further polling it only after the grace period has been in effect for at least jiffies_till_sched_qs jiffies.
--- include/trace/events/rcu.h | 10 +++++----- kernel/rcu/tree.c | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 17 deletions(-)
include/trace/events/rcu.h +5 -5
@@ -385,11 +385,11 @@ TRACE_EVENT(rcu_quiescent_state_report,/* * Tracepoint for quiescent states detected by force_quiescent_state(). -* These trace events include the type of RCU, the grace-period number -* that was blocked by the CPU, the CPU itself, and the type of quiescent -* state, which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, -* or "kick" when kicking a CPU that has been in dyntick-idle mode for -* too long. +* These trace events include the type of RCU, the grace-period number that +* was blocked by the CPU, the CPU itself, and the type of quiescent state, +* which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, "kick" +* when kicking a CPU that has been in dyntick-idle mode for too long, or +* "rqc" if the CPU got a quiescent state via its rcu_qs_ctr. */ TRACE_EVENT(rcu_fqs,
kernel/rcu/tree.c +34 -12
83 lines not on this page · raw message
Signature · 1 line
2.5.2
PATCH v2 6/6 rcu: Adjust FQS offline checks for exact online-CPU detection
In reply to Paul E. McKenneyCommit 7ec99de36f40 ("rcu: Provide exact CPU-online tracking for RCU"), as its title suggests, got rid of RCU's remaining CPU-hotplug timing guesswork. This commit therefore removes the one-jiffy kludge that was used to paper over this guesswork.
--- kernel/rcu/tree.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-)
kernel/rcu/tree.c +2 -15
@@ -1276,21 +1276,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,return 1 ; } -/* -* Check for the CPU being offline, but only if the grace period -* is old enough. We don't need to worry about the CPU changing -* state: If we see it offline even once, it has been through a -* quiescent state. -* -* The reason for insisting that the grace period be at least -* one jiffy old is that CPUs that are not quite online and that -* have just gone offline can still execute RCU read-side critical -* sections. -*/ -if (ULONG_CMP_GE (rdp->rsp->gp_start +2 , jiffies)) -return 0 ;/* Grace period is not old enough. */ -barrier (); -if (cpu_is_offline (rdp->cpu)) { +/* Check for the CPU being offline. */ +if (!(rdp->grpmask &rcu_rnp_online_cpus (rnp))) {trace_rcu_fqs (rdp->rsp->name, rdp->gpnum, rdp->cpu,TPS ("ofl" )); rdp->offline_fqs++;return 1 ;
Signature · 1 line
2.5.2
Hello!
This series provides v3 of the dynticks updates:
1-4. Abstract access to the dyntick counter, replacing the current
open-coding of atomic operations.
5. Check cond_resched_rcu_qs() state less often to reduce GP overhead.
6. Adjust FQS offline checks for exact online-CPU detection.
Changes since v2:
o Fix RCU_TRACE() statements called out by Josh Triplett.
Changes since v1:
o Apply feedback from Josh Triplett and Peter Zijlstra.
Thanx, Paul
------------------------------------------------------------------------
include/linux/rcutiny.h | 6 + include/trace/events/rcu.h | 10 - kernel/rcu/tree.c | 241 ++++++++++++++++++++++++++++++--------------- kernel/rcu/tree.h | 2 kernel/rcu/tree_exp.h | 12 -- kernel/rcu/tree_plugin.h | 2 kernel/rcu/tree_trace.c | 2 7 files changed, 186 insertions(+), 89 deletions(-)
PATCH v3 1/6 rcu: Abstract the dynticks momentary-idle operation
This commit is the first step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of two in a new rcu_dynticks_momentary_idle() function. This abstraction will ease changes to the ->dynticks counter operation.
Note that this commit gets rid of the smp_mb__before_atomic() and the smp_mb__after_atomic() calls that were previously present. The reason that this is OK from a memory-ordering perspective is that the atomic operation is now atomic_add_return(), which, as a value-returning atomic, guarantees full ordering.
--- kernel/rcu/tree.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
kernel/rcu/tree.c +14 -5
@@ -281,6 +281,19 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ }; +/* +* Do a double-increment of the ->dynticks counter to emulate a +* momentary idle-CPU quiescent state. +*/ +static void rcu_dynticks_momentary_idle (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special =atomic_add_return (2 , &rdtp->dynticks); + +/* It is illegal to call this from idle state. */ +WARN_ON_ONCE (!(special &0x1 )); +} + DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, rcu_qs_ctr);EXPORT_PER_CPU_SYMBOL_GPL (rcu_qs_ctr);
@@ -300,7 +313,6 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);static void rcu_momentary_dyntick_idle (void ) {struct rcu_data *rdp; -struct rcu_dynticks *rdtp;int resched_mask;struct rcu_state *rsp;
@@ -327,10 +339,7 @@ static void rcu_momentary_dyntick_idle(void)* quiescent state, with no need for this CPU to do anything * further. */ - rdtp =this_cpu_ptr (&rcu_dynticks); -smp_mb__before_atomic ();/* Earlier stuff before QS. */ -atomic_add (2 , &rdtp->dynticks);/* QS. */ -smp_mb__after_atomic ();/* Later stuff after QS. */ +rcu_dynticks_momentary_idle ();break ; } }
Signature · 1 line
2.5.2
PATCH v3 2/6 rcu: Abstract the dynticks snapshot operation
In reply to Paul E. McKenneyThis commit is the second step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of zero in a new rcu_dynticks_snap() function. This abstraction will ease changes o the ->dynticks counter operation.
--- kernel/rcu/tree.c | 19 ++++++++++++++++--- kernel/rcu/tree_exp.h | 6 ++---- 2 files changed, 18 insertions(+), 7 deletions(-)
kernel/rcu/tree.c +16 -3
@@ -282,6 +282,17 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Snapshot the ->dynticks counter with full ordering so as to allow +* stable comparison of this counter with past and future snapshots. +*/ +static int rcu_dynticks_snap (struct rcu_dynticks *rdtp) +{ +int snap =atomic_add_return (0 , &rdtp->dynticks); + +return snap; +} + +/* * Do a double-increment of the ->dynticks counter to emulate a * momentary idle-CPU quiescent state. */
@@ -1049,7 +1060,9 @@ void rcu_nmi_exit(void)*/ bool notrace __rcu_is_watching(void) { -return atomic_read (this_cpu_ptr (&rcu_dynticks.dynticks)) &0x1 ; +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +return atomic_read (&rdtp->dynticks) &0x1 ; }/**
@@ -1132,7 +1145,7 @@ static int rcu_is_cpu_rrupt_from_idle(void)static int dyntick_save_progress_counter (struct rcu_data *rdp,bool *isidle,unsigned long *maxj) { - rdp->dynticks_snap =atomic_add_return (0 , &rdp->dynticks->dynticks); + rdp->dynticks_snap =rcu_dynticks_snap (rdp->dynticks);rcu_sysidle_check_cpu (rdp, isidle, maxj);if ((rdp->dynticks_snap &0x1 ) ==0 ) {trace_rcu_fqs (rdp->rsp->name, rdp->gpnum, rdp->cpu,TPS ("dti" ));
@@ -1157,7 +1170,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,int *rcrmp;unsigned int snap; - curr = (unsigned int )atomic_add_return (0 , &rdp->dynticks->dynticks); + curr = (unsigned int )rcu_dynticks_snap (rdp->dynticks); snap = (unsigned int )rdp->dynticks_snap;/*
kernel/rcu/tree_exp.h +2 -4
@@ -356,10 +356,9 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, mask_ofl_test =0 ;for_each_leaf_node_possible_cpu (rnp, cpu) {struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu); -struct rcu_dynticks *rdtp = &per_cpu (rcu_dynticks, cpu); rdp->exp_dynticks_snap = -atomic_add_return (0 , &rdtp->dynticks); +rcu_dynticks_snap (rdp->dynticks);if (raw_smp_processor_id () == cpu || !(rdp->exp_dynticks_snap &0x1 ) || !(rnp->qsmaskinitnext & rdp->grpmask))
@@ -380,12 +379,11 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,for_each_leaf_node_possible_cpu (rnp, cpu) {unsigned long mask =leaf_node_cpu_bit (rnp, cpu);struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu); -struct rcu_dynticks *rdtp = &per_cpu (rcu_dynticks, cpu);if (!(mask_ofl_ipi & mask))continue ; retry_ipi: -if (atomic_add_return (0 , &rdtp->dynticks) != +if (rcu_dynticks_snap (rdp->dynticks) != rdp->exp_dynticks_snap) { mask_ofl_test |= mask;continue ;
Signature · 1 line
2.5.2
PATCH v3 3/6 rcu: Abstract dynticks extended quiescent state enter/exit operations
In reply to Paul E. McKenneyThis commit is the third step towards full abstraction of all accesses to the ->dynticks counter, implementing the previously open-coded atomic add of 1 and entry checks in a new rcu_dynticks_eqs_enter() function, and the same but with exit checks in a new rcu_dynticks_eqs_exit() function. This abstraction will ease changes to the ->dynticks counter operation.
Note that this commit gets rid of the smp_mb__before_atomic() and the smp_mb__after_atomic() calls that were previously present. The reason that this is OK from a memory-ordering perspective is that the atomic operation is now atomic_add_return(), which, as a value-returning atomic, guarantees full ordering.
--- kernel/rcu/tree.c | 88 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 26 deletions(-)
kernel/rcu/tree.c +62 -26
@@ -282,6 +282,61 @@ static DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { };/* +* Record entry into an extended quiescent state. This is only to be +* called when not already in an extended quiescent state. +*/ +static void rcu_dynticks_eqs_enter (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior RCU read-side +* critical sections, and we also must force ordering with the +* next idle sojourn. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && special &0x1 ); +} + +/* +* Record exit from an extended quiescent state. This is only to be +* called from an extended quiescent state. +*/ +static void rcu_dynticks_eqs_exit (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +int special; + +/* +* CPUs seeing atomic_inc_return() must see prior idle sojourns, +* and we also must force ordering with the next RCU read-side +* critical section. +*/ + special =atomic_inc_return (&rdtp->dynticks); +WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && !(special &0x1 )); +} + +/* +* Reset the current CPU's ->dynticks counter to indicate that the +* newly onlined CPU is no longer in an extended quiescent state. +* This will either leave the counter unchanged, or increment it +* to the next non-quiescent value. +* +* The non-atomic test/increment sequence works because the upper bits +* of the ->dynticks counter are manipulated only by the corresponding CPU, +* or when the corresponding CPU is offline. +*/ +static void rcu_dynticks_eqs_online (void ) +{ +struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + +if (atomic_read (&rdtp->dynticks) &0x1 ) +return ; +atomic_add (0x1 , &rdtp->dynticks); +} + +/* * Snapshot the ->dynticks counter with full ordering so as to allow * stable comparison of this counter with past and future snapshots. */
@@ -693,7 +748,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user) {struct rcu_state *rsp;struct rcu_data *rdp; -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);)trace_rcu_dyntick (TPS ("Start" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -712,12 +767,7 @@ static void rcu_eqs_enter_common(long long oldval, bool user)do_nocb_deferred_wakeup (rdp); }rcu_prepare_for_idle (); -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force ordering with next sojourn. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && -atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter ();rcu_dynticks_task_enter ();/*
@@ -846,15 +896,10 @@ void rcu_irq_exit_irqson(void)*/ static void rcu_eqs_exit_common (long long oldval,int user) { -struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); + RCU_TRACE(struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);)rcu_dynticks_task_exit (); -smp_mb__before_atomic ();/* Force ordering w/previous sojourn. */ -atomic_inc (&rdtp->dynticks); -/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (IS_ENABLED (CONFIG_RCU_EQS_DEBUG ) && - !(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit ();rcu_cleanup_after_idle ();trace_rcu_dyntick (TPS ("End" ), oldval, rdtp->dynticks_nesting); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -1001,11 +1046,7 @@ void rcu_nmi_enter(void)* period (observation due to Andy Lutomirski). */ if (!(atomic_read (&rdtp->dynticks) &0x1 )) { -smp_mb__before_atomic ();/* Force delay from prior write. */ -atomic_inc (&rdtp->dynticks); -/* atomic_inc() before later RCU read-side crit sects */ -smp_mb__after_atomic ();/* See above. */ -WARN_ON_ONCE (!(atomic_read (&rdtp->dynticks) &0x1 )); +rcu_dynticks_eqs_exit (); incby =1 ; } rdtp->dynticks_nmi_nesting += incby;
@@ -1043,11 +1084,7 @@ void rcu_nmi_exit(void)/* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */ rdtp->dynticks_nmi_nesting =0 ; -/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ -smp_mb__before_atomic ();/* See above. */ -atomic_inc (&rdtp->dynticks); -smp_mb__after_atomic ();/* Force delay to next write. */ -WARN_ON_ONCE (atomic_read (&rdtp->dynticks) &0x1 ); +rcu_dynticks_eqs_enter (); }/**
@@ -3800,8 +3837,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)init_callback_list (rdp);/* Re-enable callbacks on this CPU. */ rdp->dynticks->dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;rcu_sysidle_init_percpu_data (rdp->dynticks); -atomic_set (&rdp->dynticks->dynticks, - (atomic_read (&rdp->dynticks->dynticks) & ~0x1 ) +1 ); +rcu_dynticks_eqs_online ();raw_spin_unlock_rcu_node (rnp);/* irqs remain disabled. */ /*
Signature · 1 line
2.5.2
PATCH v3 4/6 rcu: Abstract extended quiescent state determination
In reply to Paul E. McKenneyThis commit is the fourth step towards full abstraction of all accesses to the ->dynticks counter, implementing previously open-coded checks and comparisons in new rcu_dynticks_in_eqs() and rcu_dynticks_in_eqs_since() functions. This abstraction will ease changes to the ->dynticks counter operation.
--- include/linux/rcutiny.h | 6 ++++++ kernel/rcu/tree.c | 52 +++++++++++++++++++++++++++++++++++------------- kernel/rcu/tree.h | 2 ++ kernel/rcu/tree_exp.h | 6 +++--- kernel/rcu/tree_plugin.h | 2 +- kernel/rcu/tree_trace.c | 2 +- 6 files changed, 51 insertions(+), 19 deletions(-)
include/linux/rcutiny.h +6 -0
@@ -27,6 +27,12 @@#include <linux/cache.h> +struct rcu_dynticks ; +static inline int rcu_dynticks_snap (struct rcu_dynticks *rdtp) +{ +return 0 ; +} +static inline unsigned long get_state_synchronize_rcu (void ) {return 0 ;
kernel/rcu/tree.c +38 -14
110 lines not on this page · raw message
kernel/rcu/tree.h +2 -0
@@ -595,6 +595,8 @@ extern struct rcu_state rcu_bh_state;extern struct rcu_state rcu_preempt_state;#endif /* #ifdef CONFIG_PREEMPT_RCU */ +int rcu_dynticks_snap (struct rcu_dynticks *rdtp); +#ifdef CONFIG_RCU_BOOST DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);DECLARE_PER_CPU (int, rcu_cpu_kthread_cpu);
kernel/rcu/tree_exp.h +3 -3
@@ -360,7 +360,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, rdp->exp_dynticks_snap =rcu_dynticks_snap (rdp->dynticks);if (raw_smp_processor_id () == cpu || - !(rdp->exp_dynticks_snap &0x1 ) || +rcu_dynticks_in_eqs (rdp->exp_dynticks_snap) || !(rnp->qsmaskinitnext & rdp->grpmask)) mask_ofl_test |= rdp->grpmask; }
@@ -383,8 +383,8 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,if (!(mask_ofl_ipi & mask))continue ; retry_ipi: -if (rcu_dynticks_snap (rdp->dynticks) != - rdp->exp_dynticks_snap) { +if (rcu_dynticks_in_eqs_since (rdp->dynticks, + rdp->exp_dynticks_snap)) { mask_ofl_test |= mask;continue ; }
kernel/rcu/tree_plugin.h +1 -1
@@ -1643,7 +1643,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)"o." [!!(rdp->grpmask & rdp->mynode->qsmaskinit)],"N." [!!(rdp->grpmask & rdp->mynode->qsmaskinitnext)], ticks_value, ticks_title, -atomic_read (&rdtp->dynticks) &0xfff , +rcu_dynticks_snap (rdtp) &0xfff , rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting, rdp->softirq_snap,kstat_softirqs_cpu (RCU_SOFTIRQ , cpu), READ_ONCE(rsp->n_force_qs) - rsp->n_force_qs_gpstart,
kernel/rcu/tree_trace.c +1 -1
@@ -124,7 +124,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->rcu_qs_ctr_snap ==per_cpu (rcu_qs_ctr, rdp->cpu), rdp->core_needs_qs);seq_printf (m," dt=%d/%llx/%d df=%lu" , -atomic_read (&rdp->dynticks->dynticks), +rcu_dynticks_snap (rdp->dynticks), rdp->dynticks->dynticks_nesting, rdp->dynticks->dynticks_nmi_nesting, rdp->dynticks_fqs);
Signature · 1 line
2.5.2
PATCH v3 5/6 rcu: Check cond_resched_rcu_qs() state less often to reduce GP overhead
In reply to Paul E. McKenneyCommit 4a81e8328d37 ("rcu: Reduce overhead of cond_resched() checks for RCU") moved quiescent-state generation out of cond_resched() and commit bde6c3aa9930 ("rcu: Provide cond_resched_rcu_qs() to force quiescent states in long loops") introduced cond_resched_rcu_qs(), and commit 5cd37193ce85 ("rcu: Make cond_resched_rcu_qs() apply to normal RCU flavors") introduced the per-CPU rcu_qs_ctr variable, which is frequently polled by the RCU core state machine.
This frequent polling can increase grace-period rate, which in turn increases grace-period overhead, which is visible in some benchmarks (for example, the "open1" benchmark in Anton Blanchard's "will it scale" suite). This commit therefore reduces the rate at which rcu_qs_ctr is polled by moving that polling into the force-quiescent-state (FQS) machinery, and by further polling it only after the grace period has been in effect for at least jiffies_till_sched_qs jiffies.
--- include/trace/events/rcu.h | 10 +++++----- kernel/rcu/tree.c | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 17 deletions(-)
include/trace/events/rcu.h +5 -5
@@ -385,11 +385,11 @@ TRACE_EVENT(rcu_quiescent_state_report,/* * Tracepoint for quiescent states detected by force_quiescent_state(). -* These trace events include the type of RCU, the grace-period number -* that was blocked by the CPU, the CPU itself, and the type of quiescent -* state, which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, -* or "kick" when kicking a CPU that has been in dyntick-idle mode for -* too long. +* These trace events include the type of RCU, the grace-period number that +* was blocked by the CPU, the CPU itself, and the type of quiescent state, +* which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, "kick" +* when kicking a CPU that has been in dyntick-idle mode for too long, or +* "rqc" if the CPU got a quiescent state via its rcu_qs_ctr. */ TRACE_EVENT(rcu_fqs,
kernel/rcu/tree.c +34 -12
83 lines not on this page · raw message
Signature · 1 line
2.5.2
PATCH v3 6/6 rcu: Adjust FQS offline checks for exact online-CPU detection
In reply to Paul E. McKenneyCommit 7ec99de36f40 ("rcu: Provide exact CPU-online tracking for RCU"), as its title suggests, got rid of RCU's remaining CPU-hotplug timing guesswork. This commit therefore removes the one-jiffy kludge that was used to paper over this guesswork.
--- kernel/rcu/tree.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-)
kernel/rcu/tree.c +2 -15
@@ -1276,21 +1276,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,return 1 ; } -/* -* Check for the CPU being offline, but only if the grace period -* is old enough. We don't need to worry about the CPU changing -* state: If we see it offline even once, it has been through a -* quiescent state. -* -* The reason for insisting that the grace period be at least -* one jiffy old is that CPUs that are not quite online and that -* have just gone offline can still execute RCU read-side critical -* sections. -*/ -if (ULONG_CMP_GE (rdp->rsp->gp_start +2 , jiffies)) -return 0 ;/* Grace period is not old enough. */ -barrier (); -if (cpu_is_offline (rdp->cpu)) { +/* Check for the CPU being offline. */ +if (!(rdp->grpmask &rcu_rnp_online_cpus (rnp))) {trace_rcu_fqs (rdp->rsp->name, rdp->gpnum, rdp->cpu,TPS ("ofl" )); rdp->offline_fqs++;return 1 ;
Signature · 1 line
2.5.2