sched/idle: disable tick in idle=poll idle entry
Subsystems (2)
PATCH v3 1/1 sched/idle: disable tick in idle=poll idle entry
Commit a5183862e76fdc25f36b39c2489b816a5c66e2e5 ("tick/nohz: Conditionally restart tick on idle exit") allows a nohz_full CPU to enter idle and return from it with the scheduler tick disabled (since the tick might be undesired noise).
The idle=poll case still unconditionally restarts the tick when entering idle.
To reduce the noise for that case as well, stop the tick when entering idle, for the idle=poll case.
Change tick_nohz_full_kick_cpu to set NEED_RESCHED bit, to handle the case where a new timer is added from an interrupt. This breaks out of cpu_idle_poll and rearms the timer if necessary.
---
v3: Add comment with proper explanation (Frederic Weisbecker)
Add signed-off-by (Thomas Gleixner)
v2: Handle the case where a new timer is added from an interrupt (Frederic Weisbecker)
include/linux/sched.h | 2 ++ kernel/sched/core.c | 10 ++++++++++ kernel/sched/idle.c | 2 +- kernel/time/tick-sched.c | 7 +++++++ 4 files changed, 20 insertions(+), 1 deletion(-)
include/linux/sched.h +2 -0
@@ -2428,4 +2428,6 @@ extern void migrate_enable(void); DEFINE_LOCK_GUARD_0(migrate, migrate_disable(), migrate_enable()) +void set_tif_resched_if_polling (int cpu); +#endif
kernel/sched/core.c +10 -0
@@ -988,6 +988,11 @@ static bool set_nr_if_polling(struct task_struct *p)return true; } +void set_tif_resched_if_polling (int cpu) +{ +set_nr_if_polling (cpu_rq (cpu)->idle); +} +#else static inline bool set_nr_and_not_polling (struct thread_info *ti,int tif) {
@@ -999,6 +1004,11 @@ static inline bool set_nr_if_polling(struct task_struct *p) {return false; } + +void set_tif_resched_if_polling (int cpu) +{ +set_tsk_need_resched (cpu_rq (cpu)->idle); +}#endif static bool __wake_q_add (struct wake_q_head *head,struct task_struct *task)
kernel/sched/idle.c +1 -1
@@ -324,7 +324,7 @@ static void do_idle(void)* idle as we know that the IPI is going to arrive right away. */ if (cpu_idle_force_poll ||tick_check_broadcast_expired ()) { -tick_nohz_idle_restart_tick (); +tick_nohz_idle_stop_tick ();cpu_idle_poll (); }else {cpuidle_idle_call ();
kernel/time/tick-sched.c +7 -0
@@ -408,6 +408,13 @@ void tick_nohz_full_kick_cpu(int cpu)if (!tick_nohz_full_cpu (cpu))return ; +/* +* When idle=poll, with the tick disabled (therefore idle CPU looping +* at cpu_idle_poll), if a new timer is added from an interrupt, +* the cpu_idle_poll only exits when TIF_NEED_RESCHED gets set. +*/ +set_tif_resched_if_polling (cpu); +irq_work_queue_on (&per_cpu (nohz_full_kick_work, cpu), cpu); }
Peter Zijlstra
maintainerQuoted 3 lines · Marcelo Tosatti
Commit
a5183862e76fdc25f36b39c2489b816a5c66e2e5("tick/nohz: Conditionally restart tick on idle exit") allows
Quoting a commit usually shortens the hash to 12 charters, no?
Quoted 86 lines
a
nohz_fullCPU to enter idle and return from it with the scheduler tick disabled (since the tick might be undesired noise).The idle=poll case still unconditionally restarts the tick when entering idle.
To reduce the noise for that case as well, stop the tick when entering idle, for the idle=poll case.
Change
tick_nohz_full_kick_cputo setNEED_RESCHEDbit, to handle the case where a new timer is added from an interrupt. This breaks out ofcpu_idle_polland rearms the timer if necessary.Signed-off-by Marcelo Tosatti <[email protected]>---
v3: Add comment with proper explanation (Frederic Weisbecker)
Add signed-off-by (Thomas Gleixner)
v2: Handle the case where a new timer is added from an interrupt (Frederic Weisbecker)include/linux/sched.h | 2 ++ kernel/sched/core.c | 10 ++++++++++ kernel/sched/idle.c | 2 +- kernel/time/tick-sched.c | 7 +++++++ 4 files changed, 20 insertions(+), 1 deletion(-)include/linux/sched.h +2
-0@@ -2428,4 +2428,6 @@ extern void migrate_enable(void); DEFINE_LOCK_GUARD_0(migrate, migrate_disable(), migrate_enable()) +void set_tif_resched_if_polling (int cpu); +#endif kernel/sched/core.c +10
-0@@ -988,6 +988,11 @@ static bool set_nr_if_polling(struct task_struct *p)return true; } +void set_tif_resched_if_polling (int cpu) +{ +set_nr_if_polling (cpu_rq (cpu)->idle); +} +#else static inline bool set_nr_and_not_polling (struct thread_info *ti,int tif) {@@ -999,6 +1004,11 @@ static inline bool set_nr_if_polling(struct task_struct *p) {return false; } + +void set_tif_resched_if_polling (int cpu) +{ +set_tsk_need_resched (cpu_rq (cpu)->idle); +}#endif static bool __wake_q_add (struct wake_q_head *head,struct task_struct *task)kernel/sched/idle.c +1
-1@@ -324,7 +324,7 @@ static void do_idle(void)* idle as we know that the IPI is going to arrive right away. */ if (cpu_idle_force_poll ||tick_check_broadcast_expired ()) { -tick_nohz_idle_restart_tick (); +tick_nohz_idle_stop_tick ();cpu_idle_poll (); }else {cpuidle_idle_call ();kernel/time/tick-sched.c +0
-0@@ -408,6 +408,13 @@ void tick_nohz_full_kick_cpu(int cpu)if (!tick_nohz_full_cpu (cpu))return ;
kernel/time/tick-sched.c void tick_nohz_full_kick_cpu(int cpu) · line 419
Quoted 10 lines
kernel/time/tick-sched.c +7
-0+/* +* When idle=poll, with the tick disabled (therefore idle CPU looping +* at cpu_idle_poll), if a new timer is added from an interrupt, +* the cpu_idle_poll only exits when TIF_NEED_RESCHED gets set. +*/ +set_tif_resched_if_polling (cpu); +irq_work_queue_on (&per_cpu (nohz_full_kick_work, cpu), cpu); }
I'm confused. Why is this here and not in tick_nohz_start_idle() or something?
Quoted 94 lines · Peter Zijlstra
Quoted 3 lines · Marcelo Tosatti
Commit
a5183862e76fdc25f36b39c2489b816a5c66e2e5("tick/nohz: Conditionally restart tick on idle exit") allowsQuoting a commit usually shortens the hash to 12 charters, no?
Quoted 87 lines
a
nohz_fullCPU to enter idle and return from it with the scheduler tick disabled (since the tick might be undesired noise).The idle=poll case still unconditionally restarts the tick when entering idle.
To reduce the noise for that case as well, stop the tick when entering idle, for the idle=poll case.
Change
tick_nohz_full_kick_cputo setNEED_RESCHEDbit, to handle the case where a new timer is added from an interrupt. This breaks out ofcpu_idle_polland rearms the timer if necessary.Signed-off-by Marcelo Tosatti <[email protected]>---
v3: Add comment with proper explanation (Frederic Weisbecker)
Add signed-off-by (Thomas Gleixner)
v2: Handle the case where a new timer is added from an interrupt (Frederic Weisbecker)include/linux/sched.h | 2 ++ kernel/sched/core.c | 10 ++++++++++ kernel/sched/idle.c | 2 +- kernel/time/tick-sched.c | 7 +++++++ 4 files changed, 20 insertions(+), 1 deletion(-)include/linux/sched.h +2
-0@@ -2428,4 +2428,6 @@ extern void migrate_enable(void); DEFINE_LOCK_GUARD_0(migrate, migrate_disable(), migrate_enable()) +void set_tif_resched_if_polling (int cpu); +#endif kernel/sched/core.c +10
-0@@ -988,6 +988,11 @@ static bool set_nr_if_polling(struct task_struct *p)return true; } +void set_tif_resched_if_polling (int cpu) +{ +set_nr_if_polling (cpu_rq (cpu)->idle); +} +#else static inline bool set_nr_and_not_polling (struct thread_info *ti,int tif) {@@ -999,6 +1004,11 @@ static inline bool set_nr_if_polling(struct task_struct *p) {return false; } + +void set_tif_resched_if_polling (int cpu) +{ +set_tsk_need_resched (cpu_rq (cpu)->idle); +}#endif static bool __wake_q_add (struct wake_q_head *head,struct task_struct *task)kernel/sched/idle.c +1
-1@@ -324,7 +324,7 @@ static void do_idle(void)* idle as we know that the IPI is going to arrive right away. */ if (cpu_idle_force_poll ||tick_check_broadcast_expired ()) { -tick_nohz_idle_restart_tick (); +tick_nohz_idle_stop_tick ();cpu_idle_poll (); }else {cpuidle_idle_call ();kernel/time/tick-sched.c +0
-0@@ -408,6 +408,13 @@ void tick_nohz_full_kick_cpu(int cpu)if (!tick_nohz_full_cpu (cpu))return ;
Quoted 14 lines
kernel/time/tick-sched.c void tick_nohz_full_kick_cpu(int cpu) · line 419
Quoted 9 lines
kernel/time/tick-sched.c +7
-0+/* +* When idle=poll, with the tick disabled (therefore idle CPU looping +* at cpu_idle_poll), if a new timer is added from an interrupt, +* the cpu_idle_poll only exits when TIF_NEED_RESCHED gets set. +*/ +set_tif_resched_if_polling (cpu); +irq_work_queue_on (&per_cpu (nohz_full_kick_work, cpu), cpu); }I'm confused. Why is this here and not in
tick_nohz_start_idle()or something?
Hi Peter,
The codepath being followed is:
enqueue_timer -> trigger_dyntick_cpu -> wake_up_nohz_cpu -> wake_up_full_nohz_cpu -> tick_nohz_full_kick_cpu -> set_tif_resched_if_polling.
So we only set the PF_RESCHED bit if there is a pending timer on the CPU.
Calling unconditionally from tick_nohz_start_idle seems strange:
/**
* tick_nohz_idle_enter - prepare for entering idle on the current CPU *
* Called when we start the idle loop.
*/
void tick_nohz_idle_enter(void)
{
struct tick_sched *ts;
lockdep_assert_irqs_enabled();
local_irq_disable();
ts = this_cpu_ptr(&tick_cpu_sched);
WARN_ON_ONCE(ts->timer_expires_base);
tick_sched_flag_set(ts, TS_FLAG_INIDLE);
tick_nohz_start_idle(ts);
local_irq_enable();
}Can test for TS_FLAG_INIDLE before calling set_tif_resched_if_polling (but seems not necessary since tick_nohz_full_kick_cpu will wake up the CPU anyway and is a slow path (timer addition)).
What do you think?
Quoted 146 lines · Marcelo Tosatti
Quoted 94 lines · Peter Zijlstra
Quoted 3 lines · Marcelo Tosatti
Commit
a5183862e76fdc25f36b39c2489b816a5c66e2e5("tick/nohz: Conditionally restart tick on idle exit") allowsQuoting a commit usually shortens the hash to 12 charters, no?
Quoted 87 lines
a
nohz_fullCPU to enter idle and return from it with the scheduler tick disabled (since the tick might be undesired noise).The idle=poll case still unconditionally restarts the tick when entering idle.
To reduce the noise for that case as well, stop the tick when entering idle, for the idle=poll case.
Change
tick_nohz_full_kick_cputo setNEED_RESCHEDbit, to handle the case where a new timer is added from an interrupt. This breaks out ofcpu_idle_polland rearms the timer if necessary.Signed-off-by Marcelo Tosatti <[email protected]>---
v3: Add comment with proper explanation (Frederic Weisbecker)
Add signed-off-by (Thomas Gleixner)
v2: Handle the case where a new timer is added from an interrupt (Frederic Weisbecker)include/linux/sched.h | 2 ++ kernel/sched/core.c | 10 ++++++++++ kernel/sched/idle.c | 2 +- kernel/time/tick-sched.c | 7 +++++++ 4 files changed, 20 insertions(+), 1 deletion(-)include/linux/sched.h +2
-0@@ -2428,4 +2428,6 @@ extern void migrate_enable(void); DEFINE_LOCK_GUARD_0(migrate, migrate_disable(), migrate_enable()) +void set_tif_resched_if_polling (int cpu); +#endif kernel/sched/core.c +10
-0@@ -988,6 +988,11 @@ static bool set_nr_if_polling(struct task_struct *p)return true; } +void set_tif_resched_if_polling (int cpu) +{ +set_nr_if_polling (cpu_rq (cpu)->idle); +} +#else static inline bool set_nr_and_not_polling (struct thread_info *ti,int tif) {@@ -999,6 +1004,11 @@ static inline bool set_nr_if_polling(struct task_struct *p) {return false; } + +void set_tif_resched_if_polling (int cpu) +{ +set_tsk_need_resched (cpu_rq (cpu)->idle); +}#endif static bool __wake_q_add (struct wake_q_head *head,struct task_struct *task)kernel/sched/idle.c +1
-1@@ -324,7 +324,7 @@ static void do_idle(void)* idle as we know that the IPI is going to arrive right away. */ if (cpu_idle_force_poll ||tick_check_broadcast_expired ()) { -tick_nohz_idle_restart_tick (); +tick_nohz_idle_stop_tick ();cpu_idle_poll (); }else {cpuidle_idle_call ();kernel/time/tick-sched.c +0
-0@@ -408,6 +408,13 @@ void tick_nohz_full_kick_cpu(int cpu)if (!tick_nohz_full_cpu (cpu))return ;Quoted 14 lines
kernel/time/tick-sched.c void tick_nohz_full_kick_cpu(int cpu) · line 419
Quoted 9 lines
kernel/time/tick-sched.c +7
-0+/* +* When idle=poll, with the tick disabled (therefore idle CPU looping +* at cpu_idle_poll), if a new timer is added from an interrupt, +* the cpu_idle_poll only exits when TIF_NEED_RESCHED gets set. +*/ +set_tif_resched_if_polling (cpu); +irq_work_queue_on (&per_cpu (nohz_full_kick_work, cpu), cpu); }I'm confused. Why is this here and not in
tick_nohz_start_idle()or something?Hi Peter,
The codepath being followed is:
enqueue_timer->trigger_dyntick_cpu->wake_up_nohz_cpu->wake_up_full_nohz_cpu->tick_nohz_full_kick_cpu->set_tif_resched_if_polling.So we only set the
PF_RESCHEDbit if there is a pending timer on the CPU.Calling unconditionally from
tick_nohz_start_idleseems strange:/**
*tick_nohz_idle_enter- prepare for entering idle on the current CPU *
* Called when we start the idle loop.
*/
voidtick_nohz_idle_enter(void){ struct tick_sched *ts; lockdep_assert_irqs_enabled(); local_irq_disable(); ts = this_cpu_ptr(&tick_cpu_sched); WARN_ON_ONCE(ts->timer_expires_base); tick_sched_flag_set(ts, TS_FLAG_INIDLE); tick_nohz_start_idle(ts); local_irq_enable(); }
Quoted 5 lines
Can test for
TS_FLAG_INIDLEbefore callingset_tif_resched_if_polling(but seems not necessary sincetick_nohz_full_kick_cpuwill wake up the CPU anyway and is a slow path (timer addition)).What do you think?
OK, it looks like there are no further comments on this patch.
Frederic, Peter, Thomas, can you ACK ???
Thanks
Frederic Weisbecker
maintainerQuoted 74 lines · Marcelo Tosatti
Commit
a5183862e76fdc25f36b39c2489b816a5c66e2e5("tick/nohz: Conditionally restart tick on idle exit") allows anohz_fullCPU to enter idle and return from it with the scheduler tick disabled (since the tick might be undesired noise).The idle=poll case still unconditionally restarts the tick when entering idle.
To reduce the noise for that case as well, stop the tick when entering idle, for the idle=poll case.
Change
tick_nohz_full_kick_cputo setNEED_RESCHEDbit, to handle the case where a new timer is added from an interrupt. This breaks out ofcpu_idle_polland rearms the timer if necessary.Signed-off-by Marcelo Tosatti <[email protected]>---
v3: Add comment with proper explanation (Frederic Weisbecker)
Add signed-off-by (Thomas Gleixner)
v2: Handle the case where a new timer is added from an interrupt (Frederic Weisbecker)include/linux/sched.h | 2 ++ kernel/sched/core.c | 10 ++++++++++ kernel/sched/idle.c | 2 +- kernel/time/tick-sched.c | 7 +++++++ 4 files changed, 20 insertions(+), 1 deletion(-)include/linux/sched.h +2
-0@@ -2428,4 +2428,6 @@ extern void migrate_enable(void); DEFINE_LOCK_GUARD_0(migrate, migrate_disable(), migrate_enable()) +void set_tif_resched_if_polling (int cpu); +#endif kernel/sched/core.c +10
-0@@ -988,6 +988,11 @@ static bool set_nr_if_polling(struct task_struct *p)return true; } +void set_tif_resched_if_polling (int cpu) +{ +set_nr_if_polling (cpu_rq (cpu)->idle); +} +#else static inline bool set_nr_and_not_polling (struct thread_info *ti,int tif) {@@ -999,6 +1004,11 @@ static inline bool set_nr_if_polling(struct task_struct *p) {return false; } + +void set_tif_resched_if_polling (int cpu) +{ +set_tsk_need_resched (cpu_rq (cpu)->idle); +}#endif static bool __wake_q_add (struct wake_q_head *head,struct task_struct *task)kernel/sched/idle.c +0
-0
kernel/sched/idle.c static void do_idle(void) · line 328
Quoted 6 lines
kernel/sched/idle.c +1
-1@@ -324,7 +324,7 @@ static void do_idle(void)* idle as we know that the IPI is going to arrive right away. */ if (cpu_idle_force_poll ||tick_check_broadcast_expired ()) { -tick_nohz_idle_restart_tick (); +tick_nohz_idle_stop_tick ();cpu_idle_poll ();
I still think that the polling probably should happen in userspace rather than in kernelspace. But if we have to go down that road, the tick stop here should only happen if the CPU is nohz_full. Namely we should have tick_nohz_full_idle_stop_tick() and provide a comment why we are doing that.
Because aside nohz_full, stopping the tick here is useless and can make things worse for realtime workloads which may spend time reprogramming the tick while a high prio task is waiting for the CPU.
Thanks.
Signature · 2 lines
Frederic Weisbecker SUSE Labs