Merge pull request #12383 from davidgfnet/cpufreq2

CPU governor/frequency part 2
This commit is contained in:
Autechre 2021-05-12 09:17:42 +02:00 committed by GitHub
commit e430f832cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 691 additions and 26 deletions

View File

@ -1279,6 +1279,10 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
SETTING_ARRAY("discord_app_id", settings->arrays.discord_app_id, true, DEFAULT_DISCORD_APP_ID, true);
SETTING_ARRAY("ai_service_url", settings->arrays.ai_service_url, true, DEFAULT_AI_SERVICE_URL, true);
SETTING_ARRAY("crt_switch_timings", settings->arrays.crt_switch_timings, false, NULL, true);
#ifdef HAVE_LAKKA
SETTING_ARRAY("cpu_main_gov", settings->arrays.cpu_main_gov, false, NULL, true);
SETTING_ARRAY("cpu_menu_gov", settings->arrays.cpu_menu_gov, false, NULL, true);
#endif
*size = count;
@ -2113,6 +2117,12 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("video_black_frame_insertion", &settings->uints.video_black_frame_insertion, true, DEFAULT_BLACK_FRAME_INSERTION, false);
#ifdef HAVE_LAKKA
SETTING_UINT("cpu_scaling_mode", &settings->uints.cpu_scaling_mode, true, 0, false);
SETTING_UINT("cpu_min_freq", &settings->uints.cpu_min_freq, true, 1, false);
SETTING_UINT("cpu_max_freq", &settings->uints.cpu_max_freq, true, ~0U, false);
#endif
*size = count;
return tmp;

View File

@ -288,6 +288,12 @@ typedef struct settings
unsigned core_updater_auto_backup_history_size;
unsigned video_black_frame_insertion;
unsigned quit_on_close_content;
#ifdef HAVE_LAKKA
unsigned cpu_scaling_mode;
unsigned cpu_min_freq;
unsigned cpu_max_freq;
#endif
} uints;
struct
@ -387,6 +393,8 @@ typedef struct settings
char crt_switch_timings[255];
#ifdef HAVE_LAKKA
char timezone[TIMEZONE_LENGTH];
char cpu_main_gov[32];
char cpu_menu_gov[32];
#endif
} arrays;

View File

@ -12092,6 +12092,58 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_POLICY_ENTRY,
"Policy"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE,
"Governing Mode"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANUAL,
"Manual"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANUAL,
"Allows to manually tweak every detail in every CPU: governor, frequencies, etc. Only recommended for advanced users."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF,
"Performance (Managed)"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF,
"Default and recommended mode. Maximum performance while playing while saving power when paused or browsing menus."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANAGED_PER_CONTEXT,
"Custom Managed"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANAGED_PER_CONTEXT,
"Allows to choose what governors to use in menus and during gameplay. Performance, Ondemand or Schedutil are recommended during gameplay."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MAX_PERF,
"Maximum Performance"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MAX_PERF,
"Always maximum performance: highest frequencies for best experience."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MIN_POWER,
"Minimum Power"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MIN_POWER,
"Use the lowest frequency available to save power. Useful on battery powered devices but performance will be significantly reduced."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_BALANCED,
"Balanced"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_BALANCED,
"Adapts to the current workload. Works well with most devices and emulators and helps saving power. Demanding games and cores might suffer a performance drop on some devices."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_POLICY_MIN_FREQ,
"Minimum Frequency"
@ -12100,10 +12152,26 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_POLICY_MAX_FREQ,
"Maximum Frequency"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_MANAGED_MIN_FREQ,
"Minimum Core Frequency"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_MANAGED_MAX_FREQ,
"Maximum Core Frequency"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_POLICY_GOVERNOR,
"CPU Governor"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_POLICY_CORE_GOVERNOR,
"Core Governor"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CPU_POLICY_MENU_GOVERNOR,
"Menu Governor"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_PAL60_ENABLE,
"Use PAL60 Mode"

View File

