On Sat, Sep 24, 2011 at 07:53:47PM +0200, Joerg Sonnenberger wrote: > I was listening possible decision making factors. Depending on your > environment, you have all or none of them. The main point is that good > decision making needs more than just "You can toogle this".
So here is a quick draft for the first iteration with the cpuctl(8). If there are issues, speak now, otherwise I'll proceed with something based on this. - Jukka.
/* $NetBSD$ */ /*- * Copyright (c) 2011 Jukka Ruohonen <jruoho...@iki.fi> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <sys/cdefs.h> __KERNEL_RCSID(0, "$NetBSD: subr_cpufreq.c,v 1.15 2011/09/02 22:25:08 Exp $"); #include <sys/param.h> #include <sys/cpu.h> #include <sys/cpufreq.h> #include <sys/kmem.h> #include <sys/module.h> #include <sys/mutex.h> #include <sys/time.h> #include <sys/xcall.h> static struct cpufreq_if *cpufreq_if = NULL; static int cpufreq_latency(void); int cpufreq_register(struct cpufreq_if *cif) { size_t i, j; int rv; KASSERT(cif != NULL); KASSERT(cif->get_freq != NULL); KASSERT(cif->set_freq != NULL); KASSERT(cif->state_count > 0); KASSERT(cif->state_count < CPUFREQ_STATE_MAX); mutex_enter(&cpu_lock); if (cpufreq_if != NULL) { mutex_exit(&cpu_lock); return EALREADY; } mutex_exit(&cpu_lock); cpufreq_if = kmem_zalloc(sizeof(*cif), KM_SLEEP); if (cpufreq_if == NULL) return ENOMEM; mutex_enter(&cpu_lock); cpufreq_if->cookie = cif->cookie; cpufreq_if->get_freq = cif->get_freq; cpufreq_if->set_freq = cif->set_freq; for (i = j = 0; i < cif->state_count; i++) { if (cif->state[i].freq == 0) continue; else { j++; } cpufreq_if->state[i].freq = cif->state[i].freq; cpufreq_if->state[i].power = cif->state[i].power; } cpufreq_if->state_count = j; rv = cpufreq_latency(); mutex_exit(&cpu_lock); return rv; } void cpufreq_unregister(struct cpufreq_if *cif) { mutex_enter(&cpu_lock); if (cpufreq_if == NULL) { mutex_exit(&cpu_lock); return; } mutex_exit(&cpu_lock); kmem_free(cpufreq_if, sizeof(*cif)); } static int cpufreq_latency(void) { struct cpufreq_state *state; struct timespec nta, ntb; const size_t n = 10; uint64_t sample; size_t i, j; /* * Sample the transition latency for each state. */ for (i = 0; i < cpufreq_if->state_count; i++) { state = &cpufreq_if->state[i]; KASSERT(state->freq > 0 && state->freq < 9999); for (j = 0, sample = 0; j < n; j++) { nta.tv_sec = nta.tv_nsec = 0; ntb.tv_sec = ntb.tv_nsec = 0; nanotime(&nta); mutex_exit(&cpu_lock); cpufreq_set(curcpu(), state[i].freq); mutex_enter(&cpu_lock); nanotime(&ntb); timespecsub(&ntb, &nta, &ntb); /* * If the transition latency is measured * in seconds, the backend is not suitable. */ if (ntb.tv_sec != 0) continue; sample += ntb.tv_nsec; } if (sample == 0) return EMSGSIZE; state->latency = sample / (uint64_t)n; } return 0; } void cpufreq_get(struct cpu_info *ci, uint32_t freq) { struct cpufreq_if *cif = cpufreq_if; uint64_t xc; mutex_enter(&cpu_lock); xc = xc_unicast(0, (*cif->get_freq), cif->cookie, &freq, ci); xc_wait(xc); mutex_exit(&cpu_lock); } void cpufreq_set(struct cpu_info *ci, uint32_t freq) { struct cpufreq_if *cif = cpufreq_if; uint64_t xc; mutex_enter(&cpu_lock); xc = xc_unicast(0, (*cif->set_freq), cif->cookie, &freq, ci); xc_wait(xc); mutex_exit(&cpu_lock); } MODULE(MODULE_CLASS_DRIVER, cpufreq, NULL); static int cpufreq_modcmd(modcmd_t cmd, void *aux) { if (cmd != MODULE_CMD_INIT && cmd != MODULE_CMD_FINI) return ENOTTY; return 0; }
/* $NetBSD$ */ /*- * Copyright (c) 2011 Jukka Ruohonen <jruoho...@iki.fi> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_CPUFREQ_H_ #define _SYS_CPUFREQ_H_ #ifndef _SYS_XCALL_H_ #include <sys/xcall.h> #endif #define CPUFREQ_STATE_MAX 255 struct cpufreq_state { uint32_t freq; /* MHz */ uint32_t power; /* wW */ uint64_t latency; /* nsec */ }; struct cpufreq_if { struct cpufreq_state state[CPUFREQ_STATE_MAX]; uint16_t state_count; #ifdef _KERNEL void *cookie; xcfunc_t get_freq; xcfunc_t set_freq; #endif /* _KERNEL */ }; int cpufreq_register(struct cpufreq_if *); void cpufreq_unregister(struct cpufreq_if *); void cpufreq_get(struct cpu_info *, uint32_t); void cpufreq_set(struct cpu_info *, uint32_t); #endif /* _SYS_CPUFREQ_H_ */