2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * The powerd daemon monitors the cpu load and adjusts cpu frequencies
37 * via hw.acpi.cpu.px_dom*.
40 #include <sys/types.h>
41 #include <sys/sysctl.h>
42 #include <sys/kinfo.h>
49 #define STATE_UNKNOWN 0
53 static void usage(void);
54 static double getcputime(void);
55 static void acpi_setcpufreq(int ostate
, int nstate
);
58 int PowerState
= STATE_UNKNOWN
;
60 double Trigger
= 0.25;
63 main(int ac
, char **av
)
71 while ((ch
= getopt(ac
, av
, "d")) != -1) {
85 * Prime delta cputime calculation, make sure at least dom0 exists,
86 * and make sure powerd is not already running.
91 if (sysctlbyname("hw.acpi.cpu.px_dom0.available", NULL
, NULL
,
93 fprintf(stderr
, "hw.acpi.cpu.px_dom* sysctl not available\n");
97 PowerFd
= open("/var/run/powerd.pid", O_CREAT
|O_RDWR
, 0644);
100 "Cannot create /var/run/powerd.pid, "
101 "continuing anyway\n");
103 if (flock(PowerFd
, LOCK_EX
|LOCK_NB
) < 0) {
104 fprintf(stderr
, "powerd is already running\n");
110 * Demonize and set pid
116 ftruncate(PowerFd
, 0);
117 snprintf(buf
, sizeof(buf
), "%d\n", (int)getpid());
118 write(PowerFd
, buf
, strlen(buf
));
126 savg
= (savg
* 7.0 + qavg
) / 8.0;
129 printf("\rqavg=%5.2f savg=%5.2f\r", qavg
, savg
);
134 if (nstate
== STATE_UNKNOWN
) {
139 } else if (nstate
== STATE_LOW
) {
140 if (savg
>= Trigger
|| qavg
>= 0.9)
143 if (savg
< Trigger
/ 2.0 && qavg
< Trigger
/ 2.0)
146 if (PowerState
!= nstate
) {
147 acpi_setcpufreq(PowerState
, nstate
);
155 * Return the one-second cpu load. One cpu at 100% will return a value
156 * of 1.0. On a SMP system N cpus running at 100% will return a value of N.
162 static struct kinfo_cputime ocpu_time
[64];
163 static struct kinfo_cputime ncpu_time
[64];
169 bcopy(ncpu_time
, ocpu_time
, sizeof(ncpu_time
));
170 slen
= sizeof(ncpu_time
);
171 if (sysctlbyname("kern.cputime", &ncpu_time
, &slen
, NULL
, 0) < 0) {
172 fprintf(stderr
, "kern.cputime sysctl not available\n");
175 ncpu
= slen
/ sizeof(ncpu_time
[0]);
178 for (cpu
= 0; cpu
< ncpu
; ++cpu
) {
179 delta
+= (ncpu_time
[cpu
].cp_user
+ ncpu_time
[cpu
].cp_sys
+
180 ncpu_time
[cpu
].cp_intr
) -
181 (ocpu_time
[cpu
].cp_user
+ ocpu_time
[cpu
].cp_sys
+
182 ocpu_time
[cpu
].cp_intr
);
184 return((double)delta
/ 1000000.0);
190 acpi_setcpufreq(int ostate
, int nstate
)
205 * Retrieve availability list
207 asprintf(&sysid
, "hw.acpi.cpu.px_dom%d.available", dom
);
208 buflen
= sizeof(buf
) - 1;
209 v
= sysctlbyname(sysid
, buf
, &buflen
, NULL
, 0);
216 * Parse out the highest and lowest cpu frequencies
219 highest
= lowest
= 0;
220 while (ptr
&& (v
= strtol(ptr
, &ptr
, 10)) > 0) {
221 if (lowest
== 0 || lowest
> v
)
223 if (highest
== 0 || highest
< v
)
228 * Calculate the desired cpu frequency, test, and set.
230 desired
= (nstate
== STATE_LOW
) ? lowest
: highest
;
232 asprintf(&sysid
, "hw.acpi.cpu.px_dom%d.select", dom
);
235 sysctlbyname(sysid
, &v
, &buflen
, NULL
, 0);
236 if (v
!= desired
|| ostate
== STATE_UNKNOWN
) {
238 printf("dom%d set frequency %d\n",
241 sysctlbyname(sysid
, NULL
, NULL
,
242 &desired
, sizeof(desired
));
253 fprintf(stderr
, "usage: powerd [-d]\n");