|
@@ -143,6 +143,44 @@ void tick_nohz_update_jiffies(void)
|
|
|
local_irq_restore(flags);
|
|
|
}
|
|
|
|
|
|
+void tick_nohz_stop_idle(int cpu)
|
|
|
+{
|
|
|
+ struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
|
|
|
+
|
|
|
+ if (ts->idle_active) {
|
|
|
+ ktime_t now, delta;
|
|
|
+ now = ktime_get();
|
|
|
+ delta = ktime_sub(now, ts->idle_entrytime);
|
|
|
+ ts->idle_lastupdate = now;
|
|
|
+ ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
|
|
|
+ ts->idle_active = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static ktime_t tick_nohz_start_idle(int cpu)
|
|
|
+{
|
|
|
+ struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
|
|
|
+ ktime_t now, delta;
|
|
|
+
|
|
|
+ now = ktime_get();
|
|
|
+ if (ts->idle_active) {
|
|
|
+ delta = ktime_sub(now, ts->idle_entrytime);
|
|
|
+ ts->idle_lastupdate = now;
|
|
|
+ ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
|
|
|
+ }
|
|
|
+ ts->idle_entrytime = now;
|
|
|
+ ts->idle_active = 1;
|
|
|
+ return now;
|
|
|
+}
|
|
|
+
|
|
|
+u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
|
|
|
+{
|
|
|
+ struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
|
|
|
+
|
|
|
+ *last_update_time = ktime_to_us(ts->idle_lastupdate);
|
|
|
+ return ktime_to_us(ts->idle_sleeptime);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tick_nohz_stop_sched_tick - stop the idle tick from the idle task
|
|
|
*
|
|
@@ -155,13 +193,14 @@ void tick_nohz_stop_sched_tick(void)
|
|
|
unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
|
|
|
unsigned long rt_jiffies;
|
|
|
struct tick_sched *ts;
|
|
|
- ktime_t last_update, expires, now, delta;
|
|
|
+ ktime_t last_update, expires, now;
|
|
|
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
|
|
|
int cpu;
|
|
|
|
|
|
local_irq_save(flags);
|
|
|
|
|
|
cpu = smp_processor_id();
|
|
|
+ now = tick_nohz_start_idle(cpu);
|
|
|
ts = &per_cpu(tick_cpu_sched, cpu);
|
|
|
|
|
|
/*
|
|
@@ -193,19 +232,7 @@ void tick_nohz_stop_sched_tick(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- now = ktime_get();
|
|
|
- /*
|
|
|
- * When called from irq_exit we need to account the idle sleep time
|
|
|
- * correctly.
|
|
|
- */
|
|
|
- if (ts->tick_stopped) {
|
|
|
- delta = ktime_sub(now, ts->idle_entrytime);
|
|
|
- ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
|
|
|
- }
|
|
|
-
|
|
|
- ts->idle_entrytime = now;
|
|
|
ts->idle_calls++;
|
|
|
-
|
|
|
/* Read jiffies and the time when jiffies were updated last */
|
|
|
do {
|
|
|
seq = read_seqbegin(&xtime_lock);
|
|
@@ -337,23 +364,22 @@ void tick_nohz_restart_sched_tick(void)
|
|
|
int cpu = smp_processor_id();
|
|
|
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
|
|
|
unsigned long ticks;
|
|
|
- ktime_t now, delta;
|
|
|
+ ktime_t now;
|
|
|
|
|
|
- if (!ts->tick_stopped)
|
|
|
+ local_irq_disable();
|
|
|
+ tick_nohz_stop_idle(cpu);
|
|
|
+
|
|
|
+ if (!ts->tick_stopped) {
|
|
|
+ local_irq_enable();
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
/* Update jiffies first */
|
|
|
- now = ktime_get();
|
|
|
-
|
|
|
- local_irq_disable();
|
|
|
select_nohz_load_balancer(0);
|
|
|
+ now = ktime_get();
|
|
|
tick_do_update_jiffies64(now);
|
|
|
cpu_clear(cpu, nohz_cpu_mask);
|
|
|
|
|
|
- /* Account the idle time */
|
|
|
- delta = ktime_sub(now, ts->idle_entrytime);
|
|
|
- ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
|
|
|
-
|
|
|
/*
|
|
|
* We stopped the tick in idle. Update process times would miss the
|
|
|
* time we slept as update_process_times does only a 1 tick
|