@ -518,6 +518,50 @@ static void menu_action_setting_disp_set_label_core_manager_entry(
#ifndef HAVE_LAKKA_SWITCH
#ifdef HAVE_LAKKA
static void menu_action_setting_disp_cpu_gov_mode(
file_list_t* list,
unsigned *w, unsigned type, unsigned i,
const char *label,
char *s, size_t len,
const char *path,
char *s2, size_t len2)
{
const char *alt = list->list[i].alt
? list->list[i].alt
: list->list[i].path;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(NULL);
if (alt)
strlcpy(s2, alt, len2);
strlcpy(s, msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF + (int)mode), len);
}
static void menu_action_setting_disp_cpu_gov_choose(
file_list_t* list,
unsigned *w, unsigned type, unsigned i,
const char *label,
char *s, size_t len,
const char *path,
char *s2, size_t len2)
{
const char *alt = list->list[i].alt
? list->list[i].alt
: list->list[i].path;
int fnum = atoi(list->list[i].label);
cpu_scaling_opts_t opts;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
if (alt)
strlcpy(s2, alt, len2);
if (!fnum)
strlcpy(s, opts.main_policy, len);
else
strlcpy(s, opts.menu_policy, len);
}
static void menu_action_setting_disp_set_label_cpu_policy(
file_list_t* list,
unsigned *w, unsigned type, unsigned i,
@ -542,6 +586,39 @@ static void menu_action_setting_disp_set_label_cpu_policy(
MENU_ENUM_LABEL_VALUE_CPU_POLICY_ENTRY), policyid);
}
static void menu_action_cpu_managed_freq_label(
file_list_t* list,
unsigned *w, unsigned type, unsigned i,
const char *label,
char *s, size_t len,
const char *path,
char *s2, size_t len2)
{
uint32_t freq = 0;
cpu_scaling_opts_t opts;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
switch (type) {
case MENU_SETTINGS_CPU_MANAGED_SET_MINFREQ:
strlcpy(s2, msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CPU_MANAGED_MIN_FREQ), len2);
freq = opts.min_freq;
break;
case MENU_SETTINGS_CPU_MANAGED_SET_MAXFREQ:
strlcpy(s2, msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CPU_MANAGED_MAX_FREQ), len2);
freq = opts.max_freq;
break;
};
if (freq == 1)
strlcpy(s, "Min.", len);
else if (freq == ~0U)
strlcpy(s, "Max.", len);
else
snprintf(s, len, "%u MHz", freq / 1000);
}
static void menu_action_cpu_freq_label(
file_list_t* list,
unsigned *w, unsigned type, unsigned i,
@ -1786,6 +1863,15 @@ static int menu_cbs_init_bind_get_string_representation_compare_label(
break;
#ifndef HAVE_LAKKA_SWITCH
#ifdef HAVE_LAKKA
case MENU_ENUM_LABEL_CPU_PERF_MODE:
BIND_ACTION_GET_VALUE(cbs,
menu_action_setting_disp_cpu_gov_mode);
break;
case MENU_ENUM_LABEL_CPU_POLICY_CORE_GOVERNOR:
case MENU_ENUM_LABEL_CPU_POLICY_MENU_GOVERNOR:
BIND_ACTION_GET_VALUE(cbs,
menu_action_setting_disp_cpu_gov_choose);
break;
case MENU_ENUM_LABEL_CPU_POLICY_ENTRY:
BIND_ACTION_GET_VALUE(cbs,
menu_action_setting_disp_set_label_cpu_policy);
@ -1794,6 +1880,10 @@ static int menu_cbs_init_bind_get_string_representation_compare_label(
case MENU_ENUM_LABEL_CPU_POLICY_MAX_FREQ:
BIND_ACTION_GET_VALUE(cbs, menu_action_cpu_freq_label);
break;
case MENU_ENUM_LABEL_CPU_MANAGED_MIN_FREQ:
case MENU_ENUM_LABEL_CPU_MANAGED_MAX_FREQ:
BIND_ACTION_GET_VALUE(cbs, menu_action_cpu_managed_freq_label);
break;
case MENU_ENUM_LABEL_CPU_POLICY_GOVERNOR:
BIND_ACTION_GET_VALUE(cbs, menu_action_cpu_governor_label);
break;

View File

@ -672,6 +672,82 @@ static int manual_content_scan_core_name_left(unsigned type, const char *label,
}
#ifdef HAVE_LAKKA
static int cpu_policy_mode_change(unsigned type, const char *label,
bool wraparound)
{
bool refresh = false;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(NULL);
if (mode != CPUSCALING_MANAGED_PERFORMANCE)
mode--;
set_cpu_scaling_mode(mode, NULL);
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
return 0;
}
static int cpu_policy_freq_managed_tweak(unsigned type, const char *label,
bool wraparound)
{
bool refresh = false;
cpu_scaling_opts_t opts;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
switch (type) {
case MENU_SETTINGS_CPU_MANAGED_SET_MINFREQ:
opts.min_freq = get_cpu_scaling_next_frequency_limit(
opts.min_freq, -1);
set_cpu_scaling_mode(mode, &opts);
break;
case MENU_SETTINGS_CPU_MANAGED_SET_MAXFREQ:
opts.max_freq = get_cpu_scaling_next_frequency_limit(
opts.max_freq, -1);
set_cpu_scaling_mode(mode, &opts);
break;
};
return 0;
}
static int cpu_policy_freq_managed_gov(unsigned type, const char *label,
bool wraparound)
{
int pidx;
bool refresh = false;
cpu_scaling_opts_t opts;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
cpu_scaling_driver_t **drivers = get_cpu_scaling_drivers(false);
/* Using drivers[0] governors, should be improved */
if (!drivers || !drivers[0])
return -1;
switch (atoi(label)) {
case 0:
pidx = string_list_find_elem(drivers[0]->available_governors,
opts.main_policy);
if (pidx > 1)
{
strlcpy(opts.main_policy,
drivers[0]->available_governors->elems[pidx-2].data,
sizeof(opts.main_policy));
set_cpu_scaling_mode(mode, &opts);
}
break;
case 1:
pidx = string_list_find_elem(drivers[0]->available_governors,
opts.menu_policy);
if (pidx > 1)
{
strlcpy(opts.menu_policy,
drivers[0]->available_governors->elems[pidx-2].data,
sizeof(opts.menu_policy));
set_cpu_scaling_mode(mode, &opts);
}
break;
};
return 0;
}
static int cpu_policy_freq_tweak(unsigned type, const char *label,
bool wraparound)
{
@ -1012,11 +1088,22 @@ static int menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t *cbs,
break;
#ifndef HAVE_LAKKA_SWITCH
#ifdef HAVE_LAKKA
case MENU_ENUM_LABEL_CPU_PERF_MODE:
BIND_ACTION_LEFT(cbs, cpu_policy_mode_change);
break;
case MENU_ENUM_LABEL_CPU_POLICY_MAX_FREQ:
case MENU_ENUM_LABEL_CPU_POLICY_MIN_FREQ:
case MENU_ENUM_LABEL_CPU_POLICY_GOVERNOR:
BIND_ACTION_LEFT(cbs, cpu_policy_freq_tweak);
break;
case MENU_ENUM_LABEL_CPU_MANAGED_MIN_FREQ:
case MENU_ENUM_LABEL_CPU_MANAGED_MAX_FREQ:
BIND_ACTION_LEFT(cbs, cpu_policy_freq_managed_tweak);
break;
case MENU_ENUM_LABEL_CPU_POLICY_CORE_GOVERNOR:
case MENU_ENUM_LABEL_CPU_POLICY_MENU_GOVERNOR:
BIND_ACTION_LEFT(cbs, cpu_policy_freq_managed_gov);
break;
#endif
#endif
default:

View File

@ -789,8 +789,84 @@ static int manual_content_scan_core_name_right(unsigned type, const char *label,
return 0;
}
#ifdef HAVE_LAKKA_SWITCH
#ifndef HAVE_LAKKA_SWITCH
#ifdef HAVE_LAKKA
static int cpu_policy_mode_change(unsigned type, const char *label,
bool wraparound)
{
bool refresh = false;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(NULL);
if (mode != CPUSCALING_MANUAL)
mode++;
set_cpu_scaling_mode(mode, NULL);
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
return 0;
}
static int cpu_policy_freq_managed_tweak(unsigned type, const char *label,
bool wraparound)
{
bool refresh = false;
cpu_scaling_opts_t opts;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
switch (type) {
case MENU_SETTINGS_CPU_MANAGED_SET_MINFREQ:
opts.min_freq = get_cpu_scaling_next_frequency_limit(
opts.min_freq, 1);
set_cpu_scaling_mode(mode, &opts);
break;
case MENU_SETTINGS_CPU_MANAGED_SET_MAXFREQ:
opts.max_freq = get_cpu_scaling_next_frequency_limit(
opts.max_freq, 1);
set_cpu_scaling_mode(mode, &opts);
break;
};
return 0;
}
static int cpu_policy_freq_managed_gov(unsigned type, const char *label,
bool wraparound)
{
int pidx;
bool refresh = false;
cpu_scaling_opts_t opts;
enum cpu_scaling_mode mode = get_cpu_scaling_mode(&opts);
cpu_scaling_driver_t **drivers = get_cpu_scaling_drivers(false);
/* Using drivers[0] governors, should be improved */
if (!drivers || !drivers[0])
return -1;
switch (atoi(label)) {
case 0:
pidx = string_list_find_elem(drivers[0]->available_governors,
opts.main_policy);
if (pidx && pidx + 1 < drivers[0]->available_governors->size)
{
strlcpy(opts.main_policy,
drivers[0]->available_governors->elems[pidx].data,
sizeof(opts.main_policy));
set_cpu_scaling_mode(mode, &opts);
}
break;
case 1:
pidx = string_list_find_elem(drivers[0]->available_governors,
opts.menu_policy);
if (pidx && pidx + 1 < drivers[0]->available_governors->size)
{
strlcpy(opts.menu_policy,
drivers[0]->available_governors->elems[pidx].data,
sizeof(opts.menu_policy));
set_cpu_scaling_mode(mode, &opts);
}
break;
};
return 0;
}
static int cpu_policy_freq_tweak(unsigned type, const char *label,
bool wraparound)
{
@ -1132,11 +1208,22 @@ static int menu_cbs_init_bind_right_compare_label(menu_file_list_cbs_t *cbs,
break;
#ifndef HAVE_LAKKA_SWITCH
#ifdef HAVE_LAKKA
case MENU_ENUM_LABEL_CPU_PERF_MODE:
BIND_ACTION_RIGHT(cbs, cpu_policy_mode_change);
break;
case MENU_ENUM_LABEL_CPU_POLICY_MAX_FREQ:
case MENU_ENUM_LABEL_CPU_POLICY_MIN_FREQ:
case MENU_ENUM_LABEL_CPU_POLICY_GOVERNOR:
BIND_ACTION_RIGHT(cbs, cpu_policy_freq_tweak);
break;
case MENU_ENUM_LABEL_CPU_MANAGED_MIN_FREQ:
case MENU_ENUM_LABEL_CPU_MANAGED_MAX_FREQ:
BIND_ACTION_RIGHT(cbs, cpu_policy_freq_managed_tweak);
break;
case MENU_ENUM_LABEL_CPU_POLICY_CORE_GOVERNOR:
case MENU_ENUM_LABEL_CPU_POLICY_MENU_GOVERNOR:
BIND_ACTION_RIGHT(cbs, cpu_policy_freq_managed_gov);
break;
#endif
#endif
default:

View File

@ -1020,15 +1020,28 @@ static int action_bind_sublabel_cpu_policy_entry_list(
{
/* Displays info about the Policy entry */
cpu_scaling_driver_t **drivers = get_cpu_scaling_drivers(false);
int idx = atoi(path);
if (drivers)
{
sprintf(s, "%s | Freq: %u MHz\n", drivers[i]->scaling_governor,
drivers[i]->current_frequency / 1000);
sprintf(s, "%s | Freq: %u MHz\n", drivers[idx]->scaling_governor,
drivers[idx]->current_frequency / 1000);
return 0;
}
return -1;
}
static int action_bind_sublabel_cpu_perf_mode(
file_list_t *list,
unsigned type, unsigned i,
const char *label, const char *path,
char *s, size_t len)
{
/* Displays info about the mode selected */
enum cpu_scaling_mode mode = get_cpu_scaling_mode(NULL);
strlcpy(s, msg_hash_to_str(
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF + (int)mode), len);
return 0;
}
#endif
#endif
#ifdef HAVE_CHEEVOS
@ -3947,6 +3960,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_CPU_POLICY_ENTRY:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cpu_policy_entry_list);
break;
case MENU_ENUM_LABEL_CPU_PERF_MODE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cpu_perf_mode);
break;
#endif
#endif
case MENU_ENUM_LABEL_USER_LANGUAGE:

View File

@ -9869,17 +9869,66 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
if (drivers)
{
int count = 0;
while (*drivers)
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE),
msg_hash_to_str(MENU_ENUM_LABEL_CPU_PERF_MODE),
MENU_ENUM_LABEL_CPU_PERF_MODE,
0, 0, 0);
switch (get_cpu_scaling_mode(NULL))
{
char policyid[16];
sprintf(policyid, "%u", count++);
case CPUSCALING_MANUAL:
while (*drivers)
{
char policyid[16];
sprintf(policyid, "%u", count++);
menu_entries_append_enum(info->list,
policyid,
policyid,
MENU_ENUM_LABEL_CPU_POLICY_ENTRY,
0, 0, 0);
drivers++;
}
break;
case CPUSCALING_MANAGED_PER_CONTEXT:
/* Allows user to pick two governors */
menu_entries_append_enum(info->list,
policyid,
policyid,
MENU_ENUM_LABEL_CPU_POLICY_ENTRY,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_POLICY_CORE_GOVERNOR),
"0",
MENU_ENUM_LABEL_CPU_POLICY_CORE_GOVERNOR,
0, 0, 0);
drivers++;
}
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_POLICY_MENU_GOVERNOR),
"1",
MENU_ENUM_LABEL_CPU_POLICY_MENU_GOVERNOR,
0, 0, 0);
/* fallthrough */
case CPUSCALING_MANAGED_PERFORMANCE:
/* Allow users to choose max/min frequencies */
menu_entries_append_enum(info->list,
"0",
"0",
MENU_ENUM_LABEL_CPU_MANAGED_MIN_FREQ,
MENU_SETTINGS_CPU_MANAGED_SET_MINFREQ,
0, 0);
menu_entries_append_enum(info->list,
"1",
"1",
MENU_ENUM_LABEL_CPU_MANAGED_MAX_FREQ,
MENU_SETTINGS_CPU_MANAGED_SET_MAXFREQ,
0, 0);
break;
case CPUSCALING_MAX_PERFORMANCE:
case CPUSCALING_MIN_POWER:
case CPUSCALING_BALANCED:
/* No settings for these modes */
break;
};
}
info->need_push = true;

