1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> |
4 | * (C) 2010 Thomas Renninger <trenn@suse.de> |
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> |
14 | |
15 | #include <cpuidle.h> |
16 | |
17 | #include "helpers/sysfs.h" |
18 | #include "helpers/helpers.h" |
19 | #include "helpers/bitmask.h" |
20 | |
21 | #define LINE_LEN 10 |
22 | |
23 | static void cpuidle_cpu_output(unsigned int cpu, int verbose) |
24 | { |
25 | unsigned int idlestates, idlestate; |
26 | char *tmp; |
27 | |
28 | idlestates = cpuidle_state_count(cpu); |
29 | if (idlestates == 0) { |
30 | printf(_("CPU %u: No idle states\n" ), cpu); |
31 | return; |
32 | } |
33 | |
34 | printf(_("Number of idle states: %d\n" ), idlestates); |
35 | printf(_("Available idle states:" )); |
36 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
37 | tmp = cpuidle_state_name(cpu, idlestate); |
38 | if (!tmp) |
39 | continue; |
40 | printf(" %s" , tmp); |
41 | free(tmp); |
42 | } |
43 | printf("\n" ); |
44 | |
45 | if (!verbose) |
46 | return; |
47 | |
48 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
49 | int disabled = cpuidle_is_state_disabled(cpu, idlestate); |
50 | /* Disabled interface not supported on older kernels */ |
51 | if (disabled < 0) |
52 | disabled = 0; |
53 | tmp = cpuidle_state_name(cpu, idlestate); |
54 | if (!tmp) |
55 | continue; |
56 | printf("%s%s:\n" , tmp, (disabled) ? " (DISABLED) " : "" ); |
57 | free(tmp); |
58 | |
59 | tmp = cpuidle_state_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 | cpuidle_state_latency(cpu, idlestate)); |
67 | printf(_("Usage: %lu\n" ), |
68 | cpuidle_state_usage(cpu, idlestate)); |
69 | printf(_("Duration: %llu\n" ), |
70 | cpuidle_state_time(cpu, idlestate)); |
71 | } |
72 | } |
73 | |
74 | static void cpuidle_general_output(void) |
75 | { |
76 | char *tmp; |
77 | |
78 | tmp = cpuidle_get_driver(); |
79 | if (!tmp) { |
80 | printf(_("Could not determine cpuidle driver\n" )); |
81 | return; |
82 | } |
83 | |
84 | printf(_("CPUidle driver: %s\n" ), tmp); |
85 | free(tmp); |
86 | |
87 | tmp = cpuidle_get_governor(); |
88 | if (!tmp) { |
89 | printf(_("Could not determine cpuidle governor\n" )); |
90 | return; |
91 | } |
92 | |
93 | printf(_("CPUidle governor: %s\n" ), tmp); |
94 | free(tmp); |
95 | } |
96 | |
97 | static void proc_cpuidle_cpu_output(unsigned int cpu) |
98 | { |
99 | long max_allowed_cstate = 2000000000; |
100 | unsigned int cstate, cstates; |
101 | |
102 | cstates = cpuidle_state_count(cpu); |
103 | if (cstates == 0) { |
104 | printf(_("CPU %u: No C-states info\n" ), cpu); |
105 | return; |
106 | } |
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] " ), |
117 | cpuidle_state_latency(cpu, cstate)); |
118 | printf(_("usage[%08lu] " ), |
119 | cpuidle_state_usage(cpu, cstate)); |
120 | printf(_("duration[%020Lu] \n" ), |
121 | cpuidle_state_time(cpu, cstate)); |
122 | } |
123 | } |
124 | |
125 | static struct option info_opts[] = { |
126 | {"silent" , no_argument, NULL, 's'}, |
127 | {"proc" , no_argument, NULL, 'o'}, |
128 | { }, |
129 | }; |
130 | |
131 | static inline void cpuidle_exit(int fail) |
132 | { |
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 { |
144 | ret = getopt_long(argc, argv, "os" , info_opts, NULL); |
145 | if (ret == -1) |
146 | break; |
147 | switch (ret) { |
148 | case '?': |
149 | output_param = '?'; |
150 | cont = 0; |
151 | break; |
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 | } |
167 | } while (cont); |
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(fail: EXIT_FAILURE); |
174 | case '?': |
175 | printf(_("invalid or unknown argument\n" )); |
176 | cpuidle_exit(fail: EXIT_FAILURE); |
177 | } |
178 | |
179 | /* Default is: show output of base_cpu only */ |
180 | if (bitmask_isallclear(bmp: cpus_chosen)) |
181 | bitmask_setbit(bmp: cpus_chosen, i: base_cpu); |
182 | |
183 | if (output_param == 0) |
184 | cpuidle_general_output(); |
185 | |
186 | for (cpu = bitmask_first(bmp: cpus_chosen); |
187 | cpu <= bitmask_last(bmp: cpus_chosen); cpu++) { |
188 | |
189 | if (!bitmask_isbitset(bmp: cpus_chosen, i: cpu)) |
190 | continue; |
191 | |
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 | |
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 | } |
210 | printf("\n" ); |
211 | } |
212 | return EXIT_SUCCESS; |
213 | } |
214 | |