aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/perf_event.h13
-rw-r--r--arch/x86/kernel/cpu/perf_event.c185
-rw-r--r--include/trace/ftrace.h15
-rw-r--r--kernel/trace/ring_buffer.c15
-rw-r--r--kernel/trace/trace_events.c24
-rw-r--r--kernel/trace/trace_export.c25
-rw-r--r--kernel/trace/trace_syscalls.c20
-rw-r--r--tools/perf/Makefile10
-rw-r--r--tools/perf/builtin-annotate.c501
-rw-r--r--tools/perf/builtin-record.c73
-rw-r--r--tools/perf/builtin-report.c840
-rw-r--r--tools/perf/builtin-sched.c276
-rw-r--r--tools/perf/builtin-top.c155
-rw-r--r--tools/perf/builtin-trace.c153
-rw-r--r--tools/perf/util/cache.h6
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/data_map.c222
-rw-r--r--tools/perf/util/data_map.h31
-rw-r--r--tools/perf/util/debug.h4
-rw-r--r--tools/perf/util/event.h15
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c50
-rw-r--r--tools/perf/util/header.h10
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/hist.c210
-rw-r--r--tools/perf/util/hist.h50
-rw-r--r--tools/perf/util/levenshtein.h6
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.h6
-rw-r--r--tools/perf/util/parse-options.h6
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/sigchain.h6
-rw-r--r--tools/perf/util/sort.c276
-rw-r--r--tools/perf/util/sort.h90
-rw-r--r--tools/perf/util/strbuf.h6
-rw-r--r--tools/perf/util/string.c11
-rw-r--r--tools/perf/util/string.h7
-rw-r--r--tools/perf/util/strlist.h6
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol.c721
-rw-r--r--tools/perf/util/symbol.h24
-rw-r--r--tools/perf/util/thread.c129
-rw-r--r--tools/perf/util/thread.h21
-rw-r--r--tools/perf/util/trace-event-info.c6
-rw-r--r--tools/perf/util/trace-event-parse.c52
-rw-r--r--tools/perf/util/trace-event-read.c7
-rw-r--r--tools/perf/util/trace-event.h16
-rw-r--r--tools/perf/util/types.h6
-rw-r--r--tools/perf/util/values.h6
52 files changed, 2366 insertions, 2581 deletions
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index ad7ce3fd5065..8d9f8548a870 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -28,9 +28,20 @@
28 */ 28 */
29#define ARCH_PERFMON_EVENT_MASK 0xffff 29#define ARCH_PERFMON_EVENT_MASK 0xffff
30 30
31/*
32 * filter mask to validate fixed counter events.
33 * the following filters disqualify for fixed counters:
34 * - inv
35 * - edge
36 * - cnt-mask
37 * The other filters are supported by fixed counters.
38 * The any-thread option is supported starting with v3.
39 */
40#define ARCH_PERFMON_EVENT_FILTER_MASK 0xff840000
41
31#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c 42#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c
32#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) 43#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
33#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0 44#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0
34#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \ 45#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
35 (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) 46 (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
36 47
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index b5801c311846..2e20bca3cca1 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -77,6 +77,18 @@ struct cpu_hw_events {
77 struct debug_store *ds; 77 struct debug_store *ds;
78}; 78};
79 79
80struct event_constraint {
81 unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
82 int code;
83};
84
85#define EVENT_CONSTRAINT(c, m) { .code = (c), .idxmsk[0] = (m) }
86#define EVENT_CONSTRAINT_END { .code = 0, .idxmsk[0] = 0 }
87
88#define for_each_event_constraint(e, c) \
89 for ((e) = (c); (e)->idxmsk[0]; (e)++)
90
91
80/* 92/*
81 * struct x86_pmu - generic x86 pmu 93 * struct x86_pmu - generic x86 pmu
82 */ 94 */
@@ -102,6 +114,8 @@ struct x86_pmu {
102 u64 intel_ctrl; 114 u64 intel_ctrl;
103 void (*enable_bts)(u64 config); 115 void (*enable_bts)(u64 config);
104 void (*disable_bts)(void); 116 void (*disable_bts)(void);
117 int (*get_event_idx)(struct cpu_hw_events *cpuc,
118 struct hw_perf_event *hwc);
105}; 119};
106 120
107static struct x86_pmu x86_pmu __read_mostly; 121static struct x86_pmu x86_pmu __read_mostly;
@@ -110,6 +124,8 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
110 .enabled = 1, 124 .enabled = 1,
111}; 125};
112 126
127static const struct event_constraint *event_constraints;
128
113/* 129/*
114 * Not sure about some of these 130 * Not sure about some of these
115 */ 131 */
@@ -155,6 +171,16 @@ static u64 p6_pmu_raw_event(u64 hw_event)
155 return hw_event & P6_EVNTSEL_MASK; 171 return hw_event & P6_EVNTSEL_MASK;
156} 172}
157 173
174static const struct event_constraint intel_p6_event_constraints[] =
175{
176 EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */
177 EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
178 EVENT_CONSTRAINT(0x11, 0x1), /* FP_ASSIST */
179 EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
180 EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
181 EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
182 EVENT_CONSTRAINT_END
183};
158 184
159/* 185/*
160 * Intel PerfMon v3. Used on Core2 and later. 186 * Intel PerfMon v3. Used on Core2 and later.
@@ -170,6 +196,35 @@ static const u64 intel_perfmon_event_map[] =
170 [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, 196 [PERF_COUNT_HW_BUS_CYCLES] = 0x013c,
171}; 197};
172 198
199static const struct event_constraint intel_core_event_constraints[] =
200{
201 EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
202 EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
203 EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
204 EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
205 EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
206 EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */
207 EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */
208 EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */
209 EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */
210 EVENT_CONSTRAINT_END
211};
212
213static const struct event_constraint intel_nehalem_event_constraints[] =
214{
215 EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */
216 EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */
217 EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */
218 EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */
219 EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */
220 EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */
221 EVENT_CONSTRAINT(0x51, 0x3), /* L1D */
222 EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
223 EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */
224 EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */
225 EVENT_CONSTRAINT_END
226};
227
173static u64 intel_pmu_event_map(int hw_event) 228static u64 intel_pmu_event_map(int hw_event)
174{ 229{
175 return intel_perfmon_event_map[hw_event]; 230 return intel_perfmon_event_map[hw_event];
@@ -469,7 +524,7 @@ static u64 intel_pmu_raw_event(u64 hw_event)
469#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL 524#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL
470#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL 525#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL
471#define CORE_EVNTSEL_INV_MASK 0x00800000ULL 526#define CORE_EVNTSEL_INV_MASK 0x00800000ULL
472#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL 527#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL
473 528
474#define CORE_EVNTSEL_MASK \ 529#define CORE_EVNTSEL_MASK \
475 (CORE_EVNTSEL_EVENT_MASK | \ 530 (CORE_EVNTSEL_EVENT_MASK | \
@@ -932,6 +987,8 @@ static int __hw_perf_event_init(struct perf_event *event)
932 */ 987 */
933 hwc->config = ARCH_PERFMON_EVENTSEL_INT; 988 hwc->config = ARCH_PERFMON_EVENTSEL_INT;
934 989
990 hwc->idx = -1;
991
935 /* 992 /*
936 * Count user and OS events unless requested not to. 993 * Count user and OS events unless requested not to.
937 */ 994 */
@@ -1334,8 +1391,7 @@ static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx)
1334 x86_pmu_enable_event(hwc, idx); 1391 x86_pmu_enable_event(hwc, idx);
1335} 1392}
1336 1393
1337static int 1394static int fixed_mode_idx(struct hw_perf_event *hwc)
1338fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
1339{ 1395{
1340 unsigned int hw_event; 1396 unsigned int hw_event;
1341 1397
@@ -1349,6 +1405,12 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
1349 if (!x86_pmu.num_events_fixed) 1405 if (!x86_pmu.num_events_fixed)
1350 return -1; 1406 return -1;
1351 1407
1408 /*
1409 * fixed counters do not take all possible filters
1410 */
1411 if (hwc->config & ARCH_PERFMON_EVENT_FILTER_MASK)
1412 return -1;
1413
1352 if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS))) 1414 if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
1353 return X86_PMC_IDX_FIXED_INSTRUCTIONS; 1415 return X86_PMC_IDX_FIXED_INSTRUCTIONS;
1354 if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES))) 1416 if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES)))
@@ -1360,22 +1422,57 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
1360} 1422}
1361 1423
1362/* 1424/*
1363 * Find a PMC slot for the freshly enabled / scheduled in event: 1425 * generic counter allocator: get next free counter
1364 */ 1426 */
1365static int x86_pmu_enable(struct perf_event *event) 1427static int
1428gen_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
1429{
1430 int idx;
1431
1432 idx = find_first_zero_bit(cpuc->used_mask, x86_pmu.num_events);
1433 return idx == x86_pmu.num_events ? -1 : idx;
1434}
1435
1436/*
1437 * intel-specific counter allocator: check event constraints
1438 */
1439static int
1440intel_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
1441{
1442 const struct event_constraint *event_constraint;
1443 int i, code;
1444
1445 if (!event_constraints)
1446 goto skip;
1447
1448 code = hwc->config & CORE_EVNTSEL_EVENT_MASK;
1449
1450 for_each_event_constraint(event_constraint, event_constraints) {
1451 if (code == event_constraint->code) {
1452 for_each_bit(i, event_constraint->idxmsk, X86_PMC_IDX_MAX) {
1453 if (!test_and_set_bit(i, cpuc->used_mask))
1454 return i;
1455 }
1456 return -1;
1457 }
1458 }
1459skip:
1460 return gen_get_event_idx(cpuc, hwc);
1461}
1462
1463static int
1464x86_schedule_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
1366{ 1465{
1367 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
1368 struct hw_perf_event *hwc = &event->hw;
1369 int idx; 1466 int idx;
1370 1467
1371 idx = fixed_mode_idx(event, hwc); 1468 idx = fixed_mode_idx(hwc);
1372 if (idx == X86_PMC_IDX_FIXED_BTS) { 1469 if (idx == X86_PMC_IDX_FIXED_BTS) {
1373 /* BTS is already occupied. */ 1470 /* BTS is already occupied. */
1374 if (test_and_set_bit(idx, cpuc->used_mask)) 1471 if (test_and_set_bit(idx, cpuc->used_mask))
1375 return -EAGAIN; 1472 return -EAGAIN;
1376 1473
1377 hwc->config_base = 0; 1474 hwc->config_base = 0;
1378 hwc->event_base = 0; 1475 hwc->event_base = 0;
1379 hwc->idx = idx; 1476 hwc->idx = idx;
1380 } else if (idx >= 0) { 1477 } else if (idx >= 0) {
1381 /* 1478 /*
@@ -1396,20 +1493,35 @@ static int x86_pmu_enable(struct perf_event *event)
1396 } else { 1493 } else {
1397 idx = hwc->idx; 1494 idx = hwc->idx;
1398 /* Try to get the previous generic event again */ 1495 /* Try to get the previous generic event again */
1399 if (test_and_set_bit(idx, cpuc->used_mask)) { 1496 if (idx == -1 || test_and_set_bit(idx, cpuc->used_mask)) {
1400try_generic: 1497try_generic:
1401 idx = find_first_zero_bit(cpuc->used_mask, 1498 idx = x86_pmu.get_event_idx(cpuc, hwc);
1402 x86_pmu.num_events); 1499 if (idx == -1)
1403 if (idx == x86_pmu.num_events)
1404 return -EAGAIN; 1500 return -EAGAIN;
1405 1501
1406 set_bit(idx, cpuc->used_mask); 1502 set_bit(idx, cpuc->used_mask);
1407 hwc->idx = idx; 1503 hwc->idx = idx;
1408 } 1504 }
1409 hwc->config_base = x86_pmu.eventsel; 1505 hwc->config_base = x86_pmu.eventsel;
1410 hwc->event_base = x86_pmu.perfctr; 1506 hwc->event_base = x86_pmu.perfctr;
1411 } 1507 }
1412 1508
1509 return idx;
1510}
1511
1512/*
1513 * Find a PMC slot for the freshly enabled / scheduled in event:
1514 */
1515static int x86_pmu_enable(struct perf_event *event)
1516{
1517 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
1518 struct hw_perf_event *hwc = &event->hw;
1519 int idx;
1520
1521 idx = x86_schedule_event(cpuc, hwc);
1522 if (idx < 0)
1523 return idx;
1524
1413 perf_events_lapic_init(); 1525 perf_events_lapic_init();
1414 1526
1415 x86_pmu.disable(hwc, idx); 1527 x86_pmu.disable(hwc, idx);
@@ -1877,6 +1989,7 @@ static struct x86_pmu p6_pmu = {
1877 */ 1989 */
1878 .event_bits = 32, 1990 .event_bits = 32,
1879 .event_mask = (1ULL << 32) - 1, 1991 .event_mask = (1ULL << 32) - 1,
1992 .get_event_idx = intel_get_event_idx,
1880}; 1993};
1881 1994
1882static struct x86_pmu intel_pmu = { 1995static struct x86_pmu intel_pmu = {
@@ -1900,6 +2013,7 @@ static struct x86_pmu intel_pmu = {
1900 .max_period = (1ULL << 31) - 1, 2013 .max_period = (1ULL << 31) - 1,
1901 .enable_bts = intel_pmu_enable_bts, 2014 .enable_bts = intel_pmu_enable_bts,
1902 .disable_bts = intel_pmu_disable_bts, 2015 .disable_bts = intel_pmu_disable_bts,
2016 .get_event_idx = intel_get_event_idx,
1903}; 2017};
1904 2018
1905static struct x86_pmu amd_pmu = { 2019static struct x86_pmu amd_pmu = {
@@ -1920,6 +2034,7 @@ static struct x86_pmu amd_pmu = {
1920 .apic = 1, 2034 .apic = 1,
1921 /* use highest bit to detect overflow */ 2035 /* use highest bit to detect overflow */
1922 .max_period = (1ULL << 47) - 1, 2036 .max_period = (1ULL << 47) - 1,
2037 .get_event_idx = gen_get_event_idx,
1923}; 2038};
1924 2039
1925static int p6_pmu_init(void) 2040static int p6_pmu_init(void)
@@ -1932,10 +2047,12 @@ static int p6_pmu_init(void)
1932 case 7: 2047 case 7:
1933 case 8: 2048 case 8:
1934 case 11: /* Pentium III */ 2049 case 11: /* Pentium III */
2050 event_constraints = intel_p6_event_constraints;
1935 break; 2051 break;
1936 case 9: 2052 case 9:
1937 case 13: 2053 case 13:
1938 /* Pentium M */ 2054 /* Pentium M */
2055 event_constraints = intel_p6_event_constraints;
1939 break; 2056 break;
1940 default: 2057 default:
1941 pr_cont("unsupported p6 CPU model %d ", 2058 pr_cont("unsupported p6 CPU model %d ",
@@ -2007,12 +2124,14 @@ static int intel_pmu_init(void)
2007 sizeof(hw_cache_event_ids)); 2124 sizeof(hw_cache_event_ids));
2008 2125
2009 pr_cont("Core2 events, "); 2126 pr_cont("Core2 events, ");
2127 event_constraints = intel_core_event_constraints;
2010 break; 2128 break;
2011 default: 2129 default:
2012 case 26: 2130 case 26:
2013 memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, 2131 memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
2014 sizeof(hw_cache_event_ids)); 2132 sizeof(hw_cache_event_ids));
2015 2133
2134 event_constraints = intel_nehalem_event_constraints;
2016 pr_cont("Nehalem/Corei7 events, "); 2135 pr_cont("Nehalem/Corei7 events, ");
2017 break; 2136 break;
2018 case 28: 2137 case 28:
@@ -2105,11 +2224,47 @@ static const struct pmu pmu = {
2105 .unthrottle = x86_pmu_unthrottle, 2224 .unthrottle = x86_pmu_unthrottle,
2106}; 2225};
2107 2226
2227static int
2228validate_event(struct cpu_hw_events *cpuc, struct perf_event *event)
2229{
2230 struct hw_perf_event fake_event = event->hw;
2231
2232 if (event->pmu != &pmu)
2233 return 0;
2234
2235 return x86_schedule_event(cpuc, &fake_event);
2236}
2237
2238static int validate_group(struct perf_event *event)
2239{
2240 struct perf_event *sibling, *leader = event->group_leader;
2241 struct cpu_hw_events fake_pmu;
2242
2243 memset(&fake_pmu, 0, sizeof(fake_pmu));
2244
2245 if (!validate_event(&fake_pmu, leader))
2246 return -ENOSPC;
2247
2248 list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
2249 if (!validate_event(&fake_pmu, sibling))
2250 return -ENOSPC;
2251 }
2252
2253 if (!validate_event(&fake_pmu, event))
2254 return -ENOSPC;
2255
2256 return 0;
2257}
2258
2108const struct pmu *hw_perf_event_init(struct perf_event *event) 2259const struct pmu *hw_perf_event_init(struct perf_event *event)
2109{ 2260{
2110 int err; 2261 int err;
2111 2262
2112 err = __hw_perf_event_init(event); 2263 err = __hw_perf_event_init(event);
2264 if (!err) {
2265 if (event->group_leader != event)
2266 err = validate_group(event);
2267 }
2113 if (err) { 2268 if (err) {
2114 if (event->destroy) 2269 if (event->destroy)
2115 event->destroy(event); 2270 event->destroy(event);
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index cc0d9667e182..c9bbcab95fbe 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -120,9 +120,10 @@
120#undef __field 120#undef __field
121#define __field(type, item) \ 121#define __field(type, item) \
122 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ 122 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
123 "offset:%u;\tsize:%u;\n", \ 123 "offset:%u;\tsize:%u;\tsigned:%u;\n", \
124 (unsigned int)offsetof(typeof(field), item), \ 124 (unsigned int)offsetof(typeof(field), item), \
125 (unsigned int)sizeof(field.item)); \ 125 (unsigned int)sizeof(field.item), \
126 (unsigned int)is_signed_type(type)); \
126 if (!ret) \ 127 if (!ret) \
127 return 0; 128 return 0;
128 129
@@ -132,19 +133,21 @@
132#undef __array 133#undef __array
133#define __array(type, item, len) \ 134#define __array(type, item, len) \
134 ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ 135 ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
135 "offset:%u;\tsize:%u;\n", \ 136 "offset:%u;\tsize:%u;\tsigned:%u;\n", \
136 (unsigned int)offsetof(typeof(field), item), \ 137 (unsigned int)offsetof(typeof(field), item), \
137 (unsigned int)sizeof(field.item)); \ 138 (unsigned int)sizeof(field.item), \
139 (unsigned int)is_signed_type(type)); \
138 if (!ret) \ 140 if (!ret) \
139 return 0; 141 return 0;
140 142
141#undef __dynamic_array 143#undef __dynamic_array
142#define __dynamic_array(type, item, len) \ 144#define __dynamic_array(type, item, len) \
143 ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\ 145 ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\
144 "offset:%u;\tsize:%u;\n", \ 146 "offset:%u;\tsize:%u;\tsigned:%u;\n", \
145 (unsigned int)offsetof(typeof(field), \ 147 (unsigned int)offsetof(typeof(field), \
146 __data_loc_##item), \ 148 __data_loc_##item), \
147 (unsigned int)sizeof(field.__data_loc_##item)); \ 149 (unsigned int)sizeof(field.__data_loc_##item), \
150 (unsigned int)is_signed_type(type)); \
148 if (!ret) \ 151 if (!ret) \
149 return 0; 152 return 0;
150 153
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index d4ff01970547..e43c928356ee 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -397,18 +397,21 @@ int ring_buffer_print_page_header(struct trace_seq *s)
397 int ret; 397 int ret;
398 398
399 ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t" 399 ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
400 "offset:0;\tsize:%u;\n", 400 "offset:0;\tsize:%u;\tsigned:%u;\n",
401 (unsigned int)sizeof(field.time_stamp)); 401 (unsigned int)sizeof(field.time_stamp),
402 (unsigned int)is_signed_type(u64));
402 403
403 ret = trace_seq_printf(s, "\tfield: local_t commit;\t" 404 ret = trace_seq_printf(s, "\tfield: local_t commit;\t"
404 "offset:%u;\tsize:%u;\n", 405 "offset:%u;\tsize:%u;\tsigned:%u;\n",
405 (unsigned int)offsetof(typeof(field), commit), 406 (unsigned int)offsetof(typeof(field), commit),
406 (unsigned int)sizeof(field.commit)); 407 (unsigned int)sizeof(field.commit),
408 (unsigned int)is_signed_type(long));
407 409
408 ret = trace_seq_printf(s, "\tfield: char data;\t" 410 ret = trace_seq_printf(s, "\tfield: char data;\t"
409 "offset:%u;\tsize:%u;\n", 411 "offset:%u;\tsize:%u;\tsigned:%u;\n",
410 (unsigned int)offsetof(typeof(field), data), 412 (unsigned int)offsetof(typeof(field), data),
411 (unsigned int)BUF_PAGE_SIZE); 413 (unsigned int)BUF_PAGE_SIZE,
414 (unsigned int)is_signed_type(char));
412 415
413 return ret; 416 return ret;
414} 417}
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index d128f65778e6..cf3cabf6ce14 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -507,7 +507,7 @@ extern char *__bad_type_size(void);
507#define FIELD(type, name) \ 507#define FIELD(type, name) \
508 sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ 508 sizeof(type) != sizeof(field.name) ? __bad_type_size() : \
509 #type, "common_" #name, offsetof(typeof(field), name), \ 509 #type, "common_" #name, offsetof(typeof(field), name), \
510 sizeof(field.name) 510 sizeof(field.name), is_signed_type(type)
511 511
512static int trace_write_header(struct trace_seq *s) 512static int trace_write_header(struct trace_seq *s)
513{ 513{
@@ -515,17 +515,17 @@ static int trace_write_header(struct trace_seq *s)
515 515
516 /* struct trace_entry */ 516 /* struct trace_entry */
517 return trace_seq_printf(s, 517 return trace_seq_printf(s,
518 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" 518 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
519 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" 519 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
520 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" 520 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
521 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" 521 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
522 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" 522 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
523 "\n", 523 "\n",
524 FIELD(unsigned short, type), 524 FIELD(unsigned short, type),
525 FIELD(unsigned char, flags), 525 FIELD(unsigned char, flags),
526 FIELD(unsigned char, preempt_count), 526 FIELD(unsigned char, preempt_count),
527 FIELD(int, pid), 527 FIELD(int, pid),
528 FIELD(int, lock_depth)); 528 FIELD(int, lock_depth));
529} 529}
530 530
531static ssize_t 531static ssize_t
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index 9753fcc61bc5..31da218ee10f 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -66,44 +66,47 @@ static void __used ____ftrace_check_##name(void) \
66#undef __field 66#undef __field
67#define __field(type, item) \ 67#define __field(type, item) \
68 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ 68 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
69 "offset:%zu;\tsize:%zu;\n", \ 69 "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
70 offsetof(typeof(field), item), \ 70 offsetof(typeof(field), item), \
71 sizeof(field.item)); \ 71 sizeof(field.item), is_signed_type(type)); \
72 if (!ret) \ 72 if (!ret) \
73 return 0; 73 return 0;
74 74
75#undef __field_desc 75#undef __field_desc
76#define __field_desc(type, container, item) \ 76#define __field_desc(type, container, item) \
77 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ 77 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
78 "offset:%zu;\tsize:%zu;\n", \ 78 "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
79 offsetof(typeof(field), container.item), \ 79 offsetof(typeof(field), container.item), \
80 sizeof(field.container.item)); \ 80 sizeof(field.container.item), \
81 is_signed_type(type)); \
81 if (!ret) \ 82 if (!ret) \
82 return 0; 83 return 0;
83 84
84#undef __array 85#undef __array
85#define __array(type, item, len) \ 86#define __array(type, item, len) \
86 ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ 87 ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
87 "offset:%zu;\tsize:%zu;\n", \ 88 "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
88 offsetof(typeof(field), item), \ 89 offsetof(typeof(field), item), \
89 sizeof(field.item)); \ 90 sizeof(field.item), is_signed_type(type)); \
90 if (!ret) \ 91 if (!ret) \
91 return 0; 92 return 0;
92 93
93#undef __array_desc 94#undef __array_desc
94#define __array_desc(type, container, item, len) \ 95#define __array_desc(type, container, item, len) \
95 ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ 96 ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
96 "offset:%zu;\tsize:%zu;\n", \ 97 "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
97 offsetof(typeof(field), container.item), \ 98 offsetof(typeof(field), container.item), \
98 sizeof(field.container.item)); \ 99 sizeof(field.container.item), \
100 is_signed_type(type)); \
99 if (!ret) \ 101 if (!ret) \
100 return 0; 102 return 0;
101 103
102#undef __dynamic_array 104#undef __dynamic_array
103#define __dynamic_array(type, item) \ 105#define __dynamic_array(type, item) \
104 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ 106 ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
105 "offset:%zu;\tsize:0;\n", \ 107 "offset:%zu;\tsize:0;\tsigned:%u;\n", \
106 offsetof(typeof(field), item)); \ 108 offsetof(typeof(field), item), \
109 is_signed_type(type)); \
107 if (!ret) \ 110 if (!ret) \
108 return 0; 111 return 0;
109 112
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 527e17eae575..d99abc427c39 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -103,7 +103,8 @@ extern char *__bad_type_size(void);
103#define SYSCALL_FIELD(type, name) \ 103#define SYSCALL_FIELD(type, name) \
104 sizeof(type) != sizeof(trace.name) ? \ 104 sizeof(type) != sizeof(trace.name) ? \
105 __bad_type_size() : \ 105 __bad_type_size() : \
106 #type, #name, offsetof(typeof(trace), name), sizeof(trace.name) 106 #type, #name, offsetof(typeof(trace), name), \
107 sizeof(trace.name), is_signed_type(type)
107 108
108int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) 109int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
109{ 110{
@@ -120,7 +121,8 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
120 if (!entry) 121 if (!entry)
121 return 0; 122 return 0;
122 123
123 ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", 124 ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
125 "\tsigned:%u;\n",
124 SYSCALL_FIELD(int, nr)); 126 SYSCALL_FIELD(int, nr));
125 if (!ret) 127 if (!ret)
126 return 0; 128 return 0;
@@ -130,8 +132,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
130 entry->args[i]); 132 entry->args[i]);
131 if (!ret) 133 if (!ret)
132 return 0; 134 return 0;
133 ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset, 135 ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;"
134 sizeof(unsigned long)); 136 "\tsigned:%u;\n", offset,
137 sizeof(unsigned long),
138 is_signed_type(unsigned long));
135 if (!ret) 139 if (!ret)
136 return 0; 140 return 0;
137 offset += sizeof(unsigned long); 141 offset += sizeof(unsigned long);
@@ -163,8 +167,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
163 struct syscall_trace_exit trace; 167 struct syscall_trace_exit trace;
164 168
165 ret = trace_seq_printf(s, 169 ret = trace_seq_printf(s,
166 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" 170 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
167 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", 171 "\tsigned:%u;\n"
172 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
173 "\tsigned:%u;\n",
168 SYSCALL_FIELD(int, nr), 174 SYSCALL_FIELD(int, nr),
169 SYSCALL_FIELD(long, ret)); 175 SYSCALL_FIELD(long, ret));
170 if (!ret) 176 if (!ret)
@@ -212,7 +218,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
212 if (ret) 218 if (ret)
213 return ret; 219 return ret;
214 220
215 ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0, 221 ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
216 FILTER_OTHER); 222 FILTER_OTHER);
217 223
218 return ret; 224 return ret;
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 5881943f0c34..495eb6d97fa0 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -323,6 +323,7 @@ LIB_H += ../../include/linux/rbtree.h
323LIB_H += ../../include/linux/list.h 323LIB_H += ../../include/linux/list.h
324LIB_H += util/include/linux/list.h 324LIB_H += util/include/linux/list.h
325LIB_H += perf.h 325LIB_H += perf.h
326LIB_H += util/event.h
326LIB_H += util/types.h 327LIB_H += util/types.h
327LIB_H += util/levenshtein.h 328LIB_H += util/levenshtein.h
328LIB_H += util/parse-options.h 329LIB_H += util/parse-options.h
@@ -336,9 +337,12 @@ LIB_H += util/strlist.h
336LIB_H += util/run-command.h 337LIB_H += util/run-command.h
337LIB_H += util/sigchain.h 338LIB_H += util/sigchain.h
338LIB_H += util/symbol.h 339LIB_H += util/symbol.h
339LIB_H += util/module.h
340LIB_H += util/color.h 340LIB_H += util/color.h
341LIB_H += util/values.h 341LIB_H += util/values.h
342LIB_H += util/sort.h
343LIB_H += util/hist.h
344LIB_H += util/thread.h
345LIB_H += util/data_map.h
342 346
343LIB_OBJS += util/abspath.o 347LIB_OBJS += util/abspath.o
344LIB_OBJS += util/alias.o 348LIB_OBJS += util/alias.o
@@ -361,7 +365,6 @@ LIB_OBJS += util/usage.o
361LIB_OBJS += util/wrapper.o 365LIB_OBJS += util/wrapper.o
362LIB_OBJS += util/sigchain.o 366LIB_OBJS += util/sigchain.o
363LIB_OBJS += util/symbol.o 367LIB_OBJS += util/symbol.o
364LIB_OBJS += util/module.o
365LIB_OBJS += util/color.o 368LIB_OBJS += util/color.o
366LIB_OBJS += util/pager.o 369LIB_OBJS += util/pager.o
367LIB_OBJS += util/header.o 370LIB_OBJS += util/header.o
@@ -374,6 +377,9 @@ LIB_OBJS += util/trace-event-parse.o
374LIB_OBJS += util/trace-event-read.o 377LIB_OBJS += util/trace-event-read.o
375LIB_OBJS += util/trace-event-info.o 378LIB_OBJS += util/trace-event-info.o
376LIB_OBJS += util/svghelper.o 379LIB_OBJS += util/svghelper.o
380LIB_OBJS += util/sort.o
381LIB_OBJS += util/hist.o
382LIB_OBJS += util/data_map.o
377 383
378BUILTIN_OBJS += builtin-annotate.o 384BUILTIN_OBJS += builtin-annotate.o
379BUILTIN_OBJS += builtin-help.o 385BUILTIN_OBJS += builtin-help.o
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 1ec741615814..8c84320ecb06 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -22,15 +22,13 @@
22#include "util/parse-options.h" 22#include "util/parse-options.h"
23#include "util/parse-events.h" 23#include "util/parse-events.h"
24#include "util/thread.h" 24#include "util/thread.h"
25#include "util/sort.h"
26#include "util/hist.h"
25 27
26static char const *input_name = "perf.data"; 28static char const *input_name = "perf.data";
27 29
28static char default_sort_order[] = "comm,symbol";
29static char *sort_order = default_sort_order;
30
31static int force; 30static int force;
32static int input; 31static int input;
33static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
34 32
35static int full_paths; 33static int full_paths;
36 34
@@ -49,248 +47,6 @@ struct sym_ext {
49 char *path; 47 char *path;
50}; 48};
51 49
52/*
53 * histogram, sorted on item, collects counts
54 */
55
56static struct rb_root hist;
57
58struct hist_entry {
59 struct rb_node rb_node;
60
61 struct thread *thread;
62 struct map *map;
63 struct dso *dso;
64 struct symbol *sym;
65 u64 ip;
66 char level;
67
68 uint32_t count;
69};
70
71/*
72 * configurable sorting bits
73 */
74
75struct sort_entry {
76 struct list_head list;
77
78 const char *header;
79
80 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
81 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
82 size_t (*print)(FILE *fp, struct hist_entry *);
83};
84
85/* --sort pid */
86
87static int64_t
88sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
89{
90 return right->thread->pid - left->thread->pid;
91}
92
93static size_t
94sort__thread_print(FILE *fp, struct hist_entry *self)
95{
96 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
97}
98
99static struct sort_entry sort_thread = {
100 .header = " Command: Pid",
101 .cmp = sort__thread_cmp,
102 .print = sort__thread_print,
103};
104
105/* --sort comm */
106
107static int64_t
108sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
109{
110 return right->thread->pid - left->thread->pid;
111}
112
113static int64_t
114sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
115{
116 char *comm_l = left->thread->comm;
117 char *comm_r = right->thread->comm;
118
119 if (!comm_l || !comm_r) {
120 if (!comm_l && !comm_r)
121 return 0;
122 else if (!comm_l)
123 return -1;
124 else
125 return 1;
126 }
127
128 return strcmp(comm_l, comm_r);
129}
130
131static size_t
132sort__comm_print(FILE *fp, struct hist_entry *self)
133{
134 return fprintf(fp, "%16s", self->thread->comm);
135}
136
137static struct sort_entry sort_comm = {
138 .header = " Command",
139 .cmp = sort__comm_cmp,
140 .collapse = sort__comm_collapse,
141 .print = sort__comm_print,
142};
143
144/* --sort dso */
145
146static int64_t
147sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
148{
149 struct dso *dso_l = left->dso;
150 struct dso *dso_r = right->dso;
151
152 if (!dso_l || !dso_r) {
153 if (!dso_l && !dso_r)
154 return 0;
155 else if (!dso_l)
156 return -1;
157 else
158 return 1;
159 }
160
161 return strcmp(dso_l->name, dso_r->name);
162}
163
164static size_t
165sort__dso_print(FILE *fp, struct hist_entry *self)
166{
167 if (self->dso)
168 return fprintf(fp, "%-25s", self->dso->name);
169
170 return fprintf(fp, "%016llx ", (u64)self->ip);
171}
172
173static struct sort_entry sort_dso = {
174 .header = "Shared Object ",
175 .cmp = sort__dso_cmp,
176 .print = sort__dso_print,
177};
178
179/* --sort symbol */
180
181static int64_t
182sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
183{
184 u64 ip_l, ip_r;
185
186 if (left->sym == right->sym)
187 return 0;
188
189 ip_l = left->sym ? left->sym->start : left->ip;
190 ip_r = right->sym ? right->sym->start : right->ip;
191
192 return (int64_t)(ip_r - ip_l);
193}
194
195static size_t
196sort__sym_print(FILE *fp, struct hist_entry *self)
197{
198 size_t ret = 0;
199
200 if (verbose)
201 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
202
203 if (self->sym) {
204 ret += fprintf(fp, "[%c] %s",
205 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
206 } else {
207 ret += fprintf(fp, "%#016llx", (u64)self->ip);
208 }
209
210 return ret;
211}
212
213static struct sort_entry sort_sym = {
214 .header = "Symbol",
215 .cmp = sort__sym_cmp,
216 .print = sort__sym_print,
217};
218
219static int sort__need_collapse = 0;
220
221struct sort_dimension {
222 const char *name;
223 struct sort_entry *entry;
224 int taken;
225};
226
227static struct sort_dimension sort_dimensions[] = {
228 { .name = "pid", .entry = &sort_thread, },
229 { .name = "comm", .entry = &sort_comm, },
230 { .name = "dso", .entry = &sort_dso, },
231 { .name = "symbol", .entry = &sort_sym, },
232};
233
234static LIST_HEAD(hist_entry__sort_list);
235
236static int sort_dimension__add(char *tok)
237{
238 unsigned int i;
239
240 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
241 struct sort_dimension *sd = &sort_dimensions[i];
242
243 if (sd->taken)
244 continue;
245
246 if (strncasecmp(tok, sd->name, strlen(tok)))
247 continue;
248
249 if (sd->entry->collapse)
250 sort__need_collapse = 1;
251
252 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
253 sd->taken = 1;
254
255 return 0;
256 }
257
258 return -ESRCH;
259}
260
261static int64_t
262hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
263{
264 struct sort_entry *se;
265 int64_t cmp = 0;
266
267 list_for_each_entry(se, &hist_entry__sort_list, list) {
268 cmp = se->cmp(left, right);
269 if (cmp)
270 break;
271 }
272
273 return cmp;
274}
275
276static int64_t
277hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
278{
279 struct sort_entry *se;
280 int64_t cmp = 0;
281
282 list_for_each_entry(se, &hist_entry__sort_list, list) {
283 int64_t (*f)(struct hist_entry *, struct hist_entry *);
284
285 f = se->collapse ?: se->cmp;
286
287 cmp = f(left, right);
288 if (cmp)
289 break;
290 }
291
292 return cmp;
293}
294 50
295/* 51/*
296 * collect histogram counts 52 * collect histogram counts
@@ -306,6 +62,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
306 return; 62 return;
307 63
308 sym_size = sym->end - sym->start; 64 sym_size = sym->end - sym->start;
65 ip = he->map->map_ip(he->map, ip);
309 offset = ip - sym->start; 66 offset = ip - sym->start;
310 67
311 if (offset >= sym_size) 68 if (offset >= sym_size)
@@ -322,171 +79,27 @@ static void hist_hit(struct hist_entry *he, u64 ip)
322 sym->hist[offset]); 79 sym->hist[offset]);
323} 80}
324 81
325static int 82static int hist_entry__add(struct thread *thread, struct map *map,
326hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 83 struct symbol *sym, u64 ip, u64 count, char level)
327 struct symbol *sym, u64 ip, char level)
328{ 84{
329 struct rb_node **p = &hist.rb_node; 85 bool hit;
330 struct rb_node *parent = NULL; 86 struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip,
331 struct hist_entry *he; 87 count, level, &hit);
332 struct hist_entry entry = { 88 if (he == NULL)
333 .thread = thread,
334 .map = map,
335 .dso = dso,
336 .sym = sym,
337 .ip = ip,
338 .level = level,
339 .count = 1,
340 };
341 int cmp;
342
343 while (*p != NULL) {
344 parent = *p;
345 he = rb_entry(parent, struct hist_entry, rb_node);
346
347 cmp = hist_entry__cmp(&entry, he);
348
349 if (!cmp) {
350 hist_hit(he, ip);
351
352 return 0;
353 }
354
355 if (cmp < 0)
356 p = &(*p)->rb_left;
357 else
358 p = &(*p)->rb_right;
359 }
360
361 he = malloc(sizeof(*he));
362 if (!he)
363 return -ENOMEM; 89 return -ENOMEM;
364 *he = entry; 90 if (hit)
365 rb_link_node(&he->rb_node, parent, p); 91 hist_hit(he, ip);
366 rb_insert_color(&he->rb_node, &hist);
367
368 return 0; 92 return 0;
369} 93}
370 94
371static void hist_entry__free(struct hist_entry *he)
372{
373 free(he);
374}
375
376/*
377 * collapse the histogram
378 */
379
380static struct rb_root collapse_hists;
381
382static void collapse__insert_entry(struct hist_entry *he)
383{
384 struct rb_node **p = &collapse_hists.rb_node;
385 struct rb_node *parent = NULL;
386 struct hist_entry *iter;
387 int64_t cmp;
388
389 while (*p != NULL) {
390 parent = *p;
391 iter = rb_entry(parent, struct hist_entry, rb_node);
392
393 cmp = hist_entry__collapse(iter, he);
394
395 if (!cmp) {
396 iter->count += he->count;
397 hist_entry__free(he);
398 return;
399 }
400
401 if (cmp < 0)
402 p = &(*p)->rb_left;
403 else
404 p = &(*p)->rb_right;
405 }
406
407 rb_link_node(&he->rb_node, parent, p);
408 rb_insert_color(&he->rb_node, &collapse_hists);
409}
410
411static void collapse__resort(void)
412{
413 struct rb_node *next;
414 struct hist_entry *n;
415
416 if (!sort__need_collapse)
417 return;
418
419 next = rb_first(&hist);
420 while (next) {
421 n = rb_entry(next, struct hist_entry, rb_node);
422 next = rb_next(&n->rb_node);
423
424 rb_erase(&n->rb_node, &hist);
425 collapse__insert_entry(n);
426 }
427}
428
429/*
430 * reverse the map, sort on count.
431 */
432
433static struct rb_root output_hists;
434
435static void output__insert_entry(struct hist_entry *he)
436{
437 struct rb_node **p = &output_hists.rb_node;
438 struct rb_node *parent = NULL;
439 struct hist_entry *iter;
440
441 while (*p != NULL) {
442 parent = *p;
443 iter = rb_entry(parent, struct hist_entry, rb_node);
444
445 if (he->count > iter->count)
446 p = &(*p)->rb_left;
447 else
448 p = &(*p)->rb_right;
449 }
450
451 rb_link_node(&he->rb_node, parent, p);
452 rb_insert_color(&he->rb_node, &output_hists);
453}
454
455static void output__resort(void)
456{
457 struct rb_node *next;
458 struct hist_entry *n;
459 struct rb_root *tree = &hist;
460
461 if (sort__need_collapse)
462 tree = &collapse_hists;
463
464 next = rb_first(tree);
465
466 while (next) {
467 n = rb_entry(next, struct hist_entry, rb_node);
468 next = rb_next(&n->rb_node);
469
470 rb_erase(&n->rb_node, tree);
471 output__insert_entry(n);
472 }
473}
474
475static unsigned long total = 0,
476 total_mmap = 0,
477 total_comm = 0,
478 total_fork = 0,
479 total_unknown = 0;
480
481static int 95static int
482process_sample_event(event_t *event, unsigned long offset, unsigned long head) 96process_sample_event(event_t *event, unsigned long offset, unsigned long head)
483{ 97{
484 char level; 98 char level;
485 int show = 0;
486 struct dso *dso = NULL;
487 struct thread *thread; 99 struct thread *thread;
488 u64 ip = event->ip.ip; 100 u64 ip = event->ip.ip;
489 struct map *map = NULL; 101 struct map *map = NULL;
102 struct symbol *sym = NULL;
490 103
491 thread = threads__findnew(event->ip.pid, &threads, &last_match); 104 thread = threads__findnew(event->ip.pid, &threads, &last_match);
492 105
@@ -506,51 +119,44 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
506 } 119 }
507 120
508 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 121 if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
509 show = SHOW_KERNEL;
510 level = 'k'; 122 level = 'k';
511 123 sym = kernel_maps__find_symbol(ip, &map);
512 dso = kernel_dso; 124 dump_printf(" ...... dso: %s\n",
513 125 map ? map->dso->long_name : "<not found>");
514 dump_printf(" ...... dso: %s\n", dso->name);
515
516 } else if (event->header.misc & PERF_RECORD_MISC_USER) { 126 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
517
518 show = SHOW_USER;
519 level = '.'; 127 level = '.';
520
521 map = thread__find_map(thread, ip); 128 map = thread__find_map(thread, ip);
522 if (map != NULL) { 129 if (map != NULL) {
130got_map:
523 ip = map->map_ip(map, ip); 131 ip = map->map_ip(map, ip);
524 dso = map->dso; 132 sym = map->dso->find_symbol(map->dso, ip);
525 } else { 133 } else {
526 /* 134 /*
527 * If this is outside of all known maps, 135 * If this is outside of all known maps,
528 * and is a negative address, try to look it 136 * and is a negative address, try to look it
529 * up in the kernel dso, as it might be a 137 * up in the kernel dso, as it might be a
530 * vsyscall (which executes in user-mode): 138 * vsyscall or vdso (which executes in user-mode).
139 *
140 * XXX This is nasty, we should have a symbol list in
141 * the "[vdso]" dso, but for now lets use the old
142 * trick of looking in the whole kernel symbol list.
531 */ 143 */
532 if ((long long)ip < 0) 144 if ((long long)ip < 0) {
533 dso = kernel_dso; 145 map = kernel_map;
146 goto got_map;
147 }
534 } 148 }
535 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 149 dump_printf(" ...... dso: %s\n",
536 150 map ? map->dso->long_name : "<not found>");
537 } else { 151 } else {
538 show = SHOW_HV;
539 level = 'H'; 152 level = 'H';
540 dump_printf(" ...... dso: [hypervisor]\n"); 153 dump_printf(" ...... dso: [hypervisor]\n");
541 } 154 }
542 155
543 if (show & show_mask) { 156 if (hist_entry__add(thread, map, sym, ip, 1, level)) {
544 struct symbol *sym = NULL; 157 fprintf(stderr, "problem incrementing symbol count, "
545 158 "skipping event\n");
546 if (dso) 159 return -1;
547 sym = dso->find_symbol(dso, ip);
548
549 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
550 fprintf(stderr,
551 "problem incrementing symbol count, skipping event\n");
552 return -1;
553 }
554 } 160 }
555 total++; 161 total++;
556 162
@@ -666,7 +272,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
666} 272}
667 273
668static int 274static int
669parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) 275parse_line(FILE *file, struct symbol *sym, u64 len)
670{ 276{
671 char *line = NULL, *tmp, *tmp2; 277 char *line = NULL, *tmp, *tmp2;
672 static const char *prev_line; 278 static const char *prev_line;
@@ -716,7 +322,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
716 const char *color; 322 const char *color;
717 struct sym_ext *sym_ext = sym->priv; 323 struct sym_ext *sym_ext = sym->priv;
718 324
719 offset = line_ip - start; 325 offset = line_ip - sym->start;
720 if (offset < len) 326 if (offset < len)
721 hits = sym->hist[offset]; 327 hits = sym->hist[offset];
722 328
@@ -795,7 +401,7 @@ static void free_source_line(struct symbol *sym, int len)
795 401
796/* Get the filename:line for the colored entries */ 402/* Get the filename:line for the colored entries */
797static void 403static void
798get_source_line(struct symbol *sym, u64 start, int len, const char *filename) 404get_source_line(struct symbol *sym, int len, const char *filename)
799{ 405{
800 int i; 406 int i;
801 char cmd[PATH_MAX * 2]; 407 char cmd[PATH_MAX * 2];
@@ -820,7 +426,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
820 if (sym_ext[i].percent <= 0.5) 426 if (sym_ext[i].percent <= 0.5)
821 continue; 427 continue;
822 428
823 offset = start + i; 429 offset = sym->start + i;
824 sprintf(cmd, "addr2line -e %s %016llx", filename, offset); 430 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
825 fp = popen(cmd, "r"); 431 fp = popen(cmd, "r");
826 if (!fp) 432 if (!fp)
@@ -872,31 +478,23 @@ static void print_summary(const char *filename)
872 478
873static void annotate_sym(struct dso *dso, struct symbol *sym) 479static void annotate_sym(struct dso *dso, struct symbol *sym)
874{ 480{
875 const char *filename = dso->name, *d_filename; 481 const char *filename = dso->long_name, *d_filename;
876 u64 start, end, len; 482 u64 len;
877 char command[PATH_MAX*2]; 483 char command[PATH_MAX*2];
878 FILE *file; 484 FILE *file;
879 485
880 if (!filename) 486 if (!filename)
881 return; 487 return;
882 if (sym->module) 488
883 filename = sym->module->path;
884 else if (dso == kernel_dso)
885 filename = vmlinux_name;
886
887 start = sym->obj_start;
888 if (!start)
889 start = sym->start;
890 if (full_paths) 489 if (full_paths)
891 d_filename = filename; 490 d_filename = filename;
892 else 491 else
893 d_filename = basename(filename); 492 d_filename = basename(filename);
894 493
895 end = start + sym->end - sym->start + 1;
896 len = sym->end - sym->start; 494 len = sym->end - sym->start;
897 495
898 if (print_line) { 496 if (print_line) {
899 get_source_line(sym, start, len, filename); 497 get_source_line(sym, len, filename);
900 print_summary(filename); 498 print_summary(filename);
901 } 499 }
902 500
@@ -905,10 +503,11 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
905 printf("------------------------------------------------\n"); 503 printf("------------------------------------------------\n");
906 504
907 if (verbose >= 2) 505 if (verbose >= 2)
908 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 506 printf("annotating [%p] %30s : [%p] %30s\n",
507 dso, dso->long_name, sym, sym->name);
909 508
910 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 509 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
911 (u64)start, (u64)end, filename, filename); 510 sym->start, sym->end, filename, filename);
912 511
913 if (verbose >= 3) 512 if (verbose >= 3)
914 printf("doing: %s\n", command); 513 printf("doing: %s\n", command);
@@ -918,7 +517,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
918 return; 517 return;
919 518
920 while (!feof(file)) { 519 while (!feof(file)) {
921 if (parse_line(file, sym, start, len) < 0) 520 if (parse_line(file, sym, len) < 0)
922 break; 521 break;
923 } 522 }
924 523
@@ -1059,14 +658,14 @@ more:
1059 if (dump_trace) 658 if (dump_trace)
1060 return 0; 659 return 0;
1061 660
1062 if (verbose >= 3) 661 if (verbose > 3)
1063 threads__fprintf(stdout, &threads); 662 threads__fprintf(stdout, &threads);
1064 663
1065 if (verbose >= 2) 664 if (verbose > 2)
1066 dsos__fprintf(stdout); 665 dsos__fprintf(stdout);
1067 666
1068 collapse__resort(); 667 collapse__resort();
1069 output__resort(); 668 output__resort(total);
1070 669
1071 find_annotations(); 670 find_annotations();
1072 671
@@ -1139,5 +738,11 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1139 738
1140 setup_pager(); 739 setup_pager();
1141 740
741 if (field_sep && *field_sep == '.') {
742 fputs("'.' is the only non valid --field-separator argument\n",
743 stderr);
744 exit(129);
745 }
746
1142 return __cmd_annotate(); 747 return __cmd_annotate();
1143} 748}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 3eeef339c787..4e3a374e7aa7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,7 +17,6 @@
17#include "util/header.h" 17#include "util/header.h"
18#include "util/event.h" 18#include "util/event.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include "util/trace-event.h"
21 20
22#include <unistd.h> 21#include <unistd.h>
23#include <sched.h> 22#include <sched.h>
@@ -27,45 +26,45 @@
27 26
28static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 27static int fd[MAX_NR_CPUS][MAX_COUNTERS];
29 28
30static long default_interval = 100000; 29static long default_interval = 0;
31 30
32static int nr_cpus = 0; 31static int nr_cpus = 0;
33static unsigned int page_size; 32static unsigned int page_size;
34static unsigned int mmap_pages = 128; 33static unsigned int mmap_pages = 128;
35static int freq = 0; 34static int freq = 1000;
36static int output; 35static int output;
37static const char *output_name = "perf.data"; 36static const char *output_name = "perf.data";
38static int group = 0; 37static int group = 0;
39static unsigned int realtime_prio = 0; 38static unsigned int realtime_prio = 0;
40static int raw_samples = 0; 39static int raw_samples = 0;
41static int system_wide = 0; 40static int system_wide = 0;
42static int profile_cpu = -1; 41static int profile_cpu = -1;
43static pid_t target_pid = -1; 42static pid_t target_pid = -1;
44static pid_t child_pid = -1; 43static pid_t child_pid = -1;
45static int inherit = 1; 44static int inherit = 1;
46static int force = 0; 45static int force = 0;
47static int append_file = 0; 46static int append_file = 0;
48static int call_graph = 0; 47static int call_graph = 0;
49static int inherit_stat = 0; 48static int inherit_stat = 0;
50static int no_samples = 0; 49static int no_samples = 0;
51static int sample_address = 0; 50static int sample_address = 0;
52static int multiplex = 0; 51static int multiplex = 0;
53static int multiplex_fd = -1; 52static int multiplex_fd = -1;
54 53
55static long samples; 54static long samples = 0;
56static struct timeval last_read; 55static struct timeval last_read;
57static struct timeval this_read; 56static struct timeval this_read;
58 57
59static u64 bytes_written; 58static u64 bytes_written = 0;
60 59
61static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 60static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
62 61
63static int nr_poll; 62static int nr_poll = 0;
64static int nr_cpu; 63static int nr_cpu = 0;
65 64
66static int file_new = 1; 65static int file_new = 1;
67 66
68struct perf_header *header; 67struct perf_header *header = NULL;
69 68
70struct mmap_data { 69struct mmap_data {
71 int counter; 70 int counter;
@@ -566,17 +565,17 @@ static int __cmd_record(int argc, const char **argv)
566 else 565 else
567 header = perf_header__new(); 566 header = perf_header__new();
568 567
569
570 if (raw_samples) { 568 if (raw_samples) {
571 read_tracing_data(attrs, nr_counters); 569 perf_header__set_trace_info();
572 } else { 570 } else {
573 for (i = 0; i < nr_counters; i++) { 571 for (i = 0; i < nr_counters; i++) {
574 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 572 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
575 read_tracing_data(attrs, nr_counters); 573 perf_header__set_trace_info();
576 break; 574 break;
577 } 575 }
578 } 576 }
579 } 577 }
578
580 atexit(atexit_header); 579 atexit(atexit_header);
581 580
582 if (!system_wide) { 581 if (!system_wide) {
@@ -731,6 +730,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
731 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 730 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
732 } 731 }
733 732
733 /*
734 * User specified count overrides default frequency.
735 */
736 if (default_interval)
737 freq = 0;
738 else if (freq) {
739 default_interval = freq;
740 } else {
741 fprintf(stderr, "frequency and count are zero, aborting\n");
742 exit(EXIT_FAILURE);
743 }
744
734 for (counter = 0; counter < nr_counters; counter++) { 745 for (counter = 0; counter < nr_counters; counter++) {
735 if (attrs[counter].sample_period) 746 if (attrs[counter].sample_period)
736 continue; 747 continue;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 19669c20088e..f57a23b19f3c 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -26,20 +26,18 @@
26#include "util/parse-options.h" 26#include "util/parse-options.h"
27#include "util/parse-events.h" 27#include "util/parse-events.h"
28 28
29#include "util/data_map.h"
29#include "util/thread.h" 30#include "util/thread.h"
31#include "util/sort.h"
32#include "util/hist.h"
30 33
31static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
32 35
33static char default_sort_order[] = "comm,dso,symbol";
34static char *sort_order = default_sort_order;
35static char *dso_list_str, *comm_list_str, *sym_list_str, 36static char *dso_list_str, *comm_list_str, *sym_list_str,
36 *col_width_list_str; 37 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list; 38static struct strlist *dso_list, *comm_list, *sym_list;
38static char *field_sep;
39 39
40static int force; 40static int force;
41static int input;
42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
43 41
44static int full_paths; 42static int full_paths;
45static int show_nr_samples; 43static int show_nr_samples;
@@ -50,21 +48,11 @@ static struct perf_read_values show_threads_values;
50static char default_pretty_printing_style[] = "normal"; 48static char default_pretty_printing_style[] = "normal";
51static char *pretty_printing_style = default_pretty_printing_style; 49static char *pretty_printing_style = default_pretty_printing_style;
52 50
53static unsigned long page_size;
54static unsigned long mmap_window = 32;
55
56static char default_parent_pattern[] = "^sys_|^do_page_fault";
57static char *parent_pattern = default_parent_pattern;
58static regex_t parent_regex;
59
60static int exclude_other = 1; 51static int exclude_other = 1;
61 52
62static char callchain_default_opt[] = "fractal,0.5"; 53static char callchain_default_opt[] = "fractal,0.5";
63 54
64static int callchain; 55static char *cwd;
65
66static char __cwd[PATH_MAX];
67static char *cwd = __cwd;
68static int cwdlen; 56static int cwdlen;
69 57
70static struct rb_root threads; 58static struct rb_root threads;
@@ -72,346 +60,8 @@ static struct thread *last_match;
72 60
73static struct perf_header *header; 61static struct perf_header *header;
74 62
75static
76struct callchain_param callchain_param = {
77 .mode = CHAIN_GRAPH_REL,
78 .min_percent = 0.5
79};
80
81static u64 sample_type; 63static u64 sample_type;
82 64
83static int repsep_fprintf(FILE *fp, const char *fmt, ...)
84{
85 int n;
86 va_list ap;
87
88 va_start(ap, fmt);
89 if (!field_sep)
90 n = vfprintf(fp, fmt, ap);
91 else {
92 char *bf = NULL;
93 n = vasprintf(&bf, fmt, ap);
94 if (n > 0) {
95 char *sep = bf;
96
97 while (1) {
98 sep = strchr(sep, *field_sep);
99 if (sep == NULL)
100 break;
101 *sep = '.';
102 }
103 }
104 fputs(bf, fp);
105 free(bf);
106 }
107 va_end(ap);
108 return n;
109}
110
111static unsigned int dsos__col_width,
112 comms__col_width,
113 threads__col_width;
114
115/*
116 * histogram, sorted on item, collects counts
117 */
118
119static struct rb_root hist;
120
121struct hist_entry {
122 struct rb_node rb_node;
123
124 struct thread *thread;
125 struct map *map;
126 struct dso *dso;
127 struct symbol *sym;
128 struct symbol *parent;
129 u64 ip;
130 char level;
131 struct callchain_node callchain;
132 struct rb_root sorted_chain;
133
134 u64 count;
135};
136
137/*
138 * configurable sorting bits
139 */
140
141struct sort_entry {
142 struct list_head list;
143
144 const char *header;
145
146 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
147 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
148 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
149 unsigned int *width;
150 bool elide;
151};
152
153static int64_t cmp_null(void *l, void *r)
154{
155 if (!l && !r)
156 return 0;
157 else if (!l)
158 return -1;
159 else
160 return 1;
161}
162
163/* --sort pid */
164
165static int64_t
166sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
167{
168 return right->thread->pid - left->thread->pid;
169}
170
171static size_t
172sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
173{
174 return repsep_fprintf(fp, "%*s:%5d", width - 6,
175 self->thread->comm ?: "", self->thread->pid);
176}
177
178static struct sort_entry sort_thread = {
179 .header = "Command: Pid",
180 .cmp = sort__thread_cmp,
181 .print = sort__thread_print,
182 .width = &threads__col_width,
183};
184
185/* --sort comm */
186
187static int64_t
188sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
189{
190 return right->thread->pid - left->thread->pid;
191}
192
193static int64_t
194sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
195{
196 char *comm_l = left->thread->comm;
197 char *comm_r = right->thread->comm;
198
199 if (!comm_l || !comm_r)
200 return cmp_null(comm_l, comm_r);
201
202 return strcmp(comm_l, comm_r);
203}
204
205static size_t
206sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
207{
208 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
209}
210
211static struct sort_entry sort_comm = {
212 .header = "Command",
213 .cmp = sort__comm_cmp,
214 .collapse = sort__comm_collapse,
215 .print = sort__comm_print,
216 .width = &comms__col_width,
217};
218
219/* --sort dso */
220
221static int64_t
222sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
223{
224 struct dso *dso_l = left->dso;
225 struct dso *dso_r = right->dso;
226
227 if (!dso_l || !dso_r)
228 return cmp_null(dso_l, dso_r);
229
230 return strcmp(dso_l->name, dso_r->name);
231}
232
233static size_t
234sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
235{
236 if (self->dso)
237 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
238
239 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
240}
241
242static struct sort_entry sort_dso = {
243 .header = "Shared Object",
244 .cmp = sort__dso_cmp,
245 .print = sort__dso_print,
246 .width = &dsos__col_width,
247};
248
249/* --sort symbol */
250
251static int64_t
252sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
253{
254 u64 ip_l, ip_r;
255
256 if (left->sym == right->sym)
257 return 0;
258
259 ip_l = left->sym ? left->sym->start : left->ip;
260 ip_r = right->sym ? right->sym->start : right->ip;
261
262 return (int64_t)(ip_r - ip_l);
263}
264
265static size_t
266sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
267{
268 size_t ret = 0;
269
270 if (verbose)
271 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
272 dso__symtab_origin(self->dso));
273
274 ret += repsep_fprintf(fp, "[%c] ", self->level);
275 if (self->sym) {
276 ret += repsep_fprintf(fp, "%s", self->sym->name);
277
278 if (self->sym->module)
279 ret += repsep_fprintf(fp, "\t[%s]",
280 self->sym->module->name);
281 } else {
282 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
283 }
284
285 return ret;
286}
287
288static struct sort_entry sort_sym = {
289 .header = "Symbol",
290 .cmp = sort__sym_cmp,
291 .print = sort__sym_print,
292};
293
294/* --sort parent */
295
296static int64_t
297sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
298{
299 struct symbol *sym_l = left->parent;
300 struct symbol *sym_r = right->parent;
301
302 if (!sym_l || !sym_r)
303 return cmp_null(sym_l, sym_r);
304
305 return strcmp(sym_l->name, sym_r->name);
306}
307
308static size_t
309sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
310{
311 return repsep_fprintf(fp, "%-*s", width,
312 self->parent ? self->parent->name : "[other]");
313}
314
315static unsigned int parent_symbol__col_width;
316
317static struct sort_entry sort_parent = {
318 .header = "Parent symbol",
319 .cmp = sort__parent_cmp,
320 .print = sort__parent_print,
321 .width = &parent_symbol__col_width,
322};
323
324static int sort__need_collapse = 0;
325static int sort__has_parent = 0;
326
327struct sort_dimension {
328 const char *name;
329 struct sort_entry *entry;
330 int taken;
331};
332
333static struct sort_dimension sort_dimensions[] = {
334 { .name = "pid", .entry = &sort_thread, },
335 { .name = "comm", .entry = &sort_comm, },
336 { .name = "dso", .entry = &sort_dso, },
337 { .name = "symbol", .entry = &sort_sym, },
338 { .name = "parent", .entry = &sort_parent, },
339};
340
341static LIST_HEAD(hist_entry__sort_list);
342
343static int sort_dimension__add(const char *tok)
344{
345 unsigned int i;
346
347 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
348 struct sort_dimension *sd = &sort_dimensions[i];
349
350 if (sd->taken)
351 continue;
352
353 if (strncasecmp(tok, sd->name, strlen(tok)))
354 continue;
355
356 if (sd->entry->collapse)
357 sort__need_collapse = 1;
358
359 if (sd->entry == &sort_parent) {
360 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
361 if (ret) {
362 char err[BUFSIZ];
363
364 regerror(ret, &parent_regex, err, sizeof(err));
365 fprintf(stderr, "Invalid regex: %s\n%s",
366 parent_pattern, err);
367 exit(-1);
368 }
369 sort__has_parent = 1;
370 }
371
372 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
373 sd->taken = 1;
374
375 return 0;
376 }
377
378 return -ESRCH;
379}
380
381static int64_t
382hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
383{
384 struct sort_entry *se;
385 int64_t cmp = 0;
386
387 list_for_each_entry(se, &hist_entry__sort_list, list) {
388 cmp = se->cmp(left, right);
389 if (cmp)
390 break;
391 }
392
393 return cmp;
394}
395
396static int64_t
397hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
398{
399 struct sort_entry *se;
400 int64_t cmp = 0;
401
402 list_for_each_entry(se, &hist_entry__sort_list, list) {
403 int64_t (*f)(struct hist_entry *, struct hist_entry *);
404
405 f = se->collapse ?: se->cmp;
406
407 cmp = f(left, right);
408 if (cmp)
409 break;
410 }
411
412 return cmp;
413}
414
415static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask) 65static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
416{ 66{
417 int i; 67 int i;
@@ -610,7 +260,6 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
610 return ret; 260 return ret;
611} 261}
612 262
613
614static size_t 263static size_t
615hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) 264hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
616{ 265{
@@ -695,22 +344,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
695 344
696 345
697static struct symbol * 346static struct symbol *
698resolve_symbol(struct thread *thread, struct map **mapp, 347resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
699 struct dso **dsop, u64 *ipp)
700{ 348{
701 struct dso *dso = dsop ? *dsop : NULL;
702 struct map *map = mapp ? *mapp : NULL; 349 struct map *map = mapp ? *mapp : NULL;
703 u64 ip = *ipp; 350 u64 ip = *ipp;
704 351
705 if (!thread)
706 return NULL;
707
708 if (dso)
709 goto got_dso;
710
711 if (map) 352 if (map)
712 goto got_map; 353 goto got_map;
713 354
355 if (!thread)
356 return NULL;
357
714 map = thread__find_map(thread, ip); 358 map = thread__find_map(thread, ip);
715 if (map != NULL) { 359 if (map != NULL) {
716 /* 360 /*
@@ -725,29 +369,26 @@ resolve_symbol(struct thread *thread, struct map **mapp,
725 *mapp = map; 369 *mapp = map;
726got_map: 370got_map:
727 ip = map->map_ip(map, ip); 371 ip = map->map_ip(map, ip);
728
729 dso = map->dso;
730 } else { 372 } else {
731 /* 373 /*
732 * If this is outside of all known maps, 374 * If this is outside of all known maps,
733 * and is a negative address, try to look it 375 * and is a negative address, try to look it
734 * up in the kernel dso, as it might be a 376 * up in the kernel dso, as it might be a
735 * vsyscall (which executes in user-mode): 377 * vsyscall or vdso (which executes in user-mode).
378 *
379 * XXX This is nasty, we should have a symbol list in
380 * the "[vdso]" dso, but for now lets use the old
381 * trick of looking in the whole kernel symbol list.
736 */ 382 */
737 if ((long long)ip < 0) 383 if ((long long)ip < 0)
738 dso = kernel_dso; 384 return kernel_maps__find_symbol(ip, mapp);
739 } 385 }
740 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 386 dump_printf(" ...... dso: %s\n",
387 map ? map->dso->long_name : "<not found>");
741 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); 388 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
742 *ipp = ip; 389 *ipp = ip;
743 390
744 if (dsop) 391 return map ? map->dso->find_symbol(map->dso, ip) : NULL;
745 *dsop = dso;
746
747 if (!dso)
748 return NULL;
749got_dso:
750 return dso->find_symbol(dso, ip);
751} 392}
752 393
753static int call__match(struct symbol *sym) 394static int call__match(struct symbol *sym)
@@ -758,9 +399,9 @@ static int call__match(struct symbol *sym)
758 return 0; 399 return 0;
759} 400}
760 401
761static struct symbol ** 402static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
762resolve_callchain(struct thread *thread, struct map *map __used, 403 struct ip_callchain *chain,
763 struct ip_callchain *chain, struct hist_entry *entry) 404 struct symbol **parent)
764{ 405{
765 u64 context = PERF_CONTEXT_MAX; 406 u64 context = PERF_CONTEXT_MAX;
766 struct symbol **syms = NULL; 407 struct symbol **syms = NULL;
@@ -776,8 +417,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
776 417
777 for (i = 0; i < chain->nr; i++) { 418 for (i = 0; i < chain->nr; i++) {
778 u64 ip = chain->ips[i]; 419 u64 ip = chain->ips[i];
779 struct dso *dso = NULL; 420 struct symbol *sym = NULL;
780 struct symbol *sym;
781 421
782 if (ip >= PERF_CONTEXT_MAX) { 422 if (ip >= PERF_CONTEXT_MAX) {
783 context = ip; 423 context = ip;
@@ -786,21 +426,18 @@ resolve_callchain(struct thread *thread, struct map *map __used,
786 426
787 switch (context) { 427 switch (context) {
788 case PERF_CONTEXT_HV: 428 case PERF_CONTEXT_HV:
789 dso = hypervisor_dso;
790 break; 429 break;
791 case PERF_CONTEXT_KERNEL: 430 case PERF_CONTEXT_KERNEL:
792 dso = kernel_dso; 431 sym = kernel_maps__find_symbol(ip, &map);
793 break; 432 break;
794 default: 433 default:
434 sym = resolve_symbol(thread, &map, &ip);
795 break; 435 break;
796 } 436 }
797 437
798 sym = resolve_symbol(thread, NULL, &dso, &ip);
799
800 if (sym) { 438 if (sym) {
801 if (sort__has_parent && call__match(sym) && 439 if (sort__has_parent && !*parent && call__match(sym))
802 !entry->parent) 440 *parent = sym;
803 entry->parent = sym;
804 if (!callchain) 441 if (!callchain)
805 break; 442 break;
806 syms[i] = sym; 443 syms[i] = sym;
@@ -815,177 +452,35 @@ resolve_callchain(struct thread *thread, struct map *map __used,
815 */ 452 */
816 453
817static int 454static int
818hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 455hist_entry__add(struct thread *thread, struct map *map,
819 struct symbol *sym, u64 ip, struct ip_callchain *chain, 456 struct symbol *sym, u64 ip, struct ip_callchain *chain,
820 char level, u64 count) 457 char level, u64 count)
821{ 458{
822 struct rb_node **p = &hist.rb_node; 459 struct symbol **syms = NULL, *parent = NULL;
823 struct rb_node *parent = NULL; 460 bool hit;
824 struct hist_entry *he; 461 struct hist_entry *he;
825 struct symbol **syms = NULL;
826 struct hist_entry entry = {
827 .thread = thread,
828 .map = map,
829 .dso = dso,
830 .sym = sym,
831 .ip = ip,
832 .level = level,
833 .count = count,
834 .parent = NULL,
835 .sorted_chain = RB_ROOT
836 };
837 int cmp;
838 462
839 if ((sort__has_parent || callchain) && chain) 463 if ((sort__has_parent || callchain) && chain)
840 syms = resolve_callchain(thread, map, chain, &entry); 464 syms = resolve_callchain(thread, map, chain, &parent);
841 465
842 while (*p != NULL) { 466 he = __hist_entry__add(thread, map, sym, parent,
843 parent = *p; 467 ip, count, level, &hit);
844 he = rb_entry(parent, struct hist_entry, rb_node); 468 if (he == NULL)
845 469 return -ENOMEM;
846 cmp = hist_entry__cmp(&entry, he);
847
848 if (!cmp) {
849 he->count += count;
850 if (callchain) {
851 append_chain(&he->callchain, chain, syms);
852 free(syms);
853 }
854 return 0;
855 }
856 470
857 if (cmp < 0) 471 if (hit)
858 p = &(*p)->rb_left; 472 he->count += count;
859 else
860 p = &(*p)->rb_right;
861 }
862 473
863 he = malloc(sizeof(*he));
864 if (!he)
865 return -ENOMEM;
866 *he = entry;
867 if (callchain) { 474 if (callchain) {
868 callchain_init(&he->callchain); 475 if (!hit)
476 callchain_init(&he->callchain);
869 append_chain(&he->callchain, chain, syms); 477 append_chain(&he->callchain, chain, syms);
870 free(syms); 478 free(syms);
871 } 479 }
872 rb_link_node(&he->rb_node, parent, p);
873 rb_insert_color(&he->rb_node, &hist);
874 480
875 return 0; 481 return 0;
876} 482}
877 483
878static void hist_entry__free(struct hist_entry *he)
879{
880 free(he);
881}
882
883/*
884 * collapse the histogram
885 */
886
887static struct rb_root collapse_hists;
888
889static void collapse__insert_entry(struct hist_entry *he)
890{
891 struct rb_node **p = &collapse_hists.rb_node;
892 struct rb_node *parent = NULL;
893 struct hist_entry *iter;
894 int64_t cmp;
895
896 while (*p != NULL) {
897 parent = *p;
898 iter = rb_entry(parent, struct hist_entry, rb_node);
899
900 cmp = hist_entry__collapse(iter, he);
901
902 if (!cmp) {
903 iter->count += he->count;
904 hist_entry__free(he);
905 return;
906 }
907
908 if (cmp < 0)
909 p = &(*p)->rb_left;
910 else
911 p = &(*p)->rb_right;
912 }
913
914 rb_link_node(&he->rb_node, parent, p);
915 rb_insert_color(&he->rb_node, &collapse_hists);
916}
917
918static void collapse__resort(void)
919{
920 struct rb_node *next;
921 struct hist_entry *n;
922
923 if (!sort__need_collapse)
924 return;
925
926 next = rb_first(&hist);
927 while (next) {
928 n = rb_entry(next, struct hist_entry, rb_node);
929 next = rb_next(&n->rb_node);
930
931 rb_erase(&n->rb_node, &hist);
932 collapse__insert_entry(n);
933 }
934}
935
936/*
937 * reverse the map, sort on count.
938 */
939
940static struct rb_root output_hists;
941
942static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
943{
944 struct rb_node **p = &output_hists.rb_node;
945 struct rb_node *parent = NULL;
946 struct hist_entry *iter;
947
948 if (callchain)
949 callchain_param.sort(&he->sorted_chain, &he->callchain,
950 min_callchain_hits, &callchain_param);
951
952 while (*p != NULL) {
953 parent = *p;
954 iter = rb_entry(parent, struct hist_entry, rb_node);
955
956 if (he->count > iter->count)
957 p = &(*p)->rb_left;
958 else
959 p = &(*p)->rb_right;
960 }
961
962 rb_link_node(&he->rb_node, parent, p);
963 rb_insert_color(&he->rb_node, &output_hists);
964}
965
966static void output__resort(u64 total_samples)
967{
968 struct rb_node *next;
969 struct hist_entry *n;
970 struct rb_root *tree = &hist;
971 u64 min_callchain_hits;
972
973 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
974
975 if (sort__need_collapse)
976 tree = &collapse_hists;
977
978 next = rb_first(tree);
979
980 while (next) {
981 n = rb_entry(next, struct hist_entry, rb_node);
982 next = rb_next(&n->rb_node);
983
984 rb_erase(&n->rb_node, tree);
985 output__insert_entry(n, min_callchain_hits);
986 }
987}
988
989static size_t output__fprintf(FILE *fp, u64 total_samples) 484static size_t output__fprintf(FILE *fp, u64 total_samples)
990{ 485{
991 struct hist_entry *pos; 486 struct hist_entry *pos;
@@ -1080,13 +575,6 @@ print_entries:
1080 return ret; 575 return ret;
1081} 576}
1082 577
1083static unsigned long total = 0,
1084 total_mmap = 0,
1085 total_comm = 0,
1086 total_fork = 0,
1087 total_unknown = 0,
1088 total_lost = 0;
1089
1090static int validate_chain(struct ip_callchain *chain, event_t *event) 578static int validate_chain(struct ip_callchain *chain, event_t *event)
1091{ 579{
1092 unsigned int chain_size; 580 unsigned int chain_size;
@@ -1104,8 +592,7 @@ static int
1104process_sample_event(event_t *event, unsigned long offset, unsigned long head) 592process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1105{ 593{
1106 char level; 594 char level;
1107 int show = 0; 595 struct symbol *sym = NULL;
1108 struct dso *dso = NULL;
1109 struct thread *thread; 596 struct thread *thread;
1110 u64 ip = event->ip.ip; 597 u64 ip = event->ip.ip;
1111 u64 period = 1; 598 u64 period = 1;
@@ -1161,42 +648,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 648 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1162 649
1163 if (cpumode == PERF_RECORD_MISC_KERNEL) { 650 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1164 show = SHOW_KERNEL;
1165 level = 'k'; 651 level = 'k';
1166 652 sym = kernel_maps__find_symbol(ip, &map);
1167 dso = kernel_dso; 653 dump_printf(" ...... dso: %s\n",
1168 654 map ? map->dso->long_name : "<not found>");
1169 dump_printf(" ...... dso: %s\n", dso->name);
1170
1171 } else if (cpumode == PERF_RECORD_MISC_USER) { 655 } else if (cpumode == PERF_RECORD_MISC_USER) {
1172
1173 show = SHOW_USER;
1174 level = '.'; 656 level = '.';
657 sym = resolve_symbol(thread, &map, &ip);
1175 658
1176 } else { 659 } else {
1177 show = SHOW_HV;
1178 level = 'H'; 660 level = 'H';
1179
1180 dso = hypervisor_dso;
1181
1182 dump_printf(" ...... dso: [hypervisor]\n"); 661 dump_printf(" ...... dso: [hypervisor]\n");
1183 } 662 }
1184 663
1185 if (show & show_mask) { 664 if (dso_list &&
1186 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 665 (!map || !map->dso ||
1187 666 !(strlist__has_entry(dso_list, map->dso->short_name) ||
1188 if (dso_list && (!dso || !dso->name || 667 (map->dso->short_name != map->dso->long_name &&
1189 !strlist__has_entry(dso_list, dso->name))) 668 strlist__has_entry(dso_list, map->dso->long_name)))))
1190 return 0; 669 return 0;
1191 670
1192 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name))) 671 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
1193 return 0; 672 return 0;
1194 673
1195 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 674 if (hist_entry__add(thread, map, sym, ip,
1196 eprintf("problem incrementing symbol count, skipping event\n"); 675 chain, level, period)) {
1197 return -1; 676 eprintf("problem incrementing symbol count, skipping event\n");
1198 } 677 return -1;
1199 } 678 }
679
1200 total += period; 680 total += period;
1201 681
1202 return 0; 682 return 0;
@@ -1331,216 +811,79 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
1331 return 0; 811 return 0;
1332} 812}
1333 813
1334static int 814static int sample_type_check(u64 type)
1335process_event(event_t *event, unsigned long offset, unsigned long head)
1336{ 815{
1337 trace_event(event); 816 sample_type = type;
1338
1339 switch (event->header.type) {
1340 case PERF_RECORD_SAMPLE:
1341 return process_sample_event(event, offset, head);
1342
1343 case PERF_RECORD_MMAP:
1344 return process_mmap_event(event, offset, head);
1345
1346 case PERF_RECORD_COMM:
1347 return process_comm_event(event, offset, head);
1348
1349 case PERF_RECORD_FORK:
1350 case PERF_RECORD_EXIT:
1351 return process_task_event(event, offset, head);
1352
1353 case PERF_RECORD_LOST:
1354 return process_lost_event(event, offset, head);
1355
1356 case PERF_RECORD_READ:
1357 return process_read_event(event, offset, head);
1358
1359 /*
1360 * We dont process them right now but they are fine:
1361 */
1362
1363 case PERF_RECORD_THROTTLE:
1364 case PERF_RECORD_UNTHROTTLE:
1365 return 0;
1366
1367 default:
1368 return -1;
1369 }
1370
1371 return 0;
1372}
1373
1374static int __cmd_report(void)
1375{
1376 int ret, rc = EXIT_FAILURE;
1377 unsigned long offset = 0;
1378 unsigned long head, shift;
1379 struct stat input_stat;
1380 struct thread *idle;
1381 event_t *event;
1382 uint32_t size;
1383 char *buf;
1384
1385 idle = register_idle_thread(&threads, &last_match);
1386 thread__comm_adjust(idle);
1387
1388 if (show_threads)
1389 perf_read_values_init(&show_threads_values);
1390
1391 input = open(input_name, O_RDONLY);
1392 if (input < 0) {
1393 fprintf(stderr, " failed to open file: %s", input_name);
1394 if (!strcmp(input_name, "perf.data"))
1395 fprintf(stderr, " (try 'perf record' first)");
1396 fprintf(stderr, "\n");
1397 exit(-1);
1398 }
1399
1400 ret = fstat(input, &input_stat);
1401 if (ret < 0) {
1402 perror("failed to stat file");
1403 exit(-1);
1404 }
1405
1406 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
1407 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1408 exit(-1);
1409 }
1410
1411 if (!input_stat.st_size) {
1412 fprintf(stderr, "zero-sized file, nothing to do!\n");
1413 exit(0);
1414 }
1415
1416 header = perf_header__read(input);
1417 head = header->data_offset;
1418
1419 sample_type = perf_header__sample_type(header);
1420 817
1421 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { 818 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1422 if (sort__has_parent) { 819 if (sort__has_parent) {
1423 fprintf(stderr, "selected --sort parent, but no" 820 fprintf(stderr, "selected --sort parent, but no"
1424 " callchain data. Did you call" 821 " callchain data. Did you call"
1425 " perf record without -g?\n"); 822 " perf record without -g?\n");
1426 exit(-1); 823 return -1;
1427 } 824 }
1428 if (callchain) { 825 if (callchain) {
1429 fprintf(stderr, "selected -g but no callchain data." 826 fprintf(stderr, "selected -g but no callchain data."
1430 " Did you call perf record without" 827 " Did you call perf record without"
1431 " -g?\n"); 828 " -g?\n");
1432 exit(-1); 829 return -1;
1433 } 830 }
1434 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 831 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1435 callchain = 1; 832 callchain = 1;
1436 if (register_callchain_param(&callchain_param) < 0) { 833 if (register_callchain_param(&callchain_param) < 0) {
1437 fprintf(stderr, "Can't register callchain" 834 fprintf(stderr, "Can't register callchain"
1438 " params\n"); 835 " params\n");
1439 exit(-1); 836 return -1;
1440 } 837 }
1441 } 838 }
1442 839
1443 if (load_kernel() < 0) { 840 return 0;
1444 perror("failed to load kernel symbols"); 841}
1445 return EXIT_FAILURE;
1446 }
1447
1448 if (!full_paths) {
1449 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1450 perror("failed to get the current directory");
1451 return EXIT_FAILURE;
1452 }
1453 cwdlen = strlen(cwd);
1454 } else {
1455 cwd = NULL;
1456 cwdlen = 0;
1457 }
1458
1459 shift = page_size * (head / page_size);
1460 offset += shift;
1461 head -= shift;
1462
1463remap:
1464 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1465 MAP_SHARED, input, offset);
1466 if (buf == MAP_FAILED) {
1467 perror("failed to mmap file");
1468 exit(-1);
1469 }
1470
1471more:
1472 event = (event_t *)(buf + head);
1473
1474 size = event->header.size;
1475 if (!size)
1476 size = 8;
1477
1478 if (head + event->header.size >= page_size * mmap_window) {
1479 int munmap_ret;
1480
1481 shift = page_size * (head / page_size);
1482
1483 munmap_ret = munmap(buf, page_size * mmap_window);
1484 assert(munmap_ret == 0);
1485
1486 offset += shift;
1487 head -= shift;
1488 goto remap;
1489 }
1490
1491 size = event->header.size;
1492
1493 dump_printf("\n%p [%p]: event: %d\n",
1494 (void *)(offset + head),
1495 (void *)(long)event->header.size,
1496 event->header.type);
1497
1498 if (!size || process_event(event, offset, head) < 0) {
1499
1500 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1501 (void *)(offset + head),
1502 (void *)(long)(event->header.size),
1503 event->header.type);
1504
1505 total_unknown++;
1506 842
1507 /* 843static struct perf_file_handler file_handler = {
1508 * assume we lost track of the stream, check alignment, and 844 .process_sample_event = process_sample_event,
1509 * increment a single u64 in the hope to catch on again 'soon'. 845 .process_mmap_event = process_mmap_event,
1510 */ 846 .process_comm_event = process_comm_event,
847 .process_exit_event = process_task_event,
848 .process_fork_event = process_task_event,
849 .process_lost_event = process_lost_event,
850 .process_read_event = process_read_event,
851 .sample_type_check = sample_type_check,
852};
1511 853
1512 if (unlikely(head & 7))
1513 head &= ~7ULL;
1514 854
1515 size = 8; 855static int __cmd_report(void)
1516 } 856{
857 struct thread *idle;
858 int ret;
1517 859
1518 head += size; 860 idle = register_idle_thread(&threads, &last_match);
861 thread__comm_adjust(idle);
1519 862
1520 if (offset + head >= header->data_offset + header->data_size) 863 if (show_threads)
1521 goto done; 864 perf_read_values_init(&show_threads_values);
1522 865
1523 if (offset + head < (unsigned long)input_stat.st_size) 866 register_perf_file_handler(&file_handler);
1524 goto more;
1525 867
1526done: 868 ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths,
1527 rc = EXIT_SUCCESS; 869 &cwdlen, &cwd);
1528 close(input); 870 if (ret)
871 return ret;
1529 872
1530 dump_printf(" IP events: %10ld\n", total); 873 dump_printf(" IP events: %10ld\n", total);
1531 dump_printf(" mmap events: %10ld\n", total_mmap); 874 dump_printf(" mmap events: %10ld\n", total_mmap);
1532 dump_printf(" comm events: %10ld\n", total_comm); 875 dump_printf(" comm events: %10ld\n", total_comm);
1533 dump_printf(" fork events: %10ld\n", total_fork); 876 dump_printf(" fork events: %10ld\n", total_fork);
1534 dump_printf(" lost events: %10ld\n", total_lost); 877 dump_printf(" lost events: %10ld\n", total_lost);
1535 dump_printf(" unknown events: %10ld\n", total_unknown); 878 dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);
1536 879
1537 if (dump_trace) 880 if (dump_trace)
1538 return 0; 881 return 0;
1539 882
1540 if (verbose >= 3) 883 if (verbose > 3)
1541 threads__fprintf(stdout, &threads); 884 threads__fprintf(stdout, &threads);
1542 885
1543 if (verbose >= 2) 886 if (verbose > 2)
1544 dsos__fprintf(stdout); 887 dsos__fprintf(stdout);
1545 888
1546 collapse__resort(); 889 collapse__resort();
@@ -1550,7 +893,7 @@ done:
1550 if (show_threads) 893 if (show_threads)
1551 perf_read_values_destroy(&show_threads_values); 894 perf_read_values_destroy(&show_threads_values);
1552 895
1553 return rc; 896 return ret;
1554} 897}
1555 898
1556static int 899static int
@@ -1606,7 +949,8 @@ setup:
1606 return 0; 949 return 0;
1607} 950}
1608 951
1609static const char * const report_usage[] = { 952//static const char * const report_usage[] = {
953const char * const report_usage[] = {
1610 "perf report [<options>] <command>", 954 "perf report [<options>] <command>",
1611 NULL 955 NULL
1612}; 956};
@@ -1692,8 +1036,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1692{ 1036{
1693 symbol__init(); 1037 symbol__init();
1694 1038
1695 page_size = getpagesize();
1696
1697 argc = parse_options(argc, argv, options, report_usage, 0); 1039 argc = parse_options(argc, argv, options, report_usage, 0);
1698 1040
1699 setup_sorting(); 1041 setup_sorting();
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index ea9c15c0cdfe..387a44234368 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -11,6 +11,7 @@
11#include "util/trace-event.h" 11#include "util/trace-event.h"
12 12
13#include "util/debug.h" 13#include "util/debug.h"
14#include "util/data_map.h"
14 15
15#include <sys/types.h> 16#include <sys/types.h>
16#include <sys/prctl.h> 17#include <sys/prctl.h>
@@ -20,9 +21,6 @@
20#include <math.h> 21#include <math.h>
21 22
22static char const *input_name = "perf.data"; 23static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26 24
27static unsigned long total_comm = 0; 25static unsigned long total_comm = 0;
28 26
@@ -35,6 +33,11 @@ static u64 sample_type;
35static char default_sort_order[] = "avg, max, switch, runtime"; 33static char default_sort_order[] = "avg, max, switch, runtime";
36static char *sort_order = default_sort_order; 34static char *sort_order = default_sort_order;
37 35
36static int profile_cpu = -1;
37
38static char *cwd;
39static int cwdlen;
40
38#define PR_SET_NAME 15 /* Set process name */ 41#define PR_SET_NAME 15 /* Set process name */
39#define MAX_CPUS 4096 42#define MAX_CPUS 4096
40 43
@@ -74,6 +77,7 @@ enum sched_event_type {
74 SCHED_EVENT_RUN, 77 SCHED_EVENT_RUN,
75 SCHED_EVENT_SLEEP, 78 SCHED_EVENT_SLEEP,
76 SCHED_EVENT_WAKEUP, 79 SCHED_EVENT_WAKEUP,
80 SCHED_EVENT_MIGRATION,
77}; 81};
78 82
79struct sched_atom { 83struct sched_atom {
@@ -398,6 +402,8 @@ process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
398 ret = sem_post(atom->wait_sem); 402 ret = sem_post(atom->wait_sem);
399 BUG_ON(ret); 403 BUG_ON(ret);
400 break; 404 break;
405 case SCHED_EVENT_MIGRATION:
406 break;
401 default: 407 default:
402 BUG_ON(1); 408 BUG_ON(1);
403 } 409 }
@@ -637,7 +643,7 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
637{ 643{
638 struct thread *thread; 644 struct thread *thread;
639 645
640 thread = threads__findnew(event->comm.pid, &threads, &last_match); 646 thread = threads__findnew(event->comm.tid, &threads, &last_match);
641 647
642 dump_printf("%p [%p]: perf_event_comm: %s:%d\n", 648 dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
643 (void *)(offset + head), 649 (void *)(offset + head),
@@ -745,6 +751,22 @@ struct trace_fork_event {
745 u32 child_pid; 751 u32 child_pid;
746}; 752};
747 753
754struct trace_migrate_task_event {
755 u32 size;
756
757 u16 common_type;
758 u8 common_flags;
759 u8 common_preempt_count;
760 u32 common_pid;
761 u32 common_tgid;
762
763 char comm[16];
764 u32 pid;
765
766 u32 prio;
767 u32 cpu;
768};
769
748struct trace_sched_handler { 770struct trace_sched_handler {
749 void (*switch_event)(struct trace_switch_event *, 771 void (*switch_event)(struct trace_switch_event *,
750 struct event *, 772 struct event *,
@@ -769,6 +791,12 @@ struct trace_sched_handler {
769 int cpu, 791 int cpu,
770 u64 timestamp, 792 u64 timestamp,
771 struct thread *thread); 793 struct thread *thread);
794
795 void (*migrate_task_event)(struct trace_migrate_task_event *,
796 struct event *,
797 int cpu,
798 u64 timestamp,
799 struct thread *thread);
772}; 800};
773 801
774 802
@@ -1139,7 +1167,12 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1139 1167
1140 atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1168 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1141 1169
1142 if (atom->state != THREAD_SLEEPING) 1170 /*
1171 * You WILL be missing events if you've recorded only
1172 * one CPU, or are only looking at only one, so don't
1173 * make useless noise.
1174 */
1175 if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1143 nr_state_machine_bugs++; 1176 nr_state_machine_bugs++;
1144 1177
1145 nr_timestamps++; 1178 nr_timestamps++;
@@ -1152,11 +1185,51 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1152 atom->wake_up_time = timestamp; 1185 atom->wake_up_time = timestamp;
1153} 1186}
1154 1187
1188static void
1189latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1190 struct event *__event __used,
1191 int cpu __used,
1192 u64 timestamp,
1193 struct thread *thread __used)
1194{
1195 struct work_atoms *atoms;
1196 struct work_atom *atom;
1197 struct thread *migrant;
1198
1199 /*
1200 * Only need to worry about migration when profiling one CPU.
1201 */
1202 if (profile_cpu == -1)
1203 return;
1204
1205 migrant = threads__findnew(migrate_task_event->pid, &threads, &last_match);
1206 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1207 if (!atoms) {
1208 thread_atoms_insert(migrant);
1209 register_pid(migrant->pid, migrant->comm);
1210 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1211 if (!atoms)
1212 die("migration-event: Internal tree error");
1213 add_sched_out_event(atoms, 'R', timestamp);
1214 }
1215
1216 BUG_ON(list_empty(&atoms->work_list));
1217
1218 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1219 atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
1220
1221 nr_timestamps++;
1222
1223 if (atom->sched_out_time > timestamp)
1224 nr_unordered_timestamps++;
1225}
1226
1155static struct trace_sched_handler lat_ops = { 1227static struct trace_sched_handler lat_ops = {
1156 .wakeup_event = latency_wakeup_event, 1228 .wakeup_event = latency_wakeup_event,
1157 .switch_event = latency_switch_event, 1229 .switch_event = latency_switch_event,
1158 .runtime_event = latency_runtime_event, 1230 .runtime_event = latency_runtime_event,
1159 .fork_event = latency_fork_event, 1231 .fork_event = latency_fork_event,
1232 .migrate_task_event = latency_migrate_task_event,
1160}; 1233};
1161 1234
1162static void output_lat_thread(struct work_atoms *work_list) 1235static void output_lat_thread(struct work_atoms *work_list)
@@ -1517,6 +1590,26 @@ process_sched_exit_event(struct event *event,
1517} 1590}
1518 1591
1519static void 1592static void
1593process_sched_migrate_task_event(struct raw_event_sample *raw,
1594 struct event *event,
1595 int cpu __used,
1596 u64 timestamp __used,
1597 struct thread *thread __used)
1598{
1599 struct trace_migrate_task_event migrate_task_event;
1600
1601 FILL_COMMON_FIELDS(migrate_task_event, event, raw->data);
1602
1603 FILL_ARRAY(migrate_task_event, comm, event, raw->data);
1604 FILL_FIELD(migrate_task_event, pid, event, raw->data);
1605 FILL_FIELD(migrate_task_event, prio, event, raw->data);
1606 FILL_FIELD(migrate_task_event, cpu, event, raw->data);
1607
1608 if (trace_handler->migrate_task_event)
1609 trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread);
1610}
1611
1612static void
1520process_raw_event(event_t *raw_event __used, void *more_data, 1613process_raw_event(event_t *raw_event __used, void *more_data,
1521 int cpu, u64 timestamp, struct thread *thread) 1614 int cpu, u64 timestamp, struct thread *thread)
1522{ 1615{
@@ -1539,21 +1632,22 @@ process_raw_event(event_t *raw_event __used, void *more_data,
1539 process_sched_fork_event(raw, event, cpu, timestamp, thread); 1632 process_sched_fork_event(raw, event, cpu, timestamp, thread);
1540 if (!strcmp(event->name, "sched_process_exit")) 1633 if (!strcmp(event->name, "sched_process_exit"))
1541 process_sched_exit_event(event, cpu, timestamp, thread); 1634 process_sched_exit_event(event, cpu, timestamp, thread);
1635 if (!strcmp(event->name, "sched_migrate_task"))
1636 process_sched_migrate_task_event(raw, event, cpu, timestamp, thread);
1542} 1637}
1543 1638
1544static int 1639static int
1545process_sample_event(event_t *event, unsigned long offset, unsigned long head) 1640process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1546{ 1641{
1547 char level;
1548 int show = 0;
1549 struct dso *dso = NULL;
1550 struct thread *thread; 1642 struct thread *thread;
1551 u64 ip = event->ip.ip; 1643 u64 ip = event->ip.ip;
1552 u64 timestamp = -1; 1644 u64 timestamp = -1;
1553 u32 cpu = -1; 1645 u32 cpu = -1;
1554 u64 period = 1; 1646 u64 period = 1;
1555 void *more_data = event->ip.__more_data; 1647 void *more_data = event->ip.__more_data;
1556 int cpumode; 1648
1649 if (!(sample_type & PERF_SAMPLE_RAW))
1650 return 0;
1557 1651
1558 thread = threads__findnew(event->ip.pid, &threads, &last_match); 1652 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1559 1653
@@ -1589,161 +1683,52 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1589 return -1; 1683 return -1;
1590 } 1684 }
1591 1685
1592 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1686 if (profile_cpu != -1 && profile_cpu != (int) cpu)
1593 1687 return 0;
1594 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1595 show = SHOW_KERNEL;
1596 level = 'k';
1597
1598 dso = kernel_dso;
1599
1600 dump_printf(" ...... dso: %s\n", dso->name);
1601
1602 } else if (cpumode == PERF_RECORD_MISC_USER) {
1603
1604 show = SHOW_USER;
1605 level = '.';
1606
1607 } else {
1608 show = SHOW_HV;
1609 level = 'H';
1610
1611 dso = hypervisor_dso;
1612
1613 dump_printf(" ...... dso: [hypervisor]\n");
1614 }
1615 1688
1616 if (sample_type & PERF_SAMPLE_RAW) 1689 process_raw_event(event, more_data, cpu, timestamp, thread);
1617 process_raw_event(event, more_data, cpu, timestamp, thread);
1618 1690
1619 return 0; 1691 return 0;
1620} 1692}
1621 1693
1622static int 1694static int
1623process_event(event_t *event, unsigned long offset, unsigned long head) 1695process_lost_event(event_t *event __used,
1696 unsigned long offset __used,
1697 unsigned long head __used)
1624{ 1698{
1625 trace_event(event); 1699 nr_lost_chunks++;
1626 1700 nr_lost_events += event->lost.lost;
1627 nr_events++;
1628 switch (event->header.type) {
1629 case PERF_RECORD_MMAP:
1630 return 0;
1631 case PERF_RECORD_LOST:
1632 nr_lost_chunks++;
1633 nr_lost_events += event->lost.lost;
1634 return 0;
1635 1701
1636 case PERF_RECORD_COMM: 1702 return 0;
1637 return process_comm_event(event, offset, head); 1703}
1638
1639 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
1640 return 0;
1641 1704
1642 case PERF_RECORD_SAMPLE: 1705static int sample_type_check(u64 type)
1643 return process_sample_event(event, offset, head); 1706{
1707 sample_type = type;
1644 1708
1645 case PERF_RECORD_MAX: 1709 if (!(sample_type & PERF_SAMPLE_RAW)) {
1646 default: 1710 fprintf(stderr,
1711 "No trace sample to read. Did you call perf record "
1712 "without -R?");
1647 return -1; 1713 return -1;
1648 } 1714 }
1649 1715
1650 return 0; 1716 return 0;
1651} 1717}
1652 1718
1719static struct perf_file_handler file_handler = {
1720 .process_sample_event = process_sample_event,
1721 .process_comm_event = process_comm_event,
1722 .process_lost_event = process_lost_event,
1723 .sample_type_check = sample_type_check,
1724};
1725
1653static int read_events(void) 1726static int read_events(void)
1654{ 1727{
1655 int ret, rc = EXIT_FAILURE;
1656 unsigned long offset = 0;
1657 unsigned long head = 0;
1658 struct stat perf_stat;
1659 event_t *event;
1660 uint32_t size;
1661 char *buf;
1662
1663 trace_report();
1664 register_idle_thread(&threads, &last_match); 1728 register_idle_thread(&threads, &last_match);
1729 register_perf_file_handler(&file_handler);
1665 1730
1666 input = open(input_name, O_RDONLY); 1731 return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd);
1667 if (input < 0) {
1668 perror("failed to open file");
1669 exit(-1);
1670 }
1671
1672 ret = fstat(input, &perf_stat);
1673 if (ret < 0) {
1674 perror("failed to stat file");
1675 exit(-1);
1676 }
1677
1678 if (!perf_stat.st_size) {
1679 fprintf(stderr, "zero-sized file, nothing to do!\n");
1680 exit(0);
1681 }
1682 header = perf_header__read(input);
1683 head = header->data_offset;
1684 sample_type = perf_header__sample_type(header);
1685
1686 if (!(sample_type & PERF_SAMPLE_RAW))
1687 die("No trace sample to read. Did you call perf record "
1688 "without -R?");
1689
1690 if (load_kernel() < 0) {
1691 perror("failed to load kernel symbols");
1692 return EXIT_FAILURE;
1693 }
1694
1695remap:
1696 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1697 MAP_SHARED, input, offset);
1698 if (buf == MAP_FAILED) {
1699 perror("failed to mmap file");
1700 exit(-1);
1701 }
1702
1703more:
1704 event = (event_t *)(buf + head);
1705
1706 size = event->header.size;
1707 if (!size)
1708 size = 8;
1709
1710 if (head + event->header.size >= page_size * mmap_window) {
1711 unsigned long shift = page_size * (head / page_size);
1712 int res;
1713
1714 res = munmap(buf, page_size * mmap_window);
1715 assert(res == 0);
1716
1717 offset += shift;
1718 head -= shift;
1719 goto remap;
1720 }
1721
1722 size = event->header.size;
1723
1724
1725 if (!size || process_event(event, offset, head) < 0) {
1726
1727 /*
1728 * assume we lost track of the stream, check alignment, and
1729 * increment a single u64 in the hope to catch on again 'soon'.
1730 */
1731
1732 if (unlikely(head & 7))
1733 head &= ~7ULL;
1734
1735 size = 8;
1736 }
1737
1738 head += size;
1739
1740 if (offset + head < (unsigned long)perf_stat.st_size)
1741 goto more;
1742
1743 rc = EXIT_SUCCESS;
1744 close(input);
1745
1746 return rc;
1747} 1732}
1748 1733
1749static void print_bad_events(void) 1734static void print_bad_events(void)
@@ -1883,6 +1868,8 @@ static const struct option latency_options[] = {
1883 "sort by key(s): runtime, switch, avg, max"), 1868 "sort by key(s): runtime, switch, avg, max"),
1884 OPT_BOOLEAN('v', "verbose", &verbose, 1869 OPT_BOOLEAN('v', "verbose", &verbose,
1885 "be more verbose (show symbol address, etc)"), 1870 "be more verbose (show symbol address, etc)"),
1871 OPT_INTEGER('C', "CPU", &profile_cpu,
1872 "CPU to profile on"),
1886 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1873 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1887 "dump raw trace in ASCII"), 1874 "dump raw trace in ASCII"),
1888 OPT_END() 1875 OPT_END()
@@ -1961,7 +1948,6 @@ static int __cmd_record(int argc, const char **argv)
1961int cmd_sched(int argc, const char **argv, const char *prefix __used) 1948int cmd_sched(int argc, const char **argv, const char *prefix __used)
1962{ 1949{
1963 symbol__init(); 1950 symbol__init();
1964 page_size = getpagesize();
1965 1951
1966 argc = parse_options(argc, argv, sched_options, sched_usage, 1952 argc = parse_options(argc, argv, sched_options, sched_usage,
1967 PARSE_OPT_STOP_AT_NON_OPTION); 1953 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 37512e936235..c0f69e80b2cc 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -22,6 +22,7 @@
22 22
23#include "util/symbol.h" 23#include "util/symbol.h"
24#include "util/color.h" 24#include "util/color.h"
25#include "util/thread.h"
25#include "util/util.h" 26#include "util/util.h"
26#include <linux/rbtree.h> 27#include <linux/rbtree.h>
27#include "util/parse-options.h" 28#include "util/parse-options.h"
@@ -54,26 +55,26 @@
54 55
55static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 56static int fd[MAX_NR_CPUS][MAX_COUNTERS];
56 57
57static int system_wide = 0; 58static int system_wide = 0;
58 59
59static int default_interval = 100000; 60static int default_interval = 0;
60 61
61static int count_filter = 5; 62static int count_filter = 5;
62static int print_entries = 15; 63static int print_entries = 15;
63 64
64static int target_pid = -1; 65static int target_pid = -1;
65static int inherit = 0; 66static int inherit = 0;
66static int profile_cpu = -1; 67static int profile_cpu = -1;
67static int nr_cpus = 0; 68static int nr_cpus = 0;
68static unsigned int realtime_prio = 0; 69static unsigned int realtime_prio = 0;
69static int group = 0; 70static int group = 0;
70static unsigned int page_size; 71static unsigned int page_size;
71static unsigned int mmap_pages = 16; 72static unsigned int mmap_pages = 16;
72static int freq = 0; 73static int freq = 1000; /* 1 KHz */
73 74
74static int delay_secs = 2; 75static int delay_secs = 2;
75static int zero; 76static int zero = 0;
76static int dump_symtab; 77static int dump_symtab = 0;
77 78
78/* 79/*
79 * Source 80 * Source
@@ -86,19 +87,16 @@ struct source_line {
86 struct source_line *next; 87 struct source_line *next;
87}; 88};
88 89
89static char *sym_filter = NULL; 90static char *sym_filter = NULL;
90struct sym_entry *sym_filter_entry = NULL; 91struct sym_entry *sym_filter_entry = NULL;
91static int sym_pcnt_filter = 5; 92static int sym_pcnt_filter = 5;
92static int sym_counter = 0; 93static int sym_counter = 0;
93static int display_weighted = -1; 94static int display_weighted = -1;
94 95
95/* 96/*
96 * Symbols 97 * Symbols
97 */ 98 */
98 99
99static u64 min_ip;
100static u64 max_ip = -1ll;
101
102struct sym_entry { 100struct sym_entry {
103 struct rb_node rb_node; 101 struct rb_node rb_node;
104 struct list_head node; 102 struct list_head node;
@@ -106,6 +104,7 @@ struct sym_entry {
106 unsigned long snap_count; 104 unsigned long snap_count;
107 double weight; 105 double weight;
108 int skip; 106 int skip;
107 struct map *map;
109 struct source_line *source; 108 struct source_line *source;
110 struct source_line *lines; 109 struct source_line *lines;
111 struct source_line **lines_tail; 110 struct source_line **lines_tail;
@@ -119,12 +118,11 @@ struct sym_entry {
119static void parse_source(struct sym_entry *syme) 118static void parse_source(struct sym_entry *syme)
120{ 119{
121 struct symbol *sym; 120 struct symbol *sym;
122 struct module *module; 121 struct map *map;
123 struct section *section = NULL;
124 FILE *file; 122 FILE *file;
125 char command[PATH_MAX*2]; 123 char command[PATH_MAX*2];
126 const char *path = vmlinux_name; 124 const char *path;
127 u64 start, end, len; 125 u64 len;
128 126
129 if (!syme) 127 if (!syme)
130 return; 128 return;
@@ -135,27 +133,15 @@ static void parse_source(struct sym_entry *syme)
135 } 133 }
136 134
137 sym = (struct symbol *)(syme + 1); 135 sym = (struct symbol *)(syme + 1);
138 module = sym->module; 136 map = syme->map;
139 137 path = map->dso->long_name;
140 if (module)
141 path = module->path;
142 if (!path)
143 return;
144
145 start = sym->obj_start;
146 if (!start)
147 start = sym->start;
148 138
149 if (module) {
150 section = module->sections->find_section(module->sections, ".text");
151 if (section)
152 start -= section->vma;
153 }
154
155 end = start + sym->end - sym->start + 1;
156 len = sym->end - sym->start; 139 len = sym->end - sym->start;
157 140
158 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); 141 sprintf(command,
142 "objdump --start-address=0x%016Lx "
143 "--stop-address=0x%016Lx -dS %s",
144 sym->start, sym->end, path);
159 145
160 file = popen(command, "r"); 146 file = popen(command, "r");
161 if (!file) 147 if (!file)
@@ -187,13 +173,11 @@ static void parse_source(struct sym_entry *syme)
187 173
188 if (strlen(src->line)>8 && src->line[8] == ':') { 174 if (strlen(src->line)>8 && src->line[8] == ':') {
189 src->eip = strtoull(src->line, NULL, 16); 175 src->eip = strtoull(src->line, NULL, 16);
190 if (section) 176 src->eip += map->start;
191 src->eip += section->vma;
192 } 177 }
193 if (strlen(src->line)>8 && src->line[16] == ':') { 178 if (strlen(src->line)>8 && src->line[16] == ':') {
194 src->eip = strtoull(src->line, NULL, 16); 179 src->eip = strtoull(src->line, NULL, 16);
195 if (section) 180 src->eip += map->start;
196 src->eip += section->vma;
197 } 181 }
198 } 182 }
199 pclose(file); 183 pclose(file);
@@ -245,16 +229,9 @@ static void lookup_sym_source(struct sym_entry *syme)
245 struct symbol *symbol = (struct symbol *)(syme + 1); 229 struct symbol *symbol = (struct symbol *)(syme + 1);
246 struct source_line *line; 230 struct source_line *line;
247 char pattern[PATH_MAX]; 231 char pattern[PATH_MAX];
248 char *idx;
249 232
250 sprintf(pattern, "<%s>:", symbol->name); 233 sprintf(pattern, "<%s>:", symbol->name);
251 234
252 if (symbol->module) {
253 idx = strstr(pattern, "\t");
254 if (idx)
255 *idx = 0;
256 }
257
258 pthread_mutex_lock(&syme->source_lock); 235 pthread_mutex_lock(&syme->source_lock);
259 for (line = syme->lines; line; line = line->next) { 236 for (line = syme->lines; line; line = line->next) {
260 if (strstr(line->line, pattern)) { 237 if (strstr(line->line, pattern)) {
@@ -516,8 +493,8 @@ static void print_sym_table(void)
516 if (verbose) 493 if (verbose)
517 printf(" - %016llx", sym->start); 494 printf(" - %016llx", sym->start);
518 printf(" : %s", sym->name); 495 printf(" : %s", sym->name);
519 if (sym->module) 496 if (syme->map->dso->name[0] == '[')
520 printf("\t[%s]", sym->module->name); 497 printf(" \t%s", syme->map->dso->name);
521 printf("\n"); 498 printf("\n");
522 } 499 }
523} 500}
@@ -788,7 +765,7 @@ static const char *skip_symbols[] = {
788 NULL 765 NULL
789}; 766};
790 767
791static int symbol_filter(struct dso *self, struct symbol *sym) 768static int symbol_filter(struct map *map, struct symbol *sym)
792{ 769{
793 struct sym_entry *syme; 770 struct sym_entry *syme;
794 const char *name = sym->name; 771 const char *name = sym->name;
@@ -810,7 +787,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
810 strstr(name, "_text_end")) 787 strstr(name, "_text_end"))
811 return 1; 788 return 1;
812 789
813 syme = dso__sym_priv(self, sym); 790 syme = dso__sym_priv(map->dso, sym);
791 syme->map = map;
814 pthread_mutex_init(&syme->source_lock, NULL); 792 pthread_mutex_init(&syme->source_lock, NULL);
815 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 793 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
816 sym_filter_entry = syme; 794 sym_filter_entry = syme;
@@ -827,34 +805,14 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
827 805
828static int parse_symbols(void) 806static int parse_symbols(void)
829{ 807{
830 struct rb_node *node; 808 if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry),
831 struct symbol *sym; 809 symbol_filter, verbose, 1) <= 0)
832 int use_modules = vmlinux_name ? 1 : 0;
833
834 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
835 if (kernel_dso == NULL)
836 return -1; 810 return -1;
837 811
838 if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
839 goto out_delete_dso;
840
841 node = rb_first(&kernel_dso->syms);
842 sym = rb_entry(node, struct symbol, rb_node);
843 min_ip = sym->start;
844
845 node = rb_last(&kernel_dso->syms);
846 sym = rb_entry(node, struct symbol, rb_node);
847 max_ip = sym->end;
848
849 if (dump_symtab) 812 if (dump_symtab)
850 dso__fprintf(kernel_dso, stderr); 813 dsos__fprintf(stderr);
851 814
852 return 0; 815 return 0;
853
854out_delete_dso:
855 dso__delete(kernel_dso);
856 kernel_dso = NULL;
857 return -1;
858} 816}
859 817
860/* 818/*
@@ -862,10 +820,11 @@ out_delete_dso:
862 */ 820 */
863static void record_ip(u64 ip, int counter) 821static void record_ip(u64 ip, int counter)
864{ 822{
865 struct symbol *sym = dso__find_symbol(kernel_dso, ip); 823 struct map *map;
824 struct symbol *sym = kernel_maps__find_symbol(ip, &map);
866 825
867 if (sym != NULL) { 826 if (sym != NULL) {
868 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); 827 struct sym_entry *syme = dso__sym_priv(map->dso, sym);
869 828
870 if (!syme->skip) { 829 if (!syme->skip) {
871 syme->count[counter]++; 830 syme->count[counter]++;
@@ -1016,7 +975,13 @@ static void start_counter(int i, int counter)
1016 attr = attrs + counter; 975 attr = attrs + counter;
1017 976
1018 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 977 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1019 attr->freq = freq; 978
979 if (freq) {
980 attr->sample_type |= PERF_SAMPLE_PERIOD;
981 attr->freq = 1;
982 attr->sample_freq = freq;
983 }
984
1020 attr->inherit = (cpu < 0) && inherit; 985 attr->inherit = (cpu < 0) && inherit;
1021 986
1022try_again: 987try_again:
@@ -1171,11 +1136,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1171 if (argc) 1136 if (argc)
1172 usage_with_options(top_usage, options); 1137 usage_with_options(top_usage, options);
1173 1138
1174 if (freq) {
1175 default_interval = freq;
1176 freq = 1;
1177 }
1178
1179 /* CPU and PID are mutually exclusive */ 1139 /* CPU and PID are mutually exclusive */
1180 if (target_pid != -1 && profile_cpu != -1) { 1140 if (target_pid != -1 && profile_cpu != -1) {
1181 printf("WARNING: PID switch overriding CPU\n"); 1141 printf("WARNING: PID switch overriding CPU\n");
@@ -1192,6 +1152,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1192 parse_symbols(); 1152 parse_symbols();
1193 parse_source(sym_filter_entry); 1153 parse_source(sym_filter_entry);
1194 1154
1155
1156 /*
1157 * User specified count overrides default frequency.
1158 */
1159 if (default_interval)
1160 freq = 0;
1161 else if (freq) {
1162 default_interval = freq;
1163 } else {
1164 fprintf(stderr, "frequency and count are zero, aborting\n");
1165 exit(EXIT_FAILURE);
1166 }
1167
1195 /* 1168 /*
1196 * Fill in the ones not specifically initialized via -c: 1169 * Fill in the ones not specifically initialized via -c:
1197 */ 1170 */
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0c5e4f72f2ba..fb3f3c220211 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -12,11 +12,9 @@
12#include "util/debug.h" 12#include "util/debug.h"
13 13
14#include "util/trace-event.h" 14#include "util/trace-event.h"
15#include "util/data_map.h"
15 16
16static char const *input_name = "perf.data"; 17static char const *input_name = "perf.data";
17static int input;
18static unsigned long page_size;
19static unsigned long mmap_window = 32;
20 18
21static unsigned long total = 0; 19static unsigned long total = 0;
22static unsigned long total_comm = 0; 20static unsigned long total_comm = 0;
@@ -27,6 +25,9 @@ static struct thread *last_match;
27static struct perf_header *header; 25static struct perf_header *header;
28static u64 sample_type; 26static u64 sample_type;
29 27
28static char *cwd;
29static int cwdlen;
30
30 31
31static int 32static int
32process_comm_event(event_t *event, unsigned long offset, unsigned long head) 33process_comm_event(event_t *event, unsigned long offset, unsigned long head)
@@ -53,16 +54,12 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
53static int 54static int
54process_sample_event(event_t *event, unsigned long offset, unsigned long head) 55process_sample_event(event_t *event, unsigned long offset, unsigned long head)
55{ 56{
56 char level;
57 int show = 0;
58 struct dso *dso = NULL;
59 struct thread *thread; 57 struct thread *thread;
60 u64 ip = event->ip.ip; 58 u64 ip = event->ip.ip;
61 u64 timestamp = -1; 59 u64 timestamp = -1;
62 u32 cpu = -1; 60 u32 cpu = -1;
63 u64 period = 1; 61 u64 period = 1;
64 void *more_data = event->ip.__more_data; 62 void *more_data = event->ip.__more_data;
65 int cpumode;
66 63
67 thread = threads__findnew(event->ip.pid, &threads, &last_match); 64 thread = threads__findnew(event->ip.pid, &threads, &last_match);
68 65
@@ -98,30 +95,6 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
98 return -1; 95 return -1;
99 } 96 }
100 97
101 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
102
103 if (cpumode == PERF_RECORD_MISC_KERNEL) {
104 show = SHOW_KERNEL;
105 level = 'k';
106
107 dso = kernel_dso;
108
109 dump_printf(" ...... dso: %s\n", dso->name);
110
111 } else if (cpumode == PERF_RECORD_MISC_USER) {
112
113 show = SHOW_USER;
114 level = '.';
115
116 } else {
117 show = SHOW_HV;
118 level = 'H';
119
120 dso = hypervisor_dso;
121
122 dump_printf(" ...... dso: [hypervisor]\n");
123 }
124
125 if (sample_type & PERF_SAMPLE_RAW) { 98 if (sample_type & PERF_SAMPLE_RAW) {
126 struct { 99 struct {
127 u32 size; 100 u32 size;
@@ -140,121 +113,32 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
140 return 0; 113 return 0;
141} 114}
142 115
143static int 116static int sample_type_check(u64 type)
144process_event(event_t *event, unsigned long offset, unsigned long head)
145{ 117{
146 trace_event(event); 118 sample_type = type;
147 119
148 switch (event->header.type) { 120 if (!(sample_type & PERF_SAMPLE_RAW)) {
149 case PERF_RECORD_MMAP ... PERF_RECORD_LOST: 121 fprintf(stderr,
150 return 0; 122 "No trace sample to read. Did you call perf record "
151 123 "without -R?");
152 case PERF_RECORD_COMM:
153 return process_comm_event(event, offset, head);
154
155 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
156 return 0;
157
158 case PERF_RECORD_SAMPLE:
159 return process_sample_event(event, offset, head);
160
161 case PERF_RECORD_MAX:
162 default:
163 return -1; 124 return -1;
164 } 125 }
165 126
166 return 0; 127 return 0;
167} 128}
168 129
130static struct perf_file_handler file_handler = {
131 .process_sample_event = process_sample_event,
132 .process_comm_event = process_comm_event,
133 .sample_type_check = sample_type_check,
134};
135
169static int __cmd_trace(void) 136static int __cmd_trace(void)
170{ 137{
171 int ret, rc = EXIT_FAILURE;
172 unsigned long offset = 0;
173 unsigned long head = 0;
174 struct stat perf_stat;
175 event_t *event;
176 uint32_t size;
177 char *buf;
178
179 trace_report();
180 register_idle_thread(&threads, &last_match); 138 register_idle_thread(&threads, &last_match);
139 register_perf_file_handler(&file_handler);
181 140
182 input = open(input_name, O_RDONLY); 141 return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd);
183 if (input < 0) {
184 perror("failed to open file");
185 exit(-1);
186 }
187
188 ret = fstat(input, &perf_stat);
189 if (ret < 0) {
190 perror("failed to stat file");
191 exit(-1);
192 }
193
194 if (!perf_stat.st_size) {
195 fprintf(stderr, "zero-sized file, nothing to do!\n");
196 exit(0);
197 }
198 header = perf_header__read(input);
199 head = header->data_offset;
200 sample_type = perf_header__sample_type(header);
201
202 if (!(sample_type & PERF_SAMPLE_RAW))
203 die("No trace sample to read. Did you call perf record "
204 "without -R?");
205
206 if (load_kernel() < 0) {
207 perror("failed to load kernel symbols");
208 return EXIT_FAILURE;
209 }
210
211remap:
212 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
213 MAP_SHARED, input, offset);
214 if (buf == MAP_FAILED) {
215 perror("failed to mmap file");
216 exit(-1);
217 }
218
219more:
220 event = (event_t *)(buf + head);
221
222 if (head + event->header.size >= page_size * mmap_window) {
223 unsigned long shift = page_size * (head / page_size);
224 int res;
225
226 res = munmap(buf, page_size * mmap_window);
227 assert(res == 0);
228
229 offset += shift;
230 head -= shift;
231 goto remap;
232 }
233
234 size = event->header.size;
235
236 if (!size || process_event(event, offset, head) < 0) {
237
238 /*
239 * assume we lost track of the stream, check alignment, and
240 * increment a single u64 in the hope to catch on again 'soon'.
241 */
242
243 if (unlikely(head & 7))
244 head &= ~7ULL;
245
246 size = 8;
247 }
248
249 head += size;
250
251 if (offset + head < (unsigned long)perf_stat.st_size)
252 goto more;
253
254 rc = EXIT_SUCCESS;
255 close(input);
256
257 return rc;
258} 142}
259 143
260static const char * const annotate_usage[] = { 144static const char * const annotate_usage[] = {
@@ -273,7 +157,6 @@ static const struct option options[] = {
273int cmd_trace(int argc, const char **argv, const char *prefix __used) 157int cmd_trace(int argc, const char **argv, const char *prefix __used)
274{ 158{
275 symbol__init(); 159 symbol__init();
276 page_size = getpagesize();
277 160
278 argc = parse_options(argc, argv, options, annotate_usage, 0); 161 argc = parse_options(argc, argv, options, annotate_usage, 0);
279 if (argc) { 162 if (argc) {
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 6f8ea9d210b6..f26172c0c919 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,5 +1,5 @@
1#ifndef CACHE_H 1#ifndef __PERF_CACHE_H
2#define CACHE_H 2#define __PERF_CACHE_H
3 3
4#include "util.h" 4#include "util.h"
5#include "strbuf.h" 5#include "strbuf.h"
@@ -117,4 +117,4 @@ extern char *perf_pathdup(const char *fmt, ...)
117 117
118extern size_t strlcpy(char *dest, const char *src, size_t size); 118extern size_t strlcpy(char *dest, const char *src, size_t size);
119 119
120#endif /* CACHE_H */ 120#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 43cf3ea9e088..ad4626de4c2b 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
58int register_callchain_param(struct callchain_param *param); 58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 59void append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 60 struct symbol **syms);
61#endif 61#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 58d597564b99..24e8809210bb 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -1,5 +1,5 @@
1#ifndef COLOR_H 1#ifndef __PERF_COLOR_H
2#define COLOR_H 2#define __PERF_COLOR_H
3 3
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ 4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24 5#define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 40const char *get_percent_color(double percent);
41 41
42#endif /* COLOR_H */ 42#endif /* __PERF_COLOR_H */
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
new file mode 100644
index 000000000000..242b0555ab91
--- /dev/null
+++ b/tools/perf/util/data_map.c
@@ -0,0 +1,222 @@
1#include "data_map.h"
2#include "symbol.h"
3#include "util.h"
4#include "debug.h"
5
6
7static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int
12process_event_stub(event_t *event __used,
13 unsigned long offset __used,
14 unsigned long head __used)
15{
16 return 0;
17}
18
19void register_perf_file_handler(struct perf_file_handler *handler)
20{
21 if (!handler->process_sample_event)
22 handler->process_sample_event = process_event_stub;
23 if (!handler->process_mmap_event)
24 handler->process_mmap_event = process_event_stub;
25 if (!handler->process_comm_event)
26 handler->process_comm_event = process_event_stub;
27 if (!handler->process_fork_event)
28 handler->process_fork_event = process_event_stub;
29 if (!handler->process_exit_event)
30 handler->process_exit_event = process_event_stub;
31 if (!handler->process_lost_event)
32 handler->process_lost_event = process_event_stub;
33 if (!handler->process_read_event)
34 handler->process_read_event = process_event_stub;
35 if (!handler->process_throttle_event)
36 handler->process_throttle_event = process_event_stub;
37 if (!handler->process_unthrottle_event)
38 handler->process_unthrottle_event = process_event_stub;
39
40 curr_handler = handler;
41}
42
43static int
44process_event(event_t *event, unsigned long offset, unsigned long head)
45{
46 trace_event(event);
47
48 switch (event->header.type) {
49 case PERF_RECORD_SAMPLE:
50 return curr_handler->process_sample_event(event, offset, head);
51 case PERF_RECORD_MMAP:
52 return curr_handler->process_mmap_event(event, offset, head);
53 case PERF_RECORD_COMM:
54 return curr_handler->process_comm_event(event, offset, head);
55 case PERF_RECORD_FORK:
56 return curr_handler->process_fork_event(event, offset, head);
57 case PERF_RECORD_EXIT:
58 return curr_handler->process_exit_event(event, offset, head);
59 case PERF_RECORD_LOST:
60 return curr_handler->process_lost_event(event, offset, head);
61 case PERF_RECORD_READ:
62 return curr_handler->process_read_event(event, offset, head);
63 case PERF_RECORD_THROTTLE:
64 return curr_handler->process_throttle_event(event, offset, head);
65 case PERF_RECORD_UNTHROTTLE:
66 return curr_handler->process_unthrottle_event(event, offset, head);
67 default:
68 curr_handler->total_unknown++;
69 return -1;
70 }
71}
72
73int mmap_dispatch_perf_file(struct perf_header **pheader,
74 const char *input_name,
75 int force,
76 int full_paths,
77 int *cwdlen,
78 char **cwd)
79{
80 int ret, rc = EXIT_FAILURE;
81 struct perf_header *header;
82 unsigned long head, shift;
83 unsigned long offset = 0;
84 struct stat input_stat;
85 size_t page_size;
86 u64 sample_type;
87 event_t *event;
88 uint32_t size;
89 int input;
90 char *buf;
91
92 if (!curr_handler)
93 die("Forgot to register perf file handler");
94
95 page_size = getpagesize();
96
97 input = open(input_name, O_RDONLY);
98 if (input < 0) {
99 fprintf(stderr, " failed to open file: %s", input_name);
100 if (!strcmp(input_name, "perf.data"))
101 fprintf(stderr, " (try 'perf record' first)");
102 fprintf(stderr, "\n");
103 exit(-1);
104 }
105
106 ret = fstat(input, &input_stat);
107 if (ret < 0) {
108 perror("failed to stat file");
109 exit(-1);
110 }
111
112 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
113 fprintf(stderr, "file: %s not owned by current user or root\n",
114 input_name);
115 exit(-1);
116 }
117
118 if (!input_stat.st_size) {
119 fprintf(stderr, "zero-sized file, nothing to do!\n");
120 exit(0);
121 }
122
123 *pheader = perf_header__read(input);
124 header = *pheader;
125 head = header->data_offset;
126
127 sample_type = perf_header__sample_type(header);
128
129 if (curr_handler->sample_type_check)
130 if (curr_handler->sample_type_check(sample_type) < 0)
131 exit(-1);
132
133 if (load_kernel() < 0) {
134 perror("failed to load kernel symbols");
135 return EXIT_FAILURE;
136 }
137
138 if (!full_paths) {
139 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
140 perror("failed to get the current directory");
141 return EXIT_FAILURE;
142 }
143 *cwd = __cwd;
144 *cwdlen = strlen(*cwd);
145 } else {
146 *cwd = NULL;
147 *cwdlen = 0;
148 }
149
150 shift = page_size * (head / page_size);
151 offset += shift;
152 head -= shift;
153
154remap:
155 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
156 MAP_SHARED, input, offset);
157 if (buf == MAP_FAILED) {
158 perror("failed to mmap file");
159 exit(-1);
160 }
161
162more:
163 event = (event_t *)(buf + head);
164
165 size = event->header.size;
166 if (!size)
167 size = 8;
168
169 if (head + event->header.size >= page_size * mmap_window) {
170 int munmap_ret;
171
172 shift = page_size * (head / page_size);
173
174 munmap_ret = munmap(buf, page_size * mmap_window);
175 assert(munmap_ret == 0);
176
177 offset += shift;
178 head -= shift;
179 goto remap;
180 }
181
182 size = event->header.size;
183
184 dump_printf("\n%p [%p]: event: %d\n",
185 (void *)(offset + head),
186 (void *)(long)event->header.size,
187 event->header.type);
188
189 if (!size || process_event(event, offset, head) < 0) {
190
191 dump_printf("%p [%p]: skipping unknown header type: %d\n",
192 (void *)(offset + head),
193 (void *)(long)(event->header.size),
194 event->header.type);
195
196 /*
197 * assume we lost track of the stream, check alignment, and
198 * increment a single u64 in the hope to catch on again 'soon'.
199 */
200
201 if (unlikely(head & 7))
202 head &= ~7ULL;
203
204 size = 8;
205 }
206
207 head += size;
208
209 if (offset + head >= header->data_offset + header->data_size)
210 goto done;
211
212 if (offset + head < (unsigned long)input_stat.st_size)
213 goto more;
214
215done:
216 rc = EXIT_SUCCESS;
217 close(input);
218
219 return rc;
220}
221
222
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
new file mode 100644
index 000000000000..716d1053b074
--- /dev/null
+++ b/tools/perf/util/data_map.h
@@ -0,0 +1,31 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6
7typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long);
8
9struct perf_file_handler {
10 event_type_handler_t process_sample_event;
11 event_type_handler_t process_mmap_event;
12 event_type_handler_t process_comm_event;
13 event_type_handler_t process_fork_event;
14 event_type_handler_t process_exit_event;
15 event_type_handler_t process_lost_event;
16 event_type_handler_t process_read_event;
17 event_type_handler_t process_throttle_event;
18 event_type_handler_t process_unthrottle_event;
19 int (*sample_type_check)(u64 sample_type);
20 unsigned long total_unknown;
21};
22
23void register_perf_file_handler(struct perf_file_handler *handler);
24int mmap_dispatch_perf_file(struct perf_header **pheader,
25 const char *input_name,
26 int force,
27 int full_paths,
28 int *cwdlen,
29 char **cwd);
30
31#endif
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 437eea58ce40..02d1fa1c2465 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -1,4 +1,6 @@
1/* For debugging general purposes */ 1/* For debugging general purposes */
2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H
2 4
3extern int verbose; 5extern int verbose;
4extern int dump_trace; 6extern int dump_trace;
@@ -6,3 +8,5 @@ extern int dump_trace;
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 8int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 9int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event); 10void trace_event(event_t *event);
11
12#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..c2e62be62798 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,14 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3
3#include "../perf.h" 4#include "../perf.h"
4#include "util.h" 5#include "util.h"
5#include <linux/list.h> 6#include <linux/list.h>
6 7#include <linux/rbtree.h>
7enum {
8 SHOW_KERNEL = 1,
9 SHOW_USER = 2,
10 SHOW_HV = 4,
11};
12 8
13/* 9/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -78,7 +74,10 @@ typedef union event_union {
78} event_t; 74} event_t;
79 75
80struct map { 76struct map {
81 struct list_head node; 77 union {
78 struct rb_node rb_node;
79 struct list_head node;
80 };
82 u64 start; 81 u64 start;
83 u64 end; 82 u64 end;
84 u64 pgoff; 83 u64 pgoff;
@@ -101,4 +100,4 @@ struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r); 100int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp); 101size_t map__fprintf(struct map *self, FILE *fp);
103 102
104#endif 103#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index effe25eb1545..31647ac92ed1 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -1,5 +1,5 @@
1#ifndef PERF_EXEC_CMD_H 1#ifndef __PERF_EXEC_CMD_H
2#define PERF_EXEC_CMD_H 2#define __PERF_EXEC_CMD_H
3 3
4extern void perf_set_argv_exec_path(const char *exec_path); 4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path); 5extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...); 10extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path); 11extern const char *system_path(const char *path);
12 12
13#endif /* PERF_EXEC_CMD_H */ 13#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e306857b2c2b..9aae360c0f28 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -5,6 +5,8 @@
5 5
6#include "util.h" 6#include "util.h"
7#include "header.h" 7#include "header.h"
8#include "../perf.h"
9#include "trace-event.h"
8 10
9/* 11/*
10 * Create new perf.data header attribute: 12 * Create new perf.data header attribute:
@@ -62,6 +64,8 @@ struct perf_header *perf_header__new(void)
62 64
63 self->data_offset = 0; 65 self->data_offset = 0;
64 self->data_size = 0; 66 self->data_size = 0;
67 self->trace_info_offset = 0;
68 self->trace_info_size = 0;
65 69
66 return self; 70 return self;
67} 71}
@@ -145,8 +149,16 @@ struct perf_file_header {
145 struct perf_file_section attrs; 149 struct perf_file_section attrs;
146 struct perf_file_section data; 150 struct perf_file_section data;
147 struct perf_file_section event_types; 151 struct perf_file_section event_types;
152 struct perf_file_section trace_info;
148}; 153};
149 154
155static int trace_info;
156
157void perf_header__set_trace_info(void)
158{
159 trace_info = 1;
160}
161
150static void do_write(int fd, void *buf, size_t size) 162static void do_write(int fd, void *buf, size_t size)
151{ 163{
152 while (size) { 164 while (size) {
@@ -198,6 +210,23 @@ void perf_header__write(struct perf_header *self, int fd)
198 if (events) 210 if (events)
199 do_write(fd, events, self->event_size); 211 do_write(fd, events, self->event_size);
200 212
213 if (trace_info) {
214 static int trace_info_written;
215
216 /*
217 * Write it only once
218 */
219 if (!trace_info_written) {
220 self->trace_info_offset = lseek(fd, 0, SEEK_CUR);
221 read_tracing_data(fd, attrs, nr_counters);
222 self->trace_info_size = lseek(fd, 0, SEEK_CUR) -
223 self->trace_info_offset;
224 trace_info_written = 1;
225 } else {
226 lseek(fd, self->trace_info_offset +
227 self->trace_info_size, SEEK_SET);
228 }
229 }
201 230
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 231 self->data_offset = lseek(fd, 0, SEEK_CUR);
203 232
@@ -217,6 +246,10 @@ void perf_header__write(struct perf_header *self, int fd)
217 .offset = self->event_offset, 246 .offset = self->event_offset,
218 .size = self->event_size, 247 .size = self->event_size,
219 }, 248 },
249 .trace_info = {
250 .offset = self->trace_info_offset,
251 .size = self->trace_info_size,
252 },
220 }; 253 };
221 254
222 lseek(fd, 0, SEEK_SET); 255 lseek(fd, 0, SEEK_SET);
@@ -254,10 +287,16 @@ struct perf_header *perf_header__read(int fd)
254 do_read(fd, &f_header, sizeof(f_header)); 287 do_read(fd, &f_header, sizeof(f_header));
255 288
256 if (f_header.magic != PERF_MAGIC || 289 if (f_header.magic != PERF_MAGIC ||
257 f_header.size != sizeof(f_header) ||
258 f_header.attr_size != sizeof(f_attr)) 290 f_header.attr_size != sizeof(f_attr))
259 die("incompatible file format"); 291 die("incompatible file format");
260 292
293 if (f_header.size != sizeof(f_header)) {
294 /* Support the previous format */
295 if (f_header.size == offsetof(typeof(f_header), trace_info))
296 f_header.trace_info.size = 0;
297 else
298 die("incompatible file format");
299 }
261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 300 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET); 301 lseek(fd, f_header.attrs.offset, SEEK_SET);
263 302
@@ -290,6 +329,15 @@ struct perf_header *perf_header__read(int fd)
290 do_read(fd, events, f_header.event_types.size); 329 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 330 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 } 331 }
332
333 self->trace_info_offset = f_header.trace_info.offset;
334 self->trace_info_size = f_header.trace_info.size;
335
336 if (self->trace_info_size) {
337 lseek(fd, self->trace_info_offset, SEEK_SET);
338 trace_report(fd);
339 }
340
293 self->event_offset = f_header.event_types.offset; 341 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size; 342 self->event_size = f_header.event_types.size;
295 343
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..30aee5160dc0 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_HEADER_H 1#ifndef __PERF_HEADER_H
2#define _PERF_HEADER_H 2#define __PERF_HEADER_H
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
@@ -21,6 +21,8 @@ struct perf_header {
21 u64 data_size; 21 u64 data_size;
22 u64 event_offset; 22 u64 event_offset;
23 u64 event_size; 23 u64 event_size;
24 u64 trace_info_offset;
25 u64 trace_info_size;
24}; 26};
25 27
26struct perf_header *perf_header__read(int fd); 28struct perf_header *perf_header__read(int fd);
@@ -40,8 +42,8 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
40u64 perf_header__sample_type(struct perf_header *header); 42u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr * 43struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header); 44perf_header__find_attr(u64 id, struct perf_header *header);
43 45void perf_header__set_trace_info(void);
44 46
45struct perf_header *perf_header__new(void); 47struct perf_header *perf_header__new(void);
46 48
47#endif /* _PERF_HEADER_H */ 49#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 7128783637b4..7f5c6dedd714 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -1,5 +1,5 @@
1#ifndef HELP_H 1#ifndef __PERF_HELP_H
2#define HELP_H 2#define __PERF_HELP_H
3 3
4struct cmdnames { 4struct cmdnames {
5 size_t alloc; 5 size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds, 26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds); 27 struct cmdnames *other_cmds);
28 28
29#endif /* HELP_H */ 29#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644
index 000000000000..7393a02fd8d4
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,210 @@
1#include "hist.h"
2
3struct rb_root hist;
4struct rb_root collapse_hists;
5struct rb_root output_hists;
6int callchain;
7
8struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL,
10 .min_percent = 0.5
11};
12
13unsigned long total;
14unsigned long total_mmap;
15unsigned long total_comm;
16unsigned long total_fork;
17unsigned long total_unknown;
18unsigned long total_lost;
19
20/*
21 * histogram, sorted on item, collects counts
22 */
23
24struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
25 struct symbol *sym,
26 struct symbol *sym_parent,
27 u64 ip, u64 count, char level, bool *hit)
28{
29 struct rb_node **p = &hist.rb_node;
30 struct rb_node *parent = NULL;
31 struct hist_entry *he;
32 struct hist_entry entry = {
33 .thread = thread,
34 .map = map,
35 .sym = sym,
36 .ip = ip,
37 .level = level,
38 .count = count,
39 .parent = sym_parent,
40 };
41 int cmp;
42
43 while (*p != NULL) {
44 parent = *p;
45 he = rb_entry(parent, struct hist_entry, rb_node);
46
47 cmp = hist_entry__cmp(&entry, he);
48
49 if (!cmp) {
50 *hit = true;
51 return he;
52 }
53
54 if (cmp < 0)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 he = malloc(sizeof(*he));
61 if (!he)
62 return NULL;
63 *he = entry;
64 rb_link_node(&he->rb_node, parent, p);
65 rb_insert_color(&he->rb_node, &hist);
66 *hit = false;
67 return he;
68}
69
70int64_t
71hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
72{
73 struct sort_entry *se;
74 int64_t cmp = 0;
75
76 list_for_each_entry(se, &hist_entry__sort_list, list) {
77 cmp = se->cmp(left, right);
78 if (cmp)
79 break;
80 }
81
82 return cmp;
83}
84
85int64_t
86hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
87{
88 struct sort_entry *se;
89 int64_t cmp = 0;
90
91 list_for_each_entry(se, &hist_entry__sort_list, list) {
92 int64_t (*f)(struct hist_entry *, struct hist_entry *);
93
94 f = se->collapse ?: se->cmp;
95
96 cmp = f(left, right);
97 if (cmp)
98 break;
99 }
100
101 return cmp;
102}
103
104void hist_entry__free(struct hist_entry *he)
105{
106 free(he);
107}
108
109/*
110 * collapse the histogram
111 */
112
113void collapse__insert_entry(struct hist_entry *he)
114{
115 struct rb_node **p = &collapse_hists.rb_node;
116 struct rb_node *parent = NULL;
117 struct hist_entry *iter;
118 int64_t cmp;
119
120 while (*p != NULL) {
121 parent = *p;
122 iter = rb_entry(parent, struct hist_entry, rb_node);
123
124 cmp = hist_entry__collapse(iter, he);
125
126 if (!cmp) {
127 iter->count += he->count;
128 hist_entry__free(he);
129 return;
130 }
131
132 if (cmp < 0)
133 p = &(*p)->rb_left;
134 else
135 p = &(*p)->rb_right;
136 }
137
138 rb_link_node(&he->rb_node, parent, p);
139 rb_insert_color(&he->rb_node, &collapse_hists);
140}
141
142void collapse__resort(void)
143{
144 struct rb_node *next;
145 struct hist_entry *n;
146
147 if (!sort__need_collapse)
148 return;
149
150 next = rb_first(&hist);
151 while (next) {
152 n = rb_entry(next, struct hist_entry, rb_node);
153 next = rb_next(&n->rb_node);
154
155 rb_erase(&n->rb_node, &hist);
156 collapse__insert_entry(n);
157 }
158}
159
160/*
161 * reverse the map, sort on count.
162 */
163
164void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
165{
166 struct rb_node **p = &output_hists.rb_node;
167 struct rb_node *parent = NULL;
168 struct hist_entry *iter;
169
170 if (callchain)
171 callchain_param.sort(&he->sorted_chain, &he->callchain,
172 min_callchain_hits, &callchain_param);
173
174 while (*p != NULL) {
175 parent = *p;
176 iter = rb_entry(parent, struct hist_entry, rb_node);
177
178 if (he->count > iter->count)
179 p = &(*p)->rb_left;
180 else
181 p = &(*p)->rb_right;
182 }
183
184 rb_link_node(&he->rb_node, parent, p);
185 rb_insert_color(&he->rb_node, &output_hists);
186}
187
188void output__resort(u64 total_samples)
189{
190 struct rb_node *next;
191 struct hist_entry *n;
192 struct rb_root *tree = &hist;
193 u64 min_callchain_hits;
194
195 min_callchain_hits =
196 total_samples * (callchain_param.min_percent / 100);
197
198 if (sort__need_collapse)
199 tree = &collapse_hists;
200
201 next = rb_first(tree);
202
203 while (next) {
204 n = rb_entry(next, struct hist_entry, rb_node);
205 next = rb_next(&n->rb_node);
206
207 rb_erase(&n->rb_node, tree);
208 output__insert_entry(n, min_callchain_hits);
209 }
210}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..ac2149c559b0
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,50 @@
1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern struct rb_root hist;
28extern struct rb_root collapse_hists;
29extern struct rb_root output_hists;
30extern int callchain;
31extern struct callchain_param callchain_param;
32extern unsigned long total;
33extern unsigned long total_mmap;
34extern unsigned long total_comm;
35extern unsigned long total_fork;
36extern unsigned long total_unknown;
37extern unsigned long total_lost;
38
39struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
40 struct symbol *sym, struct symbol *parent,
41 u64 ip, u64 count, char level, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *);
45extern void collapse__insert_entry(struct hist_entry *);
46extern void collapse__resort(void);
47extern void output__insert_entry(struct hist_entry *, u64);
48extern void output__resort(u64);
49
50#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h
index 0173abeef52c..b0fcb6d8a881 100644
--- a/tools/perf/util/levenshtein.h
+++ b/tools/perf/util/levenshtein.h
@@ -1,8 +1,8 @@
1#ifndef LEVENSHTEIN_H 1#ifndef __PERF_LEVENSHTEIN_H
2#define LEVENSHTEIN_H 2#define __PERF_LEVENSHTEIN_H
3 3
4int levenshtein(const char *string1, const char *string2, 4int levenshtein(const char *string1, const char *string2,
5 int swap_penalty, int substition_penalty, 5 int swap_penalty, int substition_penalty,
6 int insertion_penalty, int deletion_penalty); 6 int insertion_penalty, int deletion_penalty);
7 7
8#endif 8#endif /* __PERF_LEVENSHTEIN_H */
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644
index 0d8c85defcd2..000000000000
--- a/tools/perf/util/module.c
+++ /dev/null
@@ -1,545 +0,0 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <libgen.h>
8#include <gelf.h>
9#include <elf.h>
10#include <dirent.h>
11#include <sys/utsname.h>
12
13static unsigned int crc32(const char *p, unsigned int len)
14{
15 int i;
16 unsigned int crc = 0;
17
18 while (len--) {
19 crc ^= *p++;
20 for (i = 0; i < 8; i++)
21 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
22 }
23 return crc;
24}
25
26/* module section methods */
27
28struct sec_dso *sec_dso__new_dso(const char *name)
29{
30 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
31
32 if (self != NULL) {
33 strcpy(self->name, name);
34 self->secs = RB_ROOT;
35 self->find_section = sec_dso__find_section;
36 }
37
38 return self;
39}
40
41static void sec_dso__delete_section(struct section *self)
42{
43 free(((void *)self));
44}
45
46void sec_dso__delete_sections(struct sec_dso *self)
47{
48 struct section *pos;
49 struct rb_node *next = rb_first(&self->secs);
50
51 while (next) {
52 pos = rb_entry(next, struct section, rb_node);
53 next = rb_next(&pos->rb_node);
54 rb_erase(&pos->rb_node, &self->secs);
55 sec_dso__delete_section(pos);
56 }
57}
58
59void sec_dso__delete_self(struct sec_dso *self)
60{
61 sec_dso__delete_sections(self);
62 free(self);
63}
64
65static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
66{
67 struct rb_node **p = &self->secs.rb_node;
68 struct rb_node *parent = NULL;
69 const u64 hash = sec->hash;
70 struct section *s;
71
72 while (*p != NULL) {
73 parent = *p;
74 s = rb_entry(parent, struct section, rb_node);
75 if (hash < s->hash)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80 rb_link_node(&sec->rb_node, parent, p);
81 rb_insert_color(&sec->rb_node, &self->secs);
82}
83
84struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
85{
86 struct rb_node *n;
87 u64 hash;
88 int len;
89
90 if (self == NULL)
91 return NULL;
92
93 len = strlen(name);
94 hash = crc32(name, len);
95
96 n = self->secs.rb_node;
97
98 while (n) {
99 struct section *s = rb_entry(n, struct section, rb_node);
100
101 if (hash < s->hash)
102 n = n->rb_left;
103 else if (hash > s->hash)
104 n = n->rb_right;
105 else {
106 if (!strcmp(name, s->name))
107 return s;
108 else
109 n = rb_next(&s->rb_node);
110 }
111 }
112
113 return NULL;
114}
115
116static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
117{
118 return fprintf(fp, "name:%s vma:%llx path:%s\n",
119 self->name, self->vma, self->path);
120}
121
122size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
123{
124 size_t ret = fprintf(fp, "dso: %s\n", self->name);
125
126 struct rb_node *nd;
127 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
128 struct section *pos = rb_entry(nd, struct section, rb_node);
129 ret += sec_dso__fprintf_section(pos, fp);
130 }
131
132 return ret;
133}
134
135static struct section *section__new(const char *name, const char *path)
136{
137 struct section *self = calloc(1, sizeof(*self));
138
139 if (!self)
140 goto out_failure;
141
142 self->name = calloc(1, strlen(name) + 1);
143 if (!self->name)
144 goto out_failure;
145
146 self->path = calloc(1, strlen(path) + 1);
147 if (!self->path)
148 goto out_failure;
149
150 strcpy(self->name, name);
151 strcpy(self->path, path);
152 self->hash = crc32(self->name, strlen(name));
153
154 return self;
155
156out_failure:
157 if (self) {
158 if (self->name)
159 free(self->name);
160 if (self->path)
161 free(self->path);
162 free(self);
163 }
164
165 return NULL;
166}
167
168/* module methods */
169
170struct mod_dso *mod_dso__new_dso(const char *name)
171{
172 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
173
174 if (self != NULL) {
175 strcpy(self->name, name);
176 self->mods = RB_ROOT;
177 self->find_module = mod_dso__find_module;
178 }
179
180 return self;
181}
182
183static void mod_dso__delete_module(struct module *self)
184{
185 free(((void *)self));
186}
187
188void mod_dso__delete_modules(struct mod_dso *self)
189{
190 struct module *pos;
191 struct rb_node *next = rb_first(&self->mods);
192
193 while (next) {
194 pos = rb_entry(next, struct module, rb_node);
195 next = rb_next(&pos->rb_node);
196 rb_erase(&pos->rb_node, &self->mods);
197 mod_dso__delete_module(pos);
198 }
199}
200
201void mod_dso__delete_self(struct mod_dso *self)
202{
203 mod_dso__delete_modules(self);
204 free(self);
205}
206
207static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
208{
209 struct rb_node **p = &self->mods.rb_node;
210 struct rb_node *parent = NULL;
211 const u64 hash = mod->hash;
212 struct module *m;
213
214 while (*p != NULL) {
215 parent = *p;
216 m = rb_entry(parent, struct module, rb_node);
217 if (hash < m->hash)
218 p = &(*p)->rb_left;
219 else
220 p = &(*p)->rb_right;
221 }
222 rb_link_node(&mod->rb_node, parent, p);
223 rb_insert_color(&mod->rb_node, &self->mods);
224}
225
226struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
227{
228 struct rb_node *n;
229 u64 hash;
230 int len;
231
232 if (self == NULL)
233 return NULL;
234
235 len = strlen(name);
236 hash = crc32(name, len);
237
238 n = self->mods.rb_node;
239
240 while (n) {
241 struct module *m = rb_entry(n, struct module, rb_node);
242
243 if (hash < m->hash)
244 n = n->rb_left;
245 else if (hash > m->hash)
246 n = n->rb_right;
247 else {
248 if (!strcmp(name, m->name))
249 return m;
250 else
251 n = rb_next(&m->rb_node);
252 }
253 }
254
255 return NULL;
256}
257
258static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
259{
260 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
261}
262
263size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
264{
265 struct rb_node *nd;
266 size_t ret;
267
268 ret = fprintf(fp, "dso: %s\n", self->name);
269
270 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
271 struct module *pos = rb_entry(nd, struct module, rb_node);
272
273 ret += mod_dso__fprintf_module(pos, fp);
274 }
275
276 return ret;
277}
278
279static struct module *module__new(const char *name, const char *path)
280{
281 struct module *self = calloc(1, sizeof(*self));
282
283 if (!self)
284 goto out_failure;
285
286 self->name = calloc(1, strlen(name) + 1);
287 if (!self->name)
288 goto out_failure;
289
290 self->path = calloc(1, strlen(path) + 1);
291 if (!self->path)
292 goto out_failure;
293
294 strcpy(self->name, name);
295 strcpy(self->path, path);
296 self->hash = crc32(self->name, strlen(name));
297
298 return self;
299
300out_failure:
301 if (self) {
302 if (self->name)
303 free(self->name);
304 if (self->path)
305 free(self->path);
306 free(self);
307 }
308
309 return NULL;
310}
311
312static int mod_dso__load_sections(struct module *mod)
313{
314 int count = 0, path_len;
315 struct dirent *entry;
316 char *line = NULL;
317 char *dir_path;
318 DIR *dir;
319 size_t n;
320
321 path_len = strlen("/sys/module/");
322 path_len += strlen(mod->name);
323 path_len += strlen("/sections/");
324
325 dir_path = calloc(1, path_len + 1);
326 if (dir_path == NULL)
327 goto out_failure;
328
329 strcat(dir_path, "/sys/module/");
330 strcat(dir_path, mod->name);
331 strcat(dir_path, "/sections/");
332
333 dir = opendir(dir_path);
334 if (dir == NULL)
335 goto out_free;
336
337 while ((entry = readdir(dir))) {
338 struct section *section;
339 char *path, *vma;
340 int line_len;
341 FILE *file;
342
343 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
344 continue;
345
346 path = calloc(1, path_len + strlen(entry->d_name) + 1);
347 if (path == NULL)
348 break;
349 strcat(path, dir_path);
350 strcat(path, entry->d_name);
351
352 file = fopen(path, "r");
353 if (file == NULL) {
354 free(path);
355 break;
356 }
357
358 line_len = getline(&line, &n, file);
359 if (line_len < 0) {
360 free(path);
361 fclose(file);
362 break;
363 }
364
365 if (!line) {
366 free(path);
367 fclose(file);
368 break;
369 }
370
371 line[--line_len] = '\0'; /* \n */
372
373 vma = strstr(line, "0x");
374 if (!vma) {
375 free(path);
376 fclose(file);
377 break;
378 }
379 vma += 2;
380
381 section = section__new(entry->d_name, path);
382 if (!section) {
383 fprintf(stderr, "load_sections: allocation error\n");
384 free(path);
385 fclose(file);
386 break;
387 }
388
389 hex2u64(vma, &section->vma);
390 sec_dso__insert_section(mod->sections, section);
391
392 free(path);
393 fclose(file);
394 count++;
395 }
396
397 closedir(dir);
398 free(line);
399 free(dir_path);
400
401 return count;
402
403out_free:
404 free(dir_path);
405
406out_failure:
407 return count;
408}
409
410static int mod_dso__load_module_paths(struct mod_dso *self)
411{
412 struct utsname uts;
413 int count = 0, len, err = -1;
414 char *line = NULL;
415 FILE *file;
416 char *dpath, *dir;
417 size_t n;
418
419 if (uname(&uts) < 0)
420 return err;
421
422 len = strlen("/lib/modules/");
423 len += strlen(uts.release);
424 len += strlen("/modules.dep");
425
426 dpath = calloc(1, len + 1);
427 if (dpath == NULL)
428 return err;
429
430 strcat(dpath, "/lib/modules/");
431 strcat(dpath, uts.release);
432 strcat(dpath, "/modules.dep");
433
434 file = fopen(dpath, "r");
435 if (file == NULL)
436 goto out_failure;
437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
443 while (!feof(file)) {
444 struct module *module;
445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
448
449 line_len = getline(&line, &n, file);
450 if (line_len < 0)
451 break;
452
453 if (!line)
454 break;
455
456 line[--line_len] = '\0'; /* \n */
457
458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
464 if (!path)
465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
483
484 name = strdup(path);
485 if (!name)
486 break;
487
488 name = strtok(name, "/");
489 tmp = name;
490
491 while (tmp) {
492 tmp = strtok(NULL, "/");
493 if (tmp)
494 name = tmp;
495 }
496
497 name = strsep(&name, ".");
498 if (!name)
499 break;
500
501 /* Quirk: replace '-' with '_' in all modules */
502 for (len = strlen(name); len; len--) {
503 if (*(name+len) == '-')
504 *(name+len) = '_';
505 }
506
507 module = module__new(name, path);
508 if (!module)
509 break;
510 mod_dso__insert_module(self, module);
511
512 module->sections = sec_dso__new_dso("sections");
513 if (!module->sections)
514 break;
515
516 module->active = mod_dso__load_sections(module);
517
518 if (module->active > 0)
519 count++;
520 }
521
522 if (feof(file))
523 err = count;
524 else
525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
526
527out_failure:
528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
536}
537
538int mod_dso__load_modules(struct mod_dso *dso)
539{
540 int err;
541
542 err = mod_dso__load_module_paths(dso);
543
544 return err;
545}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644
index 8a592ef641ca..000000000000
--- a/tools/perf/util/module.h
+++ /dev/null
@@ -1,53 +0,0 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 30c608112845..8626a439033d 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,5 +1,5 @@
1#ifndef _PARSE_EVENTS_H 1#ifndef __PERF_PARSE_EVENTS_H
2#define _PARSE_EVENTS_H 2#define __PERF_PARSE_EVENTS_H
3/* 3/*
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
@@ -31,4 +31,4 @@ extern char debugfs_path[];
31extern int valid_debugfs_mount(const char *debugfs); 31extern int valid_debugfs_mount(const char *debugfs);
32 32
33 33
34#endif /* _PARSE_EVENTS_H */ 34#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 2ee248ff27e5..948805af43c2 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,5 +1,5 @@
1#ifndef PARSE_OPTIONS_H 1#ifndef __PERF_PARSE_OPTIONS_H
2#define PARSE_OPTIONS_H 2#define __PERF_PARSE_OPTIONS_H
3 3
4enum parse_opt_type { 4enum parse_opt_type {
5 /* special types */ 5 /* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
174 174
175extern const char *parse_options_fix_filename(const char *prefix, const char *file); 175extern const char *parse_options_fix_filename(const char *prefix, const char *file);
176 176
177#endif 177#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index a5454a1d1c13..b6a019733919 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -1,5 +1,5 @@
1#ifndef QUOTE_H 1#ifndef __PERF_QUOTE_H
2#define QUOTE_H 2#define __PERF_QUOTE_H
3 3
4#include <stddef.h> 4#include <stddef.h>
5#include <stdio.h> 5#include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src); 65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src); 66extern void tcl_quote_print(FILE *stream, const char *src);
67 67
68#endif 68#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index cc1837deba88..d79028727ce2 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -1,5 +1,5 @@
1#ifndef RUN_COMMAND_H 1#ifndef __PERF_RUN_COMMAND_H
2#define RUN_COMMAND_H 2#define __PERF_RUN_COMMAND_H
3 3
4enum { 4enum {
5 ERR_RUN_COMMAND_FORK = 10000, 5 ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
85int start_async(struct async *async); 85int start_async(struct async *async);
86int finish_async(struct async *async); 86int finish_async(struct async *async);
87 87
88#endif 88#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef SIGCHAIN_H 1#ifndef __PERF_SIGCHAIN_H
2#define SIGCHAIN_H 2#define __PERF_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
8 8
9void sigchain_push_common(sigchain_fun f); 9void sigchain_push_common(sigchain_fun f);
10 10
11#endif /* SIGCHAIN_H */ 11#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..40c9acd41cad
--- /dev/null
+++ b/tools/perf/util/sort.c
@@ -0,0 +1,276 @@
1#include "sort.h"
2
3regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order;
8int sort__need_collapse = 0;
9int sort__has_parent = 0;
10
11unsigned int dsos__col_width;
12unsigned int comms__col_width;
13unsigned int threads__col_width;
14static unsigned int parent_symbol__col_width;
15char * field_sep;
16
17LIST_HEAD(hist_entry__sort_list);
18
19struct sort_entry sort_thread = {
20 .header = "Command: Pid",
21 .cmp = sort__thread_cmp,
22 .print = sort__thread_print,
23 .width = &threads__col_width,
24};
25
26struct sort_entry sort_comm = {
27 .header = "Command",
28 .cmp = sort__comm_cmp,
29 .collapse = sort__comm_collapse,
30 .print = sort__comm_print,
31 .width = &comms__col_width,
32};
33
34struct sort_entry sort_dso = {
35 .header = "Shared Object",
36 .cmp = sort__dso_cmp,
37 .print = sort__dso_print,
38 .width = &dsos__col_width,
39};
40
41struct sort_entry sort_sym = {
42 .header = "Symbol",
43 .cmp = sort__sym_cmp,
44 .print = sort__sym_print,
45};
46
47struct sort_entry sort_parent = {
48 .header = "Parent symbol",
49 .cmp = sort__parent_cmp,
50 .print = sort__parent_print,
51 .width = &parent_symbol__col_width,
52};
53
54struct sort_dimension {
55 const char *name;
56 struct sort_entry *entry;
57 int taken;
58};
59
60static struct sort_dimension sort_dimensions[] = {
61 { .name = "pid", .entry = &sort_thread, },
62 { .name = "comm", .entry = &sort_comm, },
63 { .name = "dso", .entry = &sort_dso, },
64 { .name = "symbol", .entry = &sort_sym, },
65 { .name = "parent", .entry = &sort_parent, },
66};
67
68int64_t cmp_null(void *l, void *r)
69{
70 if (!l && !r)
71 return 0;
72 else if (!l)
73 return -1;
74 else
75 return 1;
76}
77
78/* --sort pid */
79
80int64_t
81sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
82{
83 return right->thread->pid - left->thread->pid;
84}
85
86int repsep_fprintf(FILE *fp, const char *fmt, ...)
87{
88 int n;
89 va_list ap;
90
91 va_start(ap, fmt);
92 if (!field_sep)
93 n = vfprintf(fp, fmt, ap);
94 else {
95 char *bf = NULL;
96 n = vasprintf(&bf, fmt, ap);
97 if (n > 0) {
98 char *sep = bf;
99
100 while (1) {
101 sep = strchr(sep, *field_sep);
102 if (sep == NULL)
103 break;
104 *sep = '.';
105 }
106 }
107 fputs(bf, fp);
108 free(bf);
109 }
110 va_end(ap);
111 return n;
112}
113
114size_t
115sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
116{
117 return repsep_fprintf(fp, "%*s:%5d", width - 6,
118 self->thread->comm ?: "", self->thread->pid);
119}
120
121size_t
122sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
123{
124 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
125}
126
127/* --sort dso */
128
129int64_t
130sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
131{
132 struct dso *dso_l = left->map ? left->map->dso : NULL;
133 struct dso *dso_r = right->map ? right->map->dso : NULL;
134 const char *dso_name_l, *dso_name_r;
135
136 if (!dso_l || !dso_r)
137 return cmp_null(dso_l, dso_r);
138
139 if (verbose) {
140 dso_name_l = dso_l->long_name;
141 dso_name_r = dso_r->long_name;
142 } else {
143 dso_name_l = dso_l->short_name;
144 dso_name_r = dso_r->short_name;
145 }
146
147 return strcmp(dso_name_l, dso_name_r);
148}
149
150size_t
151sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
152{
153 if (self->map && self->map->dso) {
154 const char *dso_name = !verbose ? self->map->dso->short_name :
155 self->map->dso->long_name;
156 return repsep_fprintf(fp, "%-*s", width, dso_name);
157 }
158
159 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
160}
161
162/* --sort symbol */
163
164int64_t
165sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
166{
167 u64 ip_l, ip_r;
168
169 if (left->sym == right->sym)
170 return 0;
171
172 ip_l = left->sym ? left->sym->start : left->ip;
173 ip_r = right->sym ? right->sym->start : right->ip;
174
175 return (int64_t)(ip_r - ip_l);
176}
177
178
179size_t
180sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
181{
182 size_t ret = 0;
183
184 if (verbose) {
185 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
186 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
187 }
188
189 ret += repsep_fprintf(fp, "[%c] ", self->level);
190 if (self->sym)
191 ret += repsep_fprintf(fp, "%s", self->sym->name);
192 else
193 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
194
195 return ret;
196}
197
198/* --sort comm */
199
200int64_t
201sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
202{
203 return right->thread->pid - left->thread->pid;
204}
205
206int64_t
207sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
208{
209 char *comm_l = left->thread->comm;
210 char *comm_r = right->thread->comm;
211
212 if (!comm_l || !comm_r)
213 return cmp_null(comm_l, comm_r);
214
215 return strcmp(comm_l, comm_r);
216}
217
218/* --sort parent */
219
220int64_t
221sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
222{
223 struct symbol *sym_l = left->parent;
224 struct symbol *sym_r = right->parent;
225
226 if (!sym_l || !sym_r)
227 return cmp_null(sym_l, sym_r);
228
229 return strcmp(sym_l->name, sym_r->name);
230}
231
232size_t
233sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
234{
235 return repsep_fprintf(fp, "%-*s", width,
236 self->parent ? self->parent->name : "[other]");
237}
238
239int sort_dimension__add(const char *tok)
240{
241 unsigned int i;
242
243 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
244 struct sort_dimension *sd = &sort_dimensions[i];
245
246 if (sd->taken)
247 continue;
248
249 if (strncasecmp(tok, sd->name, strlen(tok)))
250 continue;
251
252 if (sd->entry->collapse)
253 sort__need_collapse = 1;
254
255 if (sd->entry == &sort_parent) {
256 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
257 if (ret) {
258 char err[BUFSIZ];
259
260 regerror(ret, &parent_regex, err, sizeof(err));
261 fprintf(stderr, "Invalid regex: %s\n%s",
262 parent_pattern, err);
263 exit(-1);
264 }
265 sort__has_parent = 1;
266 }
267
268 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
269 sd->taken = 1;
270
271 return 0;
272 }
273
274 return -ESRCH;
275}
276
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644
index 000000000000..13806d782af6
--- /dev/null
+++ b/tools/perf/util/sort.h
@@ -0,0 +1,90 @@
1#ifndef __PERF_SORT_H
2#define __PERF_SORT_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern regex_t parent_regex;
28extern char *sort_order;
29extern char default_parent_pattern[];
30extern char *parent_pattern;
31extern char default_sort_order[];
32extern int sort__need_collapse;
33extern int sort__has_parent;
34extern char *field_sep;
35extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42
43struct hist_entry {
44 struct rb_node rb_node;
45 u64 count;
46 struct thread *thread;
47 struct map *map;
48 struct symbol *sym;
49 u64 ip;
50 char level;
51 struct symbol *parent;
52 struct callchain_node callchain;
53 struct rb_root sorted_chain;
54};
55
56/*
57 * configurable sorting bits
58 */
59
60struct sort_entry {
61 struct list_head list;
62
63 const char *header;
64
65 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
66 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
67 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
68 unsigned int *width;
69 bool elide;
70};
71
72extern struct sort_entry sort_thread;
73extern struct list_head hist_entry__sort_list;
74
75extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
76extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
77extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
78extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
79extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
80extern int64_t cmp_null(void *, void *);
81extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
82extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
83extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
84extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
85extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
86extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
87extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
88extern int sort_dimension__add(const char *);
89
90#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index d2aa86c014c1..a3d121d6c83e 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -1,5 +1,5 @@
1#ifndef STRBUF_H 1#ifndef __PERF_STRBUF_H
2#define STRBUF_H 2#define __PERF_STRBUF_H
3 3
4/* 4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary 5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
134extern int strbuf_branchname(struct strbuf *sb, const char *name); 134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); 135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 136
137#endif /* STRBUF_H */ 137#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c93eca9a7be3..04743d3e9039 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,3 +1,4 @@
1#include <string.h>
1#include "string.h" 2#include "string.h"
2 3
3static int hex(char ch) 4static int hex(char ch)
@@ -32,3 +33,13 @@ int hex2u64(const char *ptr, u64 *long_val)
32 33
33 return p - ptr; 34 return p - ptr;
34} 35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..2c84bf65ba0f 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,12 @@
1#ifndef _PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define _PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include "types.h" 4#include "types.h"
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7char *strxfrchar(char *s, char from, char to);
7 8
8#define _STR(x) #x 9#define _STR(x) #x
9#define STR(x) _STR(x) 10#define STR(x) _STR(x)
10 11
11#endif 12#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 921818e44a54..cb4659306d7b 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,5 +1,5 @@
1#ifndef STRLIST_H_ 1#ifndef __PERF_STRLIST_H
2#define STRLIST_H_ 2#define __PERF_STRLIST_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
@@ -36,4 +36,4 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
36} 36}
37 37
38int strlist__parse_list(struct strlist *self, const char *s); 38int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */ 39#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index cd93195aedb3..e0781989cc31 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,5 +1,5 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_ 1#ifndef __PERF_SVGHELPER_H
2#define _INCLUDE_GUARD_SVG_HELPER_ 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -25,4 +25,4 @@ extern void svg_close(void);
25 25
26extern int svg_page_width; 26extern int svg_page_width;
27 27
28#endif 28#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 47ea0609a760..faa84f5d4f54 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2,12 +2,14 @@
2#include "../perf.h" 2#include "../perf.h"
3#include "string.h" 3#include "string.h"
4#include "symbol.h" 4#include "symbol.h"
5#include "thread.h"
5 6
6#include "debug.h" 7#include "debug.h"
7 8
8#include <libelf.h> 9#include <libelf.h>
9#include <gelf.h> 10#include <gelf.h>
10#include <elf.h> 11#include <elf.h>
12#include <sys/utsname.h>
11 13
12const char *sym_hist_filter; 14const char *sym_hist_filter;
13 15
@@ -18,12 +20,65 @@ enum dso_origin {
18 DSO__ORIG_UBUNTU, 20 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID, 21 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO, 22 DSO__ORIG_DSO,
23 DSO__ORIG_KMODULE,
21 DSO__ORIG_NOT_FOUND, 24 DSO__ORIG_NOT_FOUND,
22}; 25};
23 26
24static struct symbol *symbol__new(u64 start, u64 len, 27static void dsos__add(struct dso *dso);
25 const char *name, unsigned int priv_size, 28static struct dso *dsos__find(const char *name);
26 u64 obj_start, int v) 29static struct map *map__new2(u64 start, struct dso *dso);
30static void kernel_maps__insert(struct map *map);
31
32static struct rb_root kernel_maps;
33
34static void dso__fixup_sym_end(struct dso *self)
35{
36 struct rb_node *nd, *prevnd = rb_first(&self->syms);
37 struct symbol *curr, *prev;
38
39 if (prevnd == NULL)
40 return;
41
42 curr = rb_entry(prevnd, struct symbol, rb_node);
43
44 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
45 prev = curr;
46 curr = rb_entry(nd, struct symbol, rb_node);
47
48 if (prev->end == prev->start)
49 prev->end = curr->start - 1;
50 }
51
52 /* Last entry */
53 if (curr->end == curr->start)
54 curr->end = roundup(curr->start, 4096);
55}
56
57static void kernel_maps__fixup_end(void)
58{
59 struct map *prev, *curr;
60 struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
61
62 if (prevnd == NULL)
63 return;
64
65 curr = rb_entry(prevnd, struct map, rb_node);
66
67 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
68 prev = curr;
69 curr = rb_entry(nd, struct map, rb_node);
70 prev->end = curr->start - 1;
71 }
72
73 nd = rb_last(&curr->dso->syms);
74 if (nd) {
75 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
76 curr->end = sym->end;
77 }
78}
79
80static struct symbol *symbol__new(u64 start, u64 len, const char *name,
81 unsigned int priv_size, int v)
27{ 82{
28 size_t namelen = strlen(name) + 1; 83 size_t namelen = strlen(name) + 1;
29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 84 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -31,11 +86,10 @@ static struct symbol *symbol__new(u64 start, u64 len,
31 if (!self) 86 if (!self)
32 return NULL; 87 return NULL;
33 88
34 if (v >= 2) 89 if (v > 2)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 90 printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n",
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 91 start, (unsigned long)len, name, self->hist);
37 92
38 self->obj_start= obj_start;
39 self->hist = NULL; 93 self->hist = NULL;
40 self->hist_sum = 0; 94 self->hist_sum = 0;
41 95
@@ -60,12 +114,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
60 114
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 115static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 116{
63 if (!self->module) 117 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 118 self->start, self->end, self->name);
66 else
67 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
68 self->start, self->end, self->name, self->module->name);
69} 119}
70 120
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 121struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -74,6 +124,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
74 124
75 if (self != NULL) { 125 if (self != NULL) {
76 strcpy(self->name, name); 126 strcpy(self->name, name);
127 self->long_name = self->name;
128 self->short_name = self->name;
77 self->syms = RB_ROOT; 129 self->syms = RB_ROOT;
78 self->sym_priv_size = sym_priv_size; 130 self->sym_priv_size = sym_priv_size;
79 self->find_symbol = dso__find_symbol; 131 self->find_symbol = dso__find_symbol;
@@ -100,6 +152,8 @@ static void dso__delete_symbols(struct dso *self)
100void dso__delete(struct dso *self) 152void dso__delete(struct dso *self)
101{ 153{
102 dso__delete_symbols(self); 154 dso__delete_symbols(self);
155 if (self->long_name != self->name)
156 free(self->long_name);
103 free(self); 157 free(self);
104} 158}
105 159
@@ -147,7 +201,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
147 201
148size_t dso__fprintf(struct dso *self, FILE *fp) 202size_t dso__fprintf(struct dso *self, FILE *fp)
149{ 203{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 204 size_t ret = fprintf(fp, "dso: %s\n", self->short_name);
151 205
152 struct rb_node *nd; 206 struct rb_node *nd;
153 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 207 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
@@ -158,13 +212,16 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 212 return ret;
159} 213}
160 214
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 215/*
216 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
217 * so that we can in the next step set the symbol ->end address and then
218 * call kernel_maps__split_kallsyms.
219 */
220static int kernel_maps__load_all_kallsyms(int v)
162{ 221{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 222 char *line = NULL;
165 size_t n; 223 size_t n;
166 FILE *file = fopen("/proc/kallsyms", "r"); 224 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
168 225
169 if (file == NULL) 226 if (file == NULL)
170 goto out_failure; 227 goto out_failure;
@@ -174,6 +231,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
174 struct symbol *sym; 231 struct symbol *sym;
175 int line_len, len; 232 int line_len, len;
176 char symbol_type; 233 char symbol_type;
234 char *symbol_name;
177 235
178 line_len = getline(&line, &n, file); 236 line_len = getline(&line, &n, file);
179 if (line_len < 0) 237 if (line_len < 0)
@@ -196,44 +254,24 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
196 */ 254 */
197 if (symbol_type != 'T' && symbol_type != 'W') 255 if (symbol_type != 'T' && symbol_type != 'W')
198 continue; 256 continue;
257
258 symbol_name = line + len + 2;
199 /* 259 /*
200 * Well fix up the end later, when we have all sorted. 260 * Will fix up the end later, when we have all symbols sorted.
201 */ 261 */
202 sym = symbol__new(start, 0xdead, line + len + 2, 262 sym = symbol__new(start, 0, symbol_name,
203 self->sym_priv_size, 0, v); 263 kernel_map->dso->sym_priv_size, v);
204 264
205 if (sym == NULL) 265 if (sym == NULL)
206 goto out_delete_line; 266 goto out_delete_line;
207 267
208 if (filter && filter(self, sym)) 268 dso__insert_symbol(kernel_map->dso, sym);
209 symbol__delete(sym, self->sym_priv_size);
210 else {
211 dso__insert_symbol(self, sym);
212 count++;
213 }
214 }
215
216 /*
217 * Now that we have all sorted out, just set the ->end of all
218 * symbols
219 */
220 prevnd = rb_first(&self->syms);
221
222 if (prevnd == NULL)
223 goto out_delete_line;
224
225 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
226 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
227 *curr = rb_entry(nd, struct symbol, rb_node);
228
229 prev->end = curr->start - 1;
230 prevnd = nd;
231 } 269 }
232 270
233 free(line); 271 free(line);
234 fclose(file); 272 fclose(file);
235 273
236 return count; 274 return 0;
237 275
238out_delete_line: 276out_delete_line:
239 free(line); 277 free(line);
@@ -241,14 +279,125 @@ out_failure:
241 return -1; 279 return -1;
242} 280}
243 281
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 282/*
283 * Split the symbols into maps, making sure there are no overlaps, i.e. the
284 * kernel range is broken in several maps, named [kernel].N, as we don't have
285 * the original ELF section names vmlinux have.
286 */
287static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
288{
289 struct map *map = kernel_map;
290 struct symbol *pos;
291 int count = 0;
292 struct rb_node *next = rb_first(&kernel_map->dso->syms);
293 int kernel_range = 0;
294
295 while (next) {
296 char *module;
297
298 pos = rb_entry(next, struct symbol, rb_node);
299 next = rb_next(&pos->rb_node);
300
301 module = strchr(pos->name, '\t');
302 if (module) {
303 if (!use_modules)
304 goto delete_symbol;
305
306 *module++ = '\0';
307
308 if (strcmp(map->dso->name, module)) {
309 map = kernel_maps__find_by_dso_name(module);
310 if (!map) {
311 fputs("/proc/{kallsyms,modules} "
312 "inconsistency!\n", stderr);
313 return -1;
314 }
315 }
316 /*
317 * So that we look just like we get from .ko files,
318 * i.e. not prelinked, relative to map->start.
319 */
320 pos->start = map->map_ip(map, pos->start);
321 pos->end = map->map_ip(map, pos->end);
322 } else if (map != kernel_map) {
323 char dso_name[PATH_MAX];
324 struct dso *dso;
325
326 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
327 kernel_range++);
328
329 dso = dso__new(dso_name,
330 kernel_map->dso->sym_priv_size);
331 if (dso == NULL)
332 return -1;
333
334 map = map__new2(pos->start, dso);
335 if (map == NULL) {
336 dso__delete(dso);
337 return -1;
338 }
339
340 map->map_ip = vdso__map_ip;
341 kernel_maps__insert(map);
342 ++kernel_range;
343 }
344
345 if (filter && filter(map, pos)) {
346delete_symbol:
347 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
348 symbol__delete(pos, kernel_map->dso->sym_priv_size);
349 } else {
350 if (map != kernel_map) {
351 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
352 dso__insert_symbol(map->dso, pos);
353 }
354 count++;
355 }
356 }
357
358 return count;
359}
360
361
362static int kernel_maps__load_kallsyms(symbol_filter_t filter,
363 int use_modules, int v)
364{
365 if (kernel_maps__load_all_kallsyms(v))
366 return -1;
367
368 dso__fixup_sym_end(kernel_map->dso);
369
370 return kernel_maps__split_kallsyms(filter, use_modules);
371}
372
373static size_t kernel_maps__fprintf(FILE *fp, int v)
374{
375 size_t printed = fprintf(stderr, "Kernel maps:\n");
376 struct rb_node *nd;
377
378 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
379 struct map *pos = rb_entry(nd, struct map, rb_node);
380
381 printed += fprintf(fp, "Map:");
382 printed += map__fprintf(pos, fp);
383 if (v > 1) {
384 printed += dso__fprintf(pos->dso, fp);
385 printed += fprintf(fp, "--\n");
386 }
387 }
388
389 return printed + fprintf(stderr, "END kernel maps\n");
390}
391
392static int dso__load_perf_map(struct dso *self, struct map *map,
393 symbol_filter_t filter, int v)
245{ 394{
246 char *line = NULL; 395 char *line = NULL;
247 size_t n; 396 size_t n;
248 FILE *file; 397 FILE *file;
249 int nr_syms = 0; 398 int nr_syms = 0;
250 399
251 file = fopen(self->name, "r"); 400 file = fopen(self->long_name, "r");
252 if (file == NULL) 401 if (file == NULL)
253 goto out_failure; 402 goto out_failure;
254 403
@@ -279,12 +428,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
279 continue; 428 continue;
280 429
281 sym = symbol__new(start, size, line + len, 430 sym = symbol__new(start, size, line + len,
282 self->sym_priv_size, start, v); 431 self->sym_priv_size, v);
283 432
284 if (sym == NULL) 433 if (sym == NULL)
285 goto out_delete_line; 434 goto out_delete_line;
286 435
287 if (filter && filter(self, sym)) 436 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 437 symbol__delete(sym, self->sym_priv_size);
289 else { 438 else {
290 dso__insert_symbol(self, sym); 439 dso__insert_symbol(self, sym);
@@ -409,7 +558,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 558 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 559 int nr = 0, symidx, fd, err = 0;
411 560
412 fd = open(self->name, O_RDONLY); 561 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 562 if (fd < 0)
414 goto out; 563 goto out;
415 564
@@ -477,7 +626,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 626 "%s@plt", elf_sym__name(&sym, symstrs));
478 627
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 628 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 629 sympltname, self->sym_priv_size, v);
481 if (!f) 630 if (!f)
482 goto out_elf_end; 631 goto out_elf_end;
483 632
@@ -495,7 +644,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 644 "%s@plt", elf_sym__name(&sym, symstrs));
496 645
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 646 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 647 sympltname, self->sym_priv_size, v);
499 if (!f) 648 if (!f)
500 goto out_elf_end; 649 goto out_elf_end;
501 650
@@ -514,13 +663,17 @@ out_close:
514 return nr; 663 return nr;
515out: 664out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 665 fprintf(stderr, "%s: problems reading %s PLT info.\n",
517 __func__, self->name); 666 __func__, self->long_name);
518 return 0; 667 return 0;
519} 668}
520 669
521static int dso__load_sym(struct dso *self, int fd, const char *name, 670static int dso__load_sym(struct dso *self, struct map *map, const char *name,
522 symbol_filter_t filter, int v, struct module *mod) 671 int fd, symbol_filter_t filter, int kernel,
672 int kmodule, int v)
523{ 673{
674 struct map *curr_map = map;
675 struct dso *curr_dso = self;
676 size_t dso_name_len = strlen(self->short_name);
524 Elf_Data *symstrs, *secstrs; 677 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 678 uint32_t nr_syms;
526 int err = -1; 679 int err = -1;
@@ -531,7 +684,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 684 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 685 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 686 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 687 int nr = 0;
535 688
536 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 689 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 690 if (elf == NULL) {
@@ -587,9 +740,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
587 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 740 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 741 struct symbol *f;
589 const char *elf_name; 742 const char *elf_name;
590 char *demangled; 743 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 744 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 745 const char *section_name;
595 746
@@ -605,52 +756,85 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 756 if (is_label && !elf_sec__is_text(&shdr, secstrs))
606 continue; 757 continue;
607 758
759 elf_name = elf_sym__name(&sym, symstrs);
608 section_name = elf_sec__name(&shdr, secstrs); 760 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 761
611 if (self->adjust_symbols) { 762 if (kernel || kmodule) {
612 if (v >= 2) 763 char dso_name[PATH_MAX];
764
765 if (strcmp(section_name,
766 curr_dso->short_name + dso_name_len) == 0)
767 goto new_symbol;
768
769 if (strcmp(section_name, ".text") == 0) {
770 curr_map = map;
771 curr_dso = self;
772 goto new_symbol;
773 }
774
775 snprintf(dso_name, sizeof(dso_name),
776 "%s%s", self->short_name, section_name);
777
778 curr_map = kernel_maps__find_by_dso_name(dso_name);
779 if (curr_map == NULL) {
780 u64 start = sym.st_value;
781
782 if (kmodule)
783 start += map->start + shdr.sh_offset;
784
785 curr_dso = dso__new(dso_name, self->sym_priv_size);
786 if (curr_dso == NULL)
787 goto out_elf_end;
788 curr_map = map__new2(start, curr_dso);
789 if (curr_map == NULL) {
790 dso__delete(curr_dso);
791 goto out_elf_end;
792 }
793 curr_map->map_ip = vdso__map_ip;
794 curr_dso->origin = DSO__ORIG_KERNEL;
795 kernel_maps__insert(curr_map);
796 dsos__add(curr_dso);
797 } else
798 curr_dso = curr_map->dso;
799
800 goto new_symbol;
801 }
802
803 if (curr_dso->adjust_symbols) {
804 if (v > 2)
613 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 805 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
614 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 806 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
615 807
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 808 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
617 } 809 }
618
619 if (mod) {
620 section = mod->sections->find_section(mod->sections, section_name);
621 if (section)
622 sym.st_value += section->vma;
623 else {
624 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
625 mod->name, section_name);
626 goto out_elf_end;
627 }
628 }
629 /* 810 /*
630 * We need to figure out if the object was created from C++ sources 811 * We need to figure out if the object was created from C++ sources
631 * DWARF DW_compile_unit has this, but we don't always have access 812 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 813 * to it...
633 */ 814 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 815 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 816 if (demangled != NULL)
637 elf_name = demangled; 817 elf_name = demangled;
638 818new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 819 f = symbol__new(sym.st_value, sym.st_size, elf_name,
640 self->sym_priv_size, obj_start, v); 820 curr_dso->sym_priv_size, v);
641 free(demangled); 821 free(demangled);
642 if (!f) 822 if (!f)
643 goto out_elf_end; 823 goto out_elf_end;
644 824
645 if (filter && filter(self, f)) 825 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 826 symbol__delete(f, curr_dso->sym_priv_size);
647 else { 827 else {
648 f->module = mod; 828 dso__insert_symbol(curr_dso, f);
649 dso__insert_symbol(self, f);
650 nr++; 829 nr++;
651 } 830 }
652 } 831 }
653 832
833 /*
834 * For misannotated, zeroed, ASM function sizes.
835 */
836 if (nr > 0)
837 dso__fixup_sym_end(self);
654 err = nr; 838 err = nr;
655out_elf_end: 839out_elf_end:
656 elf_end(elf); 840 elf_end(elf);
@@ -670,7 +854,7 @@ static char *dso__read_build_id(struct dso *self, int v)
670 char *build_id = NULL, *bid; 854 char *build_id = NULL, *bid;
671 unsigned char *raw; 855 unsigned char *raw;
672 Elf *elf; 856 Elf *elf;
673 int fd = open(self->name, O_RDONLY); 857 int fd = open(self->long_name, O_RDONLY);
674 858
675 if (fd < 0) 859 if (fd < 0)
676 goto out; 860 goto out;
@@ -679,7 +863,7 @@ static char *dso__read_build_id(struct dso *self, int v)
679 if (elf == NULL) { 863 if (elf == NULL) {
680 if (v) 864 if (v)
681 fprintf(stderr, "%s: cannot read %s ELF file.\n", 865 fprintf(stderr, "%s: cannot read %s ELF file.\n",
682 __func__, self->name); 866 __func__, self->long_name);
683 goto out_close; 867 goto out_close;
684 } 868 }
685 869
@@ -708,7 +892,7 @@ static char *dso__read_build_id(struct dso *self, int v)
708 bid += 2; 892 bid += 2;
709 } 893 }
710 if (v >= 2) 894 if (v >= 2)
711 printf("%s(%s): %s\n", __func__, self->name, build_id); 895 printf("%s(%s): %s\n", __func__, self->long_name, build_id);
712out_elf_end: 896out_elf_end:
713 elf_end(elf); 897 elf_end(elf);
714out_close: 898out_close:
@@ -726,6 +910,7 @@ char dso__symtab_origin(const struct dso *self)
726 [DSO__ORIG_UBUNTU] = 'u', 910 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 911 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 912 [DSO__ORIG_DSO] = 'd',
913 [DSO__ORIG_KMODULE] = 'K',
729 }; 914 };
730 915
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 916 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,7 +918,7 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 918 return origin[self->origin];
734} 919}
735 920
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 921int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v)
737{ 922{
738 int size = PATH_MAX; 923 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 924 char *name = malloc(size), *build_id = NULL;
@@ -746,7 +931,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v)
746 self->adjust_symbols = 0; 931 self->adjust_symbols = 0;
747 932
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 933 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 934 ret = dso__load_perf_map(self, map, filter, v);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 935 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 936 DSO__ORIG_NOT_FOUND;
752 return ret; 937 return ret;
@@ -759,10 +944,12 @@ more:
759 self->origin++; 944 self->origin++;
760 switch (self->origin) { 945 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 946 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 947 snprintf(name, size, "/usr/lib/debug%s.debug",
948 self->long_name);
763 break; 949 break;
764 case DSO__ORIG_UBUNTU: 950 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 951 snprintf(name, size, "/usr/lib/debug%s",
952 self->long_name);
766 break; 953 break;
767 case DSO__ORIG_BUILDID: 954 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 955 build_id = dso__read_build_id(self, v);
@@ -776,7 +963,7 @@ more:
776 self->origin++; 963 self->origin++;
777 /* Fall thru */ 964 /* Fall thru */
778 case DSO__ORIG_DSO: 965 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 966 snprintf(name, size, "%s", self->long_name);
780 break; 967 break;
781 968
782 default: 969 default:
@@ -786,7 +973,7 @@ more:
786 fd = open(name, O_RDONLY); 973 fd = open(name, O_RDONLY);
787 } while (fd < 0); 974 } while (fd < 0);
788 975
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 976 ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v);
790 close(fd); 977 close(fd);
791 978
792 /* 979 /*
@@ -807,89 +994,243 @@ out:
807 return ret; 994 return ret;
808} 995}
809 996
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 997struct map *kernel_map;
811 symbol_filter_t filter, int v) 998
999static void kernel_maps__insert(struct map *map)
1000{
1001 maps__insert(&kernel_maps, map);
1002}
1003
1004struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
812{ 1005{
813 struct module *mod = mod_dso__find_module(mods, name); 1006 struct map *map = maps__find(&kernel_maps, ip);
814 int err = 0, fd;
815 1007
816 if (mod == NULL || !mod->active) 1008 if (mapp)
817 return err; 1009 *mapp = map;
818 1010
819 fd = open(mod->path, O_RDONLY); 1011 if (map) {
1012 ip = map->map_ip(map, ip);
1013 return map->dso->find_symbol(map->dso, ip);
1014 }
820 1015
821 if (fd < 0) 1016 return NULL;
1017}
1018
1019struct map *kernel_maps__find_by_dso_name(const char *name)
1020{
1021 struct rb_node *nd;
1022
1023 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
1024 struct map *map = rb_entry(nd, struct map, rb_node);
1025
1026 if (map->dso && strcmp(map->dso->name, name) == 0)
1027 return map;
1028 }
1029
1030 return NULL;
1031}
1032
1033static int dso__load_module_sym(struct dso *self, struct map *map,
1034 symbol_filter_t filter, int v)
1035{
1036 int err = 0, fd = open(self->long_name, O_RDONLY);
1037
1038 if (fd < 0) {
1039 if (v)
1040 fprintf(stderr, "%s: cannot open %s\n",
1041 __func__, self->long_name);
822 return err; 1042 return err;
1043 }
823 1044
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1045 err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v);
825 close(fd); 1046 close(fd);
826 1047
827 return err; 1048 return err;
828} 1049}
829 1050
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1051static int dsos__load_modules_sym_dir(char *dirname,
1052 symbol_filter_t filter, int v)
831{ 1053{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1054 struct dirent *dent;
833 struct module *pos; 1055 int nr_symbols = 0, err;
834 struct rb_node *next; 1056 DIR *dir = opendir(dirname);
835 int err, count = 0;
836 1057
837 err = mod_dso__load_modules(mods); 1058 if (!dir) {
1059 if (v)
1060 fprintf(stderr, "%s: cannot open %s dir\n", __func__,
1061 dirname);
1062 return -1;
1063 }
838 1064
839 if (err <= 0) 1065 while ((dent = readdir(dir)) != NULL) {
840 return err; 1066 char path[PATH_MAX];
1067
1068 if (dent->d_type == DT_DIR) {
1069 if (!strcmp(dent->d_name, ".") ||
1070 !strcmp(dent->d_name, ".."))
1071 continue;
1072
1073 snprintf(path, sizeof(path), "%s/%s",
1074 dirname, dent->d_name);
1075 err = dsos__load_modules_sym_dir(path, filter, v);
1076 if (err < 0)
1077 goto failure;
1078 } else {
1079 char *dot = strrchr(dent->d_name, '.'),
1080 dso_name[PATH_MAX];
1081 struct map *map;
1082 struct rb_node *last;
1083
1084 if (dot == NULL || strcmp(dot, ".ko"))
1085 continue;
1086 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1087 (int)(dot - dent->d_name), dent->d_name);
1088
1089 strxfrchar(dso_name, '-', '_');
1090 map = kernel_maps__find_by_dso_name(dso_name);
1091 if (map == NULL)
1092 continue;
1093
1094 snprintf(path, sizeof(path), "%s/%s",
1095 dirname, dent->d_name);
1096
1097 map->dso->long_name = strdup(path);
1098 if (map->dso->long_name == NULL)
1099 goto failure;
1100
1101 err = dso__load_module_sym(map->dso, map, filter, v);
1102 if (err < 0)
1103 goto failure;
1104 last = rb_last(&map->dso->syms);
1105 if (last) {
1106 struct symbol *sym;
1107 /*
1108 * We do this here as well, even having the
1109 * symbol size found in the symtab because
1110 * misannotated ASM symbols may have the size
1111 * set to zero.
1112 */
1113 dso__fixup_sym_end(map->dso);
1114
1115 sym = rb_entry(last, struct symbol, rb_node);
1116 map->end = map->start + sym->end;
1117 }
1118 }
1119 nr_symbols += err;
1120 }
841 1121
842 /* 1122 return nr_symbols;
843 * Iterate over modules, and load active symbols. 1123failure:
844 */ 1124 closedir(dir);
845 next = rb_first(&mods->mods); 1125 return -1;
846 while (next) { 1126}
847 pos = rb_entry(next, struct module, rb_node);
848 err = dso__load_module(self, mods, pos->name, filter, v);
849 1127
850 if (err < 0) 1128static int dsos__load_modules_sym(symbol_filter_t filter, int v)
851 break; 1129{
1130 struct utsname uts;
1131 char modules_path[PATH_MAX];
852 1132
853 next = rb_next(&pos->rb_node); 1133 if (uname(&uts) < 0)
854 count += err; 1134 return -1;
855 }
856 1135
857 if (err < 0) { 1136 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
858 mod_dso__delete_modules(mods); 1137 uts.release);
859 mod_dso__delete_self(mods);
860 return err;
861 }
862 1138
863 return count; 1139 return dsos__load_modules_sym_dir(modules_path, filter, v);
864} 1140}
865 1141
866static inline void dso__fill_symbol_holes(struct dso *self) 1142/*
1143 * Constructor variant for modules (where we know from /proc/modules where
1144 * they are loaded) and for vmlinux, where only after we load all the
1145 * symbols we'll know where it starts and ends.
1146 */
1147static struct map *map__new2(u64 start, struct dso *dso)
867{ 1148{
868 struct symbol *prev = NULL; 1149 struct map *self = malloc(sizeof(*self));
869 struct rb_node *nd;
870 1150
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1151 if (self != NULL) {
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1152 self->start = start;
1153 /*
1154 * Will be filled after we load all the symbols
1155 */
1156 self->end = 0;
873 1157
874 if (prev) { 1158 self->pgoff = 0;
875 u64 hole = 0; 1159 self->dso = dso;
876 int alias = pos->start == prev->start; 1160 self->map_ip = map__map_ip;
1161 RB_CLEAR_NODE(&self->rb_node);
1162 }
1163 return self;
1164}
877 1165
878 if (!alias) 1166static int dsos__load_modules(unsigned int sym_priv_size)
879 hole = prev->start - pos->end - 1; 1167{
1168 char *line = NULL;
1169 size_t n;
1170 FILE *file = fopen("/proc/modules", "r");
1171 struct map *map;
880 1172
881 if (hole || alias) { 1173 if (file == NULL)
882 if (alias) 1174 return -1;
883 pos->end = prev->end; 1175
884 else if (hole) 1176 while (!feof(file)) {
885 pos->end = prev->start - 1; 1177 char name[PATH_MAX];
886 } 1178 u64 start;
1179 struct dso *dso;
1180 char *sep;
1181 int line_len;
1182
1183 line_len = getline(&line, &n, file);
1184 if (line_len < 0)
1185 break;
1186
1187 if (!line)
1188 goto out_failure;
1189
1190 line[--line_len] = '\0'; /* \n */
1191
1192 sep = strrchr(line, 'x');
1193 if (sep == NULL)
1194 continue;
1195
1196 hex2u64(sep + 1, &start);
1197
1198 sep = strchr(line, ' ');
1199 if (sep == NULL)
1200 continue;
1201
1202 *sep = '\0';
1203
1204 snprintf(name, sizeof(name), "[%s]", line);
1205 dso = dso__new(name, sym_priv_size);
1206
1207 if (dso == NULL)
1208 goto out_delete_line;
1209
1210 map = map__new2(start, dso);
1211 if (map == NULL) {
1212 dso__delete(dso);
1213 goto out_delete_line;
887 } 1214 }
888 prev = pos; 1215
1216 dso->origin = DSO__ORIG_KMODULE;
1217 kernel_maps__insert(map);
1218 dsos__add(dso);
889 } 1219 }
1220
1221 free(line);
1222 fclose(file);
1223
1224 return 0;
1225
1226out_delete_line:
1227 free(line);
1228out_failure:
1229 return -1;
890} 1230}
891 1231
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1232static int dso__load_vmlinux(struct dso *self, struct map *map,
1233 const char *vmlinux,
893 symbol_filter_t filter, int v) 1234 symbol_filter_t filter, int v)
894{ 1235{
895 int err, fd = open(vmlinux, O_RDONLY); 1236 int err, fd = open(vmlinux, O_RDONLY);
@@ -897,47 +1238,82 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
897 if (fd < 0) 1238 if (fd < 0)
898 return -1; 1239 return -1;
899 1240
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1241 err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v);
901
902 if (err > 0)
903 dso__fill_symbol_holes(self);
904 1242
905 close(fd); 1243 close(fd);
906 1244
907 return err; 1245 return err;
908} 1246}
909 1247
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1248int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
911 symbol_filter_t filter, int v, int use_modules) 1249 symbol_filter_t filter, int v, int use_modules)
912{ 1250{
913 int err = -1; 1251 int err = -1;
1252 struct dso *dso = dso__new(vmlinux, sym_priv_size);
1253
1254 if (dso == NULL)
1255 return -1;
1256
1257 dso->short_name = "[kernel]";
1258 kernel_map = map__new2(0, dso);
1259 if (kernel_map == NULL)
1260 goto out_delete_dso;
1261
1262 kernel_map->map_ip = vdso__map_ip;
1263
1264 if (use_modules && dsos__load_modules(sym_priv_size) < 0) {
1265 fprintf(stderr, "Failed to load list of modules in use! "
1266 "Continuing...\n");
1267 use_modules = 0;
1268 }
914 1269
915 if (vmlinux) { 1270 if (vmlinux) {
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1271 err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
917 if (err > 0 && use_modules) { 1272 if (err > 0 && use_modules) {
918 int syms = dso__load_modules(self, filter, v); 1273 int syms = dsos__load_modules_sym(filter, v);
919 1274
920 if (syms < 0) { 1275 if (syms < 0)
921 fprintf(stderr, "dso__load_modules failed!\n"); 1276 fprintf(stderr, "Failed to read module symbols!"
922 return syms; 1277 " Continuing...\n");
923 } 1278 else
924 err += syms; 1279 err += syms;
925 } 1280 }
926 } 1281 }
927 1282
928 if (err <= 0) 1283 if (err <= 0)
929 err = dso__load_kallsyms(self, filter, v); 1284 err = kernel_maps__load_kallsyms(filter, use_modules, v);
930 1285
931 if (err > 0) 1286 if (err > 0) {
932 self->origin = DSO__ORIG_KERNEL; 1287 struct rb_node *node = rb_first(&dso->syms);
1288 struct symbol *sym = rb_entry(node, struct symbol, rb_node);
1289
1290 kernel_map->start = sym->start;
1291 node = rb_last(&dso->syms);
1292 sym = rb_entry(node, struct symbol, rb_node);
1293 kernel_map->end = sym->end;
1294
1295 dso->origin = DSO__ORIG_KERNEL;
1296 kernel_maps__insert(kernel_map);
1297 /*
1298 * Now that we have all sorted out, just set the ->end of all
1299 * maps:
1300 */
1301 kernel_maps__fixup_end();
1302 dsos__add(dso);
1303
1304 if (v > 0)
1305 kernel_maps__fprintf(stderr, v);
1306 }
933 1307
934 return err; 1308 return err;
1309
1310out_delete_dso:
1311 dso__delete(dso);
1312 return -1;
935} 1313}
936 1314
937LIST_HEAD(dsos); 1315LIST_HEAD(dsos);
938struct dso *kernel_dso;
939struct dso *vdso; 1316struct dso *vdso;
940struct dso *hypervisor_dso;
941 1317
942const char *vmlinux_name = "vmlinux"; 1318const char *vmlinux_name = "vmlinux";
943int modules; 1319int modules;
@@ -969,7 +1345,7 @@ struct dso *dsos__findnew(const char *name)
969 if (!dso) 1345 if (!dso)
970 goto out_delete_dso; 1346 goto out_delete_dso;
971 1347
972 nr = dso__load(dso, NULL, verbose); 1348 nr = dso__load(dso, NULL, NULL, verbose);
973 if (nr < 0) { 1349 if (nr < 0) {
974 eprintf("Failed to open: %s\n", name); 1350 eprintf("Failed to open: %s\n", name);
975 goto out_delete_dso; 1351 goto out_delete_dso;
@@ -994,43 +1370,20 @@ void dsos__fprintf(FILE *fp)
994 dso__fprintf(pos, fp); 1370 dso__fprintf(pos, fp);
995} 1371}
996 1372
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
998{
999 return dso__find_symbol(dso, ip);
1000}
1001
1002int load_kernel(void) 1373int load_kernel(void)
1003{ 1374{
1004 int err; 1375 if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0)
1005
1006 kernel_dso = dso__new("[kernel]", 0);
1007 if (!kernel_dso)
1008 return -1; 1376 return -1;
1009 1377
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1011 if (err <= 0) {
1012 dso__delete(kernel_dso);
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016
1017 vdso = dso__new("[vdso]", 0); 1378 vdso = dso__new("[vdso]", 0);
1018 if (!vdso) 1379 if (!vdso)
1019 return -1; 1380 return -1;
1020 1381
1021 vdso->find_symbol = vdso__find_symbol;
1022
1023 dsos__add(vdso); 1382 dsos__add(vdso);
1024 1383
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1384 return 0;
1026 if (!hypervisor_dso)
1027 return -1;
1028 dsos__add(hypervisor_dso);
1029
1030 return err;
1031} 1385}
1032 1386
1033
1034void symbol__init(void) 1387void symbol__init(void)
1035{ 1388{
1036 elf_version(EV_CURRENT); 1389 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 6e8490716408..2e4522edeb07 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -1,11 +1,10 @@
1#ifndef _PERF_SYMBOL_ 1#ifndef __PERF_SYMBOL
2#define _PERF_SYMBOL_ 1 2#define __PERF_SYMBOL 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include "types.h" 5#include "types.h"
6#include <linux/list.h> 6#include <linux/list.h>
7#include <linux/rbtree.h> 7#include <linux/rbtree.h>
8#include "module.h"
9#include "event.h" 8#include "event.h"
10 9
11#ifdef HAVE_CPLUS_DEMANGLE 10#ifdef HAVE_CPLUS_DEMANGLE
@@ -36,10 +35,8 @@ struct symbol {
36 struct rb_node rb_node; 35 struct rb_node rb_node;
37 u64 start; 36 u64 start;
38 u64 end; 37 u64 end;
39 u64 obj_start;
40 u64 hist_sum; 38 u64 hist_sum;
41 u64 *hist; 39 u64 *hist;
42 struct module *module;
43 void *priv; 40 void *priv;
44 char name[0]; 41 char name[0];
45}; 42};
@@ -52,12 +49,14 @@ struct dso {
52 unsigned char adjust_symbols; 49 unsigned char adjust_symbols;
53 unsigned char slen_calculated; 50 unsigned char slen_calculated;
54 unsigned char origin; 51 unsigned char origin;
52 const char *short_name;
53 char *long_name;
55 char name[0]; 54 char name[0];
56}; 55};
57 56
58extern const char *sym_hist_filter; 57extern const char *sym_hist_filter;
59 58
60typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); 59typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
61 60
62struct dso *dso__new(const char *name, unsigned int sym_priv_size); 61struct dso *dso__new(const char *name, unsigned int sym_priv_size);
63void dso__delete(struct dso *self); 62void dso__delete(struct dso *self);
@@ -69,10 +68,10 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
69 68
70struct symbol *dso__find_symbol(struct dso *self, u64 ip); 69struct symbol *dso__find_symbol(struct dso *self, u64 ip);
71 70
72int dso__load_kernel(struct dso *self, const char *vmlinux, 71int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
73 symbol_filter_t filter, int verbose, int modules); 72 symbol_filter_t filter, int verbose, int modules);
74int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); 73int dso__load(struct dso *self, struct map *map, symbol_filter_t filter,
75int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 74 int verbose);
76struct dso *dsos__findnew(const char *name); 75struct dso *dsos__findnew(const char *name);
77void dsos__fprintf(FILE *fp); 76void dsos__fprintf(FILE *fp);
78 77
@@ -84,9 +83,8 @@ int load_kernel(void);
84void symbol__init(void); 83void symbol__init(void);
85 84
86extern struct list_head dsos; 85extern struct list_head dsos;
87extern struct dso *kernel_dso; 86extern struct map *kernel_map;
88extern struct dso *vdso; 87extern struct dso *vdso;
89extern struct dso *hypervisor_dso;
90extern const char *vmlinux_name; 88extern const char *vmlinux_name;
91extern int modules; 89extern int modules;
92#endif /* _PERF_SYMBOL_ */ 90#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45efb5db0d19..3b56aebb1f4b 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -15,7 +15,8 @@ static struct thread *thread__new(pid_t pid)
15 self->comm = malloc(32); 15 self->comm = malloc(32);
16 if (self->comm) 16 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 17 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps); 18 self->maps = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps);
19 } 20 }
20 21
21 return self; 22 return self;
@@ -31,10 +32,19 @@ int thread__set_comm(struct thread *self, const char *comm)
31 32
32static size_t thread__fprintf(struct thread *self, FILE *fp) 33static size_t thread__fprintf(struct thread *self, FILE *fp)
33{ 34{
35 struct rb_node *nd;
34 struct map *pos; 36 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 37 size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
38 self->pid, self->comm);
39
40 for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
41 pos = rb_entry(nd, struct map, rb_node);
42 ret += map__fprintf(pos, fp);
43 }
44
45 ret = fprintf(fp, "Removed maps:\n");
36 46
37 list_for_each_entry(pos, &self->maps, node) 47 list_for_each_entry(pos, &self->removed_maps, node)
38 ret += map__fprintf(pos, fp); 48 ret += map__fprintf(pos, fp);
39 49
40 return ret; 50 return ret;
@@ -93,42 +103,82 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
93 return thread; 103 return thread;
94} 104}
95 105
96void thread__insert_map(struct thread *self, struct map *map) 106static void thread__remove_overlappings(struct thread *self, struct map *map)
97{ 107{
98 struct map *pos, *tmp; 108 struct rb_node *next = rb_first(&self->maps);
99 109
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 110 while (next) {
101 if (map__overlap(pos, map)) { 111 struct map *pos = rb_entry(next, struct map, rb_node);
102 if (verbose >= 2) { 112 next = rb_next(&pos->rb_node);
103 printf("overlapping maps:\n"); 113
104 map__fprintf(map, stdout); 114 if (!map__overlap(pos, map))
105 map__fprintf(pos, stdout); 115 continue;
106 } 116
107 117 if (verbose >= 2) {
108 if (map->start <= pos->start && map->end > pos->start) 118 printf("overlapping maps:\n");
109 pos->start = map->end; 119 map__fprintf(map, stdout);
110 120 map__fprintf(pos, stdout);
111 if (map->end >= pos->end && map->start < pos->end)
112 pos->end = map->start;
113
114 if (verbose >= 2) {
115 printf("after collision:\n");
116 map__fprintf(pos, stdout);
117 }
118
119 if (pos->start >= pos->end) {
120 list_del_init(&pos->node);
121 free(pos);
122 }
123 } 121 }
122
123 rb_erase(&pos->rb_node, &self->maps);
124 /*
125 * We may have references to this map, for instance in some
126 * hist_entry instances, so just move them to a separate
127 * list.
128 */
129 list_add_tail(&pos->node, &self->removed_maps);
130 }
131}
132
133void maps__insert(struct rb_root *maps, struct map *map)
134{
135 struct rb_node **p = &maps->rb_node;
136 struct rb_node *parent = NULL;
137 const u64 ip = map->start;
138 struct map *m;
139
140 while (*p != NULL) {
141 parent = *p;
142 m = rb_entry(parent, struct map, rb_node);
143 if (ip < m->start)
144 p = &(*p)->rb_left;
145 else
146 p = &(*p)->rb_right;
124 } 147 }
125 148
126 list_add_tail(&map->node, &self->maps); 149 rb_link_node(&map->rb_node, parent, p);
150 rb_insert_color(&map->rb_node, maps);
151}
152
153struct map *maps__find(struct rb_root *maps, u64 ip)
154{
155 struct rb_node **p = &maps->rb_node;
156 struct rb_node *parent = NULL;
157 struct map *m;
158
159 while (*p != NULL) {
160 parent = *p;
161 m = rb_entry(parent, struct map, rb_node);
162 if (ip < m->start)
163 p = &(*p)->rb_left;
164 else if (ip > m->end)
165 p = &(*p)->rb_right;
166 else
167 return m;
168 }
169
170 return NULL;
171}
172
173void thread__insert_map(struct thread *self, struct map *map)
174{
175 thread__remove_overlappings(self, map);
176 maps__insert(&self->maps, map);
127} 177}
128 178
129int thread__fork(struct thread *self, struct thread *parent) 179int thread__fork(struct thread *self, struct thread *parent)
130{ 180{
131 struct map *map; 181 struct rb_node *nd;
132 182
133 if (self->comm) 183 if (self->comm)
134 free(self->comm); 184 free(self->comm);
@@ -136,7 +186,8 @@ int thread__fork(struct thread *self, struct thread *parent)
136 if (!self->comm) 186 if (!self->comm)
137 return -ENOMEM; 187 return -ENOMEM;
138 188
139 list_for_each_entry(map, &parent->maps, node) { 189 for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) {
190 struct map *map = rb_entry(nd, struct map, rb_node);
140 struct map *new = map__clone(map); 191 struct map *new = map__clone(map);
141 if (!new) 192 if (!new)
142 return -ENOMEM; 193 return -ENOMEM;
@@ -146,20 +197,6 @@ int thread__fork(struct thread *self, struct thread *parent)
146 return 0; 197 return 0;
147} 198}
148 199
149struct map *thread__find_map(struct thread *self, u64 ip)
150{
151 struct map *pos;
152
153 if (self == NULL)
154 return NULL;
155
156 list_for_each_entry(pos, &self->maps, node)
157 if (ip >= pos->start && ip <= pos->end)
158 return pos;
159
160 return NULL;
161}
162
163size_t threads__fprintf(FILE *fp, struct rb_root *threads) 200size_t threads__fprintf(FILE *fp, struct rb_root *threads)
164{ 201{
165 size_t ret = 0; 202 size_t ret = 0;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..845d9b62f96f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,11 +1,14 @@
1#ifndef __PERF_THREAD_H
2#define __PERF_THREAD_H
3
1#include <linux/rbtree.h> 4#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h> 5#include <unistd.h>
4#include "symbol.h" 6#include "symbol.h"
5 7
6struct thread { 8struct thread {
7 struct rb_node rb_node; 9 struct rb_node rb_node;
8 struct list_head maps; 10 struct rb_root maps;
11 struct list_head removed_maps;
9 pid_t pid; 12 pid_t pid;
10 char shortname[3]; 13 char shortname[3];
11 char *comm; 14 char *comm;
@@ -18,5 +21,17 @@ struct thread *
18register_idle_thread(struct rb_root *threads, struct thread **last_match); 21register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map); 22void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 23int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 24size_t threads__fprintf(FILE *fp, struct rb_root *threads);
25
26void maps__insert(struct rb_root *maps, struct map *map);
27struct map *maps__find(struct rb_root *maps, u64 ip);
28
29struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp);
30struct map *kernel_maps__find_by_dso_name(const char *name);
31
32static inline struct map *thread__find_map(struct thread *self, u64 ip)
33{
34 return self ? maps__find(&self->maps, ip) : NULL;
35}
36
37#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index af4b0573b37f..831052d4b4fb 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -496,14 +496,12 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
496 496
497 return path.next; 497 return path.next;
498} 498}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events) 499void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
500{ 500{
501 char buf[BUFSIZ]; 501 char buf[BUFSIZ];
502 struct tracepoint_path *tps; 502 struct tracepoint_path *tps;
503 503
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); 504 output_fd = fd;
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507 505
508 buf[0] = 23; 506 buf[0] = 23;
509 buf[1] = 8; 507 buf[1] = 8;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 55b41b9e3834..6f851f98b5b4 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -721,6 +721,24 @@ static int event_read_id(void)
721 return -1; 721 return -1;
722} 722}
723 723
724static int field_is_string(struct format_field *field)
725{
726 if ((field->flags & FIELD_IS_ARRAY) &&
727 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
728 !strstr(field->type, "s8")))
729 return 1;
730
731 return 0;
732}
733
734static int field_is_dynamic(struct format_field *field)
735{
736 if (!strcmp(field->type, "__data_loc"))
737 return 1;
738
739 return 0;
740}
741
724static int event_read_fields(struct event *event, struct format_field **fields) 742static int event_read_fields(struct event *event, struct format_field **fields)
725{ 743{
726 struct format_field *field = NULL; 744 struct format_field *field = NULL;
@@ -865,6 +883,12 @@ static int event_read_fields(struct event *event, struct format_field **fields)
865 free(brackets); 883 free(brackets);
866 } 884 }
867 885
886 if (field_is_string(field)) {
887 field->flags |= FIELD_IS_STRING;
888 if (field_is_dynamic(field))
889 field->flags |= FIELD_IS_DYNAMIC;
890 }
891
868 if (test_type_token(type, token, EVENT_OP, (char *)";")) 892 if (test_type_token(type, token, EVENT_OP, (char *)";"))
869 goto fail; 893 goto fail;
870 free_token(token); 894 free_token(token);
@@ -897,6 +921,21 @@ static int event_read_fields(struct event *event, struct format_field **fields)
897 if (read_expected(EVENT_OP, (char *)";") < 0) 921 if (read_expected(EVENT_OP, (char *)";") < 0)
898 goto fail_expect; 922 goto fail_expect;
899 923
924 if (read_expected(EVENT_ITEM, (char *)"signed") < 0)
925 goto fail_expect;
926
927 if (read_expected(EVENT_OP, (char *)":") < 0)
928 goto fail_expect;
929
930 if (read_expect_type(EVENT_ITEM, &token))
931 goto fail;
932 if (strtoul(token, NULL, 0))
933 field->flags |= FIELD_IS_SIGNED;
934 free_token(token);
935
936 if (read_expected(EVENT_OP, (char *)";") < 0)
937 goto fail_expect;
938
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0) 939 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
901 goto fail; 940 goto fail;
902 free_token(token); 941 free_token(token);
@@ -2845,6 +2884,15 @@ static void parse_header_field(char *type,
2845 free_token(token); 2884 free_token(token);
2846 if (read_expected(EVENT_OP, (char *)";") < 0) 2885 if (read_expected(EVENT_OP, (char *)";") < 0)
2847 return; 2886 return;
2887 if (read_expected(EVENT_ITEM, (char *)"signed") < 0)
2888 return;
2889 if (read_expected(EVENT_OP, (char *)":") < 0)
2890 return;
2891 if (read_expect_type(EVENT_ITEM, &token) < 0)
2892 return;
2893 free_token(token);
2894 if (read_expected(EVENT_OP, (char *)";") < 0)
2895 return;
2848 if (read_expect_type(EVENT_NEWLINE, &token) < 0) 2896 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2849 return; 2897 return;
2850 free_token(token); 2898 free_token(token);
@@ -2926,7 +2974,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
2926 return 0; 2974 return 0;
2927} 2975}
2928 2976
2929int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) 2977int parse_event_file(char *buf, unsigned long size, char *sys)
2930{ 2978{
2931 struct event *event; 2979 struct event *event;
2932 int ret; 2980 int ret;
@@ -2953,6 +3001,8 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2953 if (ret < 0) 3001 if (ret < 0)
2954 die("failed to read event print fmt"); 3002 die("failed to read event print fmt");
2955 3003
3004 event->system = strdup(sys);
3005
2956#define PRINT_ARGS 0 3006#define PRINT_ARGS 0
2957 if (PRINT_ARGS && event->print_fmt.args) 3007 if (PRINT_ARGS && event->print_fmt.args)
2958 print_args(event->print_fmt.args); 3008 print_args(event->print_fmt.args);
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1b5c847d2c22..44292e06cca4 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -458,9 +458,8 @@ struct record *trace_read_data(int cpu)
458 return data; 458 return data;
459} 459}
460 460
461void trace_report(void) 461void trace_report(int fd)
462{ 462{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ]; 463 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 464 char test[] = { 23, 8, 68 };
466 char *version; 465 char *version;
@@ -468,9 +467,7 @@ void trace_report(void)
468 int show_funcs = 0; 467 int show_funcs = 0;
469 int show_printk = 0; 468 int show_printk = 0;
470 469
471 input_fd = open(input_file, O_RDONLY); 470 input_fd = fd;
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474 471
475 read_or_die(buf, 3); 472 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0) 473 if (memcmp(buf, test, 3) != 0)
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 693f815c9429..da77e073c867 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,5 +1,5 @@
1#ifndef _TRACE_EVENTS_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define _TRACE_EVENTS_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include "parse-events.h" 4#include "parse-events.h"
5 5
@@ -26,6 +26,9 @@ enum {
26enum format_flags { 26enum format_flags {
27 FIELD_IS_ARRAY = 1, 27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2, 28 FIELD_IS_POINTER = 2,
29 FIELD_IS_SIGNED = 4,
30 FIELD_IS_STRING = 8,
31 FIELD_IS_DYNAMIC = 16,
29}; 32};
30 33
31struct format_field { 34struct format_field {
@@ -132,6 +135,7 @@ struct event {
132 int flags; 135 int flags;
133 struct format format; 136 struct format format;
134 struct print_fmt print_fmt; 137 struct print_fmt print_fmt;
138 char *system;
135}; 139};
136 140
137enum { 141enum {
@@ -154,7 +158,7 @@ struct record *trace_read_data(int cpu);
154 158
155void parse_set_info(int nr_cpus, int long_sz); 159void parse_set_info(int nr_cpus, int long_sz);
156 160
157void trace_report(void); 161void trace_report(int fd);
158 162
159void *malloc_or_die(unsigned int size); 163void *malloc_or_die(unsigned int size);
160 164
@@ -166,7 +170,7 @@ void print_funcs(void);
166void print_printk(void); 170void print_printk(void);
167 171
168int parse_ftrace_file(char *buf, unsigned long size); 172int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system); 173int parse_event_file(char *buf, unsigned long size, char *sys);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs, 174void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm); 175 char *comm);
172 176
@@ -240,6 +244,6 @@ unsigned long long
240raw_field_value(struct event *event, const char *name, void *data); 244raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data); 245void *raw_field_ptr(struct event *event, const char *name, void *data);
242 246
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events); 247void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
244 248
245#endif /* _TRACE_EVENTS_H */ 249#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5e75f9005940..7d6b8331f898 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_TYPES_H 1#ifndef __PERF_TYPES_H
2#define _PERF_TYPES_H 2#define __PERF_TYPES_H
3 3
4/* 4/*
5 * We define u64 as unsigned long long for every architecture 5 * We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short s16;
14typedef unsigned char u8; 14typedef unsigned char u8;
15typedef signed char s8; 15typedef signed char s8;
16 16
17#endif /* _PERF_TYPES_H */ 17#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index cadf8cf2a590..2fa967e1a88a 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define _PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
24void perf_read_values_display(FILE *fp, struct perf_read_values *values, 24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw); 25 int raw);
26 26
27#endif /* _PERF_VALUES_H */ 27#endif /* __PERF_VALUES_H */