From: Kirill A. Korinsky Subject: Re: improvement of perfpolicy auto To: Vitaliy Makkoveev Cc: Ted Unangst , tech@openbsd.org Date: Fri, 16 May 2025 02:51:54 +0200 On Thu, 15 May 2025 23:25:53 +0200, Vitaliy Makkoveev wrote: > > I could say my > gnome session works acceptable. > I think that it can be improved. May I ask you to try this version and try different hw.autoperfpolint? My bet that 100 ms is too slow to change speed and smaller value, like 50 or 10 ms, is that should be used. Index: sys/kern/kern_sysctl.c =================================================================== RCS file: /home/cvs/src/sys/kern/kern_sysctl.c,v diff -u -p -r1.468 kern_sysctl.c --- sys/kern/kern_sysctl.c 9 May 2025 14:53:22 -0000 1.468 +++ sys/kern/kern_sysctl.c 15 May 2025 23:32:47 -0000 @@ -851,6 +851,7 @@ hw_sysctl(int *name, u_int namelen, void case HW_SENSORS: case HW_SETPERF: case HW_PERFPOLICY: + case HW_PERFPOLICY_AUTO_INT: case HW_BATTERY: #endif /* !SMALL_KERNEL */ case HW_ALLOWPOWERDOWN: @@ -944,6 +945,8 @@ hw_sysctl_locked(int *name, u_int namele return (sysctl_hwsetperf(oldp, oldlenp, newp, newlen)); case HW_PERFPOLICY: return (sysctl_hwperfpolicy(oldp, oldlenp, newp, newlen)); + case HW_PERFPOLICY_AUTO_INT: + return (sysctl_hwperfpolicy_auto_int(oldp, oldlenp, newp, newlen)); #endif /* !SMALL_KERNEL */ case HW_ALLOWPOWERDOWN: return (sysctl_securelevel_int(oldp, oldlenp, newp, newlen, Index: sys/kern/sched_bsd.c =================================================================== RCS file: /home/cvs/src/sys/kern/sched_bsd.c,v diff -u -p -r1.99 sched_bsd.c --- sys/kern/sched_bsd.c 10 Mar 2025 09:28:56 -0000 1.99 +++ sys/kern/sched_bsd.c 16 May 2025 00:39:48 -0000 @@ -575,16 +575,22 @@ current_perfpolicy(void) return (hw_power) ? perfpolicy_on_ac : perfpolicy_on_battery; } +#define PERFPOL_AUTO_HW_POWER_HIGH 80 +#define PERFPOL_AUTO_AC_POWER_HIGH 95 + +static int perfpol_auto_interval_ms = 100; + void setperf_auto(void *v) { - static uint64_t *idleticks, *totalticks; - static int downbeats; - int i, j = 0; - int speedup = 0; + static struct timespec last, *idletimes; + int i = 0; + int speedup = 0, load = 0, speed = 0; + uint64_t idle, window; CPU_INFO_ITERATOR cii; struct cpu_info *ci; - uint64_t idle, total, allidle = 0, alltotal = 0; + struct timespec now, ts, its; + struct schedstate_percpu *spc; if (!perfpolicy_dynamic()) return; @@ -597,49 +603,70 @@ setperf_auto(void *v) goto faster; } - if (!idleticks) - if (!(idleticks = mallocarray(ncpusfound, sizeof(*idleticks), + if (!idletimes) + if (!(idletimes = mallocarray(ncpusfound, sizeof(*idletimes), M_DEVBUF, M_NOWAIT | M_ZERO))) return; - if (!totalticks) - if (!(totalticks = mallocarray(ncpusfound, sizeof(*totalticks), - M_DEVBUF, M_NOWAIT | M_ZERO))) { - free(idleticks, M_DEVBUF, - sizeof(*idleticks) * ncpusfound); - return; - } + + nanouptime(&now); + timespecsub(&now, &last, &ts); + last = now; + /* window = TIMESPEC_TO_NSEC(&ts) / 1000000ULL; */ + window = TIMESPEC_TO_NSEC(&ts); + CPU_INFO_FOREACH(cii, ci) { if (!cpu_is_online(ci)) continue; - total = 0; - for (i = 0; i < CPUSTATES; i++) { - total += ci->ci_schedstate.spc_cp_time[i]; - } - total -= totalticks[j]; - idle = ci->ci_schedstate.spc_cp_time[CP_IDLE] - idleticks[j]; - if (idle < total / 3) - speedup = 1; - alltotal += total; - allidle += idle; - idleticks[j] += idle; - totalticks[j] += total; - j++; + + spc = &ci->ci_schedstate; + + ts = spc->spc_runtime; + its = spc->spc_idleproc->p_tu.tu_runtime; + + if (ci->ci_curproc == spc->spc_idleproc && + timespeccmp(&ts, &spc->spc_runtime, ==) && + timespeccmp(&now, &ts, >)) + timespecsub(&now, &ts, &ts); + else + timespecclear(&ts); + + timespecsub(&its, &idletimes[i], &its); + timespecadd(&idletimes[i], &its, &idletimes[i]); + + timespecadd(&ts, &its, &ts); + + /* idle = TIMESPEC_TO_NSEC(&ts) / 1000000ULL; */ + idle = TIMESPEC_TO_NSEC(&ts); + + if (idle <= 0) + speed = 100; + + if (idle > window) + load = 0; + else + load = (100 * (window - idle)) / window; + + if (load > speed) + speed = load; + + i++; } - if (allidle < alltotal / 2) + + if (hw_power && speed >= PERFPOL_AUTO_HW_POWER_HIGH) + speedup = 1; + else if (speed >= PERFPOL_AUTO_AC_POWER_HIGH) speedup = 1; - if (speedup && downbeats < 5) - downbeats++; if (speedup && perflevel != 100) { faster: perflevel = 100; cpu_setperf(perflevel); - } else if (!speedup && perflevel != 0 && --downbeats <= 0) { - perflevel = 0; + } else if (!speedup && speed != perflevel) { + perflevel = speed; cpu_setperf(perflevel); } - timeout_add_msec(&setperf_to, 100); + timeout_add_msec(&setperf_to, perfpol_auto_interval_ms); } int @@ -737,6 +764,17 @@ sysctl_hwperfpolicy(void *oldp, size_t * timeout_add_msec(&setperf_to, 200); return 0; +} + +int +sysctl_hwperfpolicy_auto_int(void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + if (!cpu_setperf) + return EOPNOTSUPP; + + return sysctl_int_bounded(oldp, oldlenp, newp, newlen, + &perfpol_auto_interval_ms, 1, 1000); } #endif Index: sys/sys/sched.h =================================================================== RCS file: /home/cvs/src/sys/sys/sched.h,v diff -u -p -r1.73 sched.h --- sys/sys/sched.h 8 Jul 2024 14:46:47 -0000 1.73 +++ sys/sys/sched.h 15 May 2025 23:33:10 -0000 @@ -174,6 +174,7 @@ void sched_barrier(struct cpu_info *ci); int sysctl_hwsetperf(void *, size_t *, void *, size_t); int sysctl_hwperfpolicy(void *, size_t *, void *, size_t); +int sysctl_hwperfpolicy_auto_int(void *, size_t *, void *, size_t); int sysctl_hwsmt(void *, size_t *, void *, size_t); int sysctl_hwncpuonline(void); Index: sys/sys/sysctl.h =================================================================== RCS file: /home/cvs/src/sys/sys/sysctl.h,v diff -u -p -r1.242 sysctl.h --- sys/sys/sysctl.h 29 Apr 2025 02:24:32 -0000 1.242 +++ sys/sys/sysctl.h 16 May 2025 00:34:48 -0000 @@ -926,7 +926,8 @@ struct kinfo_file { #define HW_POWER 26 /* int: machine has wall-power */ #define HW_BATTERY 27 /* node: battery */ #define HW_UCOMNAMES 28 /* strings: ucom names */ -#define HW_MAXID 29 /* number of valid hw ids */ +#define HW_PERFPOLICY_AUTO_INT 29 /* set auto perfpolicy interval */ +#define HW_MAXID 30 /* number of valid hw ids */ #define CTL_HW_NAMES { \ { 0, 0 }, \ @@ -958,6 +959,7 @@ struct kinfo_file { { "power", CTLTYPE_INT }, \ { "battery", CTLTYPE_NODE }, \ { "ucomnames", CTLTYPE_STRING }, \ + { "autoperfpolint", CTLTYPE_INT }, \ } /* -- wbr, Kirill