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
37 * - Monitor the cpu load and adjusts cpu and cpu power domain
38 * performance accordingly.
39 * - Monitor battery life. Alarm alerts and shutdown the machine
40 * if battery life goes low.
43 #define _KERNEL_STRUCTURES
44 #include <sys/types.h>
45 #include <sys/sysctl.h>
46 #include <sys/kinfo.h>
48 #include <sys/queue.h>
49 #include <sys/soundcard.h>
51 #include <machine/cpufunc.h>
52 #include <machine/cpumask.h>
62 #define MAXDOM MAXCPU /* worst case, 1 cpu per domain */
68 TAILQ_ENTRY(cpu_pwrdom
) dom_link
;
71 cpumask_t dom_cpumask
;
76 double cpu_uavg
; /* used for speeding up */
77 double cpu_davg
; /* used for slowing down */
83 static void usage(void);
84 static void get_ncpus(void);
87 static void get_uschedcpus(void);
88 static void set_uschedcpus(void);
91 static int has_perfbias(void);
92 static void set_perfbias(int, int);
95 static void acpi_getcpufreq_str(int, int *, int *);
96 static int acpi_getcpufreq_bin(int, int *, int *);
97 static void acpi_get_cpufreq(int, int *, int *);
98 static void acpi_set_cpufreq(int, int);
99 static int acpi_get_cpupwrdom(void);
101 /* mwait C-state hint */
102 static int probe_cstate(void);
103 static void set_cstate(int, int);
105 /* Performance monitoring */
106 static void init_perf(void);
107 static void mon_perf(double);
108 static void adj_perf(cpumask_t
, cpumask_t
);
109 static void adj_cpu_pwrdom(int, int);
110 static void adj_cpu_perf(int, int);
111 static void get_cputime(double);
112 static int get_nstate(struct cpu_state
*, double);
113 static void add_spare_cpus(const cpumask_t
, int);
114 static void restore_perf(void);
116 /* Battery monitoring */
117 static int has_battery(void);
118 static int mon_battery(void);
119 static void low_battery_alert(int);
122 static void restore_backlight(void);
124 /* Runtime states for performance monitoring */
125 static int global_pcpu_limit
;
126 static struct cpu_state pcpu_state
[MAXCPU
];
127 static struct cpu_state global_cpu_state
;
128 static cpumask_t cpu_used
; /* cpus w/ high perf */
129 static cpumask_t cpu_pwrdom_used
; /* cpu power domains w/ high perf */
130 static cpumask_t usched_cpu_used
; /* cpus for usched */
133 static cpumask_t cpu_pwrdom_mask
; /* usable cpu power domains */
134 static int cpu2pwrdom
[MAXCPU
]; /* cpu to cpu power domain map */
135 static struct cpu_pwrdom
*cpu_pwrdomain
[MAXDOM
];
136 static int NCpus
; /* # of cpus */
137 static char orig_global_cx
[CST_STRLEN
];
138 static char cpu_perf_cx
[CST_STRLEN
];
139 static int cpu_perf_cxlen
;
140 static char cpu_idle_cx
[CST_STRLEN
];
141 static int cpu_idle_cxlen
;
144 static int TurboOpt
= 1;
146 static int Hysteresis
= 10; /* percentage */
147 static double TriggerUp
= 0.25; /* single-cpu load to force max freq */
148 static double TriggerDown
; /* load per cpu to force the min freq */
149 static int HasPerfbias
= 0;
150 static int AdjustCpuFreq
= 1;
151 static int AdjustCstate
= 0;
152 static int HighestCpuFreq
;
153 static int LowestCpuFreq
;
155 static volatile int stopped
;
157 /* Battery life monitoring */
158 static int BatLifeMin
= 2; /* shutdown the box, if low on battery life */
159 static struct timespec BatLifePrevT
;
160 static int BatLifePollIntvl
= 5; /* unit: sec */
161 static struct timespec BatShutdownStartT
;
162 static int BatShutdownLinger
= -1;
163 static int BatShutdownLingerSet
= 60; /* unit: sec */
164 static int BatShutdownLingerCnt
;
165 static int BatShutdownAudioAlert
= 1;
166 static int BackLightPct
= 100;
167 static int OldBackLightLevel
;
168 static int BackLightDown
;
170 static void sigintr(int signo
);
173 main(int ac
, char **av
)
181 srt
= 8.0; /* time for samples - 8 seconds */
182 pollrate
= 1.0; /* polling rate in seconds */
184 while ((ch
= getopt(ac
, av
, "b:cdefh:l:p:r:tu:B:L:P:QT:")) != -1) {
187 BackLightPct
= strtol(optarg
, NULL
, 10);
202 HighestCpuFreq
= strtol(optarg
, NULL
, 10);
205 LowestCpuFreq
= strtol(optarg
, NULL
, 10);
208 Hysteresis
= (int)strtol(optarg
, NULL
, 10);
211 pollrate
= strtod(optarg
, NULL
);
217 TriggerUp
= (double)strtol(optarg
, NULL
, 10) / 100;
220 BatLifeMin
= strtol(optarg
, NULL
, 10);
223 BatShutdownLingerSet
= strtol(optarg
, NULL
, 10);
224 if (BatShutdownLingerSet
< 0)
225 BatShutdownLingerSet
= 0;
228 BatLifePollIntvl
= strtol(optarg
, NULL
, 10);
231 BatShutdownAudioAlert
= 0;
234 srt
= strtod(optarg
, NULL
);
246 /* Get number of cpus */
249 if (0 > Hysteresis
|| Hysteresis
> 99) {
250 fprintf(stderr
, "Invalid hysteresis value\n");
254 if (0 > TriggerUp
|| TriggerUp
> 1) {
255 fprintf(stderr
, "Invalid load limit value\n");
259 if (BackLightPct
> 100 || BackLightPct
<= 0) {
260 fprintf(stderr
, "Invalid backlight setting, ignore\n");
264 TriggerDown
= TriggerUp
- (TriggerUp
* (double) Hysteresis
/ 100);
267 * Make sure powerd is not already running.
269 PowerFd
= open("/var/run/powerd.pid", O_CREAT
|O_RDWR
, 0644);
272 "Cannot create /var/run/powerd.pid, "
273 "continuing anyway\n");
275 if (flock(PowerFd
, LOCK_EX
|LOCK_NB
) < 0) {
276 fprintf(stderr
, "powerd is already running\n");
282 * Demonize and set pid
286 openlog("powerd", LOG_CONS
| LOG_PID
, LOG_DAEMON
);
290 ftruncate(PowerFd
, 0);
291 snprintf(buf
, sizeof(buf
), "%d\n", (int)getpid());
292 write(PowerFd
, buf
, strlen(buf
));
295 /* Do we need to monitor battery life? */
296 if (BatLifePollIntvl
<= 0)
299 monbat
= has_battery();
301 /* Do we have perfbias(4)? */
303 HasPerfbias
= has_perfbias();
305 /* Could we adjust C-state? */
307 AdjustCstate
= probe_cstate();
310 * Wait hw.acpi.cpu.px_dom* sysctl to be created by kernel.
312 * Since hw.acpi.cpu.px_dom* creation is queued into ACPI
313 * taskqueue and ACPI taskqueue is shared across various
314 * ACPI modules, any delay in other modules may cause
315 * hw.acpi.cpu.px_dom* to be created at quite a later time
316 * (e.g. cmbat module's task could take quite a lot of time).
319 /* Prime delta cputime calculation. */
320 get_cputime(pollrate
);
322 /* Wait for all cpus to appear */
323 if (acpi_get_cpupwrdom())
325 usleep((int)(pollrate
* 1000000.0));
329 * Catch some signals so that max performance could be restored.
331 signal(SIGINT
, sigintr
);
332 signal(SIGTERM
, sigintr
);
334 /* Initialize performance states */
337 srt
= srt
/ pollrate
; /* convert to sample count */
339 printf("samples for downgrading: %5.2f\n", srt
);
346 * Monitor performance
348 get_cputime(pollrate
);
355 monbat
= mon_battery();
357 usleep((int)(pollrate
* 1000000.0));
361 * Set to maximum performance if killed.
363 syslog(LOG_INFO
, "killed, setting max and exiting");
371 sigintr(int signo __unused
)
377 * Figure out the cpu power domains.
380 acpi_get_cpupwrdom(void)
382 struct cpu_pwrdom
*dom
;
383 cpumask_t pwrdom_mask
;
388 int n
, i
, ncpu
= 0, dom_id
;
390 memset(cpu2pwrdom
, 0, sizeof(cpu2pwrdom
));
391 memset(cpu_pwrdomain
, 0, sizeof(cpu_pwrdomain
));
392 CPUMASK_ASSZERO(cpu_pwrdom_mask
);
394 for (i
= 0; i
< MAXDOM
; ++i
) {
395 snprintf(buf
, sizeof(buf
),
396 "hw.acpi.cpu.px_dom%d.available", i
);
397 if (sysctlbyname(buf
, NULL
, NULL
, NULL
, 0) < 0)
400 dom
= calloc(1, sizeof(*dom
));
403 if (cpu_pwrdomain
[i
] != NULL
) {
404 fprintf(stderr
, "cpu power domain %d exists\n", i
);
407 cpu_pwrdomain
[i
] = dom
;
408 CPUMASK_ORBIT(cpu_pwrdom_mask
, i
);
410 pwrdom_mask
= cpu_pwrdom_mask
;
412 while (CPUMASK_TESTNZERO(pwrdom_mask
)) {
413 dom_id
= BSFCPUMASK(pwrdom_mask
);
414 CPUMASK_NANDBIT(pwrdom_mask
, dom_id
);
415 dom
= cpu_pwrdomain
[dom_id
];
417 CPUMASK_ASSZERO(dom
->dom_cpumask
);
419 snprintf(buf
, sizeof(buf
),
420 "hw.acpi.cpu.px_dom%d.members", dom
->dom_id
);
421 msize
= sizeof(members
);
422 if (sysctlbyname(buf
, members
, &msize
, NULL
, 0) < 0) {
423 cpu_pwrdomain
[dom_id
] = NULL
;
429 for (str
= strtok(members
, " "); str
; str
= strtok(NULL
, " ")) {
431 sscanf(str
, "cpu%d", &n
);
435 CPUMASK_ORBIT(dom
->dom_cpumask
, n
);
436 cpu2pwrdom
[n
] = dom
->dom_id
;
439 if (dom
->dom_ncpus
== 0) {
440 cpu_pwrdomain
[dom_id
] = NULL
;
445 printf("dom%d cpumask: ", dom
->dom_id
);
446 for (i
= 0; i
< (int)NELEM(dom
->dom_cpumask
.ary
); ++i
) {
448 (uintmax_t)dom
->dom_cpumask
.ary
[i
]);
456 printf("Found %d cpus, expecting %d\n", ncpu
, NCpus
);
458 pwrdom_mask
= cpu_pwrdom_mask
;
459 while (CPUMASK_TESTNZERO(pwrdom_mask
)) {
460 dom_id
= BSFCPUMASK(pwrdom_mask
);
461 CPUMASK_NANDBIT(pwrdom_mask
, dom_id
);
462 dom
= cpu_pwrdomain
[dom_id
];
472 * Save per-cpu load and sum of per-cpu load.
475 get_cputime(double pollrate
)
477 static struct kinfo_cputime ocpu_time
[MAXCPU
];
478 static struct kinfo_cputime ncpu_time
[MAXCPU
];
484 bcopy(ncpu_time
, ocpu_time
, sizeof(struct kinfo_cputime
) * NCpus
);
486 slen
= sizeof(ncpu_time
);
487 if (sysctlbyname("kern.cputime", &ncpu_time
, &slen
, NULL
, 0) < 0) {
488 fprintf(stderr
, "kern.cputime sysctl not available\n");
491 ncpu
= slen
/ sizeof(ncpu_time
[0]);
494 for (cpu
= 0; cpu
< ncpu
; ++cpu
) {
497 d
= (ncpu_time
[cpu
].cp_user
+ ncpu_time
[cpu
].cp_sys
+
498 ncpu_time
[cpu
].cp_nice
+ ncpu_time
[cpu
].cp_intr
) -
499 (ocpu_time
[cpu
].cp_user
+ ocpu_time
[cpu
].cp_sys
+
500 ocpu_time
[cpu
].cp_nice
+ ocpu_time
[cpu
].cp_intr
);
501 pcpu_state
[cpu
].cpu_qavg
= (double)d
/ (pollrate
* 1000000.0);
505 global_cpu_state
.cpu_qavg
= (double)delta
/ (pollrate
* 1000000.0);
509 acpi_getcpufreq_str(int dom_id
, int *highest0
, int *lowest0
)
511 char buf
[256], sysid
[64];
514 int v
, highest
, lowest
;
517 * Retrieve availability list
519 snprintf(sysid
, sizeof(sysid
), "hw.acpi.cpu.px_dom%d.available",
521 buflen
= sizeof(buf
) - 1;
522 if (sysctlbyname(sysid
, buf
, &buflen
, NULL
, 0) < 0)
527 * Parse out the highest and lowest cpu frequencies
530 highest
= lowest
= 0;
531 while (ptr
&& (v
= strtol(ptr
, &ptr
, 10)) > 0) {
532 if ((lowest
== 0 || lowest
> v
) &&
533 (LowestCpuFreq
<= 0 || v
>= LowestCpuFreq
))
535 if ((highest
== 0 || highest
< v
) &&
536 (HighestCpuFreq
<= 0 || v
<= HighestCpuFreq
))
541 if (!TurboOpt
&& highest
- v
== 1)
550 acpi_getcpufreq_bin(int dom_id
, int *highest0
, int *lowest0
)
558 * Retrieve availability list
560 snprintf(sysid
, sizeof(sysid
), "hw.acpi.cpu.px_dom%d.avail", dom_id
);
561 freqlen
= sizeof(freq
);
562 if (sysctlbyname(sysid
, freq
, &freqlen
, NULL
, 0) < 0)
565 freqcnt
= freqlen
/ sizeof(freq
[0]);
569 for (i
= freqcnt
- 1; i
>= 0; --i
) {
571 if (LowestCpuFreq
<= 0 || *lowest0
>= LowestCpuFreq
)
577 if (!TurboOpt
&& freqcnt
> 1 && freq
[0] - freq
[1] == 1) {
581 for (; i
< freqcnt
; ++i
) {
582 if (HighestCpuFreq
<= 0 || *highest0
<= HighestCpuFreq
)
590 acpi_get_cpufreq(int dom_id
, int *highest
, int *lowest
)
595 if (acpi_getcpufreq_bin(dom_id
, highest
, lowest
))
597 acpi_getcpufreq_str(dom_id
, highest
, lowest
);
604 fprintf(stderr
, "usage: powerd [-cdeftQ] [-p hysteresis] "
605 "[-h highest_freq] [-l lowest_freq] "
606 "[-r poll_interval] [-u trigger_up] "
607 "[-B min_battery_life] [-L low_battery_linger] "
608 "[-P battery_poll_interval] [-T sample_interval] "
614 #define timespecsub(vvp, uvp) \
616 (vvp)->tv_sec -= (uvp)->tv_sec; \
617 (vvp)->tv_nsec -= (uvp)->tv_nsec; \
618 if ((vvp)->tv_nsec < 0) { \
620 (vvp)->tv_nsec += 1000000000; \
625 #define BAT_SYSCTL_TIME_MAX 50000000 /* unit: nanosecond */
630 struct timespec s
, e
;
634 clock_gettime(CLOCK_MONOTONIC_FAST
, &s
);
638 if (sysctlbyname("hw.acpi.acline", &val
, &len
, NULL
, 0) < 0) {
639 /* No AC line information */
642 clock_gettime(CLOCK_MONOTONIC_FAST
, &e
);
645 if (e
.tv_sec
> 0 || e
.tv_nsec
> BAT_SYSCTL_TIME_MAX
) {
646 /* hw.acpi.acline takes to long to be useful */
647 syslog(LOG_NOTICE
, "hw.acpi.acline takes too long");
651 clock_gettime(CLOCK_MONOTONIC_FAST
, &s
);
653 if (sysctlbyname("hw.acpi.battery.life", &val
, &len
, NULL
, 0) < 0) {
654 /* No battery life */
657 clock_gettime(CLOCK_MONOTONIC_FAST
, &e
);
660 if (e
.tv_sec
> 0 || e
.tv_nsec
> BAT_SYSCTL_TIME_MAX
) {
661 /* hw.acpi.battery.life takes to long to be useful */
662 syslog(LOG_NOTICE
, "hw.acpi.battery.life takes too long");
669 low_battery_alert(int life
)
671 int fmt
, stereo
, freq
;
674 syslog(LOG_ALERT
, "low battery life %d%%, please plugin AC line, #%d",
675 life
, BatShutdownLingerCnt
);
676 ++BatShutdownLingerCnt
;
678 if (!BatShutdownAudioAlert
)
681 fd
= open("/dev/dsp", O_WRONLY
);
686 if (ioctl(fd
, SNDCTL_DSP_SETFMT
, &fmt
, sizeof(fmt
)) < 0)
690 if (ioctl(fd
, SNDCTL_DSP_STEREO
, &stereo
, sizeof(stereo
)) < 0)
694 if (ioctl(fd
, SNDCTL_DSP_SPEED
, &freq
, sizeof(freq
)) < 0)
697 write(fd
, alert1
, sizeof(alert1
));
698 write(fd
, alert1
, sizeof(alert1
));
707 struct timespec cur
, ts
;
711 clock_gettime(CLOCK_MONOTONIC_FAST
, &cur
);
713 timespecsub(&ts
, &BatLifePrevT
);
714 if (ts
.tv_sec
< BatLifePollIntvl
)
718 len
= sizeof(acline
);
719 if (sysctlbyname("hw.acpi.acline", &acline
, &len
, NULL
, 0) < 0)
722 BatShutdownLinger
= -1;
723 BatShutdownLingerCnt
= 0;
728 if (!BackLightDown
&& BackLightPct
!= 100) {
729 int backlight_max
, backlight
;
731 len
= sizeof(backlight_max
);
732 if (sysctlbyname("hw.backlight_max", &backlight_max
, &len
,
734 /* No more backlight adjustment */
736 goto after_backlight
;
739 len
= sizeof(OldBackLightLevel
);
740 if (sysctlbyname("hw.backlight_level", &OldBackLightLevel
, &len
,
742 /* No more backlight adjustment */
744 goto after_backlight
;
747 backlight
= (backlight_max
* BackLightPct
) / 100;
748 if (backlight
>= OldBackLightLevel
) {
749 /* No more backlight adjustment */
751 goto after_backlight
;
754 if (sysctlbyname("hw.backlight_level", NULL
, NULL
,
755 &backlight
, sizeof(backlight
)) < 0) {
756 /* No more backlight adjustment */
758 goto after_backlight
;
765 if (sysctlbyname("hw.acpi.battery.life", &life
, &len
, NULL
, 0) < 0)
768 if (BatShutdownLinger
> 0) {
770 timespecsub(&ts
, &BatShutdownStartT
);
771 if (ts
.tv_sec
> BatShutdownLinger
)
772 BatShutdownLinger
= 0;
775 if (life
<= BatLifeMin
) {
776 if (BatShutdownLinger
== 0 || BatShutdownLingerSet
== 0) {
777 syslog(LOG_ALERT
, "low battery life %d%%, "
778 "shutting down", life
);
780 execlp("poweroff", "poweroff", NULL
);
782 } else if (BatShutdownLinger
< 0) {
783 BatShutdownLinger
= BatShutdownLingerSet
;
784 BatShutdownStartT
= cur
;
786 low_battery_alert(life
);
796 slen
= sizeof(NCpus
);
797 if (sysctlbyname("hw.ncpu", &NCpus
, &slen
, NULL
, 0) < 0)
798 err(1, "sysctlbyname hw.ncpu failed");
800 printf("hw.ncpu %d\n", NCpus
);
808 slen
= sizeof(usched_cpu_used
);
809 if (sysctlbyname("kern.usched_global_cpumask", &usched_cpu_used
, &slen
,
811 err(1, "sysctlbyname kern.usched_global_cpumask failed");
815 printf("usched cpumask was: ");
816 for (i
= 0; i
< (int)NELEM(usched_cpu_used
.ary
); ++i
)
817 printf("%jx ", (uintmax_t)usched_cpu_used
.ary
[i
]);
828 printf("usched cpumask: ");
829 for (i
= 0; i
< (int)NELEM(usched_cpu_used
.ary
); ++i
) {
831 (uintmax_t)usched_cpu_used
.ary
[i
]);
835 sysctlbyname("kern.usched_global_cpumask", NULL
, 0,
836 &usched_cpu_used
, sizeof(usched_cpu_used
));
846 if (sysctlbyname("machdep.perfbias0.hint", &hint
, &len
, NULL
, 0) < 0)
852 set_perfbias(int cpu
, int inc
)
854 int hint
= inc
? 0 : 15;
858 printf("cpu%d set perfbias hint %d\n", cpu
, hint
);
859 snprintf(sysid
, sizeof(sysid
), "machdep.perfbias%d.hint", cpu
);
860 sysctlbyname(sysid
, NULL
, NULL
, &hint
, sizeof(hint
));
866 struct cpu_state
*state
;
869 /* Get usched cpumask */
873 * Assume everything are used and are maxed out, before we
877 CPUMASK_ASSBMASK(cpu_used
, NCpus
);
878 cpu_pwrdom_used
= cpu_pwrdom_mask
;
879 global_pcpu_limit
= NCpus
;
881 for (cpu
= 0; cpu
< NCpus
; ++cpu
) {
882 state
= &pcpu_state
[cpu
];
884 state
->cpu_uavg
= 0.0;
885 state
->cpu_davg
= 0.0;
886 state
->cpu_limit
= 1;
887 state
->cpu_count
= 1;
888 snprintf(state
->cpu_name
, sizeof(state
->cpu_name
), "cpu%d",
892 state
= &global_cpu_state
;
893 state
->cpu_uavg
= 0.0;
894 state
->cpu_davg
= 0.0;
895 state
->cpu_limit
= NCpus
;
896 state
->cpu_count
= NCpus
;
897 strlcpy(state
->cpu_name
, "global", sizeof(state
->cpu_name
));
901 get_nstate(struct cpu_state
*state
, double srt
)
903 int ustate
, dstate
, nstate
;
906 state
->cpu_uavg
= (state
->cpu_uavg
* 2.0 + state
->cpu_qavg
) / 3.0;
908 state
->cpu_davg
= (state
->cpu_davg
* srt
+ state
->cpu_qavg
) / (srt
+ 1);
909 if (state
->cpu_davg
< state
->cpu_uavg
)
910 state
->cpu_davg
= state
->cpu_uavg
;
912 ustate
= state
->cpu_uavg
/ TriggerUp
;
913 if (ustate
< state
->cpu_limit
)
914 ustate
= state
->cpu_uavg
/ TriggerDown
;
915 dstate
= state
->cpu_davg
/ TriggerUp
;
916 if (dstate
< state
->cpu_limit
)
917 dstate
= state
->cpu_davg
/ TriggerDown
;
919 nstate
= (ustate
> dstate
) ? ustate
: dstate
;
920 if (nstate
> state
->cpu_count
)
921 nstate
= state
->cpu_count
;
924 printf("%s qavg=%5.2f uavg=%5.2f davg=%5.2f "
925 "%2d ncpus=%d\n", state
->cpu_name
,
926 state
->cpu_qavg
, state
->cpu_uavg
, state
->cpu_davg
,
927 state
->cpu_limit
, nstate
);
935 cpumask_t ocpu_used
, ocpu_pwrdom_used
;
936 int pnstate
= 0, nstate
;
940 * Find cpus requiring performance and their cooresponding power
941 * domains. Save the number of cpus requiring performance in
944 ocpu_used
= cpu_used
;
945 ocpu_pwrdom_used
= cpu_pwrdom_used
;
947 CPUMASK_ASSZERO(cpu_used
);
948 CPUMASK_ASSZERO(cpu_pwrdom_used
);
950 for (cpu
= 0; cpu
< NCpus
; ++cpu
) {
951 struct cpu_state
*state
= &pcpu_state
[cpu
];
954 s
= get_nstate(state
, srt
);
956 CPUMASK_ORBIT(cpu_used
, cpu
);
957 CPUMASK_ORBIT(cpu_pwrdom_used
, cpu2pwrdom
[cpu
]);
961 state
->cpu_limit
= s
;
965 * Calculate nstate, the number of cpus we wish to run at max
968 nstate
= get_nstate(&global_cpu_state
, srt
);
970 if (nstate
== global_cpu_state
.cpu_limit
&&
971 (pnstate
== global_pcpu_limit
|| nstate
> pnstate
)) {
972 /* Nothing changed; keep the sets */
973 cpu_used
= ocpu_used
;
974 cpu_pwrdom_used
= ocpu_pwrdom_used
;
976 global_pcpu_limit
= pnstate
;
979 global_pcpu_limit
= pnstate
;
981 if (nstate
> pnstate
) {
983 * Add spare cpus to meet global performance requirement.
985 add_spare_cpus(ocpu_used
, nstate
- pnstate
);
988 global_cpu_state
.cpu_limit
= nstate
;
991 * Adjust cpu and cpu power domain performance
993 adj_perf(ocpu_used
, ocpu_pwrdom_used
);
997 add_spare_cpus(const cpumask_t ocpu_used
, int ncpu
)
999 cpumask_t saved_pwrdom
, xcpu_used
;
1003 * Find more cpus in the previous cpu set.
1005 xcpu_used
= cpu_used
;
1006 CPUMASK_XORMASK(xcpu_used
, ocpu_used
);
1007 while (CPUMASK_TESTNZERO(xcpu_used
)) {
1008 cpu
= BSFCPUMASK(xcpu_used
);
1009 CPUMASK_NANDBIT(xcpu_used
, cpu
);
1011 if (CPUMASK_TESTBIT(ocpu_used
, cpu
)) {
1012 CPUMASK_ORBIT(cpu_pwrdom_used
, cpu2pwrdom
[cpu
]);
1013 CPUMASK_ORBIT(cpu_used
, cpu
);
1021 * Find more cpus in the used cpu power domains.
1023 saved_pwrdom
= cpu_pwrdom_used
;
1025 while (CPUMASK_TESTNZERO(saved_pwrdom
)) {
1026 cpumask_t unused_cpumask
;
1029 dom
= BSFCPUMASK(saved_pwrdom
);
1030 CPUMASK_NANDBIT(saved_pwrdom
, dom
);
1032 unused_cpumask
= cpu_pwrdomain
[dom
]->dom_cpumask
;
1033 CPUMASK_NANDMASK(unused_cpumask
, cpu_used
);
1035 while (CPUMASK_TESTNZERO(unused_cpumask
)) {
1036 cpu
= BSFCPUMASK(unused_cpumask
);
1037 CPUMASK_NANDBIT(unused_cpumask
, cpu
);
1039 CPUMASK_ORBIT(cpu_pwrdom_used
, dom
);
1040 CPUMASK_ORBIT(cpu_used
, cpu
);
1049 * Find more cpus in unused cpu power domains
1051 saved_pwrdom
= cpu_pwrdom_mask
;
1052 CPUMASK_NANDMASK(saved_pwrdom
, cpu_pwrdom_used
);
1056 printf("%d cpus not found\n", ncpu
);
1060 acpi_set_cpufreq(int dom
, int inc
)
1062 int lowest
, highest
, desired
;
1065 acpi_get_cpufreq(dom
, &highest
, &lowest
);
1066 if (highest
== 0 || lowest
== 0)
1068 desired
= inc
? highest
: lowest
;
1071 printf("dom%d set frequency %d\n", dom
, desired
);
1072 snprintf(sysid
, sizeof(sysid
), "hw.acpi.cpu.px_dom%d.select", dom
);
1073 sysctlbyname(sysid
, NULL
, NULL
, &desired
, sizeof(desired
));
1077 adj_cpu_pwrdom(int dom
, int inc
)
1080 acpi_set_cpufreq(dom
, inc
);
1084 adj_cpu_perf(int cpu
, int inc
)
1088 printf("cpu%d increase perf\n", cpu
);
1090 printf("cpu%d decrease perf\n", cpu
);
1094 set_perfbias(cpu
, inc
);
1096 set_cstate(cpu
, inc
);
1100 adj_perf(cpumask_t xcpu_used
, cpumask_t xcpu_pwrdom_used
)
1102 cpumask_t old_usched_used
;
1106 * Set cpus requiring performance to the userland process
1107 * scheduler. Leave the rest of cpus unmapped.
1109 old_usched_used
= usched_cpu_used
;
1110 usched_cpu_used
= cpu_used
;
1111 if (CPUMASK_TESTZERO(usched_cpu_used
))
1112 CPUMASK_ORBIT(usched_cpu_used
, 0);
1113 if (CPUMASK_CMPMASKNEQ(usched_cpu_used
, old_usched_used
))
1117 * Adjust per-cpu performance.
1119 CPUMASK_XORMASK(xcpu_used
, cpu_used
);
1120 while (CPUMASK_TESTNZERO(xcpu_used
)) {
1121 cpu
= BSFCPUMASK(xcpu_used
);
1122 CPUMASK_NANDBIT(xcpu_used
, cpu
);
1124 if (CPUMASK_TESTBIT(cpu_used
, cpu
)) {
1125 /* Increase cpu performance */
1128 /* Decrease cpu performance */
1131 adj_cpu_perf(cpu
, inc
);
1135 * Adjust cpu power domain performance. This could affect
1138 CPUMASK_XORMASK(xcpu_pwrdom_used
, cpu_pwrdom_used
);
1139 while (CPUMASK_TESTNZERO(xcpu_pwrdom_used
)) {
1142 dom
= BSFCPUMASK(xcpu_pwrdom_used
);
1143 CPUMASK_NANDBIT(xcpu_pwrdom_used
, dom
);
1145 if (CPUMASK_TESTBIT(cpu_pwrdom_used
, dom
)) {
1146 /* Increase cpu power domain performance */
1149 /* Decrease cpu power domain performance */
1152 adj_cpu_pwrdom(dom
, inc
);
1159 cpumask_t ocpu_used
, ocpu_pwrdom_used
;
1161 /* Remove highest cpu frequency limitation */
1164 ocpu_used
= cpu_used
;
1165 ocpu_pwrdom_used
= cpu_pwrdom_used
;
1167 /* Max out all cpus and cpu power domains performance */
1168 CPUMASK_ASSBMASK(cpu_used
, NCpus
);
1169 cpu_pwrdom_used
= cpu_pwrdom_mask
;
1171 adj_perf(ocpu_used
, ocpu_pwrdom_used
);
1175 * Restore the original mwait C-state
1178 printf("global set cstate %s\n", orig_global_cx
);
1179 sysctlbyname("machdep.mwait.CX.idle", NULL
, NULL
,
1180 orig_global_cx
, strlen(orig_global_cx
) + 1);
1187 char cx_supported
[1024];
1190 int idle_hlt
, deep
= 1;
1193 len
= sizeof(idle_hlt
);
1194 if (sysctlbyname("machdep.cpu_idle_hlt", &idle_hlt
, &len
, NULL
, 0) < 0)
1199 len
= sizeof(cx_supported
);
1200 if (sysctlbyname("machdep.mwait.CX.supported", cx_supported
, &len
,
1204 len
= sizeof(orig_global_cx
);
1205 if (sysctlbyname("machdep.mwait.CX.idle", orig_global_cx
, &len
,
1209 strlcpy(cpu_perf_cx
, "AUTODEEP", sizeof(cpu_perf_cx
));
1210 cpu_perf_cxlen
= strlen(cpu_perf_cx
) + 1;
1211 if (sysctlbyname("machdep.mwait.CX.idle", NULL
, NULL
,
1212 cpu_perf_cx
, cpu_perf_cxlen
) < 0) {
1213 /* AUTODEEP is not supported; try AUTO */
1215 strlcpy(cpu_perf_cx
, "AUTO", sizeof(cpu_perf_cx
));
1216 cpu_perf_cxlen
= strlen(cpu_perf_cx
) + 1;
1217 if (sysctlbyname("machdep.mwait.CX.idle", NULL
, NULL
,
1218 cpu_perf_cx
, cpu_perf_cxlen
) < 0)
1226 for (ptr
= strtok(cx_supported
, " "); ptr
!= NULL
;
1227 ptr
= strtok(NULL
, " ")) {
1228 if (target
== NULL
||
1229 (target
!= NULL
&& strcmp(ptr
, target
) == 0)) {
1230 strlcpy(cpu_idle_cx
, ptr
, sizeof(cpu_idle_cx
));
1231 cpu_idle_cxlen
= strlen(cpu_idle_cx
) + 1;
1236 if (cpu_idle_cxlen
== 0)
1240 printf("cstate orig %s, perf %s, idle %s\n",
1241 orig_global_cx
, cpu_perf_cx
, cpu_idle_cx
);
1247 set_cstate(int cpu
, int inc
)
1255 len
= cpu_perf_cxlen
;
1258 len
= cpu_idle_cxlen
;
1262 printf("cpu%d set cstate %s\n", cpu
, cst
);
1263 snprintf(sysid
, sizeof(sysid
), "machdep.mwait.CX.idle%d", cpu
);
1264 sysctlbyname(sysid
, NULL
, NULL
, cst
, len
);
1268 restore_backlight(void)
1270 if (BackLightDown
) {
1272 sysctlbyname("hw.backlight_level", NULL
, NULL
,
1273 &OldBackLightLevel
, sizeof(OldBackLightLevel
));