ksoftirqd: Enable IRQs and call cond_resched() before poking RCU
PATCH 1/1 ksoftirqd: Enable IRQs and call cond_resched() before poking RCU
While debugging an issue with excessive softirq usage, I encountered the following note in commit 3e339b5dae24a706 ("softirq: Use hotplug thread infrastructure"):
[ paulmck: Call rcu_note_context_switch() with interrupts enabled. ]
...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to rcu_note_context_switch() after the cond_sched() call, as it was originally before the hotplug patch, completely eliminated this problem.
--- kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/softirq.c +5 -1
@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (cpu); +preempt_enable (); +return ; }local_irq_enable ();
Signature · 1 line
2.1.1
PATCH v2 1/1 ksoftirqd: Enable IRQs and call cond_resched() before poking RCU
While debugging an issue with excessive softirq usage, I encountered the following note in commit 3e339b5dae24a706 ("softirq: Use hotplug thread infrastructure"):
[ paulmck: Call rcu_note_context_switch() with interrupts enabled. ]
...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to rcu_note_context_switch() after the cond_sched() call, as it was originally before the hotplug patch, completely eliminated this problem.
---
Changes since v1:
I mixed up the kernel versions I was patching against, sorry!
kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/softirq.c +5 -1
@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (); +preempt_enable (); +return ; }local_irq_enable ();
Signature · 1 line
2.1.1
Quoted 30 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>---
Changes since v1:
I mixed up the kernel versions I was patching against, sorry!kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +0
-0
kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 660
Quoted 6 lines
kernel/softirq.c +0
-1@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable ();cond_resched ();
If this is for 3.20, we can just replace cond_resched() with cond_resched_rcu_qs(), and get rid of the direct call to rcu_note_context_switch(). This has the benefit of avoiding needless rcu_note_context_switch() overhead if cond_resched() actually did a reschedule.
But don't try it in 3.19 or earlier. ;-)
Thanx, Paul
Quoted 11 lines
kernel/softirq.c +5
-0+ +preempt_disable (); +rcu_note_context_switch (); +preempt_enable (); +return ; }local_irq_enable ();Signature · 1 line
2.1.1
Quoted 44 lines · Paul E. McKenney
Quoted 30 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>---
Changes since v1:
I mixed up the kernel versions I was patching against, sorry!kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +0
-0kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 660
Quoted 6 lines
kernel/softirq.c +0
-1@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable ();cond_resched ();If this is for 3.20, we can just replace
cond_resched()withcond_resched_rcu_qs(), and get rid of the direct call torcu_note_context_switch(). This has the benefit of avoiding needlessrcu_note_context_switch()overhead ifcond_resched()actually did a reschedule.
Quoted 1 line
But don't try it in 3.19 or earlier. ;-)
As in the following for 3.20. Does this version work for you?
Thanx, Paul
------------------------------------------------------------------------
ksoftirqd: Enable IRQs and call cond_resched() before poking RCU
While debugging an issue with excessive softirq usage, I encountered the following note in commit 3e339b5dae24a706 ("softirq: Use hotplug thread infrastructure"):
[ paulmck: Call rcu_note_context_switch() with interrupts enabled. ]
...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to rcu_note_context_switch() after the cond_sched() call, as it was originally before the hotplug patch, completely eliminated this problem, but the new cond_resched_rcu_qs() provides shorter code and avoids double RCU notification in the case where cond_resched() really did a context switch.
kernel/softirq.c +1 -2
@@ -656,9 +656,8 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable (); -cond_resched (); +cond_resched_rcu_qs ();return ; }local_irq_enable ();
Quoted 45 lines · Paul E. McKenney
Quoted 44 lines · Paul E. McKenney
Quoted 30 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>---
Changes since v1:
I mixed up the kernel versions I was patching against, sorry!kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +0
-0kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 660
Quoted 6 lines
kernel/softirq.c +0
-1@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable ();cond_resched ();If this is for 3.20, we can just replace
cond_resched()withcond_resched_rcu_qs(), and get rid of the direct call torcu_note_context_switch(). This has the benefit of avoiding needlessrcu_note_context_switch()overhead ifcond_resched()actually did a reschedule.
Quoted 3 lines
Quoted 1 line
But don't try it in 3.19 or earlier. ;-)
As in the following for 3.20. Does this version work for you?
That's great, thanks :)
Should this go to stable as well? It is technically a regression, albeit a rather long-standing one.
My original scenario was a bit contrived, but I tested this on some real loads and it makes a difference: on a heavily loaded Proxygen server, the aggregate softirq CPU usage decreases by roughly 10% (relative) given the same amount of traffic with the patch. It also produces statistically significant performance wins at higher loads on
webservers: about a 1% reduction in overall CPU utilization and improved latency metrics.
Thanks,
Calvin
Quoted 45 lines
Thanx, Paul
------------------------------------------------------------------------
ksoftirqd: Enable IRQs and call
cond_resched()before poking RCUWhile debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem, but the newcond_resched_rcu_qs()provides shorter code and avoids double RCU notification in the case wherecond_resched()really did a context switch.Signed-off-by Calvin Owens <[email protected]>[ paulmck: Substituted shiny new cond_resched_rcu_qs() primitive. ]Signed-off-by Paul E. McKenney <[email protected]>kernel/softirq.c +1
-2@@ -656,9 +656,8 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable (); -cond_resched (); +cond_resched_rcu_qs ();return ; }local_irq_enable ();
Quoted 46 lines · Calvin Owens
Quoted 45 lines · Paul E. McKenney
Quoted 44 lines · Paul E. McKenney
Quoted 30 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>---
Changes since v1:
I mixed up the kernel versions I was patching against, sorry!kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +0
-0kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 660
Quoted 6 lines
kernel/softirq.c +0
-1@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable ();cond_resched ();If this is for 3.20, we can just replace
cond_resched()withcond_resched_rcu_qs(), and get rid of the direct call torcu_note_context_switch(). This has the benefit of avoiding needlessrcu_note_context_switch()overhead ifcond_resched()actually did a reschedule.
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
But don't try it in 3.19 or earlier. ;-)
As in the following for 3.20. Does this version work for you?
That's great, thanks :)
Should this go to stable as well? It is technically a regression, albeit a rather long-standing one.
Your original patch could go into stable, but my updated version depends on functionality not present before 3.20.
Quoted 7 lines
My original scenario was a bit contrived, but I tested this on some real loads and it makes a difference: on a heavily loaded Proxygen server, the aggregate softirq CPU usage decreases by roughly 10% (relative) given the same amount of traffic with the patch. It also produces statistically significant performance wins at higher loads on
webservers: about a 1% reduction in overall CPU utilization and improved latency metrics.
OK, good to know. I have added this information to the commit log, please see below for updated commit.
Thanx, Paul
------------------------------------------------------------------------
ksoftirqd: Enable IRQs and call cond_resched() before poking RCU
While debugging an issue with excessive softirq usage, I encountered the following note in commit 3e339b5dae24a706 ("softirq: Use hotplug thread infrastructure"):
[ paulmck: Call rcu_note_context_switch() with interrupts enabled. ]
...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%. On a heavily loaded Proxygen server, the aggregate softirq CPU usage decreases by roughly 10% (relative) given the same amount of traffic with the patch. It also produces statistically significant performance wins at higher loads on webservers: about a 1% reduction in overall CPU utilization and improved latency metrics.
Moving the call to rcu_note_context_switch() after the cond_sched() call, as it was originally before the hotplug patch, completely eliminated this problem, but the new cond_resched_rcu_qs() provides shorter code and avoids double RCU notification in the case where cond_resched() really did a context switch.
kernel/softirq.c +1 -2
@@ -656,9 +656,8 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable (); -cond_resched (); +cond_resched_rcu_qs ();return ; }local_irq_enable ();
Quoted 51 lines · Paul E. McKenney
Quoted 50 lines · Calvin Owens
Quoted 48 lines · Paul E. McKenney
Quoted 44 lines · Paul E. McKenney
Quoted 30 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>---
Changes since v1:
I mixed up the kernel versions I was patching against, sorry!kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +0
-0kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 660
Quoted 6 lines
kernel/softirq.c +0
-1@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable ();cond_resched ();If this is for 3.20, we can just replace
cond_resched()withcond_resched_rcu_qs(), and get rid of the direct call torcu_note_context_switch(). This has the benefit of avoiding needlessrcu_note_context_switch()overhead ifcond_resched()actually did a reschedule.Quoted 1 line
But don't try it in 3.19 or earlier. ;-)
As in the following for 3.20. Does this version work for you?
Quoted 7 lines
Quoted 4 lines
That's great, thanks :)
Should this go to stable as well? It is technically a regression, albeit a rather long-standing one.
Your original patch could go into stable, but my updated version depends on functionality not present before 3.20.
Right. I'll wait until 3.20-rc1, and then I'll send the original to stable with a reference to the commit.
Quoted 10 lines
Quoted 7 lines
My original scenario was a bit contrived, but I tested this on some real loads and it makes a difference: on a heavily loaded Proxygen server, the aggregate softirq CPU usage decreases by roughly 10% (relative) given the same amount of traffic with the patch. It also produces statistically significant performance wins at higher loads on
webservers: about a 1% reduction in overall CPU utilization and improved latency metrics.OK, good to know. I have added this information to the commit log, please see below for updated commit.
Looks good!
Thanks,
Calvin
Quoted 51 lines
Thanx, Paul
------------------------------------------------------------------------
ksoftirqd: Enable IRQs and call
cond_resched()before poking RCUWhile debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%. On a heavily loaded Proxygen server, the aggregate softirq CPU usage decreases by roughly 10% (relative) given the same amount of traffic with the patch. It also produces statistically significant performance wins at higher loads on webservers: about a 1% reduction in overall CPU utilization and improved latency metrics.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem, but the newcond_resched_rcu_qs()provides shorter code and avoids double RCU notification in the case wherecond_resched()really did a context switch.Signed-off-by Calvin Owens <[email protected]>[ paulmck: Substituted shiny new cond_resched_rcu_qs() primitive. ]Signed-off-by Paul E. McKenney <[email protected]>[ paulmck: Added Calvin's measurements on Proxygen server and webservers. ]kernel/softirq.c +1
-2@@ -656,9 +656,8 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch ();local_irq_enable (); -cond_resched (); +cond_resched_rcu_qs ();return ; }local_irq_enable ();
Quoted 9 lines · Calvin Owens
Quoted 5 lines · Paul E. McKenney
Quoted 2 lines
Should this go to stable as well? It is technically a regression, albeit a rather long-standing one.
Your original patch could go into stable, but my updated version depends on functionality not present before 3.20.
Right. I'll wait until 3.20-rc1, and then I'll send the original to stable with a reference to the commit.
We better do that in two steps:
1) The original patch tagged for stable
2) Pauls version as a delta patch
Can one of you please provide such a series?
Thanks,
tglx
Quoted 11 lines · Thomas Gleixner
Quoted 9 lines · Calvin Owens
Quoted 5 lines · Paul E. McKenney
Quoted 2 lines
Should this go to stable as well? It is technically a regression, albeit a rather long-standing one.
Your original patch could go into stable, but my updated version depends on functionality not present before 3.20.
Right. I'll wait until 3.20-rc1, and then I'll send the original to stable with a reference to the commit.
Quoted 6 lines
We better do that in two steps:
1) The original patch tagged for stable
2) Pauls version as a delta patchCan one of you please provide such a series?
Carl, could you please send me the original with the proper -stable reference? I will then queue that one and rebase mine on top of it.
Thanx, Paul
PATCH 1/1 ksoftirqd: Enable IRQs and call cond_resched() before poking RCU
While debugging an issue with excessive softirq usage, I encountered the following note in commit 3e339b5dae24a706 ("softirq: Use hotplug thread infrastructure"):
[ paulmck: Call rcu_note_context_switch() with interrupts enabled. ]
...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to rcu_note_context_switch() after the cond_sched() call, as it was originally before the hotplug patch, completely eliminated this problem.
---
This version includes the "cpu" argument to rcu_note_context_switch() in order to apply cleanly to stable kernels. It will need to be removed to apply to 3.18+ and 3.19 (upstream commit 38200cf2 removed the argument).
kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/softirq.c +5 -1
@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch (cpu);local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (cpu); +preempt_enable (); +return ; }local_irq_enable ();
Signature · 1 line
2.1.1
Paul E. McKenney
AppliedQuoted 13 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Quoted 6 lines
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>
Applied, thank you! I deleted the "cpu" arguments from the calls to rcu_note_context_switch() below in order for the patch to apply.
I the put the patch following that on top, as Thomas suggested.
Thanx, Paul
Quoted 29 lines
---
This version includes the "cpu" argument torcu_note_context_switch()in order to apply cleanly to stable kernels. It will need to be removed to apply to 3.18+ and 3.19 (upstream commit38200cf2removed the argument).kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +5
-1@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. */ __do_softirq (); -rcu_note_context_switch (cpu);local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (cpu); +preempt_enable (); +return ; }local_irq_enable ();Signature · 1 line
2.1.1
------------------------------------------------------------------------
ksoftirqd: Use new cond_resched_rcu_qs() function
Simplify run_ksoftirqd() by using the new cond_resched_rcu_qs() function that conditionally reschedules, but unconditionally supplies an RCU quiescent state. This commit is separate from the previous commit by Calvin Owens because Calvin's approach can be backported, while this commit cannot be. The reason that this commit cannot be backported is that cond_resched_rcu_qs() does not always provide the needed quiescent state in earlier kernels.
kernel/softirq.c +1 -6
@@ -657,12 +657,7 @@ static void run_ksoftirqd(unsigned int cpu)*/ __do_softirq ();local_irq_enable (); -cond_resched (); - -preempt_disable (); -rcu_note_context_switch (); -preempt_enable (); - +cond_resched_rcu_qs ();return ; }local_irq_enable ();
Quoted 33 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>---
This version includes the "cpu" argument torcu_note_context_switch()in order to apply cleanly to stable kernels. It will need to be removed to apply to 3.18+ and 3.19 (upstream commit38200cf2removed the argument).kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +0
-0@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here.
kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 665
Quoted 10 lines
kernel/softirq.c +5
-1*/ __do_softirq (); -rcu_note_context_switch (cpu);local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (cpu); +preempt_enable (); +
The whole rcu_note_context_switch() in run_ksoftirqd() is silly.
cond_resched() __preempt_count_add(PREEMPT_ACTIVE); __schedule(); preempt_disable(); rcu_note_context_switch(); .... __preempt_count_sub(PREEMPT_ACTIVE);
Thanks,
tglx
Quoted 48 lines · Thomas Gleixner
Quoted 33 lines · Calvin Owens
While debugging an issue with excessive softirq usage, I encountered the following note in commit
3e339b5dae24a706("softirq: Use hotplug thread infrastructure"):[ paulmck: Call
rcu_note_context_switch()with interrupts enabled. ]...but despite this note, the patch still calls RCU with IRQs disabled.
This seemingly innocuous change caused a significant regression in softirq CPU usage on the sending side of a large TCP transfer (~1 GB/s): when introducing 0.01% packet loss, the softirq usage would jump to around 25%, spiking as high as 50%. Before the change, the usage would never exceed 5%.
Moving the call to
rcu_note_context_switch()after thecond_sched()call, as it was originally before the hotplug patch, completely eliminated this problem.Signed-off-by Calvin Owens <[email protected]>---
This version includes the "cpu" argument torcu_note_context_switch()in order to apply cleanly to stable kernels. It will need to be removed to apply to 3.18+ and 3.19 (upstream commit38200cf2removed the argument).kernel/softirq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/softirq.c +0
-0@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 665
Quoted 10 lines
kernel/softirq.c +5
-1*/ __do_softirq (); -rcu_note_context_switch (cpu);local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (cpu); +preempt_enable (); +The whole
rcu_note_context_switch()inrun_ksoftirqd()is silly.
Quoted 9 lines
cond_resched() __preempt_count_add(PREEMPT_ACTIVE); __schedule(); preempt_disable(); rcu_note_context_switch(); .... __preempt_count_sub(PREEMPT_ACTIVE);
I agree that if should_resched() returns true as assumed above, then there is no point to invoking rcu_note_context_switch(). However, the case that this code applies to is when should_resched() returns false, but RCU is waiting for a quiescent state from the current CPU. In that case, cond_resched() won't do anything for RCU, and we do need the rcu_note_context_switch().
Of course, it would be better to avoid the extra RCU work in the common case where cond_resched() does inovke the scheduler. And that is the point of the following patch, which uses cond_resched_rcu_qs(). However, this use of cond_resched_rcu_qs() doesn't work in older kernels. So Calvin's patch is for backporting, and the follow-up patch for future kernels.
Make sense, or am I missing something?
Thanx, Paul
Quoted 29 lines · Paul E. McKenney
Quoted 27 lines · Thomas Gleixner
Quoted 6 lines
kernel/softirq.c +0
-0@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 665
Quoted 10 lines
kernel/softirq.c +5
-1*/ __do_softirq (); -rcu_note_context_switch (cpu);local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (cpu); +preempt_enable (); +The whole
rcu_note_context_switch()inrun_ksoftirqd()is silly.cond_resched() __preempt_count_add(PREEMPT_ACTIVE); __schedule(); preempt_disable(); rcu_note_context_switch(); ....
Quoted 8 lines
Quoted 1 line
__preempt_count_sub(PREEMPT_ACTIVE);I agree that if
should_resched()returns true as assumed above, then there is no point to invokingrcu_note_context_switch(). However, the case that this code applies to is whenshould_resched()returns false, but RCU is waiting for a quiescent state from the current CPU. In that case,cond_resched()won't do anything for RCU, and we do need thercu_note_context_switch().
I've been curious about this for ages, so now is a great time to bite the bullet and ask TheMan. A context switch is not far away, why do we need that quiescent state badly enough to tell what looks like a little white lie to get it immediately?
(I commented it out in an -rt kernel I was testing yesterday, beat it enthusiastically for a while, and box didn't _seem_ to notice that it was missing anything)
-Mike
Quoted 39 lines · Mike Galbraith
Quoted 29 lines · Paul E. McKenney
Quoted 27 lines · Thomas Gleixner
Quoted 6 lines
kernel/softirq.c +0
-0@@ -656,9 +656,13 @@ static void run_ksoftirqd(unsigned int cpu)* in the task stack here. kernel/softirq.c static void run_ksoftirqd(unsigned int cpu) · line 665
Quoted 10 lines
kernel/softirq.c +5
-1*/ __do_softirq (); -rcu_note_context_switch (cpu);local_irq_enable ();cond_resched (); + +preempt_disable (); +rcu_note_context_switch (cpu); +preempt_enable (); +The whole
rcu_note_context_switch()inrun_ksoftirqd()is silly.cond_resched() __preempt_count_add(PREEMPT_ACTIVE); __schedule(); preempt_disable(); rcu_note_context_switch(); ....Quoted 8 lines
Quoted 1 line
__preempt_count_sub(PREEMPT_ACTIVE);I agree that if
should_resched()returns true as assumed above, then there is no point to invokingrcu_note_context_switch(). However, the case that this code applies to is whenshould_resched()returns false, but RCU is waiting for a quiescent state from the current CPU. In that case,cond_resched()won't do anything for RCU, and we do need thercu_note_context_switch().
Quoted 8 lines
I've been curious about this for ages, so now is a great time to bite the bullet and ask TheMan. A context switch is not far away, why do we need that quiescent state badly enough to tell what looks like a little white lie to get it immediately?
(I commented it out in an -rt kernel I was testing yesterday, beat it enthusiastically for a while, and box didn't _seem_ to notice that it was missing anything)
Yeah, you do have to have a fairly violent network-based DoS attack to see the difference. Robert Olsson was the first to make this happen back in the day.
Thanx, Paul
Quoted 7 lines · Paul E. McKenney
Quoted 5 lines · Mike Galbraith
I've been curious about this for ages, so now is a great time to bite the bullet and ask TheMan. A context switch is not far away, why do we need that quiescent state badly enough to tell what looks like a little white lie to get it immediately?
Quoted 7 lines
Quoted 3 lines
(I commented it out in an -rt kernel I was testing yesterday, beat it enthusiastically for a while, and box didn't _seem_ to notice that it was missing anything)
Yeah, you do have to have a fairly violent network-based DoS attack to see the difference. Robert Olsson was the first to make this happen back in the day.
Ah, my little NIC doesn't have enough poop to do that. Thanks.
-Mike
Quoted 11 lines · Paul E. McKenney
Quoted 10 lines · Thomas Gleixner
The whole
rcu_note_context_switch()inrun_ksoftirqd()is silly.cond_resched() __preempt_count_add(PREEMPT_ACTIVE); __schedule(); preempt_disable(); rcu_note_context_switch(); ....
Quoted 8 lines
Quoted 1 line
__preempt_count_sub(PREEMPT_ACTIVE);I agree that if
should_resched()returns true as assumed above, then there is no point to invokingrcu_note_context_switch(). However, the case that this code applies to is whenshould_resched()returns false, but RCU is waiting for a quiescent state from the current CPU. In that case,cond_resched()won't do anything for RCU, and we do need thercu_note_context_switch().
So this should be:
if (!cond_resched())
rcu_note_context_switch();Hmm?
Quoted 6 lines
Of course, it would be better to avoid the extra RCU work in the common case where
cond_resched()does inovke the scheduler. And that is the point of the following patch, which usescond_resched_rcu_qs(). However, this use ofcond_resched_rcu_qs()doesn't work in older kernels. So Calvin's patch is for backporting, and the follow-up patch for future kernels.
I see.
Thanks,
tglx
Quoted 21 lines · Thomas Gleixner
Quoted 11 lines · Paul E. McKenney
Quoted 10 lines · Thomas Gleixner
The whole
rcu_note_context_switch()inrun_ksoftirqd()is silly.cond_resched() __preempt_count_add(PREEMPT_ACTIVE); __schedule(); preempt_disable(); rcu_note_context_switch(); ....Quoted 8 lines
Quoted 1 line
__preempt_count_sub(PREEMPT_ACTIVE);I agree that if
should_resched()returns true as assumed above, then there is no point to invokingrcu_note_context_switch(). However, the case that this code applies to is whenshould_resched()returns false, but RCU is waiting for a quiescent state from the current CPU. In that case,cond_resched()won't do anything for RCU, and we do need thercu_note_context_switch().
Quoted 3 lines
So this should be:
if (!cond_resched()) {
preempt_disable();
Quoted 1 line
rcu_note_context_switch();
preempt_enable();
}Quoted 2 lines
Hmm?
Going forward, yes, and cond_resched_rcu_qs() in fact does something very similar. For backporting, which is what this patch is for, we are preserving the same double-quiescent-state behavior that existed earlier, meaning minimal perturbation of old releases.
Seem reasonable, or do you really feel strongly about pushing this optimization into -stable?
Quoted 8 lines
Quoted 6 lines
Of course, it would be better to avoid the extra RCU work in the common case where
cond_resched()does inovke the scheduler. And that is the point of the following patch, which usescond_resched_rcu_qs(). However, this use ofcond_resched_rcu_qs()doesn't work in older kernels. So Calvin's patch is for backporting, and the follow-up patch for future kernels.I see.
Thanx, Paul
Quoted 32 lines · Paul E. McKenney
Quoted 21 lines · Thomas Gleixner
Quoted 11 lines · Paul E. McKenney
Quoted 10 lines · Thomas Gleixner
The whole
rcu_note_context_switch()inrun_ksoftirqd()is silly.cond_resched() __preempt_count_add(PREEMPT_ACTIVE); __schedule(); preempt_disable(); rcu_note_context_switch(); ....Quoted 8 lines
Quoted 1 line
__preempt_count_sub(PREEMPT_ACTIVE);I agree that if
should_resched()returns true as assumed above, then there is no point to invokingrcu_note_context_switch(). However, the case that this code applies to is whenshould_resched()returns false, but RCU is waiting for a quiescent state from the current CPU. In that case,cond_resched()won't do anything for RCU, and we do need thercu_note_context_switch().Quoted 3 lines
So this should be:
if (!cond_resched()) {preempt_disable();Quoted 1 line
rcu_note_context_switch();preempt_enable(); }Quoted 2 lines
Hmm?
Quoted 7 lines
Going forward, yes, and
cond_resched_rcu_qs()in fact does something very similar. For backporting, which is what this patch is for, we are preserving the same double-quiescent-state behavior that existed earlier, meaning minimal perturbation of old releases.Seem reasonable, or do you really feel strongly about pushing this optimization into -stable?
No.
Thanks,
tglx