aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2016-12-22 23:57:55 -0500
committerLen Brown <len.brown@intel.com>2016-12-24 15:16:10 -0500
commit388e9c8134be6bbc3751ba7072f5fa9bc8ecbe01 (patch)
treee43e0ee0818f20e82785fdcc659f2c4d776b02fc /tools
parent7268d407ad4c49fbd521fb2e2f675a447bfef472 (diff)
tools/power turbostat: Make extensible via the --add parameter
Create the "--add" parameter. This can be used to teach an existing turbostat binary about any number of any type of counter. turbostat(8) details the syntax for --add. Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/power/x86/turbostat/turbostat.822
-rw-r--r--tools/power/x86/turbostat/turbostat.c396
2 files changed, 409 insertions, 9 deletions
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index 492e84fbebfa..39f7daeb6fbd 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -25,6 +25,28 @@ Some information is not available on older processors.
25.SS Options 25.SS Options
26Options can be specified with a single or double '-', and only as much of the option 26Options can be specified with a single or double '-', and only as much of the option
27name as necessary to disambiguate it from others is necessary. Note that options are case-sensitive. 27name as necessary to disambiguate it from others is necessary. Note that options are case-sensitive.
28.PP
29\fB--add attributes\fP add column with counter having specified 'attributes'. The 'location' attribute is required, all others are optional.
30.nf
31 location: {\fBmsrDDD\fP | \fBmsr0xXXX\fP}
32 msrDDD is a decimal offset, eg. msr16
33 msr0xXXX is a hex offset, eg. msr0x10
34
35 scope: {\fBcpu\fP | \fBcore\fP | \fBpackage\fP}
36 sample and print the counter for every cpu, core, or package.
37 default: cpu
38
39 size: {\fBu32\fP | \fBu64\fP }
40 MSRs are read as 64-bits, u32 truncates the displayed value to 32-bits.
41 default: u64
42
43 format: {\fBraw\fP | \fBdelta\fP | \fBpercent\fP}
44 'raw' shows the MSR contents in hex.
45 'delta' shows the difference in values during the measurement interval.
46 'percent' shows the delta as a percentage of the cycles elapsed.
47 default: delta
48.fi
49.PP
28\fB--Counter MSR#\fP shows the delta of the specified 64-bit MSR counter. 50\fB--Counter MSR#\fP shows the delta of the specified 64-bit MSR counter.
29.PP 51.PP
30\fB--counter MSR#\fP shows the delta of the specified 32-bit MSR counter. 52\fB--counter MSR#\fP shows the delta of the specified 32-bit MSR counter.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 3708386531f2..4490a776bbae 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -147,6 +147,12 @@ unsigned int has_hwp_pkg; /* IA32_HWP_REQUEST_PKG */
147 147
148#define MAX(a, b) ((a) > (b) ? (a) : (b)) 148#define MAX(a, b) ((a) > (b) ? (a) : (b))
149 149
150/*
151 * buffer size used by sscanf() for added column names
152 * Usually truncated to 7 characters, but also handles 18 columns for raw 64-bit counters
153 */
154#define NAME_BYTES 20
155
150int backwards_count; 156int backwards_count;
151char *progname; 157char *progname;
152 158
@@ -168,6 +174,7 @@ struct thread_data {
168 unsigned int flags; 174 unsigned int flags;
169#define CPU_IS_FIRST_THREAD_IN_CORE 0x2 175#define CPU_IS_FIRST_THREAD_IN_CORE 0x2
170#define CPU_IS_FIRST_CORE_IN_PACKAGE 0x4 176#define CPU_IS_FIRST_CORE_IN_PACKAGE 0x4
177 unsigned long long counter[1];
171} *thread_even, *thread_odd; 178} *thread_even, *thread_odd;
172 179
173struct core_data { 180struct core_data {
@@ -176,6 +183,7 @@ struct core_data {
176 unsigned long long c7; 183 unsigned long long c7;
177 unsigned int core_temp_c; 184 unsigned int core_temp_c;
178 unsigned int core_id; 185 unsigned int core_id;
186 unsigned long long counter[1];
179} *core_even, *core_odd; 187} *core_even, *core_odd;
180 188
181struct pkg_data { 189struct pkg_data {
@@ -200,7 +208,7 @@ struct pkg_data {
200 unsigned int rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */ 208 unsigned int rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */
201 unsigned int rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */ 209 unsigned int rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */
202 unsigned int pkg_temp_c; 210 unsigned int pkg_temp_c;
203 211 unsigned long long counter[1];
204} *package_even, *package_odd; 212} *package_even, *package_odd;
205 213
206#define ODD_COUNTERS thread_odd, core_odd, package_odd 214#define ODD_COUNTERS thread_odd, core_odd, package_odd
@@ -214,11 +222,33 @@ struct pkg_data {
214 (core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no)) 222 (core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no))
215#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no) 223#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
216 224
225enum counter_scope {SCOPE_CPU, SCOPE_CORE, SCOPE_PACKAGE};
226enum counter_type {COUNTER_CYCLES, COUNTER_SECONDS};
227enum counter_format {FORMAT_RAW, FORMAT_DELTA, FORMAT_PERCENT};
228
229struct msr_counter {
230 unsigned int msr_num;
231 char name[NAME_BYTES];
232 unsigned int width;
233 enum counter_type type;
234 enum counter_format format;
235 struct msr_counter *next;
236};
237
238struct sys_counters {
239 unsigned int thread_counter_bytes;
240 unsigned int core_counter_bytes;
241 unsigned int package_counter_bytes;
242 struct msr_counter *tp;
243 struct msr_counter *cp;
244 struct msr_counter *pp;
245} sys;
246
217struct system_summary { 247struct system_summary {
218 struct thread_data threads; 248 struct thread_data threads;
219 struct core_data cores; 249 struct core_data cores;
220 struct pkg_data packages; 250 struct pkg_data packages;
221} sum, average; 251} average;
222 252
223 253
224struct topo_params { 254struct topo_params {
@@ -320,12 +350,14 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
320/* 350/*
321 * Example Format w/ field column widths: 351 * Example Format w/ field column widths:
322 * 352 *
323 * Package Core CPU Avg_MHz Bzy_MHz TSC_MHz IRQ SMI Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp PkgTmp GFXMHz Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt 353 * Package Core CPU Avg_MHz Bzy_MHz TSC_MHz IRQ SMI Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 ThreadC CoreTmp CoreCnt PkgTmp GFXMHz Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt PkgCnt
324 * 12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 354 * 12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
325 */ 355 */
326 356
327void print_header(void) 357void print_header(void)
328{ 358{
359 struct msr_counter *mp;
360
329 if (show_pkg) 361 if (show_pkg)
330 outp += sprintf(outp, "\tPackage"); 362 outp += sprintf(outp, "\tPackage");
331 if (show_core) 363 if (show_core)
@@ -366,8 +398,31 @@ void print_header(void)
366 if (do_snb_cstates) 398 if (do_snb_cstates)
367 outp += sprintf(outp, "\tCPU%%c7"); 399 outp += sprintf(outp, "\tCPU%%c7");
368 400
401 for (mp = sys.tp; mp; mp = mp->next) {
402 if (mp->format == FORMAT_RAW) {
403 if (mp->width == 64)
404 outp += sprintf(outp, "\t%18.18s", mp->name);
405 else
406 outp += sprintf(outp, "\t%10.10s", mp->name);
407 } else {
408 outp += sprintf(outp, "\t%-7.7s", mp->name);
409 }
410 }
411
369 if (do_dts) 412 if (do_dts)
370 outp += sprintf(outp, "\tCoreTmp"); 413 outp += sprintf(outp, "\tCoreTmp");
414
415 for (mp = sys.cp; mp; mp = mp->next) {
416 if (mp->format == FORMAT_RAW) {
417 if (mp->width == 64)
418 outp += sprintf(outp, "\t%18.18s", mp->name);
419 else
420 outp += sprintf(outp, "\t%10.10s", mp->name);
421 } else {
422 outp += sprintf(outp, "\t%-7.7s", mp->name);
423 }
424 }
425
371 if (do_ptm) 426 if (do_ptm)
372 outp += sprintf(outp, "\tPkgTmp"); 427 outp += sprintf(outp, "\tPkgTmp");
373 428
@@ -425,13 +480,27 @@ void print_header(void)
425 if (do_rapl & RAPL_DRAM_PERF_STATUS) 480 if (do_rapl & RAPL_DRAM_PERF_STATUS)
426 outp += sprintf(outp, "\tRAM_%%"); 481 outp += sprintf(outp, "\tRAM_%%");
427 } 482 }
428 done: 483 for (mp = sys.pp; mp; mp = mp->next) {
484 if (mp->format == FORMAT_RAW) {
485 if (mp->width == 64)
486 outp += sprintf(outp, "\t%18.18s", mp->name);
487 else
488 outp += sprintf(outp, "\t%10.10s", mp->name);
489 } else {
490 outp += sprintf(outp, "\t%-7.7s", mp->name);
491 }
492 }
493
494done:
429 outp += sprintf(outp, "\n"); 495 outp += sprintf(outp, "\n");
430} 496}
431 497
432int dump_counters(struct thread_data *t, struct core_data *c, 498int dump_counters(struct thread_data *t, struct core_data *c,
433 struct pkg_data *p) 499 struct pkg_data *p)
434{ 500{
501 int i;
502 struct msr_counter *mp;
503
435 outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p); 504 outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p);
436 505
437 if (t) { 506 if (t) {
@@ -453,6 +522,11 @@ int dump_counters(struct thread_data *t, struct core_data *c,
453 outp += sprintf(outp, "IRQ: %08X\n", t->irq_count); 522 outp += sprintf(outp, "IRQ: %08X\n", t->irq_count);
454 if (do_smi) 523 if (do_smi)
455 outp += sprintf(outp, "SMI: %08X\n", t->smi_count); 524 outp += sprintf(outp, "SMI: %08X\n", t->smi_count);
525
526 for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
527 outp += sprintf(outp, "tADDED [%d] msr0x%x: %08llX\n",
528 i, mp->msr_num, t->counter[i]);
529 }
456 } 530 }
457 531
458 if (c) { 532 if (c) {
@@ -461,6 +535,11 @@ int dump_counters(struct thread_data *t, struct core_data *c,
461 outp += sprintf(outp, "c6: %016llX\n", c->c6); 535 outp += sprintf(outp, "c6: %016llX\n", c->c6);
462 outp += sprintf(outp, "c7: %016llX\n", c->c7); 536 outp += sprintf(outp, "c7: %016llX\n", c->c7);
463 outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c); 537 outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c);
538
539 for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
540 outp += sprintf(outp, "cADDED [%d] msr0x%x: %08llX\n",
541 i, mp->msr_num, c->counter[i]);
542 }
464 } 543 }
465 544
466 if (p) { 545 if (p) {
@@ -490,6 +569,11 @@ int dump_counters(struct thread_data *t, struct core_data *c,
490 outp += sprintf(outp, "Throttle RAM: %0X\n", 569 outp += sprintf(outp, "Throttle RAM: %0X\n",
491 p->rapl_dram_perf_status); 570 p->rapl_dram_perf_status);
492 outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c); 571 outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c);
572
573 for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
574 outp += sprintf(outp, "pADDED [%d] msr0x%x: %08llX\n",
575 i, mp->msr_num, p->counter[i]);
576 }
493 } 577 }
494 578
495 outp += sprintf(outp, "\n"); 579 outp += sprintf(outp, "\n");
@@ -505,6 +589,8 @@ int format_counters(struct thread_data *t, struct core_data *c,
505{ 589{
506 double interval_float; 590 double interval_float;
507 char *fmt8; 591 char *fmt8;
592 int i;
593 struct msr_counter *mp;
508 594
509 /* if showing only 1st thread in core and this isn't one, bail out */ 595 /* if showing only 1st thread in core and this isn't one, bail out */
510 if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 596 if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
@@ -602,9 +688,36 @@ int format_counters(struct thread_data *t, struct core_data *c,
602 if (do_snb_cstates) 688 if (do_snb_cstates)
603 outp += sprintf(outp, "\t%.2f", 100.0 * c->c7/t->tsc); 689 outp += sprintf(outp, "\t%.2f", 100.0 * c->c7/t->tsc);
604 690
691 for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
692 if (mp->format == FORMAT_RAW) {
693 if (mp->width == 32)
694 outp += sprintf(outp, "\t0x%08lx", (unsigned long) t->counter[i]);
695 else
696 outp += sprintf(outp, "\t0x%016llx", t->counter[i]);
697 } else if (mp->format == FORMAT_DELTA) {
698 outp += sprintf(outp, "\t%8lld", t->counter[i]);
699 } else if (mp->format == FORMAT_PERCENT) {
700 outp += sprintf(outp, "\t%.2f", 100.0 * t->counter[i]/t->tsc);
701 }
702 }
703
704
605 if (do_dts) 705 if (do_dts)
606 outp += sprintf(outp, "\t%d", c->core_temp_c); 706 outp += sprintf(outp, "\t%d", c->core_temp_c);
607 707
708 for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
709 if (mp->format == FORMAT_RAW) {
710 if (mp->width == 32)
711 outp += sprintf(outp, "\t0x%08lx", (unsigned long) c->counter[i]);
712 else
713 outp += sprintf(outp, "\t0x%016llx", c->counter[i]);
714 } else if (mp->format == FORMAT_DELTA) {
715 outp += sprintf(outp, "\t%8lld", c->counter[i]);
716 } else if (mp->format == FORMAT_PERCENT) {
717 outp += sprintf(outp, "\t%.2f", 100.0 * c->counter[i]/t->tsc);
718 }
719 }
720
608 /* print per-package data only for 1st core in package */ 721 /* print per-package data only for 1st core in package */
609 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) 722 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
610 goto done; 723 goto done;
@@ -689,6 +802,19 @@ int format_counters(struct thread_data *t, struct core_data *c,
689 if (do_rapl & RAPL_DRAM_PERF_STATUS) 802 if (do_rapl & RAPL_DRAM_PERF_STATUS)
690 outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); 803 outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
691 } 804 }
805 for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
806 if (mp->format == FORMAT_RAW) {
807 if (mp->width == 32)
808 outp += sprintf(outp, "\t0x%08lx", (unsigned long) p->counter[i]);
809 else
810 outp += sprintf(outp, "\t0x%016llx", p->counter[i]);
811 } else if (mp->format == FORMAT_DELTA) {
812 outp += sprintf(outp, "\t%8lld", p->counter[i]);
813 } else if (mp->format == FORMAT_PERCENT) {
814 outp += sprintf(outp, "\t%.2f", 100.0 * p->counter[i]/t->tsc);
815 }
816 }
817
692done: 818done:
693 outp += sprintf(outp, "\n"); 819 outp += sprintf(outp, "\n");
694 820
@@ -744,6 +870,8 @@ void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_
744int 870int
745delta_package(struct pkg_data *new, struct pkg_data *old) 871delta_package(struct pkg_data *new, struct pkg_data *old)
746{ 872{
873 int i;
874 struct msr_counter *mp;
747 875
748 if (do_skl_residency) { 876 if (do_skl_residency) {
749 old->pkg_wtd_core_c0 = new->pkg_wtd_core_c0 - old->pkg_wtd_core_c0; 877 old->pkg_wtd_core_c0 = new->pkg_wtd_core_c0 - old->pkg_wtd_core_c0;
@@ -778,16 +906,33 @@ delta_package(struct pkg_data *new, struct pkg_data *old)
778 DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status); 906 DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status);
779 DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status); 907 DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status);
780 908
909 for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
910 if (mp->format == FORMAT_RAW)
911 old->counter[i] = new->counter[i];
912 else
913 old->counter[i] = new->counter[i] - old->counter[i];
914 }
915
781 return 0; 916 return 0;
782} 917}
783 918
784void 919void
785delta_core(struct core_data *new, struct core_data *old) 920delta_core(struct core_data *new, struct core_data *old)
786{ 921{
922 int i;
923 struct msr_counter *mp;
924
787 old->c3 = new->c3 - old->c3; 925 old->c3 = new->c3 - old->c3;
788 old->c6 = new->c6 - old->c6; 926 old->c6 = new->c6 - old->c6;
789 old->c7 = new->c7 - old->c7; 927 old->c7 = new->c7 - old->c7;
790 old->core_temp_c = new->core_temp_c; 928 old->core_temp_c = new->core_temp_c;
929
930 for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
931 if (mp->format == FORMAT_RAW)
932 old->counter[i] = new->counter[i];
933 else
934 old->counter[i] = new->counter[i] - old->counter[i];
935 }
791} 936}
792 937
793/* 938/*
@@ -797,6 +942,9 @@ int
797delta_thread(struct thread_data *new, struct thread_data *old, 942delta_thread(struct thread_data *new, struct thread_data *old,
798 struct core_data *core_delta) 943 struct core_data *core_delta)
799{ 944{
945 int i;
946 struct msr_counter *mp;
947
800 old->tsc = new->tsc - old->tsc; 948 old->tsc = new->tsc - old->tsc;
801 949
802 /* check for TSC < 1 Mcycles over interval */ 950 /* check for TSC < 1 Mcycles over interval */
@@ -860,6 +1008,12 @@ delta_thread(struct thread_data *new, struct thread_data *old,
860 if (do_smi) 1008 if (do_smi)
861 old->smi_count = new->smi_count - old->smi_count; 1009 old->smi_count = new->smi_count - old->smi_count;
862 1010
1011 for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1012 if (mp->format == FORMAT_RAW)
1013 old->counter[i] = new->counter[i];
1014 else
1015 old->counter[i] = new->counter[i] - old->counter[i];
1016 }
863 return 0; 1017 return 0;
864} 1018}
865 1019
@@ -887,6 +1041,9 @@ int delta_cpu(struct thread_data *t, struct core_data *c,
887 1041
888void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) 1042void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
889{ 1043{
1044 int i;
1045 struct msr_counter *mp;
1046
890 t->tsc = 0; 1047 t->tsc = 0;
891 t->aperf = 0; 1048 t->aperf = 0;
892 t->mperf = 0; 1049 t->mperf = 0;
@@ -932,10 +1089,22 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
932 1089
933 p->gfx_rc6_ms = 0; 1090 p->gfx_rc6_ms = 0;
934 p->gfx_mhz = 0; 1091 p->gfx_mhz = 0;
1092
1093 for (i = 0, mp = sys.tp; mp; i++, mp = mp->next)
1094 t->counter[i] = 0;
1095
1096 for (i = 0, mp = sys.cp; mp; i++, mp = mp->next)
1097 c->counter[i] = 0;
1098
1099 for (i = 0, mp = sys.pp; mp; i++, mp = mp->next)
1100 p->counter[i] = 0;
935} 1101}
936int sum_counters(struct thread_data *t, struct core_data *c, 1102int sum_counters(struct thread_data *t, struct core_data *c,
937 struct pkg_data *p) 1103 struct pkg_data *p)
938{ 1104{
1105 int i;
1106 struct msr_counter *mp;
1107
939 average.threads.tsc += t->tsc; 1108 average.threads.tsc += t->tsc;
940 average.threads.aperf += t->aperf; 1109 average.threads.aperf += t->aperf;
941 average.threads.mperf += t->mperf; 1110 average.threads.mperf += t->mperf;
@@ -947,6 +1116,12 @@ int sum_counters(struct thread_data *t, struct core_data *c,
947 average.threads.irq_count += t->irq_count; 1116 average.threads.irq_count += t->irq_count;
948 average.threads.smi_count += t->smi_count; 1117 average.threads.smi_count += t->smi_count;
949 1118
1119 for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1120 if (mp->format == FORMAT_RAW)
1121 continue;
1122 average.threads.counter[i] += t->counter[i];
1123 }
1124
950 /* sum per-core values only for 1st thread in core */ 1125 /* sum per-core values only for 1st thread in core */
951 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 1126 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
952 return 0; 1127 return 0;
@@ -957,6 +1132,12 @@ int sum_counters(struct thread_data *t, struct core_data *c,
957 1132
958 average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c); 1133 average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c);
959 1134
1135 for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1136 if (mp->format == FORMAT_RAW)
1137 continue;
1138 average.cores.counter[i] += c->counter[i];
1139 }
1140
960 /* sum per-pkg values only for 1st core in pkg */ 1141 /* sum per-pkg values only for 1st core in pkg */
961 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) 1142 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
962 return 0; 1143 return 0;
@@ -991,6 +1172,12 @@ int sum_counters(struct thread_data *t, struct core_data *c,
991 1172
992 average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status; 1173 average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status;
993 average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status; 1174 average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status;
1175
1176 for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1177 if (mp->format == FORMAT_RAW)
1178 continue;
1179 average.packages.counter[i] += p->counter[i];
1180 }
994 return 0; 1181 return 0;
995} 1182}
996/* 1183/*
@@ -1000,6 +1187,9 @@ int sum_counters(struct thread_data *t, struct core_data *c,
1000void compute_average(struct thread_data *t, struct core_data *c, 1187void compute_average(struct thread_data *t, struct core_data *c,
1001 struct pkg_data *p) 1188 struct pkg_data *p)
1002{ 1189{
1190 int i;
1191 struct msr_counter *mp;
1192
1003 clear_counters(&average.threads, &average.cores, &average.packages); 1193 clear_counters(&average.threads, &average.cores, &average.packages);
1004 1194
1005 for_all_cpus(sum_counters, t, c, p); 1195 for_all_cpus(sum_counters, t, c, p);
@@ -1036,6 +1226,22 @@ void compute_average(struct thread_data *t, struct core_data *c,
1036 average.packages.pc8 /= topo.num_packages; 1226 average.packages.pc8 /= topo.num_packages;
1037 average.packages.pc9 /= topo.num_packages; 1227 average.packages.pc9 /= topo.num_packages;
1038 average.packages.pc10 /= topo.num_packages; 1228 average.packages.pc10 /= topo.num_packages;
1229
1230 for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1231 if (mp->format == FORMAT_RAW)
1232 continue;
1233 average.threads.counter[i] /= topo.num_cpus;
1234 }
1235 for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1236 if (mp->format == FORMAT_RAW)
1237 continue;
1238 average.cores.counter[i] /= topo.num_cores;
1239 }
1240 for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1241 if (mp->format == FORMAT_RAW)
1242 continue;
1243 average.packages.counter[i] /= topo.num_packages;
1244 }
1039} 1245}
1040 1246
1041static unsigned long long rdtsc(void) 1247static unsigned long long rdtsc(void)
@@ -1057,6 +1263,8 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1057 int cpu = t->cpu_id; 1263 int cpu = t->cpu_id;
1058 unsigned long long msr; 1264 unsigned long long msr;
1059 int aperf_mperf_retry_count = 0; 1265 int aperf_mperf_retry_count = 0;
1266 struct msr_counter *mp;
1267 int i;
1060 1268
1061 if (cpu_migrate(cpu)) { 1269 if (cpu_migrate(cpu)) {
1062 fprintf(outf, "Could not migrate to CPU %d\n", cpu); 1270 fprintf(outf, "Could not migrate to CPU %d\n", cpu);
@@ -1154,6 +1362,12 @@ retry:
1154 return -6; 1362 return -6;
1155 } 1363 }
1156 1364
1365 for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
1366 if (get_msr(cpu, mp->msr_num, &t->counter[i]))
1367 return -10;
1368 }
1369
1370
1157 /* collect core counters only for 1st thread in core */ 1371 /* collect core counters only for 1st thread in core */
1158 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 1372 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
1159 return 0; 1373 return 0;
@@ -1181,6 +1395,10 @@ retry:
1181 c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F); 1395 c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
1182 } 1396 }
1183 1397
1398 for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
1399 if (get_msr(cpu, mp->msr_num, &c->counter[i]))
1400 return -10;
1401 }
1184 1402
1185 /* collect package counters only for 1st core in package */ 1403 /* collect package counters only for 1st core in package */
1186 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) 1404 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
@@ -1258,6 +1476,11 @@ retry:
1258 if (do_gfx_mhz) 1476 if (do_gfx_mhz)
1259 p->gfx_mhz = gfx_cur_mhz; 1477 p->gfx_mhz = gfx_cur_mhz;
1260 1478
1479 for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
1480 if (get_msr(cpu, mp->msr_num, &p->counter[i]))
1481 return -10;
1482 }
1483
1261 return 0; 1484 return 0;
1262} 1485}
1263 1486
@@ -2740,7 +2963,7 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
2740 cpu = t->cpu_id; 2963 cpu = t->cpu_id;
2741 2964
2742 /* DTS is per-core, no need to print for each thread */ 2965 /* DTS is per-core, no need to print for each thread */
2743 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 2966 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
2744 return 0; 2967 return 0;
2745 2968
2746 if (cpu_migrate(cpu)) { 2969 if (cpu_migrate(cpu)) {
@@ -3391,6 +3614,8 @@ void help()
3391 "when COMMAND completes.\n" 3614 "when COMMAND completes.\n"
3392 "If no COMMAND is specified, turbostat wakes every 5-seconds\n" 3615 "If no COMMAND is specified, turbostat wakes every 5-seconds\n"
3393 "to print statistics, until interrupted.\n" 3616 "to print statistics, until interrupted.\n"
3617 "--add add a counter\n"
3618 " eg. --add msr0x10,u64,cpu,delta,MY_TSC\n"
3394 "--debug run in \"debug\" mode\n" 3619 "--debug run in \"debug\" mode\n"
3395 "--interval sec Override default 5-second measurement interval\n" 3620 "--interval sec Override default 5-second measurement interval\n"
3396 "--help print this help message\n" 3621 "--help print this help message\n"
@@ -3521,7 +3746,7 @@ allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data
3521 int i; 3746 int i;
3522 3747
3523 *t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg * 3748 *t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg *
3524 topo.num_packages, sizeof(struct thread_data)); 3749 topo.num_packages, sizeof(struct thread_data) + sys.thread_counter_bytes);
3525 if (*t == NULL) 3750 if (*t == NULL)
3526 goto error; 3751 goto error;
3527 3752
@@ -3530,14 +3755,14 @@ allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data
3530 (*t)[i].cpu_id = -1; 3755 (*t)[i].cpu_id = -1;
3531 3756
3532 *c = calloc(topo.num_cores_per_pkg * topo.num_packages, 3757 *c = calloc(topo.num_cores_per_pkg * topo.num_packages,
3533 sizeof(struct core_data)); 3758 sizeof(struct core_data) + sys.core_counter_bytes);
3534 if (*c == NULL) 3759 if (*c == NULL)
3535 goto error; 3760 goto error;
3536 3761
3537 for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++) 3762 for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++)
3538 (*c)[i].core_id = -1; 3763 (*c)[i].core_id = -1;
3539 3764
3540 *p = calloc(topo.num_packages, sizeof(struct pkg_data)); 3765 *p = calloc(topo.num_packages, sizeof(struct pkg_data) + sys.package_counter_bytes);
3541 if (*p == NULL) 3766 if (*p == NULL)
3542 goto error; 3767 goto error;
3543 3768
@@ -3735,15 +3960,165 @@ int get_and_dump_counters(void)
3735} 3960}
3736 3961
3737void print_version() { 3962void print_version() {
3738 fprintf(outf, "turbostat version 4.14 22 Apr 2016" 3963 fprintf(outf, "turbostat version 4.15 21 Dec 2016"
3739 " - Len Brown <lenb@kernel.org>\n"); 3964 " - Len Brown <lenb@kernel.org>\n");
3740} 3965}
3741 3966
3967int add_counter(unsigned int msr_num, char *name, unsigned int width,
3968 enum counter_scope scope, enum counter_type type,
3969 enum counter_format format)
3970{
3971 struct msr_counter *msrp;
3972
3973 msrp = calloc(1, sizeof(struct msr_counter));
3974 if (msrp == NULL) {
3975 perror("calloc");
3976 exit(1);
3977 }
3978
3979 msrp->msr_num = msr_num;
3980 strncpy(msrp->name, name, NAME_BYTES);
3981 msrp->width = width;
3982 msrp->type = type;
3983 msrp->format = format;
3984
3985 switch (scope) {
3986
3987 case SCOPE_CPU:
3988 sys.thread_counter_bytes += 64;
3989 msrp->next = sys.tp;
3990 sys.tp = msrp;
3991 sys.thread_counter_bytes += sizeof(unsigned long long);
3992 break;
3993
3994 case SCOPE_CORE:
3995 sys.core_counter_bytes += 64;
3996 msrp->next = sys.cp;
3997 sys.cp = msrp;
3998 sys.core_counter_bytes += sizeof(unsigned long long);
3999 break;
4000
4001 case SCOPE_PACKAGE:
4002 sys.package_counter_bytes += 64;
4003 msrp->next = sys.pp;
4004 sys.pp = msrp;
4005 sys.package_counter_bytes += sizeof(unsigned long long);
4006 break;
4007 }
4008
4009 return 0;
4010}
4011
4012void parse_add_command(char *add_command)
4013{
4014 int msr_num = 0;
4015 char name_buffer[NAME_BYTES];
4016 int width = 64;
4017 int fail = 0;
4018 enum counter_scope scope = SCOPE_CPU;
4019 enum counter_type type = COUNTER_CYCLES;
4020 enum counter_format format = FORMAT_DELTA;
4021
4022 while (add_command) {
4023
4024 if (sscanf(add_command, "msr0x%x", &msr_num) == 1)
4025 goto next;
4026
4027 if (sscanf(add_command, "msr%d", &msr_num) == 1)
4028 goto next;
4029
4030 if (sscanf(add_command, "u%d", &width) == 1) {
4031 if ((width == 32) || (width == 64))
4032 goto next;
4033 width = 64;
4034 }
4035 if (!strncmp(add_command, "cpu", strlen("cpu"))) {
4036 scope = SCOPE_CPU;
4037 goto next;
4038 }
4039 if (!strncmp(add_command, "core", strlen("core"))) {
4040 scope = SCOPE_CORE;
4041 goto next;
4042 }
4043 if (!strncmp(add_command, "package", strlen("package"))) {
4044 scope = SCOPE_PACKAGE;
4045 goto next;
4046 }
4047 if (!strncmp(add_command, "cycles", strlen("cycles"))) {
4048 type = COUNTER_CYCLES;
4049 goto next;
4050 }
4051 if (!strncmp(add_command, "seconds", strlen("seconds"))) {
4052 type = COUNTER_SECONDS;
4053 goto next;
4054 }
4055 if (!strncmp(add_command, "raw", strlen("raw"))) {
4056 format = FORMAT_RAW;
4057 goto next;
4058 }
4059 if (!strncmp(add_command, "delta", strlen("delta"))) {
4060 format = FORMAT_DELTA;
4061 goto next;
4062 }
4063 if (!strncmp(add_command, "percent", strlen("percent"))) {
4064 format = FORMAT_PERCENT;
4065 goto next;
4066 }
4067
4068 if (sscanf(add_command, "%18s,%*s", name_buffer) == 1) { /* 18 < NAME_BYTES */
4069 char *eos;
4070
4071 eos = strchr(name_buffer, ',');
4072 if (eos)
4073 *eos = '\0';
4074 goto next;
4075 }
4076
4077next:
4078 add_command = strchr(add_command, ',');
4079 if (add_command)
4080 add_command++;
4081
4082 }
4083 if (msr_num == 0) {
4084 fprintf(stderr, "--add: (msrDDD | msr0xXXX) required\n");
4085 fail++;
4086 }
4087
4088 /* generate default column header */
4089 if (*name_buffer == '\0') {
4090 if (format == FORMAT_RAW) {
4091 if (width == 32)
4092 sprintf(name_buffer, "msr%d", msr_num);
4093 else
4094 sprintf(name_buffer, "MSR%d", msr_num);
4095 } else if (format == FORMAT_DELTA) {
4096 if (width == 32)
4097 sprintf(name_buffer, "cnt%d", msr_num);
4098 else
4099 sprintf(name_buffer, "CNT%d", msr_num);
4100 } else if (format == FORMAT_PERCENT) {
4101 if (width == 32)
4102 sprintf(name_buffer, "msr%d%%", msr_num);
4103 else
4104 sprintf(name_buffer, "MSR%d%%", msr_num);
4105 }
4106 }
4107
4108 if (add_counter(msr_num, name_buffer, width, scope, type, format))
4109 fail++;
4110
4111 if (fail) {
4112 help();
4113 exit(1);
4114 }
4115}
3742void cmdline(int argc, char **argv) 4116void cmdline(int argc, char **argv)
3743{ 4117{
3744 int opt; 4118 int opt;
3745 int option_index = 0; 4119 int option_index = 0;
3746 static struct option long_options[] = { 4120 static struct option long_options[] = {
4121 {"add", required_argument, 0, 'a'},
3747 {"Counter", required_argument, 0, 'C'}, 4122 {"Counter", required_argument, 0, 'C'},
3748 {"counter", required_argument, 0, 'c'}, 4123 {"counter", required_argument, 0, 'c'},
3749 {"Dump", no_argument, 0, 'D'}, 4124 {"Dump", no_argument, 0, 'D'},
@@ -3767,6 +4142,9 @@ void cmdline(int argc, char **argv)
3767 while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:o:PpST:v", 4142 while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:o:PpST:v",
3768 long_options, &option_index)) != -1) { 4143 long_options, &option_index)) != -1) {
3769 switch (opt) { 4144 switch (opt) {
4145 case 'a':
4146 parse_add_command(optarg);
4147 break;
3770 case 'C': 4148 case 'C':
3771 sscanf(optarg, "%x", &extra_delta_offset64); 4149 sscanf(optarg, "%x", &extra_delta_offset64);
3772 break; 4150 break;