Skip to content

Commit

Permalink
timer events oriented (teo)
Browse files Browse the repository at this point in the history
  • Loading branch information
CCCC-L committed Jul 20, 2024
1 parent 3cb8ad6 commit f6c875e
Show file tree
Hide file tree
Showing 13 changed files with 1,430 additions and 57 deletions.
719 changes: 719 additions & 0 deletions Documentation/admin-guide/pm/cpuidle.rst

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion arch/arm64/configs/vendor/gts7xlwifi_eur_open_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,8 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
# CONFIG_CPU_IDLE_GOV_LADDER is not set
CONFIG_CPU_IDLE_GOV_MENU=y
# CONFIG_CPU_IDLE_GOV_MENU is not set
CONFIG_CPU_IDLE_GOV_TEO=y
CONFIG_DT_IDLE_STATES=y

#
Expand Down
9 changes: 9 additions & 0 deletions drivers/cpuidle/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ config CPU_IDLE_GOV_LADDER
config CPU_IDLE_GOV_MENU
bool "Menu governor (for tickless system)"

config CPU_IDLE_GOV_TEO
bool "Timer events oriented (TEO) governor (for tickless systems)"
help
This governor implements a simplified idle state selection method
focused on timer events and does not do any interactivity boosting.

Some workloads benefit from using it and it generally should be safe
to use. Say Y here if you are not happy with the alternatives.

config DT_IDLE_STATES
bool

