GNU Linux-libre 4.9.314-gnu1
[releases.git] / tools / power / cpupower / utils / cpufreq-info.c
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 }