Loading drivers/cpuidle/driver.c +4 −0 Original line number Diff line number Diff line Loading @@ -181,9 +181,13 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv) */ if (s->target_residency > 0) s->target_residency_ns = s->target_residency * NSEC_PER_USEC; else if (s->target_residency_ns < 0) s->target_residency_ns = 0; if (s->exit_latency > 0) s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC; else if (s->exit_latency_ns < 0) s->exit_latency_ns = 0; } } Loading drivers/cpuidle/governors/menu.c +11 −6 Original line number Diff line number Diff line Loading @@ -271,7 +271,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, u64 predicted_ns; u64 interactivity_req; unsigned long nr_iowaiters; ktime_t delta_next; ktime_t delta, delta_tick; int i, idx; if (data->needs_update) { Loading @@ -280,7 +280,12 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } /* determine the expected residency time, round up */ data->next_timer_ns = tick_nohz_get_sleep_length(&delta_next); delta = tick_nohz_get_sleep_length(&delta_tick); if (unlikely(delta < 0)) { delta = 0; delta_tick = 0; } data->next_timer_ns = delta; nr_iowaiters = nr_iowait_cpu(dev->cpu); data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters); Loading Loading @@ -318,7 +323,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * state selection. */ if (predicted_ns < TICK_NSEC) predicted_ns = delta_next; predicted_ns = data->next_timer_ns; } else { /* * Use the performance multiplier and the user-configurable Loading Loading @@ -377,7 +382,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * stuck in the shallow one for too long. */ if (drv->states[idx].target_residency_ns < TICK_NSEC && s->target_residency_ns <= delta_next) s->target_residency_ns <= delta_tick) idx = i; return idx; Loading @@ -399,7 +404,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, predicted_ns < TICK_NSEC) && !tick_nohz_tick_stopped()) { *stop_tick = false; if (idx > 0 && drv->states[idx].target_residency_ns > delta_next) { if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick) { /* * The tick is not going to be stopped and the target * residency of the state to be returned is not within Loading @@ -411,7 +416,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, continue; idx = i; if (drv->states[i].target_residency_ns <= delta_next) if (drv->states[i].target_residency_ns <= delta_tick) break; } } Loading drivers/cpuidle/governors/teo.c +30 −24 Original line number Diff line number Diff line Loading @@ -100,8 +100,8 @@ struct teo_idle_state { * @intervals: Saved idle duration values. */ struct teo_cpu { u64 time_span_ns; u64 sleep_length_ns; s64 time_span_ns; s64 sleep_length_ns; struct teo_idle_state states[CPUIDLE_STATE_MAX]; int interval_idx; u64 intervals[INTERVALS]; Loading @@ -117,7 +117,8 @@ static DEFINE_PER_CPU(struct teo_cpu, teo_cpus); static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); int i, idx_hit = -1, idx_timer = -1; int i, idx_hit = 0, idx_timer = 0; unsigned int hits, misses; u64 measured_ns; if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { Loading Loading @@ -174,24 +175,21 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * also increase the "early hits" metric for the state that actually * matches the measured idle duration. */ if (idx_timer >= 0) { unsigned int hits = cpu_data->states[idx_timer].hits; unsigned int misses = cpu_data->states[idx_timer].misses; hits = cpu_data->states[idx_timer].hits; hits -= hits >> DECAY_SHIFT; misses = cpu_data->states[idx_timer].misses; misses -= misses >> DECAY_SHIFT; if (idx_timer > idx_hit) { if (idx_timer == idx_hit) { hits += PULSE; } else { misses += PULSE; if (idx_hit >= 0) cpu_data->states[idx_hit].early_hits += PULSE; } else { hits += PULSE; } cpu_data->states[idx_timer].misses = misses; cpu_data->states[idx_timer].hits = hits; } /* * Save idle duration values corresponding to non-timer wakeups for Loading @@ -216,7 +214,7 @@ static bool teo_time_ok(u64 interval_ns) */ static int teo_find_shallower_state(struct cpuidle_driver *drv, struct cpuidle_device *dev, int state_idx, u64 duration_ns) s64 duration_ns) { int i; Loading @@ -242,10 +240,10 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, { struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); s64 latency_req = cpuidle_governor_latency_req(dev->cpu); u64 duration_ns; int max_early_idx, prev_max_early_idx, constraint_idx, idx0, idx, i; unsigned int hits, misses, early_hits; int max_early_idx, prev_max_early_idx, constraint_idx, idx, i; ktime_t delta_tick; s64 duration_ns; if (dev->last_state_idx >= 0) { teo_update(drv, dev); Loading @@ -264,6 +262,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, prev_max_early_idx = -1; constraint_idx = drv->state_count; idx = -1; idx0 = idx; for (i = 0; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; Loading Loading @@ -324,6 +323,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, idx = i; /* first enabled state */ hits = cpu_data->states[i].hits; misses = cpu_data->states[i].misses; idx0 = i; } if (s->target_residency_ns > duration_ns) Loading Loading @@ -376,11 +376,16 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, if (idx < 0) { idx = 0; /* No states enabled. Must use 0. */ } else if (idx > 0) { } else if (idx > idx0) { unsigned int count = 0; u64 sum = 0; /* * The target residencies of at least two different enabled idle * states are less than or equal to the current expected idle * duration. Try to refine the selection using the most recent * measured idle duration values. * * Count and sum the most recent idle duration values less than * the current expected idle duration value. */ Loading Loading @@ -428,7 +433,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * till the closest timer including the tick, try to correct * that. */ if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick) if (idx > idx0 && drv->states[idx].target_residency_ns > delta_tick) idx = teo_find_shallower_state(drv, dev, idx, delta_tick); } Loading drivers/idle/intel_idle.c +3 −2 Original line number Diff line number Diff line Loading @@ -744,8 +744,8 @@ static struct cpuidle_state icx_cstates[] __initdata = { .name = "C6", .desc = "MWAIT 0x20", .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 128, .target_residency = 384, .exit_latency = 170, .target_residency = 600, .enter = &intel_idle, .enter_s2idle = intel_idle_s2idle, }, { Loading Loading @@ -1156,6 +1156,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &idle_cpu_skl), X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &idle_cpu_skx), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &idle_cpu_icx), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &idle_cpu_icx), X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &idle_cpu_knl), X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &idle_cpu_knl), X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &idle_cpu_bxt), Loading include/linux/cpuidle.h +2 −2 Original line number Diff line number Diff line Loading @@ -49,8 +49,8 @@ struct cpuidle_state { char name[CPUIDLE_NAME_LEN]; char desc[CPUIDLE_DESC_LEN]; u64 exit_latency_ns; u64 target_residency_ns; s64 exit_latency_ns; s64 target_residency_ns; unsigned int flags; unsigned int exit_latency; /* in US */ int power_usage; /* in mW */ Loading Loading
drivers/cpuidle/driver.c +4 −0 Original line number Diff line number Diff line Loading @@ -181,9 +181,13 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv) */ if (s->target_residency > 0) s->target_residency_ns = s->target_residency * NSEC_PER_USEC; else if (s->target_residency_ns < 0) s->target_residency_ns = 0; if (s->exit_latency > 0) s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC; else if (s->exit_latency_ns < 0) s->exit_latency_ns = 0; } } Loading
drivers/cpuidle/governors/menu.c +11 −6 Original line number Diff line number Diff line Loading @@ -271,7 +271,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, u64 predicted_ns; u64 interactivity_req; unsigned long nr_iowaiters; ktime_t delta_next; ktime_t delta, delta_tick; int i, idx; if (data->needs_update) { Loading @@ -280,7 +280,12 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } /* determine the expected residency time, round up */ data->next_timer_ns = tick_nohz_get_sleep_length(&delta_next); delta = tick_nohz_get_sleep_length(&delta_tick); if (unlikely(delta < 0)) { delta = 0; delta_tick = 0; } data->next_timer_ns = delta; nr_iowaiters = nr_iowait_cpu(dev->cpu); data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters); Loading Loading @@ -318,7 +323,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * state selection. */ if (predicted_ns < TICK_NSEC) predicted_ns = delta_next; predicted_ns = data->next_timer_ns; } else { /* * Use the performance multiplier and the user-configurable Loading Loading @@ -377,7 +382,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * stuck in the shallow one for too long. */ if (drv->states[idx].target_residency_ns < TICK_NSEC && s->target_residency_ns <= delta_next) s->target_residency_ns <= delta_tick) idx = i; return idx; Loading @@ -399,7 +404,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, predicted_ns < TICK_NSEC) && !tick_nohz_tick_stopped()) { *stop_tick = false; if (idx > 0 && drv->states[idx].target_residency_ns > delta_next) { if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick) { /* * The tick is not going to be stopped and the target * residency of the state to be returned is not within Loading @@ -411,7 +416,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, continue; idx = i; if (drv->states[i].target_residency_ns <= delta_next) if (drv->states[i].target_residency_ns <= delta_tick) break; } } Loading
drivers/cpuidle/governors/teo.c +30 −24 Original line number Diff line number Diff line Loading @@ -100,8 +100,8 @@ struct teo_idle_state { * @intervals: Saved idle duration values. */ struct teo_cpu { u64 time_span_ns; u64 sleep_length_ns; s64 time_span_ns; s64 sleep_length_ns; struct teo_idle_state states[CPUIDLE_STATE_MAX]; int interval_idx; u64 intervals[INTERVALS]; Loading @@ -117,7 +117,8 @@ static DEFINE_PER_CPU(struct teo_cpu, teo_cpus); static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); int i, idx_hit = -1, idx_timer = -1; int i, idx_hit = 0, idx_timer = 0; unsigned int hits, misses; u64 measured_ns; if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { Loading Loading @@ -174,24 +175,21 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * also increase the "early hits" metric for the state that actually * matches the measured idle duration. */ if (idx_timer >= 0) { unsigned int hits = cpu_data->states[idx_timer].hits; unsigned int misses = cpu_data->states[idx_timer].misses; hits = cpu_data->states[idx_timer].hits; hits -= hits >> DECAY_SHIFT; misses = cpu_data->states[idx_timer].misses; misses -= misses >> DECAY_SHIFT; if (idx_timer > idx_hit) { if (idx_timer == idx_hit) { hits += PULSE; } else { misses += PULSE; if (idx_hit >= 0) cpu_data->states[idx_hit].early_hits += PULSE; } else { hits += PULSE; } cpu_data->states[idx_timer].misses = misses; cpu_data->states[idx_timer].hits = hits; } /* * Save idle duration values corresponding to non-timer wakeups for Loading @@ -216,7 +214,7 @@ static bool teo_time_ok(u64 interval_ns) */ static int teo_find_shallower_state(struct cpuidle_driver *drv, struct cpuidle_device *dev, int state_idx, u64 duration_ns) s64 duration_ns) { int i; Loading @@ -242,10 +240,10 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, { struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); s64 latency_req = cpuidle_governor_latency_req(dev->cpu); u64 duration_ns; int max_early_idx, prev_max_early_idx, constraint_idx, idx0, idx, i; unsigned int hits, misses, early_hits; int max_early_idx, prev_max_early_idx, constraint_idx, idx, i; ktime_t delta_tick; s64 duration_ns; if (dev->last_state_idx >= 0) { teo_update(drv, dev); Loading @@ -264,6 +262,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, prev_max_early_idx = -1; constraint_idx = drv->state_count; idx = -1; idx0 = idx; for (i = 0; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; Loading Loading @@ -324,6 +323,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, idx = i; /* first enabled state */ hits = cpu_data->states[i].hits; misses = cpu_data->states[i].misses; idx0 = i; } if (s->target_residency_ns > duration_ns) Loading Loading @@ -376,11 +376,16 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, if (idx < 0) { idx = 0; /* No states enabled. Must use 0. */ } else if (idx > 0) { } else if (idx > idx0) { unsigned int count = 0; u64 sum = 0; /* * The target residencies of at least two different enabled idle * states are less than or equal to the current expected idle * duration. Try to refine the selection using the most recent * measured idle duration values. * * Count and sum the most recent idle duration values less than * the current expected idle duration value. */ Loading Loading @@ -428,7 +433,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * till the closest timer including the tick, try to correct * that. */ if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick) if (idx > idx0 && drv->states[idx].target_residency_ns > delta_tick) idx = teo_find_shallower_state(drv, dev, idx, delta_tick); } Loading
drivers/idle/intel_idle.c +3 −2 Original line number Diff line number Diff line Loading @@ -744,8 +744,8 @@ static struct cpuidle_state icx_cstates[] __initdata = { .name = "C6", .desc = "MWAIT 0x20", .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 128, .target_residency = 384, .exit_latency = 170, .target_residency = 600, .enter = &intel_idle, .enter_s2idle = intel_idle_s2idle, }, { Loading Loading @@ -1156,6 +1156,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &idle_cpu_skl), X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &idle_cpu_skx), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &idle_cpu_icx), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &idle_cpu_icx), X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &idle_cpu_knl), X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &idle_cpu_knl), X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &idle_cpu_bxt), Loading
include/linux/cpuidle.h +2 −2 Original line number Diff line number Diff line Loading @@ -49,8 +49,8 @@ struct cpuidle_state { char name[CPUIDLE_NAME_LEN]; char desc[CPUIDLE_DESC_LEN]; u64 exit_latency_ns; u64 target_residency_ns; s64 exit_latency_ns; s64 target_residency_ns; unsigned int flags; unsigned int exit_latency; /* in US */ int power_usage; /* in mW */ Loading