Expand Down
7 changes: 2 additions & 5 deletions drivers/cpuidle/cpuidle-powernv.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,10 @@ static u64 get_snooze_timeout(struct cpuidle_device *dev,
return default_snooze_timeout;

for (i = index + 1; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
struct cpuidle_state_usage *su = &dev->states_usage[i];

if (s->disabled || su->disable)
if (dev->states_usage[i].disable)
continue;

return s->target_residency * tb_ticks_per_usec;
return drv->states[i].target_residency * tb_ticks_per_usec;
}

return default_snooze_timeout;
Expand Down
16 changes: 10 additions & 6 deletions drivers/cpuidle/cpuidle.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ static int find_deepest_state(struct cpuidle_driver *drv,

for (i = 1; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
struct cpuidle_state_usage *su = &dev->states_usage[i];

if (s->disabled || su->disable || s->exit_latency <= latency_req
|| s->exit_latency > max_latency
|| (s->flags & forbidden_flags)
|| (s2idle && !s->enter_s2idle))
if (dev->states_usage[i].disable ||
s->exit_latency <= latency_req ||
s->exit_latency > max_latency ||
(s->flags & forbidden_flags) ||
(s2idle && !s->enter_s2idle))
continue;

latency_req = s->exit_latency;
Expand Down Expand Up @@ -494,12 +494,16 @@ static void __cpuidle_device_init(struct cpuidle_device *dev)
*/
static int __cpuidle_register_device(struct cpuidle_device *dev)
{
int ret;
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
int i, ret;

if (!try_module_get(drv->owner))
return -EINVAL;

for (i = 0; i < drv->state_count; i++)
if (drv->states[i].disabled)
dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;

per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices);

Expand Down
1 change: 1 addition & 0 deletions drivers/cpuidle/governors/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

obj-$(CONFIG_CPU_IDLE_GOV_LADDER) += ladder.o
obj-$(CONFIG_CPU_IDLE_GOV_MENU) += menu.o
obj-$(CONFIG_CPU_IDLE_GOV_TEO) += teo.o
25 changes: 11 additions & 14 deletions drivers/cpuidle/governors/ladder.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ struct ladder_device_state {

struct ladder_device {
struct ladder_device_state states[CPUIDLE_STATE_MAX];
int last_state_idx;
};

static DEFINE_PER_CPU(struct ladder_device, ladder_devices);
Expand All @@ -49,12 +48,13 @@ static DEFINE_PER_CPU(struct ladder_device, ladder_devices);
* @old_idx: the current state index
* @new_idx: the new target state index
*/
static inline void ladder_do_selection(struct ladder_device *ldev,
static inline void ladder_do_selection(struct cpuidle_device *dev,
struct ladder_device *ldev,
int old_idx, int new_idx)
{
ldev->states[old_idx].stats.promotion_count = 0;
ldev->states[old_idx].stats.demotion_count = 0;
ldev->last_state_idx = new_idx;
dev->last_state_idx = new_idx;
}

/**
Expand All @@ -68,13 +68,13 @@ static int ladder_select_state(struct cpuidle_driver *drv,
{
struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
struct ladder_device_state *last_state;
int last_residency, last_idx = ldev->last_state_idx;
int last_residency, last_idx = dev->last_state_idx;
int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0;
int latency_req = cpuidle_governor_latency_req(dev->cpu);

/* Special case when user has set very strict latency requirement */
if (unlikely(latency_req == 0)) {
ladder_do_selection(ldev, last_idx, 0);
ladder_do_selection(dev, ldev, last_idx, 0);
return 0;
}

Expand All @@ -84,30 +84,28 @@ static int ladder_select_state(struct cpuidle_driver *drv,

/* consider promotion */
if (last_idx < drv->state_count - 1 &&
!drv->states[last_idx + 1].disabled &&
!dev->states_usage[last_idx + 1].disable &&
last_residency > last_state->threshold.promotion_time &&
drv->states[last_idx + 1].exit_latency <= latency_req) {
last_state->stats.promotion_count++;
last_state->stats.demotion_count = 0;
if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
ladder_do_selection(ldev, last_idx, last_idx + 1);
ladder_do_selection(dev, ldev, last_idx, last_idx + 1);
return last_idx + 1;
}
}

/* consider demotion */
if (last_idx > first_idx &&
(drv->states[last_idx].disabled ||
dev->states_usage[last_idx].disable ||
(dev->states_usage[last_idx].disable ||
drv->states[last_idx].exit_latency > latency_req)) {
int i;

for (i = last_idx - 1; i > first_idx; i--) {
if (drv->states[i].exit_latency <= latency_req)
break;
}
ladder_do_selection(ldev, last_idx, i);
ladder_do_selection(dev, ldev, last_idx, i);
return i;
}

Expand All @@ -116,7 +114,7 @@ static int ladder_select_state(struct cpuidle_driver *drv,
last_state->stats.demotion_count++;
last_state->stats.promotion_count = 0;
if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) {
ladder_do_selection(ldev, last_idx, last_idx - 1);
ladder_do_selection(dev, ldev, last_idx, last_idx - 1);
return last_idx - 1;
}
}
Expand All @@ -139,7 +137,7 @@ static int ladder_enable_device(struct cpuidle_driver *drv,
struct ladder_device_state *lstate;
struct cpuidle_state *state;

ldev->last_state_idx = first_idx;
dev->last_state_idx = first_idx;

for (i = first_idx; i < drv->state_count; i++) {
state = &drv->states[i];
Expand Down Expand Up @@ -167,9 +165,8 @@ static int ladder_enable_device(struct cpuidle_driver *drv,
*/
static void ladder_reflect(struct cpuidle_device *dev, int index)
{
struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
if (index > 0)
ldev->last_state_idx = index;
dev->last_state_idx = index;
}

static struct cpuidle_governor ladder_governor = {
Expand Down
16 changes: 6 additions & 10 deletions drivers/cpuidle/governors/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@
*/

struct menu_device {
int last_state_idx;
int needs_update;
int tick_wakeup;

Expand Down Expand Up @@ -327,7 +326,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
if (drv->states[0].flags & CPUIDLE_FLAG_POLLING) {
struct cpuidle_state *s = &drv->states[1];
unsigned int polling_threshold;

/*
* Default to a physical idle state, not to busy polling, unless
* a timer is going to trigger really really soon.
Expand Down Expand Up @@ -373,9 +371,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
idx = -1;
for (i = first_idx; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
struct cpuidle_state_usage *su = &dev->states_usage[i];

if (s->disabled || su->disable)
if (dev->states_usage[i].disable)
continue;
if (idx == -1)
idx = i; /* first enabled state */
Expand Down Expand Up @@ -440,8 +437,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* tick, so try to correct that.
*/
for (i = idx - 1; i >= 0; i--) {
if (drv->states[i].disabled ||
dev->states_usage[i].disable)
if (dev->states_usage[i].disable)
continue;

idx = i;
Expand All @@ -452,9 +448,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
}

out:
data->last_state_idx = idx;
dev->last_state_idx = idx;

return data->last_state_idx;
return dev->last_state_idx;
}

/**
Expand All @@ -469,7 +465,7 @@ static void menu_reflect(struct cpuidle_device *dev, int index)
{
struct menu_device *data = this_cpu_ptr(&menu_devices);

data->last_state_idx = index;
dev->last_state_idx = index;
data->needs_update = 1;
data->tick_wakeup = tick_nohz_idle_got_tick();
}
Expand All @@ -482,7 +478,7 @@ static void menu_reflect(struct cpuidle_device *dev, int index)
static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
struct menu_device *data = this_cpu_ptr(&menu_devices);
int last_idx = data->last_state_idx;
int last_idx = dev->last_state_idx;
struct cpuidle_state *target = &drv->states[last_idx];
unsigned int measured_us;
unsigned int new_factor;
Expand Down
Loading

0 comments on commit f6c875e

Please sign in to comment.