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(EXIT_FAILURE); 174 case '?': 175 printf(_("invalid or unknown argument\n")); 176 cpuidle_exit(EXIT_FAILURE); 177 } 178 179 /* Default is: show output of CPU 0 only */ 180 if (bitmask_isallclear(cpus_chosen)) 181 bitmask_setbit(cpus_chosen, 0); 182 183 if (output_param == 0) 184 cpuidle_general_output(); 185 186 for (cpu = bitmask_first(cpus_chosen); 187 cpu <= bitmask_last(cpus_chosen); cpu++) { 188 189 if (!bitmask_isbitset(cpus_chosen, 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