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