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(_("Residency: %lu\n"), 68 cpuidle_state_residency(cpu, idlestate)); 69 printf(_("Usage: %lu\n"), 70 cpuidle_state_usage(cpu, idlestate)); 71 printf(_("Duration: %llu\n"), 72 cpuidle_state_time(cpu, idlestate)); 73 } 74 } 75 76 static void cpuidle_general_output(void) 77 { 78 char *tmp; 79 80 tmp = cpuidle_get_driver(); 81 if (!tmp) { 82 printf(_("Could not determine cpuidle driver\n")); 83 return; 84 } 85 86 printf(_("CPUidle driver: %s\n"), tmp); 87 free(tmp); 88 89 tmp = cpuidle_get_governor(); 90 if (!tmp) { 91 printf(_("Could not determine cpuidle governor\n")); 92 return; 93 } 94 95 printf(_("CPUidle governor: %s\n"), tmp); 96 free(tmp); 97 } 98 99 static void proc_cpuidle_cpu_output(unsigned int cpu) 100 { 101 long max_allowed_cstate = 2000000000; 102 unsigned int cstate, cstates; 103 104 cstates = cpuidle_state_count(cpu); 105 if (cstates == 0) { 106 printf(_("CPU %u: No C-states info\n"), cpu); 107 return; 108 } 109 110 printf(_("active state: C0\n")); 111 printf(_("max_cstate: C%u\n"), cstates-1); 112 printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate); 113 printf(_("states:\t\n")); 114 for (cstate = 1; cstate < cstates; cstate++) { 115 printf(_(" C%d: " 116 "type[C%d] "), cstate, cstate); 117 printf(_("promotion[--] demotion[--] ")); 118 printf(_("latency[%03lu] "), 119 cpuidle_state_latency(cpu, cstate)); 120 printf(_("residency[%05lu] "), 121 cpuidle_state_residency(cpu, cstate)); 122 printf(_("usage[%08lu] "), 123 cpuidle_state_usage(cpu, cstate)); 124 printf(_("duration[%020Lu] \n"), 125 cpuidle_state_time(cpu, cstate)); 126 } 127 } 128 129 static struct option info_opts[] = { 130 {"silent", no_argument, NULL, 's'}, 131 {"proc", no_argument, NULL, 'o'}, 132 { }, 133 }; 134 135 static inline void cpuidle_exit(int fail) 136 { 137 exit(EXIT_FAILURE); 138 } 139 140 int cmd_idle_info(int argc, char **argv) 141 { 142 extern char *optarg; 143 extern int optind, opterr, optopt; 144 int ret = 0, cont = 1, output_param = 0, verbose = 1; 145 unsigned int cpu = 0; 146 147 do { 148 ret = getopt_long(argc, argv, "os", info_opts, NULL); 149 if (ret == -1) 150 break; 151 switch (ret) { 152 case '?': 153 output_param = '?'; 154 cont = 0; 155 break; 156 case 's': 157 verbose = 0; 158 break; 159 case -1: 160 cont = 0; 161 break; 162 case 'o': 163 if (output_param) { 164 output_param = -1; 165 cont = 0; 166 break; 167 } 168 output_param = ret; 169 break; 170 } 171 } while (cont); 172 173 switch (output_param) { 174 case -1: 175 printf(_("You can't specify more than one " 176 "output-specific argument\n")); 177 cpuidle_exit(EXIT_FAILURE); 178 case '?': 179 printf(_("invalid or unknown argument\n")); 180 cpuidle_exit(EXIT_FAILURE); 181 } 182 183 /* Default is: show output of base_cpu only */ 184 if (bitmask_isallclear(cpus_chosen)) 185 bitmask_setbit(cpus_chosen, base_cpu); 186 187 if (output_param == 0) 188 cpuidle_general_output(); 189 190 for (cpu = bitmask_first(cpus_chosen); 191 cpu <= bitmask_last(cpus_chosen); cpu++) { 192 193 if (!bitmask_isbitset(cpus_chosen, cpu)) 194 continue; 195 196 printf(_("analyzing CPU %d:\n"), cpu); 197 198 if (sysfs_is_cpu_online(cpu) != 1) { 199 printf(_(" *is offline\n")); 200 printf("\n"); 201 continue; 202 } 203 204 switch (output_param) { 205 206 case 'o': 207 proc_cpuidle_cpu_output(cpu); 208 break; 209 case 0: 210 printf("\n"); 211 cpuidle_cpu_output(cpu, verbose); 212 break; 213 } 214 printf("\n"); 215 } 216 return EXIT_SUCCESS; 217 } 218