18 months ago I posted a patch to make apmd's -C and -A modes work
half-sensibly on multi-processor machines:

  http://marc.info/?l=openbsd-tech&m=123315164930014&w=2

The patch went into the tree but was backed out because on some very slow,
very old Sparc machines it apparently couldn't react quickly enough to
changes in processor utilisation. Since I had no access to such a machine, I
couldn't debug it, and the patch died. That means that apmd -C has been
close to useless on MP machines, since it needs all CPUs to be working hard
before it increases hw.setperf.

One day hopefully this functionality will move into the kernel (I know Ted
and others are working towards that), but in the meantime someone asked me
if I could resurrect the backed-out patch which I attach to the end of this
e-mail. This patch cranks hw.setperf to 100 as soon as increased activity is
noticed and then gradually backs it off it can (in contrast to the old patch
which ramped up gradually; the new behaviour should increase battery life).
It also reflects recent changes to apmd.c. Apart from that it's largely the
same as before. It's been working for me over the last few days, but hasn't
been extensively tested so YMMV. However, if you work off battery on an MP
machine, you might find it helpful.


Laurie
-- 
http://tratt.net/laurie/ -- Personal
http://fetegeo.org/      -- Free text geocoding
http://convergepl.org/   -- The Converge programming language


Index: apmd.c
===================================================================
RCS file: /cvs/src/usr.sbin/apmd/apmd.c,v
retrieving revision 1.56
diff -u -r1.56 apmd.c
--- apmd.c      2 Apr 2010 04:12:46 -0000       1.56
+++ apmd.c      27 Jun 2010 12:05:11 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: apmd.c,v 1.56 2010/04/02 04:12:46 deraadt Exp $       */
+/*     $OpenBSD: apmd.c,v 1.51 2009/02/04 05:22:58 tedu Exp $  */
 
 /*
  *  Copyright (c) 1995, 1996 John T. Kohl
@@ -61,12 +61,14 @@
 int debug = 0;
 
 int doperf = PERF_NONE;
-#define PERFINC 50
-#define PERFDEC 20
+#define PERFDEC 15
 #define PERFMIN 0
 #define PERFMAX 100
 #define PERFINCTHRES 10
 #define PERFDECTHRES 30
+#define PERFTIMEOUTERR 999999999
+#define PERFTIMEOUTFAST 10000000
+#define PERFTIMEOUTSLOW 25000000
 
 extern char *__progname;
 
@@ -74,9 +76,8 @@
 int power_status(int fd, int force, struct apm_power_info *pinfo);
 int bind_socket(const char *sn);
 enum apm_state handle_client(int sock_fd, int ctl_fd);
-int  get_avg_idle_mp(int ncpu);
-int  get_avg_idle_up(void);
-void perf_status(struct apm_power_info *pinfo, int ncpu);
+int  get_min_idle_mp(int ncpu);
+useconds_t perf_status(struct apm_power_info *pinfo, int ncpu);
 void suspend(int ctl_fd);
 void stand_by(int ctl_fd);
 void setperf(int new_perf);
@@ -195,13 +196,12 @@
 
 /* multi- and uni-processor case */
 int
-get_avg_idle_mp(int ncpu)
+get_min_idle_mp(int ncpu)
 {
        static int64_t **cp_time_old;
        static int64_t **cp_time;
-       static int *avg_idle;
        int64_t change, sum, idle;
-       int i, cpu, min_avg_idle;
+       int i, cpu, min_idle;
        size_t cp_time_sz = CPUSTATES * sizeof(int64_t);
 
        if (!cp_time_old)
@@ -212,11 +212,7 @@
                if ((cp_time = calloc(sizeof(int64_t *), ncpu)) == NULL)
                        return -1;
 
-       if (!avg_idle)
-               if ((avg_idle = calloc(sizeof(int), ncpu)) == NULL)
-                       return -1;
-
-       min_avg_idle = 0;
+       min_idle = 100;
        for (cpu = 0; cpu < ncpu; cpu++) {
                int cp_time_mib[] = {CTL_KERN, KERN_CPTIME2, cpu};
 
@@ -230,14 +226,14 @@
                            calloc(sizeof(int64_t), CPUSTATES)) == NULL)
                                return -1;
 
-               if (sysctl(cp_time_mib, 3, cp_time[cpu], &cp_time_sz, NULL, 0)
-                   < 0)
+               if (sysctl(cp_time_mib, 3, cp_time[cpu], &cp_time_sz, NULL, 0))
                        syslog(LOG_INFO, "cannot read kern.cp_time2");
 
                sum = 0;
