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> 15 #include <cpufreq.h> 16 17 #include "helpers/helpers.h" 18 #include "helpers/sysfs.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 int idlestates, idlestate; 26 char *tmp; 27 28 printf(_ ("Analyzing CPU %d:\n"), cpu); 29 30 idlestates = sysfs_get_idlestate_count(cpu); 31 if (idlestates == 0) { 32 printf(_("CPU %u: No idle states\n"), cpu); 33 return; 34 } 35 else if (idlestates <= 0) { 36 printf(_("CPU %u: Can't read idle state info\n"), cpu); 37 return; 38 } 39 tmp = sysfs_get_idlestate_name(cpu, idlestates - 1); 40 if (!tmp) { 41 printf(_("Could not determine max idle state %u\n"), 42 idlestates - 1); 43 return; 44 } 45 46 printf(_("Number of idle states: %d\n"), idlestates); 47 48 printf(_("Available idle states:")); 49 for (idlestate = 1; idlestate < idlestates; idlestate++) { 50 tmp = sysfs_get_idlestate_name(cpu, idlestate); 51 if (!tmp) 52 continue; 53 printf(" %s", tmp); 54 free(tmp); 55 } 56 printf("\n"); 57 58 if (!verbose) 59 return; 60 61 for (idlestate = 1; idlestate < idlestates; idlestate++) { 62 tmp = sysfs_get_idlestate_name(cpu, idlestate); 63 if (!tmp) 64 continue; 65 printf("%s:\n", tmp); 66 free(tmp); 67 68 tmp = sysfs_get_idlestate_desc(cpu, idlestate); 69 if (!tmp) 70 continue; 71 printf(_("Flags/Description: %s\n"), tmp); 72 free(tmp); 73 74 printf(_("Latency: %lu\n"), 75 sysfs_get_idlestate_latency(cpu, idlestate)); 76 printf(_("Usage: %lu\n"), 77 sysfs_get_idlestate_usage(cpu, idlestate)); 78 printf(_("Duration: %llu\n"), 79 sysfs_get_idlestate_time(cpu, idlestate)); 80 } 81 printf("\n"); 82 } 83 84 static void cpuidle_general_output(void) 85 { 86 char *tmp; 87 88 tmp = sysfs_get_cpuidle_driver(); 89 if (!tmp) { 90 printf(_("Could not determine cpuidle driver\n")); 91 return; 92 } 93 94 printf(_("CPUidle driver: %s\n"), tmp); 95 free (tmp); 96 97 tmp = sysfs_get_cpuidle_governor(); 98 if (!tmp) { 99 printf(_("Could not determine cpuidle governor\n")); 100 return; 101 } 102 103 printf(_("CPUidle governor: %s\n"), tmp); 104 free (tmp); 105 } 106 107 static void proc_cpuidle_cpu_output(unsigned int cpu) 108 { 109 long max_allowed_cstate = 2000000000; 110 int cstates, cstate; 111 112 cstates = sysfs_get_idlestate_count(cpu); 113 if (cstates == 0) { 114 /* 115 * Go on and print same useless info as you'd see with 116 * cat /proc/acpi/processor/../power 117 * printf(_("CPU %u: No C-states available\n"), cpu); 118 * return; 119 */ 120 } 121 else if (cstates <= 0) { 122 printf(_("CPU %u: Can't read C-state info\n"), cpu); 123 return; 124 } 125 /* printf("Cstates: %d\n", cstates); */ 126 127 printf(_("active state: C0\n")); 128 printf(_("max_cstate: C%u\n"), cstates-1); 129 printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate); 130 printf(_("states:\t\n")); 131 for (cstate = 1; cstate < cstates; cstate++) { 132 printf(_(" C%d: " 133 "type[C%d] "), cstate, cstate); 134 printf(_("promotion[--] demotion[--] ")); 135 printf(_("latency[%03lu] "), 136 sysfs_get_idlestate_latency(cpu, cstate)); 137 printf(_("usage[%08lu] "), 138 sysfs_get_idlestate_usage(cpu, cstate)); 139 printf(_("duration[%020Lu] \n"), 140 sysfs_get_idlestate_time(cpu, cstate)); 141 } 142 } 143 144 /* --freq / -f */ 145 146 void idle_info_help(void) { 147 printf(_ ("Usage: cpupower idleinfo [options]\n")); 148 printf(_ ("Options:\n")); 149 printf(_ (" -s, --silent Only show general C-state information\n")); 150 printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n" 151 " interface in older kernels\n")); 152 printf(_ (" -h, --help Prints out this screen\n")); 153 154 printf("\n"); 155 } 156 157 static struct option info_opts[] = { 158 { .name="silent", .has_arg=no_argument, .flag=NULL, .val='s'}, 159 { .name="proc", .has_arg=no_argument, .flag=NULL, .val='o'}, 160 { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'}, 161 { }, 162 }; 163 164 static inline void cpuidle_exit(int fail) 165 { 166 idle_info_help(); 167 exit(EXIT_FAILURE); 168 } 169 170 int cmd_idle_info(int argc, char **argv) 171 { 172 extern char *optarg; 173 extern int optind, opterr, optopt; 174 int ret = 0, cont = 1, output_param = 0, verbose = 1; 175 unsigned int cpu = 0; 176 177 do { 178 ret = getopt_long(argc, argv, "hos", info_opts, NULL); 179 if (ret == -1) 180 break; 181 switch (ret) { 182 case '?': 183 output_param = '?'; 184 cont = 0; 185 break; 186 case 'h': 187 output_param = 'h'; 188 cont = 0; 189 break; 190 case 's': 191 verbose = 0; 192 break; 193 case -1: 194 cont = 0; 195 break; 196 case 'o': 197 if (output_param) { 198 output_param = -1; 199 cont = 0; 200 break; 201 } 202 output_param = ret; 203 break; 204 } 205 } while(cont); 206 207 switch (output_param) { 208 case -1: 209 printf(_("You can't specify more than one " 210 "output-specific argument\n")); 211 cpuidle_exit(EXIT_FAILURE); 212 case '?': 213 printf(_("invalid or unknown argument\n")); 214 cpuidle_exit(EXIT_FAILURE); 215 case 'h': 216 cpuidle_exit(EXIT_SUCCESS); 217 } 218 219 /* Default is: show output of CPU 0 only */ 220 if (bitmask_isallclear(cpus_chosen)) 221 bitmask_setbit(cpus_chosen, 0); 222 223 if (output_param == 0) 224 cpuidle_general_output(); 225 226 for (cpu = bitmask_first(cpus_chosen); 227 cpu <= bitmask_last(cpus_chosen); cpu++) { 228 229 if (!bitmask_isbitset(cpus_chosen, cpu) || 230 cpufreq_cpu_exists(cpu)) 231 continue; 232 233 switch (output_param) { 234 235 case 'o': 236 proc_cpuidle_cpu_output(cpu); 237 break; 238 case 0: 239 printf("\n"); 240 cpuidle_cpu_output(cpu, verbose); 241 break; 242 } 243 } 244 return (EXIT_SUCCESS); 245 } 246