xref: /linux/tools/power/cpupower/utils/cpufreq-info.c (revision 0883c2c06fb5bcf5b9e008270827e63c09a88c1e)
1 /*
2  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
3  *
4  *  Licensed under the terms of the GNU GPL License version 2.
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 <limits.h>
14 
15 #include <getopt.h>
16 
17 #include "cpufreq.h"
18 #include "helpers/sysfs.h"
19 #include "helpers/helpers.h"
20 #include "helpers/bitmask.h"
21 
22 #define LINE_LEN 10
23 
24 static unsigned int count_cpus(void)
25 {
26 	FILE *fp;
27 	char value[LINE_LEN];
28 	unsigned int ret = 0;
29 	unsigned int cpunr = 0;
30 
31 	fp = fopen("/proc/stat", "r");
32 	if (!fp) {
33 		printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
34 		return 1;
35 	}
36 
37 	while (!feof(fp)) {
38 		if (!fgets(value, LINE_LEN, fp))
39 			continue;
40 		value[LINE_LEN - 1] = '\0';
41 		if (strlen(value) < (LINE_LEN - 2))
42 			continue;
43 		if (strstr(value, "cpu "))
44 			continue;
45 		if (sscanf(value, "cpu%d ", &cpunr) != 1)
46 			continue;
47 		if (cpunr > ret)
48 			ret = cpunr;
49 	}
50 	fclose(fp);
51 
52 	/* cpu count starts from 0, on error return 1 (UP) */
53 	return ret + 1;
54 }
55 
56 
57 static void proc_cpufreq_output(void)
58 {
59 	unsigned int cpu, nr_cpus;
60 	struct cpufreq_policy *policy;
61 	unsigned int min_pctg = 0;
62 	unsigned int max_pctg = 0;
63 	unsigned long min, max;
64 
65 	printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"));
66 
67 	nr_cpus = count_cpus();
68 	for (cpu = 0; cpu < nr_cpus; cpu++) {
69 		policy = cpufreq_get_policy(cpu);
70 		if (!policy)
71 			continue;
72 
73 		if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
74 			max = 0;
75 		} else {
76 			min_pctg = (policy->min * 100) / max;
77 			max_pctg = (policy->max * 100) / max;
78 		}
79 		printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n",
80 			cpu , policy->min, max ? min_pctg : 0, policy->max,
81 			max ? max_pctg : 0, policy->governor);
82 
83 		cpufreq_put_policy(policy);
84 	}
85 }
86 
87 static int no_rounding;
88 static void print_speed(unsigned long speed)
89 {
90 	unsigned long tmp;
91 
92 	if (no_rounding) {
93 		if (speed > 1000000)
94 			printf("%u.%06u GHz", ((unsigned int) speed/1000000),
95 				((unsigned int) speed%1000000));
96 		else if (speed > 100000)
97 			printf("%u MHz", (unsigned int) speed);
98 		else if (speed > 1000)
99 			printf("%u.%03u MHz", ((unsigned int) speed/1000),
100 				(unsigned int) (speed%1000));
101 		else
102 			printf("%lu kHz", speed);
103 	} else {
104 		if (speed > 1000000) {
105 			tmp = speed%10000;
106 			if (tmp >= 5000)
107 				speed += 10000;
108 			printf("%u.%02u GHz", ((unsigned int) speed/1000000),
109 				((unsigned int) (speed%1000000)/10000));
110 		} else if (speed > 100000) {
111 			tmp = speed%1000;
112 			if (tmp >= 500)
113 				speed += 1000;
114 			printf("%u MHz", ((unsigned int) speed/1000));
115 		} else if (speed > 1000) {
116 			tmp = speed%100;
117 			if (tmp >= 50)
118 				speed += 100;
119 			printf("%u.%01u MHz", ((unsigned int) speed/1000),
120 				((unsigned int) (speed%1000)/100));
121 		}
122 	}
123 
124 	return;
125 }
126 
127 static void print_duration(unsigned long duration)
128 {
129 	unsigned long tmp;
130 
131 	if (no_rounding) {
132 		if (duration > 1000000)
133 			printf("%u.%06u ms", ((unsigned int) duration/1000000),
134 				((unsigned int) duration%1000000));
135 		else if (duration > 100000)
136 			printf("%u us", ((unsigned int) duration/1000));
137 		else if (duration > 1000)
138 			printf("%u.%03u us", ((unsigned int) duration/1000),
139 				((unsigned int) duration%1000));
140 		else
141 			printf("%lu ns", duration);
142 	} else {
143 		if (duration > 1000000) {
144 			tmp = duration%10000;
145 			if (tmp >= 5000)
146 				duration += 10000;
147 			printf("%u.%02u ms", ((unsigned int) duration/1000000),
148 				((unsigned int) (duration%1000000)/10000));
149 		} else if (duration > 100000) {
150 			tmp = duration%1000;
151 			if (tmp >= 500)
152 				duration += 1000;
153 			printf("%u us", ((unsigned int) duration / 1000));
154 		} else if (duration > 1000) {
155 			tmp = duration%100;
156 			if (tmp >= 50)
157 				duration += 100;
158 			printf("%u.%01u us", ((unsigned int) duration/1000),
159 				((unsigned int) (duration%1000)/100));
160 		} else
161 			printf("%lu ns", duration);
162 	}
163 	return;
164 }
165 
166 /* --boost / -b */
167 
168 static int get_boost_mode(unsigned int cpu)
169 {
170 	int support, active, b_states = 0, ret, pstate_no, i;
171 	/* ToDo: Make this more global */
172 	unsigned long pstates[MAX_HW_PSTATES] = {0,};
173 
174 	if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
175 	    cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
176 		return 0;
177 
178 	ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
179 	if (ret) {
180 		printf(_("Error while evaluating Boost Capabilities"
181 				" on CPU %d -- are you root?\n"), cpu);
182 		return ret;
183 	}
184 	/* P state changes via MSR are identified via cpuid 80000007
185 	   on Intel and AMD, but we assume boost capable machines can do that
186 	   if (cpuid_eax(0x80000000) >= 0x80000007
187 	   && (cpuid_edx(0x80000007) & (1 << 7)))
188 	*/
189 
190 	printf(_("  boost state support:\n"));
191 
192 	printf(_("    Supported: %s\n"), support ? _("yes") : _("no"));
193 	printf(_("    Active: %s\n"), active ? _("yes") : _("no"));
194 
195 	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
196 	    cpupower_cpu_info.family >= 0x10) {
197 		ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
198 				     pstates, &pstate_no);
199 		if (ret)
200 			return ret;
201 
202 		printf(_("    Boost States: %d\n"), b_states);
203 		printf(_("    Total States: %d\n"), pstate_no);
204 		for (i = 0; i < pstate_no; i++) {
205 			if (i < b_states)
206 				printf(_("    Pstate-Pb%d: %luMHz (boost state)"
207 					 "\n"), i, pstates[i]);
208 			else
209 				printf(_("    Pstate-P%d:  %luMHz\n"),
210 				       i - b_states, pstates[i]);
211 		}
212 	} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
213 		double bclk;
214 		unsigned long long intel_turbo_ratio = 0;
215 		unsigned int ratio;
216 
217 		/* Any way to autodetect this ? */
218 		if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
219 			bclk = 100.00;
220 		else
221 			bclk = 133.33;
222 		intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
223 		dprint ("    Ratio: 0x%llx - bclk: %f\n",
224 			intel_turbo_ratio, bclk);
225 
226 		ratio = (intel_turbo_ratio >> 24) & 0xFF;
227 		if (ratio)
228 			printf(_("    %.0f MHz max turbo 4 active cores\n"),
229 			       ratio * bclk);
230 
231 		ratio = (intel_turbo_ratio >> 16) & 0xFF;
232 		if (ratio)
233 			printf(_("    %.0f MHz max turbo 3 active cores\n"),
234 			       ratio * bclk);
235 
236 		ratio = (intel_turbo_ratio >> 8) & 0xFF;
237 		if (ratio)
238 			printf(_("    %.0f MHz max turbo 2 active cores\n"),
239 			       ratio * bclk);
240 
241 		ratio = (intel_turbo_ratio >> 0) & 0xFF;
242 		if (ratio)
243 			printf(_("    %.0f MHz max turbo 1 active cores\n"),
244 			       ratio * bclk);
245 	}
246 	return 0;
247 }
248 
249 /* --freq / -f */
250 
251 static int get_freq_kernel(unsigned int cpu, unsigned int human)
252 {
253 	unsigned long freq = cpufreq_get_freq_kernel(cpu);
254 	printf(_("  current CPU frequency: "));
255 	if (!freq) {
256 		printf(_(" Unable to call to kernel\n"));
257 		return -EINVAL;
258 	}
259 	if (human) {
260 		print_speed(freq);
261 	} else
262 		printf("%lu", freq);
263 	printf(_(" (asserted by call to kernel)\n"));
264 	return 0;
265 }
266 
267 
268 /* --hwfreq / -w */
269 
270 static int get_freq_hardware(unsigned int cpu, unsigned int human)
271 {
272 	unsigned long freq = cpufreq_get_freq_hardware(cpu);
273 	printf(_("  current CPU frequency: "));
274 	if (!freq) {
275 		printf("Unable to call hardware\n");
276 		return -EINVAL;
277 	}
278 	if (human) {
279 		print_speed(freq);
280 	} else
281 		printf("%lu", freq);
282 	printf(_(" (asserted by call to hardware)\n"));
283 	return 0;
284 }
285 
286 /* --hwlimits / -l */
287 
288 static int get_hardware_limits(unsigned int cpu)
289 {
290 	unsigned long min, max;
291 
292 	printf(_("  hardware limits: "));
293 	if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
294 		printf(_("Not Available\n"));
295 		return -EINVAL;
296 	}
297 
298 	print_speed(min);
299 	printf(" - ");
300 	print_speed(max);
301 	printf("\n");
302 	return 0;
303 }
304 
305 /* --driver / -d */
306 
307 static int get_driver(unsigned int cpu)
308 {
309 	char *driver = cpufreq_get_driver(cpu);
310 	if (!driver) {
311 		printf(_("  no or unknown cpufreq driver is active on this CPU\n"));
312 		return -EINVAL;
313 	}
314 	printf("  driver: %s\n", driver);
315 	cpufreq_put_driver(driver);
316 	return 0;
317 }
318 
319 /* --policy / -p */
320 
321 static int get_policy(unsigned int cpu)
322 {
323 	struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
324 	if (!policy) {
325 		printf(_("  Unable to determine current policy\n"));
326 		return -EINVAL;
327 	}
328 	printf(_("  current policy: frequency should be within "));
329 	print_speed(policy->min);
330 	printf(_(" and "));
331 	print_speed(policy->max);
332 
333 	printf(".\n                  ");
334 	printf(_("The governor \"%s\" may decide which speed to use\n"
335 	       "                  within this range.\n"),
336 	       policy->governor);
337 	cpufreq_put_policy(policy);
338 	return 0;
339 }
340 
341 /* --governors / -g */
342 
343 static int get_available_governors(unsigned int cpu)
344 {
345 	struct cpufreq_available_governors *governors =
346 		cpufreq_get_available_governors(cpu);
347 
348 	printf(_("  available cpufreq governors: "));
349 	if (!governors) {
350 		printf(_("Not Available\n"));
351 		return -EINVAL;
352 	}
353 
354 	while (governors->next) {
355 		printf("%s ", governors->governor);
356 		governors = governors->next;
357 	}
358 	printf("%s\n", governors->governor);
359 	cpufreq_put_available_governors(governors);
360 	return 0;
361 }
362 
363 
364 /* --affected-cpus  / -a */
365 
366 static int get_affected_cpus(unsigned int cpu)
367 {
368 	struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
369 
370 	printf(_("  CPUs which need to have their frequency coordinated by software: "));
371 	if (!cpus) {
372 		printf(_("Not Available\n"));
373 		return -EINVAL;
374 	}
375 
376 	while (cpus->next) {
377 		printf("%d ", cpus->cpu);
378 		cpus = cpus->next;
379 	}
380 	printf("%d\n", cpus->cpu);
381 	cpufreq_put_affected_cpus(cpus);
382 	return 0;
383 }
384 
385 /* --related-cpus  / -r */
386 
387 static int get_related_cpus(unsigned int cpu)
388 {
389 	struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
390 
391 	printf(_("  CPUs which run at the same hardware frequency: "));
392 	if (!cpus) {
393 		printf(_("Not Available\n"));
394 		return -EINVAL;
395 	}
396 
397 	while (cpus->next) {
398 		printf("%d ", cpus->cpu);
399 		cpus = cpus->next;
400 	}
401 	printf("%d\n", cpus->cpu);
402 	cpufreq_put_related_cpus(cpus);
403 	return 0;
404 }
405 
406 /* --stats / -s */
407 
408 static int get_freq_stats(unsigned int cpu, unsigned int human)
409 {
410 	unsigned long total_trans = cpufreq_get_transitions(cpu);
411 	unsigned long long total_time;
412 	struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
413 	while (stats) {
414 		if (human) {
415 			print_speed(stats->frequency);
416 			printf(":%.2f%%",
417 				(100.0 * stats->time_in_state) / total_time);
418 		} else
419 			printf("%lu:%llu",
420 				stats->frequency, stats->time_in_state);
421 		stats = stats->next;
422 		if (stats)
423 			printf(", ");
424 	}
425 	cpufreq_put_stats(stats);
426 	if (total_trans)
427 		printf("  (%lu)\n", total_trans);
428 	return 0;
429 }
430 
431 /* --latency / -y */
432 
433 static int get_latency(unsigned int cpu, unsigned int human)
434 {
435 	unsigned long latency = cpufreq_get_transition_latency(cpu);
436 
437 	printf(_("  maximum transition latency: "));
438 	if (!latency || latency == UINT_MAX) {
439 		printf(_(" Cannot determine or is not supported.\n"));
440 		return -EINVAL;
441 	}
442 
443 	if (human) {
444 		print_duration(latency);
445 		printf("\n");
446 	} else
447 		printf("%lu\n", latency);
448 	return 0;
449 }
450 
451 static void debug_output_one(unsigned int cpu)
452 {
453 	struct cpufreq_available_frequencies *freqs;
454 
455 	get_driver(cpu);
456 	get_related_cpus(cpu);
457 	get_affected_cpus(cpu);
458 	get_latency(cpu, 1);
459 	get_hardware_limits(cpu);
460 
461 	freqs = cpufreq_get_available_frequencies(cpu);
462 	if (freqs) {
463 		printf(_("  available frequency steps:  "));
464 		while (freqs->next) {
465 			print_speed(freqs->frequency);
466 			printf(", ");
467 			freqs = freqs->next;
468 		}
469 		print_speed(freqs->frequency);
470 		printf("\n");
471 		cpufreq_put_available_frequencies(freqs);
472 	}
473 
474 	get_available_governors(cpu);
475 	get_policy(cpu);
476 	if (get_freq_hardware(cpu, 1) < 0)
477 		get_freq_kernel(cpu, 1);
478 	get_boost_mode(cpu);
479 }
480 
481 static struct option info_opts[] = {
482 	{"debug",	 no_argument,		 NULL,	 'e'},
483 	{"boost",	 no_argument,		 NULL,	 'b'},
484 	{"freq",	 no_argument,		 NULL,	 'f'},
485 	{"hwfreq",	 no_argument,		 NULL,	 'w'},
486 	{"hwlimits",	 no_argument,		 NULL,	 'l'},
487 	{"driver",	 no_argument,		 NULL,	 'd'},
488 	{"policy",	 no_argument,		 NULL,	 'p'},
489 	{"governors",	 no_argument,		 NULL,	 'g'},
490 	{"related-cpus",  no_argument,	 NULL,	 'r'},
491 	{"affected-cpus", no_argument,	 NULL,	 'a'},
492 	{"stats",	 no_argument,		 NULL,	 's'},
493 	{"latency",	 no_argument,		 NULL,	 'y'},
494 	{"proc",	 no_argument,		 NULL,	 'o'},
495 	{"human",	 no_argument,		 NULL,	 'm'},
496 	{"no-rounding", no_argument,	 NULL,	 'n'},
497 	{ },
498 };
499 
500 int cmd_freq_info(int argc, char **argv)
501 {
502 	extern char *optarg;
503 	extern int optind, opterr, optopt;
504 	int ret = 0, cont = 1;
505 	unsigned int cpu = 0;
506 	unsigned int human = 0;
507 	int output_param = 0;
508 
509 	do {
510 		ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts,
511 				  NULL);
512 		switch (ret) {
513 		case '?':
514 			output_param = '?';
515 			cont = 0;
516 			break;
517 		case -1:
518 			cont = 0;
519 			break;
520 		case 'b':
521 		case 'o':
522 		case 'a':
523 		case 'r':
524 		case 'g':
525 		case 'p':
526 		case 'd':
527 		case 'l':
528 		case 'w':
529 		case 'f':
530 		case 'e':
531 		case 's':
532 		case 'y':
533 			if (output_param) {
534 				output_param = -1;
535 				cont = 0;
536 				break;
537 			}
538 			output_param = ret;
539 			break;
540 		case 'm':
541 			if (human) {
542 				output_param = -1;
543 				cont = 0;
544 				break;
545 			}
546 			human = 1;
547 			break;
548 		case 'n':
549 			no_rounding = 1;
550 			break;
551 		default:
552 			fprintf(stderr, "invalid or unknown argument\n");
553 			return EXIT_FAILURE;
554 		}
555 	} while (cont);
556 
557 	switch (output_param) {
558 	case 'o':
559 		if (!bitmask_isallclear(cpus_chosen)) {
560 			printf(_("The argument passed to this tool can't be "
561 				 "combined with passing a --cpu argument\n"));
562 			return -EINVAL;
563 		}
564 		break;
565 	case 0:
566 		output_param = 'e';
567 	}
568 
569 	ret = 0;
570 
571 	/* Default is: show output of CPU 0 only */
572 	if (bitmask_isallclear(cpus_chosen))
573 		bitmask_setbit(cpus_chosen, 0);
574 
575 	switch (output_param) {
576 	case -1:
577 		printf(_("You can't specify more than one --cpu parameter and/or\n"
578 		       "more than one output-specific argument\n"));
579 		return -EINVAL;
580 	case '?':
581 		printf(_("invalid or unknown argument\n"));
582 		return -EINVAL;
583 	case 'o':
584 		proc_cpufreq_output();
585 		return EXIT_SUCCESS;
586 	}
587 
588 	for (cpu = bitmask_first(cpus_chosen);
589 	     cpu <= bitmask_last(cpus_chosen); cpu++) {
590 
591 		if (!bitmask_isbitset(cpus_chosen, cpu))
592 			continue;
593 
594 		printf(_("analyzing CPU %d:\n"), cpu);
595 
596 		if (sysfs_is_cpu_online(cpu) != 1) {
597 			printf(_(" *is offline\n"));
598 			printf("\n");
599 			continue;
600 		}
601 
602 		switch (output_param) {
603 		case 'b':
604 			get_boost_mode(cpu);
605 			break;
606 		case 'e':
607 			debug_output_one(cpu);
608 			break;
609 		case 'a':
610 			ret = get_affected_cpus(cpu);
611 			break;
612 		case 'r':
613 			ret = get_related_cpus(cpu);
614 			break;
615 		case 'g':
616 			ret = get_available_governors(cpu);
617 			break;
618 		case 'p':
619 			ret = get_policy(cpu);
620 			break;
621 		case 'd':
622 			ret = get_driver(cpu);
623 			break;
624 		case 'l':
625 			ret = get_hardware_limits(cpu);
626 			break;
627 		case 'w':
628 			ret = get_freq_hardware(cpu, human);
629 			break;
630 		case 'f':
631 			ret = get_freq_kernel(cpu, human);
632 			break;
633 		case 's':
634 			ret = get_freq_stats(cpu, human);
635 			break;
636 		case 'y':
637 			ret = get_latency(cpu, human);
638 			break;
639 		}
640 		if (ret)
641 			return ret;
642 		printf("\n");
643 	}
644 	return ret;
645 }
646