View File

@ -214,6 +214,8 @@ enum menu_settings_type
MENU_SETTINGS_CPU_POLICY_SET_MINFREQ,
MENU_SETTINGS_CPU_POLICY_SET_MAXFREQ,
MENU_SETTINGS_CPU_POLICY_SET_GOVERNOR,
MENU_SETTINGS_CPU_MANAGED_SET_MINFREQ,
MENU_SETTINGS_CPU_MANAGED_SET_MAXFREQ,
MENU_SET_CDROM_LIST,
MENU_SET_LOAD_CDROM_LIST,

View File

@ -24,12 +24,18 @@
#include <retro_miscellaneous.h>
#include "cpufreq.h"
#include "../../configuration.h"
#define REFRESH_TIMEOUT 2
#define CPU_POLICIES_DIR "/sys/devices/system/cpu/cpufreq/"
static time_t last_update = 0;
static cpu_scaling_driver_t **scaling_drivers = NULL;
/* Mode state and its options */
static enum cpu_scaling_mode cur_smode = CPUSCALING_MANAGED_PERFORMANCE;
static cpu_scaling_opts_t cur_smode_opts = { 1, ~0U, "performance", "ondemand" };
/* Precalculate and store the absolute max and min frequencies */
static uint32_t abs_min_freq = 1, abs_max_freq = ~0U;
static bool readparse_uint32(const char *path, uint32_t *value)
{
@ -80,15 +86,6 @@ static void free_drivers(cpu_scaling_driver_t **d)
}
}
void cpu_scaling_driver_free()
{
if (scaling_drivers)
free_drivers(scaling_drivers);
scaling_drivers = NULL;
last_update = 0;
}
cpu_scaling_driver_t **get_cpu_scaling_drivers(bool can_update)
{
if (can_update && (time(NULL) > last_update + REFRESH_TIMEOUT ||
@ -142,6 +139,12 @@ cpu_scaling_driver_t **get_cpu_scaling_drivers(bool can_update)
"scaling_min_freq", sizeof(fpath));
readparse_uint32(fpath, &drv->min_policy_freq);
/* Check current freq limits and update them */
if (abs_min_freq > drv->min_cpu_freq || abs_min_freq == 1)
abs_min_freq = drv->min_cpu_freq;
if (abs_max_freq < drv->max_cpu_freq || abs_max_freq == ~0U)
abs_max_freq = drv->max_cpu_freq;
fill_pathname_join(fpath, policy_dir->elems[i].data,
"scaling_max_freq", sizeof(fpath));
readparse_uint32(fpath, &drv->max_policy_freq);
@ -160,6 +163,7 @@ cpu_scaling_driver_t **get_cpu_scaling_drivers(bool can_update)
filestream_read_file(fpath, (void**)&drv->scaling_governor, NULL);
string_remove_all_chars(drv->scaling_governor, '\n');
/* This is not available in many platforms! */
fill_pathname_join(fpath, policy_dir->elems[i].data,
"scaling_available_frequencies", sizeof(fpath));
tmplst = readparse_list(fpath);
@ -168,7 +172,12 @@ cpu_scaling_driver_t **get_cpu_scaling_drivers(bool can_update)
drv->available_freqs = calloc(tmplst->size, sizeof(uint32_t));
for (j = 0; j < tmplst->size; j++)
{
drv->available_freqs[j] = (uint32_t)atol(tmplst->elems[j].data);
uint32_t freq = (uint32_t)atol(tmplst->elems[j].data);
drv->available_freqs[j] = freq;
if (abs_min_freq > freq || abs_min_freq == 1)
abs_min_freq = freq;
if (abs_max_freq < freq || abs_max_freq == ~0U)
abs_max_freq = freq;
}
string_list_free(tmplst);
}
@ -254,10 +263,30 @@ uint32_t get_cpu_scaling_next_frequency(
freq = freq + step * 100000;
}
if (freq > driver->max_cpu_freq)
freq = driver->max_cpu_freq;
if (freq < driver->min_cpu_freq)
freq = driver->min_cpu_freq;
freq = MIN(freq, driver->max_cpu_freq);
freq = MAX(freq, driver->min_cpu_freq);
return freq;
}
uint32_t get_cpu_scaling_next_frequency_limit(uint32_t freq, int step)
{
/* Tune step, if it's smaller than 100MHz */
unsigned fstep = 100000;
if ((abs_max_freq - abs_min_freq) / 20 < fstep)
fstep = 50000;
if (freq <= abs_min_freq && step < 0)
return 1; /* Means "minimum frequency" */
if (freq >= abs_max_freq && step > 0)
return ~0U; /* Means "maximum frequency" */
/* Just do small steps towards the max/min */
freq = freq + step * fstep;
freq = MIN(freq, abs_max_freq);
freq = MAX(freq, abs_min_freq);
return freq;
}
@ -278,4 +307,136 @@ bool set_cpu_scaling_governor(cpu_scaling_driver_t *driver, const char* governor
return false;
}
static void steer_all_drivers(
const char *governor,
uint32_t minfreq,
uint32_t maxfreq)
{
cpu_scaling_driver_t **drivers = get_cpu_scaling_drivers(false);
if (!drivers)
return;
while (*drivers)
{
cpu_scaling_driver_t *d = *drivers++;
if (minfreq)
set_cpu_scaling_min_frequency(d, MAX(minfreq, d->min_cpu_freq));
if (maxfreq)
set_cpu_scaling_max_frequency(d, MIN(maxfreq, d->max_cpu_freq));
set_cpu_scaling_governor(d, governor);
}
}
void set_cpu_scaling_signal(enum cpu_scaling_event event)
{
switch (cur_smode) {
case CPUSCALING_MANAGED_PERFORMANCE:
/* Bump to perf or fall back to ondemand depending on the RA state */
if (event == CPUSCALING_EVENT_FOCUS_CORE)
steer_all_drivers("performance", cur_smode_opts.min_freq,
cur_smode_opts.max_freq);
else
steer_all_drivers("ondemand", 1, ~0U);
break;
case CPUSCALING_MANAGED_PER_CONTEXT:
/* Apply the right settings the user specified */
if (event == CPUSCALING_EVENT_FOCUS_CORE)
steer_all_drivers(cur_smode_opts.main_policy, cur_smode_opts.min_freq,
cur_smode_opts.max_freq);
else
steer_all_drivers(cur_smode_opts.menu_policy, 1, ~0U);
break;
default:
break;
};
}
enum cpu_scaling_mode get_cpu_scaling_mode(cpu_scaling_opts_t *opts)
{
if (opts)
*opts = cur_smode_opts;
return cur_smode;
}
void set_cpu_scaling_mode(
enum cpu_scaling_mode mode,
const cpu_scaling_opts_t *opts)
{
settings_t *settings = config_get_ptr();
/* Store current state */
cur_smode = mode;
if (opts)
cur_smode_opts = *opts;
switch (mode)
{
case CPUSCALING_MANUAL:
/* Do nothing, the UI allows for tweaking directly */
break;
case CPUSCALING_MANAGED_PERFORMANCE:
case CPUSCALING_MANAGED_PER_CONTEXT:
/* Simulate a state change to enforce the policy */
set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_MENU);
break;
case CPUSCALING_MAX_PERFORMANCE:
// Set performance and bump frequencies to min/max
steer_all_drivers("performance", 1, ~0U);
break;
case CPUSCALING_MIN_POWER:
// Set powersave and bump frequencies to min/max
steer_all_drivers("powersave", 1, ~0U);
break;
case CPUSCALING_BALANCED:
// Set ondemand and bump frequencies to min/max
steer_all_drivers("ondemand", 1, ~0U);
break;
};
if (settings)
{
/* Store current settings */
settings->uints.cpu_scaling_mode = (int)cur_smode;
settings->uints.cpu_min_freq = cur_smode_opts.min_freq;
settings->uints.cpu_max_freq = cur_smode_opts.max_freq;
strlcpy(settings->arrays.cpu_main_gov, cur_smode_opts.main_policy,
sizeof(settings->arrays.cpu_main_gov));
strlcpy(settings->arrays.cpu_menu_gov, cur_smode_opts.menu_policy,
sizeof(settings->arrays.cpu_menu_gov));
}
};
void cpu_scaling_driver_free()
{
if (scaling_drivers)
free_drivers(scaling_drivers);
scaling_drivers = NULL;
last_update = 0;
}
void cpu_scaling_driver_init(void)
{
/* Read the default settings */
settings_t *settings = config_get_ptr();
unsigned mode = settings->uints.cpu_scaling_mode;
cur_smode_opts.min_freq = settings->uints.cpu_min_freq;
cur_smode_opts.max_freq = settings->uints.cpu_max_freq;
if (mode <= (int)CPUSCALING_MANUAL)
cur_smode = (enum cpu_scaling_mode)mode;
if (settings->arrays.cpu_main_gov[0])
strlcpy(cur_smode_opts.main_policy, settings->arrays.cpu_main_gov,
sizeof(cur_smode_opts.main_policy));
if (settings->arrays.cpu_menu_gov[0])
strlcpy(cur_smode_opts.menu_policy, settings->arrays.cpu_menu_gov,
sizeof(cur_smode_opts.menu_policy));
/* Force update the policy tree */
get_cpu_scaling_drivers(true);
/* Force enforce these settings */
set_cpu_scaling_mode(cur_smode, NULL);
}

