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";
>       }
> 

Reply via email to