powerd doesn't decrease CPU frequency in some cases
Ian Smith
smithi at nimnet.asn.au
Fri Jan 4 06:55:51 PST 2008
On Tue, 25 Dec 2007, Rui Paulo wrote:
> At Tue, 25 Dec 2007 17:16:58 +1100 (EST),
> Ian Smith wrote:
> >
> > On Mon, 24 Dec 2007, Rui Paulo wrote:
> > > At Mon, 24 Dec 2007 23:16:54 +0200,
> > > Aragon Gouveia wrote:
> > > >
> > > > Hi,
> > > >
> > > > | By Rui Paulo <rpaulo at fnop.net>
> > > > | [ 2007-12-24 14:43 +0200 ]
> > > > > Isn't it better to teach est(4) to ignore values that differ in, say,
> > > > > +/- 5Mhz ?
> > > >
> > > > I agree my patch isn't ideal. I was thinking about it today and it might
> > > > be useful to implement something that ignores frequencies whose power
> > > > ratings don't differ by more than X mW. In my case, both 2201 and 2200 are
> > > > rated to draw 35000 mW. The question is, in these cases which one of the
> > > > two should be ignored? Can't ignore both...
> > >
> > > I think you can ignore one of them, which one doesn't really matter
> > > because the power levels are the same. I suspect that, in these cases,
> > > the 2001 comes after 2000 in the EST table, so if we ignore a value
> > > already present, 2000 will remain and 2001 will be ignored.
> >
> > I'm starting to wonder if this 2000/2001 thing isn't some sort of signal
> > to a Certain OS to do Something Proprietary. As it makes no engineering
> > sense, best we can do for powerd without Inside Knowledge is what both
> > these patches offer, eliminating/ignoring frequencies that won't set.
> >
> > It seems it does matter which is chosen; Andrey demonstrated in his case
> > that setting 2000 gave 2001 anyway, so the one that reads back wrong
> > when set is the one to ignore. It'd be better to know _why_,
> > though.
>
> Well, the fact that "setting 2000 gave 2001 anyway" is most likely
> regarding to how est is programmed, I think.
Are we certain yet that this (apparently recent) 2001|2000 or 2201|2200
freq phenomenon only appears on hardware that uses est specifically?
Trying to marginally reduce my ignorance I've done a bit of digging, not
necessarily in this order ..
% find /sys/ -name "*.[ch]" -exec egrep -Hi 'CPUFREQ_[GS]ET' {} \;
/sys/kern/kern_cpu.c:static int cpufreq_settings_sysctl(SYSCTL_HANDLER_ARGS);
/sys/kern/kern_cpu.c: DEVMETHOD(cpufreq_set, cf_set_method),
/sys/kern/kern_cpu.c: DEVMETHOD(cpufreq_get, cf_get_method),
/sys/kern/kern_cpu.c: error = CPUFREQ_GET(sc->dev, &levels[0]);
/sys/kern/kern_cpu.c: * While we only call cpufreq_get() on one device (assuming all
/sys/kern/kern_cpu.c: * CPUs have equal levels), we call cpufreq_set() on all CPUs.
/sys/kern/kern_cpu.c: error = CPUFREQ_SET(devs[n], &levels[i],
/sys/kern/kern_cpu.c:cpufreq_settings_sysctl(SYSCTL_HANDLER_ARGS)
/sys/kern/kern_cpu.c: cpufreq_settings_sysctl, "A", "CPU frequency driver settings");
/sys/sys/cpu.h: * is registered, it must support calls to its CPUFREQ_GET, CPUFREQ_GET_LEVEL,
/sys/sys/cpu.h: * and CPUFREQ_SET methods. It must also unregister before returning from
So this seems where the main business is done. Up till then I'd been
hunting through just /sys/dev/acpica/* and /sys/i386/cpufreq/* so this
alone was a useful revelation. From that hunt derives this fat list:
% find /sys/ -name "*.[ch]" -exec grep -Hi CPUFREQ_ {} \;
and from there, it seems that only est.c does not use CPUFREQ_CMP():
% find /sys/ -name "*.[ch]" -exec grep -H CPUFREQ_CMP {} \;
/sys/dev/acpica/acpi_perf.c: if (CPUFREQ_CMP(set->freq, sc->px_states[i].core_freq))
/sys/dev/acpica/acpi_perf.c: if (CPUFREQ_CMP(sc->px_states[i].core_freq, rate)) {
/sys/dev/cpufreq/ichss.c: if (CPUFREQ_CMP(set->freq, sc->sets[0].freq))
/sys/dev/cpufreq/ichss.c: else if (CPUFREQ_CMP(set->freq, sc->sets[1].freq))
/sys/i386/cpufreq/powernow.c: if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq))
/sys/i386/cpufreq/smist.c: if (CPUFREQ_CMP(set->freq, sc->sets[0].freq))
/sys/i386/cpufreq/smist.c: else if (CPUFREQ_CMP(set->freq, sc->sets[1].freq))
/sys/kern/kern_cpu.c: if (CPUFREQ_CMP(sc->curr_level.total_set.freq, level->total_set.freq)) {
/sys/kern/kern_cpu.c: if (CPUFREQ_CMP(set.freq, levels[i].total_set.freq)) {
/sys/kern/kern_cpu.c: if (CPUFREQ_CMP(rate, levels[i].total_set.freq)) {
/sys/kern/kern_cpu.c: if (CPUFREQ_CMP(fill_set->freq, itr_set->freq)) {
/sys/kern/kern_cpu.c: if (CPUFREQ_CMP(levels[i].total_set.freq, freq)) {
/sys/sys/cpu.h:#define CPUFREQ_CMP(x, y) (abs((x) - (y)) < 25)
So the finest granularity in differing freqs is 25. (caveat: 5.5-STABLE
sources from months ago, but I did check cpu.h on HEAD still has that)
It's not yet clear to me, due to my generally meagre knowledge of C in
general and method passing, softc, callbacks and such in particular,
whether est's get/set calls override or assist what kern_cpu.c is up to?
Cheers, Ian
More information about the freebsd-acpi
mailing list