misc/136354: powerd Support for maxspeed in adaptive modes
Rene Schickbauer
cavac at magicbooks.org
Mon Jul 20 13:17:52 UTC 2009
Here is an updated patch that allows setting of minimum and maximum speeds.
Seperately for battery and AC mode, of course.
I also updated the man-page.
(Hope i didn't mess this follow-up up, gnats doesn't like my webmail)
-------------- next part --------------
diff -u powerd.orig2/powerd.8 powerd/powerd.8
--- powerd.orig2/powerd.8 2009-07-20 11:43:20.000000000 +0200
+++ powerd/powerd.8 2009-07-20 14:43:36.000000000 +0200
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD: src/usr.sbin/powerd/powerd.8,v 1.13 2008/12/24 09:17:30 trhodes Exp $
.\"
-.Dd December 24, 2008
+.Dd July 5, 2009
.Dt POWERD 8
.Os
.Sh NAME
@@ -34,6 +34,10 @@
.Nm
.Op Fl a Ar mode
.Op Fl b Ar mode
+.Op Fl c Ar minspeed
+.Op Fl d Ar maxspeed
+.Op Fl e Ar minspeed
+.Op Fl f Ar maxspeed
.Op Fl i Ar percent
.Op Fl n Ar mode
.Op Fl p Ar ival
@@ -45,22 +49,10 @@
.Nm
utility monitors the system state and sets various power control options
accordingly.
-It offers three modes (maximum, minimum, and adaptive) that can be
-individually selected while on AC power or batteries.
-The modes maximum, minimum, adaptive and hiadaptive may be abbreviated
-max, min, adp, hadp.
-.Pp
-Maximum mode chooses the highest performance values.
-Minimum mode selects the lowest performance values to get the most power
-savings.
-Adaptive mode attempts to strike a balance by degrading performance when
-the system appears idle and increasing it when the system is busy.
-It offers a good balance between a small performance loss for greatly
-increased power savings.
-Hiadaptive mode is alike adaptive mode, but tuned for systems where
-performance and interactivity are more important then power consumption.
-It rises frequency faster, drops slower and keeps twice lower CPU load.
-The default mode is adaptive for battery power and hiadaptive for the rest.
+It offers multiple modes (maximum, minimum, and two adaptive modes) that can be
+individually selected while on AC power or batteries. See
+.Ar MODES
+below for details.
.Pp
The
.Nm
@@ -74,6 +66,22 @@
Selects the
.Ar mode
to use while on battery power.
+.It Fl c Ar mode
+Selects the
+.Ar minspeed
+in Mhz for adaptive modes to use while on AC power.
+.It Fl d Ar mode
+Selects the
+.Ar maxspeed
+in Mhz for adaptive modes to use while on AC power.
+.It Fl e Ar mode
+Selects the
+.Ar minspeed
+in Mhz for adaptive modes to use while on battery power.
+.It Fl f Ar mode
+Selects the
+.Ar maxspeed
+in Mhz for adaptive modes to use while on battery power.
.It Fl i Ar percent
Specifies the CPU load percent level when adaptive
mode should begin to degrade performance to save power.
@@ -100,6 +108,48 @@
.Nm
will operate in the foreground.
.El
+.Sh MODES
+The following
+.Ar mode
+flags are currently implemented:
+.Pp
+.Ar max
+or
+.Ar maximum
+mode chooses the highest performance values.
+.Pp
+.Ar min
+or
+.Ar minimum
+mode selects the lowest performance values to get the most power
+savings.
+.Pp
+.Ar adp
+or
+.Ar adaptive
+mode attempts to strike a balance by degrading performance when
+the system appears idle and increasing it when the system is busy.
+It offers a good balance between a small performance loss for greatly
+increased power savings.
+.Pp
+.Ar hadp
+or
+.Ar hiadaptive
+mode is alike adaptive mode, but tuned for systems where
+performance and interactivity are more important then power consumption.
+It rises frequency faster, drops slower and keeps twice lower CPU load.
+.Pp
+For both adaptive modes, it is possible to set
+.Ar maxspeed
+to lower power consumption by limiting the dynamic range
+.Nm
+uses.
+.Pp
+The default mode is
+.Ar adaptive
+for battery power and
+.Ar hiadaptive
+for the rest.
.Sh SEE ALSO
.Xr acpi 4 ,
.Xr apm 4 ,
@@ -121,6 +171,8 @@
then updated it for
.Xr cpufreq 4 ,
added features, and wrote this manual page.
+.An Rene Schickbauer
+added speed limiting and rewrote parts of this manual page.
.Sh BUGS
The
.Nm
diff -u powerd.orig2/powerd.c powerd/powerd.c
--- powerd.orig2/powerd.c 2009-07-20 11:43:20.000000000 +0200
+++ powerd/powerd.c 2009-07-20 14:53:47.000000000 +0200
@@ -118,6 +118,11 @@
#endif
static int devd_pipe = -1;
+static int minspeed_ac = 0;
+static int maxspeed_ac = 0;
+static int minspeed_battery = 0;
+static int maxspeed_battery = 0;
+
#define DEVD_RETRY_INTERVAL 60 /* seconds */
static struct timeval tried_devd;
@@ -154,13 +159,13 @@
for (cpu = 0; cpu < ncpus; cpu++) {
total = 0;
for (i = 0; i < CPUSTATES; i++) {
- total += cp_times[cpu * CPUSTATES + i] -
+ total += cp_times[cpu * CPUSTATES + i] -
cp_times_old[cpu * CPUSTATES + i];
}
if (total == 0)
continue;
*load += 100 - (cp_times[cpu * CPUSTATES + CP_IDLE] -
- cp_times_old[cpu * CPUSTATES + CP_IDLE]) * 100 / total;
+ cp_times_old[cpu * CPUSTATES + CP_IDLE]) * 100 / total;
}
}
@@ -302,10 +307,10 @@
/* FALLTHROUGH */
}
if (rlen > 0 &&
- (ptr = strstr(buf, "system=ACPI")) != NULL &&
- (ptr = strstr(ptr, "subsystem=ACAD")) != NULL &&
- (ptr = strstr(ptr, "notify=")) != NULL &&
- sscanf(ptr, "notify=%x", ¬ify) == 1)
+ (ptr = strstr(buf, "system=ACPI")) != NULL &&
+ (ptr = strstr(ptr, "subsystem=ACAD")) != NULL &&
+ (ptr = strstr(ptr, "notify=")) != NULL &&
+ sscanf(ptr, "notify=%x", ¬ify) == 1)
acline_status = (notify ? SRC_AC : SRC_BATTERY);
}
if (acline_mode == ac_sysctl) {
@@ -314,7 +319,7 @@
len = sizeof(acline);
if (sysctl(acline_mib, acline_mib_len, &acline, &len,
- NULL, 0) == 0)
+ NULL, 0) == 0)
acline_status = (acline ? SRC_AC : SRC_BATTERY);
else
acline_status = SRC_UNKNOWN;
@@ -364,7 +369,7 @@
devd_addr.sun_family = PF_LOCAL;
strlcpy(devd_addr.sun_path, DEVDPIPE, sizeof(devd_addr.sun_path));
if (connect(devd_pipe, (struct sockaddr *)&devd_addr,
- sizeof(devd_addr)) == -1) {
+ sizeof(devd_addr)) == -1) {
if (vflag)
warn("%s(): connect()", __func__);
close(devd_pipe);
@@ -418,7 +423,7 @@
{
fprintf(stderr,
-"usage: powerd [-v] [-a mode] [-b mode] [-i %%] [-n mode] [-p ival] [-r %%] [-P pidfile]\n");
+"usage: powerd [-v] [-a mode] [-b mode] [-c minspeed] [-d maxspeed] [-e minspeed] [-f maxspeed] [-i %%] [-n mode] [-p ival] [-r %%] [-P pidfile] \n");
exit(1);
}
@@ -431,13 +436,19 @@
struct pidfh *pfh = NULL;
const char *pidfile = NULL;
int freq, curfreq, initfreq, *freqs, i, j, *mwatts, numfreqs, load;
- int ch, mode, mode_ac, mode_battery, mode_none;
+ int ch, mode, mode_ac, mode_battery, mode_none, minspeed, maxspeed;
uint64_t mjoules_used;
size_t len;
/* Default mode for all AC states is adaptive. */
mode_ac = mode_none = MODE_HIADAPTIVE;
mode_battery = MODE_ADAPTIVE;
+ minspeed_ac = 0;
+ maxspeed_ac = 0;
+ minspeed_battery = 0;
+ maxspeed_battery = 0;
+ minspeed = 0;
+ maxspeed = 0;
cpu_running_mark = DEFAULT_ACTIVE_PERCENT;
cpu_idle_mark = DEFAULT_IDLE_PERCENT;
poll_ival = DEFAULT_POLL_INTERVAL;
@@ -448,7 +459,7 @@
if (geteuid() != 0)
errx(1, "must be root to run");
- while ((ch = getopt(argc, argv, "a:b:i:n:p:P:r:v")) != -1)
+ while ((ch = getopt(argc, argv, "a:b:c:d:e:f:i:n:p:P:r:v")) != -1)
switch (ch) {
case 'a':
parse_mode(optarg, &mode_ac, ch);
@@ -456,11 +467,43 @@
case 'b':
parse_mode(optarg, &mode_battery, ch);
break;
+ case 'c':
+ minspeed_ac = atoi(optarg);
+ if (minspeed_ac <= 0) {
+ warnx("%d is not a valid CPU speed",
+ minspeed_ac);
+ usage();
+ }
+ break;
+ case 'd':
+ maxspeed_ac = atoi(optarg);
+ if (maxspeed_ac <= 0) {
+ warnx("%d is not a valid CPU speed",
+ maxspeed_ac);
+ usage();
+ }
+ break;
+ case 'e':
+ minspeed_battery = atoi(optarg);
+ if (minspeed_battery <= 0) {
+ warnx("%d is not a valid CPU speed",
+ minspeed_battery);
+ usage();
+ }
+ break;
+ case 'f':
+ maxspeed_battery = atoi(optarg);
+ if (maxspeed_battery <= 0) {
+ warnx("%d is not a valid CPU speed",
+ maxspeed_battery);
+ usage();
+ }
+ break;
case 'i':
cpu_idle_mark = atoi(optarg);
if (cpu_idle_mark < 0 || cpu_idle_mark > 100) {
warnx("%d is not a valid percent",
- cpu_idle_mark);
+ cpu_idle_mark);
usage();
}
break;
@@ -481,7 +524,7 @@
cpu_running_mark = atoi(optarg);
if (cpu_running_mark <= 0 || cpu_running_mark > 100) {
warnx("%d is not a valid percent",
- cpu_running_mark);
+ cpu_running_mark);
usage();
}
break;
@@ -492,6 +535,19 @@
usage();
}
+ if (minspeed_battery > 0 && maxspeed_battery > 0 &&
+ minspeed_battery > maxspeed_battery) {
+ warnx("Battery mode: minspeed (%d) can not be greater than maxspeed (%d)",
+ minspeed_battery, maxspeed_battery);
+ usage();
+ }
+ if (minspeed_ac > 0 && maxspeed_ac > 0 &&
+ minspeed_ac > maxspeed_ac) {
+ warnx("AC mode: minspeed (%d) can not be greater than maxspeed (%d)",
+ minspeed_ac, maxspeed_ac);
+ usage();
+ }
+
mode = mode_none;
/* Poll interval is in units of ms. */
@@ -522,7 +578,7 @@
if (pfh == NULL) {
if (errno == EEXIST) {
errx(1, "powerd already running, pid: %d",
- otherpid);
+ otherpid);
}
warn("cannot open pid file");
}
@@ -564,8 +620,8 @@
if (exit_requested) {
if (vflag && mjoules_used != 0)
printf("total joules used: %u.%03u\n",
- (u_int)(mjoules_used / 1000),
- (int)mjoules_used % 1000);
+ (u_int)(mjoules_used / 1000),
+ (int)mjoules_used % 1000);
break;
}
@@ -574,12 +630,18 @@
switch (acline_status) {
case SRC_AC:
mode = mode_ac;
+ minspeed = minspeed_ac;
+ maxspeed = maxspeed_ac;
break;
case SRC_BATTERY:
mode = mode_battery;
+ minspeed = minspeed_battery;
+ maxspeed = maxspeed_battery;
break;
case SRC_UNKNOWN:
mode = mode_none;
+ minspeed = 0;
+ maxspeed = 0;
break;
default:
errx(1, "invalid AC line status %d", acline_status);
@@ -595,7 +657,7 @@
/* Keep a sum of all power actually used. */
if (mwatts[i] != -1)
mjoules_used +=
- (mwatts[i] * (poll_ival / 1000)) / 1000;
+ (mwatts[i] * (poll_ival / 1000)) / 1000;
}
/* Always switch to the lowest frequency in min mode. */
@@ -604,12 +666,12 @@
if (curfreq != freq) {
if (vflag) {
printf("now operating on %s power; "
- "changing frequency to %d MHz\n",
- modes[acline_status], freq);
+ "changing frequency to %d MHz\n",
+ modes[acline_status], freq);
}
if (set_freq(freq) != 0) {
warn("error setting CPU freq %d",
- freq);
+ freq);
continue;
}
}
@@ -622,12 +684,12 @@
if (curfreq != freq) {
if (vflag) {
printf("now operating on %s power; "
- "changing frequency to %d MHz\n",
- modes[acline_status], freq);
+ "changing frequency to %d MHz\n",
+ modes[acline_status], freq);
}
if (set_freq(freq) != 0) {
warn("error setting CPU freq %d",
- freq);
+ freq);
continue;
}
}
@@ -647,16 +709,26 @@
freq *= 2;
else
freq = freq * load / cpu_running_mark;
+
if (freq > freqs[0])
freq = freqs[0];
} else if (load < cpu_idle_mark &&
- curfreq * load < freqs[get_freq_id(
- freq * 7 / 8, freqs, numfreqs)] *
- cpu_running_mark) {
+ curfreq * load < freqs[get_freq_id(
+ freq * 7 / 8, freqs, numfreqs)] *
+ cpu_running_mark) {
freq = freq * 7 / 8;
if (freq < freqs[numfreqs - 1])
freq = freqs[numfreqs - 1];
}
+ if(maxspeed > 0 && freq > maxspeed) {
+ if(vflag)
+ printf("Limiting calculated freq (%d Mhz) to %d Mhz\n", freq, maxspeed);
+ freq = maxspeed;
+ } else if(minspeed > 0 && freq < minspeed) {
+ if(vflag)
+ printf("Upgrading calculated freq (%d Mhz) to %d Mhz\n", freq, minspeed);
+ freq = minspeed;
+ }
} else { /* MODE_HIADAPTIVE */
if (load > cpu_running_mark / 2) {
if (load > 95 || load > cpu_running_mark)
@@ -666,28 +738,37 @@
if (freq > freqs[0] * 2)
freq = freqs[0] * 2;
} else if (load < cpu_idle_mark / 2 &&
- curfreq * load < freqs[get_freq_id(
- freq * 31 / 32, freqs, numfreqs)] *
- cpu_running_mark / 2) {
+ curfreq * load < freqs[get_freq_id(
+ freq * 31 / 32, freqs, numfreqs)] *
+ cpu_running_mark / 2) {
freq = freq * 31 / 32;
if (freq < freqs[numfreqs - 1])
freq = freqs[numfreqs - 1];
}
+ if(maxspeed > 0 && freq > maxspeed) {
+ if(vflag)
+ printf("Limiting calculated freq (%d Mhz) to %d Mhz\n", freq, maxspeed);
+ freq = maxspeed;
+ } else if(minspeed > 0 && freq < minspeed) {
+ if(vflag)
+ printf("Upgrading calculated freq (%d Mhz) to %d Mhz\n", freq, minspeed);
+ freq = minspeed;
+ }
}
if (vflag) {
- printf("load %3d%%, current freq %4d MHz (%2d), wanted freq %4d MHz\n",
+ printf("load %3d%%, current freq %4d MHz (%2d), wanted freq %4d MHz\n",
load, curfreq, i, freq);
}
j = get_freq_id(freq, freqs, numfreqs);
if (i != j) {
if (vflag) {
printf("changing clock"
- " speed from %d MHz to %d MHz\n",
- freqs[i], freqs[j]);
+ " speed from %d MHz to %d MHz\n",
+ freqs[i], freqs[j]);
}
if (set_freq(freqs[j]))
warn("error setting CPU frequency %d",
- freqs[j]);
+ freqs[j]);
}
}
if (set_freq(initfreq))
More information about the freebsd-bugs
mailing list