1
2
3
4
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
22static 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
51 return ret + 1;
52}
53
54
55static 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
85static int no_rounding;
86static 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
125static 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
165
166static int get_boost_mode(unsigned int cpu)
167{
168 int support, active, b_states = 0, ret, pstate_no, i;
169
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
183
184
185
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
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
247static 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
379
380static 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
395
396static 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
410
411static 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
421
422static 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
433
434static 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
445
446static 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
464
465static 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
481
482static 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
498
499static 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
523
524static 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
538static struct option info_opts[] = {
539 { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
540 { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
541 { .name = "freq", .has_arg = no_argument, .flag = NULL, .val = 'f'},
542 { .name = "hwfreq", .has_arg = no_argument, .flag = NULL, .val = 'w'},
543 { .name = "hwlimits", .has_arg = no_argument, .flag = NULL, .val = 'l'},
544 { .name = "driver", .has_arg = no_argument, .flag = NULL, .val = 'd'},
545 { .name = "policy", .has_arg = no_argument, .flag = NULL, .val = 'p'},
546 { .name = "governors", .has_arg = no_argument, .flag = NULL, .val = 'g'},
547 { .name = "related-cpus", .has_arg = no_argument, .flag = NULL, .val = 'r'},
548 { .name = "affected-cpus",.has_arg = no_argument, .flag = NULL, .val = 'a'},
549 { .name = "stats", .has_arg = no_argument, .flag = NULL, .val = 's'},
550 { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
551 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
552 { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
553 { .name = "no-rounding", .has_arg = no_argument, .flag = NULL, .val = 'n'},
554 { },
555};
556
557int 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
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