Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/tools/power/x86/turbostat/turbostat.c
10821 views
1
/*
2
* turbostat -- show CPU frequency and C-state residency
3
* on modern Intel turbo-capable processors.
4
*
5
* Copyright (c) 2010, Intel Corporation.
6
* Len Brown <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or modify it
9
* under the terms and conditions of the GNU General Public License,
10
* version 2, as published by the Free Software Foundation.
11
*
12
* This program is distributed in the hope it will be useful, but WITHOUT
13
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
* more details.
16
*
17
* You should have received a copy of the GNU General Public License along with
18
* this program; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20
*/
21
22
#include <stdio.h>
23
#include <unistd.h>
24
#include <sys/types.h>
25
#include <sys/wait.h>
26
#include <sys/stat.h>
27
#include <sys/resource.h>
28
#include <fcntl.h>
29
#include <signal.h>
30
#include <sys/time.h>
31
#include <stdlib.h>
32
#include <dirent.h>
33
#include <string.h>
34
#include <ctype.h>
35
36
#define MSR_TSC 0x10
37
#define MSR_NEHALEM_PLATFORM_INFO 0xCE
38
#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
39
#define MSR_APERF 0xE8
40
#define MSR_MPERF 0xE7
41
#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */
42
#define MSR_PKG_C3_RESIDENCY 0x3F8
43
#define MSR_PKG_C6_RESIDENCY 0x3F9
44
#define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */
45
#define MSR_CORE_C3_RESIDENCY 0x3FC
46
#define MSR_CORE_C6_RESIDENCY 0x3FD
47
#define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */
48
49
char *proc_stat = "/proc/stat";
50
unsigned int interval_sec = 5; /* set with -i interval_sec */
51
unsigned int verbose; /* set with -v */
52
unsigned int skip_c0;
53
unsigned int skip_c1;
54
unsigned int do_nhm_cstates;
55
unsigned int do_snb_cstates;
56
unsigned int has_aperf;
57
unsigned int units = 1000000000; /* Ghz etc */
58
unsigned int genuine_intel;
59
unsigned int has_invariant_tsc;
60
unsigned int do_nehalem_platform_info;
61
unsigned int do_nehalem_turbo_ratio_limit;
62
unsigned int extra_msr_offset;
63
double bclk;
64
unsigned int show_pkg;
65
unsigned int show_core;
66
unsigned int show_cpu;
67
68
int aperf_mperf_unstable;
69
int backwards_count;
70
char *progname;
71
int need_reinitialize;
72
73
int num_cpus;
74
75
struct counters {
76
unsigned long long tsc; /* per thread */
77
unsigned long long aperf; /* per thread */
78
unsigned long long mperf; /* per thread */
79
unsigned long long c1; /* per thread (calculated) */
80
unsigned long long c3; /* per core */
81
unsigned long long c6; /* per core */
82
unsigned long long c7; /* per core */
83
unsigned long long pc2; /* per package */
84
unsigned long long pc3; /* per package */
85
unsigned long long pc6; /* per package */
86
unsigned long long pc7; /* per package */
87
unsigned long long extra_msr; /* per thread */
88
int pkg;
89
int core;
90
int cpu;
91
struct counters *next;
92
};
93
94
struct counters *cnt_even;
95
struct counters *cnt_odd;
96
struct counters *cnt_delta;
97
struct counters *cnt_average;
98
struct timeval tv_even;
99
struct timeval tv_odd;
100
struct timeval tv_delta;
101
102
unsigned long long get_msr(int cpu, off_t offset)
103
{
104
ssize_t retval;
105
unsigned long long msr;
106
char pathname[32];
107
int fd;
108
109
sprintf(pathname, "/dev/cpu/%d/msr", cpu);
110
fd = open(pathname, O_RDONLY);
111
if (fd < 0) {
112
perror(pathname);
113
need_reinitialize = 1;
114
return 0;
115
}
116
117
retval = pread(fd, &msr, sizeof msr, offset);
118
if (retval != sizeof msr) {
119
fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",
120
cpu, offset, retval);
121
exit(-2);
122
}
123
124
close(fd);
125
return msr;
126
}
127
128
void print_header(void)
129
{
130
if (show_pkg)
131
fprintf(stderr, "pkg ");
132
if (show_core)
133
fprintf(stderr, "core");
134
if (show_cpu)
135
fprintf(stderr, " CPU");
136
if (do_nhm_cstates)
137
fprintf(stderr, " %%c0 ");
138
if (has_aperf)
139
fprintf(stderr, " GHz");
140
fprintf(stderr, " TSC");
141
if (do_nhm_cstates)
142
fprintf(stderr, " %%c1 ");
143
if (do_nhm_cstates)
144
fprintf(stderr, " %%c3 ");
145
if (do_nhm_cstates)
146
fprintf(stderr, " %%c6 ");
147
if (do_snb_cstates)
148
fprintf(stderr, " %%c7 ");
149
if (do_snb_cstates)
150
fprintf(stderr, " %%pc2 ");
151
if (do_nhm_cstates)
152
fprintf(stderr, " %%pc3 ");
153
if (do_nhm_cstates)
154
fprintf(stderr, " %%pc6 ");
155
if (do_snb_cstates)
156
fprintf(stderr, " %%pc7 ");
157
if (extra_msr_offset)
158
fprintf(stderr, " MSR 0x%x ", extra_msr_offset);
159
160
putc('\n', stderr);
161
}
162
163
void dump_cnt(struct counters *cnt)
164
{
165
fprintf(stderr, "package: %d ", cnt->pkg);
166
fprintf(stderr, "core:: %d ", cnt->core);
167
fprintf(stderr, "CPU: %d ", cnt->cpu);
168
fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
169
fprintf(stderr, "c3: %016llX\n", cnt->c3);
170
fprintf(stderr, "c6: %016llX\n", cnt->c6);
171
fprintf(stderr, "c7: %016llX\n", cnt->c7);
172
fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
173
fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
174
fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
175
fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
176
fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
177
fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
178
}
179
180
void dump_list(struct counters *cnt)
181
{
182
printf("dump_list 0x%p\n", cnt);
183
184
for (; cnt; cnt = cnt->next)
185
dump_cnt(cnt);
186
}
187
188
void print_cnt(struct counters *p)
189
{
190
double interval_float;
191
192
interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
193
194
/* topology columns, print blanks on 1st (average) line */
195
if (p == cnt_average) {
196
if (show_pkg)
197
fprintf(stderr, " ");
198
if (show_core)
199
fprintf(stderr, " ");
200
if (show_cpu)
201
fprintf(stderr, " ");
202
} else {
203
if (show_pkg)
204
fprintf(stderr, "%4d", p->pkg);
205
if (show_core)
206
fprintf(stderr, "%4d", p->core);
207
if (show_cpu)
208
fprintf(stderr, "%4d", p->cpu);
209
}
210
211
/* %c0 */
212
if (do_nhm_cstates) {
213
if (!skip_c0)
214
fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc);
215
else
216
fprintf(stderr, " ****");
217
}
218
219
/* GHz */
220
if (has_aperf) {
221
if (!aperf_mperf_unstable) {
222
fprintf(stderr, "%5.2f",
223
1.0 * p->tsc / units * p->aperf /
224
p->mperf / interval_float);
225
} else {
226
if (p->aperf > p->tsc || p->mperf > p->tsc) {
227
fprintf(stderr, " ****");
228
} else {
229
fprintf(stderr, "%4.1f*",
230
1.0 * p->tsc /
231
units * p->aperf /
232
p->mperf / interval_float);
233
}
234
}
235
}
236
237
/* TSC */
238
fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float);
239
240
if (do_nhm_cstates) {
241
if (!skip_c1)
242
fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);
243
else
244
fprintf(stderr, " ****");
245
}
246
if (do_nhm_cstates)
247
fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc);
248
if (do_nhm_cstates)
249
fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc);
250
if (do_snb_cstates)
251
fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc);
252
if (do_snb_cstates)
253
fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc);
254
if (do_nhm_cstates)
255
fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc);
256
if (do_nhm_cstates)
257
fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc);
258
if (do_snb_cstates)
259
fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc);
260
if (extra_msr_offset)
261
fprintf(stderr, " 0x%016llx", p->extra_msr);
262
putc('\n', stderr);
263
}
264
265
void print_counters(struct counters *counters)
266
{
267
struct counters *cnt;
268
269
print_header();
270
271
if (num_cpus > 1)
272
print_cnt(cnt_average);
273
274
for (cnt = counters; cnt != NULL; cnt = cnt->next)
275
print_cnt(cnt);
276
277
}
278
279
#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
280
281
int compute_delta(struct counters *after,
282
struct counters *before, struct counters *delta)
283
{
284
int errors = 0;
285
int perf_err = 0;
286
287
skip_c0 = skip_c1 = 0;
288
289
for ( ; after && before && delta;
290
after = after->next, before = before->next, delta = delta->next) {
291
if (before->cpu != after->cpu) {
292
printf("cpu configuration changed: %d != %d\n",
293
before->cpu, after->cpu);
294
return -1;
295
}
296
297
if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) {
298
fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n",
299
before->cpu, before->tsc, after->tsc);
300
errors++;
301
}
302
/* check for TSC < 1 Mcycles over interval */
303
if (delta->tsc < (1000 * 1000)) {
304
fprintf(stderr, "Insanely slow TSC rate,"
305
" TSC stops in idle?\n");
306
fprintf(stderr, "You can disable all c-states"
307
" by booting with \"idle=poll\"\n");
308
fprintf(stderr, "or just the deep ones with"
309
" \"processor.max_cstate=1\"\n");
310
exit(-3);
311
}
312
if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) {
313
fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n",
314
before->cpu, before->c3, after->c3);
315
errors++;
316
}
317
if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) {
318
fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n",
319
before->cpu, before->c6, after->c6);
320
errors++;
321
}
322
if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) {
323
fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n",
324
before->cpu, before->c7, after->c7);
325
errors++;
326
}
327
if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) {
328
fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n",
329
before->cpu, before->pc2, after->pc2);
330
errors++;
331
}
332
if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) {
333
fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n",
334
before->cpu, before->pc3, after->pc3);
335
errors++;
336
}
337
if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) {
338
fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n",
339
before->cpu, before->pc6, after->pc6);
340
errors++;
341
}
342
if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) {
343
fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n",
344
before->cpu, before->pc7, after->pc7);
345
errors++;
346
}
347
348
perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf);
349
if (perf_err) {
350
fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n",
351
before->cpu, before->aperf, after->aperf);
352
}
353
perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf);
354
if (perf_err) {
355
fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n",
356
before->cpu, before->mperf, after->mperf);
357
}
358
if (perf_err) {
359
if (!aperf_mperf_unstable) {
360
fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
361
fprintf(stderr, "* Frequency results do not cover entire interval *\n");
362
fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
363
364
aperf_mperf_unstable = 1;
365
}
366
/*
367
* mperf delta is likely a huge "positive" number
368
* can not use it for calculating c0 time
369
*/
370
skip_c0 = 1;
371
skip_c1 = 1;
372
}
373
374
/*
375
* As mperf and tsc collection are not atomic,
376
* it is possible for mperf's non-halted cycles
377
* to exceed TSC's all cycles: show c1 = 0% in that case.
378
*/
379
if (delta->mperf > delta->tsc)
380
delta->c1 = 0;
381
else /* normal case, derive c1 */
382
delta->c1 = delta->tsc - delta->mperf
383
- delta->c3 - delta->c6 - delta->c7;
384
385
if (delta->mperf == 0)
386
delta->mperf = 1; /* divide by 0 protection */
387
388
/*
389
* for "extra msr", just copy the latest w/o subtracting
390
*/
391
delta->extra_msr = after->extra_msr;
392
if (errors) {
393
fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
394
dump_cnt(before);
395
fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
396
dump_cnt(after);
397
errors = 0;
398
}
399
}
400
return 0;
401
}
402
403
void compute_average(struct counters *delta, struct counters *avg)
404
{
405
struct counters *sum;
406
407
sum = calloc(1, sizeof(struct counters));
408
if (sum == NULL) {
409
perror("calloc sum");
410
exit(1);
411
}
412
413
for (; delta; delta = delta->next) {
414
sum->tsc += delta->tsc;
415
sum->c1 += delta->c1;
416
sum->c3 += delta->c3;
417
sum->c6 += delta->c6;
418
sum->c7 += delta->c7;
419
sum->aperf += delta->aperf;
420
sum->mperf += delta->mperf;
421
sum->pc2 += delta->pc2;
422
sum->pc3 += delta->pc3;
423
sum->pc6 += delta->pc6;
424
sum->pc7 += delta->pc7;
425
}
426
avg->tsc = sum->tsc/num_cpus;
427
avg->c1 = sum->c1/num_cpus;
428
avg->c3 = sum->c3/num_cpus;
429
avg->c6 = sum->c6/num_cpus;
430
avg->c7 = sum->c7/num_cpus;
431
avg->aperf = sum->aperf/num_cpus;
432
avg->mperf = sum->mperf/num_cpus;
433
avg->pc2 = sum->pc2/num_cpus;
434
avg->pc3 = sum->pc3/num_cpus;
435
avg->pc6 = sum->pc6/num_cpus;
436
avg->pc7 = sum->pc7/num_cpus;
437
438
free(sum);
439
}
440
441
void get_counters(struct counters *cnt)
442
{
443
for ( ; cnt; cnt = cnt->next) {
444
cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
445
if (do_nhm_cstates)
446
cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
447
if (do_nhm_cstates)
448
cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
449
if (do_snb_cstates)
450
cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
451
if (has_aperf)
452
cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
453
if (has_aperf)
454
cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
455
if (do_snb_cstates)
456
cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
457
if (do_nhm_cstates)
458
cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
459
if (do_nhm_cstates)
460
cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
461
if (do_snb_cstates)
462
cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
463
if (extra_msr_offset)
464
cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
465
}
466
}
467
468
void print_nehalem_info(void)
469
{
470
unsigned long long msr;
471
unsigned int ratio;
472
473
if (!do_nehalem_platform_info)
474
return;
475
476
msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO);
477
478
ratio = (msr >> 40) & 0xFF;
479
fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
480
ratio, bclk, ratio * bclk);
481
482
ratio = (msr >> 8) & 0xFF;
483
fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",
484
ratio, bclk, ratio * bclk);
485
486
if (verbose > 1)
487
fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
488
489
if (!do_nehalem_turbo_ratio_limit)
490
return;
491
492
msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT);
493
494
ratio = (msr >> 24) & 0xFF;
495
if (ratio)
496
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
497
ratio, bclk, ratio * bclk);
498
499
ratio = (msr >> 16) & 0xFF;
500
if (ratio)
501
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
502
ratio, bclk, ratio * bclk);
503
504
ratio = (msr >> 8) & 0xFF;
505
if (ratio)
506
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
507
ratio, bclk, ratio * bclk);
508
509
ratio = (msr >> 0) & 0xFF;
510
if (ratio)
511
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
512
ratio, bclk, ratio * bclk);
513
514
}
515
516
void free_counter_list(struct counters *list)
517
{
518
struct counters *p;
519
520
for (p = list; p; ) {
521
struct counters *free_me;
522
523
free_me = p;
524
p = p->next;
525
free(free_me);
526
}
527
}
528
529
void free_all_counters(void)
530
{
531
free_counter_list(cnt_even);
532
cnt_even = NULL;
533
534
free_counter_list(cnt_odd);
535
cnt_odd = NULL;
536
537
free_counter_list(cnt_delta);
538
cnt_delta = NULL;
539
540
free_counter_list(cnt_average);
541
cnt_average = NULL;
542
}
543
544
void insert_counters(struct counters **list,
545
struct counters *new)
546
{
547
struct counters *prev;
548
549
/*
550
* list was empty
551
*/
552
if (*list == NULL) {
553
new->next = *list;
554
*list = new;
555
return;
556
}
557
558
show_cpu = 1; /* there is more than one CPU */
559
560
/*
561
* insert on front of list.
562
* It is sorted by ascending package#, core#, cpu#
563
*/
564
if (((*list)->pkg > new->pkg) ||
565
(((*list)->pkg == new->pkg) && ((*list)->core > new->core)) ||
566
(((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) {
567
new->next = *list;
568
*list = new;
569
return;
570
}
571
572
prev = *list;
573
574
while (prev->next && (prev->next->pkg < new->pkg)) {
575
prev = prev->next;
576
show_pkg = 1; /* there is more than 1 package */
577
}
578
579
while (prev->next && (prev->next->pkg == new->pkg)
580
&& (prev->next->core < new->core)) {
581
prev = prev->next;
582
show_core = 1; /* there is more than 1 core */
583
}
584
585
while (prev->next && (prev->next->pkg == new->pkg)
586
&& (prev->next->core == new->core)
587
&& (prev->next->cpu < new->cpu)) {
588
prev = prev->next;
589
}
590
591
/*
592
* insert after "prev"
593
*/
594
new->next = prev->next;
595
prev->next = new;
596
}
597
598
void alloc_new_counters(int pkg, int core, int cpu)
599
{
600
struct counters *new;
601
602
if (verbose > 1)
603
printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
604
605
new = (struct counters *)calloc(1, sizeof(struct counters));
606
if (new == NULL) {
607
perror("calloc");
608
exit(1);
609
}
610
new->pkg = pkg;
611
new->core = core;
612
new->cpu = cpu;
613
insert_counters(&cnt_odd, new);
614
615
new = (struct counters *)calloc(1,
616
sizeof(struct counters));
617
if (new == NULL) {
618
perror("calloc");
619
exit(1);
620
}
621
new->pkg = pkg;
622
new->core = core;
623
new->cpu = cpu;
624
insert_counters(&cnt_even, new);
625
626
new = (struct counters *)calloc(1, sizeof(struct counters));
627
if (new == NULL) {
628
perror("calloc");
629
exit(1);
630
}
631
new->pkg = pkg;
632
new->core = core;
633
new->cpu = cpu;
634
insert_counters(&cnt_delta, new);
635
636
new = (struct counters *)calloc(1, sizeof(struct counters));
637
if (new == NULL) {
638
perror("calloc");
639
exit(1);
640
}
641
new->pkg = pkg;
642
new->core = core;
643
new->cpu = cpu;
644
cnt_average = new;
645
}
646
647
int get_physical_package_id(int cpu)
648
{
649
char path[64];
650
FILE *filep;
651
int pkg;
652
653
sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
654
filep = fopen(path, "r");
655
if (filep == NULL) {
656
perror(path);
657
exit(1);
658
}
659
fscanf(filep, "%d", &pkg);
660
fclose(filep);
661
return pkg;
662
}
663
664
int get_core_id(int cpu)
665
{
666
char path[64];
667
FILE *filep;
668
int core;
669
670
sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
671
filep = fopen(path, "r");
672
if (filep == NULL) {
673
perror(path);
674
exit(1);
675
}
676
fscanf(filep, "%d", &core);
677
fclose(filep);
678
return core;
679
}
680
681
/*
682
* run func(index, cpu) on every cpu in /proc/stat
683
*/
684
685
int for_all_cpus(void (func)(int, int, int))
686
{
687
FILE *fp;
688
int cpu_count;
689
int retval;
690
691
fp = fopen(proc_stat, "r");
692
if (fp == NULL) {
693
perror(proc_stat);
694
exit(1);
695
}
696
697
retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
698
if (retval != 0) {
699
perror("/proc/stat format");
700
exit(1);
701
}
702
703
for (cpu_count = 0; ; cpu_count++) {
704
int cpu;
705
706
retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu);
707
if (retval != 1)
708
break;
709
710
func(get_physical_package_id(cpu), get_core_id(cpu), cpu);
711
}
712
fclose(fp);
713
return cpu_count;
714
}
715
716
void re_initialize(void)
717
{
718
printf("turbostat: topology changed, re-initializing.\n");
719
free_all_counters();
720
num_cpus = for_all_cpus(alloc_new_counters);
721
need_reinitialize = 0;
722
printf("num_cpus is now %d\n", num_cpus);
723
}
724
725
void dummy(int pkg, int core, int cpu) { return; }
726
/*
727
* check to see if a cpu came on-line
728
*/
729
void verify_num_cpus(void)
730
{
731
int new_num_cpus;
732
733
new_num_cpus = for_all_cpus(dummy);
734
735
if (new_num_cpus != num_cpus) {
736
if (verbose)
737
printf("num_cpus was %d, is now %d\n",
738
num_cpus, new_num_cpus);
739
need_reinitialize = 1;
740
}
741
}
742
743
void turbostat_loop()
744
{
745
restart:
746
get_counters(cnt_even);
747
gettimeofday(&tv_even, (struct timezone *)NULL);
748
749
while (1) {
750
verify_num_cpus();
751
if (need_reinitialize) {
752
re_initialize();
753
goto restart;
754
}
755
sleep(interval_sec);
756
get_counters(cnt_odd);
757
gettimeofday(&tv_odd, (struct timezone *)NULL);
758
759
compute_delta(cnt_odd, cnt_even, cnt_delta);
760
timersub(&tv_odd, &tv_even, &tv_delta);
761
compute_average(cnt_delta, cnt_average);
762
print_counters(cnt_delta);
763
if (need_reinitialize) {
764
re_initialize();
765
goto restart;
766
}
767
sleep(interval_sec);
768
get_counters(cnt_even);
769
gettimeofday(&tv_even, (struct timezone *)NULL);
770
compute_delta(cnt_even, cnt_odd, cnt_delta);
771
timersub(&tv_even, &tv_odd, &tv_delta);
772
compute_average(cnt_delta, cnt_average);
773
print_counters(cnt_delta);
774
}
775
}
776
777
void check_dev_msr()
778
{
779
struct stat sb;
780
781
if (stat("/dev/cpu/0/msr", &sb)) {
782
fprintf(stderr, "no /dev/cpu/0/msr\n");
783
fprintf(stderr, "Try \"# modprobe msr\"\n");
784
exit(-5);
785
}
786
}
787
788
void check_super_user()
789
{
790
if (getuid() != 0) {
791
fprintf(stderr, "must be root\n");
792
exit(-6);
793
}
794
}
795
796
int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
797
{
798
if (!genuine_intel)
799
return 0;
800
801
if (family != 6)
802
return 0;
803
804
switch (model) {
805
case 0x1A: /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
806
case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
807
case 0x1F: /* Core i7 and i5 Processor - Nehalem */
808
case 0x25: /* Westmere Client - Clarkdale, Arrandale */
809
case 0x2C: /* Westmere EP - Gulftown */
810
case 0x2A: /* SNB */
811
case 0x2D: /* SNB Xeon */
812
return 1;
813
case 0x2E: /* Nehalem-EX Xeon - Beckton */
814
case 0x2F: /* Westmere-EX Xeon - Eagleton */
815
default:
816
return 0;
817
}
818
}
819
820
int is_snb(unsigned int family, unsigned int model)
821
{
822
if (!genuine_intel)
823
return 0;
824
825
switch (model) {
826
case 0x2A:
827
case 0x2D:
828
return 1;
829
}
830
return 0;
831
}
832
833
double discover_bclk(unsigned int family, unsigned int model)
834
{
835
if (is_snb(family, model))
836
return 100.00;
837
else
838
return 133.33;
839
}
840
841
void check_cpuid()
842
{
843
unsigned int eax, ebx, ecx, edx, max_level;
844
unsigned int fms, family, model, stepping;
845
846
eax = ebx = ecx = edx = 0;
847
848
asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0));
849
850
if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
851
genuine_intel = 1;
852
853
if (verbose)
854
fprintf(stderr, "%.4s%.4s%.4s ",
855
(char *)&ebx, (char *)&edx, (char *)&ecx);
856
857
asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
858
family = (fms >> 8) & 0xf;
859
model = (fms >> 4) & 0xf;
860
stepping = fms & 0xf;
861
if (family == 6 || family == 0xf)
862
model += ((fms >> 16) & 0xf) << 4;
863
864
if (verbose)
865
fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
866
max_level, family, model, stepping, family, model, stepping);
867
868
if (!(edx & (1 << 5))) {
869
fprintf(stderr, "CPUID: no MSR\n");
870
exit(1);
871
}
872
873
/*
874
* check max extended function levels of CPUID.
875
* This is needed to check for invariant TSC.
876
* This check is valid for both Intel and AMD.
877
*/
878
ebx = ecx = edx = 0;
879
asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000));
880
881
if (max_level < 0x80000007) {
882
fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level);
883
exit(1);
884
}
885
886
/*
887
* Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
888
* this check is valid for both Intel and AMD
889
*/
890
asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));
891
has_invariant_tsc = edx & (1 << 8);
892
893
if (!has_invariant_tsc) {
894
fprintf(stderr, "No invariant TSC\n");
895
exit(1);
896
}
897
898
/*
899
* APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
900
* this check is valid for both Intel and AMD
901
*/
902
903
asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
904
has_aperf = ecx & (1 << 0);
905
if (!has_aperf) {
906
fprintf(stderr, "No APERF MSR\n");
907
exit(1);
908
}
909
910
do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
911
do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
912
do_snb_cstates = is_snb(family, model);
913
bclk = discover_bclk(family, model);
914
915
do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
916
}
917
918
919
void usage()
920
{
921
fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
922
progname);
923
exit(1);
924
}
925
926
927
/*
928
* in /dev/cpu/ return success for names that are numbers
929
* ie. filter out ".", "..", "microcode".
930
*/
931
int dir_filter(const struct dirent *dirp)
932
{
933
if (isdigit(dirp->d_name[0]))
934
return 1;
935
else
936
return 0;
937
}
938
939
int open_dev_cpu_msr(int dummy1)
940
{
941
return 0;
942
}
943
944
void turbostat_init()
945
{
946
check_cpuid();
947
948
check_dev_msr();
949
check_super_user();
950
951
num_cpus = for_all_cpus(alloc_new_counters);
952
953
if (verbose)
954
print_nehalem_info();
955
}
956
957
int fork_it(char **argv)
958
{
959
int retval;
960
pid_t child_pid;
961
get_counters(cnt_even);
962
gettimeofday(&tv_even, (struct timezone *)NULL);
963
964
child_pid = fork();
965
if (!child_pid) {
966
/* child */
967
execvp(argv[0], argv);
968
} else {
969
int status;
970
971
/* parent */
972
if (child_pid == -1) {
973
perror("fork");
974
exit(1);
975
}
976
977
signal(SIGINT, SIG_IGN);
978
signal(SIGQUIT, SIG_IGN);
979
if (waitpid(child_pid, &status, 0) == -1) {
980
perror("wait");
981
exit(1);
982
}
983
}
984
get_counters(cnt_odd);
985
gettimeofday(&tv_odd, (struct timezone *)NULL);
986
retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
987
988
timersub(&tv_odd, &tv_even, &tv_delta);
989
compute_average(cnt_delta, cnt_average);
990
if (!retval)
991
print_counters(cnt_delta);
992
993
fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
994
995
return 0;
996
}
997
998
void cmdline(int argc, char **argv)
999
{
1000
int opt;
1001
1002
progname = argv[0];
1003
1004
while ((opt = getopt(argc, argv, "+vi:M:")) != -1) {
1005
switch (opt) {
1006
case 'v':
1007
verbose++;
1008
break;
1009
case 'i':
1010
interval_sec = atoi(optarg);
1011
break;
1012
case 'M':
1013
sscanf(optarg, "%x", &extra_msr_offset);
1014
if (verbose > 1)
1015
fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
1016
break;
1017
default:
1018
usage();
1019
}
1020
}
1021
}
1022
1023
int main(int argc, char **argv)
1024
{
1025
cmdline(argc, argv);
1026
1027
if (verbose > 1)
1028
fprintf(stderr, "turbostat Dec 6, 2010"
1029
" - Len Brown <[email protected]>\n");
1030
if (verbose > 1)
1031
fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");
1032
1033
turbostat_init();
1034
1035
/*
1036
* if any params left, it must be a command to fork
1037
*/
1038
if (argc - optind)
1039
return fork_it(argv + optind);
1040
else
1041
turbostat_loop();
1042
1043
return 0;
1044
}
1045
1046