Hello, I've been using this diff for a week now. I didn't encounter any issue.
As my laptop has a quite old battery, I noticed improvements : I can work 30min longer on battery now. The systemp is a bit slower though (ie libreoffice longer to start), but that was expected and I must say I didn't feel any discomfort either. >From a non-power-tech user point of view, this patch is a great improvement. Regards. prx * Solene Rapenne <sol...@perso.pw> le [25-09-2021 20:26:06 +0200]: > Last time I proposed a CPU frequency scheduling change to make it > more performance oriented, however this would hurt badly the battery > life for nomad users. > > As we don't like tweaks and complicated settings, I create a new > CPU frequency policy that is oriented for nomad users, it reduces > performance a bit but from my (short) experiments it would give a > way better battery life while keeping the system responsive which > is not allowing apm -L > > The current auto mode is kept as it is now and I added a new > powersaving mode that will be triggered automatically by apmd when > the system is on battery AND automatic mode is activated. > > So, on A/C you have the usual automatic policy and on battery it > would switch on the new powersaving policy. > > I hope this could be useful for nomad people and later we could > tune the automatic mode (to be used on A/C) to be giving more > performance, without affecting people on battery. > > The code change is relatively simple, I'm pretty sure this can be > improved but I wanted to share it as this for now so people can > comment and/or try it out. > > I created a new policy which is basically a copy/paste of the current > one with a different name and differents thresholds, declared it > in apmd. There is another change in apmd to check on event if we > are using the policy auto and if on battery or not, this takes care > of changing the policy automatically. I'm not sure it's at the right > place. As for the code in the kernel, I'm quite sure it could be > merged into one and use different thresholds depending on the policy > name currently in use. > > Kernel + usr.sbin/apmd + usr.sbin/apm recompilation required > > Index: sys/kern//sched_bsd.c > =================================================================== > RCS file: /home/reposync/src/sys/kern/sched_bsd.c,v > retrieving revision 1.69 > diff -u -p -r1.69 sched_bsd.c > --- sys/kern//sched_bsd.c 9 Sep 2021 18:41:39 -0000 1.69 > +++ sys/kern//sched_bsd.c 25 Sep 2021 18:09:40 -0000 > @@ -531,6 +531,7 @@ void (*cpu_setperf)(int); > #define PERFPOL_MANUAL 0 > #define PERFPOL_AUTO 1 > #define PERFPOL_HIGH 2 > +#define PERFPOL_POWERSAVING 4 > int perflevel = 100; > int perfpolicy = PERFPOL_MANUAL; > > @@ -541,7 +542,9 @@ int perfpolicy = PERFPOL_MANUAL; > #include <sys/sysctl.h> > > void setperf_auto(void *); > +void setperf_powersaving(void *); > struct timeout setperf_to = TIMEOUT_INITIALIZER(setperf_auto, NULL); > +struct timeout setperf_to_powersaving = > TIMEOUT_INITIALIZER(setperf_powersaving, NULL); > > void > setperf_auto(void *v) > @@ -606,6 +609,73 @@ setperf_auto(void *v) > timeout_add_msec(&setperf_to, 100); > } > > +void > +setperf_powersaving(void *v) > +{ > + static uint64_t *idleticks, *totalticks; > + static int downbeats; > + > + int i, j; > + int speedup; > + CPU_INFO_ITERATOR cii; > + struct cpu_info *ci; > + uint64_t idle, total, allidle, alltotal; > + > + if (perfpolicy != PERFPOL_POWERSAVING) > + return; > + > + if (!idleticks) > + if (!(idleticks = mallocarray(ncpusfound, sizeof(*idleticks), > + 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; > + } > + > + alltotal = allidle = 0; > + j = 0; > + speedup = 0; > + 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]; > + // speedup if at least one core idle time < 33% > + if (idle < total / 3) > + speedup = 1; > + alltotal += total; > + allidle += idle; > + idleticks[j] += idle; > + totalticks[j] += total; > + j++; > + } > + if (allidle < alltotal / 3) > + speedup = 1; > + if (speedup) > + /* twice as long here because we check every 200ms */ > + downbeats = 1; > + > + if (speedup && perflevel != 100) { > + perflevel = 100; > + cpu_setperf(perflevel); > + } else if (!speedup && perflevel != 0 && --downbeats <= 0) { > + perflevel = 0; > + cpu_setperf(perflevel); > + } > + > + /* every 200ms to have a better resolution of the load */ > + timeout_add_msec(&setperf_to_powersaving, 200); > +} > + > + > int > sysctl_hwsetperf(void *oldp, size_t *oldlenp, void *newp, size_t newlen) > { > @@ -644,6 +714,9 @@ sysctl_hwperfpolicy(void *oldp, size_t * > case PERFPOL_AUTO: > strlcpy(policy, "auto", sizeof(policy)); > break; > + case PERFPOL_POWERSAVING: > + strlcpy(policy, "powersaving", sizeof(policy)); > + break; > case PERFPOL_HIGH: > strlcpy(policy, "high", sizeof(policy)); > break; > @@ -662,6 +735,8 @@ sysctl_hwperfpolicy(void *oldp, size_t * > perfpolicy = PERFPOL_MANUAL; > else if (strcmp(policy, "auto") == 0) > perfpolicy = PERFPOL_AUTO; > + else if (strcmp(policy, "powersaving") == 0) > + perfpolicy = PERFPOL_POWERSAVING; > else if (strcmp(policy, "high") == 0) > perfpolicy = PERFPOL_HIGH; > else > @@ -669,6 +744,8 @@ sysctl_hwperfpolicy(void *oldp, size_t * > > if (perfpolicy == PERFPOL_AUTO) { > timeout_add_msec(&setperf_to, 200); > + } else if (perfpolicy == PERFPOL_POWERSAVING) { > + timeout_add_msec(&setperf_to_powersaving, 200); > } else if (perfpolicy == PERFPOL_HIGH) { > perflevel = 100; > cpu_setperf(perflevel); > Index: usr.sbin/apmd//apm-proto.h > =================================================================== > RCS file: /home/reposync/src/usr.sbin/apmd/apm-proto.h,v > retrieving revision 1.12 > diff -u -p -r1.12 apm-proto.h > --- usr.sbin/apmd//apm-proto.h 6 Apr 2021 22:09:56 -0000 1.12 > +++ usr.sbin/apmd//apm-proto.h 25 Sep 2021 18:04:14 -0000 > @@ -38,6 +38,7 @@ enum apm_action { > SETPERF_LOW, > SETPERF_HIGH, > SETPERF_AUTO, > + SETPERF_POWERSAVING, > }; > > enum apm_state { > @@ -51,6 +52,7 @@ enum apm_perfmode { > PERF_NONE = -1, > PERF_MANUAL, > PERF_AUTO, > + PERF_POWERSAVING, > }; > > struct apm_command { > Index: usr.sbin/apmd//apmd.c > =================================================================== > RCS file: /home/reposync/src/usr.sbin/apmd/apmd.c,v > retrieving revision 1.106 > diff -u -p -r1.106 apmd.c > --- usr.sbin/apmd//apmd.c 12 Jul 2021 15:09:20 -0000 1.106 > +++ usr.sbin/apmd//apmd.c 25 Sep 2021 18:04:39 -0000 > @@ -140,6 +140,11 @@ power_status(int fd, int force, struct a > static struct apm_power_info last; > int acon = 0, priority = LOG_NOTICE; > > + /* solene */ > + int perfpol_mib[] = { CTL_HW, HW_PERFPOLICY }; > + char perfpol[32]; > + size_t perfpol_sz = sizeof(perfpol); > + > if (fd == -1) { > if (pinfo) { > bstate.battery_state = 255; > @@ -152,11 +157,18 @@ power_status(int fd, int force, struct a > return 0; > } > > + if (sysctl(perfpol_mib, 2, perfpol, &perfpol_sz, NULL, 0) == -1) > + logmsg(LOG_INFO, "cannot read hw.perfpolicy"); > + > if (ioctl(fd, APM_IOC_GETPOWER, &bstate) == 0) { > /* various conditions under which we report status: something changed > * enough since last report, or asked to force a print */ > - if (bstate.ac_state == APM_AC_ON) > + if (bstate.ac_state == APM_AC_ON) { > acon = 1; > + if(strcmp(perfpol, "powersaving") == 0) > setperfpolicy("auto"); > + } else > + if(strcmp(perfpol, "auto") == 0) > setperfpolicy("powersaving"); > + > if (bstate.battery_state == APM_BATT_CRITICAL && > bstate.battery_state != last.battery_state) > priority = LOG_EMERG; > @@ -291,6 +303,11 @@ handle_client(int sock_fd, int ctl_fd) > logmsg(LOG_NOTICE, "setting hw.perfpolicy to high"); > setperfpolicy("high"); > break; > + case SETPERF_POWERSAVING: > + reply.newstate = NORMAL; > + logmsg(LOG_NOTICE, "setting hw.perfpolicy to powersaving"); > + setperfpolicy("powersaving"); > + break; > case SETPERF_AUTO: > reply.newstate = NORMAL; > logmsg(LOG_NOTICE, "setting hw.perfpolicy to auto"); > @@ -308,8 +325,10 @@ handle_client(int sock_fd, int ctl_fd) > if (strcmp(perfpol, "manual") == 0 || > strcmp(perfpol, "high") == 0) { > reply.perfmode = PERF_MANUAL; > - } else if (strcmp(perfpol, "auto") == 0) > + } else if (strcmp(perfpol, "auto") == 0) { > reply.perfmode = PERF_AUTO; > + } else if (strcmp(perfpol, "powersaving") == 0) > + reply.perfmode = PERF_POWERSAVING; > } > > if (sysctl(cpuspeed_mib, 2, &cpuspeed, &cpuspeed_sz, NULL, 0) == -1) { > @@ -593,6 +612,8 @@ main(int argc, char *argv[]) > powerstatus = powerbak; > powerchange = 1; > } > + > + > > if (!powerstatus && autoaction && > autolimit > (int)pinfo.battery_life) { > Index: usr.sbin/apmd//apmsubr.c > =================================================================== > RCS file: /home/reposync/src/usr.sbin/apmd/apmsubr.c,v > retrieving revision 1.12 > diff -u -p -r1.12 apmsubr.c > --- usr.sbin/apmd//apmsubr.c 8 Jul 2021 18:54:21 -0000 1.12 > +++ usr.sbin/apmd//apmsubr.c 25 Sep 2021 18:04:26 -0000 > @@ -79,6 +79,8 @@ perf_mode(int mode) > return "manual"; > case PERF_AUTO: > return "auto"; > + case PERF_POWERSAVING: > + return "powersaving"; > default: > return "invalid"; > } >