summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/init_main.c11
-rw-r--r--sys/kern/kern_sysctl.c92
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)