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 unsigned 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 36 printf(_("Number of idle states: %d\n"), idlestates); 37 printf(_("Available idle states:")); 38 for (idlestate = 0; idlestate < idlestates; idlestate++) { 39 tmp = sysfs_get_idlestate_name(cpu, idlestate); 40 if (!tmp) 41 continue; 42 printf(" %s", tmp); 43 free(tmp); 44 } 45 printf("\n"); 46 47 if (!verbose) 48 return; 49 50 for (idlestate = 0; idlestate < idlestates; idlestate++) { 51 int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); 52 /* Disabled interface not supported on older kernels */ 53 if (disabled < 0) 54 disabled = 0; 55 tmp = sysfs_get_idlestate_name(cpu, idlestate); 56 if (!tmp) 57 continue; 58 printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); 59 free(tmp); 60 61 tmp = sysfs_get_idlestate_desc(cpu, idlestate); 62 if (!tmp) 63 continue; 64 printf(_("Flags/Description: %s\n"), tmp); 65 free(tmp); 66 67 printf(_("Latency: %lu\n"), 68 sysfs_get_idlestate_latency(cpu, idlestate)); 69 printf(_("Usage: %lu\n"), 70 sysfs_get_idlestate_usage(cpu, idlestate)); 71 printf(_("Duration: %llu\n"), 72 sysfs_get_idlestate_time(cpu, idlestate)); 73 } 74 printf("\n"); 75 } 76 77 static void cpuidle_general_output(void) 78 { 79 char *tmp; 80 81 tmp = sysfs_get_cpuidle_driver(); 82 if (!tmp) { 83 printf(_("Could not determine cpuidle driver\n")); 84 return; 85 } 86 87 printf(_("CPUidle driver: %s\n"), tmp); 88 free(tmp); 89 90 tmp = sysfs_get_cpuidle_governor(); 91 if (!tmp) { 92 printf(_("Could not determine cpuidle governor\n")); 93 return; 94 } 95 96 printf(_("CPUidle governor: %s\n"), tmp); 97 free(tmp); 98 } 99 100 static void proc_cpuidle_cpu_output(unsigned int cpu) 101 { 102 long max_allowed_cstate = 2000000000; 103 unsigned int cstate, cstates; 104 105 cstates = sysfs_get_idlestate_count(cpu); 106 if (cstates == 0) { 107 printf(_("CPU %u: No C-states info\n"), cpu); 108 return; 109 } 110 111 printf(_("active state: C0\n")); 112 printf(_("max_cstate: C%u\n"), cstates-1); 113 printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate); 114 printf(_("states:\t\n")); 115 for (cstate = 1; cstate < cstates; cstate++) { 116 printf(_(" C%d: " 117 "type[C%d] "), cstate, cstate); 118 printf(_("promotion[--] demotion[--] ")); 119 printf(_("latency[%03lu] "), 120 sysfs_get_idlestate_latency(cpu, cstate)); 121 printf(_("usage[%08lu] "), 122 sysfs_get_idlestate_usage(cpu, cstate)); 123 printf(_("duration[%020Lu] \n"), 124 sysfs_get_idlestate_time(cpu, cstate)); 125 } 126 } 127 128 static struct option info_opts[] = { 129 { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, 130 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, 131 { }, 132 }; 133 134 static inline void cpuidle_exit(int fail) 135 { 136 exit(EXIT_FAILURE); 137 } 138 139 int cmd_idle_info(int argc, char **argv) 140 { 141 extern char *optarg; 142 extern int optind, opterr, optopt; 143 int ret = 0, cont = 1, output_param = 0, verbose = 1; 144 unsigned int cpu = 0; 145 146 do { 147 ret = getopt_long(argc, argv, "os", info_opts, NULL); 148 if (ret == -1) 149 break; 150 switch (ret) { 151 case '?': 152 output_param = '?'; 153 cont = 0; 154 break; 155 case 's': 156 verbose = 0; 157 break; 158 case -1: 159 cont = 0; 160 break; 161 case 'o': 162 if (output_param) { 163 output_param = -1; 164 cont = 0; 165 break; 166 } 167 output_param = ret; 168 break; 169 } 170 } while (cont); 171 172 switch (output_param) { 173 case -1: 174 printf(_("You can't specify more than one " 175 "output-specific argument\n")); 176 cpuidle_exit(EXIT_FAILURE); 177 case '?': 178 printf(_("invalid or unknown argument\n")); 179 cpuidle_exit(EXIT_FAILURE); 180 } 181 182 /* Default is: show output of CPU 0 only */ 183 if (bitmask_isallclear(cpus_chosen)) 184 bitmask_setbit(cpus_chosen, 0); 185 186 if (output_param == 0) 187 cpuidle_general_output(); 188 189 for (cpu = bitmask_first(cpus_chosen); 190 cpu <= bitmask_last(cpus_chosen); cpu++) { 191 192 if (!bitmask_isbitset(cpus_chosen, cpu) || 193 cpufreq_cpu_exists(cpu)) 194 continue; 195 196 switch (output_param) { 197 198 case 'o': 199 proc_cpuidle_cpu_output(cpu); 200 break; 201 case 0: 202 printf("\n"); 203 cpuidle_cpu_output(cpu, verbose); 204 break; 205 } 206 } 207 return EXIT_SUCCESS; 208 } 209