1 /*
2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
3 * (C) 2010 Thomas Renninger <trenn@suse.de>
4 *
5 * Licensed under the terms of the GNU GPL License version 2.
6 */
7
8
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <getopt.h>
15 #include <cpufreq.h>
16
17 #include "helpers/helpers.h"
18 #include "helpers/sysfs.h"
19 #include "helpers/bitmask.h"
20
21 #define LINE_LEN 10
22
cpuidle_cpu_output(unsigned int cpu,int verbose)23 static void cpuidle_cpu_output(unsigned int cpu, int verbose)
24 {
25 int idlestates, idlestate;
26 char *tmp;
27
28 printf(_ ("Analyzing CPU %d:\n"), cpu);
29
30 idlestates = sysfs_get_idlestate_count(cpu);
31 if (idlestates == 0) {
32 printf(_("CPU %u: No idle states\n"), cpu);
33 return;
34 } else if (idlestates <= 0) {
35 printf(_("CPU %u: Can't read idle state info\n"), cpu);
36 return;
37 }
38 printf(_("Number of idle states: %d\n"), idlestates);
39 printf(_("Available idle states:"));
40 for (idlestate = 0; idlestate < idlestates; idlestate++) {
41 tmp = sysfs_get_idlestate_name(cpu, idlestate);
42 if (!tmp)
43 continue;
44 printf(" %s", tmp);
45 free(tmp);
46 }
47 printf("\n");
48
49 if (!verbose)
50 return;
51
52 for (idlestate = 0; idlestate < idlestates; idlestate++) {
53 tmp = sysfs_get_idlestate_name(cpu, idlestate);
54 if (!tmp)
55 continue;
56 printf("%s:\n", tmp);
57 free(tmp);
58
59 tmp = sysfs_get_idlestate_desc(cpu, idlestate);
60 if (!tmp)
61 continue;
62 printf(_("Flags/Description: %s\n"), tmp);
63 free(tmp);
64
65 printf(_("Latency: %lu\n"),
66 sysfs_get_idlestate_latency(cpu, idlestate));
67 printf(_("Usage: %lu\n"),
68 sysfs_get_idlestate_usage(cpu, idlestate));
69 printf(_("Duration: %llu\n"),
70 sysfs_get_idlestate_time(cpu, idlestate));
71 }
72 printf("\n");
73 }
74
cpuidle_general_output(void)75 static void cpuidle_general_output(void)
76 {
77 char *tmp;
78
79 tmp = sysfs_get_cpuidle_driver();
80 if (!tmp) {
81 printf(_("Could not determine cpuidle driver\n"));
82 return;
83 }
84
85 printf(_("CPUidle driver: %s\n"), tmp);
86 free(tmp);
87
88 tmp = sysfs_get_cpuidle_governor();
89 if (!tmp) {
90 printf(_("Could not determine cpuidle governor\n"));
91 return;
92 }
93
94 printf(_("CPUidle governor: %s\n"), tmp);
95 free(tmp);
96 }
97
proc_cpuidle_cpu_output(unsigned int cpu)98 static void proc_cpuidle_cpu_output(unsigned int cpu)
99 {
100 long max_allowed_cstate = 2000000000;
101 int cstates, cstate;
102
103 cstates = sysfs_get_idlestate_count(cpu);
104 if (cstates == 0) {
105 /*
106 * Go on and print same useless info as you'd see with
107 * cat /proc/acpi/processor/../power
108 * printf(_("CPU %u: No C-states available\n"), cpu);
109 * return;
110 */
111 } else if (cstates <= 0) {
112 printf(_("CPU %u: Can't read C-state info\n"), cpu);
113 return;
114 }
115 /* printf("Cstates: %d\n", cstates); */
116
117 printf(_("active state: C0\n"));
118 printf(_("max_cstate: C%u\n"), cstates-1);
119 printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate);
120 printf(_("states:\t\n"));
121 for (cstate = 1; cstate < cstates; cstate++) {
122 printf(_(" C%d: "
123 "type[C%d] "), cstate, cstate);
124 printf(_("promotion[--] demotion[--] "));
125 printf(_("latency[%03lu] "),
126 sysfs_get_idlestate_latency(cpu, cstate));
127 printf(_("usage[%08lu] "),
128 sysfs_get_idlestate_usage(cpu, cstate));
129 printf(_("duration[%020Lu] \n"),
130 sysfs_get_idlestate_time(cpu, cstate));
131 }
132 }
133
134 static struct option info_opts[] = {
135 { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'},
136 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
137 { },
138 };
139
cpuidle_exit(int fail)140 static inline void cpuidle_exit(int fail)
141 {
142 exit(EXIT_FAILURE);
143 }
144
cmd_idle_info(int argc,char ** argv)145 int cmd_idle_info(int argc, char **argv)
146 {
147 extern char *optarg;
148 extern int optind, opterr, optopt;
149 int ret = 0, cont = 1, output_param = 0, verbose = 1;
150 unsigned int cpu = 0;
151
152 do {
153 ret = getopt_long(argc, argv, "os", info_opts, NULL);
154 if (ret == -1)
155 break;
156 switch (ret) {
157 case '?':
158 output_param = '?';
159 cont = 0;
160 break;
161 case 's':
162 verbose = 0;
163 break;
164 case -1:
165 cont = 0;
166 break;
167 case 'o':
168 if (output_param) {
169 output_param = -1;
170 cont = 0;
171 break;
172 }
173 output_param = ret;
174 break;
175 }
176 } while (cont);
177
178 switch (output_param) {
179 case -1:
180 printf(_("You can't specify more than one "
181 "output-specific argument\n"));
182 cpuidle_exit(EXIT_FAILURE);
183 case '?':
184 printf(_("invalid or unknown argument\n"));
185 cpuidle_exit(EXIT_FAILURE);
186 }
187
188 /* Default is: show output of CPU 0 only */
189 if (bitmask_isallclear(cpus_chosen))
190 bitmask_setbit(cpus_chosen, 0);
191
192 if (output_param == 0)
193 cpuidle_general_output();
194
195 for (cpu = bitmask_first(cpus_chosen);
196 cpu <= bitmask_last(cpus_chosen); cpu++) {
197
198 if (!bitmask_isbitset(cpus_chosen, cpu) ||
199 cpufreq_cpu_exists(cpu))
200 continue;
201
202 switch (output_param) {
203
204 case 'o':
205 proc_cpuidle_cpu_output(cpu);
206 break;
207 case 0:
208 printf("\n");
209 cpuidle_cpu_output(cpu, verbose);
210 break;
211 }
212 }
213 return EXIT_SUCCESS;
214 }
215