View File

@ -20,6 +20,36 @@
RETRO_BEGIN_DECLS
#define MAX_GOV_STRLEN 32
/* Events from Frontend to the driver to drive policies */
enum cpu_scaling_event
{
CPUSCALING_EVENT_FOCUS_CORE,
CPUSCALING_EVENT_FOCUS_MENU,
CPUSCALING_EVENT_FOCUS_SCREENSAVER
};
/* Scaling mode selected by the user */
enum cpu_scaling_mode
{
CPUSCALING_MANAGED_PERFORMANCE = 0, /* Performance while running core */
CPUSCALING_MANAGED_PER_CONTEXT, /* Policies for core, menu, etc. */
CPUSCALING_MAX_PERFORMANCE, /* Performance (Max Freq) */
CPUSCALING_MIN_POWER, /* Use Powersave governor */
CPUSCALING_BALANCED, /* Uses schedutil/ondemand */
CPUSCALING_MANUAL, /* Can manually tweak stuff */
};
typedef struct cpu_scaling_opts
{
/* Max/Min frequencies */
uint32_t min_freq, max_freq;
/* Options for CPUSCALING_POLICY_PER_CONTEXT */
char main_policy[MAX_GOV_STRLEN];
char menu_policy[MAX_GOV_STRLEN];
} cpu_scaling_opts_t;
typedef struct cpu_scaling_driver
{
/* Policy number in the sysfs tree */
@ -39,7 +69,10 @@ typedef struct cpu_scaling_driver
} cpu_scaling_driver_t;
/* Safely free all memory used by the driver */
void cpu_scaling_driver_free();
void cpu_scaling_driver_free(void);
/* Signal the initialization */
void cpu_scaling_driver_init(void);
/* Get a list of the available cpu scaling drivers */
cpu_scaling_driver_t **get_cpu_scaling_drivers(bool can_update);
@ -53,10 +86,21 @@ bool set_cpu_scaling_max_frequency(
/* Calculate next/previous frequencies */
uint32_t get_cpu_scaling_next_frequency(cpu_scaling_driver_t *driver,
uint32_t freq, int step);
uint32_t get_cpu_scaling_next_frequency_limit(uint32_t freq, int step);
/* Set the scaling governor for this scaling driver */
bool set_cpu_scaling_governor(cpu_scaling_driver_t *driver, const char* governor);
/* Signal certain events that are of interest of this driver */
void set_cpu_scaling_signal(enum cpu_scaling_event);
/* Set the base cpufreq policy mode */
void set_cpu_scaling_mode(enum cpu_scaling_mode mode,
const cpu_scaling_opts_t *opts);
/* Get the base cpufreq policy mode */
enum cpu_scaling_mode get_cpu_scaling_mode(cpu_scaling_opts_t *opts);
RETRO_END_DECLS
#endif

View File

@ -2941,11 +2941,30 @@ enum msg_hash_enums
MENU_LABEL(MIDI_VOLUME),
MENU_LABEL(SUSTAINED_PERFORMANCE_MODE),
MENU_LABEL(CPU_PERF_MODE),
MENU_LABEL(CPU_PERFPOWER),
MENU_LABEL(CPU_POLICY_ENTRY),
MENU_LABEL(CPU_POLICY_MIN_FREQ),
MENU_LABEL(CPU_POLICY_MAX_FREQ),
MENU_LABEL(CPU_POLICY_GOVERNOR),
MENU_LABEL(CPU_POLICY_CORE_GOVERNOR),
MENU_LABEL(CPU_POLICY_MENU_GOVERNOR),
MENU_LABEL(CPU_MANAGED_MIN_FREQ),
MENU_LABEL(CPU_MANAGED_MAX_FREQ),
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF,
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANAGED_PER_CONTEXT,
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MAX_PERF,
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MIN_POWER,
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_BALANCED,
MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE_MANUAL,
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANAGED_PERF,
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANAGED_PER_CONTEXT,
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MAX_PERF,
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MIN_POWER,
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_BALANCED,
MENU_ENUM_SUBLABEL_VALUE_CPU_PERF_MODE_MANUAL,
MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_EMU,
MENU_ENUM_LABEL_CHEAT_HANDLER_TYPE_RETRO,

View File

@ -228,6 +228,7 @@
#include "gfx/video_crt_switch.h"
#include "bluetooth/bluetooth_driver.h"
#include "wifi/wifi_driver.h"
#include "misc/cpufreq/cpufreq.h"
#include "led/led_driver.h"
#include "midi/midi_driver.h"
#include "core.h"
@ -13314,10 +13315,18 @@ static void retroarch_pause_checks(struct rarch_state *p_rarch)
userdata.status = DISCORD_PRESENCE_GAME_PAUSED;
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
#endif
#ifdef HAVE_LAKKA
set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_MENU);
#endif
}
else
{
RARCH_LOG("[Core]: %s\n", msg_hash_to_str(MSG_UNPAUSED));
#ifdef HAVE_LAKKA
set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_CORE);
#endif
}
#if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
@ -33206,6 +33215,10 @@ static void drivers_init(struct rarch_state *p_rarch,
/* Initialize MIDI driver */
if (flags & DRIVER_MIDI_MASK)
midi_driver_init(p_rarch, settings);
#ifdef HAVE_LAKKA
cpu_scaling_driver_init();
#endif
}
/**
@ -33298,6 +33311,10 @@ static void driver_uninit(struct rarch_state *p_rarch, int flags)
if (flags & DRIVER_MIDI_MASK)
midi_driver_free(p_rarch);
#ifdef HAVE_LAKKA
cpu_scaling_driver_free();
#endif
}
static void retroarch_deinit_drivers(
@ -35632,6 +35649,13 @@ static void menu_driver_toggle(
p_rarch->menu_driver_alive = on;
#ifdef HAVE_LAKKA
if (on)
set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_MENU);
else
set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_CORE);
#endif
/* Apply any required menu pointer input inhibits
* (i.e. prevent phantom input when using an overlay
* to toggle the menu on) */