Skip to content

Commit

Permalink
nohz: Separate idle sleeping time accounting from nohz logic
Browse files Browse the repository at this point in the history
As we plan to be able to stop the tick outside the idle task, we
need to prepare for separating nohz logic from idle. As a start,
this pulls the idle sleeping time accounting out of the tick
stop/restart API to the callers on idle entry/exit.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Alessio Igor Bogani <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Avi Kivity <[email protected]>
Cc: Chris Metcalf <[email protected]>
Cc: Christoph Lameter <[email protected]>
Cc: Daniel Lezcano <[email protected]>
Cc: Geoff Levand <[email protected]>
Cc: Gilad Ben Yossef <[email protected]>
Cc: Hakan Akkan <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Kevin Hilman <[email protected]>
Cc: Max Krasnyansky <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephen Hemminger <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Sven-Thorsten Dietrich <[email protected]>
Cc: Thomas Gleixner <[email protected]>
  • Loading branch information
fweisbec committed Jun 11, 2012
1 parent cfaf025 commit 19f5f73
Showing 1 changed file with 42 additions and 35 deletions.
77 changes: 42 additions & 35 deletions kernel/time/tick-sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,19 +271,17 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
}
EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);

static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
static void tick_nohz_stop_sched_tick(struct tick_sched *ts, ktime_t now)
{
unsigned long seq, last_jiffies, next_jiffies, delta_jiffies;
ktime_t last_update, expires, now;
ktime_t last_update, expires;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
u64 time_delta;
int cpu;

cpu = smp_processor_id();
ts = &per_cpu(tick_cpu_sched, cpu);

now = tick_nohz_start_idle(cpu, ts);

/*
* If this cpu is offline and it is the one which updates
* jiffies, then give up the assignment and let it be taken by
Expand Down Expand Up @@ -444,6 +442,14 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
ts->sleep_length = ktime_sub(dev->next_event, now);
}

static void __tick_nohz_idle_enter(struct tick_sched *ts)
{
ktime_t now;

now = tick_nohz_start_idle(smp_processor_id(), ts);
tick_nohz_stop_sched_tick(ts, now);
}

/**
* tick_nohz_idle_enter - stop the idle tick from the idle task
*
Expand Down Expand Up @@ -479,7 +485,7 @@ void tick_nohz_idle_enter(void)
* update of the idle time accounting in tick_nohz_start_idle().
*/
ts->inidle = 1;
tick_nohz_stop_sched_tick(ts);
__tick_nohz_idle_enter(ts);

local_irq_enable();
}
Expand All @@ -499,7 +505,7 @@ void tick_nohz_irq_exit(void)
if (!ts->inidle)
return;

tick_nohz_stop_sched_tick(ts);
__tick_nohz_idle_enter(ts);
}

/**
Expand Down Expand Up @@ -540,39 +546,11 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
}
}

/**
* tick_nohz_idle_exit - restart the idle tick from the idle task
*
* Restart the idle tick when the CPU is woken up from idle
* This also exit the RCU extended quiescent state. The CPU
* can use RCU again after this function is called.
*/
void tick_nohz_idle_exit(void)
static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
{
int cpu = smp_processor_id();
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
#ifndef CONFIG_VIRT_CPU_ACCOUNTING
unsigned long ticks;
#endif
ktime_t now;

local_irq_disable();

WARN_ON_ONCE(!ts->inidle);

ts->inidle = 0;

if (ts->idle_active || ts->tick_stopped)
now = ktime_get();

if (ts->idle_active)
tick_nohz_stop_idle(cpu, now);

if (!ts->tick_stopped) {
local_irq_enable();
return;
}

/* Update jiffies first */
select_nohz_load_balancer(0);
tick_do_update_jiffies64(now);
Expand Down Expand Up @@ -600,6 +578,35 @@ void tick_nohz_idle_exit(void)
ts->idle_exittime = now;

tick_nohz_restart(ts, now);
}

/**
* tick_nohz_idle_exit - restart the idle tick from the idle task
*
* Restart the idle tick when the CPU is woken up from idle
* This also exit the RCU extended quiescent state. The CPU
* can use RCU again after this function is called.
*/
void tick_nohz_idle_exit(void)
{
int cpu = smp_processor_id();
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
ktime_t now;

local_irq_disable();

WARN_ON_ONCE(!ts->inidle);

ts->inidle = 0;

if (ts->idle_active || ts->tick_stopped)
now = ktime_get();

if (ts->idle_active)
tick_nohz_stop_idle(cpu, now);

if (ts->tick_stopped)
tick_nohz_restart_sched_tick(ts, now);

local_irq_enable();
}
Expand Down

0 comments on commit 19f5f73

Please sign in to comment.