Commit | Line | Data |
---|---|---|
7fe2f639 DB |
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> | |
7fe2f639 | 15 | |
ac5a181d TR |
16 | #include <cpuidle.h> |
17 | ||
7fe2f639 | 18 | #include "helpers/sysfs.h" |
ac5a181d | 19 | #include "helpers/helpers.h" |
7fe2f639 DB |
20 | #include "helpers/bitmask.h" |
21 | ||
22 | #define LINE_LEN 10 | |
23 | ||
24 | static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |
25 | { | |
f605181a | 26 | unsigned int idlestates, idlestate; |
7fe2f639 DB |
27 | char *tmp; |
28 | ||
ac5a181d | 29 | idlestates = cpuidle_state_count(cpu); |
7fe2f639 DB |
30 | if (idlestates == 0) { |
31 | printf(_("CPU %u: No idle states\n"), cpu); | |
32 | return; | |
7fe2f639 | 33 | } |
f605181a | 34 | |
7fe2f639 | 35 | printf(_("Number of idle states: %d\n"), idlestates); |
7fe2f639 | 36 | printf(_("Available idle states:")); |
0b37ee65 | 37 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
ac5a181d | 38 | tmp = cpuidle_state_name(cpu, idlestate); |
7fe2f639 DB |
39 | if (!tmp) |
40 | continue; | |
41 | printf(" %s", tmp); | |
42 | free(tmp); | |
43 | } | |
44 | printf("\n"); | |
45 | ||
46 | if (!verbose) | |
47 | return; | |
48 | ||
0b37ee65 | 49 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
ac5a181d | 50 | int disabled = cpuidle_is_state_disabled(cpu, idlestate); |
c4f3610e TR |
51 | /* Disabled interface not supported on older kernels */ |
52 | if (disabled < 0) | |
53 | disabled = 0; | |
ac5a181d | 54 | tmp = cpuidle_state_name(cpu, idlestate); |
7fe2f639 DB |
55 | if (!tmp) |
56 | continue; | |
c4f3610e | 57 | printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); |
7fe2f639 DB |
58 | free(tmp); |
59 | ||
ac5a181d | 60 | tmp = cpuidle_state_desc(cpu, idlestate); |
7fe2f639 DB |
61 | if (!tmp) |
62 | continue; | |
63 | printf(_("Flags/Description: %s\n"), tmp); | |
64 | free(tmp); | |
65 | ||
66 | printf(_("Latency: %lu\n"), | |
ac5a181d | 67 | cpuidle_state_latency(cpu, idlestate)); |
7fe2f639 | 68 | printf(_("Usage: %lu\n"), |
ac5a181d | 69 | cpuidle_state_usage(cpu, idlestate)); |
7fe2f639 | 70 | printf(_("Duration: %llu\n"), |
ac5a181d | 71 | cpuidle_state_time(cpu, idlestate)); |
7fe2f639 | 72 | } |
7fe2f639 DB |
73 | } |
74 | ||
75 | static void cpuidle_general_output(void) | |
76 | { | |
77 | char *tmp; | |
78 | ||
ac5a181d | 79 | tmp = cpuidle_get_driver(); |
7fe2f639 DB |
80 | if (!tmp) { |
81 | printf(_("Could not determine cpuidle driver\n")); | |
82 | return; | |
83 | } | |
84 | ||
85 | printf(_("CPUidle driver: %s\n"), tmp); | |
a1ce5ba2 | 86 | free(tmp); |
7fe2f639 | 87 | |
ac5a181d | 88 | tmp = cpuidle_get_governor(); |
7fe2f639 DB |
89 | if (!tmp) { |
90 | printf(_("Could not determine cpuidle governor\n")); | |
91 | return; | |
92 | } | |
93 | ||
94 | printf(_("CPUidle governor: %s\n"), tmp); | |
a1ce5ba2 | 95 | free(tmp); |
7fe2f639 DB |
96 | } |
97 | ||
98 | static void proc_cpuidle_cpu_output(unsigned int cpu) | |
99 | { | |
100 | long max_allowed_cstate = 2000000000; | |
f605181a | 101 | unsigned int cstate, cstates; |
7fe2f639 | 102 | |
ac5a181d | 103 | cstates = cpuidle_state_count(cpu); |
7fe2f639 | 104 | if (cstates == 0) { |
f605181a | 105 | printf(_("CPU %u: No C-states info\n"), cpu); |
7fe2f639 DB |
106 | return; |
107 | } | |
7fe2f639 DB |
108 | |
109 | printf(_("active state: C0\n")); | |
110 | printf(_("max_cstate: C%u\n"), cstates-1); | |
111 | printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate); | |
112 | printf(_("states:\t\n")); | |
113 | for (cstate = 1; cstate < cstates; cstate++) { | |
114 | printf(_(" C%d: " | |
115 | "type[C%d] "), cstate, cstate); | |
116 | printf(_("promotion[--] demotion[--] ")); | |
117 | printf(_("latency[%03lu] "), | |
ac5a181d | 118 | cpuidle_state_latency(cpu, cstate)); |
7fe2f639 | 119 | printf(_("usage[%08lu] "), |
ac5a181d | 120 | cpuidle_state_usage(cpu, cstate)); |
7fe2f639 | 121 | printf(_("duration[%020Lu] \n"), |
ac5a181d | 122 | cpuidle_state_time(cpu, cstate)); |
7fe2f639 DB |
123 | } |
124 | } | |
125 | ||
7fe2f639 | 126 | static struct option info_opts[] = { |
57ab3b08 SR |
127 | {"silent", no_argument, NULL, 's'}, |
128 | {"proc", no_argument, NULL, 'o'}, | |
7fe2f639 DB |
129 | { }, |
130 | }; | |
131 | ||
132 | static inline void cpuidle_exit(int fail) | |
133 | { | |
7fe2f639 DB |
134 | exit(EXIT_FAILURE); |
135 | } | |
136 | ||
137 | int cmd_idle_info(int argc, char **argv) | |
138 | { | |
139 | extern char *optarg; | |
140 | extern int optind, opterr, optopt; | |
141 | int ret = 0, cont = 1, output_param = 0, verbose = 1; | |
142 | unsigned int cpu = 0; | |
143 | ||
144 | do { | |
498ca793 | 145 | ret = getopt_long(argc, argv, "os", info_opts, NULL); |
7fe2f639 DB |
146 | if (ret == -1) |
147 | break; | |
148 | switch (ret) { | |
149 | case '?': | |
150 | output_param = '?'; | |
151 | cont = 0; | |
152 | break; | |
7fe2f639 DB |
153 | case 's': |
154 | verbose = 0; | |
155 | break; | |
156 | case -1: | |
157 | cont = 0; | |
158 | break; | |
159 | case 'o': | |
160 | if (output_param) { | |
161 | output_param = -1; | |
162 | cont = 0; | |
163 | break; | |
164 | } | |
165 | output_param = ret; | |
166 | break; | |
167 | } | |
a1ce5ba2 | 168 | } while (cont); |
7fe2f639 DB |
169 | |
170 | switch (output_param) { | |
171 | case -1: | |
172 | printf(_("You can't specify more than one " | |
173 | "output-specific argument\n")); | |
174 | cpuidle_exit(EXIT_FAILURE); | |
175 | case '?': | |
176 | printf(_("invalid or unknown argument\n")); | |
177 | cpuidle_exit(EXIT_FAILURE); | |
7fe2f639 DB |
178 | } |
179 | ||
180 | /* Default is: show output of CPU 0 only */ | |
181 | if (bitmask_isallclear(cpus_chosen)) | |
182 | bitmask_setbit(cpus_chosen, 0); | |
a1ce5ba2 | 183 | |
7fe2f639 DB |
184 | if (output_param == 0) |
185 | cpuidle_general_output(); | |
a1ce5ba2 | 186 | |
7fe2f639 DB |
187 | for (cpu = bitmask_first(cpus_chosen); |
188 | cpu <= bitmask_last(cpus_chosen); cpu++) { | |
189 | ||
ce512b84 | 190 | if (!bitmask_isbitset(cpus_chosen, cpu)) |
7fe2f639 DB |
191 | continue; |
192 | ||
ce512b84 TR |
193 | printf(_("analyzing CPU %d:\n"), cpu); |
194 | ||
195 | if (sysfs_is_cpu_online(cpu) != 1) { | |
196 | printf(_(" *is offline\n")); | |
197 | printf("\n"); | |
198 | continue; | |
199 | } | |
200 | ||
7fe2f639 DB |
201 | switch (output_param) { |
202 | ||
203 | case 'o': | |
204 | proc_cpuidle_cpu_output(cpu); | |
205 | break; | |
206 | case 0: | |
207 | printf("\n"); | |
208 | cpuidle_cpu_output(cpu, verbose); | |
209 | break; | |
210 | } | |
ce512b84 | 211 | printf("\n"); |
7fe2f639 | 212 | } |
a1ce5ba2 | 213 | return EXIT_SUCCESS; |
7fe2f639 | 214 | } |