> This is part 2 of the apmd patch. The problem it addresses is simple: when
> running off battery power, the last thing one wants as battery power gets
> low is for the CPU to be set to its maximum power draw!
>
> This patch alters apmd so that (in both -A and -C modes) as the remaining
> battery power gets lower, it progressively lowers the maximum value that
> setperf is raised to. A simple heuristic is used so that up to 50% the
> maximum value of setperf is 100; below 50% the maxmum value of setperf then
> logarithmically decreases until battery life reaches 12%, when setperf is
> not raised above 0. Similarly if the battery state becomes critical or low,
> setperf is not raised above 0.
>
> One minor change to apmd that this patch makes is to force a check of the
> power state every minute rather than every 10 minutes as was previously the
> case, in order that the checks on battery life and state use reasonably
> current data.
>
>
> Laurie
> --
>
http://tratt.net/laurie/ -- Personal
>
http://fetegeo.org/ -- Free text geocoding
>
http://convergepl.org/ -- The Converge programming language
>
>
> --- apmd.c.orig Tue Feb 3 01:52:49 2009
> +++ apmd.c Tue Feb 3 22:51:42 2009
> @@ -48,6 +48,7 @@
> #include <signal.h>
> #include <errno.h>
> #include <err.h>
> +#include <math.h>
> #include <machine/apmvar.h>
> #include "pathnames.h"
> #include "apm-proto.h"
> @@ -258,28 +259,59 @@
> useconds_t
> perf_status(struct apm_power_info *pinfo, int ncpu)
> {
> - int avg_idle, min_idle;
> + int min_idle;
> int hw_perf_mib[] = {CTL_HW, HW_SETPERF};
> - int perf;
> + int perf, perfmax;
> int forcehi = 0;
> size_t perf_sz = sizeof(perf);
>
> - if (avg_idle == -1)
> - return PERFTIMEOUTERR;
> -
> if (sysctl(hw_perf_mib, 2, &perf, &perf_sz, NULL, 0) < 0)
> syslog(LOG_INFO, "cannot read hw.setperf");
>
> + if (pinfo->ac_state == APM_AC_ON) {
> + perfmax = PERFMAX;
> + }
> + else {
> + if (pinfo->battery_state == APM_BATT_LOW ||
> + pinfo->battery_state == APM_BATT_CRITICAL)
> + perfmax = 0;
> + else if (pinfo->battery_state == APM_BATT_UNKNOWN ||
> + pinfo->battery_state == APM_BATTERY_ABSENT)
> + perfmax = PERFMAX;
> + else {
> + /* This is a heuristic which allows hw.setperf to be set to
> + maximum until battery life is gone below 50%, then uses a
> + logarithmically descending scale to determine the maximum
> + value of hw.setperf relative to battery life, with
> + hw.setperf being set to 0 when battery life has got to
> + 12% or less. */
> + if (pinfo->battery_life >= 50)
> + perfmax = PERFMAX;
> + else if (pinfo->battery_life == 0)
> + perfmax = PERFMIN;
> + else {
> + perfmax = log10(pinfo->battery_life / 12.0) * 1.5 * 100;
> + if (perfmax > PERFMAX)
> + perfmax = PERFMAX;
> + else if (perfmax < PERFMIN)
> + perfmax = PERFMIN;
> + }
> + }
> + }
> +
> switch (doperf) {
> case PERF_AUTO:
> if (pinfo->ac_state == APM_AC_ON && pinfo->battery_life > 15)
> forcehi = 1;
> case PERF_COOL:
> min_idle = get_min_idle_mp(ncpu);
> - if (forcehi || (min_idle < PERFINCTHRES && perf < PERFMAX)) {
> + if (min_idle == -1)
> + return PERFTIMEOUTERR;
> +
> + if (forcehi || (min_idle < PERFINCTHRES && perf < perfmax)) {
> perf += PERFINC;
> - if (perf > PERFMAX)
> - perf = PERFMAX;
> + if (perf > perfmax)
> + perf = perfmax;
> setperf(perf);
> return PERFTIMEOUTFAST;
> } else if (min_idle > PERFDECTHRES && perf > PERFMIN) {
> @@ -433,7 +465,7 @@
> ioctl(ctl_fd, APM_IOC_STANDBY, 0);
> }
>
> -#define TIMO (10*60) /* 10 minutes */
> +#define TIMO 60 /* 1 minute */
>
> int
> main(int argc, char *argv[])
> @@ -595,9 +627,11 @@
> if (doperf == PERF_AUTO || doperf == PERF_COOL) {
> sts.tv_sec = 0;
> sts.tv_nsec = perf_status(&pinfo, ncpu);
> + apmtimeout += 1;
> }
> -
> - apmtimeout += sts.tv_sec;
> + else
> + apmtimeout += sts.tv_sec;
> +
> if ((rv = kevent(kq, NULL, 0, ev, 1, &sts)) < 0)
> break;
>
> --- Makefile.orig Tue Feb 3 19:17:50 2009
> +++ Makefile Tue Feb 3 20:08:10 2009
> @@ -6,6 +6,7 @@
> SRCS= apmd.c apmsubr.c
>
> PROG= apmd
> +LDADD= -lm
> .else
> NOPROG=yes
> .endif
>