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