diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2014-10-11 16:28:07 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2014-10-11 16:28:07 +0000 |
commit | fb6cedef0014587351eed1e2b56fe262f7be6b3e (patch) | |
tree | ea3b891c41395190573a8843a494424158f15e6c | |
parent | f2ebb4ede8dec3bc7548b216af559167fd74f320 (diff) |
resurrect a many year old diff. move CPU throttling into the kernel,
enabled by setting hw.setperf=-1. some other bugs preventing this from
going in before have been fixed. my thanks to phessler for keeping the
diff alive in the mean time. tested by several to not regress.
-rw-r--r-- | sys/kern/init_main.c | 11 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 92 |
2 files changed, 93 insertions, 10 deletions
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index b2922581365..d00ab037998 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_main.c,v 1.218 2014/10/03 18:06:46 kettenis Exp $ */ +/* $OpenBSD: init_main.c,v 1.219 2014/10/11 16:28:06 tedu Exp $ */ /* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */ /* @@ -116,6 +116,11 @@ struct sigacts sigacts0; struct process *initprocess; struct proc *reaperproc; +#ifndef SMALL_KERNEL +extern struct timeout setperf_to; +void auto_setperf(void *); +#endif + int cmask = CMASK; extern struct user *proc0paddr; @@ -543,6 +548,10 @@ main(void *framep) start_init_exec = 1; wakeup((void *)&start_init_exec); +#ifndef SMALL_KERNEL + timeout_set(&setperf_to, auto_setperf, NULL); +#endif + /* * proc0: nothing to do, back to sleep */ diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 433f4d05098..3aadefc153a 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.264 2014/09/15 19:08:21 miod Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.265 2014/10/11 16:28:06 tedu Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -129,6 +129,10 @@ void fill_kproc(struct process *, struct kinfo_proc *, struct proc *, int); int (*cpu_cpuspeed)(int *); void (*cpu_setperf)(int); int perflevel = 100; +#ifndef SMALL_KERNEL +struct timeout setperf_to; +void auto_setperf(void *); +#endif /* * Lock to avoid too many processes vslocking a large amount of memory @@ -254,6 +258,65 @@ int securelevel = -1; int securelevel; #endif +#ifndef SMALL_KERNEL +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; + + if (!auto_perfctl) + return; + if (!idleticks) + if (!(idleticks = malloc(sizeof(*idleticks) * ncpusfound, + M_DEVBUF, M_NOWAIT | M_ZERO))) + return; + if (!totalticks) + if (!(totalticks = malloc(sizeof(*totalticks) * ncpusfound, + M_DEVBUF, M_NOWAIT | M_ZERO))) { + free(idleticks, M_DEVBUF, 0); + 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 / 3) + speedup = 1; + alltotal += total; + allidle += idle; + idleticks[j] += idle; + totalticks[j] += total; + + j++; + } + if (allidle < alltotal / 2) + speedup = 1; + + if (speedup && perflevel != 100) { + perflevel = 100; + cpu_setperf(perflevel); + } else if (!speedup && perflevel != 0) { + perflevel = 0; + cpu_setperf(perflevel); + } + + timeout_add_msec(&setperf_to, 100); +} +#endif /* !SMALL_KERNEL */ + /* * kernel related system variables. */ @@ -608,7 +671,7 @@ hw_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen, struct proc *p) { extern char machine[], cpu_model[]; - int err, cpuspeed; + int err, cpuspeed, newperf; /* all sysctl names at this level except sensors are terminal */ if (name[0] != HW_SENSORS && namelen != 1) @@ -664,15 +727,26 @@ hw_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, case HW_SETPERF: if (!cpu_setperf) return (EOPNOTSUPP); - err = sysctl_int(oldp, oldlenp, newp, newlen, &perflevel); + newperf = perflevel; + err = sysctl_int(oldp, oldlenp, newp, newlen, &newperf); if (err) return err; - if (perflevel > 100) - perflevel = 100; - if (perflevel < 0) - perflevel = 0; - if (newp) - cpu_setperf(perflevel); +#ifndef SMALL_KERNEL + if (newp) { + if (newperf == -1) { + auto_perfctl = 1; + timeout_add_msec(&setperf_to, 200); + } else { + auto_perfctl = 0; + if (newperf > 100) + newperf = 100; + if (newperf < 0) + newperf = 0; + perflevel = newperf; + cpu_setperf(newperf); + } + } +#endif /* !SMALL_KERNEL */ return (0); case HW_VENDOR: if (hw_vendor) |