I like this one better. Slow down the poll interval just a little so it's
not so hysterical, but also go straight to 100. If you need CPU, you need
CPU. It still backs down slowly, but that's just to prevent getting
caught in slow mode again. It also pays attention to per-core load, much
better on smp machines. I'm running this now and will probably continue
to do so for a while.
Index: init_main.c
===================================================================
RCS file: /home/tedu/cvs/src/sys/kern/init_main.c,v
retrieving revision 1.168
diff -u -r1.168 init_main.c
--- init_main.c 29 Jun 2010 20:25:57 -0000 1.168
+++ init_main.c 30 Jun 2010 18:23:22 -0000
@@ -172,6 +172,72 @@
EMUL_ENABLED | EMUL_NATIVE,
};
+struct timeout setperf_to;
+
+void auto_setperf(void *v);
+void
+auto_setperf(void *v)
+{
+ static uint64_t *idleticks, *totalticks;
+
+ int i, j;
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+ int speedup;
+ uint64_t idle, total, allidle, alltotal;
+
+ extern int perflevel;
+
+ if (!cpu_setperf)
+ return;
+ if (!idleticks)
+ if (!(idleticks = malloc(sizeof(*idleticks) * ncpus,
+ M_DEVBUF, M_NOWAIT | M_ZERO)))
+ return;
+ if (!totalticks)
+ if (!(totalticks = malloc(sizeof(*totalticks) * ncpus,
+ M_DEVBUF, M_NOWAIT | M_ZERO))) {
+ free(idleticks, M_DEVBUF);
+ return;
+ }
+ alltotal = allidle = 0;
+ j = 0;
+ speedup = 0;
+ CPU_INFO_FOREACH(cii, ci) {
+ 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];
+ if (idle < total / 2)
+ speedup = 1;
+ alltotal += total;
+ allidle += idle;
+ idleticks[j] += idle;
+ totalticks[j] += total;
+
+ j++;
+ }
+ if (allidle < alltotal * 3 / 4)
+ speedup = 1;
+
+ if (speedup && perflevel != 100) {
+ perflevel = 100;
+ printf("going up %d\n", perflevel);
+ cpu_setperf(perflevel);
+ } else if (!speedup) {
+ perflevel -= 10;
+ if (perflevel < 0)
+ perflevel = 0;
+ else
+ printf("going down %d\n", perflevel);
+ cpu_setperf(perflevel);
+ }
+
+ timeout_add_msec(&setperf_to, 200);
+}
/*
* System startup; initialize the world, create process 0, mount root
@@ -545,6 +611,9 @@
*/
start_init_exec = 1;
wakeup((void *)&start_init_exec);
+
+ timeout_set(&setperf_to, auto_setperf, NULL);
+ timeout_add_msec(&setperf_to, 200);
/*
* proc0: nothing to do, back to sleep