Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates and fixes from Ingo Molnar:
"It's mostly fixes, but there's also two late items:

- preliminary GTK GUI support for perf report
- PMU raw event format descriptors in sysfs, to be parsed by tooling

The raw event format in sysfs is a new ABI. For example for the 'CPU'
PMU we have:

aldebaran:~> ll /sys/bus/event_source/devices/cpu/format/*
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/any
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/cmask
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/edge
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/event
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/inv
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/offcore_rsp
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/pc
-r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/umask

those lists of fields contain a specific format:

aldebaran:~> cat /sys/bus/event_source/devices/cpu/format/offcore_rsp
config1:0-63

So, those who wish to specify raw events can now use the following
event format:

-e cpu/cmask=1,event=2,umask=3

Most people will not want to specify any events (let alone raw
events), they'll just use whatever default event the tools use.

But for more obscure PMU events that have no cross-architecture
generic events the above syntax is more usable and a bit more
structured than specifying hex numbers."

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (41 commits)
perf tools: Remove auto-generated bison/flex files
perf annotate: Fix off by one symbol hist size allocation and hit accounting
perf tools: Add missing ref-cycles event back to event parser
perf annotate: addr2line wants addresses in same format as objdump
perf probe: Finder fails to resolve function name to address
tracing: Fix ent_size in trace output
perf symbols: Handle NULL dso in dso__name_len
perf symbols: Do not include libgen.h
perf tools: Fix bug in raw sample parsing
perf tools: Fix display of first level of callchains
perf tools: Switch module.h into export.h
perf: Move mmap page data_head offset assertion out of header
perf: Fix mmap_page capabilities and docs
perf diff: Fix to work with new hists design
perf tools: Fix modifier to be applied on correct events
perf tools: Fix various casting issues for 32 bits
perf tools: Simplify event_read_id exit path
tracing: Fix ftrace stack trace entries
tracing: Move the tracing_on/off() declarations into CONFIG_TRACING
perf report: Add a simple GTK2-based 'perf report' browser
...

+14
Documentation/ABI/testing/sysfs-bus-event_source-devices-format
··· 1 + Where: /sys/bus/event_source/devices/<dev>/format 2 + Date: January 2012 3 + Kernel Version: 3.3 4 + Contact: Jiri Olsa <jolsa@redhat.com> 5 + Description: 6 + Attribute group to describe the magic bits that go into 7 + perf_event_attr::config[012] for a particular pmu. 8 + Each attribute of this group defines the 'hardware' bitmask 9 + we want to export, so that userspace can deal with sane 10 + name/value pairs. 11 + 12 + Example: 'config1:1,6-10,44' 13 + Defines contents of attribute that occupies bits 1,6-10,44 of 14 + perf_event_attr::config1.
+16 -1
arch/x86/kernel/cpu/perf_event.c
··· 1313 1313 pr_info("no hardware sampling interrupt available.\n"); 1314 1314 } 1315 1315 1316 + static struct attribute_group x86_pmu_format_group = { 1317 + .name = "format", 1318 + .attrs = NULL, 1319 + }; 1320 + 1316 1321 static int __init init_hw_perf_events(void) 1317 1322 { 1318 1323 struct x86_pmu_quirk *quirk; ··· 1392 1387 } 1393 1388 1394 1389 x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ 1390 + x86_pmu_format_group.attrs = x86_pmu.format_attrs; 1395 1391 1396 1392 pr_info("... version: %d\n", x86_pmu.version); 1397 1393 pr_info("... bit width: %d\n", x86_pmu.cntval_bits); ··· 1621 1615 { 1622 1616 int idx = event->hw.idx; 1623 1617 1618 + if (!x86_pmu.attr_rdpmc) 1619 + return 0; 1620 + 1624 1621 if (x86_pmu.num_counters_fixed && idx >= X86_PMC_IDX_FIXED) { 1625 1622 idx -= X86_PMC_IDX_FIXED; 1626 1623 idx |= 1 << 30; ··· 1676 1667 1677 1668 static const struct attribute_group *x86_pmu_attr_groups[] = { 1678 1669 &x86_pmu_attr_group, 1670 + &x86_pmu_format_group, 1679 1671 NULL, 1680 1672 }; 1681 1673 ··· 1708 1698 .flush_branch_stack = x86_pmu_flush_branch_stack, 1709 1699 }; 1710 1700 1711 - void perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now) 1701 + void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now) 1712 1702 { 1703 + userpg->cap_usr_time = 0; 1704 + userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; 1705 + userpg->pmc_width = x86_pmu.cntval_bits; 1706 + 1713 1707 if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) 1714 1708 return; 1715 1709 1716 1710 if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) 1717 1711 return; 1718 1712 1713 + userpg->cap_usr_time = 1; 1719 1714 userpg->time_mult = this_cpu_read(cyc2ns); 1720 1715 userpg->time_shift = CYC2NS_SCALE_FACTOR; 1721 1716 userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
+1
arch/x86/kernel/cpu/perf_event.h
··· 339 339 * sysfs attrs 340 340 */ 341 341 int attr_rdpmc; 342 + struct attribute **format_attrs; 342 343 343 344 /* 344 345 * CPU Hotplug hooks
+18
arch/x86/kernel/cpu/perf_event_amd.c
··· 404 404 } 405 405 } 406 406 407 + PMU_FORMAT_ATTR(event, "config:0-7,32-35"); 408 + PMU_FORMAT_ATTR(umask, "config:8-15" ); 409 + PMU_FORMAT_ATTR(edge, "config:18" ); 410 + PMU_FORMAT_ATTR(inv, "config:23" ); 411 + PMU_FORMAT_ATTR(cmask, "config:24-31" ); 412 + 413 + static struct attribute *amd_format_attr[] = { 414 + &format_attr_event.attr, 415 + &format_attr_umask.attr, 416 + &format_attr_edge.attr, 417 + &format_attr_inv.attr, 418 + &format_attr_cmask.attr, 419 + NULL, 420 + }; 421 + 407 422 static __initconst const struct x86_pmu amd_pmu = { 408 423 .name = "AMD", 409 424 .handle_irq = x86_pmu_handle_irq, ··· 440 425 .max_period = (1ULL << 47) - 1, 441 426 .get_event_constraints = amd_get_event_constraints, 442 427 .put_event_constraints = amd_put_event_constraints, 428 + 429 + .format_attrs = amd_format_attr, 443 430 444 431 .cpu_prepare = amd_pmu_cpu_prepare, 445 432 .cpu_starting = amd_pmu_cpu_starting, ··· 613 596 .cpu_dead = amd_pmu_cpu_dead, 614 597 #endif 615 598 .cpu_starting = amd_pmu_cpu_starting, 599 + .format_attrs = amd_format_attr, 616 600 }; 617 601 618 602 __init int amd_pmu_init(void)
+36
arch/x86/kernel/cpu/perf_event_intel.c
··· 1431 1431 } 1432 1432 } 1433 1433 1434 + PMU_FORMAT_ATTR(event, "config:0-7" ); 1435 + PMU_FORMAT_ATTR(umask, "config:8-15" ); 1436 + PMU_FORMAT_ATTR(edge, "config:18" ); 1437 + PMU_FORMAT_ATTR(pc, "config:19" ); 1438 + PMU_FORMAT_ATTR(any, "config:21" ); /* v3 + */ 1439 + PMU_FORMAT_ATTR(inv, "config:23" ); 1440 + PMU_FORMAT_ATTR(cmask, "config:24-31" ); 1441 + 1442 + static struct attribute *intel_arch_formats_attr[] = { 1443 + &format_attr_event.attr, 1444 + &format_attr_umask.attr, 1445 + &format_attr_edge.attr, 1446 + &format_attr_pc.attr, 1447 + &format_attr_inv.attr, 1448 + &format_attr_cmask.attr, 1449 + NULL, 1450 + }; 1451 + 1434 1452 static __initconst const struct x86_pmu core_pmu = { 1435 1453 .name = "core", 1436 1454 .handle_irq = x86_pmu_handle_irq, ··· 1473 1455 .put_event_constraints = intel_put_event_constraints, 1474 1456 .event_constraints = intel_core_event_constraints, 1475 1457 .guest_get_msrs = core_guest_get_msrs, 1458 + .format_attrs = intel_arch_formats_attr, 1476 1459 }; 1477 1460 1478 1461 struct intel_shared_regs *allocate_shared_regs(int cpu) ··· 1572 1553 intel_pmu_lbr_reset(); 1573 1554 } 1574 1555 1556 + PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); 1557 + 1558 + static struct attribute *intel_arch3_formats_attr[] = { 1559 + &format_attr_event.attr, 1560 + &format_attr_umask.attr, 1561 + &format_attr_edge.attr, 1562 + &format_attr_pc.attr, 1563 + &format_attr_any.attr, 1564 + &format_attr_inv.attr, 1565 + &format_attr_cmask.attr, 1566 + 1567 + &format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */ 1568 + NULL, 1569 + }; 1570 + 1575 1571 static __initconst const struct x86_pmu intel_pmu = { 1576 1572 .name = "Intel", 1577 1573 .handle_irq = intel_pmu_handle_irq, ··· 1609 1575 .max_period = (1ULL << 31) - 1, 1610 1576 .get_event_constraints = intel_get_event_constraints, 1611 1577 .put_event_constraints = intel_put_event_constraints, 1578 + 1579 + .format_attrs = intel_arch3_formats_attr, 1612 1580 1613 1581 .cpu_prepare = intel_pmu_cpu_prepare, 1614 1582 .cpu_starting = intel_pmu_cpu_starting,
+19
arch/x86/kernel/cpu/perf_event_p6.c
··· 87 87 (void)checking_wrmsrl(hwc->config_base, val); 88 88 } 89 89 90 + PMU_FORMAT_ATTR(event, "config:0-7" ); 91 + PMU_FORMAT_ATTR(umask, "config:8-15" ); 92 + PMU_FORMAT_ATTR(edge, "config:18" ); 93 + PMU_FORMAT_ATTR(pc, "config:19" ); 94 + PMU_FORMAT_ATTR(inv, "config:23" ); 95 + PMU_FORMAT_ATTR(cmask, "config:24-31" ); 96 + 97 + static struct attribute *intel_p6_formats_attr[] = { 98 + &format_attr_event.attr, 99 + &format_attr_umask.attr, 100 + &format_attr_edge.attr, 101 + &format_attr_pc.attr, 102 + &format_attr_inv.attr, 103 + &format_attr_cmask.attr, 104 + NULL, 105 + }; 106 + 90 107 static __initconst const struct x86_pmu p6_pmu = { 91 108 .name = "p6", 92 109 .handle_irq = x86_pmu_handle_irq, ··· 132 115 .cntval_mask = (1ULL << 32) - 1, 133 116 .get_event_constraints = x86_get_event_constraints, 134 117 .event_constraints = p6_event_constraints, 118 + 119 + .format_attrs = intel_p6_formats_attr, 135 120 }; 136 121 137 122 __init int p6_pmu_init(void)
+2
include/linux/ftrace_event.h
··· 144 144 enum trace_reg { 145 145 TRACE_REG_REGISTER, 146 146 TRACE_REG_UNREGISTER, 147 + #ifdef CONFIG_PERF_EVENTS 147 148 TRACE_REG_PERF_REGISTER, 148 149 TRACE_REG_PERF_UNREGISTER, 149 150 TRACE_REG_PERF_OPEN, 150 151 TRACE_REG_PERF_CLOSE, 151 152 TRACE_REG_PERF_ADD, 152 153 TRACE_REG_PERF_DEL, 154 + #endif 153 155 }; 154 156 155 157 struct ftrace_event_call;
+9 -6
include/linux/kernel.h
··· 430 430 * Most likely, you want to use tracing_on/tracing_off. 431 431 */ 432 432 #ifdef CONFIG_RING_BUFFER 433 - void tracing_on(void); 434 - void tracing_off(void); 435 433 /* trace_off_permanent stops recording with no way to bring it back */ 436 434 void tracing_off_permanent(void); 437 - int tracing_is_on(void); 438 435 #else 439 - static inline void tracing_on(void) { } 440 - static inline void tracing_off(void) { } 441 436 static inline void tracing_off_permanent(void) { } 442 - static inline int tracing_is_on(void) { return 0; } 443 437 #endif 444 438 445 439 enum ftrace_dump_mode { ··· 443 449 }; 444 450 445 451 #ifdef CONFIG_TRACING 452 + void tracing_on(void); 453 + void tracing_off(void); 454 + int tracing_is_on(void); 455 + 446 456 extern void tracing_start(void); 447 457 extern void tracing_stop(void); 448 458 extern void ftrace_off_permanent(void); ··· 531 533 static inline void tracing_stop(void) { } 532 534 static inline void ftrace_off_permanent(void) { } 533 535 static inline void trace_dump_stack(void) { } 536 + 537 + static inline void tracing_on(void) { } 538 + static inline void tracing_off(void) { } 539 + static inline int tracing_is_on(void) { return 0; } 540 + 534 541 static inline int 535 542 trace_printk(const char *fmt, ...) 536 543 {
+80 -10
include/linux/perf_event.h
··· 299 299 /* 300 300 * Bits needed to read the hw events in user-space. 301 301 * 302 - * u32 seq; 303 - * s64 count; 302 + * u32 seq, time_mult, time_shift, idx, width; 303 + * u64 count, enabled, running; 304 + * u64 cyc, time_offset; 305 + * s64 pmc = 0; 304 306 * 305 307 * do { 306 308 * seq = pc->lock; 307 - * 308 309 * barrier() 309 - * if (pc->index) { 310 - * count = pmc_read(pc->index - 1); 311 - * count += pc->offset; 312 - * } else 313 - * goto regular_read; 310 + * 311 + * enabled = pc->time_enabled; 312 + * running = pc->time_running; 313 + * 314 + * if (pc->cap_usr_time && enabled != running) { 315 + * cyc = rdtsc(); 316 + * time_offset = pc->time_offset; 317 + * time_mult = pc->time_mult; 318 + * time_shift = pc->time_shift; 319 + * } 320 + * 321 + * idx = pc->index; 322 + * count = pc->offset; 323 + * if (pc->cap_usr_rdpmc && idx) { 324 + * width = pc->pmc_width; 325 + * pmc = rdpmc(idx - 1); 326 + * } 314 327 * 315 328 * barrier(); 316 329 * } while (pc->lock != seq); ··· 336 323 __s64 offset; /* add to hardware event value */ 337 324 __u64 time_enabled; /* time event active */ 338 325 __u64 time_running; /* time event on cpu */ 339 - __u32 time_mult, time_shift; 326 + union { 327 + __u64 capabilities; 328 + __u64 cap_usr_time : 1, 329 + cap_usr_rdpmc : 1, 330 + cap_____res : 62; 331 + }; 332 + 333 + /* 334 + * If cap_usr_rdpmc this field provides the bit-width of the value 335 + * read using the rdpmc() or equivalent instruction. This can be used 336 + * to sign extend the result like: 337 + * 338 + * pmc <<= 64 - width; 339 + * pmc >>= 64 - width; // signed shift right 340 + * count += pmc; 341 + */ 342 + __u16 pmc_width; 343 + 344 + /* 345 + * If cap_usr_time the below fields can be used to compute the time 346 + * delta since time_enabled (in ns) using rdtsc or similar. 347 + * 348 + * u64 quot, rem; 349 + * u64 delta; 350 + * 351 + * quot = (cyc >> time_shift); 352 + * rem = cyc & ((1 << time_shift) - 1); 353 + * delta = time_offset + quot * time_mult + 354 + * ((rem * time_mult) >> time_shift); 355 + * 356 + * Where time_offset,time_mult,time_shift and cyc are read in the 357 + * seqcount loop described above. This delta can then be added to 358 + * enabled and possible running (if idx), improving the scaling: 359 + * 360 + * enabled += delta; 361 + * if (idx) 362 + * running += delta; 363 + * 364 + * quot = count / running; 365 + * rem = count % running; 366 + * count = quot * enabled + (rem * enabled) / running; 367 + */ 368 + __u16 time_shift; 369 + __u32 time_mult; 340 370 __u64 time_offset; 341 371 342 372 /* 343 373 * Hole for extension of the self monitor capabilities 344 374 */ 345 375 346 - __u64 __reserved[121]; /* align to 1k */ 376 + __u64 __reserved[120]; /* align to 1k */ 347 377 348 378 /* 349 379 * Control data for the mmap() data buffer. ··· 606 550 #include <linux/irq_work.h> 607 551 #include <linux/static_key.h> 608 552 #include <linux/atomic.h> 553 + #include <linux/sysfs.h> 609 554 #include <asm/local.h> 610 555 611 556 #define PERF_MAX_STACK_DEPTH 255 ··· 1347 1290 (void *)(unsigned long)smp_processor_id()); \ 1348 1291 register_cpu_notifier(&fn##_nb); \ 1349 1292 } while (0) 1293 + 1294 + 1295 + #define PMU_FORMAT_ATTR(_name, _format) \ 1296 + static ssize_t \ 1297 + _name##_show(struct device *dev, \ 1298 + struct device_attribute *attr, \ 1299 + char *page) \ 1300 + { \ 1301 + BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ 1302 + return sprintf(page, _format "\n"); \ 1303 + } \ 1304 + \ 1305 + static struct device_attribute format_attr_##_name = __ATTR_RO(_name) 1350 1306 1351 1307 #endif /* __KERNEL__ */ 1352 1308 #endif /* _LINUX_PERF_EVENT_H */
+3
include/linux/ring_buffer.h
··· 151 151 152 152 void ring_buffer_record_disable(struct ring_buffer *buffer); 153 153 void ring_buffer_record_enable(struct ring_buffer *buffer); 154 + void ring_buffer_record_off(struct ring_buffer *buffer); 155 + void ring_buffer_record_on(struct ring_buffer *buffer); 156 + int ring_buffer_record_is_on(struct ring_buffer *buffer); 154 157 void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu); 155 158 void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); 156 159
+9 -2
kernel/events/core.c
··· 3348 3348 *running = ctx_time - event->tstamp_running; 3349 3349 } 3350 3350 3351 - void __weak perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now) 3351 + void __weak arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now) 3352 3352 { 3353 3353 } 3354 3354 ··· 3398 3398 userpg->time_running = running + 3399 3399 atomic64_read(&event->child_total_time_running); 3400 3400 3401 - perf_update_user_clock(userpg, now); 3401 + arch_perf_update_userpage(userpg, now); 3402 3402 3403 3403 barrier(); 3404 3404 ++userpg->lock; ··· 7116 7116 7117 7117 /* do not patch jump label more than once per second */ 7118 7118 jump_label_rate_limit(&perf_sched_events, HZ); 7119 + 7120 + /* 7121 + * Build time assertion that we keep the data_head at the intended 7122 + * location. IOW, validation we got the __reserved[] size right. 7123 + */ 7124 + BUILD_BUG_ON((offsetof(struct perf_event_mmap_page, data_head)) 7125 + != 1024); 7119 7126 } 7120 7127 7121 7128 static int __init perf_event_sysfs_init(void)
+1 -1
kernel/trace/Kconfig
··· 141 141 config FUNCTION_TRACER 142 142 bool "Kernel Function Tracer" 143 143 depends on HAVE_FUNCTION_TRACER 144 - select FRAME_POINTER if !ARM_UNWIND && !S390 && !MICROBLAZE 144 + select FRAME_POINTER if !ARM_UNWIND && !PPC && !S390 && !MICROBLAZE 145 145 select KALLSYMS 146 146 select GENERIC_TRACER 147 147 select CONTEXT_SWITCH_TRACER
+2 -1
kernel/trace/ftrace.c
··· 249 249 #else 250 250 __ftrace_trace_function = func; 251 251 #endif 252 - ftrace_trace_function = ftrace_test_stop_func; 252 + ftrace_trace_function = 253 + (func == ftrace_stub) ? func : ftrace_test_stop_func; 253 254 #endif 254 255 } 255 256
+60 -97
kernel/trace/ring_buffer.c
··· 154 154 155 155 static unsigned long ring_buffer_flags __read_mostly = RB_BUFFERS_ON; 156 156 157 + /* Used for individual buffers (after the counter) */ 158 + #define RB_BUFFER_OFF (1 << 20) 159 + 157 160 #define BUF_PAGE_HDR_SIZE offsetof(struct buffer_data_page, data) 158 - 159 - /** 160 - * tracing_on - enable all tracing buffers 161 - * 162 - * This function enables all tracing buffers that may have been 163 - * disabled with tracing_off. 164 - */ 165 - void tracing_on(void) 166 - { 167 - set_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags); 168 - } 169 - EXPORT_SYMBOL_GPL(tracing_on); 170 - 171 - /** 172 - * tracing_off - turn off all tracing buffers 173 - * 174 - * This function stops all tracing buffers from recording data. 175 - * It does not disable any overhead the tracers themselves may 176 - * be causing. This function simply causes all recording to 177 - * the ring buffers to fail. 178 - */ 179 - void tracing_off(void) 180 - { 181 - clear_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags); 182 - } 183 - EXPORT_SYMBOL_GPL(tracing_off); 184 161 185 162 /** 186 163 * tracing_off_permanent - permanently disable ring buffers ··· 169 192 { 170 193 set_bit(RB_BUFFERS_DISABLED_BIT, &ring_buffer_flags); 171 194 } 172 - 173 - /** 174 - * tracing_is_on - show state of ring buffers enabled 175 - */ 176 - int tracing_is_on(void) 177 - { 178 - return ring_buffer_flags == RB_BUFFERS_ON; 179 - } 180 - EXPORT_SYMBOL_GPL(tracing_is_on); 181 195 182 196 #define RB_EVNT_HDR_SIZE (offsetof(struct ring_buffer_event, array)) 183 197 #define RB_ALIGNMENT 4U ··· 2587 2619 EXPORT_SYMBOL_GPL(ring_buffer_record_enable); 2588 2620 2589 2621 /** 2622 + * ring_buffer_record_off - stop all writes into the buffer 2623 + * @buffer: The ring buffer to stop writes to. 2624 + * 2625 + * This prevents all writes to the buffer. Any attempt to write 2626 + * to the buffer after this will fail and return NULL. 2627 + * 2628 + * This is different than ring_buffer_record_disable() as 2629 + * it works like an on/off switch, where as the disable() verison 2630 + * must be paired with a enable(). 2631 + */ 2632 + void ring_buffer_record_off(struct ring_buffer *buffer) 2633 + { 2634 + unsigned int rd; 2635 + unsigned int new_rd; 2636 + 2637 + do { 2638 + rd = atomic_read(&buffer->record_disabled); 2639 + new_rd = rd | RB_BUFFER_OFF; 2640 + } while (atomic_cmpxchg(&buffer->record_disabled, rd, new_rd) != rd); 2641 + } 2642 + EXPORT_SYMBOL_GPL(ring_buffer_record_off); 2643 + 2644 + /** 2645 + * ring_buffer_record_on - restart writes into the buffer 2646 + * @buffer: The ring buffer to start writes to. 2647 + * 2648 + * This enables all writes to the buffer that was disabled by 2649 + * ring_buffer_record_off(). 2650 + * 2651 + * This is different than ring_buffer_record_enable() as 2652 + * it works like an on/off switch, where as the enable() verison 2653 + * must be paired with a disable(). 2654 + */ 2655 + void ring_buffer_record_on(struct ring_buffer *buffer) 2656 + { 2657 + unsigned int rd; 2658 + unsigned int new_rd; 2659 + 2660 + do { 2661 + rd = atomic_read(&buffer->record_disabled); 2662 + new_rd = rd & ~RB_BUFFER_OFF; 2663 + } while (atomic_cmpxchg(&buffer->record_disabled, rd, new_rd) != rd); 2664 + } 2665 + EXPORT_SYMBOL_GPL(ring_buffer_record_on); 2666 + 2667 + /** 2668 + * ring_buffer_record_is_on - return true if the ring buffer can write 2669 + * @buffer: The ring buffer to see if write is enabled 2670 + * 2671 + * Returns true if the ring buffer is in a state that it accepts writes. 2672 + */ 2673 + int ring_buffer_record_is_on(struct ring_buffer *buffer) 2674 + { 2675 + return !atomic_read(&buffer->record_disabled); 2676 + } 2677 + 2678 + /** 2590 2679 * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer 2591 2680 * @buffer: The ring buffer to stop writes to. 2592 2681 * @cpu: The CPU buffer to stop ··· 4063 4038 return ret; 4064 4039 } 4065 4040 EXPORT_SYMBOL_GPL(ring_buffer_read_page); 4066 - 4067 - #ifdef CONFIG_TRACING 4068 - static ssize_t 4069 - rb_simple_read(struct file *filp, char __user *ubuf, 4070 - size_t cnt, loff_t *ppos) 4071 - { 4072 - unsigned long *p = filp->private_data; 4073 - char buf[64]; 4074 - int r; 4075 - 4076 - if (test_bit(RB_BUFFERS_DISABLED_BIT, p)) 4077 - r = sprintf(buf, "permanently disabled\n"); 4078 - else 4079 - r = sprintf(buf, "%d\n", test_bit(RB_BUFFERS_ON_BIT, p)); 4080 - 4081 - return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 4082 - } 4083 - 4084 - static ssize_t 4085 - rb_simple_write(struct file *filp, const char __user *ubuf, 4086 - size_t cnt, loff_t *ppos) 4087 - { 4088 - unsigned long *p = filp->private_data; 4089 - unsigned long val; 4090 - int ret; 4091 - 4092 - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); 4093 - if (ret) 4094 - return ret; 4095 - 4096 - if (val) 4097 - set_bit(RB_BUFFERS_ON_BIT, p); 4098 - else 4099 - clear_bit(RB_BUFFERS_ON_BIT, p); 4100 - 4101 - (*ppos)++; 4102 - 4103 - return cnt; 4104 - } 4105 - 4106 - static const struct file_operations rb_simple_fops = { 4107 - .open = tracing_open_generic, 4108 - .read = rb_simple_read, 4109 - .write = rb_simple_write, 4110 - .llseek = default_llseek, 4111 - }; 4112 - 4113 - 4114 - static __init int rb_init_debugfs(void) 4115 - { 4116 - struct dentry *d_tracer; 4117 - 4118 - d_tracer = tracing_init_dentry(); 4119 - 4120 - trace_create_file("tracing_on", 0644, d_tracer, 4121 - &ring_buffer_flags, &rb_simple_fops); 4122 - 4123 - return 0; 4124 - } 4125 - 4126 - fs_initcall(rb_init_debugfs); 4127 - #endif 4128 4041 4129 4042 #ifdef CONFIG_HOTPLUG_CPU 4130 4043 static int rb_cpu_notify(struct notifier_block *self,
+113
kernel/trace/trace.c
··· 36 36 #include <linux/ctype.h> 37 37 #include <linux/init.h> 38 38 #include <linux/poll.h> 39 + #include <linux/nmi.h> 39 40 #include <linux/fs.h> 40 41 41 42 #include "trace.h" ··· 351 350 } 352 351 353 352 static DECLARE_DELAYED_WORK(wakeup_work, wakeup_work_handler); 353 + 354 + /** 355 + * tracing_on - enable tracing buffers 356 + * 357 + * This function enables tracing buffers that may have been 358 + * disabled with tracing_off. 359 + */ 360 + void tracing_on(void) 361 + { 362 + if (global_trace.buffer) 363 + ring_buffer_record_on(global_trace.buffer); 364 + /* 365 + * This flag is only looked at when buffers haven't been 366 + * allocated yet. We don't really care about the race 367 + * between setting this flag and actually turning 368 + * on the buffer. 369 + */ 370 + global_trace.buffer_disabled = 0; 371 + } 372 + EXPORT_SYMBOL_GPL(tracing_on); 373 + 374 + /** 375 + * tracing_off - turn off tracing buffers 376 + * 377 + * This function stops the tracing buffers from recording data. 378 + * It does not disable any overhead the tracers themselves may 379 + * be causing. This function simply causes all recording to 380 + * the ring buffers to fail. 381 + */ 382 + void tracing_off(void) 383 + { 384 + if (global_trace.buffer) 385 + ring_buffer_record_on(global_trace.buffer); 386 + /* 387 + * This flag is only looked at when buffers haven't been 388 + * allocated yet. We don't really care about the race 389 + * between setting this flag and actually turning 390 + * on the buffer. 391 + */ 392 + global_trace.buffer_disabled = 1; 393 + } 394 + EXPORT_SYMBOL_GPL(tracing_off); 395 + 396 + /** 397 + * tracing_is_on - show state of ring buffers enabled 398 + */ 399 + int tracing_is_on(void) 400 + { 401 + if (global_trace.buffer) 402 + return ring_buffer_record_is_on(global_trace.buffer); 403 + return !global_trace.buffer_disabled; 404 + } 405 + EXPORT_SYMBOL_GPL(tracing_is_on); 354 406 355 407 /** 356 408 * trace_wake_up - wake up tasks waiting for trace input ··· 1698 1644 int cpu_file = iter->cpu_file; 1699 1645 u64 next_ts = 0, ts; 1700 1646 int next_cpu = -1; 1647 + int next_size = 0; 1701 1648 int cpu; 1702 1649 1703 1650 /* ··· 1730 1675 next_cpu = cpu; 1731 1676 next_ts = ts; 1732 1677 next_lost = lost_events; 1678 + next_size = iter->ent_size; 1733 1679 } 1734 1680 } 1681 + 1682 + iter->ent_size = next_size; 1735 1683 1736 1684 if (ent_cpu) 1737 1685 *ent_cpu = next_cpu; ··· 4625 4567 create_trace_option_core_file(trace_options[i], i); 4626 4568 } 4627 4569 4570 + static ssize_t 4571 + rb_simple_read(struct file *filp, char __user *ubuf, 4572 + size_t cnt, loff_t *ppos) 4573 + { 4574 + struct ring_buffer *buffer = filp->private_data; 4575 + char buf[64]; 4576 + int r; 4577 + 4578 + if (buffer) 4579 + r = ring_buffer_record_is_on(buffer); 4580 + else 4581 + r = 0; 4582 + 4583 + r = sprintf(buf, "%d\n", r); 4584 + 4585 + return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 4586 + } 4587 + 4588 + static ssize_t 4589 + rb_simple_write(struct file *filp, const char __user *ubuf, 4590 + size_t cnt, loff_t *ppos) 4591 + { 4592 + struct ring_buffer *buffer = filp->private_data; 4593 + unsigned long val; 4594 + int ret; 4595 + 4596 + ret = kstrtoul_from_user(ubuf, cnt, 10, &val); 4597 + if (ret) 4598 + return ret; 4599 + 4600 + if (buffer) { 4601 + if (val) 4602 + ring_buffer_record_on(buffer); 4603 + else 4604 + ring_buffer_record_off(buffer); 4605 + } 4606 + 4607 + (*ppos)++; 4608 + 4609 + return cnt; 4610 + } 4611 + 4612 + static const struct file_operations rb_simple_fops = { 4613 + .open = tracing_open_generic, 4614 + .read = rb_simple_read, 4615 + .write = rb_simple_write, 4616 + .llseek = default_llseek, 4617 + }; 4618 + 4628 4619 static __init int tracer_init_debugfs(void) 4629 4620 { 4630 4621 struct dentry *d_tracer; ··· 4732 4625 4733 4626 trace_create_file("trace_clock", 0644, d_tracer, NULL, 4734 4627 &trace_clock_fops); 4628 + 4629 + trace_create_file("tracing_on", 0644, d_tracer, 4630 + global_trace.buffer, &rb_simple_fops); 4735 4631 4736 4632 #ifdef CONFIG_DYNAMIC_FTRACE 4737 4633 trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, ··· 4908 4798 if (ret != TRACE_TYPE_NO_CONSUME) 4909 4799 trace_consume(&iter); 4910 4800 } 4801 + touch_nmi_watchdog(); 4911 4802 4912 4803 trace_printk_seq(&iter.seq); 4913 4804 } ··· 4974 4863 goto out_free_cpumask; 4975 4864 } 4976 4865 global_trace.entries = ring_buffer_size(global_trace.buffer); 4866 + if (global_trace.buffer_disabled) 4867 + tracing_off(); 4977 4868 4978 4869 4979 4870 #ifdef CONFIG_TRACER_MAX_TRACE
+1 -2
kernel/trace/trace.h
··· 154 154 struct ring_buffer *buffer; 155 155 unsigned long entries; 156 156 int cpu; 157 + int buffer_disabled; 157 158 cycle_t time_start; 158 159 struct task_struct *waiter; 159 160 struct trace_array_cpu *data[NR_CPUS]; ··· 836 835 filter) 837 836 #include "trace_entries.h" 838 837 839 - #ifdef CONFIG_PERF_EVENTS 840 838 #ifdef CONFIG_FUNCTION_TRACER 841 839 int perf_ftrace_event_register(struct ftrace_event_call *call, 842 840 enum trace_reg type, void *data); 843 841 #else 844 842 #define perf_ftrace_event_register NULL 845 843 #endif /* CONFIG_FUNCTION_TRACER */ 846 - #endif /* CONFIG_PERF_EVENTS */ 847 844 848 845 #endif /* _LINUX_KERNEL_TRACE_H */
+12 -4
kernel/trace/trace_entries.h
··· 166 166 167 167 #define FTRACE_STACK_ENTRIES 8 168 168 169 + #ifndef CONFIG_64BIT 170 + # define IP_FMT "%08lx" 171 + #else 172 + # define IP_FMT "%016lx" 173 + #endif 174 + 169 175 FTRACE_ENTRY(kernel_stack, stack_entry, 170 176 171 177 TRACE_STACK, ··· 181 175 __dynamic_array(unsigned long, caller ) 182 176 ), 183 177 184 - F_printk("\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n" 185 - "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n", 178 + F_printk("\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n" 179 + "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n" 180 + "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n", 186 181 __entry->caller[0], __entry->caller[1], __entry->caller[2], 187 182 __entry->caller[3], __entry->caller[4], __entry->caller[5], 188 183 __entry->caller[6], __entry->caller[7]), ··· 200 193 __array( unsigned long, caller, FTRACE_STACK_ENTRIES ) 201 194 ), 202 195 203 - F_printk("\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n" 204 - "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n", 196 + F_printk("\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n" 197 + "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n" 198 + "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n", 205 199 __entry->caller[0], __entry->caller[1], __entry->caller[2], 206 200 __entry->caller[3], __entry->caller[4], __entry->caller[5], 207 201 __entry->caller[6], __entry->caller[7]),
+1 -1
kernel/trace/trace_export.c
··· 162 162 #define __dynamic_array(type, item) 163 163 164 164 #undef F_printk 165 - #define F_printk(fmt, args...) #fmt ", " __stringify(args) 165 + #define F_printk(fmt, args...) __stringify(fmt) ", " __stringify(args) 166 166 167 167 #undef FTRACE_ENTRY_REG 168 168 #define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, filter,\
+5
tools/perf/Documentation/perf-report.txt
··· 48 48 Only consider these symbols. CSV that understands 49 49 file://filename entries. 50 50 51 + --symbol-filter=:: 52 + Only show symbols that match (partially) with this filter. 53 + 51 54 -U:: 52 55 --hide-unresolved:: 53 56 Only display entries resolved to a symbol. ··· 112 109 zooming into DSOs or threads, among other features. Use of --tui 113 110 requires a tty, if one is not present, as when piping to other 114 111 commands, the stdio interface is used. 112 + 113 + --gtk:: Use the GTK2 interface. 115 114 116 115 -k:: 117 116 --vmlinux=<file>::
+63 -3
tools/perf/Makefile
··· 182 182 183 183 ### --- END CONFIGURATION SECTION --- 184 184 185 - BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 185 + BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 186 186 BASIC_LDFLAGS = 187 187 188 188 # Guard against environment variables ··· 234 234 235 235 export PERL_PATH 236 236 237 + FLEX = $(CROSS_COMPILE)flex 238 + BISON= $(CROSS_COMPILE)bison 239 + 240 + event-parser: 241 + $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c 242 + $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c 243 + 244 + $(OUTPUT)util/parse-events-flex.c: event-parser 245 + $(OUTPUT)util/parse-events-bison.c: event-parser 246 + 247 + pmu-parser: 248 + $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c 249 + $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c 250 + 251 + $(OUTPUT)util/pmu-flex.c: pmu-parser 252 + $(OUTPUT)util/pmu-bison.c: pmu-parser 253 + 254 + $(OUTPUT)util/parse-events.o: event-parser pmu-parser 255 + 237 256 LIB_FILE=$(OUTPUT)libperf.a 238 257 239 258 LIB_H += ../../include/linux/perf_event.h ··· 268 249 LIB_H += util/include/linux/ctype.h 269 250 LIB_H += util/include/linux/kernel.h 270 251 LIB_H += util/include/linux/list.h 271 - LIB_H += util/include/linux/module.h 252 + LIB_H += util/include/linux/export.h 272 253 LIB_H += util/include/linux/poison.h 273 254 LIB_H += util/include/linux/prefetch.h 274 255 LIB_H += util/include/linux/rbtree.h ··· 295 276 LIB_H += util/debug.h 296 277 LIB_H += util/debugfs.h 297 278 LIB_H += util/sysfs.h 279 + LIB_H += util/pmu.h 298 280 LIB_H += util/event.h 299 281 LIB_H += util/evsel.h 300 282 LIB_H += util/evlist.h ··· 343 323 LIB_OBJS += $(OUTPUT)util/ctype.o 344 324 LIB_OBJS += $(OUTPUT)util/debugfs.o 345 325 LIB_OBJS += $(OUTPUT)util/sysfs.o 326 + LIB_OBJS += $(OUTPUT)util/pmu.o 346 327 LIB_OBJS += $(OUTPUT)util/environment.o 347 328 LIB_OBJS += $(OUTPUT)util/event.o 348 329 LIB_OBJS += $(OUTPUT)util/evlist.o ··· 380 359 LIB_OBJS += $(OUTPUT)util/thread.o 381 360 LIB_OBJS += $(OUTPUT)util/thread_map.o 382 361 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 362 + LIB_OBJS += $(OUTPUT)util/parse-events-flex.o 363 + LIB_OBJS += $(OUTPUT)util/parse-events-bison.o 364 + LIB_OBJS += $(OUTPUT)util/pmu-flex.o 365 + LIB_OBJS += $(OUTPUT)util/pmu-bison.o 383 366 LIB_OBJS += $(OUTPUT)util/trace-event-read.o 384 367 LIB_OBJS += $(OUTPUT)util/trace-event-info.o 385 368 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o ··· 523 498 LIB_H += util/ui/progress.h 524 499 LIB_H += util/ui/util.h 525 500 LIB_H += util/ui/ui.h 501 + endif 502 + endif 503 + 504 + ifdef NO_GTK2 505 + BASIC_CFLAGS += -DNO_GTK2 506 + else 507 + FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0) 508 + ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) 509 + msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 510 + BASIC_CFLAGS += -DNO_GTK2_SUPPORT 511 + else 512 + BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0) 513 + EXTLIBS += $(shell pkg-config --libs gtk+-2.0) 514 + LIB_OBJS += $(OUTPUT)util/gtk/browser.o 526 515 endif 527 516 endif 528 517 ··· 686 647 QUIET_LINK = @echo ' ' LINK $@; 687 648 QUIET_MKDIR = @echo ' ' MKDIR $@; 688 649 QUIET_GEN = @echo ' ' GEN $@; 650 + QUIET_FLEX = @echo ' ' FLEX $@; 651 + QUIET_BISON = @echo ' ' BISON $@; 689 652 endif 690 653 endif 691 654 ··· 768 727 $(SCRIPTS) \ 769 728 : $(OUTPUT)PERF-VERSION-FILE 770 729 730 + .SUFFIXES: 731 + .SUFFIXES: .o .c .S .s 732 + 733 + # These two need to be here so that when O= is not used they take precedence 734 + # over the general rule for .o 735 + 736 + $(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS 737 + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $< 738 + 739 + $(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS 740 + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $< 741 + 771 742 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 772 743 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 744 + $(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS 745 + $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< 773 746 $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS 774 - $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 747 + $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $< 775 748 $(OUTPUT)%.o: %.S 776 749 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 750 + $(OUTPUT)%.s: %.S 751 + $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< 777 752 778 753 $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 779 754 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ ··· 852 795 @echo ' html - make html documentation' 853 796 @echo ' info - make GNU info documentation (access with info <foo>)' 854 797 @echo ' pdf - make pdf documentation' 798 + @echo ' event-parser - make event parser code' 799 + @echo ' pmu-parser - make pmu format parser code' 855 800 @echo ' TAGS - use etags to make tag information for source browsing' 856 801 @echo ' tags - use ctags to make tag information for source browsing' 857 802 @echo ' cscope - use cscope to make interactive browsing database' ··· 990 931 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 991 932 $(MAKE) -C Documentation/ clean 992 933 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS 934 + $(RM) $(OUTPUT)util/*-{bison,flex}* 993 935 $(python-clean) 994 936 995 937 .PHONY: all install clean strip
+35 -25
tools/perf/builtin-diff.c
··· 24 24 static bool force; 25 25 static bool show_displacement; 26 26 27 + struct perf_diff { 28 + struct perf_tool tool; 29 + struct perf_session *session; 30 + }; 31 + 27 32 static int hists__add_entry(struct hists *self, 28 33 struct addr_location *al, u64 period) 29 34 { ··· 37 32 return -ENOMEM; 38 33 } 39 34 40 - static int diff__process_sample_event(struct perf_tool *tool __used, 35 + static int diff__process_sample_event(struct perf_tool *tool, 41 36 union perf_event *event, 42 37 struct perf_sample *sample, 43 38 struct perf_evsel *evsel __used, 44 39 struct machine *machine) 45 40 { 41 + struct perf_diff *_diff = container_of(tool, struct perf_diff, tool); 42 + struct perf_session *session = _diff->session; 46 43 struct addr_location al; 47 44 48 45 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { ··· 56 49 if (al.filtered || al.sym == NULL) 57 50 return 0; 58 51 59 - if (hists__add_entry(&evsel->hists, &al, sample->period)) { 52 + if (hists__add_entry(&session->hists, &al, sample->period)) { 60 53 pr_warning("problem incrementing symbol period, skipping event\n"); 61 54 return -1; 62 55 } 63 56 64 - evsel->hists.stats.total_period += sample->period; 57 + session->hists.stats.total_period += sample->period; 65 58 return 0; 66 59 } 67 60 68 - static struct perf_tool perf_diff = { 69 - .sample = diff__process_sample_event, 70 - .mmap = perf_event__process_mmap, 71 - .comm = perf_event__process_comm, 72 - .exit = perf_event__process_task, 73 - .fork = perf_event__process_task, 74 - .lost = perf_event__process_lost, 75 - .ordered_samples = true, 76 - .ordering_requires_timestamps = true, 61 + static struct perf_diff diff = { 62 + .tool = { 63 + .sample = diff__process_sample_event, 64 + .mmap = perf_event__process_mmap, 65 + .comm = perf_event__process_comm, 66 + .exit = perf_event__process_task, 67 + .fork = perf_event__process_task, 68 + .lost = perf_event__process_lost, 69 + .ordered_samples = true, 70 + .ordering_requires_timestamps = true, 71 + }, 77 72 }; 78 73 79 74 static void perf_session__insert_hist_entry_by_name(struct rb_root *root, ··· 116 107 self->entries = tmp; 117 108 } 118 109 119 - static void hists__set_positions(struct hists *self) 120 - { 121 - hists__output_resort(self); 122 - hists__resort_entries(self); 123 - } 124 - 125 110 static struct hist_entry *hists__find_entry(struct hists *self, 126 111 struct hist_entry *he) 127 112 { ··· 149 146 static int __cmd_diff(void) 150 147 { 151 148 int ret, i; 149 + #define older (session[0]) 150 + #define newer (session[1]) 152 151 struct perf_session *session[2]; 153 152 154 - session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff); 155 - session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff); 153 + older = perf_session__new(input_old, O_RDONLY, force, false, 154 + &diff.tool); 155 + newer = perf_session__new(input_new, O_RDONLY, force, false, 156 + &diff.tool); 156 157 if (session[0] == NULL || session[1] == NULL) 157 158 return -ENOMEM; 158 159 159 160 for (i = 0; i < 2; ++i) { 160 - ret = perf_session__process_events(session[i], &perf_diff); 161 + diff.session = session[i]; 162 + ret = perf_session__process_events(session[i], &diff.tool); 161 163 if (ret) 162 164 goto out_delete; 165 + hists__output_resort(&session[i]->hists); 163 166 } 164 167 165 - hists__output_resort(&session[1]->hists); 166 168 if (show_displacement) 167 - hists__set_positions(&session[0]->hists); 169 + hists__resort_entries(&older->hists); 168 170 169 - hists__match(&session[0]->hists, &session[1]->hists); 170 - hists__fprintf(&session[1]->hists, &session[0]->hists, 171 + hists__match(&older->hists, &newer->hists); 172 + hists__fprintf(&newer->hists, &older->hists, 171 173 show_displacement, true, 0, 0, stdout); 172 174 out_delete: 173 175 for (i = 0; i < 2; ++i) 174 176 perf_session__delete(session[i]); 175 177 return ret; 178 + #undef older 179 + #undef newer 176 180 } 177 181 178 182 static const char * const diff_usage[] = {
+31 -9
tools/perf/builtin-report.c
··· 40 40 struct perf_tool tool; 41 41 struct perf_session *session; 42 42 char const *input_name; 43 - bool force, use_tui, use_stdio; 43 + bool force, use_tui, use_gtk, use_stdio; 44 44 bool hide_unresolved; 45 45 bool dont_use_callchains; 46 46 bool show_full_info; ··· 50 50 const char *pretty_printing_style; 51 51 symbol_filter_t annotate_init; 52 52 const char *cpu_list; 53 + const char *symbol_filter_str; 53 54 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 54 55 }; 55 56 ··· 401 400 list_for_each_entry(pos, &session->evlist->entries, node) { 402 401 struct hists *hists = &pos->hists; 403 402 403 + if (pos->idx == 0) 404 + hists->symbol_filter_str = rep->symbol_filter_str; 405 + 404 406 hists__collapse_resort(hists); 405 407 hists__output_resort(hists); 406 408 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; ··· 415 411 } 416 412 417 413 if (use_browser > 0) { 418 - perf_evlist__tui_browse_hists(session->evlist, help, 419 - NULL, NULL, 0); 414 + if (use_browser == 1) { 415 + perf_evlist__tui_browse_hists(session->evlist, help, 416 + NULL, NULL, 0); 417 + } else if (use_browser == 2) { 418 + perf_evlist__gtk_browse_hists(session->evlist, help, 419 + NULL, NULL, 0); 420 + } 420 421 } else 421 422 perf_evlist__tty_browse_hists(session->evlist, rep, help); 422 423 ··· 578 569 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key", 579 570 "pretty printing style key: normal raw"), 580 571 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"), 572 + OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), 581 573 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 582 574 "Use the stdio interface"), 583 575 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", ··· 601 591 "only consider symbols in these comms"), 602 592 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 603 593 "only consider these symbols"), 594 + OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter", 595 + "only show symbols that (partially) match with this filter"), 604 596 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, 605 597 "width[,width...]", 606 598 "don't try to adjust column width, use these fixed values"), ··· 636 624 use_browser = 0; 637 625 else if (report.use_tui) 638 626 use_browser = 1; 627 + else if (report.use_gtk) 628 + use_browser = 2; 639 629 640 630 if (report.inverted_callchain) 641 631 callchain_param.order = ORDER_CALLER; ··· 674 660 } 675 661 676 662 if (strcmp(report.input_name, "-") != 0) { 677 - setup_browser(true); 663 + if (report.use_gtk) 664 + perf_gtk_setup_browser(argc, argv, true); 665 + else 666 + setup_browser(true); 678 667 } else { 679 668 use_browser = 0; 680 669 } ··· 726 709 } else 727 710 symbol_conf.exclude_other = false; 728 711 729 - /* 730 - * Any (unrecognized) arguments left? 731 - */ 732 - if (argc) 733 - usage_with_options(report_usage, options); 712 + if (argc) { 713 + /* 714 + * Special case: if there's an argument left then assume that 715 + * it's a symbol filter: 716 + */ 717 + if (argc > 1) 718 + usage_with_options(report_usage, options); 719 + 720 + report.symbol_filter_str = argv[0]; 721 + } 734 722 735 723 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 736 724
+1 -1
tools/perf/builtin-stat.c
··· 296 296 if (system_wide) 297 297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, 298 298 group, group_fd); 299 - if (!target_pid && !target_tid) { 299 + if (!target_pid && !target_tid && (!group || evsel == first)) { 300 300 attr->disabled = 1; 301 301 attr->enable_on_exec = 1; 302 302 }
+169 -5
tools/perf/builtin-test.c
··· 13 13 #include "util/parse-events.h" 14 14 #include "util/symbol.h" 15 15 #include "util/thread_map.h" 16 + #include "util/pmu.h" 16 17 #include "../../include/linux/hw_breakpoint.h" 17 18 18 19 #include <sys/mman.h> ··· 651 650 652 651 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 653 652 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 654 - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); 653 + TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config); 655 654 return 0; 656 655 } 657 656 ··· 675 674 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); 676 675 TEST_ASSERT_VAL("wrong config", 677 676 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); 677 + return 0; 678 + } 679 + 680 + static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist) 681 + { 682 + struct perf_evsel *evsel = list_entry(evlist->entries.next, 683 + struct perf_evsel, node); 684 + 685 + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 686 + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); 687 + TEST_ASSERT_VAL("wrong config", 688 + PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); 689 + TEST_ASSERT_VAL("wrong period", 690 + 100000 == evsel->attr.sample_period); 691 + TEST_ASSERT_VAL("wrong config1", 692 + 0 == evsel->attr.config1); 693 + TEST_ASSERT_VAL("wrong config2", 694 + 1 == evsel->attr.config2); 678 695 return 0; 679 696 } 680 697 ··· 877 858 return test__checkevent_genhw(evlist); 878 859 } 879 860 861 + static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) 862 + { 863 + struct perf_evsel *evsel = list_entry(evlist->entries.next, 864 + struct perf_evsel, node); 865 + 866 + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); 867 + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); 868 + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 869 + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 870 + 871 + return test__checkevent_breakpoint(evlist); 872 + } 873 + 874 + static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) 875 + { 876 + struct perf_evsel *evsel = list_entry(evlist->entries.next, 877 + struct perf_evsel, node); 878 + 879 + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); 880 + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); 881 + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 882 + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 883 + 884 + return test__checkevent_breakpoint_x(evlist); 885 + } 886 + 887 + static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) 888 + { 889 + struct perf_evsel *evsel = list_entry(evlist->entries.next, 890 + struct perf_evsel, node); 891 + 892 + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); 893 + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); 894 + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); 895 + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); 896 + 897 + return test__checkevent_breakpoint_r(evlist); 898 + } 899 + 900 + static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) 901 + { 902 + struct perf_evsel *evsel = list_entry(evlist->entries.next, 903 + struct perf_evsel, node); 904 + 905 + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); 906 + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); 907 + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 908 + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); 909 + 910 + return test__checkevent_breakpoint_w(evlist); 911 + } 912 + 913 + static int test__checkevent_pmu(struct perf_evlist *evlist) 914 + { 915 + 916 + struct perf_evsel *evsel = list_entry(evlist->entries.next, 917 + struct perf_evsel, node); 918 + 919 + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 920 + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 921 + TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config); 922 + TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1); 923 + TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2); 924 + TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period); 925 + 926 + return 0; 927 + } 928 + 929 + static int test__checkevent_list(struct perf_evlist *evlist) 930 + { 931 + struct perf_evsel *evsel; 932 + 933 + TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); 934 + 935 + /* r1 */ 936 + evsel = list_entry(evlist->entries.next, struct perf_evsel, node); 937 + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 938 + TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); 939 + TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); 940 + TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2); 941 + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); 942 + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); 943 + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); 944 + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 945 + 946 + /* syscalls:sys_enter_open:k */ 947 + evsel = list_entry(evsel->node.next, struct perf_evsel, node); 948 + TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); 949 + TEST_ASSERT_VAL("wrong sample_type", 950 + (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == 951 + evsel->attr.sample_type); 952 + TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); 953 + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); 954 + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); 955 + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 956 + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 957 + 958 + /* 1:1:hp */ 959 + evsel = list_entry(evsel->node.next, struct perf_evsel, node); 960 + TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); 961 + TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); 962 + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); 963 + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); 964 + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); 965 + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); 966 + 967 + return 0; 968 + } 969 + 880 970 static struct test__event_st { 881 971 const char *name; 882 972 __u32 type; ··· 1000 872 .check = test__checkevent_tracepoint_multi, 1001 873 }, 1002 874 { 1003 - .name = "r1", 875 + .name = "r1a", 1004 876 .check = test__checkevent_raw, 1005 877 }, 1006 878 { ··· 1010 882 { 1011 883 .name = "instructions", 1012 884 .check = test__checkevent_symbolic_name, 885 + }, 886 + { 887 + .name = "cycles/period=100000,config2/", 888 + .check = test__checkevent_symbolic_name_config, 1013 889 }, 1014 890 { 1015 891 .name = "faults", ··· 1048 916 .check = test__checkevent_tracepoint_multi_modifier, 1049 917 }, 1050 918 { 1051 - .name = "r1:kp", 919 + .name = "r1a:kp", 1052 920 .check = test__checkevent_raw_modifier, 1053 921 }, 1054 922 { ··· 1066 934 { 1067 935 .name = "L1-dcache-load-miss:kp", 1068 936 .check = test__checkevent_genhw_modifier, 937 + }, 938 + { 939 + .name = "mem:0:u", 940 + .check = test__checkevent_breakpoint_modifier, 941 + }, 942 + { 943 + .name = "mem:0:x:k", 944 + .check = test__checkevent_breakpoint_x_modifier, 945 + }, 946 + { 947 + .name = "mem:0:r:hp", 948 + .check = test__checkevent_breakpoint_r_modifier, 949 + }, 950 + { 951 + .name = "mem:0:w:up", 952 + .check = test__checkevent_breakpoint_w_modifier, 953 + }, 954 + { 955 + .name = "cpu/config=10,config1,config2=3,period=1000/u", 956 + .check = test__checkevent_pmu, 957 + }, 958 + { 959 + .name = "r1,syscalls:sys_enter_open:k,1:1:hp", 960 + .check = test__checkevent_list, 1069 961 }, 1070 962 }; 1071 963 ··· 1116 960 } 1117 961 1118 962 ret = e->check(evlist); 963 + perf_evlist__delete(evlist); 1119 964 if (ret) 1120 965 break; 1121 - 1122 - perf_evlist__delete(evlist); 1123 966 } 1124 967 1125 968 return ret; ··· 1617 1462 1618 1463 #endif 1619 1464 1465 + static int test__perf_pmu(void) 1466 + { 1467 + return perf_pmu__test(); 1468 + } 1469 + 1620 1470 static struct test { 1621 1471 const char *desc; 1622 1472 int (*func)(void); ··· 1655 1495 { 1656 1496 .desc = "Validate PERF_RECORD_* events & perf_sample fields", 1657 1497 .func = test__PERF_RECORD, 1498 + }, 1499 + { 1500 + .desc = "Test perf pmu format parsing", 1501 + .func = test__perf_pmu, 1658 1502 }, 1659 1503 { 1660 1504 .func = NULL,
+15
tools/perf/config/feature-tests.mak
··· 65 65 endef 66 66 endif 67 67 68 + ifndef NO_GTK2 69 + define SOURCE_GTK2 70 + #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" 71 + #include <gtk/gtk.h> 72 + #pragma GCC diagnostic error \"-Wstrict-prototypes\" 73 + 74 + int main(int argc, char *argv[]) 75 + { 76 + gtk_init(&argc, &argv); 77 + 78 + return 0; 79 + } 80 + endef 81 + endif 82 + 68 83 ifndef NO_LIBPERL 69 84 define SOURCE_PERL_EMBED 70 85 #include <EXTERN.h>
+4 -4
tools/perf/util/annotate.c
··· 28 28 int symbol__alloc_hist(struct symbol *sym) 29 29 { 30 30 struct annotation *notes = symbol__annotation(sym); 31 - size_t sizeof_sym_hist = (sizeof(struct sym_hist) + 32 - (sym->end - sym->start) * sizeof(u64)); 31 + const size_t size = sym->end - sym->start + 1; 32 + size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); 33 33 34 34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 35 35 if (notes->src == NULL) ··· 64 64 65 65 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 66 66 67 - if (addr >= sym->end) 67 + if (addr > sym->end) 68 68 return 0; 69 69 70 70 offset = addr - sym->start; ··· 408 408 if (!notes->src->lines) 409 409 return -1; 410 410 411 - start = map->unmap_ip(map, sym->start); 411 + start = map__rip_2objdump(map, sym->start); 412 412 413 413 for (i = 0; i < len; i++) { 414 414 char *path = NULL;
+12
tools/perf/util/cache.h
··· 45 45 void exit_browser(bool wait_for_ok); 46 46 #endif 47 47 48 + #ifdef NO_GTK2_SUPPORT 49 + static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager) 50 + { 51 + if (fallback_to_pager) 52 + setup_pager(); 53 + } 54 + static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {} 55 + #else 56 + void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager); 57 + void perf_gtk_exit_browser(bool wait_for_ok); 58 + #endif 59 + 48 60 char *alias_lookup(const char *alias); 49 61 int split_cmdline(char *cmdline, const char ***argv); 50 62
+4 -2
tools/perf/util/evlist.c
··· 51 51 void perf_evlist__config_attrs(struct perf_evlist *evlist, 52 52 struct perf_record_opts *opts) 53 53 { 54 - struct perf_evsel *evsel; 54 + struct perf_evsel *evsel, *first; 55 55 56 56 if (evlist->cpus->map[0] < 0) 57 57 opts->no_inherit = true; 58 58 59 + first = list_entry(evlist->entries.next, struct perf_evsel, node); 60 + 59 61 list_for_each_entry(evsel, &evlist->entries, node) { 60 - perf_evsel__config(evsel, opts); 62 + perf_evsel__config(evsel, opts, first); 61 63 62 64 if (evlist->nr_entries > 1) 63 65 evsel->attr.sample_type |= PERF_SAMPLE_ID;
+7 -3
tools/perf/util/evsel.c
··· 34 34 return size; 35 35 } 36 36 37 - static void hists__init(struct hists *hists) 37 + void hists__init(struct hists *hists) 38 38 { 39 39 memset(hists, 0, sizeof(*hists)); 40 40 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; ··· 63 63 return evsel; 64 64 } 65 65 66 - void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) 66 + void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 67 + struct perf_evsel *first) 67 68 { 68 69 struct perf_event_attr *attr = &evsel->attr; 69 70 int track = !evsel->idx; /* only the first counter needs these */ ··· 135 134 attr->mmap = track; 136 135 attr->comm = track; 137 136 138 - if (!opts->target_pid && !opts->target_tid && !opts->system_wide) { 137 + if (!opts->target_pid && !opts->target_tid && !opts->system_wide && 138 + (!opts->group || evsel == first)) { 139 139 attr->disabled = 1; 140 140 attr->enable_on_exec = 1; 141 141 } ··· 580 578 return -EFAULT; 581 579 582 580 data->raw_data = (void *) pdata; 581 + 582 + array = (void *)array + data->raw_size + sizeof(u32); 583 583 } 584 584 585 585 if (type & PERF_SAMPLE_BRANCH_STACK) {
+4 -1
tools/perf/util/evsel.h
··· 80 80 void perf_evsel__delete(struct perf_evsel *evsel); 81 81 82 82 void perf_evsel__config(struct perf_evsel *evsel, 83 - struct perf_record_opts *opts); 83 + struct perf_record_opts *opts, 84 + struct perf_evsel *first); 84 85 85 86 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 86 87 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); ··· 169 168 { 170 169 return __perf_evsel__sample_size(evsel->attr.sample_type); 171 170 } 171 + 172 + void hists__init(struct hists *hists); 172 173 173 174 #endif /* __PERF_EVSEL_H */
+189
tools/perf/util/gtk/browser.c
··· 1 + #include "../evlist.h" 2 + #include "../cache.h" 3 + #include "../evsel.h" 4 + #include "../sort.h" 5 + #include "../hist.h" 6 + #include "gtk.h" 7 + 8 + #include <signal.h> 9 + 10 + #define MAX_COLUMNS 32 11 + 12 + void perf_gtk_setup_browser(int argc, const char *argv[], 13 + bool fallback_to_pager __used) 14 + { 15 + gtk_init(&argc, (char ***)&argv); 16 + } 17 + 18 + void perf_gtk_exit_browser(bool wait_for_ok __used) 19 + { 20 + gtk_main_quit(); 21 + } 22 + 23 + static void perf_gtk_signal(int sig) 24 + { 25 + psignal(sig, "perf"); 26 + gtk_main_quit(); 27 + } 28 + 29 + static void perf_gtk_resize_window(GtkWidget *window) 30 + { 31 + GdkRectangle rect; 32 + GdkScreen *screen; 33 + int monitor; 34 + int height; 35 + int width; 36 + 37 + screen = gtk_widget_get_screen(window); 38 + 39 + monitor = gdk_screen_get_monitor_at_window(screen, window->window); 40 + 41 + gdk_screen_get_monitor_geometry(screen, monitor, &rect); 42 + 43 + width = rect.width * 3 / 4; 44 + height = rect.height * 3 / 4; 45 + 46 + gtk_window_resize(GTK_WINDOW(window), width, height); 47 + } 48 + 49 + static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists) 50 + { 51 + GType col_types[MAX_COLUMNS]; 52 + GtkCellRenderer *renderer; 53 + struct sort_entry *se; 54 + GtkListStore *store; 55 + struct rb_node *nd; 56 + u64 total_period; 57 + GtkWidget *view; 58 + int col_idx; 59 + int nr_cols; 60 + 61 + nr_cols = 0; 62 + 63 + /* The percentage column */ 64 + col_types[nr_cols++] = G_TYPE_STRING; 65 + 66 + list_for_each_entry(se, &hist_entry__sort_list, list) { 67 + if (se->elide) 68 + continue; 69 + 70 + col_types[nr_cols++] = G_TYPE_STRING; 71 + } 72 + 73 + store = gtk_list_store_newv(nr_cols, col_types); 74 + 75 + view = gtk_tree_view_new(); 76 + 77 + renderer = gtk_cell_renderer_text_new(); 78 + 79 + col_idx = 0; 80 + 81 + /* The percentage column */ 82 + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 83 + -1, "Overhead (%)", 84 + renderer, "text", 85 + col_idx++, NULL); 86 + 87 + list_for_each_entry(se, &hist_entry__sort_list, list) { 88 + if (se->elide) 89 + continue; 90 + 91 + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 92 + -1, se->se_header, 93 + renderer, "text", 94 + col_idx++, NULL); 95 + } 96 + 97 + gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); 98 + 99 + g_object_unref(GTK_TREE_MODEL(store)); 100 + 101 + total_period = hists->stats.total_period; 102 + 103 + for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 104 + struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 105 + GtkTreeIter iter; 106 + double percent; 107 + char s[512]; 108 + 109 + if (h->filtered) 110 + continue; 111 + 112 + gtk_list_store_append(store, &iter); 113 + 114 + col_idx = 0; 115 + 116 + percent = (h->period * 100.0) / total_period; 117 + 118 + snprintf(s, ARRAY_SIZE(s), "%.2f", percent); 119 + 120 + gtk_list_store_set(store, &iter, col_idx++, s, -1); 121 + 122 + list_for_each_entry(se, &hist_entry__sort_list, list) { 123 + if (se->elide) 124 + continue; 125 + 126 + se->se_snprintf(h, s, ARRAY_SIZE(s), 127 + hists__col_len(hists, se->se_width_idx)); 128 + 129 + gtk_list_store_set(store, &iter, col_idx++, s, -1); 130 + } 131 + } 132 + 133 + gtk_container_add(GTK_CONTAINER(window), view); 134 + } 135 + 136 + int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 137 + const char *help __used, 138 + void (*timer) (void *arg)__used, 139 + void *arg __used, int delay_secs __used) 140 + { 141 + struct perf_evsel *pos; 142 + GtkWidget *notebook; 143 + GtkWidget *window; 144 + 145 + signal(SIGSEGV, perf_gtk_signal); 146 + signal(SIGFPE, perf_gtk_signal); 147 + signal(SIGINT, perf_gtk_signal); 148 + signal(SIGQUIT, perf_gtk_signal); 149 + signal(SIGTERM, perf_gtk_signal); 150 + 151 + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 152 + 153 + gtk_window_set_title(GTK_WINDOW(window), "perf report"); 154 + 155 + g_signal_connect(window, "delete_event", gtk_main_quit, NULL); 156 + 157 + notebook = gtk_notebook_new(); 158 + 159 + list_for_each_entry(pos, &evlist->entries, node) { 160 + struct hists *hists = &pos->hists; 161 + const char *evname = event_name(pos); 162 + GtkWidget *scrolled_window; 163 + GtkWidget *tab_label; 164 + 165 + scrolled_window = gtk_scrolled_window_new(NULL, NULL); 166 + 167 + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 168 + GTK_POLICY_AUTOMATIC, 169 + GTK_POLICY_AUTOMATIC); 170 + 171 + perf_gtk_show_hists(scrolled_window, hists); 172 + 173 + tab_label = gtk_label_new(evname); 174 + 175 + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); 176 + } 177 + 178 + gtk_container_add(GTK_CONTAINER(window), notebook); 179 + 180 + gtk_widget_show_all(window); 181 + 182 + perf_gtk_resize_window(window); 183 + 184 + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); 185 + 186 + gtk_main(); 187 + 188 + return 0; 189 + }
+8
tools/perf/util/gtk/gtk.h
··· 1 + #ifndef _PERF_GTK_H_ 2 + #define _PERF_GTK_H_ 1 3 + 4 + #pragma GCC diagnostic ignored "-Wstrict-prototypes" 5 + #include <gtk/gtk.h> 6 + #pragma GCC diagnostic error "-Wstrict-prototypes" 7 + 8 + #endif /* _PERF_GTK_H_ */
+1 -1
tools/perf/util/header.c
··· 1177 1177 goto error; 1178 1178 1179 1179 msz = sizeof(attr); 1180 - if (sz < (ssize_t)msz) 1180 + if (sz < msz) 1181 1181 msz = sz; 1182 1182 1183 1183 for (i = 0 ; i < nre; i++) {
+132 -68
tools/perf/util/hist.c
··· 10 10 struct hist_entry *he); 11 11 static bool hists__filter_entry_by_thread(struct hists *hists, 12 12 struct hist_entry *he); 13 + static bool hists__filter_entry_by_symbol(struct hists *hists, 14 + struct hist_entry *he); 13 15 14 16 enum hist_filter { 15 17 HIST_FILTER__DSO, 16 18 HIST_FILTER__THREAD, 17 19 HIST_FILTER__PARENT, 20 + HIST_FILTER__SYMBOL, 18 21 }; 19 22 20 23 struct callchain_param callchain_param = { ··· 423 420 { 424 421 hists__filter_entry_by_dso(hists, he); 425 422 hists__filter_entry_by_thread(hists, he); 423 + hists__filter_entry_by_symbol(hists, he); 426 424 } 427 425 428 426 static void __hists__collapse_resort(struct hists *hists, bool threaded) ··· 607 603 rem_hits.ms.sym = rem_sq_bracket; 608 604 } 609 605 610 - static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 606 + static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, 611 607 u64 total_samples, int depth, 612 608 int depth_mask, int left_margin) 613 609 { ··· 615 611 struct callchain_node *child; 616 612 struct callchain_list *chain; 617 613 int new_depth_mask = depth_mask; 618 - u64 new_total; 619 614 u64 remaining; 620 615 size_t ret = 0; 621 616 int i; 622 617 uint entries_printed = 0; 623 618 624 - if (callchain_param.mode == CHAIN_GRAPH_REL) 625 - new_total = self->children_hit; 626 - else 627 - new_total = total_samples; 619 + remaining = total_samples; 628 620 629 - remaining = new_total; 630 - 631 - node = rb_first(&self->rb_root); 621 + node = rb_first(root); 632 622 while (node) { 623 + u64 new_total; 633 624 u64 cumul; 634 625 635 626 child = rb_entry(node, struct callchain_node, rb_node); ··· 652 653 list_for_each_entry(chain, &child->val, list) { 653 654 ret += ipchain__fprintf_graph(fp, chain, depth, 654 655 new_depth_mask, i++, 655 - new_total, 656 + total_samples, 656 657 cumul, 657 658 left_margin); 658 659 } 659 - ret += __callchain__fprintf_graph(fp, child, new_total, 660 + 661 + if (callchain_param.mode == CHAIN_GRAPH_REL) 662 + new_total = child->children_hit; 663 + else 664 + new_total = total_samples; 665 + 666 + ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total, 660 667 depth + 1, 661 668 new_depth_mask | (1 << depth), 662 669 left_margin); ··· 672 667 } 673 668 674 669 if (callchain_param.mode == CHAIN_GRAPH_REL && 675 - remaining && remaining != new_total) { 670 + remaining && remaining != total_samples) { 676 671 677 672 if (!rem_sq_bracket) 678 673 return ret; 679 674 680 675 new_depth_mask &= ~(1 << (depth - 1)); 681 - 682 676 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 683 - new_depth_mask, 0, new_total, 677 + new_depth_mask, 0, total_samples, 684 678 remaining, left_margin); 685 679 } 686 680 687 681 return ret; 688 682 } 689 683 690 - static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 684 + static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 691 685 u64 total_samples, int left_margin) 692 686 { 687 + struct callchain_node *cnode; 693 688 struct callchain_list *chain; 694 - bool printed = false; 695 - int i = 0; 696 - int ret = 0; 697 689 u32 entries_printed = 0; 690 + bool printed = false; 691 + struct rb_node *node; 692 + int i = 0; 693 + int ret; 698 694 699 - list_for_each_entry(chain, &self->val, list) { 700 - if (!i++ && sort__first_dimension == SORT_SYM) 701 - continue; 695 + /* 696 + * If have one single callchain root, don't bother printing 697 + * its percentage (100 % in fractal mode and the same percentage 698 + * than the hist in graph mode). This also avoid one level of column. 699 + */ 700 + node = rb_first(root); 701 + if (node && !rb_next(node)) { 702 + cnode = rb_entry(node, struct callchain_node, rb_node); 703 + list_for_each_entry(chain, &cnode->val, list) { 704 + /* 705 + * If we sort by symbol, the first entry is the same than 706 + * the symbol. No need to print it otherwise it appears as 707 + * displayed twice. 708 + */ 709 + if (!i++ && sort__first_dimension == SORT_SYM) 710 + continue; 711 + if (!printed) { 712 + ret += callchain__fprintf_left_margin(fp, left_margin); 713 + ret += fprintf(fp, "|\n"); 714 + ret += callchain__fprintf_left_margin(fp, left_margin); 715 + ret += fprintf(fp, "---"); 716 + left_margin += 3; 717 + printed = true; 718 + } else 719 + ret += callchain__fprintf_left_margin(fp, left_margin); 702 720 703 - if (!printed) { 704 - ret += callchain__fprintf_left_margin(fp, left_margin); 705 - ret += fprintf(fp, "|\n"); 706 - ret += callchain__fprintf_left_margin(fp, left_margin); 707 - ret += fprintf(fp, "---"); 721 + if (chain->ms.sym) 722 + ret += fprintf(fp, " %s\n", chain->ms.sym->name); 723 + else 724 + ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 708 725 709 - left_margin += 3; 710 - printed = true; 711 - } else 712 - ret += callchain__fprintf_left_margin(fp, left_margin); 713 - 714 - if (chain->ms.sym) 715 - ret += fprintf(fp, " %s\n", chain->ms.sym->name); 716 - else 717 - ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 718 - 719 - if (++entries_printed == callchain_param.print_limit) 720 - break; 726 + if (++entries_printed == callchain_param.print_limit) 727 + break; 728 + } 729 + root = &cnode->rb_root; 721 730 } 722 731 723 - ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 724 - 725 - return ret; 732 + return __callchain__fprintf_graph(fp, root, total_samples, 733 + 1, 1, left_margin); 726 734 } 727 735 728 - static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 729 - u64 total_samples) 736 + static size_t __callchain__fprintf_flat(FILE *fp, 737 + struct callchain_node *self, 738 + u64 total_samples) 730 739 { 731 740 struct callchain_list *chain; 732 741 size_t ret = 0; ··· 748 729 if (!self) 749 730 return 0; 750 731 751 - ret += callchain__fprintf_flat(fp, self->parent, total_samples); 732 + ret += __callchain__fprintf_flat(fp, self->parent, total_samples); 752 733 753 734 754 735 list_for_each_entry(chain, &self->val, list) { ··· 764 745 return ret; 765 746 } 766 747 767 - static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 768 - u64 total_samples, int left_margin, 769 - FILE *fp) 748 + static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self, 749 + u64 total_samples) 770 750 { 771 - struct rb_node *rb_node; 772 - struct callchain_node *chain; 773 751 size_t ret = 0; 774 752 u32 entries_printed = 0; 753 + struct rb_node *rb_node; 754 + struct callchain_node *chain; 775 755 776 - rb_node = rb_first(&he->sorted_chain); 756 + rb_node = rb_first(self); 777 757 while (rb_node) { 778 758 double percent; 779 759 780 760 chain = rb_entry(rb_node, struct callchain_node, rb_node); 781 761 percent = chain->hit * 100.0 / total_samples; 782 - switch (callchain_param.mode) { 783 - case CHAIN_FLAT: 784 - ret += percent_color_fprintf(fp, " %6.2f%%\n", 785 - percent); 786 - ret += callchain__fprintf_flat(fp, chain, total_samples); 787 - break; 788 - case CHAIN_GRAPH_ABS: /* Falldown */ 789 - case CHAIN_GRAPH_REL: 790 - ret += callchain__fprintf_graph(fp, chain, total_samples, 791 - left_margin); 792 - case CHAIN_NONE: 793 - default: 794 - break; 795 - } 762 + 763 + ret = percent_color_fprintf(fp, " %6.2f%%\n", percent); 764 + ret += __callchain__fprintf_flat(fp, chain, total_samples); 796 765 ret += fprintf(fp, "\n"); 797 766 if (++entries_printed == callchain_param.print_limit) 798 767 break; 768 + 799 769 rb_node = rb_next(rb_node); 800 770 } 801 771 802 772 return ret; 773 + } 774 + 775 + static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 776 + u64 total_samples, int left_margin, 777 + FILE *fp) 778 + { 779 + switch (callchain_param.mode) { 780 + case CHAIN_GRAPH_REL: 781 + return callchain__fprintf_graph(fp, &he->sorted_chain, he->period, 782 + left_margin); 783 + break; 784 + case CHAIN_GRAPH_ABS: 785 + return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 786 + left_margin); 787 + break; 788 + case CHAIN_FLAT: 789 + return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 790 + break; 791 + case CHAIN_NONE: 792 + break; 793 + default: 794 + pr_err("Bad callchain mode\n"); 795 + } 796 + 797 + return 0; 803 798 } 804 799 805 800 void hists__output_recalc_col_len(struct hists *hists, int max_rows) ··· 920 887 diff = new_percent - old_percent; 921 888 922 889 if (fabs(diff) >= 0.01) 923 - ret += scnprintf(bf, sizeof(bf), "%+4.2F%%", diff); 890 + scnprintf(bf, sizeof(bf), "%+4.2F%%", diff); 924 891 else 925 - ret += scnprintf(bf, sizeof(bf), " "); 892 + scnprintf(bf, sizeof(bf), " "); 926 893 927 894 if (sep) 928 895 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); ··· 931 898 932 899 if (show_displacement) { 933 900 if (displacement) 934 - ret += scnprintf(bf, sizeof(bf), "%+4ld", displacement); 901 + scnprintf(bf, sizeof(bf), "%+4ld", displacement); 935 902 else 936 - ret += scnprintf(bf, sizeof(bf), " "); 903 + scnprintf(bf, sizeof(bf), " "); 937 904 938 905 if (sep) 939 906 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); ··· 1277 1244 continue; 1278 1245 1279 1246 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD); 1247 + } 1248 + } 1249 + 1250 + static bool hists__filter_entry_by_symbol(struct hists *hists, 1251 + struct hist_entry *he) 1252 + { 1253 + if (hists->symbol_filter_str != NULL && 1254 + (!he->ms.sym || strstr(he->ms.sym->name, 1255 + hists->symbol_filter_str) == NULL)) { 1256 + he->filtered |= (1 << HIST_FILTER__SYMBOL); 1257 + return true; 1258 + } 1259 + 1260 + return false; 1261 + } 1262 + 1263 + void hists__filter_by_symbol(struct hists *hists) 1264 + { 1265 + struct rb_node *nd; 1266 + 1267 + hists->nr_entries = hists->stats.total_period = 0; 1268 + hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1269 + hists__reset_col_len(hists); 1270 + 1271 + for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1272 + struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1273 + 1274 + if (hists__filter_entry_by_symbol(hists, h)) 1275 + continue; 1276 + 1277 + hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL); 1280 1278 } 1281 1279 } 1282 1280
+19
tools/perf/util/hist.h
··· 62 62 const struct thread *thread_filter; 63 63 const struct dso *dso_filter; 64 64 const char *uid_filter_str; 65 + const char *symbol_filter_str; 65 66 pthread_mutex_t lock; 66 67 struct events_stats stats; 67 68 u64 event_stream; ··· 108 107 109 108 void hists__filter_by_dso(struct hists *hists); 110 109 void hists__filter_by_thread(struct hists *hists); 110 + void hists__filter_by_symbol(struct hists *hists); 111 111 112 112 u16 hists__col_len(struct hists *self, enum hist_column col); 113 113 void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); ··· 143 141 void(*timer)(void *arg), void *arg, int delay_secs); 144 142 145 143 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 144 + void(*timer)(void *arg), void *arg, 145 + int refresh); 146 + #endif 147 + 148 + #ifdef NO_GTK2_SUPPORT 149 + static inline 150 + int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __used, 151 + const char *help __used, 152 + void(*timer)(void *arg) __used, 153 + void *arg __used, 154 + int refresh __used) 155 + { 156 + return 0; 157 + } 158 + 159 + #else 160 + int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, 146 161 void(*timer)(void *arg), void *arg, 147 162 int refresh); 148 163 #endif
tools/perf/util/include/linux/module.h tools/perf/util/include/linux/export.h
+273 -326
tools/perf/util/parse-events.c
··· 11 11 #include "cache.h" 12 12 #include "header.h" 13 13 #include "debugfs.h" 14 + #include "parse-events-flex.h" 15 + #include "pmu.h" 16 + 17 + #define MAX_NAME_LEN 100 14 18 15 19 struct event_symbol { 16 20 u8 type; ··· 23 19 const char *alias; 24 20 }; 25 21 26 - enum event_result { 27 - EVT_FAILED, 28 - EVT_HANDLED, 29 - EVT_HANDLED_ALL 30 - }; 22 + int parse_events_parse(struct list_head *list, struct list_head *list_tmp, 23 + int *idx); 31 24 32 25 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 33 26 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x ··· 355 354 return "unknown"; 356 355 } 357 356 358 - static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size) 357 + static int add_event(struct list_head *list, int *idx, 358 + struct perf_event_attr *attr, char *name) 359 + { 360 + struct perf_evsel *evsel; 361 + 362 + event_attr_init(attr); 363 + 364 + evsel = perf_evsel__new(attr, (*idx)++); 365 + if (!evsel) 366 + return -ENOMEM; 367 + 368 + list_add_tail(&evsel->node, list); 369 + 370 + evsel->name = strdup(name); 371 + return 0; 372 + } 373 + 374 + static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size) 359 375 { 360 376 int i, j; 361 377 int n, longest = -1; ··· 380 362 for (i = 0; i < size; i++) { 381 363 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { 382 364 n = strlen(names[i][j]); 383 - if (n > longest && !strncasecmp(*str, names[i][j], n)) 365 + if (n > longest && !strncasecmp(str, names[i][j], n)) 384 366 longest = n; 385 367 } 386 - if (longest > 0) { 387 - *str += longest; 368 + if (longest > 0) 388 369 return i; 389 - } 390 370 } 391 371 392 372 return -1; 393 373 } 394 374 395 - static enum event_result 396 - parse_generic_hw_event(const char **str, struct perf_event_attr *attr) 375 + int parse_events_add_cache(struct list_head *list, int *idx, 376 + char *type, char *op_result1, char *op_result2) 397 377 { 398 - const char *s = *str; 378 + struct perf_event_attr attr; 379 + char name[MAX_NAME_LEN]; 399 380 int cache_type = -1, cache_op = -1, cache_result = -1; 381 + char *op_result[2] = { op_result1, op_result2 }; 382 + int i, n; 400 383 401 - cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX); 402 384 /* 403 385 * No fallback - if we cannot get a clear cache type 404 386 * then bail out: 405 387 */ 388 + cache_type = parse_aliases(type, hw_cache, 389 + PERF_COUNT_HW_CACHE_MAX); 406 390 if (cache_type == -1) 407 - return EVT_FAILED; 391 + return -EINVAL; 408 392 409 - while ((cache_op == -1 || cache_result == -1) && *s == '-') { 410 - ++s; 393 + n = snprintf(name, MAX_NAME_LEN, "%s", type); 394 + 395 + for (i = 0; (i < 2) && (op_result[i]); i++) { 396 + char *str = op_result[i]; 397 + 398 + snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); 411 399 412 400 if (cache_op == -1) { 413 - cache_op = parse_aliases(&s, hw_cache_op, 414 - PERF_COUNT_HW_CACHE_OP_MAX); 401 + cache_op = parse_aliases(str, hw_cache_op, 402 + PERF_COUNT_HW_CACHE_OP_MAX); 415 403 if (cache_op >= 0) { 416 404 if (!is_cache_op_valid(cache_type, cache_op)) 417 - return EVT_FAILED; 405 + return -EINVAL; 418 406 continue; 419 407 } 420 408 } 421 409 422 410 if (cache_result == -1) { 423 - cache_result = parse_aliases(&s, hw_cache_result, 411 + cache_result = parse_aliases(str, hw_cache_result, 424 412 PERF_COUNT_HW_CACHE_RESULT_MAX); 425 413 if (cache_result >= 0) 426 414 continue; 427 415 } 428 - 429 - /* 430 - * Can't parse this as a cache op or result, so back up 431 - * to the '-'. 432 - */ 433 - --s; 434 - break; 435 416 } 436 417 437 418 /* ··· 445 428 if (cache_result == -1) 446 429 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; 447 430 448 - attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 449 - attr->type = PERF_TYPE_HW_CACHE; 450 - 451 - *str = s; 452 - return EVT_HANDLED; 431 + memset(&attr, 0, sizeof(attr)); 432 + attr.config = cache_type | (cache_op << 8) | (cache_result << 16); 433 + attr.type = PERF_TYPE_HW_CACHE; 434 + return add_event(list, idx, &attr, name); 453 435 } 454 436 455 - static enum event_result 456 - parse_single_tracepoint_event(char *sys_name, 457 - const char *evt_name, 458 - unsigned int evt_length, 459 - struct perf_event_attr *attr, 460 - const char **strp) 437 + static int add_tracepoint(struct list_head *list, int *idx, 438 + char *sys_name, char *evt_name) 461 439 { 440 + struct perf_event_attr attr; 441 + char name[MAX_NAME_LEN]; 462 442 char evt_path[MAXPATHLEN]; 463 443 char id_buf[4]; 464 444 u64 id; ··· 466 452 467 453 fd = open(evt_path, O_RDONLY); 468 454 if (fd < 0) 469 - return EVT_FAILED; 455 + return -1; 470 456 471 457 if (read(fd, id_buf, sizeof(id_buf)) < 0) { 472 458 close(fd); 473 - return EVT_FAILED; 459 + return -1; 474 460 } 475 461 476 462 close(fd); 477 463 id = atoll(id_buf); 478 - attr->config = id; 479 - attr->type = PERF_TYPE_TRACEPOINT; 480 - *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */ 481 464 482 - attr->sample_type |= PERF_SAMPLE_RAW; 483 - attr->sample_type |= PERF_SAMPLE_TIME; 484 - attr->sample_type |= PERF_SAMPLE_CPU; 465 + memset(&attr, 0, sizeof(attr)); 466 + attr.config = id; 467 + attr.type = PERF_TYPE_TRACEPOINT; 468 + attr.sample_type |= PERF_SAMPLE_RAW; 469 + attr.sample_type |= PERF_SAMPLE_TIME; 470 + attr.sample_type |= PERF_SAMPLE_CPU; 471 + attr.sample_period = 1; 485 472 486 - attr->sample_period = 1; 487 - 488 - 489 - return EVT_HANDLED; 473 + snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); 474 + return add_event(list, idx, &attr, name); 490 475 } 491 476 492 - /* sys + ':' + event + ':' + flags*/ 493 - #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 494 - static enum event_result 495 - parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name, 496 - const char *evt_exp, char *flags) 477 + static int add_tracepoint_multi(struct list_head *list, int *idx, 478 + char *sys_name, char *evt_name) 497 479 { 498 480 char evt_path[MAXPATHLEN]; 499 481 struct dirent *evt_ent; 500 482 DIR *evt_dir; 483 + int ret = 0; 501 484 502 485 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); 503 486 evt_dir = opendir(evt_path); 504 - 505 487 if (!evt_dir) { 506 488 perror("Can't open event dir"); 507 - return EVT_FAILED; 489 + return -1; 508 490 } 509 491 510 - while ((evt_ent = readdir(evt_dir))) { 511 - char event_opt[MAX_EVOPT_LEN + 1]; 512 - int len; 513 - 492 + while (!ret && (evt_ent = readdir(evt_dir))) { 514 493 if (!strcmp(evt_ent->d_name, ".") 515 494 || !strcmp(evt_ent->d_name, "..") 516 495 || !strcmp(evt_ent->d_name, "enable") 517 496 || !strcmp(evt_ent->d_name, "filter")) 518 497 continue; 519 498 520 - if (!strglobmatch(evt_ent->d_name, evt_exp)) 499 + if (!strglobmatch(evt_ent->d_name, evt_name)) 521 500 continue; 522 501 523 - len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 524 - evt_ent->d_name, flags ? ":" : "", 525 - flags ?: ""); 526 - if (len < 0) 527 - return EVT_FAILED; 528 - 529 - if (parse_events(evlist, event_opt, 0)) 530 - return EVT_FAILED; 502 + ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); 531 503 } 532 504 533 - return EVT_HANDLED_ALL; 505 + return ret; 534 506 } 535 507 536 - static enum event_result 537 - parse_tracepoint_event(struct perf_evlist *evlist, const char **strp, 538 - struct perf_event_attr *attr) 508 + int parse_events_add_tracepoint(struct list_head *list, int *idx, 509 + char *sys, char *event) 539 510 { 540 - const char *evt_name; 541 - char *flags = NULL, *comma_loc; 542 - char sys_name[MAX_EVENT_LENGTH]; 543 - unsigned int sys_length, evt_length; 511 + int ret; 544 512 545 - if (debugfs_valid_mountpoint(tracing_events_path)) 546 - return 0; 513 + ret = debugfs_valid_mountpoint(tracing_events_path); 514 + if (ret) 515 + return ret; 547 516 548 - evt_name = strchr(*strp, ':'); 549 - if (!evt_name) 550 - return EVT_FAILED; 551 - 552 - sys_length = evt_name - *strp; 553 - if (sys_length >= MAX_EVENT_LENGTH) 554 - return 0; 555 - 556 - strncpy(sys_name, *strp, sys_length); 557 - sys_name[sys_length] = '\0'; 558 - evt_name = evt_name + 1; 559 - 560 - comma_loc = strchr(evt_name, ','); 561 - if (comma_loc) { 562 - /* take the event name up to the comma */ 563 - evt_name = strndup(evt_name, comma_loc - evt_name); 564 - } 565 - flags = strchr(evt_name, ':'); 566 - if (flags) { 567 - /* split it out: */ 568 - evt_name = strndup(evt_name, flags - evt_name); 569 - flags++; 570 - } 571 - 572 - evt_length = strlen(evt_name); 573 - if (evt_length >= MAX_EVENT_LENGTH) 574 - return EVT_FAILED; 575 - if (strpbrk(evt_name, "*?")) { 576 - *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ 577 - return parse_multiple_tracepoint_event(evlist, sys_name, 578 - evt_name, flags); 579 - } else { 580 - return parse_single_tracepoint_event(sys_name, evt_name, 581 - evt_length, attr, strp); 582 - } 517 + return strpbrk(event, "*?") ? 518 + add_tracepoint_multi(list, idx, sys, event) : 519 + add_tracepoint(list, idx, sys, event); 583 520 } 584 521 585 - static enum event_result 586 - parse_breakpoint_type(const char *type, const char **strp, 587 - struct perf_event_attr *attr) 522 + static int 523 + parse_breakpoint_type(const char *type, struct perf_event_attr *attr) 588 524 { 589 525 int i; 590 526 591 527 for (i = 0; i < 3; i++) { 592 - if (!type[i]) 528 + if (!type || !type[i]) 593 529 break; 594 530 595 531 switch (type[i]) { ··· 553 589 attr->bp_type |= HW_BREAKPOINT_X; 554 590 break; 555 591 default: 556 - return EVT_FAILED; 592 + return -EINVAL; 557 593 } 558 594 } 595 + 559 596 if (!attr->bp_type) /* Default */ 560 597 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; 561 598 562 - *strp = type + i; 563 - 564 - return EVT_HANDLED; 599 + return 0; 565 600 } 566 601 567 - static enum event_result 568 - parse_breakpoint_event(const char **strp, struct perf_event_attr *attr) 602 + int parse_events_add_breakpoint(struct list_head *list, int *idx, 603 + void *ptr, char *type) 569 604 { 570 - const char *target; 571 - const char *type; 572 - char *endaddr; 573 - u64 addr; 574 - enum event_result err; 605 + struct perf_event_attr attr; 606 + char name[MAX_NAME_LEN]; 575 607 576 - target = strchr(*strp, ':'); 577 - if (!target) 578 - return EVT_FAILED; 608 + memset(&attr, 0, sizeof(attr)); 609 + attr.bp_addr = (unsigned long) ptr; 579 610 580 - if (strncmp(*strp, "mem", target - *strp) != 0) 581 - return EVT_FAILED; 582 - 583 - target++; 584 - 585 - addr = strtoull(target, &endaddr, 0); 586 - if (target == endaddr) 587 - return EVT_FAILED; 588 - 589 - attr->bp_addr = addr; 590 - *strp = endaddr; 591 - 592 - type = strchr(target, ':'); 593 - 594 - /* If no type is defined, just rw as default */ 595 - if (!type) { 596 - attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; 597 - } else { 598 - err = parse_breakpoint_type(++type, strp, attr); 599 - if (err == EVT_FAILED) 600 - return EVT_FAILED; 601 - } 611 + if (parse_breakpoint_type(type, &attr)) 612 + return -EINVAL; 602 613 603 614 /* 604 615 * We should find a nice way to override the access length 605 616 * Provide some defaults for now 606 617 */ 607 - if (attr->bp_type == HW_BREAKPOINT_X) 608 - attr->bp_len = sizeof(long); 618 + if (attr.bp_type == HW_BREAKPOINT_X) 619 + attr.bp_len = sizeof(long); 609 620 else 610 - attr->bp_len = HW_BREAKPOINT_LEN_4; 621 + attr.bp_len = HW_BREAKPOINT_LEN_4; 611 622 612 - attr->type = PERF_TYPE_BREAKPOINT; 623 + attr.type = PERF_TYPE_BREAKPOINT; 613 624 614 - return EVT_HANDLED; 625 + snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw"); 626 + return add_event(list, idx, &attr, name); 615 627 } 616 628 617 - static int check_events(const char *str, unsigned int i) 629 + static int config_term(struct perf_event_attr *attr, 630 + struct parse_events__term *term) 618 631 { 619 - int n; 620 - 621 - n = strlen(event_symbols[i].symbol); 622 - if (!strncasecmp(str, event_symbols[i].symbol, n)) 623 - return n; 624 - 625 - n = strlen(event_symbols[i].alias); 626 - if (n) { 627 - if (!strncasecmp(str, event_symbols[i].alias, n)) 628 - return n; 632 + switch (term->type) { 633 + case PARSE_EVENTS__TERM_TYPE_CONFIG: 634 + attr->config = term->val.num; 635 + break; 636 + case PARSE_EVENTS__TERM_TYPE_CONFIG1: 637 + attr->config1 = term->val.num; 638 + break; 639 + case PARSE_EVENTS__TERM_TYPE_CONFIG2: 640 + attr->config2 = term->val.num; 641 + break; 642 + case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 643 + attr->sample_period = term->val.num; 644 + break; 645 + case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 646 + /* 647 + * TODO uncomment when the field is available 648 + * attr->branch_sample_type = term->val.num; 649 + */ 650 + break; 651 + default: 652 + return -EINVAL; 629 653 } 654 + return 0; 655 + } 656 + 657 + static int config_attr(struct perf_event_attr *attr, 658 + struct list_head *head, int fail) 659 + { 660 + struct parse_events__term *term; 661 + 662 + list_for_each_entry(term, head, list) 663 + if (config_term(attr, term) && fail) 664 + return -EINVAL; 630 665 631 666 return 0; 632 667 } 633 668 634 - static enum event_result 635 - parse_symbolic_event(const char **strp, struct perf_event_attr *attr) 669 + int parse_events_add_numeric(struct list_head *list, int *idx, 670 + unsigned long type, unsigned long config, 671 + struct list_head *head_config) 636 672 { 637 - const char *str = *strp; 638 - unsigned int i; 639 - int n; 673 + struct perf_event_attr attr; 640 674 641 - for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 642 - n = check_events(str, i); 643 - if (n > 0) { 644 - attr->type = event_symbols[i].type; 645 - attr->config = event_symbols[i].config; 646 - *strp = str + n; 647 - return EVT_HANDLED; 648 - } 649 - } 650 - return EVT_FAILED; 675 + memset(&attr, 0, sizeof(attr)); 676 + attr.type = type; 677 + attr.config = config; 678 + 679 + if (head_config && 680 + config_attr(&attr, head_config, 1)) 681 + return -EINVAL; 682 + 683 + return add_event(list, idx, &attr, 684 + (char *) __event_name(type, config)); 651 685 } 652 686 653 - static enum event_result 654 - parse_raw_event(const char **strp, struct perf_event_attr *attr) 687 + int parse_events_add_pmu(struct list_head *list, int *idx, 688 + char *name, struct list_head *head_config) 655 689 { 656 - const char *str = *strp; 657 - u64 config; 658 - int n; 690 + struct perf_event_attr attr; 691 + struct perf_pmu *pmu; 659 692 660 - if (*str != 'r') 661 - return EVT_FAILED; 662 - n = hex2u64(str + 1, &config); 663 - if (n > 0) { 664 - const char *end = str + n + 1; 665 - if (*end != '\0' && *end != ',' && *end != ':') 666 - return EVT_FAILED; 693 + pmu = perf_pmu__find(name); 694 + if (!pmu) 695 + return -EINVAL; 667 696 668 - *strp = end; 669 - attr->type = PERF_TYPE_RAW; 670 - attr->config = config; 671 - return EVT_HANDLED; 672 - } 673 - return EVT_FAILED; 697 + memset(&attr, 0, sizeof(attr)); 698 + 699 + /* 700 + * Configure hardcoded terms first, no need to check 701 + * return value when called with fail == 0 ;) 702 + */ 703 + config_attr(&attr, head_config, 0); 704 + 705 + if (perf_pmu__config(pmu, &attr, head_config)) 706 + return -EINVAL; 707 + 708 + return add_event(list, idx, &attr, (char *) "pmu"); 674 709 } 675 710 676 - static enum event_result 677 - parse_numeric_event(const char **strp, struct perf_event_attr *attr) 711 + void parse_events_update_lists(struct list_head *list_event, 712 + struct list_head *list_all) 678 713 { 679 - const char *str = *strp; 680 - char *endp; 681 - unsigned long type; 682 - u64 config; 683 - 684 - type = strtoul(str, &endp, 0); 685 - if (endp > str && type < PERF_TYPE_MAX && *endp == ':') { 686 - str = endp + 1; 687 - config = strtoul(str, &endp, 0); 688 - if (endp > str) { 689 - attr->type = type; 690 - attr->config = config; 691 - *strp = endp; 692 - return EVT_HANDLED; 693 - } 694 - } 695 - return EVT_FAILED; 714 + /* 715 + * Called for single event definition. Update the 716 + * 'all event' list, and reinit the 'signle event' 717 + * list, for next event definition. 718 + */ 719 + list_splice_tail(list_event, list_all); 720 + INIT_LIST_HEAD(list_event); 696 721 } 697 722 698 - static int 699 - parse_event_modifier(const char **strp, struct perf_event_attr *attr) 723 + int parse_events_modifier(struct list_head *list, char *str) 700 724 { 701 - const char *str = *strp; 725 + struct perf_evsel *evsel; 702 726 int exclude = 0, exclude_GH = 0; 703 727 int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0; 704 728 705 - if (!*str) 729 + if (str == NULL) 706 730 return 0; 707 - 708 - if (*str == ',') 709 - return 0; 710 - 711 - if (*str++ != ':') 712 - return -1; 713 731 714 732 while (*str) { 715 733 if (*str == 'u') { ··· 721 775 722 776 ++str; 723 777 } 724 - if (str < *strp + 2) 725 - return -1; 726 778 727 - *strp = str; 779 + /* 780 + * precise ip: 781 + * 782 + * 0 - SAMPLE_IP can have arbitrary skid 783 + * 1 - SAMPLE_IP must have constant skid 784 + * 2 - SAMPLE_IP requested to have 0 skid 785 + * 3 - SAMPLE_IP must have 0 skid 786 + * 787 + * See also PERF_RECORD_MISC_EXACT_IP 788 + */ 789 + if (precise > 3) 790 + return -EINVAL; 728 791 729 - attr->exclude_user = eu; 730 - attr->exclude_kernel = ek; 731 - attr->exclude_hv = eh; 732 - attr->precise_ip = precise; 733 - attr->exclude_host = eH; 734 - attr->exclude_guest = eG; 792 + list_for_each_entry(evsel, list, node) { 793 + evsel->attr.exclude_user = eu; 794 + evsel->attr.exclude_kernel = ek; 795 + evsel->attr.exclude_hv = eh; 796 + evsel->attr.precise_ip = precise; 797 + evsel->attr.exclude_host = eH; 798 + evsel->attr.exclude_guest = eG; 799 + } 735 800 736 801 return 0; 737 802 } 738 803 739 - /* 740 - * Each event can have multiple symbolic names. 741 - * Symbolic names are (almost) exactly matched. 742 - */ 743 - static enum event_result 744 - parse_event_symbols(struct perf_evlist *evlist, const char **str, 745 - struct perf_event_attr *attr) 804 + int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) 746 805 { 747 - enum event_result ret; 806 + LIST_HEAD(list); 807 + LIST_HEAD(list_tmp); 808 + YY_BUFFER_STATE buffer; 809 + int ret, idx = evlist->nr_entries; 748 810 749 - ret = parse_tracepoint_event(evlist, str, attr); 750 - if (ret != EVT_FAILED) 751 - goto modifier; 811 + buffer = parse_events__scan_string(str); 752 812 753 - ret = parse_raw_event(str, attr); 754 - if (ret != EVT_FAILED) 755 - goto modifier; 813 + ret = parse_events_parse(&list, &list_tmp, &idx); 756 814 757 - ret = parse_numeric_event(str, attr); 758 - if (ret != EVT_FAILED) 759 - goto modifier; 815 + parse_events__flush_buffer(buffer); 816 + parse_events__delete_buffer(buffer); 760 817 761 - ret = parse_symbolic_event(str, attr); 762 - if (ret != EVT_FAILED) 763 - goto modifier; 818 + if (!ret) { 819 + int entries = idx - evlist->nr_entries; 820 + perf_evlist__splice_list_tail(evlist, &list, entries); 821 + return 0; 822 + } 764 823 765 - ret = parse_generic_hw_event(str, attr); 766 - if (ret != EVT_FAILED) 767 - goto modifier; 768 - 769 - ret = parse_breakpoint_event(str, attr); 770 - if (ret != EVT_FAILED) 771 - goto modifier; 772 - 773 - fprintf(stderr, "invalid or unsupported event: '%s'\n", *str); 824 + /* 825 + * There are 2 users - builtin-record and builtin-test objects. 826 + * Both call perf_evlist__delete in case of error, so we dont 827 + * need to bother. 828 + */ 829 + fprintf(stderr, "invalid or unsupported event: '%s'\n", str); 774 830 fprintf(stderr, "Run 'perf list' for a list of valid events\n"); 775 - return EVT_FAILED; 776 - 777 - modifier: 778 - if (parse_event_modifier(str, attr) < 0) { 779 - fprintf(stderr, "invalid event modifier: '%s'\n", *str); 780 - fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n"); 781 - 782 - return EVT_FAILED; 783 - } 784 - 785 831 return ret; 786 - } 787 - 788 - int parse_events(struct perf_evlist *evlist , const char *str, int unset __used) 789 - { 790 - struct perf_event_attr attr; 791 - enum event_result ret; 792 - const char *ostr; 793 - 794 - for (;;) { 795 - ostr = str; 796 - memset(&attr, 0, sizeof(attr)); 797 - event_attr_init(&attr); 798 - ret = parse_event_symbols(evlist, &str, &attr); 799 - if (ret == EVT_FAILED) 800 - return -1; 801 - 802 - if (!(*str == 0 || *str == ',' || isspace(*str))) 803 - return -1; 804 - 805 - if (ret != EVT_HANDLED_ALL) { 806 - struct perf_evsel *evsel; 807 - evsel = perf_evsel__new(&attr, evlist->nr_entries); 808 - if (evsel == NULL) 809 - return -1; 810 - perf_evlist__add(evlist, evsel); 811 - 812 - evsel->name = calloc(str - ostr + 1, 1); 813 - if (!evsel->name) 814 - return -1; 815 - strncpy(evsel->name, ostr, str - ostr); 816 - } 817 - 818 - if (*str == 0) 819 - break; 820 - if (*str == ',') 821 - ++str; 822 - while (isspace(*str)) 823 - ++str; 824 - } 825 - 826 - return 0; 827 832 } 828 833 829 834 int parse_events_option(const struct option *opt, const char *str, ··· 949 1052 return printed; 950 1053 } 951 1054 952 - #define MAX_NAME_LEN 100 953 - 954 1055 /* 955 1056 * Print the help text for the event symbols: 956 1057 */ ··· 997 1102 998 1103 printf("\n"); 999 1104 printf(" %-50s [%s]\n", 1000 - "rNNN (see 'perf list --help' on how to encode it)", 1105 + "rNNN", 1001 1106 event_type_descriptors[PERF_TYPE_RAW]); 1107 + printf(" %-50s [%s]\n", 1108 + "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 1109 + event_type_descriptors[PERF_TYPE_RAW]); 1110 + printf(" (see 'perf list --help' on how to encode it)\n"); 1002 1111 printf("\n"); 1003 1112 1004 1113 printf(" %-50s [%s]\n", ··· 1011 1112 printf("\n"); 1012 1113 1013 1114 print_tracepoint_events(NULL, NULL); 1115 + } 1116 + 1117 + int parse_events__is_hardcoded_term(struct parse_events__term *term) 1118 + { 1119 + return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX; 1120 + } 1121 + 1122 + int parse_events__new_term(struct parse_events__term **_term, int type, 1123 + char *config, char *str, long num) 1124 + { 1125 + struct parse_events__term *term; 1126 + 1127 + term = zalloc(sizeof(*term)); 1128 + if (!term) 1129 + return -ENOMEM; 1130 + 1131 + INIT_LIST_HEAD(&term->list); 1132 + term->type = type; 1133 + term->config = config; 1134 + 1135 + switch (type) { 1136 + case PARSE_EVENTS__TERM_TYPE_CONFIG: 1137 + case PARSE_EVENTS__TERM_TYPE_CONFIG1: 1138 + case PARSE_EVENTS__TERM_TYPE_CONFIG2: 1139 + case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 1140 + case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 1141 + case PARSE_EVENTS__TERM_TYPE_NUM: 1142 + term->val.num = num; 1143 + break; 1144 + case PARSE_EVENTS__TERM_TYPE_STR: 1145 + term->val.str = str; 1146 + break; 1147 + default: 1148 + return -EINVAL; 1149 + } 1150 + 1151 + *_term = term; 1152 + return 0; 1153 + } 1154 + 1155 + void parse_events__free_terms(struct list_head *terms) 1156 + { 1157 + struct parse_events__term *term, *h; 1158 + 1159 + list_for_each_entry_safe(term, h, terms, list) 1160 + free(term); 1161 + 1162 + free(terms); 1014 1163 }
+49
tools/perf/util/parse-events.h
··· 33 33 34 34 #define EVENTS_HELP_MAX (128*1024) 35 35 36 + enum { 37 + PARSE_EVENTS__TERM_TYPE_CONFIG, 38 + PARSE_EVENTS__TERM_TYPE_CONFIG1, 39 + PARSE_EVENTS__TERM_TYPE_CONFIG2, 40 + PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, 41 + PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 42 + PARSE_EVENTS__TERM_TYPE_NUM, 43 + PARSE_EVENTS__TERM_TYPE_STR, 44 + 45 + PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX = 46 + PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 47 + }; 48 + 49 + struct parse_events__term { 50 + char *config; 51 + union { 52 + char *str; 53 + long num; 54 + } val; 55 + int type; 56 + 57 + struct list_head list; 58 + }; 59 + 60 + int parse_events__is_hardcoded_term(struct parse_events__term *term); 61 + int parse_events__new_term(struct parse_events__term **term, int type, 62 + char *config, char *str, long num); 63 + void parse_events__free_terms(struct list_head *terms); 64 + int parse_events_modifier(struct list_head *list __used, char *str __used); 65 + int parse_events_add_tracepoint(struct list_head *list, int *idx, 66 + char *sys, char *event); 67 + int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config, 68 + unsigned long config1, unsigned long config2, 69 + char *mod); 70 + int parse_events_add_numeric(struct list_head *list, int *idx, 71 + unsigned long type, unsigned long config, 72 + struct list_head *head_config); 73 + int parse_events_add_cache(struct list_head *list, int *idx, 74 + char *type, char *op_result1, char *op_result2); 75 + int parse_events_add_breakpoint(struct list_head *list, int *idx, 76 + void *ptr, char *type); 77 + int parse_events_add_pmu(struct list_head *list, int *idx, 78 + char *pmu , struct list_head *head_config); 79 + void parse_events_update_lists(struct list_head *list_event, 80 + struct list_head *list_all); 81 + void parse_events_error(struct list_head *list_all, 82 + struct list_head *list_event, 83 + int *idx, char const *msg); 84 + 36 85 void print_events(const char *event_glob); 37 86 void print_events_type(u8 type); 38 87 void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
+127
tools/perf/util/parse-events.l
··· 1 + 2 + %option prefix="parse_events_" 3 + 4 + %{ 5 + #include <errno.h> 6 + #include "../perf.h" 7 + #include "parse-events-bison.h" 8 + #include "parse-events.h" 9 + 10 + static int __value(char *str, int base, int token) 11 + { 12 + long num; 13 + 14 + errno = 0; 15 + num = strtoul(str, NULL, base); 16 + if (errno) 17 + return PE_ERROR; 18 + 19 + parse_events_lval.num = num; 20 + return token; 21 + } 22 + 23 + static int value(int base) 24 + { 25 + return __value(parse_events_text, base, PE_VALUE); 26 + } 27 + 28 + static int raw(void) 29 + { 30 + return __value(parse_events_text + 1, 16, PE_RAW); 31 + } 32 + 33 + static int str(int token) 34 + { 35 + parse_events_lval.str = strdup(parse_events_text); 36 + return token; 37 + } 38 + 39 + static int sym(int type, int config) 40 + { 41 + parse_events_lval.num = (type << 16) + config; 42 + return PE_VALUE_SYM; 43 + } 44 + 45 + static int term(int type) 46 + { 47 + parse_events_lval.num = type; 48 + return PE_TERM; 49 + } 50 + 51 + %} 52 + 53 + num_dec [0-9]+ 54 + num_hex 0x[a-fA-F0-9]+ 55 + num_raw_hex [a-fA-F0-9]+ 56 + name [a-zA-Z_*?][a-zA-Z0-9_*?]* 57 + modifier_event [ukhp]{1,5} 58 + modifier_bp [rwx] 59 + 60 + %% 61 + cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } 62 + stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } 63 + stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } 64 + instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } 65 + cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } 66 + cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } 67 + branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } 68 + branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } 69 + bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } 70 + ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } 71 + cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } 72 + task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } 73 + page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } 74 + minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } 75 + major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } 76 + context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } 77 + cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } 78 + alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } 79 + emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } 80 + 81 + L1-dcache|l1-d|l1d|L1-data | 82 + L1-icache|l1-i|l1i|L1-instruction | 83 + LLC|L2 | 84 + dTLB|d-tlb|Data-TLB | 85 + iTLB|i-tlb|Instruction-TLB | 86 + branch|branches|bpu|btb|bpc | 87 + node { return str(PE_NAME_CACHE_TYPE); } 88 + 89 + load|loads|read | 90 + store|stores|write | 91 + prefetch|prefetches | 92 + speculative-read|speculative-load | 93 + refs|Reference|ops|access | 94 + misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } 95 + 96 + /* 97 + * These are event config hardcoded term names to be specified 98 + * within xxx/.../ syntax. So far we dont clash with other names, 99 + * so we can put them here directly. In case the we have a conflict 100 + * in future, this needs to go into '//' condition block. 101 + */ 102 + config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } 103 + config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } 104 + config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } 105 + period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } 106 + branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 107 + 108 + mem: { return PE_PREFIX_MEM; } 109 + r{num_raw_hex} { return raw(); } 110 + {num_dec} { return value(10); } 111 + {num_hex} { return value(16); } 112 + 113 + {modifier_event} { return str(PE_MODIFIER_EVENT); } 114 + {modifier_bp} { return str(PE_MODIFIER_BP); } 115 + {name} { return str(PE_NAME); } 116 + "/" { return '/'; } 117 + - { return '-'; } 118 + , { return ','; } 119 + : { return ':'; } 120 + = { return '='; } 121 + 122 + %% 123 + 124 + int parse_events_wrap(void) 125 + { 126 + return 1; 127 + }
+229
tools/perf/util/parse-events.y
··· 1 + 2 + %name-prefix "parse_events_" 3 + %parse-param {struct list_head *list_all} 4 + %parse-param {struct list_head *list_event} 5 + %parse-param {int *idx} 6 + 7 + %{ 8 + 9 + #define YYDEBUG 1 10 + 11 + #include <linux/compiler.h> 12 + #include <linux/list.h> 13 + #include "types.h" 14 + #include "util.h" 15 + #include "parse-events.h" 16 + 17 + extern int parse_events_lex (void); 18 + 19 + #define ABORT_ON(val) \ 20 + do { \ 21 + if (val) \ 22 + YYABORT; \ 23 + } while (0) 24 + 25 + %} 26 + 27 + %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM 28 + %token PE_NAME 29 + %token PE_MODIFIER_EVENT PE_MODIFIER_BP 30 + %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT 31 + %token PE_PREFIX_MEM PE_PREFIX_RAW 32 + %token PE_ERROR 33 + %type <num> PE_VALUE 34 + %type <num> PE_VALUE_SYM 35 + %type <num> PE_RAW 36 + %type <num> PE_TERM 37 + %type <str> PE_NAME 38 + %type <str> PE_NAME_CACHE_TYPE 39 + %type <str> PE_NAME_CACHE_OP_RESULT 40 + %type <str> PE_MODIFIER_EVENT 41 + %type <str> PE_MODIFIER_BP 42 + %type <head> event_config 43 + %type <term> event_term 44 + 45 + %union 46 + { 47 + char *str; 48 + unsigned long num; 49 + struct list_head *head; 50 + struct parse_events__term *term; 51 + } 52 + %% 53 + 54 + events: 55 + events ',' event | event 56 + 57 + event: 58 + event_def PE_MODIFIER_EVENT 59 + { 60 + /* 61 + * Apply modifier on all events added by single event definition 62 + * (there could be more events added for multiple tracepoint 63 + * definitions via '*?'. 64 + */ 65 + ABORT_ON(parse_events_modifier(list_event, $2)); 66 + parse_events_update_lists(list_event, list_all); 67 + } 68 + | 69 + event_def 70 + { 71 + parse_events_update_lists(list_event, list_all); 72 + } 73 + 74 + event_def: event_pmu | 75 + event_legacy_symbol | 76 + event_legacy_cache sep_dc | 77 + event_legacy_mem | 78 + event_legacy_tracepoint sep_dc | 79 + event_legacy_numeric sep_dc | 80 + event_legacy_raw sep_dc 81 + 82 + event_pmu: 83 + PE_NAME '/' event_config '/' 84 + { 85 + ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3)); 86 + parse_events__free_terms($3); 87 + } 88 + 89 + event_legacy_symbol: 90 + PE_VALUE_SYM '/' event_config '/' 91 + { 92 + int type = $1 >> 16; 93 + int config = $1 & 255; 94 + 95 + ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3)); 96 + parse_events__free_terms($3); 97 + } 98 + | 99 + PE_VALUE_SYM sep_slash_dc 100 + { 101 + int type = $1 >> 16; 102 + int config = $1 & 255; 103 + 104 + ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL)); 105 + } 106 + 107 + event_legacy_cache: 108 + PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 109 + { 110 + ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5)); 111 + } 112 + | 113 + PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 114 + { 115 + ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL)); 116 + } 117 + | 118 + PE_NAME_CACHE_TYPE 119 + { 120 + ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL)); 121 + } 122 + 123 + event_legacy_mem: 124 + PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 125 + { 126 + ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4)); 127 + } 128 + | 129 + PE_PREFIX_MEM PE_VALUE sep_dc 130 + { 131 + ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL)); 132 + } 133 + 134 + event_legacy_tracepoint: 135 + PE_NAME ':' PE_NAME 136 + { 137 + ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3)); 138 + } 139 + 140 + event_legacy_numeric: 141 + PE_VALUE ':' PE_VALUE 142 + { 143 + ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL)); 144 + } 145 + 146 + event_legacy_raw: 147 + PE_RAW 148 + { 149 + ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL)); 150 + } 151 + 152 + event_config: 153 + event_config ',' event_term 154 + { 155 + struct list_head *head = $1; 156 + struct parse_events__term *term = $3; 157 + 158 + ABORT_ON(!head); 159 + list_add_tail(&term->list, head); 160 + $$ = $1; 161 + } 162 + | 163 + event_term 164 + { 165 + struct list_head *head = malloc(sizeof(*head)); 166 + struct parse_events__term *term = $1; 167 + 168 + ABORT_ON(!head); 169 + INIT_LIST_HEAD(head); 170 + list_add_tail(&term->list, head); 171 + $$ = head; 172 + } 173 + 174 + event_term: 175 + PE_NAME '=' PE_NAME 176 + { 177 + struct parse_events__term *term; 178 + 179 + ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR, 180 + $1, $3, 0)); 181 + $$ = term; 182 + } 183 + | 184 + PE_NAME '=' PE_VALUE 185 + { 186 + struct parse_events__term *term; 187 + 188 + ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 189 + $1, NULL, $3)); 190 + $$ = term; 191 + } 192 + | 193 + PE_NAME 194 + { 195 + struct parse_events__term *term; 196 + 197 + ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 198 + $1, NULL, 1)); 199 + $$ = term; 200 + } 201 + | 202 + PE_TERM '=' PE_VALUE 203 + { 204 + struct parse_events__term *term; 205 + 206 + ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3)); 207 + $$ = term; 208 + } 209 + | 210 + PE_TERM 211 + { 212 + struct parse_events__term *term; 213 + 214 + ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1)); 215 + $$ = term; 216 + } 217 + 218 + sep_dc: ':' | 219 + 220 + sep_slash_dc: '/' | ':' | 221 + 222 + %% 223 + 224 + void parse_events_error(struct list_head *list_all __used, 225 + struct list_head *list_event __used, 226 + int *idx __used, 227 + char const *msg __used) 228 + { 229 + }
+469
tools/perf/util/pmu.c
··· 1 + 2 + #include <linux/list.h> 3 + #include <sys/types.h> 4 + #include <sys/stat.h> 5 + #include <unistd.h> 6 + #include <stdio.h> 7 + #include <dirent.h> 8 + #include "sysfs.h" 9 + #include "util.h" 10 + #include "pmu.h" 11 + #include "parse-events.h" 12 + 13 + int perf_pmu_parse(struct list_head *list, char *name); 14 + extern FILE *perf_pmu_in; 15 + 16 + static LIST_HEAD(pmus); 17 + 18 + /* 19 + * Parse & process all the sysfs attributes located under 20 + * the directory specified in 'dir' parameter. 21 + */ 22 + static int pmu_format_parse(char *dir, struct list_head *head) 23 + { 24 + struct dirent *evt_ent; 25 + DIR *format_dir; 26 + int ret = 0; 27 + 28 + format_dir = opendir(dir); 29 + if (!format_dir) 30 + return -EINVAL; 31 + 32 + while (!ret && (evt_ent = readdir(format_dir))) { 33 + char path[PATH_MAX]; 34 + char *name = evt_ent->d_name; 35 + FILE *file; 36 + 37 + if (!strcmp(name, ".") || !strcmp(name, "..")) 38 + continue; 39 + 40 + snprintf(path, PATH_MAX, "%s/%s", dir, name); 41 + 42 + ret = -EINVAL; 43 + file = fopen(path, "r"); 44 + if (!file) 45 + break; 46 + 47 + perf_pmu_in = file; 48 + ret = perf_pmu_parse(head, name); 49 + fclose(file); 50 + } 51 + 52 + closedir(format_dir); 53 + return ret; 54 + } 55 + 56 + /* 57 + * Reading/parsing the default pmu format definition, which should be 58 + * located at: 59 + * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 60 + */ 61 + static int pmu_format(char *name, struct list_head *format) 62 + { 63 + struct stat st; 64 + char path[PATH_MAX]; 65 + const char *sysfs; 66 + 67 + sysfs = sysfs_find_mountpoint(); 68 + if (!sysfs) 69 + return -1; 70 + 71 + snprintf(path, PATH_MAX, 72 + "%s/bus/event_source/devices/%s/format", sysfs, name); 73 + 74 + if (stat(path, &st) < 0) 75 + return -1; 76 + 77 + if (pmu_format_parse(path, format)) 78 + return -1; 79 + 80 + return 0; 81 + } 82 + 83 + /* 84 + * Reading/parsing the default pmu type value, which should be 85 + * located at: 86 + * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 87 + */ 88 + static int pmu_type(char *name, __u32 *type) 89 + { 90 + struct stat st; 91 + char path[PATH_MAX]; 92 + const char *sysfs; 93 + FILE *file; 94 + int ret = 0; 95 + 96 + sysfs = sysfs_find_mountpoint(); 97 + if (!sysfs) 98 + return -1; 99 + 100 + snprintf(path, PATH_MAX, 101 + "%s/bus/event_source/devices/%s/type", sysfs, name); 102 + 103 + if (stat(path, &st) < 0) 104 + return -1; 105 + 106 + file = fopen(path, "r"); 107 + if (!file) 108 + return -EINVAL; 109 + 110 + if (1 != fscanf(file, "%u", type)) 111 + ret = -1; 112 + 113 + fclose(file); 114 + return ret; 115 + } 116 + 117 + static struct perf_pmu *pmu_lookup(char *name) 118 + { 119 + struct perf_pmu *pmu; 120 + LIST_HEAD(format); 121 + __u32 type; 122 + 123 + /* 124 + * The pmu data we store & need consists of the pmu 125 + * type value and format definitions. Load both right 126 + * now. 127 + */ 128 + if (pmu_format(name, &format)) 129 + return NULL; 130 + 131 + if (pmu_type(name, &type)) 132 + return NULL; 133 + 134 + pmu = zalloc(sizeof(*pmu)); 135 + if (!pmu) 136 + return NULL; 137 + 138 + INIT_LIST_HEAD(&pmu->format); 139 + list_splice(&format, &pmu->format); 140 + pmu->name = strdup(name); 141 + pmu->type = type; 142 + return pmu; 143 + } 144 + 145 + static struct perf_pmu *pmu_find(char *name) 146 + { 147 + struct perf_pmu *pmu; 148 + 149 + list_for_each_entry(pmu, &pmus, list) 150 + if (!strcmp(pmu->name, name)) 151 + return pmu; 152 + 153 + return NULL; 154 + } 155 + 156 + struct perf_pmu *perf_pmu__find(char *name) 157 + { 158 + struct perf_pmu *pmu; 159 + 160 + /* 161 + * Once PMU is loaded it stays in the list, 162 + * so we keep us from multiple reading/parsing 163 + * the pmu format definitions. 164 + */ 165 + pmu = pmu_find(name); 166 + if (pmu) 167 + return pmu; 168 + 169 + return pmu_lookup(name); 170 + } 171 + 172 + static struct perf_pmu__format* 173 + pmu_find_format(struct list_head *formats, char *name) 174 + { 175 + struct perf_pmu__format *format; 176 + 177 + list_for_each_entry(format, formats, list) 178 + if (!strcmp(format->name, name)) 179 + return format; 180 + 181 + return NULL; 182 + } 183 + 184 + /* 185 + * Returns value based on the format definition (format parameter) 186 + * and unformated value (value parameter). 187 + * 188 + * TODO maybe optimize a little ;) 189 + */ 190 + static __u64 pmu_format_value(unsigned long *format, __u64 value) 191 + { 192 + unsigned long fbit, vbit; 193 + __u64 v = 0; 194 + 195 + for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 196 + 197 + if (!test_bit(fbit, format)) 198 + continue; 199 + 200 + if (!(value & (1llu << vbit++))) 201 + continue; 202 + 203 + v |= (1llu << fbit); 204 + } 205 + 206 + return v; 207 + } 208 + 209 + /* 210 + * Setup one of config[12] attr members based on the 211 + * user input data - temr parameter. 212 + */ 213 + static int pmu_config_term(struct list_head *formats, 214 + struct perf_event_attr *attr, 215 + struct parse_events__term *term) 216 + { 217 + struct perf_pmu__format *format; 218 + __u64 *vp; 219 + 220 + /* 221 + * Support only for hardcoded and numnerial terms. 222 + * Hardcoded terms should be already in, so nothing 223 + * to be done for them. 224 + */ 225 + if (parse_events__is_hardcoded_term(term)) 226 + return 0; 227 + 228 + if (term->type != PARSE_EVENTS__TERM_TYPE_NUM) 229 + return -EINVAL; 230 + 231 + format = pmu_find_format(formats, term->config); 232 + if (!format) 233 + return -EINVAL; 234 + 235 + switch (format->value) { 236 + case PERF_PMU_FORMAT_VALUE_CONFIG: 237 + vp = &attr->config; 238 + break; 239 + case PERF_PMU_FORMAT_VALUE_CONFIG1: 240 + vp = &attr->config1; 241 + break; 242 + case PERF_PMU_FORMAT_VALUE_CONFIG2: 243 + vp = &attr->config2; 244 + break; 245 + default: 246 + return -EINVAL; 247 + } 248 + 249 + *vp |= pmu_format_value(format->bits, term->val.num); 250 + return 0; 251 + } 252 + 253 + static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 254 + struct list_head *head_terms) 255 + { 256 + struct parse_events__term *term, *h; 257 + 258 + list_for_each_entry_safe(term, h, head_terms, list) 259 + if (pmu_config_term(formats, attr, term)) 260 + return -EINVAL; 261 + 262 + return 0; 263 + } 264 + 265 + /* 266 + * Configures event's 'attr' parameter based on the: 267 + * 1) users input - specified in terms parameter 268 + * 2) pmu format definitions - specified by pmu parameter 269 + */ 270 + int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 271 + struct list_head *head_terms) 272 + { 273 + attr->type = pmu->type; 274 + return pmu_config(&pmu->format, attr, head_terms); 275 + } 276 + 277 + int perf_pmu__new_format(struct list_head *list, char *name, 278 + int config, unsigned long *bits) 279 + { 280 + struct perf_pmu__format *format; 281 + 282 + format = zalloc(sizeof(*format)); 283 + if (!format) 284 + return -ENOMEM; 285 + 286 + format->name = strdup(name); 287 + format->value = config; 288 + memcpy(format->bits, bits, sizeof(format->bits)); 289 + 290 + list_add_tail(&format->list, list); 291 + return 0; 292 + } 293 + 294 + void perf_pmu__set_format(unsigned long *bits, long from, long to) 295 + { 296 + long b; 297 + 298 + if (!to) 299 + to = from; 300 + 301 + memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); 302 + for (b = from; b <= to; b++) 303 + set_bit(b, bits); 304 + } 305 + 306 + /* Simulated format definitions. */ 307 + static struct test_format { 308 + const char *name; 309 + const char *value; 310 + } test_formats[] = { 311 + { "krava01", "config:0-1,62-63\n", }, 312 + { "krava02", "config:10-17\n", }, 313 + { "krava03", "config:5\n", }, 314 + { "krava11", "config1:0,2,4,6,8,20-28\n", }, 315 + { "krava12", "config1:63\n", }, 316 + { "krava13", "config1:45-47\n", }, 317 + { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", }, 318 + { "krava22", "config2:8,18,48,58\n", }, 319 + { "krava23", "config2:28-29,38\n", }, 320 + }; 321 + 322 + #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format)) 323 + 324 + /* Simulated users input. */ 325 + static struct parse_events__term test_terms[] = { 326 + { 327 + .config = (char *) "krava01", 328 + .val.num = 15, 329 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 330 + }, 331 + { 332 + .config = (char *) "krava02", 333 + .val.num = 170, 334 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 335 + }, 336 + { 337 + .config = (char *) "krava03", 338 + .val.num = 1, 339 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 340 + }, 341 + { 342 + .config = (char *) "krava11", 343 + .val.num = 27, 344 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 345 + }, 346 + { 347 + .config = (char *) "krava12", 348 + .val.num = 1, 349 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 350 + }, 351 + { 352 + .config = (char *) "krava13", 353 + .val.num = 2, 354 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 355 + }, 356 + { 357 + .config = (char *) "krava21", 358 + .val.num = 119, 359 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 360 + }, 361 + { 362 + .config = (char *) "krava22", 363 + .val.num = 11, 364 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 365 + }, 366 + { 367 + .config = (char *) "krava23", 368 + .val.num = 2, 369 + .type = PARSE_EVENTS__TERM_TYPE_NUM, 370 + }, 371 + }; 372 + #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) 373 + 374 + /* 375 + * Prepare format directory data, exported by kernel 376 + * at /sys/bus/event_source/devices/<dev>/format. 377 + */ 378 + static char *test_format_dir_get(void) 379 + { 380 + static char dir[PATH_MAX]; 381 + unsigned int i; 382 + 383 + snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX"); 384 + if (!mkdtemp(dir)) 385 + return NULL; 386 + 387 + for (i = 0; i < TEST_FORMATS_CNT; i++) { 388 + static char name[PATH_MAX]; 389 + struct test_format *format = &test_formats[i]; 390 + FILE *file; 391 + 392 + snprintf(name, PATH_MAX, "%s/%s", dir, format->name); 393 + 394 + file = fopen(name, "w"); 395 + if (!file) 396 + return NULL; 397 + 398 + if (1 != fwrite(format->value, strlen(format->value), 1, file)) 399 + break; 400 + 401 + fclose(file); 402 + } 403 + 404 + return dir; 405 + } 406 + 407 + /* Cleanup format directory. */ 408 + static int test_format_dir_put(char *dir) 409 + { 410 + char buf[PATH_MAX]; 411 + snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir); 412 + if (system(buf)) 413 + return -1; 414 + 415 + snprintf(buf, PATH_MAX, "rmdir %s\n", dir); 416 + return system(buf); 417 + } 418 + 419 + static struct list_head *test_terms_list(void) 420 + { 421 + static LIST_HEAD(terms); 422 + unsigned int i; 423 + 424 + for (i = 0; i < TERMS_CNT; i++) 425 + list_add_tail(&test_terms[i].list, &terms); 426 + 427 + return &terms; 428 + } 429 + 430 + #undef TERMS_CNT 431 + 432 + int perf_pmu__test(void) 433 + { 434 + char *format = test_format_dir_get(); 435 + LIST_HEAD(formats); 436 + struct list_head *terms = test_terms_list(); 437 + int ret; 438 + 439 + if (!format) 440 + return -EINVAL; 441 + 442 + do { 443 + struct perf_event_attr attr; 444 + 445 + memset(&attr, 0, sizeof(attr)); 446 + 447 + ret = pmu_format_parse(format, &formats); 448 + if (ret) 449 + break; 450 + 451 + ret = pmu_config(&formats, &attr, terms); 452 + if (ret) 453 + break; 454 + 455 + ret = -EINVAL; 456 + 457 + if (attr.config != 0xc00000000002a823) 458 + break; 459 + if (attr.config1 != 0x8000400000000145) 460 + break; 461 + if (attr.config2 != 0x0400000020041d07) 462 + break; 463 + 464 + ret = 0; 465 + } while (0); 466 + 467 + test_format_dir_put(format); 468 + return ret; 469 + }
+41
tools/perf/util/pmu.h
··· 1 + #ifndef __PMU_H 2 + #define __PMU_H 3 + 4 + #include <linux/bitops.h> 5 + #include "../../../include/linux/perf_event.h" 6 + 7 + enum { 8 + PERF_PMU_FORMAT_VALUE_CONFIG, 9 + PERF_PMU_FORMAT_VALUE_CONFIG1, 10 + PERF_PMU_FORMAT_VALUE_CONFIG2, 11 + }; 12 + 13 + #define PERF_PMU_FORMAT_BITS 64 14 + 15 + struct perf_pmu__format { 16 + char *name; 17 + int value; 18 + DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 19 + struct list_head list; 20 + }; 21 + 22 + struct perf_pmu { 23 + char *name; 24 + __u32 type; 25 + struct list_head format; 26 + struct list_head list; 27 + }; 28 + 29 + struct perf_pmu *perf_pmu__find(char *name); 30 + int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 31 + struct list_head *head_terms); 32 + 33 + int perf_pmu_wrap(void); 34 + void perf_pmu_error(struct list_head *list, char *name, char const *msg); 35 + 36 + int perf_pmu__new_format(struct list_head *list, char *name, 37 + int config, unsigned long *bits); 38 + void perf_pmu__set_format(unsigned long *bits, long from, long to); 39 + 40 + int perf_pmu__test(void); 41 + #endif /* __PMU_H */
+43
tools/perf/util/pmu.l
··· 1 + %option prefix="perf_pmu_" 2 + 3 + %{ 4 + #include <stdlib.h> 5 + #include <linux/bitops.h> 6 + #include "pmu.h" 7 + #include "pmu-bison.h" 8 + 9 + static int value(int base) 10 + { 11 + long num; 12 + 13 + errno = 0; 14 + num = strtoul(perf_pmu_text, NULL, base); 15 + if (errno) 16 + return PP_ERROR; 17 + 18 + perf_pmu_lval.num = num; 19 + return PP_VALUE; 20 + } 21 + 22 + %} 23 + 24 + num_dec [0-9]+ 25 + 26 + %% 27 + 28 + {num_dec} { return value(10); } 29 + config { return PP_CONFIG; } 30 + config1 { return PP_CONFIG1; } 31 + config2 { return PP_CONFIG2; } 32 + - { return '-'; } 33 + : { return ':'; } 34 + , { return ','; } 35 + . { ; } 36 + \n { ; } 37 + 38 + %% 39 + 40 + int perf_pmu_wrap(void) 41 + { 42 + return 1; 43 + }
+93
tools/perf/util/pmu.y
··· 1 + 2 + %name-prefix "perf_pmu_" 3 + %parse-param {struct list_head *format} 4 + %parse-param {char *name} 5 + 6 + %{ 7 + 8 + #include <linux/compiler.h> 9 + #include <linux/list.h> 10 + #include <linux/bitmap.h> 11 + #include <string.h> 12 + #include "pmu.h" 13 + 14 + extern int perf_pmu_lex (void); 15 + 16 + #define ABORT_ON(val) \ 17 + do { \ 18 + if (val) \ 19 + YYABORT; \ 20 + } while (0) 21 + 22 + %} 23 + 24 + %token PP_CONFIG PP_CONFIG1 PP_CONFIG2 25 + %token PP_VALUE PP_ERROR 26 + %type <num> PP_VALUE 27 + %type <bits> bit_term 28 + %type <bits> bits 29 + 30 + %union 31 + { 32 + unsigned long num; 33 + DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 34 + } 35 + 36 + %% 37 + 38 + format: 39 + format format_term 40 + | 41 + format_term 42 + 43 + format_term: 44 + PP_CONFIG ':' bits 45 + { 46 + ABORT_ON(perf_pmu__new_format(format, name, 47 + PERF_PMU_FORMAT_VALUE_CONFIG, 48 + $3)); 49 + } 50 + | 51 + PP_CONFIG1 ':' bits 52 + { 53 + ABORT_ON(perf_pmu__new_format(format, name, 54 + PERF_PMU_FORMAT_VALUE_CONFIG1, 55 + $3)); 56 + } 57 + | 58 + PP_CONFIG2 ':' bits 59 + { 60 + ABORT_ON(perf_pmu__new_format(format, name, 61 + PERF_PMU_FORMAT_VALUE_CONFIG2, 62 + $3)); 63 + } 64 + 65 + bits: 66 + bits ',' bit_term 67 + { 68 + bitmap_or($$, $1, $3, 64); 69 + } 70 + | 71 + bit_term 72 + { 73 + memcpy($$, $1, sizeof($1)); 74 + } 75 + 76 + bit_term: 77 + PP_VALUE '-' PP_VALUE 78 + { 79 + perf_pmu__set_format($$, $1, $3); 80 + } 81 + | 82 + PP_VALUE 83 + { 84 + perf_pmu__set_format($$, $1, 0); 85 + } 86 + 87 + %% 88 + 89 + void perf_pmu_error(struct list_head *list __used, 90 + char *name __used, 91 + char const *msg __used) 92 + { 93 + }
+3 -1
tools/perf/util/probe-finder.c
··· 972 972 struct dwarf_callback_param *param = data; 973 973 struct probe_finder *pf = param->data; 974 974 struct perf_probe_point *pp = &pf->pev->point; 975 + Dwarf_Attribute attr; 975 976 976 977 /* Check tag and diename */ 977 978 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 978 - !die_compare_name(sp_die, pp->function)) 979 + !die_compare_name(sp_die, pp->function) || 980 + dwarf_attr(sp_die, DW_AT_declaration, &attr)) 979 981 return DWARF_CB_OK; 980 982 981 983 /* Check declared file */
+1
tools/perf/util/session.c
··· 140 140 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 141 141 INIT_LIST_HEAD(&self->ordered_samples.to_free); 142 142 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 143 + hists__init(&self->hists); 143 144 144 145 if (mode == O_RDONLY) { 145 146 if (perf_session__open(self, force) < 0)
+2 -1
tools/perf/util/symbol.c
··· 1 1 #include <dirent.h> 2 2 #include <errno.h> 3 - #include <libgen.h> 4 3 #include <stdlib.h> 5 4 #include <stdio.h> 6 5 #include <string.h> ··· 50 51 51 52 int dso__name_len(const struct dso *dso) 52 53 { 54 + if (!dso) 55 + return strlen("[unknown]"); 53 56 if (verbose) 54 57 return dso->long_name_len; 55 58
+4 -6
tools/perf/util/trace-event-parse.c
··· 722 722 static int event_read_id(void) 723 723 { 724 724 char *token; 725 - int id; 725 + int id = -1; 726 726 727 727 if (read_expected_item(EVENT_ITEM, "ID") < 0) 728 728 return -1; ··· 731 731 return -1; 732 732 733 733 if (read_expect_type(EVENT_ITEM, &token) < 0) 734 - goto fail; 734 + goto free; 735 735 736 736 id = strtoul(token, NULL, 0); 737 + 738 + free: 737 739 free_token(token); 738 740 return id; 739 - 740 - fail: 741 - free_token(token); 742 - return -1; 743 741 } 744 742 745 743 static int field_is_string(struct format_field *field)
+2
tools/perf/util/ui/browser.h
··· 49 49 const char *format, ...); 50 50 int ui_browser__help_window(struct ui_browser *browser, const char *text); 51 51 bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); 52 + int ui_browser__input_window(const char *title, const char *text, char *input, 53 + const char *exit_msg, int delay_sec); 52 54 53 55 void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); 54 56 unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
+13 -1
tools/perf/util/ui/browsers/hists.c
··· 879 879 char *options[16]; 880 880 int nr_options = 0; 881 881 int key = -1; 882 + char buf[64]; 882 883 883 884 if (browser == NULL) 884 885 return -1; ··· 934 933 goto zoom_dso; 935 934 case 't': 936 935 goto zoom_thread; 936 + case 's': 937 + if (ui_browser__input_window("Symbol to show", 938 + "Please enter the name of symbol you want to see", 939 + buf, "ENTER: OK, ESC: Cancel", 940 + delay_secs * 2) == K_ENTER) { 941 + self->symbol_filter_str = *buf ? buf : NULL; 942 + hists__filter_by_symbol(self); 943 + hist_browser__reset(browser); 944 + } 945 + continue; 937 946 case K_F1: 938 947 case 'h': 939 948 case '?': ··· 961 950 "C Collapse all callchains\n" 962 951 "E Expand all callchains\n" 963 952 "d Zoom into current DSO\n" 964 - "t Zoom into current Thread"); 953 + "t Zoom into current Thread\n" 954 + "s Filter symbol by name"); 965 955 continue; 966 956 case K_ENTER: 967 957 case K_RIGHT:
+2
tools/perf/util/ui/keysyms.h
··· 16 16 #define K_TAB '\t' 17 17 #define K_UNTAB SL_KEY_UNTAB 18 18 #define K_UP SL_KEY_UP 19 + #define K_BKSPC 0x7f 20 + #define K_DEL SL_KEY_DELETE 19 21 20 22 /* Not really keys */ 21 23 #define K_TIMER -1
+82
tools/perf/util/ui/util.c
··· 69 69 return popup_menu__run(&menu); 70 70 } 71 71 72 + int ui_browser__input_window(const char *title, const char *text, char *input, 73 + const char *exit_msg, int delay_secs) 74 + { 75 + int x, y, len, key; 76 + int max_len = 60, nr_lines = 0; 77 + static char buf[50]; 78 + const char *t; 79 + 80 + t = text; 81 + while (1) { 82 + const char *sep = strchr(t, '\n'); 83 + 84 + if (sep == NULL) 85 + sep = strchr(t, '\0'); 86 + len = sep - t; 87 + if (max_len < len) 88 + max_len = len; 89 + ++nr_lines; 90 + if (*sep == '\0') 91 + break; 92 + t = sep + 1; 93 + } 94 + 95 + max_len += 2; 96 + nr_lines += 8; 97 + y = SLtt_Screen_Rows / 2 - nr_lines / 2; 98 + x = SLtt_Screen_Cols / 2 - max_len / 2; 99 + 100 + SLsmg_set_color(0); 101 + SLsmg_draw_box(y, x++, nr_lines, max_len); 102 + if (title) { 103 + SLsmg_gotorc(y, x + 1); 104 + SLsmg_write_string((char *)title); 105 + } 106 + SLsmg_gotorc(++y, x); 107 + nr_lines -= 7; 108 + max_len -= 2; 109 + SLsmg_write_wrapped_string((unsigned char *)text, y, x, 110 + nr_lines, max_len, 1); 111 + y += nr_lines; 112 + len = 5; 113 + while (len--) { 114 + SLsmg_gotorc(y + len - 1, x); 115 + SLsmg_write_nstring((char *)" ", max_len); 116 + } 117 + SLsmg_draw_box(y++, x + 1, 3, max_len - 2); 118 + 119 + SLsmg_gotorc(y + 3, x); 120 + SLsmg_write_nstring((char *)exit_msg, max_len); 121 + SLsmg_refresh(); 122 + 123 + x += 2; 124 + len = 0; 125 + key = ui__getch(delay_secs); 126 + while (key != K_TIMER && key != K_ENTER && key != K_ESC) { 127 + if (key == K_BKSPC) { 128 + if (len == 0) 129 + goto next_key; 130 + SLsmg_gotorc(y, x + --len); 131 + SLsmg_write_char(' '); 132 + } else { 133 + buf[len] = key; 134 + SLsmg_gotorc(y, x + len++); 135 + SLsmg_write_char(key); 136 + } 137 + SLsmg_refresh(); 138 + 139 + /* XXX more graceful overflow handling needed */ 140 + if (len == sizeof(buf) - 1) { 141 + ui_helpline__push("maximum size of symbol name reached!"); 142 + key = K_ENTER; 143 + break; 144 + } 145 + next_key: 146 + key = ui__getch(delay_secs); 147 + } 148 + 149 + buf[len] = '\0'; 150 + strncpy(input, buf, len+1); 151 + return key; 152 + } 153 + 72 154 int ui__question_window(const char *title, const char *text, 73 155 const char *exit_msg, int delay_secs) 74 156 {