aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/perf_counter.h10
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c325
-rw-r--r--tools/perf/Documentation/perf-report.txt3
-rw-r--r--tools/perf/Makefile4
-rw-r--r--tools/perf/builtin-annotate.c209
-rw-r--r--tools/perf/builtin-record.c20
-rw-r--r--tools/perf/builtin-report.c308
-rw-r--r--tools/perf/builtin-stat.c1
-rw-r--r--tools/perf/builtin-top.c24
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/util/callchain.h1
-rw-r--r--tools/perf/util/debug.c22
-rw-r--r--tools/perf/util/debug.h5
-rw-r--r--tools/perf/util/event.h90
-rw-r--r--tools/perf/util/map.c97
-rw-r--r--tools/perf/util/symbol.c97
-rw-r--r--tools/perf/util/symbol.h12
-rw-r--r--tools/perf/util/util.h1
-rw-r--r--tools/perf/util/values.c231
-rw-r--r--tools/perf/util/values.h27
21 files changed, 962 insertions, 527 deletions
diff --git a/arch/x86/include/asm/perf_counter.h b/arch/x86/include/asm/perf_counter.h
index fa64e401589d..e7b7c938ae27 100644
--- a/arch/x86/include/asm/perf_counter.h
+++ b/arch/x86/include/asm/perf_counter.h
@@ -84,6 +84,16 @@ union cpuid10_edx {
84#define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b 84#define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b
85#define X86_PMC_IDX_FIXED_BUS_CYCLES (X86_PMC_IDX_FIXED + 2) 85#define X86_PMC_IDX_FIXED_BUS_CYCLES (X86_PMC_IDX_FIXED + 2)
86 86
87/*
88 * We model BTS tracing as another fixed-mode PMC.
89 *
90 * We choose a value in the middle of the fixed counter range, since lower
91 * values are used by actual fixed counters and higher values are used
92 * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
93 */
94#define X86_PMC_IDX_FIXED_BTS (X86_PMC_IDX_FIXED + 16)
95
96
87#ifdef CONFIG_PERF_COUNTERS 97#ifdef CONFIG_PERF_COUNTERS
88extern void init_hw_perf_counters(void); 98extern void init_hw_perf_counters(void);
89extern void perf_counters_lapic_init(void); 99extern void perf_counters_lapic_init(void);
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 900332b800f8..396e35db7058 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -6,6 +6,7 @@
6 * Copyright (C) 2009 Jaswinder Singh Rajput 6 * Copyright (C) 2009 Jaswinder Singh Rajput
7 * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter 7 * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
8 * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> 8 * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
9 * Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
9 * 10 *
10 * For licencing details see kernel-base/COPYING 11 * For licencing details see kernel-base/COPYING
11 */ 12 */
@@ -20,6 +21,7 @@
20#include <linux/sched.h> 21#include <linux/sched.h>
21#include <linux/uaccess.h> 22#include <linux/uaccess.h>
22#include <linux/highmem.h> 23#include <linux/highmem.h>
24#include <linux/cpu.h>
23 25
24#include <asm/apic.h> 26#include <asm/apic.h>
25#include <asm/stacktrace.h> 27#include <asm/stacktrace.h>
@@ -27,12 +29,52 @@
27 29
28static u64 perf_counter_mask __read_mostly; 30static u64 perf_counter_mask __read_mostly;
29 31
32/* The maximal number of PEBS counters: */
33#define MAX_PEBS_COUNTERS 4
34
35/* The size of a BTS record in bytes: */
36#define BTS_RECORD_SIZE 24
37
38/* The size of a per-cpu BTS buffer in bytes: */
39#define BTS_BUFFER_SIZE (BTS_RECORD_SIZE * 1024)
40
41/* The BTS overflow threshold in bytes from the end of the buffer: */
42#define BTS_OVFL_TH (BTS_RECORD_SIZE * 64)
43
44
45/*
46 * Bits in the debugctlmsr controlling branch tracing.
47 */
48#define X86_DEBUGCTL_TR (1 << 6)
49#define X86_DEBUGCTL_BTS (1 << 7)
50#define X86_DEBUGCTL_BTINT (1 << 8)
51#define X86_DEBUGCTL_BTS_OFF_OS (1 << 9)
52#define X86_DEBUGCTL_BTS_OFF_USR (1 << 10)
53
54/*
55 * A debug store configuration.
56 *
57 * We only support architectures that use 64bit fields.
58 */
59struct debug_store {
60 u64 bts_buffer_base;
61 u64 bts_index;
62 u64 bts_absolute_maximum;
63 u64 bts_interrupt_threshold;
64 u64 pebs_buffer_base;
65 u64 pebs_index;
66 u64 pebs_absolute_maximum;
67 u64 pebs_interrupt_threshold;
68 u64 pebs_counter_reset[MAX_PEBS_COUNTERS];
69};
70
30struct cpu_hw_counters { 71struct cpu_hw_counters {
31 struct perf_counter *counters[X86_PMC_IDX_MAX]; 72 struct perf_counter *counters[X86_PMC_IDX_MAX];
32 unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; 73 unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
33 unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; 74 unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
34 unsigned long interrupts; 75 unsigned long interrupts;
35 int enabled; 76 int enabled;
77 struct debug_store *ds;
36}; 78};
37 79
38/* 80/*
@@ -58,6 +100,8 @@ struct x86_pmu {
58 int apic; 100 int apic;
59 u64 max_period; 101 u64 max_period;
60 u64 intel_ctrl; 102 u64 intel_ctrl;
103 void (*enable_bts)(u64 config);
104 void (*disable_bts)(void);
61}; 105};
62 106
63static struct x86_pmu x86_pmu __read_mostly; 107static struct x86_pmu x86_pmu __read_mostly;
@@ -577,6 +621,9 @@ x86_perf_counter_update(struct perf_counter *counter,
577 u64 prev_raw_count, new_raw_count; 621 u64 prev_raw_count, new_raw_count;
578 s64 delta; 622 s64 delta;
579 623
624 if (idx == X86_PMC_IDX_FIXED_BTS)
625 return 0;
626
580 /* 627 /*
581 * Careful: an NMI might modify the previous counter value. 628 * Careful: an NMI might modify the previous counter value.
582 * 629 *
@@ -666,10 +713,109 @@ static void release_pmc_hardware(void)
666#endif 713#endif
667} 714}
668 715
716static inline bool bts_available(void)
717{
718 return x86_pmu.enable_bts != NULL;
719}
720
721static inline void init_debug_store_on_cpu(int cpu)
722{
723 struct debug_store *ds = per_cpu(cpu_hw_counters, cpu).ds;
724
725 if (!ds)
726 return;
727
728 wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA,
729 (u32)((u64)(long)ds), (u32)((u64)(long)ds >> 32));
730}
731
732static inline void fini_debug_store_on_cpu(int cpu)
733{
734 if (!per_cpu(cpu_hw_counters, cpu).ds)
735 return;
736
737 wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
738}
739
740static void release_bts_hardware(void)
741{
742 int cpu;
743
744 if (!bts_available())
745 return;
746
747 get_online_cpus();
748
749 for_each_online_cpu(cpu)
750 fini_debug_store_on_cpu(cpu);
751
752 for_each_possible_cpu(cpu) {
753 struct debug_store *ds = per_cpu(cpu_hw_counters, cpu).ds;
754
755 if (!ds)
756 continue;
757
758 per_cpu(cpu_hw_counters, cpu).ds = NULL;
759
760 kfree((void *)(long)ds->bts_buffer_base);
761 kfree(ds);
762 }
763
764 put_online_cpus();
765}
766
767static int reserve_bts_hardware(void)
768{
769 int cpu, err = 0;
770
771 if (!bts_available())
772 return -EOPNOTSUPP;
773
774 get_online_cpus();
775
776 for_each_possible_cpu(cpu) {
777 struct debug_store *ds;
778 void *buffer;
779
780 err = -ENOMEM;
781 buffer = kzalloc(BTS_BUFFER_SIZE, GFP_KERNEL);
782 if (unlikely(!buffer))
783 break;
784
785 ds = kzalloc(sizeof(*ds), GFP_KERNEL);
786 if (unlikely(!ds)) {
787 kfree(buffer);
788 break;
789 }
790
791 ds->bts_buffer_base = (u64)(long)buffer;
792 ds->bts_index = ds->bts_buffer_base;
793 ds->bts_absolute_maximum =
794 ds->bts_buffer_base + BTS_BUFFER_SIZE;
795 ds->bts_interrupt_threshold =
796 ds->bts_absolute_maximum - BTS_OVFL_TH;
797
798 per_cpu(cpu_hw_counters, cpu).ds = ds;
799 err = 0;
800 }
801
802 if (err)
803 release_bts_hardware();
804 else {
805 for_each_online_cpu(cpu)
806 init_debug_store_on_cpu(cpu);
807 }
808
809 put_online_cpus();
810
811 return err;
812}
813
669static void hw_perf_counter_destroy(struct perf_counter *counter) 814static void hw_perf_counter_destroy(struct perf_counter *counter)
670{ 815{
671 if (atomic_dec_and_mutex_lock(&active_counters, &pmc_reserve_mutex)) { 816 if (atomic_dec_and_mutex_lock(&active_counters, &pmc_reserve_mutex)) {
672 release_pmc_hardware(); 817 release_pmc_hardware();
818 release_bts_hardware();
673 mutex_unlock(&pmc_reserve_mutex); 819 mutex_unlock(&pmc_reserve_mutex);
674 } 820 }
675} 821}
@@ -712,6 +858,42 @@ set_ext_hw_attr(struct hw_perf_counter *hwc, struct perf_counter_attr *attr)
712 return 0; 858 return 0;
713} 859}
714 860
861static void intel_pmu_enable_bts(u64 config)
862{
863 unsigned long debugctlmsr;
864
865 debugctlmsr = get_debugctlmsr();
866
867 debugctlmsr |= X86_DEBUGCTL_TR;
868 debugctlmsr |= X86_DEBUGCTL_BTS;
869 debugctlmsr |= X86_DEBUGCTL_BTINT;
870
871 if (!(config & ARCH_PERFMON_EVENTSEL_OS))
872 debugctlmsr |= X86_DEBUGCTL_BTS_OFF_OS;
873
874 if (!(config & ARCH_PERFMON_EVENTSEL_USR))
875 debugctlmsr |= X86_DEBUGCTL_BTS_OFF_USR;
876
877 update_debugctlmsr(debugctlmsr);
878}
879
880static void intel_pmu_disable_bts(void)
881{
882 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
883 unsigned long debugctlmsr;
884
885 if (!cpuc->ds)
886 return;
887
888 debugctlmsr = get_debugctlmsr();
889
890 debugctlmsr &=
891 ~(X86_DEBUGCTL_TR | X86_DEBUGCTL_BTS | X86_DEBUGCTL_BTINT |
892 X86_DEBUGCTL_BTS_OFF_OS | X86_DEBUGCTL_BTS_OFF_USR);
893
894 update_debugctlmsr(debugctlmsr);
895}
896
715/* 897/*
716 * Setup the hardware configuration for a given attr_type 898 * Setup the hardware configuration for a given attr_type
717 */ 899 */
@@ -728,9 +910,13 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
728 err = 0; 910 err = 0;
729 if (!atomic_inc_not_zero(&active_counters)) { 911 if (!atomic_inc_not_zero(&active_counters)) {
730 mutex_lock(&pmc_reserve_mutex); 912 mutex_lock(&pmc_reserve_mutex);
731 if (atomic_read(&active_counters) == 0 && !reserve_pmc_hardware()) 913 if (atomic_read(&active_counters) == 0) {
732 err = -EBUSY; 914 if (!reserve_pmc_hardware())
733 else 915 err = -EBUSY;
916 else
917 reserve_bts_hardware();
918 }
919 if (!err)
734 atomic_inc(&active_counters); 920 atomic_inc(&active_counters);
735 mutex_unlock(&pmc_reserve_mutex); 921 mutex_unlock(&pmc_reserve_mutex);
736 } 922 }
@@ -817,7 +1003,18 @@ static void p6_pmu_disable_all(void)
817 1003
818static void intel_pmu_disable_all(void) 1004static void intel_pmu_disable_all(void)
819{ 1005{
1006 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
1007
1008 if (!cpuc->enabled)
1009 return;
1010
1011 cpuc->enabled = 0;
1012 barrier();
1013
820 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); 1014 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
1015
1016 if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask))
1017 intel_pmu_disable_bts();
821} 1018}
822 1019
823static void amd_pmu_disable_all(void) 1020static void amd_pmu_disable_all(void)
@@ -875,7 +1072,25 @@ static void p6_pmu_enable_all(void)
875 1072
876static void intel_pmu_enable_all(void) 1073static void intel_pmu_enable_all(void)
877{ 1074{
1075 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
1076
1077 if (cpuc->enabled)
1078 return;
1079
1080 cpuc->enabled = 1;
1081 barrier();
1082
878 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl); 1083 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
1084
1085 if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) {
1086 struct perf_counter *counter =
1087 cpuc->counters[X86_PMC_IDX_FIXED_BTS];
1088
1089 if (WARN_ON_ONCE(!counter))
1090 return;
1091
1092 intel_pmu_enable_bts(counter->hw.config);
1093 }
879} 1094}
880 1095
881static void amd_pmu_enable_all(void) 1096static void amd_pmu_enable_all(void)
@@ -962,6 +1177,11 @@ p6_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
962static inline void 1177static inline void
963intel_pmu_disable_counter(struct hw_perf_counter *hwc, int idx) 1178intel_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
964{ 1179{
1180 if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
1181 intel_pmu_disable_bts();
1182 return;
1183 }
1184
965 if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) { 1185 if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
966 intel_pmu_disable_fixed(hwc, idx); 1186 intel_pmu_disable_fixed(hwc, idx);
967 return; 1187 return;
@@ -990,6 +1210,9 @@ x86_perf_counter_set_period(struct perf_counter *counter,
990 s64 period = hwc->sample_period; 1210 s64 period = hwc->sample_period;
991 int err, ret = 0; 1211 int err, ret = 0;
992 1212
1213 if (idx == X86_PMC_IDX_FIXED_BTS)
1214 return 0;
1215
993 /* 1216 /*
994 * If we are way outside a reasoable range then just skip forward: 1217 * If we are way outside a reasoable range then just skip forward:
995 */ 1218 */
@@ -1072,6 +1295,14 @@ static void p6_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
1072 1295
1073static void intel_pmu_enable_counter(struct hw_perf_counter *hwc, int idx) 1296static void intel_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
1074{ 1297{
1298 if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
1299 if (!__get_cpu_var(cpu_hw_counters).enabled)
1300 return;
1301
1302 intel_pmu_enable_bts(hwc->config);
1303 return;
1304 }
1305
1075 if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) { 1306 if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
1076 intel_pmu_enable_fixed(hwc, idx); 1307 intel_pmu_enable_fixed(hwc, idx);
1077 return; 1308 return;
@@ -1093,11 +1324,16 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
1093{ 1324{
1094 unsigned int event; 1325 unsigned int event;
1095 1326
1327 event = hwc->config & ARCH_PERFMON_EVENT_MASK;
1328
1329 if (unlikely((event ==
1330 x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) &&
1331 (hwc->sample_period == 1)))
1332 return X86_PMC_IDX_FIXED_BTS;
1333
1096 if (!x86_pmu.num_counters_fixed) 1334 if (!x86_pmu.num_counters_fixed)
1097 return -1; 1335 return -1;
1098 1336
1099 event = hwc->config & ARCH_PERFMON_EVENT_MASK;
1100
1101 if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS))) 1337 if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
1102 return X86_PMC_IDX_FIXED_INSTRUCTIONS; 1338 return X86_PMC_IDX_FIXED_INSTRUCTIONS;
1103 if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES))) 1339 if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES)))
@@ -1118,7 +1354,25 @@ static int x86_pmu_enable(struct perf_counter *counter)
1118 int idx; 1354 int idx;
1119 1355
1120 idx = fixed_mode_idx(counter, hwc); 1356 idx = fixed_mode_idx(counter, hwc);
1121 if (idx >= 0) { 1357 if (idx == X86_PMC_IDX_FIXED_BTS) {
1358 /*
1359 * Try to use BTS for branch tracing. If that is not
1360 * available, try to get a generic counter.
1361 */
1362 if (unlikely(!cpuc->ds))
1363 goto try_generic;
1364
1365 /*
1366 * Try to get the fixed counter, if that is already taken
1367 * then try to get a generic counter:
1368 */
1369 if (test_and_set_bit(idx, cpuc->used_mask))
1370 goto try_generic;
1371
1372 hwc->config_base = 0;
1373 hwc->counter_base = 0;
1374 hwc->idx = idx;
1375 } else if (idx >= 0) {
1122 /* 1376 /*
1123 * Try to get the fixed counter, if that is already taken 1377 * Try to get the fixed counter, if that is already taken
1124 * then try to get a generic counter: 1378 * then try to get a generic counter:
@@ -1229,6 +1483,45 @@ void perf_counter_print_debug(void)
1229 local_irq_restore(flags); 1483 local_irq_restore(flags);
1230} 1484}
1231 1485
1486static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc,
1487 struct perf_sample_data *data)
1488{
1489 struct debug_store *ds = cpuc->ds;
1490 struct bts_record {
1491 u64 from;
1492 u64 to;
1493 u64 flags;
1494 };
1495 struct perf_counter *counter = cpuc->counters[X86_PMC_IDX_FIXED_BTS];
1496 unsigned long orig_ip = data->regs->ip;
1497 u64 at;
1498
1499 if (!counter)
1500 return;
1501
1502 if (!ds)
1503 return;
1504
1505 for (at = ds->bts_buffer_base;
1506 at < ds->bts_index;
1507 at += sizeof(struct bts_record)) {
1508 struct bts_record *rec = (struct bts_record *)(long)at;
1509
1510 data->regs->ip = rec->from;
1511 data->addr = rec->to;
1512
1513 perf_counter_output(counter, 1, data);
1514 }
1515
1516 ds->bts_index = ds->bts_buffer_base;
1517
1518 data->regs->ip = orig_ip;
1519 data->addr = 0;
1520
1521 /* There's new data available. */
1522 counter->pending_kill = POLL_IN;
1523}
1524
1232static void x86_pmu_disable(struct perf_counter *counter) 1525static void x86_pmu_disable(struct perf_counter *counter)
1233{ 1526{
1234 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); 1527 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
@@ -1253,6 +1546,15 @@ static void x86_pmu_disable(struct perf_counter *counter)
1253 * that we are disabling: 1546 * that we are disabling:
1254 */ 1547 */
1255 x86_perf_counter_update(counter, hwc, idx); 1548 x86_perf_counter_update(counter, hwc, idx);
1549
1550 /* Drain the remaining BTS records. */
1551 if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
1552 struct perf_sample_data data;
1553 struct pt_regs regs;
1554
1555 data.regs = &regs;
1556 intel_pmu_drain_bts_buffer(cpuc, &data);
1557 }
1256 cpuc->counters[idx] = NULL; 1558 cpuc->counters[idx] = NULL;
1257 clear_bit(idx, cpuc->used_mask); 1559 clear_bit(idx, cpuc->used_mask);
1258 1560
@@ -1280,6 +1582,7 @@ static int intel_pmu_save_and_restart(struct perf_counter *counter)
1280 1582
1281static void intel_pmu_reset(void) 1583static void intel_pmu_reset(void)
1282{ 1584{
1585 struct debug_store *ds = __get_cpu_var(cpu_hw_counters).ds;
1283 unsigned long flags; 1586 unsigned long flags;
1284 int idx; 1587 int idx;
1285 1588
@@ -1297,6 +1600,8 @@ static void intel_pmu_reset(void)
1297 for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) { 1600 for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) {
1298 checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull); 1601 checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
1299 } 1602 }
1603 if (ds)
1604 ds->bts_index = ds->bts_buffer_base;
1300 1605
1301 local_irq_restore(flags); 1606 local_irq_restore(flags);
1302} 1607}
@@ -1362,6 +1667,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
1362 cpuc = &__get_cpu_var(cpu_hw_counters); 1667 cpuc = &__get_cpu_var(cpu_hw_counters);
1363 1668
1364 perf_disable(); 1669 perf_disable();
1670 intel_pmu_drain_bts_buffer(cpuc, &data);
1365 status = intel_pmu_get_status(); 1671 status = intel_pmu_get_status();
1366 if (!status) { 1672 if (!status) {
1367 perf_enable(); 1673 perf_enable();
@@ -1571,6 +1877,8 @@ static struct x86_pmu intel_pmu = {
1571 * the generic counter period: 1877 * the generic counter period:
1572 */ 1878 */
1573 .max_period = (1ULL << 31) - 1, 1879 .max_period = (1ULL << 31) - 1,
1880 .enable_bts = intel_pmu_enable_bts,
1881 .disable_bts = intel_pmu_disable_bts,
1574}; 1882};
1575 1883
1576static struct x86_pmu amd_pmu = { 1884static struct x86_pmu amd_pmu = {
@@ -1962,3 +2270,8 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
1962 2270
1963 return entry; 2271 return entry;
1964} 2272}
2273
2274void hw_perf_counter_setup_online(int cpu)
2275{
2276 init_debug_store_on_cpu(cpu);
2277}
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index e72e93110782..370344afb5b2 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -27,6 +27,9 @@ OPTIONS
27-n 27-n
28--show-nr-samples 28--show-nr-samples
29 Show the number of samples for each symbol 29 Show the number of samples for each symbol
30-T
31--threads
32 Show per-thread event counters
30-C:: 33-C::
31--comms=:: 34--comms=::
32 Only consider symbols in these comms. CSV that understands 35 Only consider symbols in these comms. CSV that understands
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index c045b4271e57..68218cfd38b3 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -310,6 +310,7 @@ LIB_H += util/sigchain.h
310LIB_H += util/symbol.h 310LIB_H += util/symbol.h
311LIB_H += util/module.h 311LIB_H += util/module.h
312LIB_H += util/color.h 312LIB_H += util/color.h
313LIB_H += util/values.h
313 314
314LIB_OBJS += util/abspath.o 315LIB_OBJS += util/abspath.o
315LIB_OBJS += util/alias.o 316LIB_OBJS += util/alias.o
@@ -337,6 +338,9 @@ LIB_OBJS += util/color.o
337LIB_OBJS += util/pager.o 338LIB_OBJS += util/pager.o
338LIB_OBJS += util/header.o 339LIB_OBJS += util/header.o
339LIB_OBJS += util/callchain.o 340LIB_OBJS += util/callchain.o
341LIB_OBJS += util/values.o
342LIB_OBJS += util/debug.o
343LIB_OBJS += util/map.o
340 344
341BUILTIN_OBJS += builtin-annotate.o 345BUILTIN_OBJS += builtin-annotate.o
342BUILTIN_OBJS += builtin-help.o 346BUILTIN_OBJS += builtin-help.o
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 1dba568e1941..543c4524f8c2 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -26,7 +26,6 @@
26#define SHOW_HV 4 26#define SHOW_HV 4
27 27
28static char const *input_name = "perf.data"; 28static char const *input_name = "perf.data";
29static char *vmlinux = "vmlinux";
30 29
31static char default_sort_order[] = "comm,symbol"; 30static char default_sort_order[] = "comm,symbol";
32static char *sort_order = default_sort_order; 31static char *sort_order = default_sort_order;
@@ -37,9 +36,6 @@ static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
37static int dump_trace = 0; 36static int dump_trace = 0;
38#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) 37#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
39 38
40static int verbose;
41
42static int modules;
43 39
44static int full_paths; 40static int full_paths;
45 41
@@ -48,40 +44,6 @@ static int print_line;
48static unsigned long page_size; 44static unsigned long page_size;
49static unsigned long mmap_window = 32; 45static unsigned long mmap_window = 32;
50 46
51struct ip_event {
52 struct perf_event_header header;
53 u64 ip;
54 u32 pid, tid;
55};
56
57struct mmap_event {
58 struct perf_event_header header;
59 u32 pid, tid;
60 u64 start;
61 u64 len;
62 u64 pgoff;
63 char filename[PATH_MAX];
64};
65
66struct comm_event {
67 struct perf_event_header header;
68 u32 pid, tid;
69 char comm[16];
70};
71
72struct fork_event {
73 struct perf_event_header header;
74 u32 pid, ppid;
75};
76
77typedef union event_union {
78 struct perf_event_header header;
79 struct ip_event ip;
80 struct mmap_event mmap;
81 struct comm_event comm;
82 struct fork_event fork;
83} event_t;
84
85 47
86struct sym_ext { 48struct sym_ext {
87 struct rb_node node; 49 struct rb_node node;
@@ -89,175 +51,6 @@ struct sym_ext {
89 char *path; 51 char *path;
90}; 52};
91 53
92static LIST_HEAD(dsos);
93static struct dso *kernel_dso;
94static struct dso *vdso;
95
96
97static void dsos__add(struct dso *dso)
98{
99 list_add_tail(&dso->node, &dsos);
100}
101
102static struct dso *dsos__find(const char *name)
103{
104 struct dso *pos;
105
106 list_for_each_entry(pos, &dsos, node)
107 if (strcmp(pos->name, name) == 0)
108 return pos;
109 return NULL;
110}
111
112static struct dso *dsos__findnew(const char *name)
113{
114 struct dso *dso = dsos__find(name);
115 int nr;
116
117 if (dso)
118 return dso;
119
120 dso = dso__new(name, 0);
121 if (!dso)
122 goto out_delete_dso;
123
124 nr = dso__load(dso, NULL, verbose);
125 if (nr < 0) {
126 if (verbose)
127 fprintf(stderr, "Failed to open: %s\n", name);
128 goto out_delete_dso;
129 }
130 if (!nr && verbose) {
131 fprintf(stderr,
132 "No symbols found in: %s, maybe install a debug package?\n",
133 name);
134 }
135
136 dsos__add(dso);
137
138 return dso;
139
140out_delete_dso:
141 dso__delete(dso);
142 return NULL;
143}
144
145static void dsos__fprintf(FILE *fp)
146{
147 struct dso *pos;
148
149 list_for_each_entry(pos, &dsos, node)
150 dso__fprintf(pos, fp);
151}
152
153static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
154{
155 return dso__find_symbol(dso, ip);
156}
157
158static int load_kernel(void)
159{
160 int err;
161
162 kernel_dso = dso__new("[kernel]", 0);
163 if (!kernel_dso)
164 return -1;
165
166 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
167 if (err <= 0) {
168 dso__delete(kernel_dso);
169 kernel_dso = NULL;
170 } else
171 dsos__add(kernel_dso);
172
173 vdso = dso__new("[vdso]", 0);
174 if (!vdso)
175 return -1;
176
177 vdso->find_symbol = vdso__find_symbol;
178
179 dsos__add(vdso);
180
181 return err;
182}
183
184struct map {
185 struct list_head node;
186 u64 start;
187 u64 end;
188 u64 pgoff;
189 u64 (*map_ip)(struct map *, u64);
190 struct dso *dso;
191};
192
193static u64 map__map_ip(struct map *map, u64 ip)
194{
195 return ip - map->start + map->pgoff;
196}
197
198static u64 vdso__map_ip(struct map *map __used, u64 ip)
199{
200 return ip;
201}
202
203static struct map *map__new(struct mmap_event *event)
204{
205 struct map *self = malloc(sizeof(*self));
206
207 if (self != NULL) {
208 const char *filename = event->filename;
209
210 self->start = event->start;
211 self->end = event->start + event->len;
212 self->pgoff = event->pgoff;
213
214 self->dso = dsos__findnew(filename);
215 if (self->dso == NULL)
216 goto out_delete;
217
218 if (self->dso == vdso)
219 self->map_ip = vdso__map_ip;
220 else
221 self->map_ip = map__map_ip;
222 }
223 return self;
224out_delete:
225 free(self);
226 return NULL;
227}
228
229static struct map *map__clone(struct map *self)
230{
231 struct map *map = malloc(sizeof(*self));
232
233 if (!map)
234 return NULL;
235
236 memcpy(map, self, sizeof(*self));
237
238 return map;
239}
240
241static int map__overlap(struct map *l, struct map *r)
242{
243 if (l->start > r->start) {
244 struct map *t = l;
245 l = r;
246 r = t;
247 }
248
249 if (l->end > r->start)
250 return 1;
251
252 return 0;
253}
254
255static size_t map__fprintf(struct map *self, FILE *fp)
256{
257 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
258 self->start, self->end, self->pgoff, self->dso->name);
259}
260
261 54
262struct thread { 55struct thread {
263 struct rb_node rb_node; 56 struct rb_node rb_node;
@@ -927,7 +720,7 @@ static int
927process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 720process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
928{ 721{
929 struct thread *thread = threads__findnew(event->mmap.pid); 722 struct thread *thread = threads__findnew(event->mmap.pid);
930 struct map *map = map__new(&event->mmap); 723 struct map *map = map__new(&event->mmap, NULL, 0);
931 724
932 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 725 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
933 (void *)(offset + head), 726 (void *)(offset + head),
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 89a5ddcd1ded..65b4115e417d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -15,6 +15,7 @@
15#include "util/string.h" 15#include "util/string.h"
16 16
17#include "util/header.h" 17#include "util/header.h"
18#include "util/event.h"
18 19
19#include <unistd.h> 20#include <unistd.h>
20#include <sched.h> 21#include <sched.h>
@@ -42,7 +43,6 @@ static int inherit = 1;
42static int force = 0; 43static int force = 0;
43static int append_file = 0; 44static int append_file = 0;
44static int call_graph = 0; 45static int call_graph = 0;
45static int verbose = 0;
46static int inherit_stat = 0; 46static int inherit_stat = 0;
47static int no_samples = 0; 47static int no_samples = 0;
48static int sample_address = 0; 48static int sample_address = 0;
@@ -62,24 +62,6 @@ static int file_new = 1;
62 62
63struct perf_header *header; 63struct perf_header *header;
64 64
65struct mmap_event {
66 struct perf_event_header header;
67 u32 pid;
68 u32 tid;
69 u64 start;
70 u64 len;
71 u64 pgoff;
72 char filename[PATH_MAX];
73};
74
75struct comm_event {
76 struct perf_event_header header;
77 u32 pid;
78 u32 tid;
79 char comm[16];
80};
81
82
83struct mmap_data { 65struct mmap_data {
84 int counter; 66 int counter;
85 void *base; 67 void *base;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b53a60fc12de..6321951fe1bf 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -17,6 +17,7 @@
17#include "util/string.h" 17#include "util/string.h"
18#include "util/callchain.h" 18#include "util/callchain.h"
19#include "util/strlist.h" 19#include "util/strlist.h"
20#include "util/values.h"
20 21
21#include "perf.h" 22#include "perf.h"
22#include "util/header.h" 23#include "util/header.h"
@@ -29,7 +30,6 @@
29#define SHOW_HV 4 30#define SHOW_HV 4
30 31
31static char const *input_name = "perf.data"; 32static char const *input_name = "perf.data";
32static char *vmlinux = NULL;
33 33
34static char default_sort_order[] = "comm,dso,symbol"; 34static char default_sort_order[] = "comm,dso,symbol";
35static char *sort_order = default_sort_order; 35static char *sort_order = default_sort_order;
@@ -45,14 +45,15 @@ static int dump_trace = 0;
45#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) 45#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
46#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) 46#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
47 47
48static int verbose;
49#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
50
51static int modules;
52
53static int full_paths; 48static int full_paths;
54static int show_nr_samples; 49static int show_nr_samples;
55 50
51static int show_threads;
52static struct perf_read_values show_threads_values;
53
54static char default_pretty_printing_style[] = "normal";
55static char *pretty_printing_style = default_pretty_printing_style;
56
56static unsigned long page_size; 57static unsigned long page_size;
57static unsigned long mmap_window = 32; 58static unsigned long mmap_window = 32;
58 59
@@ -66,6 +67,10 @@ static char callchain_default_opt[] = "fractal,0.5";
66 67
67static int callchain; 68static int callchain;
68 69
70static char __cwd[PATH_MAX];
71static char *cwd = __cwd;
72static int cwdlen;
73
69static 74static
70struct callchain_param callchain_param = { 75struct callchain_param callchain_param = {
71 .mode = CHAIN_GRAPH_REL, 76 .mode = CHAIN_GRAPH_REL,
@@ -74,59 +79,6 @@ struct callchain_param callchain_param = {
74 79
75static u64 sample_type; 80static u64 sample_type;
76 81
77struct ip_event {
78 struct perf_event_header header;
79 u64 ip;
80 u32 pid, tid;
81 unsigned char __more_data[];
82};
83
84struct mmap_event {
85 struct perf_event_header header;
86 u32 pid, tid;
87 u64 start;
88 u64 len;
89 u64 pgoff;
90 char filename[PATH_MAX];
91};
92
93struct comm_event {
94 struct perf_event_header header;
95 u32 pid, tid;
96 char comm[16];
97};
98
99struct fork_event {
100 struct perf_event_header header;
101 u32 pid, ppid;
102 u32 tid, ptid;
103};
104
105struct lost_event {
106 struct perf_event_header header;
107 u64 id;
108 u64 lost;
109};
110
111struct read_event {
112 struct perf_event_header header;
113 u32 pid,tid;
114 u64 value;
115 u64 time_enabled;
116 u64 time_running;
117 u64 id;
118};
119
120typedef union event_union {
121 struct perf_event_header header;
122 struct ip_event ip;
123 struct mmap_event mmap;
124 struct comm_event comm;
125 struct fork_event fork;
126 struct lost_event lost;
127 struct read_event read;
128} event_t;
129
130static int repsep_fprintf(FILE *fp, const char *fmt, ...) 82static int repsep_fprintf(FILE *fp, const char *fmt, ...)
131{ 83{
132 int n; 84 int n;
@@ -154,215 +106,6 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...)
154 return n; 106 return n;
155} 107}
156 108
157static LIST_HEAD(dsos);
158static struct dso *kernel_dso;
159static struct dso *vdso;
160static struct dso *hypervisor_dso;
161
162static void dsos__add(struct dso *dso)
163{
164 list_add_tail(&dso->node, &dsos);
165}
166
167static struct dso *dsos__find(const char *name)
168{
169 struct dso *pos;
170
171 list_for_each_entry(pos, &dsos, node)
172 if (strcmp(pos->name, name) == 0)
173 return pos;
174 return NULL;
175}
176
177static struct dso *dsos__findnew(const char *name)
178{
179 struct dso *dso = dsos__find(name);
180 int nr;
181
182 if (dso)
183 return dso;
184
185 dso = dso__new(name, 0);
186 if (!dso)
187 goto out_delete_dso;
188
189 nr = dso__load(dso, NULL, verbose);
190 if (nr < 0) {
191 eprintf("Failed to open: %s\n", name);
192 goto out_delete_dso;
193 }
194 if (!nr)
195 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
196
197 dsos__add(dso);
198
199 return dso;
200
201out_delete_dso:
202 dso__delete(dso);
203 return NULL;
204}
205
206static void dsos__fprintf(FILE *fp)
207{
208 struct dso *pos;
209
210 list_for_each_entry(pos, &dsos, node)
211 dso__fprintf(pos, fp);
212}
213
214static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
215{
216 return dso__find_symbol(dso, ip);
217}
218
219static int load_kernel(void)
220{
221 int err;
222
223 kernel_dso = dso__new("[kernel]", 0);
224 if (!kernel_dso)
225 return -1;
226
227 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
228 if (err <= 0) {
229 dso__delete(kernel_dso);
230 kernel_dso = NULL;
231 } else
232 dsos__add(kernel_dso);
233
234 vdso = dso__new("[vdso]", 0);
235 if (!vdso)
236 return -1;
237
238 vdso->find_symbol = vdso__find_symbol;
239
240 dsos__add(vdso);
241
242 hypervisor_dso = dso__new("[hypervisor]", 0);
243 if (!hypervisor_dso)
244 return -1;
245 dsos__add(hypervisor_dso);
246
247 return err;
248}
249
250static char __cwd[PATH_MAX];
251static char *cwd = __cwd;
252static int cwdlen;
253
254static int strcommon(const char *pathname)
255{
256 int n = 0;
257
258 while (n < cwdlen && pathname[n] == cwd[n])
259 ++n;
260
261 return n;
262}
263
264struct map {
265 struct list_head node;
266 u64 start;
267 u64 end;
268 u64 pgoff;
269 u64 (*map_ip)(struct map *, u64);
270 struct dso *dso;
271};
272
273static u64 map__map_ip(struct map *map, u64 ip)
274{
275 return ip - map->start + map->pgoff;
276}
277
278static u64 vdso__map_ip(struct map *map __used, u64 ip)
279{
280 return ip;
281}
282
283static inline int is_anon_memory(const char *filename)
284{
285 return strcmp(filename, "//anon") == 0;
286}
287
288static struct map *map__new(struct mmap_event *event)
289{
290 struct map *self = malloc(sizeof(*self));
291
292 if (self != NULL) {
293 const char *filename = event->filename;
294 char newfilename[PATH_MAX];
295 int anon;
296
297 if (cwd) {
298 int n = strcommon(filename);
299
300 if (n == cwdlen) {
301 snprintf(newfilename, sizeof(newfilename),
302 ".%s", filename + n);
303 filename = newfilename;
304 }
305 }
306
307 anon = is_anon_memory(filename);
308
309 if (anon) {
310 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
311 filename = newfilename;
312 }
313
314 self->start = event->start;
315 self->end = event->start + event->len;
316 self->pgoff = event->pgoff;
317
318 self->dso = dsos__findnew(filename);
319 if (self->dso == NULL)
320 goto out_delete;
321
322 if (self->dso == vdso || anon)
323 self->map_ip = vdso__map_ip;
324 else
325 self->map_ip = map__map_ip;
326 }
327 return self;
328out_delete:
329 free(self);
330 return NULL;
331}
332
333static struct map *map__clone(struct map *self)
334{
335 struct map *map = malloc(sizeof(*self));
336
337 if (!map)
338 return NULL;
339
340 memcpy(map, self, sizeof(*self));
341
342 return map;
343}
344
345static int map__overlap(struct map *l, struct map *r)
346{
347 if (l->start > r->start) {
348 struct map *t = l;
349 l = r;
350 r = t;
351 }
352
353 if (l->end > r->start)
354 return 1;
355
356 return 0;
357}
358
359static size_t map__fprintf(struct map *self, FILE *fp)
360{
361 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
362 self->start, self->end, self->pgoff, self->dso->name);
363}
364
365
366struct thread { 109struct thread {
367 struct rb_node rb_node; 110 struct rb_node rb_node;
368 struct list_head maps; 111 struct list_head maps;
@@ -1397,6 +1140,9 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1397 size_t ret = 0; 1140 size_t ret = 0;
1398 unsigned int width; 1141 unsigned int width;
1399 char *col_width = col_width_list_str; 1142 char *col_width = col_width_list_str;
1143 int raw_printing_style;
1144
1145 raw_printing_style = !strcmp(pretty_printing_style, "raw");
1400 1146
1401 init_rem_hits(); 1147 init_rem_hits();
1402 1148
@@ -1473,6 +1219,10 @@ print_entries:
1473 1219
1474 free(rem_sq_bracket); 1220 free(rem_sq_bracket);
1475 1221
1222 if (show_threads)
1223 perf_read_values_display(fp, &show_threads_values,
1224 raw_printing_style);
1225
1476 return ret; 1226 return ret;
1477} 1227}
1478 1228
@@ -1611,7 +1361,7 @@ static int
1611process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 1361process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1612{ 1362{
1613 struct thread *thread = threads__findnew(event->mmap.pid); 1363 struct thread *thread = threads__findnew(event->mmap.pid);
1614 struct map *map = map__new(&event->mmap); 1364 struct map *map = map__new(&event->mmap, cwd, cwdlen);
1615 1365
1616 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", 1366 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1617 (void *)(offset + head), 1367 (void *)(offset + head),
@@ -1760,6 +1510,16 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
1760{ 1510{
1761 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); 1511 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1762 1512
1513 if (show_threads) {
1514 char *name = attr ? __event_name(attr->type, attr->config)
1515 : "unknown";
1516 perf_read_values_add_value(&show_threads_values,
1517 event->read.pid, event->read.tid,
1518 event->read.id,
1519 name,
1520 event->read.value);
1521 }
1522
1763 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", 1523 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1764 (void *)(offset + head), 1524 (void *)(offset + head),
1765 (void *)(long)(event->header.size), 1525 (void *)(long)(event->header.size),
@@ -1841,6 +1601,9 @@ static int __cmd_report(void)
1841 1601
1842 register_idle_thread(); 1602 register_idle_thread();
1843 1603
1604 if (show_threads)
1605 perf_read_values_init(&show_threads_values);
1606
1844 input = open(input_name, O_RDONLY); 1607 input = open(input_name, O_RDONLY);
1845 if (input < 0) { 1608 if (input < 0) {
1846 fprintf(stderr, " failed to open file: %s", input_name); 1609 fprintf(stderr, " failed to open file: %s", input_name);
@@ -1995,6 +1758,9 @@ done:
1995 output__resort(total); 1758 output__resort(total);
1996 output__fprintf(stdout, total); 1759 output__fprintf(stdout, total);
1997 1760
1761 if (show_threads)
1762 perf_read_values_destroy(&show_threads_values);
1763
1998 return rc; 1764 return rc;
1999} 1765}
2000 1766
@@ -2068,6 +1834,10 @@ static const struct option options[] = {
2068 "load module symbols - WARNING: use only with -k and LIVE kernel"), 1834 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2069 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 1835 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2070 "Show a column with the number of samples"), 1836 "Show a column with the number of samples"),
1837 OPT_BOOLEAN('T', "threads", &show_threads,
1838 "Show per-thread event counters"),
1839 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1840 "pretty printing style key: normal raw"),
2071 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1841 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
2072 "sort by key(s): pid, comm, dso, symbol, parent"), 1842 "sort by key(s): pid, comm, dso, symbol, parent"),
2073 OPT_BOOLEAN('P', "full-paths", &full_paths, 1843 OPT_BOOLEAN('P', "full-paths", &full_paths,
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index b4b06c7903e1..4b9dd4af61a6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -63,7 +63,6 @@ static struct perf_counter_attr default_attrs[] = {
63#define MAX_RUN 100 63#define MAX_RUN 100
64 64
65static int system_wide = 0; 65static int system_wide = 0;
66static int verbose = 0;
67static unsigned int nr_cpus = 0; 66static unsigned int nr_cpus = 0;
68static int run_idx = 0; 67static int run_idx = 0;
69 68
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7de28ce9ca26..9a6dbbff9a9f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -68,8 +68,6 @@ static int group = 0;
68static unsigned int page_size; 68static unsigned int page_size;
69static unsigned int mmap_pages = 16; 69static unsigned int mmap_pages = 16;
70static int freq = 0; 70static int freq = 0;
71static int verbose = 0;
72static char *vmlinux = NULL;
73 71
74static int delay_secs = 2; 72static int delay_secs = 2;
75static int zero; 73static int zero;
@@ -338,8 +336,6 @@ static void show_details(struct sym_entry *syme)
338 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 336 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
339} 337}
340 338
341struct dso *kernel_dso;
342
343/* 339/*
344 * Symbols will be added here in record_ip and will get out 340 * Symbols will be added here in record_ip and will get out
345 * after decayed. 341 * after decayed.
@@ -937,26 +933,6 @@ static void mmap_read_counter(struct mmap_data *md)
937 last_read = this_read; 933 last_read = this_read;
938 934
939 for (; old != head;) { 935 for (; old != head;) {
940 struct ip_event {
941 struct perf_event_header header;
942 u64 ip;
943 u32 pid, target_pid;
944 };
945 struct mmap_event {
946 struct perf_event_header header;
947 u32 pid, target_pid;
948 u64 start;
949 u64 len;
950 u64 pgoff;
951 char filename[PATH_MAX];
952 };
953
954 typedef union event_union {
955 struct perf_event_header header;
956 struct ip_event ip;
957 struct mmap_event mmap;
958 } event_t;
959
960 event_t *event = (event_t *)&data[old & md->mask]; 936 event_t *event = (event_t *)&data[old & md->mask];
961 937
962 event_t event_copy; 938 event_t event_copy;
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 51d168230ee7..3a63e41fb44e 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -22,5 +22,6 @@ extern int cmd_stat(int argc, const char **argv, const char *prefix);
22extern int cmd_top(int argc, const char **argv, const char *prefix); 22extern int cmd_top(int argc, const char **argv, const char *prefix);
23extern int cmd_version(int argc, const char **argv, const char *prefix); 23extern int cmd_version(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix); 24extern int cmd_list(int argc, const char **argv, const char *prefix);
25extern int cmd_trace(int argc, const char **argv, const char *prefix);
25 26
26#endif 27#endif
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index e5148e2b6134..f5509213f030 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -48,6 +48,7 @@
48 48
49#include "../../include/linux/perf_counter.h" 49#include "../../include/linux/perf_counter.h"
50#include "util/types.h" 50#include "util/types.h"
51#include "util/debug.h"
51 52
52/* 53/*
53 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all 54 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index a926ae4f5a16..43cf3ea9e088 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -4,6 +4,7 @@
4#include "../perf.h" 4#include "../perf.h"
5#include <linux/list.h> 5#include <linux/list.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include "util.h"
7#include "symbol.h" 8#include "symbol.h"
8 9
9enum chain_mode { 10enum chain_mode {
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
new file mode 100644
index 000000000000..7cb8464abe61
--- /dev/null
+++ b/tools/perf/util/debug.c
@@ -0,0 +1,22 @@
1/* For general debugging purposes */
2
3#include "../perf.h"
4#include <string.h>
5#include <stdarg.h>
6#include <stdio.h>
7
8int verbose = 0;
9
10int eprintf(const char *fmt, ...)
11{
12 va_list args;
13 int ret = 0;
14
15 if (verbose) {
16 va_start(args, fmt);
17 ret = vfprintf(stderr, fmt, args);
18 va_end(args);
19 }
20
21 return ret;
22}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
new file mode 100644
index 000000000000..2ae9090108d3
--- /dev/null
+++ b/tools/perf/util/debug.h
@@ -0,0 +1,5 @@
1/* For debugging general purposes */
2
3extern int verbose;
4
5int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
new file mode 100644
index 000000000000..fa7c50b654e1
--- /dev/null
+++ b/tools/perf/util/event.h
@@ -0,0 +1,90 @@
1#ifndef __PERF_EVENT_H
2#define __PERF_EVENT_H
3#include "../perf.h"
4#include "util.h"
5#include <linux/list.h>
6
7/*
8 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
9 */
10struct ip_event {
11 struct perf_event_header header;
12 u64 ip;
13 u32 pid, tid;
14 unsigned char __more_data[];
15};
16
17struct mmap_event {
18 struct perf_event_header header;
19 u32 pid, tid;
20 u64 start;
21 u64 len;
22 u64 pgoff;
23 char filename[PATH_MAX];
24};
25
26struct comm_event {
27 struct perf_event_header header;
28 u32 pid, tid;
29 char comm[16];
30};
31
32struct fork_event {
33 struct perf_event_header header;
34 u32 pid, ppid;
35 u32 tid, ptid;
36};
37
38struct lost_event {
39 struct perf_event_header header;
40 u64 id;
41 u64 lost;
42};
43
44/*
45 * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
46 */
47struct read_event {
48 struct perf_event_header header;
49 u32 pid,tid;
50 u64 value;
51 u64 time_enabled;
52 u64 time_running;
53 u64 id;
54};
55
56typedef union event_union {
57 struct perf_event_header header;
58 struct ip_event ip;
59 struct mmap_event mmap;
60 struct comm_event comm;
61 struct fork_event fork;
62 struct lost_event lost;
63 struct read_event read;
64} event_t;
65
66struct map {
67 struct list_head node;
68 u64 start;
69 u64 end;
70 u64 pgoff;
71 u64 (*map_ip)(struct map *, u64);
72 struct dso *dso;
73};
74
75static inline u64 map__map_ip(struct map *map, u64 ip)
76{
77 return ip - map->start + map->pgoff;
78}
79
80static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
81{
82 return ip;
83}
84
85struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
86struct map *map__clone(struct map *self);
87int map__overlap(struct map *l, struct map *r);
88size_t map__fprintf(struct map *self, FILE *fp);
89
90#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
new file mode 100644
index 000000000000..804e02382739
--- /dev/null
+++ b/tools/perf/util/map.c
@@ -0,0 +1,97 @@
1#include "event.h"
2#include "symbol.h"
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6
7static inline int is_anon_memory(const char *filename)
8{
9 return strcmp(filename, "//anon") == 0;
10}
11
12static int strcommon(const char *pathname, char *cwd, int cwdlen)
13{
14 int n = 0;
15
16 while (n < cwdlen && pathname[n] == cwd[n])
17 ++n;
18
19 return n;
20}
21
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
23{
24 struct map *self = malloc(sizeof(*self));
25
26 if (self != NULL) {
27 const char *filename = event->filename;
28 char newfilename[PATH_MAX];
29 int anon;
30
31 if (cwd) {
32 int n = strcommon(filename, cwd, cwdlen);
33
34 if (n == cwdlen) {
35 snprintf(newfilename, sizeof(newfilename),
36 ".%s", filename + n);
37 filename = newfilename;
38 }
39 }
40
41 anon = is_anon_memory(filename);
42
43 if (anon) {
44 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
45 filename = newfilename;
46 }
47
48 self->start = event->start;
49 self->end = event->start + event->len;
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete;
55
56 if (self->dso == vdso || anon)
57 self->map_ip = vdso__map_ip;
58 else
59 self->map_ip = map__map_ip;
60 }
61 return self;
62out_delete:
63 free(self);
64 return NULL;
65}
66
67struct map *map__clone(struct map *self)
68{
69 struct map *map = malloc(sizeof(*self));
70
71 if (!map)
72 return NULL;
73
74 memcpy(map, self, sizeof(*self));
75
76 return map;
77}
78
79int map__overlap(struct map *l, struct map *r)
80{
81 if (l->start > r->start) {
82 struct map *t = l;
83 l = r;
84 r = t;
85 }
86
87 if (l->end > r->start)
88 return 1;
89
90 return 0;
91}
92
93size_t map__fprintf(struct map *self, FILE *fp)
94{
95 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
96 self->start, self->end, self->pgoff, self->dso->name);
97}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5c0f42e6b33b..0b9862351260 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -924,6 +924,103 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
924 return err; 924 return err;
925} 925}
926 926
927LIST_HEAD(dsos);
928struct dso *kernel_dso;
929struct dso *vdso;
930struct dso *hypervisor_dso;
931
932char *vmlinux = "vmlinux";
933int modules;
934
935static void dsos__add(struct dso *dso)
936{
937 list_add_tail(&dso->node, &dsos);
938}
939
940static struct dso *dsos__find(const char *name)
941{
942 struct dso *pos;
943
944 list_for_each_entry(pos, &dsos, node)
945 if (strcmp(pos->name, name) == 0)
946 return pos;
947 return NULL;
948}
949
950struct dso *dsos__findnew(const char *name)
951{
952 struct dso *dso = dsos__find(name);
953 int nr;
954
955 if (dso)
956 return dso;
957
958 dso = dso__new(name, 0);
959 if (!dso)
960 goto out_delete_dso;
961
962 nr = dso__load(dso, NULL, verbose);
963 if (nr < 0) {
964 eprintf("Failed to open: %s\n", name);
965 goto out_delete_dso;
966 }
967 if (!nr)
968 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
969
970 dsos__add(dso);
971
972 return dso;
973
974out_delete_dso:
975 dso__delete(dso);
976 return NULL;
977}
978
979void dsos__fprintf(FILE *fp)
980{
981 struct dso *pos;
982
983 list_for_each_entry(pos, &dsos, node)
984 dso__fprintf(pos, fp);
985}
986
987static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
988{
989 return dso__find_symbol(dso, ip);
990}
991
992int load_kernel(void)
993{
994 int err;
995
996 kernel_dso = dso__new("[kernel]", 0);
997 if (!kernel_dso)
998 return -1;
999
1000 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
1001 if (err <= 0) {
1002 dso__delete(kernel_dso);
1003 kernel_dso = NULL;
1004 } else
1005 dsos__add(kernel_dso);
1006
1007 vdso = dso__new("[vdso]", 0);
1008 if (!vdso)
1009 return -1;
1010
1011 vdso->find_symbol = vdso__find_symbol;
1012
1013 dsos__add(vdso);
1014
1015 hypervisor_dso = dso__new("[hypervisor]", 0);
1016 if (!hypervisor_dso)
1017 return -1;
1018 dsos__add(hypervisor_dso);
1019
1020 return err;
1021}
1022
1023
927void symbol__init(void) 1024void symbol__init(void)
928{ 1025{
929 elf_version(EV_CURRENT); 1026 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b53bf0125c1b..48b8e5759af9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -6,6 +6,7 @@
6#include <linux/list.h> 6#include <linux/list.h>
7#include <linux/rbtree.h> 7#include <linux/rbtree.h>
8#include "module.h" 8#include "module.h"
9#include "event.h"
9 10
10#ifdef HAVE_CPLUS_DEMANGLE 11#ifdef HAVE_CPLUS_DEMANGLE
11extern char *cplus_demangle(const char *, int); 12extern char *cplus_demangle(const char *, int);
@@ -72,9 +73,20 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
72 symbol_filter_t filter, int verbose, int modules); 73 symbol_filter_t filter, int verbose, int modules);
73int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); 74int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
74int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 75int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
76struct dso *dsos__findnew(const char *name);
77void dsos__fprintf(FILE *fp);
75 78
76size_t dso__fprintf(struct dso *self, FILE *fp); 79size_t dso__fprintf(struct dso *self, FILE *fp);
77char dso__symtab_origin(const struct dso *self); 80char dso__symtab_origin(const struct dso *self);
78 81
82int load_kernel(void);
83
79void symbol__init(void); 84void symbol__init(void);
85
86extern struct list_head dsos;
87extern struct dso *kernel_dso;
88extern struct dso *vdso;
89extern struct dso *hypervisor_dso;
90extern char *vmlinux;
91extern int modules;
80#endif /* _PERF_SYMBOL_ */ 92#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 68fe157d72fb..d61a6f037631 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -83,6 +83,7 @@
83#include <inttypes.h> 83#include <inttypes.h>
84#include "../../../include/linux/magic.h" 84#include "../../../include/linux/magic.h"
85 85
86
86#ifndef NO_ICONV 87#ifndef NO_ICONV
87#include <iconv.h> 88#include <iconv.h>
88#endif 89#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
new file mode 100644
index 000000000000..614cfaf4712a
--- /dev/null
+++ b/tools/perf/util/values.c
@@ -0,0 +1,231 @@
1#include <stdlib.h>
2
3#include "util.h"
4#include "values.h"
5
6void perf_read_values_init(struct perf_read_values *values)
7{
8 values->threads_max = 16;
9 values->pid = malloc(values->threads_max * sizeof(*values->pid));
10 values->tid = malloc(values->threads_max * sizeof(*values->tid));
11 values->value = malloc(values->threads_max * sizeof(*values->value));
12 if (!values->pid || !values->tid || !values->value)
13 die("failed to allocate read_values threads arrays");
14 values->threads = 0;
15
16 values->counters_max = 16;
17 values->counterrawid = malloc(values->counters_max
18 * sizeof(*values->counterrawid));
19 values->countername = malloc(values->counters_max
20 * sizeof(*values->countername));
21 if (!values->counterrawid || !values->countername)
22 die("failed to allocate read_values counters arrays");
23 values->counters = 0;
24}
25
26void perf_read_values_destroy(struct perf_read_values *values)
27{
28 int i;
29
30 if (!values->threads_max || !values->counters_max)
31 return;
32
33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]);
35 free(values->pid);
36 free(values->tid);
37 free(values->counterrawid);
38 for (i = 0; i < values->counters; i++)
39 free(values->countername[i]);
40 free(values->countername);
41}
42
43static void perf_read_values__enlarge_threads(struct perf_read_values *values)
44{
45 values->threads_max *= 2;
46 values->pid = realloc(values->pid,
47 values->threads_max * sizeof(*values->pid));
48 values->tid = realloc(values->tid,
49 values->threads_max * sizeof(*values->tid));
50 values->value = realloc(values->value,
51 values->threads_max * sizeof(*values->value));
52 if (!values->pid || !values->tid || !values->value)
53 die("failed to enlarge read_values threads arrays");
54}
55
56static int perf_read_values__findnew_thread(struct perf_read_values *values,
57 u32 pid, u32 tid)
58{
59 int i;
60
61 for (i = 0; i < values->threads; i++)
62 if (values->pid[i] == pid && values->tid[i] == tid)
63 return i;
64
65 if (values->threads == values->threads_max)
66 perf_read_values__enlarge_threads(values);
67
68 i = values->threads++;
69 values->pid[i] = pid;
70 values->tid[i] = tid;
71 values->value[i] = malloc(values->counters_max * sizeof(**values->value));
72 if (!values->value[i])
73 die("failed to allocate read_values counters array");
74
75 return i;
76}
77
78static void perf_read_values__enlarge_counters(struct perf_read_values *values)
79{
80 int i;
81
82 values->counters_max *= 2;
83 values->counterrawid = realloc(values->counterrawid,
84 values->counters_max * sizeof(*values->counterrawid));
85 values->countername = realloc(values->countername,
86 values->counters_max * sizeof(*values->countername));
87 if (!values->counterrawid || !values->countername)
88 die("failed to enlarge read_values counters arrays");
89
90 for (i = 0; i < values->threads; i++) {
91 values->value[i] = realloc(values->value[i],
92 values->counters_max * sizeof(**values->value));
93 if (!values->value[i])
94 die("failed to enlarge read_values counters arrays");
95 }
96}
97
98static int perf_read_values__findnew_counter(struct perf_read_values *values,
99 u64 rawid, char *name)
100{
101 int i;
102
103 for (i = 0; i < values->counters; i++)
104 if (values->counterrawid[i] == rawid)
105 return i;
106
107 if (values->counters == values->counters_max)
108 perf_read_values__enlarge_counters(values);
109
110 i = values->counters++;
111 values->counterrawid[i] = rawid;
112 values->countername[i] = strdup(name);
113
114 return i;
115}
116
117void perf_read_values_add_value(struct perf_read_values *values,
118 u32 pid, u32 tid,
119 u64 rawid, char *name, u64 value)
120{
121 int tindex, cindex;
122
123 tindex = perf_read_values__findnew_thread(values, pid, tid);
124 cindex = perf_read_values__findnew_counter(values, rawid, name);
125
126 values->value[tindex][cindex] = value;
127}
128
129static void perf_read_values__display_pretty(FILE *fp,
130 struct perf_read_values *values)
131{
132 int i, j;
133 int pidwidth, tidwidth;
134 int *counterwidth;
135
136 counterwidth = malloc(values->counters * sizeof(*counterwidth));
137 if (!counterwidth)
138 die("failed to allocate counterwidth array");
139 tidwidth = 3;
140 pidwidth = 3;
141 for (j = 0; j < values->counters; j++)
142 counterwidth[j] = strlen(values->countername[j]);
143 for (i = 0; i < values->threads; i++) {
144 int width;
145
146 width = snprintf(NULL, 0, "%d", values->pid[i]);
147 if (width > pidwidth)
148 pidwidth = width;
149 width = snprintf(NULL, 0, "%d", values->tid[i]);
150 if (width > tidwidth)
151 tidwidth = width;
152 for (j = 0; j < values->counters; j++) {
153 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
154 if (width > counterwidth[j])
155 counterwidth[j] = width;
156 }
157 }
158
159 fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
160 for (j = 0; j < values->counters; j++)
161 fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
162 fprintf(fp, "\n");
163
164 for (i = 0; i < values->threads; i++) {
165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
166 tidwidth, values->tid[i]);
167 for (j = 0; j < values->counters; j++)
168 fprintf(fp, " %*Lu",
169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n");
171 }
172}
173
174static void perf_read_values__display_raw(FILE *fp,
175 struct perf_read_values *values)
176{
177 int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
178 int i, j;
179
180 tidwidth = 3; /* TID */
181 pidwidth = 3; /* PID */
182 namewidth = 4; /* "Name" */
183 rawwidth = 3; /* "Raw" */
184 countwidth = 5; /* "Count" */
185
186 for (i = 0; i < values->threads; i++) {
187 width = snprintf(NULL, 0, "%d", values->pid[i]);
188 if (width > pidwidth)
189 pidwidth = width;
190 width = snprintf(NULL, 0, "%d", values->tid[i]);
191 if (width > tidwidth)
192 tidwidth = width;
193 }
194 for (j = 0; j < values->counters; j++) {
195 width = strlen(values->countername[j]);
196 if (width > namewidth)
197 namewidth = width;
198 width = snprintf(NULL, 0, "%llx", values->counterrawid[j]);
199 if (width > rawwidth)
200 rawwidth = width;
201 }
202 for (i = 0; i < values->threads; i++) {
203 for (j = 0; j < values->counters; j++) {
204 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
205 if (width > countwidth)
206 countwidth = width;
207 }
208 }
209
210 fprintf(fp, "# %*s %*s %*s %*s %*s\n",
211 pidwidth, "PID", tidwidth, "TID",
212 namewidth, "Name", rawwidth, "Raw",
213 countwidth, "Count");
214 for (i = 0; i < values->threads; i++)
215 for (j = 0; j < values->counters; j++)
216 fprintf(fp, " %*d %*d %*s %*llx %*Lu\n",
217 pidwidth, values->pid[i],
218 tidwidth, values->tid[i],
219 namewidth, values->countername[j],
220 rawwidth, values->counterrawid[j],
221 countwidth, values->value[i][j]);
222}
223
224void perf_read_values_display(FILE *fp, struct perf_read_values *values,
225 int raw)
226{
227 if (raw)
228 perf_read_values__display_raw(fp, values);
229 else
230 perf_read_values__display_pretty(fp, values);
231}
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
new file mode 100644
index 000000000000..f8960fde0547
--- /dev/null
+++ b/tools/perf/util/values.h
@@ -0,0 +1,27 @@
1#ifndef _PERF_VALUES_H
2#define _PERF_VALUES_H
3
4#include "types.h"
5
6struct perf_read_values {
7 int threads;
8 int threads_max;
9 u32 *pid, *tid;
10 int counters;
11 int counters_max;
12 u64 *counterrawid;
13 char **countername;
14 u64 **value;
15};
16
17void perf_read_values_init(struct perf_read_values *values);
18void perf_read_values_destroy(struct perf_read_values *values);
19
20void perf_read_values_add_value(struct perf_read_values *values,
21 u32 pid, u32 tid,
22 u64 rawid, char *name, u64 value);
23
24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw);
26
27#endif /* _PERF_VALUES_H */