Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 30 Jan 2008 17:56:19 -0500
From:      "Alexandre \"Sunny\" Kovalenko" <alex.kovalenko@verizon.net>
To:        acpi@freebsd.org
Subject:   [RFC] Patch to enable temperature ceiling in powerd
Message-ID:  <1201733779.902.18.camel@RabbitsDen>

next in thread | raw e-mail | index | archive | help

--Boundary_(ID_OLdYpMB8W8sfobiJiGBw+Q)
Content-type: text/plain; charset=UTF-8
Content-transfer-encoding: 8BIT

Some time ago I have put together patch for powerd, which allows user to
specify the temperature threshold at which powerd will lower CPU
frequency no matter what the load was at the time. I recently had to
adapt it to the 7.0-PRERELEASE for someone with the overheating laptop,
which got me to think that it might be useful for someone else yet.

Basic idea is fairly simple -- check temperature in TZ0 and, if it has
reached certain value, either override frequency with the lowest
available (in the case of 'max' setting) or change idle time to 100% and
let adaptive algorithm decrease frequency gradually.

I imagine it also could be poor man's substitute for the low noise
acoustic policy ;)

If there is an interest, I will go ahead and submit a PR, otherwise it
will live in the mail archives for someone to find. Any comments,
suggestions or criticisms are welcome.

Temperature threshold (in Celsius) could be set by means of '-T' command
line option (as in '-T 60').

-- 
Alexandre "Sunny" Kovalenko (Олександр Коваленко)

--Boundary_(ID_OLdYpMB8W8sfobiJiGBw+Q)
Content-type: text/x-patch; name=powerd.c.patch; charset=UTF-8
Content-transfer-encoding: 7BIT
Content-disposition: attachment; filename=powerd.c.patch

--- powerd.c.orig	2007-06-14 16:17:15.000000000 -0400
+++ powerd.c	2008-01-14 20:14:56.000000000 -0500
@@ -53,6 +53,7 @@
 #define DEFAULT_ACTIVE_PERCENT	65
 #define DEFAULT_IDLE_PERCENT	90
 #define DEFAULT_POLL_INTERVAL	500	/* Poll interval in milliseconds */
+#define VERY_HIGH_TEMPERATURE   200     /* Unlikely to be reached in the hardware lifetime */
 
 typedef enum {
 	MODE_MIN,
@@ -93,11 +94,13 @@
 static int	freq_mib[4];
 static int	levels_mib[4];
 static int	acline_mib[3];
+static int	temp_mib[5];
 
 /* Configuration */
 static int	cpu_running_mark;
 static int	cpu_idle_mark;
 static int	poll_ival;
+static int 	passive_cooling_mark;
 static int	vflag;
 
 static volatile sig_atomic_t exit_requested;
@@ -357,7 +360,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] [-i %%] [-n mode] [-p ival] [-r %%] [-P pidfile] [-T temperature]\n");
 	exit(1);
 }
 
@@ -371,6 +374,7 @@
 	const char *pidfile = NULL;
 	long idle, total;
 	int curfreq, *freqs, i, *mwatts, numfreqs;
+	int temperature;
 	int ch, mode, mode_ac, mode_battery, mode_none;
 	uint64_t mjoules_used;
 	size_t len;
@@ -381,13 +385,14 @@
 	cpu_idle_mark = DEFAULT_IDLE_PERCENT;
 	poll_ival = DEFAULT_POLL_INTERVAL;
 	mjoules_used = 0;
+	passive_cooling_mark = VERY_HIGH_TEMPERATURE;
 	vflag = 0;
 
 	/* User must be root to control frequencies. */
 	if (geteuid() != 0)
 		errx(1, "must be root to run");
 
-	while ((ch = getopt(argc, argv, "a:b:i:n:p:P:r:v")) != EOF)
+	while ((ch = getopt(argc, argv, "a:b:i:n:p:P:r:T:v")) != EOF)
 		switch (ch) {
 		case 'a':
 			parse_mode(optarg, &mode_ac, ch);
@@ -424,6 +429,16 @@
 				usage();
 			}
 			break;
+                case 'T':
+                        passive_cooling_mark = atoi(optarg);
+                        if(passive_cooling_mark < 0 || passive_cooling_mark > VERY_HIGH_TEMPERATURE) {
+                                 warnx("%d is not valid temperature for passive cooling",
+                                       passive_cooling_mark);
+                                 usage();
+                        }
+                        passive_cooling_mark *= 10;
+                        passive_cooling_mark += 2733;
+                        break;
 		case 'v':
 			vflag = 1;
 			break;
@@ -446,6 +461,9 @@
 	len = 4;
 	if (sysctlnametomib("dev.cpu.0.freq_levels", levels_mib, &len))
 		err(1, "lookup freq_levels");
+	len = 5;
+	if (sysctlnametomib("hw.acpi.thermal.tz0.temperature", temp_mib, &len))
+		err(1, "lookup temperature");
 
 	/* Check if we can read the idle time and supported freqs. */
 	if (read_usage_times(NULL, NULL))
@@ -528,6 +546,10 @@
 				warn("error reading current CPU frequency");
 			continue;
 		}
+                /* Read current temperature. */
+                len = sizeof(temperature);
+                if(sysctl(temp_mib, 5, &temperature, &len, NULL, 0))
+                        err(1, "error reading current temperature");
 
 		if (vflag) {
 			for (i = 0; i < numfreqs; i++) {
@@ -571,6 +593,17 @@
 				if (set_freq(freqs[0]) != 0) {
 					warn("error setting CPU freq %d",
 				    	    freqs[0]);
+                        		/* Check for passive cooling override */
+                        		if(temperature > passive_cooling_mark) {
+						if (vflag) {
+							printf("passive cooling override; "
+					    			"changing frequency to %d MHz\n",
+					    			freqs[numfreqs - 1]);
+						}
+						if (set_freq(freqs[numfreqs - 1]))
+							err(1, "error setting CPU freq %d",
+					    			freqs[numfreqs - 1]);
+                        		}
 					continue;
 				}
 			}
@@ -583,6 +616,14 @@
 				warn("read_usage_times() failed");
 			continue;
 		}
+                /*
+                 * If temperature has risen over passive cooling mark, we 
+                 * would want to decrease frequency regardless of the load,
+                 * Simplest way to go about this would be to report 100%
+                 * idle CPU and let adaptive algorithm do its job.
+                 */
+                if(temperature > passive_cooling_mark)
+                  idle = total;
 
 		/*
 		 * If we're idle less than the active mark, bump up two levels.

--Boundary_(ID_OLdYpMB8W8sfobiJiGBw+Q)--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1201733779.902.18.camel>