diff --git a/skeleton/SYSTEM/tg5040/bin/auto_governor.sh b/skeleton/SYSTEM/tg5040/bin/auto_governor.sh new file mode 100644 index 000000000..ed63fc372 --- /dev/null +++ b/skeleton/SYSTEM/tg5040/bin/auto_governor.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# auto_governor.sh - ondemand governor, min freq to one step below max +# All cpu*/cpufreq entries point at this same shared policy0 path. +CPU_PATH=/sys/devices/system/cpu/cpufreq/policy0 +[ -f "$CPU_PATH/scaling_available_frequencies" ] || exit 0 +FREQS=$(cat "$CPU_PATH/scaling_available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) +MIN_FREQ=$(echo "$FREQS" | head -1) +SECOND_MAX=$(echo "$FREQS" | tail -2 | head -1) +echo ondemand > "$CPU_PATH/scaling_governor" 2>/dev/null || true +echo "$MIN_FREQ" > "$CPU_PATH/scaling_min_freq" +echo "$SECOND_MAX" > "$CPU_PATH/scaling_max_freq" diff --git a/skeleton/SYSTEM/tg5040/bin/performance_governor.sh b/skeleton/SYSTEM/tg5040/bin/performance_governor.sh new file mode 100644 index 000000000..d1f36441a --- /dev/null +++ b/skeleton/SYSTEM/tg5040/bin/performance_governor.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# performance_governor.sh - schedutil governor, min freq to max freq +# All cpu*/cpufreq entries point at this same shared policy0 path. +CPU_PATH=/sys/devices/system/cpu/cpufreq/policy0 +[ -f "$CPU_PATH/scaling_available_frequencies" ] || exit 0 +FREQS=$(cat "$CPU_PATH/scaling_available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) +MIN_FREQ=$(echo "$FREQS" | head -1) +MAX_FREQ=$(echo "$FREQS" | tail -1) +echo schedutil > "$CPU_PATH/scaling_governor" 2>/dev/null || true +echo "$MIN_FREQ" > "$CPU_PATH/scaling_min_freq" +echo "$MAX_FREQ" > "$CPU_PATH/scaling_max_freq" diff --git a/skeleton/SYSTEM/tg5040/bin/powersave_governor.sh b/skeleton/SYSTEM/tg5040/bin/powersave_governor.sh new file mode 100644 index 000000000..5496df8e8 --- /dev/null +++ b/skeleton/SYSTEM/tg5040/bin/powersave_governor.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# powersave_governor.sh - conservative governor, min freq to midpoint max +# All cpu*/cpufreq entries point at this same shared policy0 path. +CPU_PATH=/sys/devices/system/cpu/cpufreq/policy0 +[ -f "$CPU_PATH/scaling_available_frequencies" ] || exit 0 +FREQS=$(cat "$CPU_PATH/scaling_available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) +COUNT=$(echo "$FREQS" | wc -l) +MID=$(( (COUNT + 1) / 2 )) +MIN_FREQ=$(echo "$FREQS" | head -1) +MID_FREQ=$(echo "$FREQS" | sed -n "${MID}p") +echo conservative > "$CPU_PATH/scaling_governor" 2>/dev/null || true +echo "$MIN_FREQ" > "$CPU_PATH/scaling_min_freq" +echo "$MID_FREQ" > "$CPU_PATH/scaling_max_freq" diff --git a/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh b/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh index 09528cf3a..b3272ff4d 100755 --- a/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh +++ b/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh @@ -111,10 +111,7 @@ fi # start stock gpio input daemon trimui_inputd & -echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor -CPU_PATH=/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed -CPU_SPEED_PERF=2000000 -echo $CPU_SPEED_PERF > $CPU_PATH +sh "$SYSTEM_PATH/bin/auto_governor.sh" keymon.elf & # &> $SDCARD_PATH/keymon.txt & batmon.elf & # &> $SDCARD_PATH/batmon.txt & diff --git a/skeleton/SYSTEM/tg5050/bin/auto_governor.sh b/skeleton/SYSTEM/tg5050/bin/auto_governor.sh new file mode 100644 index 000000000..ed63fc372 --- /dev/null +++ b/skeleton/SYSTEM/tg5050/bin/auto_governor.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# auto_governor.sh - ondemand governor, min freq to one step below max +# All cpu*/cpufreq entries point at this same shared policy0 path. +CPU_PATH=/sys/devices/system/cpu/cpufreq/policy0 +[ -f "$CPU_PATH/scaling_available_frequencies" ] || exit 0 +FREQS=$(cat "$CPU_PATH/scaling_available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) +MIN_FREQ=$(echo "$FREQS" | head -1) +SECOND_MAX=$(echo "$FREQS" | tail -2 | head -1) +echo ondemand > "$CPU_PATH/scaling_governor" 2>/dev/null || true +echo "$MIN_FREQ" > "$CPU_PATH/scaling_min_freq" +echo "$SECOND_MAX" > "$CPU_PATH/scaling_max_freq" diff --git a/skeleton/SYSTEM/tg5050/bin/performance_governor.sh b/skeleton/SYSTEM/tg5050/bin/performance_governor.sh new file mode 100644 index 000000000..d1f36441a --- /dev/null +++ b/skeleton/SYSTEM/tg5050/bin/performance_governor.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# performance_governor.sh - schedutil governor, min freq to max freq +# All cpu*/cpufreq entries point at this same shared policy0 path. +CPU_PATH=/sys/devices/system/cpu/cpufreq/policy0 +[ -f "$CPU_PATH/scaling_available_frequencies" ] || exit 0 +FREQS=$(cat "$CPU_PATH/scaling_available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) +MIN_FREQ=$(echo "$FREQS" | head -1) +MAX_FREQ=$(echo "$FREQS" | tail -1) +echo schedutil > "$CPU_PATH/scaling_governor" 2>/dev/null || true +echo "$MIN_FREQ" > "$CPU_PATH/scaling_min_freq" +echo "$MAX_FREQ" > "$CPU_PATH/scaling_max_freq" diff --git a/skeleton/SYSTEM/tg5050/bin/powersave_governor.sh b/skeleton/SYSTEM/tg5050/bin/powersave_governor.sh new file mode 100644 index 000000000..5496df8e8 --- /dev/null +++ b/skeleton/SYSTEM/tg5050/bin/powersave_governor.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# powersave_governor.sh - conservative governor, min freq to midpoint max +# All cpu*/cpufreq entries point at this same shared policy0 path. +CPU_PATH=/sys/devices/system/cpu/cpufreq/policy0 +[ -f "$CPU_PATH/scaling_available_frequencies" ] || exit 0 +FREQS=$(cat "$CPU_PATH/scaling_available_frequencies" | tr ' ' '\n' | grep -v '^$' | sort -n) +COUNT=$(echo "$FREQS" | wc -l) +MID=$(( (COUNT + 1) / 2 )) +MIN_FREQ=$(echo "$FREQS" | head -1) +MID_FREQ=$(echo "$FREQS" | sed -n "${MID}p") +echo conservative > "$CPU_PATH/scaling_governor" 2>/dev/null || true +echo "$MIN_FREQ" > "$CPU_PATH/scaling_min_freq" +echo "$MID_FREQ" > "$CPU_PATH/scaling_max_freq" diff --git a/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh b/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh index d73b92a2a..97707073d 100755 --- a/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh +++ b/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh @@ -98,21 +98,7 @@ echo 0 > /sys/class/led_anim/max_scale # start gpio input daemon trimui_inputd & -echo userspace > /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor -echo 408000 > /sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq -echo 2160000 > /sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq - -BIG_PATH=/sys/devices/system/cpu/cpu4/cpufreq/scaling_setspeed -CPU_SPEED_PERF=2160000 -echo $CPU_SPEED_PERF > $BIG_PATH - -echo schedutil > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor -echo 408000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq -echo 2000000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq - -#LITTLE_PATH=/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed -#CPU_SPEED_PERF_LITTLE=2000000 -#echo $CPU_SPEED_PERF_LITTLE > $LITTLE_PATH +sh "$SYSTEM_PATH/bin/auto_governor.sh" echo performance > /sys/devices/platform/soc@3000000/1800000.gpu/devfreq/1800000.gpu/governor diff --git a/workspace/all/common/api.c b/workspace/all/common/api.c index af9fef268..91661f39c 100644 --- a/workspace/all/common/api.c +++ b/workspace/all/common/api.c @@ -215,6 +215,49 @@ int currentshadertexh = 0; int should_rotate = 0; +static pthread_mutex_t perf_cpu_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; +static int perf_cpu_monitor_enabled = 0; +static int perf_cpu_monitor_running = 0; + +void Perf_setCPUMonitorEnabled(int enabled) +{ + pthread_mutex_lock(&perf_cpu_monitor_mutex); + perf_cpu_monitor_enabled = enabled; + pthread_mutex_unlock(&perf_cpu_monitor_mutex); +} + +int Perf_isCPUMonitorEnabled(void) +{ + int enabled; + + pthread_mutex_lock(&perf_cpu_monitor_mutex); + enabled = perf_cpu_monitor_enabled; + pthread_mutex_unlock(&perf_cpu_monitor_mutex); + + return enabled; +} + +int Perf_tryBeginCPUMonitor(void) +{ + int should_run = 0; + + pthread_mutex_lock(&perf_cpu_monitor_mutex); + if (perf_cpu_monitor_enabled && !perf_cpu_monitor_running) { + perf_cpu_monitor_running = 1; + should_run = 1; + } + pthread_mutex_unlock(&perf_cpu_monitor_mutex); + + return should_run; +} + +void Perf_endCPUMonitor(void) +{ + pthread_mutex_lock(&perf_cpu_monitor_mutex); + perf_cpu_monitor_running = 0; + pthread_mutex_unlock(&perf_cpu_monitor_mutex); +} + FALLBACK_IMPLEMENTATION void PLAT_pinToCores(int core_type) { // no-op @@ -4393,4 +4436,4 @@ FALLBACK_IMPLEMENTATION void PLAT_bluetoothStreamBegin(int buffersize) {} FALLBACK_IMPLEMENTATION void PLAT_bluetoothStreamEnd() {} FALLBACK_IMPLEMENTATION void PLAT_bluetoothStreamQuit() {} FALLBACK_IMPLEMENTATION int PLAT_bluetoothVolume() { return 100; } -FALLBACK_IMPLEMENTATION void PLAT_bluetoothSetVolume(int vol) {} \ No newline at end of file +FALLBACK_IMPLEMENTATION void PLAT_bluetoothSetVolume(int vol) {} diff --git a/workspace/all/common/api.h b/workspace/all/common/api.h index 1cef108f1..48f8ff65e 100644 --- a/workspace/all/common/api.h +++ b/workspace/all/common/api.h @@ -113,8 +113,6 @@ extern int currentshaderdsth; extern int currentshadertexw; extern int currentshadertexh; extern int should_rotate; -extern volatile int useAutoCpu; - enum { ASSET_WHITE_PILL, ASSET_BLACK_PILL, @@ -679,6 +677,11 @@ int PLAT_supportsDeepSleep(void); int PLAT_deepSleep(void); void PLAT_powerOff(int reboot); +void Perf_setCPUMonitorEnabled(int enabled); +int Perf_isCPUMonitorEnabled(void); +int Perf_tryBeginCPUMonitor(void); +void Perf_endCPUMonitor(void); + void *PLAT_cpu_monitor(void *arg); void PLAT_setCPUSpeed(int speed); // enum void PLAT_setCustomCPUSpeed(int speed); diff --git a/workspace/all/minarch/minarch.c b/workspace/all/minarch/minarch.c index ed2f92abd..ffca254aa 100644 --- a/workspace/all/minarch/minarch.c +++ b/workspace/all/minarch/minarch.c @@ -97,7 +97,7 @@ static int rewind_cfg_granularity = MINARCH_DEFAULT_REWIND_GRANULARITY; static int rewind_cfg_audio = MINARCH_DEFAULT_REWIND_AUDIO; static int rewind_cfg_compress = 1; static int rewind_cfg_lz4_acceleration = MINARCH_DEFAULT_REWIND_LZ4_ACCELERATION; -static int overclock = 3; // auto +static int overclock = 0; // auto static int has_custom_controllers = 0; static int gamepad_type = 0; // index in gamepad_labels/gamepad_values @@ -2490,10 +2490,9 @@ static char* button_labels[] = { NULL, }; static char* overclock_labels[] = { - "Powersave", - "Normal", - "Performance", "Auto", + "Performance", + "Powersave", NULL, }; @@ -2640,10 +2639,10 @@ static struct Config { [FE_OPT_OVERCLOCK] = { .key = "minarch_cpu_speed", .name = "CPU Speed", - .desc = "Over- or underclock the CPU to prioritize\npure performance or power savings.", - .default_value = 3, - .value = 3, - .count = 4, + .desc = "Choose how the CPU scales.\nAuto is recommended for most users.", + .default_value = 0, + .value = 0, + .count = 3, .values = overclock_labels, .labels = overclock_labels, }, @@ -2990,30 +2989,44 @@ static int Config_getValue(char* cfg, const char* key, char* out_value, int* loc -static void setOverclock(int i) { - overclock = i; - switch (i) { - case 0: { - useAutoCpu = 0; - PWR_setCPUSpeed(CPU_SPEED_POWERSAVE); - break; - } - case 1: { - useAutoCpu = 0; - PWR_setCPUSpeed(CPU_SPEED_NORMAL); - break; - } - case 2: { - useAutoCpu = 0; - PWR_setCPUSpeed(CPU_SPEED_PERFORMANCE); - break; - } - case 3: { - PWR_setCPUSpeed(CPU_SPEED_NORMAL); - useAutoCpu = 1; - break; - } +static void run_governor_script(const char* script_name) { + const char* system_path = getenv("SYSTEM_PATH"); + if (!system_path) { + LOG_info("WARNING: SYSTEM_PATH not set, cannot run governor script\n"); + return; + } + char cmd[512]; + int n = snprintf(cmd, sizeof(cmd), "sh \"%s/bin/%s\"", system_path, script_name); + if (n < 0 || n >= (int)sizeof(cmd)) { + LOG_info("WARNING: SYSTEM_PATH too long for governor script path\n"); + return; + } + int ret = system(cmd); + if (ret != 0) LOG_info("WARNING: governor script '%s' exited with status %d\n", script_name, ret); +} + +static void updateCPUMonitor(void) { + Perf_setCPUMonitorEnabled(show_debug); + if (!show_debug) return; + + pthread_t cpucheckthread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&cpucheckthread, &attr, PLAT_cpu_monitor, NULL) != 0) { + LOG_info("WARNING: failed to start CPU monitor thread\n"); + Perf_setCPUMonitorEnabled(0); } + pthread_attr_destroy(&attr); +} + +static void setOverclock(int i) { + overclock = i; + switch (i) { + case 0: run_governor_script("auto_governor.sh"); break; + case 1: run_governor_script("performance_governor.sh"); break; + case 2: run_governor_script("powersave_governor.sh"); break; + } } static void Config_syncFrontend(char* key, int value) { int i = -1; @@ -3080,7 +3093,9 @@ static void Config_syncFrontend(char* key, int value) { i = FE_OPT_OVERCLOCK; } else if (exactMatch(key,config.frontend.options[FE_OPT_DEBUG].key)) { - show_debug = value; + int prev_show_debug = show_debug; + show_debug = value; + if (prev_show_debug != show_debug) updateCPUMonitor(); i = FE_OPT_DEBUG; } else if (exactMatch(key,config.frontend.options[FE_OPT_MAXFF].key)) { @@ -6270,8 +6285,6 @@ void Menu_beforeSleep() { RTC_write(); State_autosave(); putFile(AUTO_RESUME_PATH, game.path + strlen(SDCARD_PATH)); - - PWR_setCPUSpeed(CPU_SPEED_MENU); } void Menu_afterSleep() { unlink(AUTO_RESUME_PATH); @@ -8503,7 +8516,6 @@ static void Menu_loop(void) { SRAM_write(); RTC_write(); if (!HAS_POWER_BUTTON) PWR_enableSleep(); - PWR_setCPUSpeed(CPU_SPEED_MENU); // set Hz directly GFX_setEffect(EFFECT_NONE); @@ -8966,23 +8978,16 @@ int main(int argc , char* argv[]) { //else // LOG_info("asoundrc does not exist at %s\n", asoundpath); - pthread_t cpucheckthread; - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&cpucheckthread, &attr, PLAT_cpu_monitor, NULL); - pthread_attr_destroy(&attr); + if(argc < 2) + return EXIT_FAILURE; - setOverclock(2); // start up in performance mode, faster init + setOverclock(1); // start up in performance mode, faster init PWR_pinToCores(CPU_CORE_PERFORMANCE); // thread affinity - + char core_path[MAX_PATH]; - char rom_path[MAX_PATH]; + char rom_path[MAX_PATH]; char tag_name[MAX_PATH]; - if(argc < 2) - return EXIT_FAILURE; - strcpy(core_path, argv[1]); strcpy(rom_path, argv[2]); getEmuName(rom_path, tag_name); @@ -9186,6 +9191,9 @@ int main(int argc , char* argv[]) { finish: + Perf_setCPUMonitorEnabled(0); + run_governor_script("auto_governor.sh"); // restore auto governor on return to menu + // Unload game and shutdown RetroAchievements before Core_quit RA_unloadGame(); RA_quit(); diff --git a/workspace/all/nextui/nextui.c b/workspace/all/nextui/nextui.c index 4b943b835..20c14b725 100644 --- a/workspace/all/nextui/nextui.c +++ b/workspace/all/nextui/nextui.c @@ -2269,11 +2269,6 @@ int main (int argc, char *argv[]) { int had_bt = PLAT_btIsConnected(); int had_sink = GetAudioSink(); - pthread_t cpucheckthread = 0; - if (pthread_create(&cpucheckthread, NULL, PLAT_cpu_monitor, NULL) == 0) { - pthread_detach(cpucheckthread); - } - int selected_row = top->selected - top->start; float targetY; float previousY; diff --git a/workspace/desktop/platform/platform.c b/workspace/desktop/platform/platform.c index bdf3f65d5..ab9fe52c0 100644 --- a/workspace/desktop/platform/platform.c +++ b/workspace/desktop/platform/platform.c @@ -62,7 +62,6 @@ void PLAT_powerOff(int reboot) { /////////////////////////////// -volatile int useAutoCpu = 0; void PLAT_setCPUSpeed(int speed) { // buh } diff --git a/workspace/tg5040/platform/platform.c b/workspace/tg5040/platform/platform.c index 07b915b55..18075a49c 100644 --- a/workspace/tg5040/platform/platform.c +++ b/workspace/tg5040/platform/platform.c @@ -243,140 +243,53 @@ static pthread_mutex_t currentcpuinfo; // a roling average for the display values of about 2 frames, otherwise they are unreadable jumping too fast up and down and stuff to read #define ROLLING_WINDOW 120 -volatile int useAutoCpu = 1; void *PLAT_cpu_monitor(void *arg) { - struct timespec start_time, curr_time; - clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); - - long clock_ticks_per_sec = sysconf(_SC_CLK_TCK); + if (!Perf_tryBeginCPUMonitor()) return NULL; double prev_real_time = get_time_sec(); double prev_cpu_time = get_process_cpu_time_sec(); - // big Cortex-A53 CPUx4 - 408Mhz to 2160Mhz - // 408000 600000 816000 1008000 1200000 1416000 1608000 1800000 2000000 - const int cpu_frequencies[] = {408,600,816,1008,1200,1416,1608,1800,2000}; - const int num_freqs = sizeof(cpu_frequencies) / sizeof(cpu_frequencies[0]); - int current_index = 1; - double cpu_usage_history[ROLLING_WINDOW] = {0}; - double cpu_speed_history[ROLLING_WINDOW] = {0}; int history_index = 0; - int history_count = 0; - - while (true) { + int history_count = 0; - double curr_real_time = get_time_sec(); - double curr_cpu_time = get_process_cpu_time_sec(); + while (Perf_isCPUMonitorEnabled()) { + double curr_real_time = get_time_sec(); + double curr_cpu_time = get_process_cpu_time_sec(); - double elapsed_real_time = curr_real_time - prev_real_time; - double elapsed_cpu_time = curr_cpu_time - prev_cpu_time; + double elapsed_real_time = curr_real_time - prev_real_time; + double elapsed_cpu_time = curr_cpu_time - prev_cpu_time; - if (useAutoCpu) { - double cpu_usage = 0; - - if (elapsed_real_time > 0) { - cpu_usage = (elapsed_cpu_time / elapsed_real_time) * 100.0; - } + if (elapsed_real_time > 0) { + double cpu_usage = (elapsed_cpu_time / elapsed_real_time) * 100.0; pthread_mutex_lock(¤tcpuinfo); - // the goal here is is to keep cpu usage between 75% and 85% at the lowest possible speed so device stays cool and battery usage is at a minimum - // if usage falls out of this range it will either scale a step down or up - // but if usage hits above 95% we need that max boost and we instant scale up to 2000mhz as long as needed - // all this happens very fast like 60 times per second, so i'm applying roling averages to display values, so debug screen is readable and gives a good estimate on whats happening cpu wise - // the roling averages are purely for displaying, the actual scaling is happening realtime each run. - if (cpu_usage > 95) { - current_index = num_freqs - 1; // Instant power needed, cpu is above 95% Jump directly to max boost 2000MHz - } - else if (cpu_usage > 85 && current_index < num_freqs - 1) { // otherwise try to keep between 75 and 85 at lowest clock speed - current_index++; - } - else if (cpu_usage < 75 && current_index > 0) { - current_index--; - } - - PLAT_setCustomCPUSpeed(cpu_frequencies[current_index] * 1000); - cpu_usage_history[history_index] = cpu_usage; - cpu_speed_history[history_index] = cpu_frequencies[current_index]; - history_index = (history_index + 1) % ROLLING_WINDOW; - if (history_count < ROLLING_WINDOW) { - history_count++; - } - - double sum_cpu_usage = 0, sum_cpu_speed = 0; - for (int i = 0; i < history_count; i++) { - sum_cpu_usage += cpu_usage_history[i]; - sum_cpu_speed += cpu_speed_history[i]; - } + if (history_count < ROLLING_WINDOW) history_count++; + double sum_cpu_usage = 0; + for (int i = 0; i < history_count; i++) sum_cpu_usage += cpu_usage_history[i]; perf.cpu_usage = sum_cpu_usage / history_count; - //perf.cpu_speed = sum_cpu_speed / history_count; pthread_mutex_unlock(¤tcpuinfo); - - prev_real_time = curr_real_time; - prev_cpu_time = curr_cpu_time; - // 20ms really seems lowest i can go, anything lower it becomes innacurate, maybe one day I will find another even more granual way to calculate usage accurately and lower this shit to 1ms haha, altough anything lower than 10ms causes cpu usage in itself so yeah - // Anyways screw it 20ms is pretty much on a frame by frame basis anyways, so will anything lower really make a difference specially if that introduces cpu usage by itself? - // Who knows, maybe some CPU engineer will find my comment here one day and can explain, maybe this is looking for the limits of C and needs Assambler or whatever to call CPU instructions directly to go further, but all I know is PUSH and MOV, how did the orignal Roller Coaster Tycoon developer wrote a whole game like this anyways? Its insane.. - usleep(20000); - - } else { - // Just measure CPU usage without changing frequency - - if (elapsed_real_time > 0) { - double cpu_usage = (elapsed_cpu_time / elapsed_real_time) * 100.0; - - pthread_mutex_lock(¤tcpuinfo); - - cpu_usage_history[history_index] = cpu_usage; - - history_index = (history_index + 1) % ROLLING_WINDOW; - if (history_count < ROLLING_WINDOW) { - history_count++; - } - - double sum_cpu_usage = 0; - for (int i = 0; i < history_count; i++) { - sum_cpu_usage += cpu_usage_history[i]; - } - - perf.cpu_usage = sum_cpu_usage / history_count; - - pthread_mutex_unlock(¤tcpuinfo); - } - - prev_real_time = curr_real_time; - prev_cpu_time = curr_cpu_time; - usleep(100000); } + + prev_real_time = curr_real_time; + prev_cpu_time = curr_cpu_time; + usleep(100000); } -} + Perf_endCPUMonitor(); + return NULL; +} -#define GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed" void PLAT_setCustomCPUSpeed(int speed) { - FILE *fp = fopen(GOVERNOR_PATH, "w"); - if (fp == NULL) { - perror("Failed to open scaling_setspeed"); - return; - } - - fprintf(fp, "%d\n", speed); - fclose(fp); + // Frequency control is now handled by kernel governor scripts } void PLAT_setCPUSpeed(int speed) { - int freq = 0; - switch (speed) { - case CPU_SPEED_MENU: freq = 600000; perf.cpu_speed = 600; break; - case CPU_SPEED_POWERSAVE: freq = 1200000; perf.cpu_speed = 1200; break; - case CPU_SPEED_NORMAL: freq = 1608000; perf.cpu_speed = 1600; break; - case CPU_SPEED_PERFORMANCE: freq = 2000000; perf.cpu_speed = 2000; break; - } - putInt(GOVERNOR_PATH, freq); + // Frequency control is now handled by kernel governor scripts } #define MAX_STRENGTH 0xFFFF diff --git a/workspace/tg5050/platform/platform.c b/workspace/tg5050/platform/platform.c index cef0e80d0..38cf8cc39 100644 --- a/workspace/tg5050/platform/platform.c +++ b/workspace/tg5050/platform/platform.c @@ -288,144 +288,53 @@ void PLAT_pinToCores(int core_type) LOG_error("Failed to pin: Are all cores sleeping?\n"); } -volatile int useAutoCpu = 1; void *PLAT_cpu_monitor(void *arg) { - struct timespec start_time, curr_time; - clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); - - long clock_ticks_per_sec = sysconf(_SC_CLK_TCK); + if (!Perf_tryBeginCPUMonitor()) return NULL; double prev_real_time = get_time_sec(); double prev_cpu_time = get_process_cpu_time_sec(); - // big Cortex-A55 CPU4 - 408Mhz to 2160Mhz - // 408000 672000 840000 1008000 1200000 1344000 1488000 1584000 1680000 1800000 1992000 2088000 2160000 - const int big_cpu_frequencies[] = {408,672,840,1008,1200,1344,1488,1584,1680,1800,1992,2088,2160}; - const int big_num_freqs = sizeof(big_cpu_frequencies) / sizeof(big_cpu_frequencies[0]); - int big_index = 1; // 672Mhz start - // little Cortex-A55 CPU0 - 408Mhz to 1416Mhz - // 408000 672000 792000 936000 1032000 1128000 1224000 1320000 1416000 - const int little_cpu_frequencies[] = {408,672,792,936,1032,1128,1224,1320,1416}; - const int little_num_freqs = sizeof(little_cpu_frequencies) / sizeof(little_cpu_frequencies[0]); - int little_index = 1; // 672Mhz start - double cpu_usage_history[ROLLING_WINDOW] = {0}; - double cpu_speed_history[ROLLING_WINDOW] = {0}; int history_index = 0; - int history_count = 0; - - while (true) { + int history_count = 0; - double curr_real_time = get_time_sec(); - double curr_cpu_time = get_process_cpu_time_sec(); + while (Perf_isCPUMonitorEnabled()) { + double curr_real_time = get_time_sec(); + double curr_cpu_time = get_process_cpu_time_sec(); - double elapsed_real_time = curr_real_time - prev_real_time; - double elapsed_cpu_time = curr_cpu_time - prev_cpu_time; + double elapsed_real_time = curr_real_time - prev_real_time; + double elapsed_cpu_time = curr_cpu_time - prev_cpu_time; - if (useAutoCpu) { - double cpu_usage = 0; - - if (elapsed_real_time > 0) { - cpu_usage = (elapsed_cpu_time / elapsed_real_time) * 100.0; - } + if (elapsed_real_time > 0) { + double cpu_usage = (elapsed_cpu_time / elapsed_real_time) * 100.0; pthread_mutex_lock(¤tcpuinfo); - // the goal here is is to keep cpu usage between 75% and 85% at the lowest possible speed so device stays cool and battery usage is at a minimum - // if usage falls out of this range it will either scale a step down or up - // but if usage hits above 95% we need that max boost and we instant scale up to 2000mhz as long as needed - // all this happens very fast like 60 times per second, so i'm applying roling averages to display values, so debug screen is readable and gives a good estimate on whats happening cpu wise - // the roling averages are purely for displaying, the actual scaling is happening realtime each run. - if (cpu_usage > 95) { - big_index = big_num_freqs - 1; // Instant power needed, cpu is above 95% Jump directly to max boost 2000MHz - } - else if (cpu_usage > 85 && big_index < big_num_freqs - 1) { // otherwise try to keep between 75 and 85 at lowest clock speed - big_index++; - } - else if (cpu_usage < 75 && big_index > 0) { - big_index--; - } - - PLAT_setCustomCPUSpeed(big_cpu_frequencies[big_index] * 1000); - cpu_usage_history[history_index] = cpu_usage; - cpu_speed_history[history_index] = big_cpu_frequencies[big_index]; - history_index = (history_index + 1) % ROLLING_WINDOW; - if (history_count < ROLLING_WINDOW) { - history_count++; - } - - double sum_cpu_usage = 0, sum_cpu_speed = 0; - for (int i = 0; i < history_count; i++) { - sum_cpu_usage += cpu_usage_history[i]; - sum_cpu_speed += cpu_speed_history[i]; - } + if (history_count < ROLLING_WINDOW) history_count++; + double sum_cpu_usage = 0; + for (int i = 0; i < history_count; i++) sum_cpu_usage += cpu_usage_history[i]; perf.cpu_usage = sum_cpu_usage / history_count; - //perf.cpu_speed = sum_cpu_speed / history_count; pthread_mutex_unlock(¤tcpuinfo); - - prev_real_time = curr_real_time; - prev_cpu_time = curr_cpu_time; - // 20ms really seems lowest i can go, anything lower it becomes innacurate, maybe one day I will find another even more granual way to calculate usage accurately and lower this shit to 1ms haha, altough anything lower than 10ms causes cpu usage in itself so yeah - // Anyways screw it 20ms is pretty much on a frame by frame basis anyways, so will anything lower really make a difference specially if that introduces cpu usage by itself? - // Who knows, maybe some CPU engineer will find my comment here one day and can explain, maybe this is looking for the limits of C and needs Assambler or whatever to call CPU instructions directly to go further, but all I know is PUSH and MOV, how did the orignal Roller Coaster Tycoon developer wrote a whole game like this anyways? Its insane.. - usleep(20000); - } else { - // Just measure CPU usage without changing frequency - - if (elapsed_real_time > 0) { - double cpu_usage = (elapsed_cpu_time / elapsed_real_time) * 100.0; - - pthread_mutex_lock(¤tcpuinfo); - - cpu_usage_history[history_index] = cpu_usage; - - history_index = (history_index + 1) % ROLLING_WINDOW; - if (history_count < ROLLING_WINDOW) { - history_count++; - } - - double sum_cpu_usage = 0; - for (int i = 0; i < history_count; i++) { - sum_cpu_usage += cpu_usage_history[i]; - } - - perf.cpu_usage = sum_cpu_usage / history_count; - - pthread_mutex_unlock(¤tcpuinfo); - } - - prev_real_time = curr_real_time; - prev_cpu_time = curr_cpu_time; - usleep(100000); } + + prev_real_time = curr_real_time; + prev_cpu_time = curr_cpu_time; + usleep(100000); } -} + Perf_endCPUMonitor(); + return NULL; +} -#define GOVERNOR_PATH "/sys/devices/system/cpu/cpu4/cpufreq/scaling_setspeed" void PLAT_setCustomCPUSpeed(int speed) { - FILE *fp = fopen(GOVERNOR_PATH, "w"); - if (fp == NULL) { - perror("Failed to open scaling_setspeed"); - return; - } - - fprintf(fp, "%d\n", speed); - fclose(fp); + // Frequency control is now handled by kernel governor scripts } void PLAT_setCPUSpeed(int speed) { - int freq = 0; - switch (speed) { - case CPU_SPEED_MENU: freq = 672000; perf.cpu_speed = 672; break; - case CPU_SPEED_POWERSAVE: freq = 1200000; perf.cpu_speed = 1200; break; - case CPU_SPEED_NORMAL: freq = 1680000; perf.cpu_speed = 1680; break; - case CPU_SPEED_PERFORMANCE: freq = 2160000; perf.cpu_speed = 2160; break; - } - putInt(GOVERNOR_PATH, freq); + // Frequency control is now handled by kernel governor scripts } #define MAX_STRENGTH 0xFFFF