MFC: ignore non-useful cpufreq levels and change the powerd algorithm to

one that saves more power with possibly more performance loss.  This is
kern_cpu.c:1.20,1.21 and powerd.c:1.9

Approved by:	re (scottl)
This commit is contained in:
njl 2005-09-06 18:01:44 +00:00
parent b0b735502c
commit 3bcc2cbd34
2 changed files with 64 additions and 52 deletions

View File

@ -650,19 +650,15 @@ cpufreq_expand_set(struct cpufreq_softc *sc, struct cf_setting_array *set_arr)
CF_MTX_ASSERT(&sc->lock);
TAILQ_FOREACH(search, &sc->all_levels, link) {
/* Skip this level if we've already modified it. */
for (i = 0; i < search->rel_count; i++) {
if (search->rel_set[i].dev == set_arr->sets[0].dev)
break;
}
if (i != search->rel_count) {
CF_DEBUG("skipping modified level, freq %d (dev %s)\n",
search->total_set.freq,
device_get_nameunit(search->rel_set[i].dev));
continue;
}
/*
* Walk the set of all existing levels in reverse. This is so we
* create derived states from the lowest absolute settings first
* and discard duplicates created from higher absolute settings.
* For instance, a level of 50 Mhz derived from 100 Mhz + 50% is
* preferable to 200 Mhz + 25% because absolute settings are more
* efficient since they often change the voltage as well.
*/
TAILQ_FOREACH_REVERSE(search, &sc->all_levels, cf_level_lst, link) {
/* Add each setting to the level, duplicating if necessary. */
for (i = 0; i < set_arr->count; i++) {
set = &set_arr->sets[i];
@ -672,15 +668,19 @@ cpufreq_expand_set(struct cpufreq_softc *sc, struct cf_setting_array *set_arr)
* into two and add this setting to the new level.
*/
fill = search;
if (set->freq < 10000)
if (set->freq < 10000) {
fill = cpufreq_dup_set(sc, search, set);
/*
* The new level was a duplicate of an existing level
* so we freed it. Go to the next setting.
*/
if (fill == NULL)
continue;
/*
* The new level was a duplicate of an existing
* level or its absolute setting is too high
* so we freed it. For example, we discard a
* derived level of 1000 MHz/25% if a level
* of 500 MHz/100% already exists.
*/
if (fill == NULL)
break;
}
/* Add this setting to the existing or new level. */
KASSERT(fill->rel_count < MAX_SETTINGS,
@ -747,38 +747,48 @@ cpufreq_dup_set(struct cpufreq_softc *sc, struct cf_level *dup,
}
/*
* Insert the new level in sorted order. If we find a duplicate,
* free the new level. We can do this since any existing level will
* be guaranteed to have the same or less settings and thus consume
* less power. For example, a level with one absolute setting of
* 800 Mhz uses less power than one composed of an absolute setting
* of 1600 Mhz and a relative setting at 50%.
* Insert the new level in sorted order. If it is a duplicate of an
* existing level (1) or has an absolute setting higher than the
* existing level (2), do not add it. We can do this since any such
* level is guaranteed use less power. For example (1), a level with
* one absolute setting of 800 Mhz uses less power than one composed
* of an absolute setting of 1600 Mhz and a relative setting at 50%.
* Also for example (2), a level of 800 Mhz/75% is preferable to
* 1600 Mhz/25% even though the latter has a lower total frequency.
*/
list = &sc->all_levels;
if (TAILQ_EMPTY(list)) {
CF_DEBUG("dup done, inserted %d at head\n", fill_set->freq);
TAILQ_INSERT_HEAD(list, fill, link);
} else {
TAILQ_FOREACH_REVERSE(itr, list, cf_level_lst, link) {
itr_set = &itr->total_set;
if (CPUFREQ_CMP(fill_set->freq, itr_set->freq)) {
CF_DEBUG(
"dup done, freeing new level %d, matches %d\n",
fill_set->freq, itr_set->freq);
free(fill, M_TEMP);
fill = NULL;
break;
} else if (fill_set->freq < itr_set->freq) {
KASSERT(!TAILQ_EMPTY(list), ("all levels list empty in dup set"));
TAILQ_FOREACH_REVERSE(itr, list, cf_level_lst, link) {
itr_set = &itr->total_set;
if (CPUFREQ_CMP(fill_set->freq, itr_set->freq)) {
CF_DEBUG("dup set rejecting %d (dupe)\n",
fill_set->freq);
itr = NULL;
break;
} else if (fill_set->freq < itr_set->freq) {
if (fill->abs_set.freq <= itr->abs_set.freq) {
CF_DEBUG(
"dup done, inserting new level %d after %d\n",
fill_set->freq, itr_set->freq);
TAILQ_INSERT_AFTER(list, itr, fill, link);
sc->all_count++;
break;
} else {
CF_DEBUG("dup set rejecting %d (abs too big)\n",
fill_set->freq);
itr = NULL;
}
break;
}
}
/* We didn't find a good place for this new level so free it. */
if (itr == NULL) {
CF_DEBUG("dup set freeing new level %d (not optimal)\n",
fill_set->freq);
free(fill, M_TEMP);
fill = NULL;
}
return (fill);
}

View File

@ -425,27 +425,29 @@ main(int argc, char * argv[])
err(1, "read_usage_times");
/*
* If we're idle less than the active mark, jump the CPU to
* its fastest speed if we're not there yet. If we're idle
* more than the idle mark, drop down to the first setting
* that is half the current speed (exponential backoff).
* If we're idle less than the active mark, bump up two levels.
* If we're idle more than the idle mark, drop down one level.
*/
for (i = 0; i < numfreqs - 1; i++) {
if (freqs[i] == curfreq)
break;
}
if (idle < (total * cpu_running_mark) / 100 &&
curfreq < freqs[0]) {
i -= 2;
if (i < 0)
i = 0;
if (vflag) {
printf("idle time < %d%%, increasing clock"
" speed from %d MHz to %d MHz\n",
cpu_running_mark, curfreq, freqs[0]);
cpu_running_mark, curfreq, freqs[i]);
}
if (set_freq(freqs[0]))
if (set_freq(freqs[i]))
err(1, "error setting CPU frequency %d",
freqs[0]);
freqs[i]);
} else if (idle > (total * cpu_idle_mark) / 100 &&
curfreq > freqs[numfreqs - 1]) {
for (i = 0; i < numfreqs - 1; i++) {
if (freqs[i] <= curfreq / 2)
break;
}
i++;
if (vflag) {
printf("idle time > %d%%, decreasing clock"
" speed from %d MHz to %d MHz\n",