xref: /openbmc/linux/tools/power/cpupower/utils/cpufreq-info.c (revision 4ed91d48259d9ddd378424d008f2e6559f7e78f8)
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, unsigned int human)
289 {
290 	unsigned long min, max;
291 
292 	if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
293 		printf(_("Not Available\n"));
294 		return -EINVAL;
295 	}
296 
297 	if (human) {
298 		printf(_("  hardware limits: "));
299 		print_speed(min);
300 		printf(" - ");
301 		print_speed(max);
302 		printf("\n");
303 	} else {
304 		printf("%lu %lu\n", min, max);
305 	}
306 	return 0;
307 }
308 
309 /* --driver / -d */
310 
311 static int get_driver(unsigned int cpu)
312 {
313 	char *driver = cpufreq_get_driver(cpu);
314 	if (!driver) {
315 		printf(_("  no or unknown cpufreq driver is active on this CPU\n"));
316 		return -EINVAL;
317 	}
318 	printf("  driver: %s\n", driver);
319 	cpufreq_put_driver(driver);
320 	return 0;
321 }
322 
323 /* --policy / -p */
324 
325 static int get_policy(unsigned int cpu)
326 {
327 	struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
328 	if (!policy) {
329 		printf(_("  Unable to determine current policy\n"));
330 		return -EINVAL;
331 	}
332 	printf(_("  current policy: frequency should be within "));
333 	print_speed(policy->min);
334 	printf(_(" and "));
335 	print_speed(policy->max);
336 
337 	printf(".\n                  ");
338 	printf(_("The governor \"%s\" may decide which speed to use\n"
339 	       "                  within this range.\n"),
340 	       policy->governor);
341 	cpufreq_put_policy(policy);
342 	return 0;
343 }
344 
345 /* --governors / -g */
346 
347 static int get_available_governors(unsigned int cpu)
348 {
349 	struct cpufreq_available_governors *governors =
350 		cpufreq_get_available_governors(cpu);
351 
352 	printf(_("  available cpufreq governors: "));
353 	if (!governors) {
354 		printf(_("Not Available\n"));
355 		return -EINVAL;
356 	}
357 
358 	while (governors->next) {
359 		printf("%s ", governors->governor);
360 		governors = governors->next;
361 	}
362 	printf("%s\n", governors->governor);
363 	cpufreq_put_available_governors(governors);
364 	return 0;
365 }
366 
367 
368 /* --affected-cpus  / -a */
369 
370 static int get_affected_cpus(unsigned int cpu)
371 {
372 	struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
373 
374 	printf(_("  CPUs which need to have their frequency coordinated by software: "));
375 	if (!cpus) {
376 		printf(_("Not Available\n"));
377 		return -EINVAL;
378 	}
379 
380 	while (cpus->next) {
381 		printf("%d ", cpus->cpu);
382 		cpus = cpus->next;
383 	}
384 	printf("%d\n", cpus->cpu);
385 	cpufreq_put_affected_cpus(cpus);
386 	return 0;
387 }
388 
389 /* --related-cpus  / -r */
390 
391 static int get_related_cpus(unsigned int cpu)
392 {
393 	struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
394 
395 	printf(_("  CPUs which run at the same hardware frequency: "));
396 	if (!cpus) {
397 		printf(_("Not Available\n"));
398 		return -EINVAL;
399 	}
400 
401 	while (cpus->next) {
402 		printf("%d ", cpus->cpu);
403 		cpus = cpus->next;
404 	}
405 	printf("%d\n", cpus->cpu);
406 	cpufreq_put_related_cpus(cpus);
407 	return 0;
408 }
409 
410 /* --stats / -s */
411 
412 static int get_freq_stats(unsigned int cpu, unsigned int human)
413 {
414 	unsigned long total_trans = cpufreq_get_transitions(cpu);
415 	unsigned long long total_time;
416 	struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
417 	while (stats) {
418 		if (human) {
419 			print_speed(stats->frequency);
420 			printf(":%.2f%%",
421 				(100.0 * stats->time_in_state) / total_time);
422 		} else
423 			printf("%lu:%llu",
424 				stats->frequency, stats->time_in_state);
425 		stats = stats->next;
426 		if (stats)
427 			printf(", ");
428 	}
429 	cpufreq_put_stats(stats);
430 	if (total_trans)
431 		printf("  (%lu)\n", total_trans);
432 	return 0;
433 }
434 
435 /* --latency / -y */
436 
437 static int get_latency(unsigned int cpu, unsigned int human)
438 {
439 	unsigned long latency = cpufreq_get_transition_latency(cpu);
440 
441 	printf(_("  maximum transition latency: "));
442 	if (!latency || latency == UINT_MAX) {
443 		printf(_(" Cannot determine or is not supported.\n"));
444 		return -EINVAL;
445 	}
446 
447 	if (human) {
448 		print_duration(latency);
449 		printf("\n");
450 	} else
451 		printf("%lu\n", latency);
452 	return 0;
453 }
454 
455 static void debug_output_one(unsigned int cpu)
456 {
457 	struct cpufreq_available_frequencies *freqs;
458 
459 	get_driver(cpu);
460 	get_related_cpus(cpu);
461 	get_affected_cpus(cpu);
462 	get_latency(cpu, 1);
463 	get_hardware_limits(cpu, 1);
464 
465 	freqs = cpufreq_get_available_frequencies(cpu);
466 	if (freqs) {
467 		printf(_("  available frequency steps:  "));
468 		while (freqs->next) {
469 			print_speed(freqs->frequency);
470 			printf(", ");
471 			freqs = freqs->next;
472 		}
473 		print_speed(freqs->frequency);
474 		printf("\n");
475 		cpufreq_put_available_frequencies(freqs);
476 	}
477 
478 	get_available_governors(cpu);
479 	get_policy(cpu);
480 	if (get_freq_hardware(cpu, 1) < 0)
481 		get_freq_kernel(cpu, 1);
482 	get_boost_mode(cpu);
483 }
484 
485 static struct option info_opts[] = {
486 	{"debug",	 no_argument,		 NULL,	 'e'},
487 	{"boost",	 no_argument,		 NULL,	 'b'},
488 	{"freq",	 no_argument,		 NULL,	 'f'},
489 	{"hwfreq",	 no_argument,		 NULL,	 'w'},
490 	{"hwlimits",	 no_argument,		 NULL,	 'l'},
491 	{"driver",	 no_argument,		 NULL,	 'd'},
492 	{"policy",	 no_argument,		 NULL,	 'p'},
493 	{"governors",	 no_argument,		 NULL,	 'g'},
494 	{"related-cpus",  no_argument,	 NULL,	 'r'},
495 	{"affected-cpus", no_argument,	 NULL,	 'a'},
496 	{"stats",	 no_argument,		 NULL,	 's'},
497 	{"latency",	 no_argument,		 NULL,	 'y'},
498 	{"proc",	 no_argument,		 NULL,	 'o'},
499 	{"human",	 no_argument,		 NULL,	 'm'},
500 	{"no-rounding", no_argument,	 NULL,	 'n'},
501 	{ },
502 };
503 
504 int cmd_freq_info(int argc, char **argv)
505 {
506 	extern char *optarg;
507 	extern int optind, opterr, optopt;
508 	int ret = 0, cont = 1;
509 	unsigned int cpu = 0;
510 	unsigned int human = 0;
511 	int output_param = 0;
512 
513 	do {
514 		ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts,
515 				  NULL);
516 		switch (ret) {
517 		case '?':
518 			output_param = '?';
519 			cont = 0;
520 			break;
521 		case -1:
522 			cont = 0;
523 			break;
524 		case 'b':
525 		case 'o':
526 		case 'a':
527 		case 'r':
528 		case 'g':
529 		case 'p':
530 		case 'd':
531 		case 'l':
532 		case 'w':
533 		case 'f':
534 		case 'e':
535 		case 's':
536 		case 'y':
537 			if (output_param) {
538 				output_param = -1;
539 				cont = 0;
540 				break;
541 			}
542 			output_param = ret;
543 			break;
544 		case 'm':
545 			if (human) {
546 				output_param = -1;
547 				cont = 0;
548 				break;
549 			}
550 			human = 1;
551 			break;
552 		case 'n':
553 			no_rounding = 1;
554 			break;
555 		default:
556 			fprintf(stderr, "invalid or unknown argument\n");
557 			return EXIT_FAILURE;
558 		}
559 	} while (cont);
560 
561 	switch (output_param) {
562 	case 'o':
563 		if (!bitmask_isallclear(cpus_chosen)) {
564 			printf(_("The argument passed to this tool can't be "
565 				 "combined with passing a --cpu argument\n"));
566 			return -EINVAL;
567 		}
568 		break;
569 	case 0:
570 		output_param = 'e';
571 	}
572 
573 	ret = 0;
574 
575 	/* Default is: show output of CPU 0 only */
576 	if (bitmask_isallclear(cpus_chosen))
577 		bitmask_setbit(cpus_chosen, 0);
578 
579 	switch (output_param) {
580 	case -1:
581 		printf(_("You can't specify more than one --cpu parameter and/or\n"
582 		       "more than one output-specific argument\n"));
583 		return -EINVAL;
584 	case '?':
585 		printf(_("invalid or unknown argument\n"));
586 		return -EINVAL;
587 	case 'o':
588 		proc_cpufreq_output();
589 		return EXIT_SUCCESS;
590 	}
591 
592 	for (cpu = bitmask_first(cpus_chosen);
593 	     cpu <= bitmask_last(cpus_chosen); cpu++) {
594 
595 		if (!bitmask_isbitset(cpus_chosen, cpu))
596 			continue;
597 
598 		printf(_("analyzing CPU %d:\n"), cpu);
599 
600 		if (sysfs_is_cpu_online(cpu) != 1) {
601 			printf(_(" *is offline\n"));
602 			printf("\n");
603 			continue;
604 		}
605 
606 		switch (output_param) {
607 		case 'b':
608 			get_boost_mode(cpu);
609 			break;
610 		case 'e':
611 			debug_output_one(cpu);
612 			break;
613 		case 'a':
614 			ret = get_affected_cpus(cpu);
615 			break;
616 		case 'r':
617 			ret = get_related_cpus(cpu);
618 			break;
619 		case 'g':
620 			ret = get_available_governors(cpu);
621 			break;
622 		case 'p':
623 			ret = get_policy(cpu);
624 			break;
625 		case 'd':
626 			ret = get_driver(cpu);
627 			break;
628 		case 'l':
629 			ret = get_hardware_limits(cpu, human);
630 			break;
631 		case 'w':
632 			ret = get_freq_hardware(cpu, human);
633 			break;
634 		case 'f':
635 			ret = get_freq_kernel(cpu, human);
636 			break;
637 		case 's':
638 			ret = get_freq_stats(cpu, human);
639 			break;
640 		case 'y':
641 			ret = get_latency(cpu, human);
642 			break;
643 		}
644 		if (ret)
645 			return ret;
646 	}
647 	return ret;
648 }
649