diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2009-02-03 01:52:50 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2009-02-03 01:52:50 +0000 |
commit | f35ff0bf2935843dc85bcd0af87b19c3333a7595 (patch) | |
tree | 9b482ea66d84421cce661ddcd6358d5c294a40cf /usr.sbin/apmd | |
parent | ee584deafdc1f2b98688f9e385ac2df560c58831 (diff) |
the prevalence of multi-core laptops revealed that taking the cpu average is
a poor way to adjust performance. Even with a cpu pegged, apmd is quite slow
to react. Change things to consider min idle time, not average.
Mostly from a diff by Laurence Tratt
Diffstat (limited to 'usr.sbin/apmd')
-rw-r--r-- | usr.sbin/apmd/apmd.c | 138 |
1 files changed, 43 insertions, 95 deletions
diff --git a/usr.sbin/apmd/apmd.c b/usr.sbin/apmd/apmd.c index 58ad09e088f..0eedae27feb 100644 --- a/usr.sbin/apmd/apmd.c +++ b/usr.sbin/apmd/apmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apmd.c,v 1.49 2007/11/24 14:58:44 deraadt Exp $ */ +/* $OpenBSD: apmd.c,v 1.50 2009/02/03 01:52:49 tedu Exp $ */ /* * Copyright (c) 1995, 1996 John T. Kohl @@ -61,12 +61,15 @@ const char sockfile[] = _PATH_APM_SOCKET; int debug = 0; int doperf = PERF_NONE; -#define PERFINC 50 -#define PERFDEC 20 +#define PERFINC 15 +#define PERFDEC 15 #define PERFMIN 0 #define PERFMAX 100 #define PERFINCTHRES 10 #define PERFDECTHRES 30 +#define PERFTIMEOUTERR 999999999 +#define PERFTIMEOUTFAST 10000 +#define PERFTIMEOUTSLOW 25000 extern char *__progname; @@ -74,9 +77,8 @@ void usage(void); 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 +197,12 @@ power_status(int fd, int force, struct apm_power_info *pinfo) /* 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 +213,7 @@ get_avg_idle_mp(int ncpu) 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 +227,14 @@ get_avg_idle_mp(int ncpu) 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,101 +246,52 @@ get_avg_idle_mp(int ncpu) 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: - /* - * force setperf towards the max if we are connected to AC - * power and have a battery life greater than 15% - */ if (pinfo->ac_state == APM_AC_ON && pinfo->battery_life > 15) - forcehi = 1; - break; + forcehi = 1; case PERF_COOL: - forcehi = 0; - break; - } - - 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); + min_idle = get_min_idle_mp(ncpu); + if (forcehi || (min_idle < PERFINCTHRES && perf < PERFMAX)) { + perf += PERFINC; + if (perf > PERFMAX) + perf = PERFMAX; + setperf(perf); + return PERFTIMEOUTFAST; + } else if (min_idle > PERFDECTHRES && perf > PERFMIN) { + perf -= PERFDEC; + if (perf < PERFMIN) + perf = PERFMIN; + setperf(perf); + return PERFTIMEOUTSLOW; + } else + return PERFTIMEOUTSLOW; } + return PERFTIMEOUTSLOW; } char socketname[MAXPATHLEN]; @@ -645,8 +593,8 @@ main(int argc, char *argv[]) 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; |