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