+               idle = 100;
                for (i = 0; i < CPUSTATES; i++) {
-                       if ((change = cp_time[cpu][i] - cp_time_old[cpu][i])
-                           < 0) {
+                       change = cp_time[cpu][i] - cp_time_old[cpu][i];
+                       if (change < 0) {
                                /* counter wrapped */
                                change = ((uint64_t)cp_time[cpu][i] -
                                    (uint64_t)cp_time_old[cpu][i]);
@@ -249,72 +245,28 @@
                if (sum == 0)
                        sum = 1;
 
-               /* smooth data */
-               avg_idle[cpu] = (avg_idle[cpu] + (100 * idle) / sum) / 2;
-
-               if (cpu == 0)
-                       min_avg_idle = avg_idle[cpu];
-
-               if (avg_idle[cpu] < min_avg_idle)
-                       min_avg_idle = avg_idle[cpu];
+               if ((100 * idle) / sum < min_idle)
+                       min_idle = (100 * idle) / sum;
 
                memcpy(cp_time_old[cpu], cp_time[cpu], cp_time_sz);
        }
 
-       return min_avg_idle;
-}
-
-int
-get_avg_idle_up(void)
-{
-       static long cp_time_old[CPUSTATES];
-       static int avg_idle;
-       long change, cp_time[CPUSTATES];
-       int cp_time_mib[] = {CTL_KERN, KERN_CPTIME};
-       size_t cp_time_sz = sizeof(cp_time);
-       int i, idle, sum = 0;
-
-       if (sysctl(cp_time_mib, 2, &cp_time, &cp_time_sz, NULL, 0) < 0)
-               syslog(LOG_INFO, "cannot read kern.cp_time");
-
-       for (i = 0; i < CPUSTATES; i++) {
-               if ((change = cp_time[i] - cp_time_old[i]) < 0) {
-                       /* counter wrapped */
-                       change = ((unsigned long)cp_time[i] -
-                           (unsigned long)cp_time_old[i]);
-               }
-               sum += change;
-               if (i == CP_IDLE)
-                       idle = change;
-       }
-       if (sum == 0)
-               sum = 1;
-
-       /* smooth data */
-       avg_idle = (avg_idle + (100 * idle) / sum) / 2;
-
-       memcpy(cp_time_old, cp_time, sizeof(cp_time_old));
-
-       return avg_idle;
+       return min_idle;
 }
 
-void
+useconds_t
 perf_status(struct apm_power_info *pinfo, int ncpu)
 {
-       int avg_idle;
+       int avg_idle, min_idle;
        int hw_perf_mib[] = {CTL_HW, HW_SETPERF};
        int perf;
-       int forcehi = 0;
        size_t perf_sz = sizeof(perf);
 
-       if (ncpu > 1) {
-               avg_idle = get_avg_idle_mp(ncpu);
-       } else {
-               avg_idle = get_avg_idle_up();
-       }
-
        if (avg_idle == -1)
-               return;
+               return PERFTIMEOUTERR;
+
+       if (sysctl(hw_perf_mib, 2, &perf, &perf_sz, NULL, 0) < 0)
+               syslog(LOG_INFO, "cannot read hw.setperf");
 
        switch (doperf) {
        case PERF_AUTO:
@@ -324,28 +276,27 @@
                 * the battery is absent
                 */
                if (pinfo->ac_state == APM_AC_ON && pinfo->battery_life > 15 ||
-                   pinfo->battery_state == APM_BATTERY_ABSENT)
-                       forcehi = 1;            
-               break;
+                   pinfo->battery_state == APM_BATTERY_ABSENT) {
+                       setperf(PERFMAX);
+                       return PERFTIMEOUTSLOW;
+               }
+               /* fallthrough */
        case PERF_COOL:
-               forcehi = 0;
-               break;
+               min_idle = get_min_idle_mp(ncpu);
+               if (min_idle < PERFINCTHRES && perf < PERFMAX) {
+                       setperf(PERFMAX);
+                       return PERFTIMEOUTFAST;
+               } else if (min_idle > PERFDECTHRES && perf > PERFMIN) {
+                       perf -= PERFDEC;
+                       if (perf < PERFMIN)
+                               perf = PERFMIN;
+                       setperf(perf);
+                       return PERFTIMEOUTSLOW;
+               } else
+                       return PERFTIMEOUTSLOW;
        }
        
-       if (sysctl(hw_perf_mib, 2, &perf, &perf_sz, NULL, 0) < 0)
-               syslog(LOG_INFO, "cannot read hw.setperf");
-
-       if (forcehi || (avg_idle < PERFINCTHRES && perf < PERFMAX)) {
-               perf += PERFINC;
-               if (perf > PERFMAX)
-                       perf = PERFMAX;
-               setperf(perf);
-       } else if (avg_idle > PERFDECTHRES && perf > PERFMIN) {
-               perf -= PERFDEC;
-               if (perf < PERFMIN)
-                       perf = PERFMIN;
-               setperf(perf);
-       }
+       return PERFTIMEOUTSLOW;
 }
 
 char socketname[MAXPATHLEN];
@@ -624,8 +575,8 @@
                sts = ts;
 
                if (doperf == PERF_AUTO || doperf == PERF_COOL) {
-                       sts.tv_sec = 1;
-                       perf_status(&pinfo, ncpu);
+                       sts.tv_sec = 0;
+                       sts.tv_nsec = perf_status(&pinfo, ncpu);
                }
 
                apmtimeout += sts.tv_sec;

Reply via email to