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", &notify) == 1)
+			(ptr = strstr(buf, "system=ACPI")) != NULL &&
+			(ptr = strstr(ptr, "subsystem=ACAD")) != NULL &&
+			(ptr = strstr(ptr, "notify=")) != NULL &&
+			sscanf(ptr, "notify=%x", &notify) == 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