2 * turbostat -- show CPU frequency and C-state residency
3 * on modern Intel turbo-capable processors.
5 * Copyright (c) 2010, Intel Corporation.
6 * Len Brown <len.brown@intel.com>
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.
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
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.
24 #include <sys/types.h>
27 #include <sys/resource.h>
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 */
49 char *proc_stat
= "/proc/stat";
50 unsigned int interval_sec
= 5; /* set with -i interval_sec */
51 unsigned int verbose
; /* set with -v */
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
;
64 unsigned int show_pkg
;
65 unsigned int show_core
;
66 unsigned int show_cpu
;
68 int aperf_mperf_unstable
;
71 int need_reinitialize
;
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 */
91 struct counters
*next
;
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
;
102 unsigned long long get_msr(int cpu
, off_t offset
)
105 unsigned long long msr
;
109 sprintf(pathname
, "/dev/cpu/%d/msr", cpu
);
110 fd
= open(pathname
, O_RDONLY
);
113 need_reinitialize
= 1;
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
);
128 void print_header(void)
131 fprintf(stderr
, "pkg ");
133 fprintf(stderr
, "core");
135 fprintf(stderr
, " CPU");
137 fprintf(stderr
, " %%c0 ");
139 fprintf(stderr
, " GHz");
140 fprintf(stderr
, " TSC");
142 fprintf(stderr
, " %%c1 ");
144 fprintf(stderr
, " %%c3 ");
146 fprintf(stderr
, " %%c6 ");
148 fprintf(stderr
, " %%c7 ");
150 fprintf(stderr
, " %%pc2 ");
152 fprintf(stderr
, " %%pc3 ");
154 fprintf(stderr
, " %%pc6 ");
156 fprintf(stderr
, " %%pc7 ");
157 if (extra_msr_offset
)
158 fprintf(stderr
, " MSR 0x%x ", extra_msr_offset
);
163 void dump_cnt(struct counters
*cnt
)
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
);
180 void dump_list(struct counters
*cnt
)
182 printf("dump_list 0x%p\n", cnt
);
184 for (; cnt
; cnt
= cnt
->next
)
188 void print_cnt(struct counters
*p
)
190 double interval_float
;
192 interval_float
= tv_delta
.tv_sec
+ tv_delta
.tv_usec
/1000000.0;
194 /* topology columns, print blanks on 1st (average) line */
195 if (p
== cnt_average
) {
197 fprintf(stderr
, " ");
199 fprintf(stderr
, " ");
201 fprintf(stderr
, " ");
204 fprintf(stderr
, "%4d", p
->pkg
);
206 fprintf(stderr
, "%4d", p
->core
);
208 fprintf(stderr
, "%4d", p
->cpu
);
212 if (do_nhm_cstates
) {
214 fprintf(stderr
, "%7.2f", 100.0 * p
->mperf
/p
->tsc
);
216 fprintf(stderr
, " ****");
221 if (!aperf_mperf_unstable
) {
222 fprintf(stderr
, "%5.2f",
223 1.0 * p
->tsc
/ units
* p
->aperf
/
224 p
->mperf
/ interval_float
);
226 if (p
->aperf
> p
->tsc
|| p
->mperf
> p
->tsc
) {
227 fprintf(stderr
, " ****");
229 fprintf(stderr
, "%4.1f*",
232 p
->mperf
/ interval_float
);
238 fprintf(stderr
, "%5.2f", 1.0 * p
->tsc
/units
/interval_float
);
240 if (do_nhm_cstates
) {
242 fprintf(stderr
, "%7.2f", 100.0 * p
->c1
/p
->tsc
);
244 fprintf(stderr
, " ****");
247 fprintf(stderr
, "%7.2f", 100.0 * p
->c3
/p
->tsc
);
249 fprintf(stderr
, "%7.2f", 100.0 * p
->c6
/p
->tsc
);
251 fprintf(stderr
, "%7.2f", 100.0 * p
->c7
/p
->tsc
);
253 fprintf(stderr
, "%7.2f", 100.0 * p
->pc2
/p
->tsc
);
255 fprintf(stderr
, "%7.2f", 100.0 * p
->pc3
/p
->tsc
);
257 fprintf(stderr
, "%7.2f", 100.0 * p
->pc6
/p
->tsc
);
259 fprintf(stderr
, "%7.2f", 100.0 * p
->pc7
/p
->tsc
);
260 if (extra_msr_offset
)
261 fprintf(stderr
, " 0x%016llx", p
->extra_msr
);
265 void print_counters(struct counters
*counters
)
267 struct counters
*cnt
;
272 print_cnt(cnt_average
);
274 for (cnt
= counters
; cnt
!= NULL
; cnt
= cnt
->next
)
279 #define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
281 int compute_delta(struct counters
*after
,
282 struct counters
*before
, struct counters
*delta
)
287 skip_c0
= skip_c1
= 0;
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
);
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
);
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");
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
);
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
);
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
);
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
);
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
);
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
);
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
);
348 perf_err
= SUBTRACT_COUNTER(after
->aperf
, before
->aperf
, delta
->aperf
);
350 fprintf(stderr
, "cpu%d aperf counter went backwards %llX to %llX\n",
351 before
->cpu
, before
->aperf
, after
->aperf
);
353 perf_err
|= SUBTRACT_COUNTER(after
->mperf
, before
->mperf
, delta
->mperf
);
355 fprintf(stderr
, "cpu%d mperf counter went backwards %llX to %llX\n",
356 before
->cpu
, before
->mperf
, after
->mperf
);
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");
364 aperf_mperf_unstable
= 1;
367 * mperf delta is likely a huge "positive" number
368 * can not use it for calculating c0 time
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.
379 if (delta
->mperf
> delta
->tsc
)
381 else /* normal case, derive c1 */
382 delta
->c1
= delta
->tsc
- delta
->mperf
383 - delta
->c3
- delta
->c6
- delta
->c7
;
385 if (delta
->mperf
== 0)
386 delta
->mperf
= 1; /* divide by 0 protection */
389 * for "extra msr", just copy the latest w/o subtracting
391 delta
->extra_msr
= after
->extra_msr
;
393 fprintf(stderr
, "ERROR cpu%d before:\n", before
->cpu
);
395 fprintf(stderr
, "ERROR cpu%d after:\n", before
->cpu
);
403 void compute_average(struct counters
*delta
, struct counters
*avg
)
405 struct counters
*sum
;
407 sum
= calloc(1, sizeof(struct counters
));
409 perror("calloc sum");
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
;
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
;
441 void get_counters(struct counters
*cnt
)
443 for ( ; cnt
; cnt
= cnt
->next
) {
444 cnt
->tsc
= get_msr(cnt
->cpu
, MSR_TSC
);
446 cnt
->c3
= get_msr(cnt
->cpu
, MSR_CORE_C3_RESIDENCY
);
448 cnt
->c6
= get_msr(cnt
->cpu
, MSR_CORE_C6_RESIDENCY
);
450 cnt
->c7
= get_msr(cnt
->cpu
, MSR_CORE_C7_RESIDENCY
);
452 cnt
->aperf
= get_msr(cnt
->cpu
, MSR_APERF
);
454 cnt
->mperf
= get_msr(cnt
->cpu
, MSR_MPERF
);
456 cnt
->pc2
= get_msr(cnt
->cpu
, MSR_PKG_C2_RESIDENCY
);
458 cnt
->pc3
= get_msr(cnt
->cpu
, MSR_PKG_C3_RESIDENCY
);
460 cnt
->pc6
= get_msr(cnt
->cpu
, MSR_PKG_C6_RESIDENCY
);
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
);
468 void print_nehalem_info(void)
470 unsigned long long msr
;
473 if (!do_nehalem_platform_info
)
476 msr
= get_msr(0, MSR_NEHALEM_PLATFORM_INFO
);
478 ratio
= (msr
>> 40) & 0xFF;
479 fprintf(stderr
, "%d * %.0f = %.0f MHz max efficiency\n",
480 ratio
, bclk
, ratio
* bclk
);
482 ratio
= (msr
>> 8) & 0xFF;
483 fprintf(stderr
, "%d * %.0f = %.0f MHz TSC frequency\n",
484 ratio
, bclk
, ratio
* bclk
);
487 fprintf(stderr
, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr
);
489 if (!do_nehalem_turbo_ratio_limit
)
492 msr
= get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT
);
494 ratio
= (msr
>> 24) & 0xFF;
496 fprintf(stderr
, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
497 ratio
, bclk
, ratio
* bclk
);
499 ratio
= (msr
>> 16) & 0xFF;
501 fprintf(stderr
, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
502 ratio
, bclk
, ratio
* bclk
);
504 ratio
= (msr
>> 8) & 0xFF;
506 fprintf(stderr
, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
507 ratio
, bclk
, ratio
* bclk
);
509 ratio
= (msr
>> 0) & 0xFF;
511 fprintf(stderr
, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
512 ratio
, bclk
, ratio
* bclk
);
516 void free_counter_list(struct counters
*list
)
520 for (p
= list
; p
; ) {
521 struct counters
*free_me
;
529 void free_all_counters(void)
531 free_counter_list(cnt_even
);
534 free_counter_list(cnt_odd
);
537 free_counter_list(cnt_delta
);
540 free_counter_list(cnt_average
);
544 void insert_counters(struct counters
**list
,
545 struct counters
*new)
547 struct counters
*prev
;
558 show_cpu
= 1; /* there is more than one CPU */
561 * insert on front of list.
562 * It is sorted by ascending package#, core#, cpu#
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
))) {
574 while (prev
->next
&& (prev
->next
->pkg
< new->pkg
)) {
576 show_pkg
= 1; /* there is more than 1 package */
579 while (prev
->next
&& (prev
->next
->pkg
== new->pkg
)
580 && (prev
->next
->core
< new->core
)) {
582 show_core
= 1; /* there is more than 1 core */
585 while (prev
->next
&& (prev
->next
->pkg
== new->pkg
)
586 && (prev
->next
->core
== new->core
)
587 && (prev
->next
->cpu
< new->cpu
)) {
592 * insert after "prev"
594 new->next
= prev
->next
;
598 void alloc_new_counters(int pkg
, int core
, int cpu
)
600 struct counters
*new;
603 printf("pkg%d core%d, cpu%d\n", pkg
, core
, cpu
);
605 new = (struct counters
*)calloc(1, sizeof(struct counters
));
613 insert_counters(&cnt_odd
, new);
615 new = (struct counters
*)calloc(1,
616 sizeof(struct counters
));
624 insert_counters(&cnt_even
, new);
626 new = (struct counters
*)calloc(1, sizeof(struct counters
));
634 insert_counters(&cnt_delta
, new);
636 new = (struct counters
*)calloc(1, sizeof(struct counters
));
647 int get_physical_package_id(int cpu
)
653 sprintf(path
, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu
);
654 filep
= fopen(path
, "r");
659 fscanf(filep
, "%d", &pkg
);
664 int get_core_id(int cpu
)
670 sprintf(path
, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu
);
671 filep
= fopen(path
, "r");
676 fscanf(filep
, "%d", &core
);
682 * run func(index, cpu) on every cpu in /proc/stat
685 int for_all_cpus(void (func
)(int, int, int))
691 fp
= fopen(proc_stat
, "r");
697 retval
= fscanf(fp
, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
699 perror("/proc/stat format");
703 for (cpu_count
= 0; ; cpu_count
++) {
706 retval
= fscanf(fp
, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu
);
710 func(get_physical_package_id(cpu
), get_core_id(cpu
), cpu
);
716 void re_initialize(void)
718 printf("turbostat: topology changed, re-initializing.\n");
720 num_cpus
= for_all_cpus(alloc_new_counters
);
721 need_reinitialize
= 0;
722 printf("num_cpus is now %d\n", num_cpus
);
725 void dummy(int pkg
, int core
, int cpu
) { return; }
727 * check to see if a cpu came on-line
729 void verify_num_cpus(void)
733 new_num_cpus
= for_all_cpus(dummy
);
735 if (new_num_cpus
!= num_cpus
) {
737 printf("num_cpus was %d, is now %d\n",
738 num_cpus
, new_num_cpus
);
739 need_reinitialize
= 1;
743 void turbostat_loop()
746 get_counters(cnt_even
);
747 gettimeofday(&tv_even
, (struct timezone
*)NULL
);
751 if (need_reinitialize
) {
756 get_counters(cnt_odd
);
757 gettimeofday(&tv_odd
, (struct timezone
*)NULL
);
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
) {
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
);
781 if (stat("/dev/cpu/0/msr", &sb
)) {
782 fprintf(stderr
, "no /dev/cpu/0/msr\n");
783 fprintf(stderr
, "Try \"# modprobe msr\"\n");
788 void check_super_user()
791 fprintf(stderr
, "must be root\n");
796 int has_nehalem_turbo_ratio_limit(unsigned int family
, unsigned int 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 */
811 case 0x2D: /* SNB Xeon */
813 case 0x2E: /* Nehalem-EX Xeon - Beckton */
814 case 0x2F: /* Westmere-EX Xeon - Eagleton */
820 int is_snb(unsigned int family
, unsigned int model
)
833 double discover_bclk(unsigned int family
, unsigned int model
)
835 if (is_snb(family
, model
))
843 unsigned int eax
, ebx
, ecx
, edx
, max_level
;
844 unsigned int fms
, family
, model
, stepping
;
846 eax
= ebx
= ecx
= edx
= 0;
848 asm("cpuid" : "=a" (max_level
), "=b" (ebx
), "=c" (ecx
), "=d" (edx
) : "a" (0));
850 if (ebx
== 0x756e6547 && edx
== 0x49656e69 && ecx
== 0x6c65746e)
854 fprintf(stderr
, "%.4s%.4s%.4s ",
855 (char *)&ebx
, (char *)&edx
, (char *)&ecx
);
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;
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
);
868 if (!(edx
& (1 << 5))) {
869 fprintf(stderr
, "CPUID: no MSR\n");
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.
879 asm("cpuid" : "=a" (max_level
), "=b" (ebx
), "=c" (ecx
), "=d" (edx
) : "a" (0x80000000));
881 if (max_level
< 0x80000007) {
882 fprintf(stderr
, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level
);
887 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
888 * this check is valid for both Intel and AMD
890 asm("cpuid" : "=a" (eax
), "=b" (ebx
), "=c" (ecx
), "=d" (edx
) : "a" (0x80000007));
891 has_invariant_tsc
= edx
& (1 << 8);
893 if (!has_invariant_tsc
) {
894 fprintf(stderr
, "No invariant TSC\n");
899 * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
900 * this check is valid for both Intel and AMD
903 asm("cpuid" : "=a" (eax
), "=b" (ebx
), "=c" (ecx
), "=d" (edx
) : "a" (0x6));
904 has_aperf
= ecx
& (1 << 0);
906 fprintf(stderr
, "No APERF MSR\n");
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
);
915 do_nehalem_turbo_ratio_limit
= has_nehalem_turbo_ratio_limit(family
, model
);
921 fprintf(stderr
, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
928 * in /dev/cpu/ return success for names that are numbers
929 * ie. filter out ".", "..", "microcode".
931 int dir_filter(const struct dirent
*dirp
)
933 if (isdigit(dirp
->d_name
[0]))
939 int open_dev_cpu_msr(int dummy1
)
944 void turbostat_init()
951 num_cpus
= for_all_cpus(alloc_new_counters
);
954 print_nehalem_info();
957 int fork_it(char **argv
)
961 get_counters(cnt_even
);
962 gettimeofday(&tv_even
, (struct timezone
*)NULL
);
967 execvp(argv
[0], argv
);
972 if (child_pid
== -1) {
977 signal(SIGINT
, SIG_IGN
);
978 signal(SIGQUIT
, SIG_IGN
);
979 if (waitpid(child_pid
, &status
, 0) == -1) {
984 get_counters(cnt_odd
);
985 gettimeofday(&tv_odd
, (struct timezone
*)NULL
);
986 retval
= compute_delta(cnt_odd
, cnt_even
, cnt_delta
);
988 timersub(&tv_odd
, &tv_even
, &tv_delta
);
989 compute_average(cnt_delta
, cnt_average
);
991 print_counters(cnt_delta
);
993 fprintf(stderr
, "%.6f sec\n", tv_delta
.tv_sec
+ tv_delta
.tv_usec
/1000000.0);
998 void cmdline(int argc
, char **argv
)
1004 while ((opt
= getopt(argc
, argv
, "+vi:M:")) != -1) {
1010 interval_sec
= atoi(optarg
);
1013 sscanf(optarg
, "%x", &extra_msr_offset
);
1015 fprintf(stderr
, "MSR 0x%X\n", extra_msr_offset
);
1023 int main(int argc
, char **argv
)
1025 cmdline(argc
, argv
);
1028 fprintf(stderr
, "turbostat Dec 6, 2010"
1029 " - Len Brown <lenb@kernel.org>\n");
1031 fprintf(stderr
, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");
1036 * if any params left, it must be a command to fork
1039 return fork_it(argv
+ optind
);