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