Pull perf updates from Ingo Molnar: "Bigger kernel side changes: - Add backwards writing capability to the perf ring-buffer code, which is preparation for future advanced features like robust 'overwrite support' and snapshot mode. (Wang Nan) - Add pause and resume ioctls for the perf ringbuffer (Wang Nan) - x86 Intel cstate code cleanups and reorgnization (Thomas Gleixner) - x86 Intel uncore and CPU PMU driver updates (Kan Liang, Peter Zijlstra) - x86 AUX (Intel PT) related enhancements and updates (Alexander Shishkin) - x86 MSR PMU driver enhancements and updates (Huang Rui) - ... and lots of other changes spread out over 40+ commits. Biggest tooling side changes: - 'perf trace' features and enhancements. (Arnaldo Carvalho de Melo) - BPF tooling updates (Wang Nan) - 'perf sched' updates (Jiri Olsa) - 'perf probe' updates (Masami Hiramatsu) - ... plus 200+ other enhancements, fixes and cleanups to tools/ The merge commits, the shortlog and the changelogs contain a lot more details" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (249 commits) perf/core: Disable the event on a truncated AUX record perf/x86/intel/pt: Generate PMI in the STOP region as well perf buildid-cache: Use lsdir() for looking up buildid caches perf symbols: Use lsdir() for the search in kcore cache directory perf tools: Use SBUILD_ID_SIZE where applicable perf tools: Fix lsdir to set errno correctly perf trace: Move seccomp args beautifiers to tools/perf/trace/beauty/ perf trace: Move flock op beautifier to tools/perf/trace/beauty/ perf build: Add build-test for debug-frame on arm/arm64 perf build: Add build-test for libunwind cross-platforms support perf script: Fix export of callchains with recursion in db-export perf script: Fix callchain addresses in db-export perf script: Fix symbol insertion behavior in db-export perf symbols: Add dso__insert_symbol function perf scripting python: Use Py_FatalError instead of die() perf tools: Remove xrealloc and ALLOC_GROW perf help: Do not use ALLOC_GROW in add_cmd_list perf pmu: Make pmu_formats_string to check return value of strbuf perf header: Make topology checkers to check return value of strbuf perf tools: Make alias handler to check return value of strbuf ...
Unified · Split
| @@ -60,6 +60,7 @@ show up in /proc/sys/kernel: · 59 unmodified lines | |||
| 60 | - panic_on_warn | 60 | - panic_on_warn |
| 61 | - perf_cpu_time_max_percent | 61 | - perf_cpu_time_max_percent |
| 62 | - perf_event_paranoid | 62 | - perf_event_paranoid |
| 63 | - perf_event_max_stack | ||
| 63 | - pid_max | 64 | - pid_max |
| 64 | - powersave-nap [ PPC only ] | 65 | - powersave-nap [ PPC only ] |
| 65 | - printk | 66 | - printk |
| @@ -654,6 +655,19 @@ users (without CAP_SYS_ADMIN). The default value is 2. · 588 unmodified lines | |||
| 654 | 655 | ||
| 655 | ============================================================== | 656 | ============================================================== |
| 656 | 657 | ||
| 658 | perf_event_max_stack: | ||
| 659 | |||
| 660 | Controls maximum number of stack frames to copy for (attr.sample_type & | ||
| 661 | PERF_SAMPLE_CALLCHAIN) configured events, for instance, when using | ||
| 662 | 'perf record -g' or 'perf trace --call-graph fp'. | ||
| 663 | |||
| 664 | This can only be done when no events are in use that have callchains | ||
| 665 | enabled, otherwise writing to this file will return -EBUSY. | ||
| 666 | |||
| 667 | The default value is 127. | ||
| 668 | |||
| 669 | ============================================================== | ||
| 670 | |||
| 657 | pid_max: | 671 | pid_max: |
| 658 | 672 | ||
| 659 | PID allocation wrap value. When the kernel's next PID value | 673 | PID allocation wrap value. When the kernel's next PID value |
| @@ -631,7 +631,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) · 630 unmodified lines | |||
| 631 | info->address &= ~alignment_mask; | 631 | info->address &= ~alignment_mask; |
| 632 | info->ctrl.len <<= offset; | 632 | info->ctrl.len <<= offset; |
| 633 | 633 | ||
| 634 | if (!bp->overflow_handler) { | 634 | if (is_default_overflow_handler(bp)) { |
| 635 | /* | 635 | /* |
| 636 | * Mismatch breakpoints are required for single-stepping | 636 | * Mismatch breakpoints are required for single-stepping |
| 637 | * breakpoints. | 637 | * breakpoints. |
| @@ -754,7 +754,7 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, · 116 unmodified lines | |||
| 754 | * mismatch breakpoint so we can single-step over the | 754 | * mismatch breakpoint so we can single-step over the |
| 755 | * watchpoint trigger. | 755 | * watchpoint trigger. |
| 756 | */ | 756 | */ |
| 757 | if (!wp->overflow_handler) | 757 | if (is_default_overflow_handler(wp)) |
| 758 | enable_single_step(wp, instruction_pointer(regs)); | 758 | enable_single_step(wp, instruction_pointer(regs)); |
| 759 | 759 | ||
| 760 | unlock: | 760 | unlock: |
| @@ -75,7 +75,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) · 74 unmodified lines | |||
| 75 | 75 | ||
| 76 | tail = (struct frame_tail __user *)regs->ARM_fp - 1; | 76 | tail = (struct frame_tail __user *)regs->ARM_fp - 1; |
| 77 | 77 | ||
| 78 | while ((entry->nr < PERF_MAX_STACK_DEPTH) && | 78 | while ((entry->nr < sysctl_perf_event_max_stack) && |
| 79 | tail && !((unsigned long)tail & 0x3)) | 79 | tail && !((unsigned long)tail & 0x3)) |
| 80 | tail = user_backtrace(tail, entry); | 80 | tail = user_backtrace(tail, entry); |
| 81 | } | 81 | } |
| @@ -616,7 +616,7 @@ static int breakpoint_handler(unsigned long unused, unsigned int esr, · 615 unmodified lines | |||
| 616 | perf_bp_event(bp, regs); | 616 | perf_bp_event(bp, regs); |
| 617 | 617 | ||
| 618 | /* Do we need to handle the stepping? */ | 618 | /* Do we need to handle the stepping? */ |
| 619 | if (!bp->overflow_handler) | 619 | if (is_default_overflow_handler(bp)) |
| 620 | step = 1; | 620 | step = 1; |
| 621 | unlock: | 621 | unlock: |
| 622 | rcu_read_unlock(); | 622 | rcu_read_unlock(); |
| @@ -712,7 +712,7 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr, · 89 unmodified lines | |||
| 712 | perf_bp_event(wp, regs); | 712 | perf_bp_event(wp, regs); |
| 713 | 713 | ||
| 714 | /* Do we need to handle the stepping? */ | 714 | /* Do we need to handle the stepping? */ |
| 715 | if (!wp->overflow_handler) | 715 | if (is_default_overflow_handler(wp)) |
| 716 | step = 1; | 716 | step = 1; |
| 717 | 717 | ||
| 718 | unlock: | 718 | unlock: |
| @@ -122,7 +122,7 @@ void perf_callchain_user(struct perf_callchain_entry *entry, · 121 unmodified lines | |||
| 122 | 122 | ||
| 123 | tail = (struct frame_tail __user *)regs->regs[29]; | 123 | tail = (struct frame_tail __user *)regs->regs[29]; |
| 124 | 124 | ||
| 125 | while (entry->nr < PERF_MAX_STACK_DEPTH && | 125 | while (entry->nr < sysctl_perf_event_max_stack && |
| 126 | tail && !((unsigned long)tail & 0xf)) | 126 | tail && !((unsigned long)tail & 0xf)) |
| 127 | tail = user_backtrace(tail, entry); | 127 | tail = user_backtrace(tail, entry); |
| 128 | } else { | 128 | } else { |
| @@ -132,7 +132,7 @@ void perf_callchain_user(struct perf_callchain_entry *entry, · 3 unmodified lines | |||
| 132 | 132 | ||
| 133 | tail = (struct compat_frame_tail __user *)regs->compat_fp - 1; | 133 | tail = (struct compat_frame_tail __user *)regs->compat_fp - 1; |
| 134 | 134 | ||
| 135 | while ((entry->nr < PERF_MAX_STACK_DEPTH) && | 135 | while ((entry->nr < sysctl_perf_event_max_stack) && |
| 136 | tail && !((unsigned long)tail & 0x3)) | 136 | tail && !((unsigned long)tail & 0x3)) |
| 137 | tail = compat_user_backtrace(tail, entry); | 137 | tail = compat_user_backtrace(tail, entry); |
| 138 | #endif | 138 | #endif |
| @@ -65,7 +65,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) · 64 unmodified lines | |||
| 65 | 65 | ||
| 66 | --frame; | 66 | --frame; |
| 67 | 67 | ||
| 68 | while ((entry->nr < PERF_MAX_STACK_DEPTH) && frame) | 68 | while ((entry->nr < sysctl_perf_event_max_stack) && frame) |
| 69 | frame = user_backtrace(frame, entry); | 69 | frame = user_backtrace(frame, entry); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| @@ -35,7 +35,7 @@ static void save_raw_perf_callchain(struct perf_callchain_entry *entry, · 34 unmodified lines | |||
| 35 | addr = *sp++; | 35 | addr = *sp++; |
| 36 | if (__kernel_text_address(addr)) { | 36 | if (__kernel_text_address(addr)) { |
| 37 | perf_callchain_store(entry, addr); | 37 | perf_callchain_store(entry, addr); |
| 38 | if (entry->nr >= PERF_MAX_STACK_DEPTH) | 38 | if (entry->nr >= sysctl_perf_event_max_stack) |
| 39 | break; | 39 | break; |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
| @@ -59,7 +59,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, · 17 unmodified lines | |||
| 59 | } | 59 | } |
| 60 | do { | 60 | do { |
| 61 | perf_callchain_store(entry, pc); | 61 | perf_callchain_store(entry, pc); |
| 62 | if (entry->nr >= PERF_MAX_STACK_DEPTH) | 62 | if (entry->nr >= sysctl_perf_event_max_stack) |
| 63 | break; | 63 | break; |
| 64 | pc = unwind_stack(current, &sp, pc, &ra); | 64 | pc = unwind_stack(current, &sp, pc, &ra); |
| 65 | } while (pc); | 65 | } while (pc); |
| @@ -247,7 +247,7 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, · 246 unmodified lines | |||
| 247 | sp = regs->gpr[1]; | 247 | sp = regs->gpr[1]; |
| 248 | perf_callchain_store(entry, next_ip); | 248 | perf_callchain_store(entry, next_ip); |
| 249 | 249 | ||
| 250 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 250 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 251 | fp = (unsigned long __user *) sp; | 251 | fp = (unsigned long __user *) sp; |
| 252 | if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp)) | 252 | if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp)) |
| 253 | return; | 253 | return; |
| @@ -453,7 +453,7 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, · 199 unmodified lines | |||
| 453 | sp = regs->gpr[1]; | 453 | sp = regs->gpr[1]; |
| 454 | perf_callchain_store(entry, next_ip); | 454 | perf_callchain_store(entry, next_ip); |
| 455 | 455 | ||
| 456 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 456 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 457 | fp = (unsigned int __user *) (unsigned long) sp; | 457 | fp = (unsigned int __user *) (unsigned long) sp; |
| 458 | if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp)) | 458 | if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp)) |
| 459 | return; | 459 | return; |
| @@ -1756,7 +1756,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, · 1755 unmodified lines | |||
| 1756 | } | 1756 | } |
| 1757 | } | 1757 | } |
| 1758 | #endif | 1758 | #endif |
| 1759 | } while (entry->nr < PERF_MAX_STACK_DEPTH); | 1759 | } while (entry->nr < sysctl_perf_event_max_stack); |
| 1760 | } | 1760 | } |
| 1761 | 1761 | ||
| 1762 | static inline int | 1762 | static inline int |
| @@ -1790,7 +1790,7 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, · 27 unmodified lines | |||
| 1790 | pc = sf.callers_pc; | 1790 | pc = sf.callers_pc; |
| 1791 | ufp = (unsigned long)sf.fp + STACK_BIAS; | 1791 | ufp = (unsigned long)sf.fp + STACK_BIAS; |
| 1792 | perf_callchain_store(entry, pc); | 1792 | perf_callchain_store(entry, pc); |
| 1793 | } while (entry->nr < PERF_MAX_STACK_DEPTH); | 1793 | } while (entry->nr < sysctl_perf_event_max_stack); |
| 1794 | } | 1794 | } |
| 1795 | 1795 | ||
| 1796 | static void perf_callchain_user_32(struct perf_callchain_entry *entry, | 1796 | static void perf_callchain_user_32(struct perf_callchain_entry *entry, |
| @@ -1822,7 +1822,7 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, · 25 unmodified lines | |||
| 1822 | ufp = (unsigned long)sf.fp; | 1822 | ufp = (unsigned long)sf.fp; |
| 1823 | } | 1823 | } |
| 1824 | perf_callchain_store(entry, pc); | 1824 | perf_callchain_store(entry, pc); |
| 1825 | } while (entry->nr < PERF_MAX_STACK_DEPTH); | 1825 | } while (entry->nr < sysctl_perf_event_max_stack); |
| 1826 | } | 1826 | } |
| 1827 | 1827 | ||
| 1828 | void | 1828 | void |
| @@ -164,10 +164,6 @@ config INSTRUCTION_DECODER · 163 unmodified lines | |||
| 164 | def_bool y | 164 | def_bool y |
| 165 | depends on KPROBES || PERF_EVENTS || UPROBES | 165 | depends on KPROBES || PERF_EVENTS || UPROBES |
| 166 | 166 | ||
| 167 | config PERF_EVENTS_INTEL_UNCORE | ||
| 168 | def_bool y | ||
| 169 | depends on PERF_EVENTS && CPU_SUP_INTEL && PCI | ||
| 170 | |||
| 171 | config OUTPUT_FORMAT | 167 | config OUTPUT_FORMAT |
| 172 | string | 168 | string |
| 173 | default "elf32-i386" if X86_32 | 169 | default "elf32-i386" if X86_32 |
| @@ -1046,6 +1042,8 @@ config X86_THERMAL_VECTOR · 872 unmodified lines | |||
| 1046 | def_bool y | 1042 | def_bool y |
| 1047 | depends on X86_MCE_INTEL | 1043 | depends on X86_MCE_INTEL |
| 1048 | 1044 | ||
| 1045 | source "arch/x86/events/Kconfig" | ||
| 1046 | |||
| 1049 | config X86_LEGACY_VM86 | 1047 | config X86_LEGACY_VM86 |
| 1050 | bool "Legacy VM86 support" | 1048 | bool "Legacy VM86 support" |
| 1051 | default n | 1049 | default n |
| @@ -1210,15 +1208,6 @@ config MICROCODE_OLD_INTERFACE · 158 unmodified lines | |||
| 1210 | def_bool y | 1208 | def_bool y |
| 1211 | depends on MICROCODE | 1209 | depends on MICROCODE |
| 1212 | 1210 | ||
| 1213 | config PERF_EVENTS_AMD_POWER | ||
| 1214 | depends on PERF_EVENTS && CPU_SUP_AMD | ||
| 1215 | tristate "AMD Processor Power Reporting Mechanism" | ||
| 1216 | ---help--- | ||
| 1217 | Provide power reporting mechanism support for AMD processors. | ||
| 1218 | Currently, it leverages X86_FEATURE_ACC_POWER | ||
| 1219 | (CPUID Fn8000_0007_EDX[12]) interface to calculate the | ||
| 1220 | average power consumption on Family 15h processors. | ||
| 1221 | |||
| 1222 | config X86_MSR | 1211 | config X86_MSR |
| 1223 | tristate "/dev/cpu/*/msr - Model-specific register support" | 1212 | tristate "/dev/cpu/*/msr - Model-specific register support" |
| 1224 | ---help--- | 1213 | ---help--- |
| @@ -0,0 +1,36 @@ | |||
| 1 | menu "Performance monitoring" | ||
| 2 | |||
| 3 | config PERF_EVENTS_INTEL_UNCORE | ||
| 4 | tristate "Intel uncore performance events" | ||
| 5 | depends on PERF_EVENTS && CPU_SUP_INTEL && PCI | ||
| 6 | default y | ||
| 7 | ---help--- | ||
| 8 | Include support for Intel uncore performance events. These are | ||
| 9 | available on NehalemEX and more modern processors. | ||
| 10 | |||
| 11 | config PERF_EVENTS_INTEL_RAPL | ||
| 12 | tristate "Intel rapl performance events" | ||
| 13 | depends on PERF_EVENTS && CPU_SUP_INTEL && PCI | ||
| 14 | default y | ||
| 15 | ---help--- | ||
| 16 | Include support for Intel rapl performance events for power | ||
| 17 | monitoring on modern processors. | ||
| 18 | |||
| 19 | config PERF_EVENTS_INTEL_CSTATE | ||
| 20 | tristate "Intel cstate performance events" | ||
| 21 | depends on PERF_EVENTS && CPU_SUP_INTEL && PCI | ||
| 22 | default y | ||
| 23 | ---help--- | ||
| 24 | Include support for Intel cstate performance events for power | ||
| 25 | monitoring on modern processors. | ||
| 26 | |||
| 27 | config PERF_EVENTS_AMD_POWER | ||
| 28 | depends on PERF_EVENTS && CPU_SUP_AMD | ||
| 29 | tristate "AMD Processor Power Reporting Mechanism" | ||
| 30 | ---help--- | ||
| 31 | Provide power reporting mechanism support for AMD processors. | ||
| 32 | Currently, it leverages X86_FEATURE_ACC_POWER | ||
| 33 | (CPUID Fn8000_0007_EDX[12]) interface to calculate the | ||
| 34 | average power consumption on Family 15h processors. | ||
| 35 | |||
| 36 | endmenu | ||
| @@ -6,9 +6,6 @@ obj-$(CONFIG_X86_LOCAL_APIC) += amd/ibs.o msr.o · 5 unmodified lines | |||
| 6 | ifdef CONFIG_AMD_IOMMU | 6 | ifdef CONFIG_AMD_IOMMU |
| 7 | obj-$(CONFIG_CPU_SUP_AMD) += amd/iommu.o | 7 | obj-$(CONFIG_CPU_SUP_AMD) += amd/iommu.o |
| 8 | endif | 8 | endif |
| 9 | obj-$(CONFIG_CPU_SUP_INTEL) += intel/core.o intel/bts.o intel/cqm.o | 9 | |
| 10 | obj-$(CONFIG_CPU_SUP_INTEL) += intel/cstate.o intel/ds.o intel/knc.o | 10 | obj-$(CONFIG_CPU_SUP_INTEL) += msr.o |
| 11 | obj-$(CONFIG_CPU_SUP_INTEL) += intel/lbr.o intel/p4.o intel/p6.o intel/pt.o | 11 | obj-$(CONFIG_CPU_SUP_INTEL) += intel/ |
| 12 | obj-$(CONFIG_CPU_SUP_INTEL) += intel/rapl.o msr.o | ||
| 13 | obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += intel/uncore.o intel/uncore_nhmex.o | ||
| 14 | obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += intel/uncore_snb.o intel/uncore_snbep.o | ||
| @@ -263,6 +263,7 @@ static const struct attribute_group *amd_uncore_attr_groups[] = { · 262 unmodified lines | |||
| 263 | }; | 263 | }; |
| 264 | 264 | ||
| 265 | static struct pmu amd_nb_pmu = { | 265 | static struct pmu amd_nb_pmu = { |
| 266 | .task_ctx_nr = perf_invalid_context, | ||
| 266 | .attr_groups = amd_uncore_attr_groups, | 267 | .attr_groups = amd_uncore_attr_groups, |
| 267 | .name = "amd_nb", | 268 | .name = "amd_nb", |
| 268 | .event_init = amd_uncore_event_init, | 269 | .event_init = amd_uncore_event_init, |
| @@ -274,6 +275,7 @@ static struct pmu amd_nb_pmu = { · 5 unmodified lines | |||
| 274 | }; | 275 | }; |
| 275 | 276 | ||
| 276 | static struct pmu amd_l2_pmu = { | 277 | static struct pmu amd_l2_pmu = { |
| 278 | .task_ctx_nr = perf_invalid_context, | ||
| 277 | .attr_groups = amd_uncore_attr_groups, | 279 | .attr_groups = amd_uncore_attr_groups, |
| 278 | .name = "amd_l2", | 280 | .name = "amd_l2", |
| 279 | .event_init = amd_uncore_event_init, | 281 | .event_init = amd_uncore_event_init, |
| @@ -360,6 +360,9 @@ int x86_add_exclusive(unsigned int what) · 359 unmodified lines | |||
| 360 | { | 360 | { |
| 361 | int i; | 361 | int i; |
| 362 | 362 | ||
| 363 | if (x86_pmu.lbr_pt_coexist) | ||
| 364 | return 0; | ||
| 365 | |||
| 363 | if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) { | 366 | if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) { |
| 364 | mutex_lock(&pmc_reserve_mutex); | 367 | mutex_lock(&pmc_reserve_mutex); |
| 365 | for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) { | 368 | for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) { |
| @@ -380,6 +383,9 @@ fail_unlock: · 14 unmodified lines | |||
| 380 | 383 | ||
| 381 | void x86_del_exclusive(unsigned int what) | 384 | void x86_del_exclusive(unsigned int what) |
| 382 | { | 385 | { |
| 386 | if (x86_pmu.lbr_pt_coexist) | ||
| 387 | return; | ||
| 388 | |||
| 383 | atomic_dec(&x86_pmu.lbr_exclusive[what]); | 389 | atomic_dec(&x86_pmu.lbr_exclusive[what]); |
| 384 | atomic_dec(&active_events); | 390 | atomic_dec(&active_events); |
| 385 | } | 391 | } |
| @@ -2277,7 +2283,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) · 1891 unmodified lines | |||
| 2277 | 2283 | ||
| 2278 | fp = compat_ptr(ss_base + regs->bp); | 2284 | fp = compat_ptr(ss_base + regs->bp); |
| 2279 | pagefault_disable(); | 2285 | pagefault_disable(); |
| 2280 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 2286 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 2281 | unsigned long bytes; | 2287 | unsigned long bytes; |
| 2282 | frame.next_frame = 0; | 2288 | frame.next_frame = 0; |
| 2283 | frame.return_address = 0; | 2289 | frame.return_address = 0; |
| @@ -2337,7 +2343,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) · 53 unmodified lines | |||
| 2337 | return; | 2343 | return; |
| 2338 | 2344 | ||
| 2339 | pagefault_disable(); | 2345 | pagefault_disable(); |
| 2340 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 2346 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 2341 | unsigned long bytes; | 2347 | unsigned long bytes; |
| 2342 | frame.next_frame = NULL; | 2348 | frame.next_frame = NULL; |
| 2343 | frame.return_address = 0; | 2349 | frame.return_address = 0; |
| @@ -0,0 +1,9 @@ | |||
| 1 | obj-$(CONFIG_CPU_SUP_INTEL) += core.o bts.o cqm.o | ||
| 2 | obj-$(CONFIG_CPU_SUP_INTEL) += ds.o knc.o | ||
| 3 | obj-$(CONFIG_CPU_SUP_INTEL) += lbr.o p4.o p6.o pt.o | ||
| 4 | obj-$(CONFIG_PERF_EVENTS_INTEL_RAPL) += intel-rapl.o | ||
| 5 | intel-rapl-objs := rapl.o | ||
| 6 | obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += intel-uncore.o | ||
| 7 | intel-uncore-objs := uncore.o uncore_nhmex.o uncore_snb.o uncore_snbep.o | ||
| 8 | obj-$(CONFIG_PERF_EVENTS_INTEL_CSTATE) += intel-cstate.o | ||
| 9 | intel-cstate-objs := cstate.o | ||
| @@ -171,18 +171,6 @@ static void bts_buffer_pad_out(struct bts_phys *phys, unsigned long head) · 170 unmodified lines | |||
| 171 | memset(page_address(phys->page) + index, 0, phys->size - index); | 171 | memset(page_address(phys->page) + index, 0, phys->size - index); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static bool bts_buffer_is_full(struct bts_buffer *buf, struct bts_ctx *bts) | ||
| 175 | { | ||
| 176 | if (buf->snapshot) | ||
| 177 | return false; | ||
| 178 | |||
| 179 | if (local_read(&buf->data_size) >= bts->handle.size || | ||
| 180 | bts->handle.size - local_read(&buf->data_size) < BTS_RECORD_SIZE) | ||
| 181 | return true; | ||
| 182 | |||
| 183 | return false; | ||
| 184 | } | ||
| 185 | |||
| 186 | static void bts_update(struct bts_ctx *bts) | 174 | static void bts_update(struct bts_ctx *bts) |
| 187 | { | 175 | { |
| 188 | int cpu = raw_smp_processor_id(); | 176 | int cpu = raw_smp_processor_id(); |
| @@ -213,18 +201,15 @@ static void bts_update(struct bts_ctx *bts) · 24 unmodified lines | |||
| 213 | } | 201 | } |
| 214 | } | 202 | } |
| 215 | 203 | ||
| 204 | static int | ||
| 205 | bts_buffer_reset(struct bts_buffer *buf, struct perf_output_handle *handle); | ||
| 206 | |||
| 216 | static void __bts_event_start(struct perf_event *event) | 207 | static void __bts_event_start(struct perf_event *event) |
| 217 | { | 208 | { |
| 218 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); | 209 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); |
| 219 | struct bts_buffer *buf = perf_get_aux(&bts->handle); | 210 | struct bts_buffer *buf = perf_get_aux(&bts->handle); |
| 220 | u64 config = 0; | 211 | u64 config = 0; |
| 221 | 212 | ||
| 222 | if (!buf || bts_buffer_is_full(buf, bts)) | ||
| 223 | return; | ||
| 224 | |||
| 225 | event->hw.itrace_started = 1; | ||
| 226 | event->hw.state = 0; | ||
| 227 | |||
| 228 | if (!buf->snapshot) | 213 | if (!buf->snapshot) |
| 229 | config |= ARCH_PERFMON_EVENTSEL_INT; | 214 | config |= ARCH_PERFMON_EVENTSEL_INT; |
| 230 | if (!event->attr.exclude_kernel) | 215 | if (!event->attr.exclude_kernel) |
| @@ -241,16 +226,41 @@ static void __bts_event_start(struct perf_event *event) · 10 unmodified lines | |||
| 241 | wmb(); | 226 | wmb(); |
| 242 | 227 | ||
| 243 | intel_pmu_enable_bts(config); | 228 | intel_pmu_enable_bts(config); |
| 229 | |||
| 244 | } | 230 | } |
| 245 | 231 | ||
| 246 | static void bts_event_start(struct perf_event *event, int flags) | 232 | static void bts_event_start(struct perf_event *event, int flags) |
| 247 | { | 233 | { |
| 234 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | ||
| 248 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); | 235 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); |
| 236 | struct bts_buffer *buf; | ||
| 237 | |||
| 238 | buf = perf_aux_output_begin(&bts->handle, event); | ||
| 239 | if (!buf) | ||
| 240 | goto fail_stop; | ||
| 241 | |||
| 242 | if (bts_buffer_reset(buf, &bts->handle)) | ||
| 243 | goto fail_end_stop; | ||
| 244 | |||
| 245 | bts->ds_back.bts_buffer_base = cpuc->ds->bts_buffer_base; | ||
| 246 | bts->ds_back.bts_absolute_maximum = cpuc->ds->bts_absolute_maximum; | ||
| 247 | bts->ds_back.bts_interrupt_threshold = cpuc->ds->bts_interrupt_threshold; | ||
| 248 | |||
| 249 | event->hw.itrace_started = 1; | ||
| 250 | event->hw.state = 0; | ||
| 249 | 251 | ||
| 250 | __bts_event_start(event); | 252 | __bts_event_start(event); |
| 251 | 253 | ||
| 252 | /* PMI handler: this counter is running and likely generating PMIs */ | 254 | /* PMI handler: this counter is running and likely generating PMIs */ |
| 253 | ACCESS_ONCE(bts->started) = 1; | 255 | ACCESS_ONCE(bts->started) = 1; |
| 256 | |||
| 257 | return; | ||
| 258 | |||
| 259 | fail_end_stop: | ||
| 260 | perf_aux_output_end(&bts->handle, 0, false); | ||
| 261 | |||
| 262 | fail_stop: | ||
| 263 | event->hw.state = PERF_HES_STOPPED; | ||
| 254 | } | 264 | } |
| 255 | 265 | ||
| 256 | static void __bts_event_stop(struct perf_event *event) | 266 | static void __bts_event_stop(struct perf_event *event) |
| @@ -269,15 +279,32 @@ static void __bts_event_stop(struct perf_event *event) · 12 unmodified lines | |||
| 269 | 279 | ||
| 270 | static void bts_event_stop(struct perf_event *event, int flags) | 280 | static void bts_event_stop(struct perf_event *event, int flags) |
| 271 | { | 281 | { |
| 282 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | ||
| 272 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); | 283 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); |
| 284 | struct bts_buffer *buf = perf_get_aux(&bts->handle); | ||
| 273 | 285 | ||
| 274 | /* PMI handler: don't restart this counter */ | 286 | /* PMI handler: don't restart this counter */ |
| 275 | ACCESS_ONCE(bts->started) = 0; | 287 | ACCESS_ONCE(bts->started) = 0; |
| 276 | 288 | ||
| 277 | __bts_event_stop(event); | 289 | __bts_event_stop(event); |
| 278 | 290 | ||
| 279 | if (flags & PERF_EF_UPDATE) | 291 | if (flags & PERF_EF_UPDATE) { |
| 280 | bts_update(bts); | 292 | bts_update(bts); |
| 293 | |||
| 294 | if (buf) { | ||
| 295 | if (buf->snapshot) | ||
| 296 | bts->handle.head = | ||
| 297 | local_xchg(&buf->data_size, | ||
| 298 | buf->nr_pages << PAGE_SHIFT); | ||
| 299 | perf_aux_output_end(&bts->handle, local_xchg(&buf->data_size, 0), | ||
| 300 | !!local_xchg(&buf->lost, 0)); | ||
| 301 | } | ||
| 302 | |||
| 303 | cpuc->ds->bts_index = bts->ds_back.bts_buffer_base; | ||
| 304 | cpuc->ds->bts_buffer_base = bts->ds_back.bts_buffer_base; | ||
| 305 | cpuc->ds->bts_absolute_maximum = bts->ds_back.bts_absolute_maximum; | ||
| 306 | cpuc->ds->bts_interrupt_threshold = bts->ds_back.bts_interrupt_threshold; | ||
| 307 | } | ||
| 281 | } | 308 | } |
| 282 | 309 | ||
| 283 | void intel_bts_enable_local(void) | 310 | void intel_bts_enable_local(void) |
| @@ -417,34 +444,14 @@ int intel_bts_interrupt(void) · 133 unmodified lines | |||
| 417 | 444 | ||
| 418 | static void bts_event_del(struct perf_event *event, int mode) | 445 | static void bts_event_del(struct perf_event *event, int mode) |
| 419 | { | 446 | { |
| 420 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | ||
| 421 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); | ||
| 422 | struct bts_buffer *buf = perf_get_aux(&bts->handle); | ||
| 423 | |||
| 424 | bts_event_stop(event, PERF_EF_UPDATE); | 447 | bts_event_stop(event, PERF_EF_UPDATE); |
| 425 | |||
| 426 | if (buf) { | ||
| 427 | if (buf->snapshot) | ||
| 428 | bts->handle.head = | ||
| 429 | local_xchg(&buf->data_size, | ||
| 430 | buf->nr_pages << PAGE_SHIFT); | ||
| 431 | perf_aux_output_end(&bts->handle, local_xchg(&buf->data_size, 0), | ||
| 432 | !!local_xchg(&buf->lost, 0)); | ||
| 433 | } | ||
| 434 | |||
| 435 | cpuc->ds->bts_index = bts->ds_back.bts_buffer_base; | ||
| 436 | cpuc->ds->bts_buffer_base = bts->ds_back.bts_buffer_base; | ||
| 437 | cpuc->ds->bts_absolute_maximum = bts->ds_back.bts_absolute_maximum; | ||
| 438 | cpuc->ds->bts_interrupt_threshold = bts->ds_back.bts_interrupt_threshold; | ||
| 439 | } | 448 | } |
| 440 | 449 | ||
| 441 | static int bts_event_add(struct perf_event *event, int mode) | 450 | static int bts_event_add(struct perf_event *event, int mode) |
| 442 | { | 451 | { |
| 443 | struct bts_buffer *buf; | ||
| 444 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); | 452 | struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); |
| 445 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); | 453 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
| 446 | struct hw_perf_event *hwc = &event->hw; | 454 | struct hw_perf_event *hwc = &event->hw; |
| 447 | int ret = -EBUSY; | ||
| 448 | 455 | ||
| 449 | event->hw.state = PERF_HES_STOPPED; | 456 | event->hw.state = PERF_HES_STOPPED; |
| 450 | 457 | ||
| @@ -454,26 +461,10 @@ static int bts_event_add(struct perf_event *event, int mode) · 3 unmodified lines | |||
| 454 | if (bts->handle.event) | 461 | if (bts->handle.event) |
| 455 | return -EBUSY; | 462 | return -EBUSY; |
| 456 | 463 | ||
| 457 | buf = perf_aux_output_begin(&bts->handle, event); | ||
| 458 | if (!buf) | ||
| 459 | return -EINVAL; | ||
| 460 | |||
| 461 | ret = bts_buffer_reset(buf, &bts->handle); | ||
| 462 | if (ret) { | ||
| 463 | perf_aux_output_end(&bts->handle, 0, false); | ||
| 464 | return ret; | ||
| 465 | } | ||
| 466 | |||
| 467 | bts->ds_back.bts_buffer_base = cpuc->ds->bts_buffer_base; | ||
| 468 | bts->ds_back.bts_absolute_maximum = cpuc->ds->bts_absolute_maximum; | ||
| 469 | bts->ds_back.bts_interrupt_threshold = cpuc->ds->bts_interrupt_threshold; | ||
| 470 | |||
| 471 | if (mode & PERF_EF_START) { | 464 | if (mode & PERF_EF_START) { |
| 472 | bts_event_start(event, 0); | 465 | bts_event_start(event, 0); |
| 473 | if (hwc->state & PERF_HES_STOPPED) { | 466 | if (hwc->state & PERF_HES_STOPPED) |
| 474 | bts_event_del(event, 0); | 467 | return -EINVAL; |
| 475 | return -EBUSY; | ||
| 476 | } | ||
| 477 | } | 468 | } |
| 478 | 469 | ||
| 479 | return 0; | 470 | return 0; |
| @@ -1465,6 +1465,140 @@ static __initconst const u64 slm_hw_cache_event_ids · 1464 unmodified lines | |||
| 1465 | }, | 1465 | }, |
| 1466 | }; | 1466 | }; |
| 1467 | 1467 | ||
| 1468 | static struct extra_reg intel_glm_extra_regs[] __read_mostly = { | ||
| 1469 | /* must define OFFCORE_RSP_X first, see intel_fixup_er() */ | ||
| 1470 | INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x760005ffbfull, RSP_0), | ||
| 1471 | INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0x360005ffbfull, RSP_1), | ||
| 1472 | EVENT_EXTRA_END | ||
| 1473 | }; | ||
| 1474 | |||
| 1475 | #define GLM_DEMAND_DATA_RD BIT_ULL(0) | ||
| 1476 | #define GLM_DEMAND_RFO BIT_ULL(1) | ||
| 1477 | #define GLM_ANY_RESPONSE BIT_ULL(16) | ||
| 1478 | #define GLM_SNP_NONE_OR_MISS BIT_ULL(33) | ||
| 1479 | #define GLM_DEMAND_READ GLM_DEMAND_DATA_RD | ||
| 1480 | #define GLM_DEMAND_WRITE GLM_DEMAND_RFO | ||
| 1481 | #define GLM_DEMAND_PREFETCH (SNB_PF_DATA_RD|SNB_PF_RFO) | ||
| 1482 | #define GLM_LLC_ACCESS GLM_ANY_RESPONSE | ||
| 1483 | #define GLM_SNP_ANY (GLM_SNP_NONE_OR_MISS|SNB_NO_FWD|SNB_HITM) | ||
| 1484 | #define GLM_LLC_MISS (GLM_SNP_ANY|SNB_NON_DRAM) | ||
| 1485 | |||
| 1486 | static __initconst const u64 glm_hw_cache_event_ids | ||
| 1487 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 1488 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 1489 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
| 1490 | [C(L1D)] = { | ||
| 1491 | [C(OP_READ)] = { | ||
| 1492 | [C(RESULT_ACCESS)] = 0x81d0, /* MEM_UOPS_RETIRED.ALL_LOADS */ | ||
| 1493 | [C(RESULT_MISS)] = 0x0, | ||
| 1494 | }, | ||
| 1495 | [C(OP_WRITE)] = { | ||
| 1496 | [C(RESULT_ACCESS)] = 0x82d0, /* MEM_UOPS_RETIRED.ALL_STORES */ | ||
| 1497 | [C(RESULT_MISS)] = 0x0, | ||
| 1498 | }, | ||
| 1499 | [C(OP_PREFETCH)] = { | ||
| 1500 | [C(RESULT_ACCESS)] = 0x0, | ||
| 1501 | [C(RESULT_MISS)] = 0x0, | ||
| 1502 | }, | ||
| 1503 | }, | ||
| 1504 | [C(L1I)] = { | ||
| 1505 | [C(OP_READ)] = { | ||
| 1506 | [C(RESULT_ACCESS)] = 0x0380, /* ICACHE.ACCESSES */ | ||
| 1507 | [C(RESULT_MISS)] = 0x0280, /* ICACHE.MISSES */ | ||
| 1508 | }, | ||
| 1509 | [C(OP_WRITE)] = { | ||
| 1510 | [C(RESULT_ACCESS)] = -1, | ||
| 1511 | [C(RESULT_MISS)] = -1, | ||
| 1512 | }, | ||
| 1513 | [C(OP_PREFETCH)] = { | ||
| 1514 | [C(RESULT_ACCESS)] = 0x0, | ||
| 1515 | [C(RESULT_MISS)] = 0x0, | ||
| 1516 | }, | ||
| 1517 | }, | ||
| 1518 | [C(LL)] = { | ||
| 1519 | [C(OP_READ)] = { | ||
| 1520 | [C(RESULT_ACCESS)] = 0x1b7, /* OFFCORE_RESPONSE */ | ||
| 1521 | [C(RESULT_MISS)] = 0x1b7, /* OFFCORE_RESPONSE */ | ||
| 1522 | }, | ||
| 1523 | [C(OP_WRITE)] = { | ||
| 1524 | [C(RESULT_ACCESS)] = 0x1b7, /* OFFCORE_RESPONSE */ | ||
| 1525 | [C(RESULT_MISS)] = 0x1b7, /* OFFCORE_RESPONSE */ | ||
| 1526 | }, | ||
| 1527 | [C(OP_PREFETCH)] = { | ||
| 1528 | [C(RESULT_ACCESS)] = 0x1b7, /* OFFCORE_RESPONSE */ | ||
| 1529 | [C(RESULT_MISS)] = 0x1b7, /* OFFCORE_RESPONSE */ | ||
| 1530 | }, | ||
| 1531 | }, | ||
| 1532 | [C(DTLB)] = { | ||
| 1533 | [C(OP_READ)] = { | ||
| 1534 | [C(RESULT_ACCESS)] = 0x81d0, /* MEM_UOPS_RETIRED.ALL_LOADS */ | ||
| 1535 | [C(RESULT_MISS)] = 0x0, | ||
| 1536 | }, | ||
| 1537 | [C(OP_WRITE)] = { | ||
| 1538 | [C(RESULT_ACCESS)] = 0x82d0, /* MEM_UOPS_RETIRED.ALL_STORES */ | ||
| 1539 | [C(RESULT_MISS)] = 0x0, | ||
| 1540 | }, | ||
| 1541 | [C(OP_PREFETCH)] = { | ||
| 1542 | [C(RESULT_ACCESS)] = 0x0, | ||
| 1543 | [C(RESULT_MISS)] = 0x0, | ||
| 1544 | }, | ||
| 1545 | }, | ||
| 1546 | [C(ITLB)] = { | ||
| 1547 | [C(OP_READ)] = { | ||
| 1548 | [C(RESULT_ACCESS)] = 0x00c0, /* INST_RETIRED.ANY_P */ | ||
| 1549 | [C(RESULT_MISS)] = 0x0481, /* ITLB.MISS */ | ||
| 1550 | }, | ||
| 1551 | [C(OP_WRITE)] = { | ||
| 1552 | [C(RESULT_ACCESS)] = -1, | ||
| 1553 | [C(RESULT_MISS)] = -1, | ||
| 1554 | }, | ||
| 1555 | [C(OP_PREFETCH)] = { | ||
| 1556 | [C(RESULT_ACCESS)] = -1, | ||
| 1557 | [C(RESULT_MISS)] = -1, | ||
| 1558 | }, | ||
| 1559 | }, | ||
| 1560 | [C(BPU)] = { | ||
| 1561 | [C(OP_READ)] = { | ||
| 1562 | [C(RESULT_ACCESS)] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */ | ||
| 1563 | [C(RESULT_MISS)] = 0x00c5, /* BR_MISP_RETIRED.ALL_BRANCHES */ | ||
| 1564 | }, | ||
| 1565 | [C(OP_WRITE)] = { | ||
| 1566 | [C(RESULT_ACCESS)] = -1, | ||
| 1567 | [C(RESULT_MISS)] = -1, | ||
| 1568 | }, | ||
| 1569 | [C(OP_PREFETCH)] = { | ||
| 1570 | [C(RESULT_ACCESS)] = -1, | ||
| 1571 | [C(RESULT_MISS)] = -1, | ||
| 1572 | }, | ||
| 1573 | }, | ||
| 1574 | }; | ||
| 1575 | |||
| 1576 | static __initconst const u64 glm_hw_cache_extra_regs | ||
| 1577 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 1578 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 1579 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
| 1580 | [C(LL)] = { | ||
| 1581 | [C(OP_READ)] = { | ||
| 1582 | [C(RESULT_ACCESS)] = GLM_DEMAND_READ| | ||
| 1583 | GLM_LLC_ACCESS, | ||
| 1584 | [C(RESULT_MISS)] = GLM_DEMAND_READ| | ||
| 1585 | GLM_LLC_MISS, | ||
| 1586 | }, | ||
| 1587 | [C(OP_WRITE)] = { | ||
| 1588 | [C(RESULT_ACCESS)] = GLM_DEMAND_WRITE| | ||
| 1589 | GLM_LLC_ACCESS, | ||
| 1590 | [C(RESULT_MISS)] = GLM_DEMAND_WRITE| | ||
| 1591 | GLM_LLC_MISS, | ||
| 1592 | }, | ||
| 1593 | [C(OP_PREFETCH)] = { | ||
| 1594 | [C(RESULT_ACCESS)] = GLM_DEMAND_PREFETCH| | ||
| 1595 | GLM_LLC_ACCESS, | ||
| 1596 | [C(RESULT_MISS)] = GLM_DEMAND_PREFETCH| | ||
| 1597 | GLM_LLC_MISS, | ||
| 1598 | }, | ||
| 1599 | }, | ||
| 1600 | }; | ||
| 1601 | |||
| 1468 | #define KNL_OT_L2_HITE BIT_ULL(19) /* Other Tile L2 Hit */ | 1602 | #define KNL_OT_L2_HITE BIT_ULL(19) /* Other Tile L2 Hit */ |
| 1469 | #define KNL_OT_L2_HITF BIT_ULL(20) /* Other Tile L2 Hit */ | 1603 | #define KNL_OT_L2_HITF BIT_ULL(20) /* Other Tile L2 Hit */ |
| 1470 | #define KNL_MCDRAM_LOCAL BIT_ULL(21) | 1604 | #define KNL_MCDRAM_LOCAL BIT_ULL(21) |
| @@ -3447,7 +3581,7 @@ __init int intel_pmu_init(void) · 1976 unmodified lines | |||
| 3447 | memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs, | 3581 | memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs, |
| 3448 | sizeof(hw_cache_extra_regs)); | 3582 | sizeof(hw_cache_extra_regs)); |
| 3449 | 3583 | ||
| 3450 | intel_pmu_lbr_init_atom(); | 3584 | intel_pmu_lbr_init_slm(); |
| 3451 | 3585 | ||
| 3452 | x86_pmu.event_constraints = intel_slm_event_constraints; | 3586 | x86_pmu.event_constraints = intel_slm_event_constraints; |
| 3453 | x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints; | 3587 | x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints; |
| @@ -3456,6 +3590,30 @@ __init int intel_pmu_init(void) · 2 unmodified lines | |||
| 3456 | pr_cont("Silvermont events, "); | 3590 | pr_cont("Silvermont events, "); |
| 3457 | break; | 3591 | break; |
| 3458 | 3592 | ||
| 3593 | case 92: /* 14nm Atom "Goldmont" */ | ||
| 3594 | case 95: /* 14nm Atom "Goldmont Denverton" */ | ||
| 3595 | memcpy(hw_cache_event_ids, glm_hw_cache_event_ids, | ||
| 3596 | sizeof(hw_cache_event_ids)); | ||
| 3597 | memcpy(hw_cache_extra_regs, glm_hw_cache_extra_regs, | ||
| 3598 | sizeof(hw_cache_extra_regs)); | ||
| 3599 | |||
| 3600 | intel_pmu_lbr_init_skl(); | ||
| 3601 | |||
| 3602 | x86_pmu.event_constraints = intel_slm_event_constraints; | ||
| 3603 | x86_pmu.pebs_constraints = intel_glm_pebs_event_constraints; | ||
| 3604 | x86_pmu.extra_regs = intel_glm_extra_regs; | ||
| 3605 | /* | ||
| 3606 | * It's recommended to use CPU_CLK_UNHALTED.CORE_P + NPEBS | ||
| 3607 | * for precise cycles. | ||
| 3608 | * :pp is identical to :ppp | ||
| 3609 | */ | ||
| 3610 | x86_pmu.pebs_aliases = NULL; | ||
| 3611 | x86_pmu.pebs_prec_dist = true; | ||
| 3612 | x86_pmu.lbr_pt_coexist = true; | ||
| 3613 | x86_pmu.flags |= PMU_FL_HAS_RSP_1; | ||
| 3614 | pr_cont("Goldmont events, "); | ||
| 3615 | break; | ||
| 3616 | |||
| 3459 | case 37: /* 32nm Westmere */ | 3617 | case 37: /* 32nm Westmere */ |
| 3460 | case 44: /* 32nm Westmere-EP */ | 3618 | case 44: /* 32nm Westmere-EP */ |
| 3461 | case 47: /* 32nm Westmere-EX */ | 3619 | case 47: /* 32nm Westmere-EX */ |
| @@ -91,6 +91,8 @@ · 90 unmodified lines | |||
| 91 | #include <asm/cpu_device_id.h> | 91 | #include <asm/cpu_device_id.h> |
| 92 | #include "../perf_event.h" | 92 | #include "../perf_event.h" |
| 93 | 93 | ||
| 94 | MODULE_LICENSE("GPL"); | ||
| 95 | |||
| 94 | #define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format) \ | 96 | #define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format) \ |
| 95 | static ssize_t __cstate_##_var##_show(struct kobject *kobj, \ | 97 | static ssize_t __cstate_##_var##_show(struct kobject *kobj, \ |
| 96 | struct kobj_attribute *attr, \ | 98 | struct kobj_attribute *attr, \ |
| @@ -106,22 +108,27 @@ static ssize_t cstate_get_attr_cpumask(struct device *dev, · 9 unmodified lines | |||
| 106 | struct device_attribute *attr, | 108 | struct device_attribute *attr, |
| 107 | char *buf); | 109 | char *buf); |
| 108 | 110 | ||
| 111 | /* Model -> events mapping */ | ||
| 112 | struct cstate_model { | ||
| 113 | unsigned long core_events; | ||
| 114 | unsigned long pkg_events; | ||
| 115 | unsigned long quirks; | ||
| 116 | }; | ||
| 117 | |||
| 118 | /* Quirk flags */ | ||
| 119 | #define SLM_PKG_C6_USE_C7_MSR (1UL << 0) | ||
| 120 | |||
| 109 | struct perf_cstate_msr { | 121 | struct perf_cstate_msr { |
| 110 | u64 msr; | 122 | u64 msr; |
| 111 | struct perf_pmu_events_attr *attr; | 123 | struct perf_pmu_events_attr *attr; |
| 112 | bool (*test)(int idx); | ||
| 113 | }; | 124 | }; |
| 114 | 125 | ||
| 115 | 126 | ||
| 116 | /* cstate_core PMU */ | 127 | /* cstate_core PMU */ |
| 117 | |||
| 118 | static struct pmu cstate_core_pmu; | 128 | static struct pmu cstate_core_pmu; |
| 119 | static bool has_cstate_core; | 129 | static bool has_cstate_core; |
| 120 | 130 | ||
| 121 | enum perf_cstate_core_id { | 131 | enum perf_cstate_core_events { |
| 122 | /* | ||
| 123 | * cstate_core events | ||
| 124 | */ | ||
| 125 | PERF_CSTATE_CORE_C1_RES = 0, | 132 | PERF_CSTATE_CORE_C1_RES = 0, |
| 126 | PERF_CSTATE_CORE_C3_RES, | 133 | PERF_CSTATE_CORE_C3_RES, |
| 127 | PERF_CSTATE_CORE_C6_RES, | 134 | PERF_CSTATE_CORE_C6_RES, |
| @@ -130,69 +137,16 @@ enum perf_cstate_core_id { · 2 unmodified lines | |||
| 130 | PERF_CSTATE_CORE_EVENT_MAX, | 137 | PERF_CSTATE_CORE_EVENT_MAX, |
| 131 | }; | 138 | }; |
| 132 | 139 | ||
| 133 | bool test_core(int idx) | ||
| 134 | { | ||
| 135 | if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || | ||
| 136 | boot_cpu_data.x86 != 6) | ||
| 137 | return false; | ||
| 138 | |||
| 139 | switch (boot_cpu_data.x86_model) { | ||
| 140 | case 30: /* 45nm Nehalem */ | ||
| 141 | case 26: /* 45nm Nehalem-EP */ | ||
| 142 | case 46: /* 45nm Nehalem-EX */ | ||
| 143 | |||
| 144 | case 37: /* 32nm Westmere */ | ||
| 145 | case 44: /* 32nm Westmere-EP */ | ||
| 146 | case 47: /* 32nm Westmere-EX */ | ||
| 147 | if (idx == PERF_CSTATE_CORE_C3_RES || | ||
| 148 | idx == PERF_CSTATE_CORE_C6_RES) | ||
| 149 | return true; | ||
| 150 | break; | ||
| 151 | case 42: /* 32nm SandyBridge */ | ||
| 152 | case 45: /* 32nm SandyBridge-E/EN/EP */ | ||
| 153 | |||
| 154 | case 58: /* 22nm IvyBridge */ | ||
| 155 | case 62: /* 22nm IvyBridge-EP/EX */ | ||
| 156 | |||
| 157 | case 60: /* 22nm Haswell Core */ | ||
| 158 | case 63: /* 22nm Haswell Server */ | ||
| 159 | case 69: /* 22nm Haswell ULT */ | ||
| 160 | case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ | ||
| 161 | |||
| 162 | case 61: /* 14nm Broadwell Core-M */ | ||
| 163 | case 86: /* 14nm Broadwell Xeon D */ | ||
| 164 | case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ | ||
| 165 | case 79: /* 14nm Broadwell Server */ | ||
| 166 | |||
| 167 | case 78: /* 14nm Skylake Mobile */ | ||
| 168 | case 94: /* 14nm Skylake Desktop */ | ||
| 169 | if (idx == PERF_CSTATE_CORE_C3_RES || | ||
| 170 | idx == PERF_CSTATE_CORE_C6_RES || | ||
| 171 | idx == PERF_CSTATE_CORE_C7_RES) | ||
| 172 | return true; | ||
| 173 | break; | ||
| 174 | case 55: /* 22nm Atom "Silvermont" */ | ||
| 175 | case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ | ||
| 176 | case 76: /* 14nm Atom "Airmont" */ | ||
| 177 | if (idx == PERF_CSTATE_CORE_C1_RES || | ||
| 178 | idx == PERF_CSTATE_CORE_C6_RES) | ||
| 179 | return true; | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | |||
| 183 | return false; | ||
| 184 | } | ||
| 185 | |||
| 186 | PMU_EVENT_ATTR_STRING(c1-residency, evattr_cstate_core_c1, "event=0x00"); | 140 | PMU_EVENT_ATTR_STRING(c1-residency, evattr_cstate_core_c1, "event=0x00"); |
| 187 | PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_core_c3, "event=0x01"); | 141 | PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_core_c3, "event=0x01"); |
| 188 | PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_core_c6, "event=0x02"); | 142 | PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_core_c6, "event=0x02"); |
| 189 | PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_core_c7, "event=0x03"); | 143 | PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_core_c7, "event=0x03"); |
| 190 | 144 | ||
| 191 | static struct perf_cstate_msr core_msr[] = { | 145 | static struct perf_cstate_msr core_msr[] = { |
| 192 | [PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &evattr_cstate_core_c1, test_core, }, | 146 | [PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &evattr_cstate_core_c1 }, |
| 193 | [PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &evattr_cstate_core_c3, test_core, }, | 147 | [PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &evattr_cstate_core_c3 }, |
| 194 | [PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &evattr_cstate_core_c6, test_core, }, | 148 | [PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &evattr_cstate_core_c6 }, |
| 195 | [PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &evattr_cstate_core_c7, test_core, }, | 149 | [PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &evattr_cstate_core_c7 }, |
| 196 | }; | 150 | }; |
| 197 | 151 | ||
| 198 | static struct attribute *core_events_attrs[PERF_CSTATE_CORE_EVENT_MAX + 1] = { | 152 | static struct attribute *core_events_attrs[PERF_CSTATE_CORE_EVENT_MAX + 1] = { |
| @@ -234,18 +188,11 @@ static const struct attribute_group *core_attr_groups[] = { · 35 unmodified lines | |||
| 234 | NULL, | 188 | NULL, |
| 235 | }; | 189 | }; |
| 236 | 190 | ||
| 237 | /* cstate_core PMU end */ | ||
| 238 | |||
| 239 | |||
| 240 | /* cstate_pkg PMU */ | 191 | /* cstate_pkg PMU */ |
| 241 | |||
| 242 | static struct pmu cstate_pkg_pmu; | 192 | static struct pmu cstate_pkg_pmu; |
| 243 | static bool has_cstate_pkg; | 193 | static bool has_cstate_pkg; |
| 244 | 194 | ||
| 245 | enum perf_cstate_pkg_id { | 195 | enum perf_cstate_pkg_events { |
| 246 | /* | ||
| 247 | * cstate_pkg events | ||
| 248 | */ | ||
| 249 | PERF_CSTATE_PKG_C2_RES = 0, | 196 | PERF_CSTATE_PKG_C2_RES = 0, |
| 250 | PERF_CSTATE_PKG_C3_RES, | 197 | PERF_CSTATE_PKG_C3_RES, |
| 251 | PERF_CSTATE_PKG_C6_RES, | 198 | PERF_CSTATE_PKG_C6_RES, |
| @@ -257,69 +204,6 @@ enum perf_cstate_pkg_id { · 5 unmodified lines | |||
| 257 | PERF_CSTATE_PKG_EVENT_MAX, | 204 | PERF_CSTATE_PKG_EVENT_MAX, |
| 258 | }; | 205 | }; |
| 259 | 206 | ||
| 260 | bool test_pkg(int idx) | ||
| 261 | { | ||
| 262 | if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || | ||
| 263 | boot_cpu_data.x86 != 6) | ||
| 264 | return false; | ||
| 265 | |||
| 266 | switch (boot_cpu_data.x86_model) { | ||
| 267 | case 30: /* 45nm Nehalem */ | ||
| 268 | case 26: /* 45nm Nehalem-EP */ | ||
| 269 | case 46: /* 45nm Nehalem-EX */ | ||
| 270 | |||
| 271 | case 37: /* 32nm Westmere */ | ||
| 272 | case 44: /* 32nm Westmere-EP */ | ||
| 273 | case 47: /* 32nm Westmere-EX */ | ||
| 274 | if (idx == PERF_CSTATE_CORE_C3_RES || | ||
| 275 | idx == PERF_CSTATE_CORE_C6_RES || | ||
| 276 | idx == PERF_CSTATE_CORE_C7_RES) | ||
| 277 | return true; | ||
| 278 | break; | ||
| 279 | case 42: /* 32nm SandyBridge */ | ||
| 280 | case 45: /* 32nm SandyBridge-E/EN/EP */ | ||
| 281 | |||
| 282 | case 58: /* 22nm IvyBridge */ | ||
| 283 | case 62: /* 22nm IvyBridge-EP/EX */ | ||
| 284 | |||
| 285 | case 60: /* 22nm Haswell Core */ | ||
| 286 | case 63: /* 22nm Haswell Server */ | ||
| 287 | case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ | ||
| 288 | |||
| 289 | case 61: /* 14nm Broadwell Core-M */ | ||
| 290 | case 86: /* 14nm Broadwell Xeon D */ | ||
| 291 | case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ | ||
| 292 | case 79: /* 14nm Broadwell Server */ | ||
| 293 | |||
| 294 | case 78: /* 14nm Skylake Mobile */ | ||
| 295 | case 94: /* 14nm Skylake Desktop */ | ||
| 296 | if (idx == PERF_CSTATE_PKG_C2_RES || | ||
| 297 | idx == PERF_CSTATE_PKG_C3_RES || | ||
| 298 | idx == PERF_CSTATE_PKG_C6_RES || | ||
| 299 | idx == PERF_CSTATE_PKG_C7_RES) | ||
| 300 | return true; | ||
| 301 | break; | ||
| 302 | case 55: /* 22nm Atom "Silvermont" */ | ||
| 303 | case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ | ||
| 304 | case 76: /* 14nm Atom "Airmont" */ | ||
| 305 | if (idx == PERF_CSTATE_CORE_C6_RES) | ||
| 306 | return true; | ||
| 307 | break; | ||
| 308 | case 69: /* 22nm Haswell ULT */ | ||
| 309 | if (idx == PERF_CSTATE_PKG_C2_RES || | ||
| 310 | idx == PERF_CSTATE_PKG_C3_RES || | ||
| 311 | idx == PERF_CSTATE_PKG_C6_RES || | ||
| 312 | idx == PERF_CSTATE_PKG_C7_RES || | ||
| 313 | idx == PERF_CSTATE_PKG_C8_RES || | ||
| 314 | idx == PERF_CSTATE_PKG_C9_RES || | ||
| 315 | idx == PERF_CSTATE_PKG_C10_RES) | ||
| 316 | return true; | ||
| 317 | break; | ||
| 318 | } | ||
| 319 | |||
| 320 | return false; | ||
| 321 | } | ||
| 322 | |||
| 323 | PMU_EVENT_ATTR_STRING(c2-residency, evattr_cstate_pkg_c2, "event=0x00"); | 207 | PMU_EVENT_ATTR_STRING(c2-residency, evattr_cstate_pkg_c2, "event=0x00"); |
| 324 | PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_pkg_c3, "event=0x01"); | 208 | PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_pkg_c3, "event=0x01"); |
| 325 | PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_pkg_c6, "event=0x02"); | 209 | PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_pkg_c6, "event=0x02"); |
| @@ -329,13 +213,13 @@ PMU_EVENT_ATTR_STRING(c9-residency, evattr_cstate_pkg_c9, "event=0x05"); · 3 unmodified lines | |||
| 329 | PMU_EVENT_ATTR_STRING(c10-residency, evattr_cstate_pkg_c10, "event=0x06"); | 213 | PMU_EVENT_ATTR_STRING(c10-residency, evattr_cstate_pkg_c10, "event=0x06"); |
| 330 | 214 | ||
| 331 | static struct perf_cstate_msr pkg_msr[] = { | 215 | static struct perf_cstate_msr pkg_msr[] = { |
| 332 | [PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &evattr_cstate_pkg_c2, test_pkg, }, | 216 | [PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &evattr_cstate_pkg_c2 }, |
| 333 | [PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &evattr_cstate_pkg_c3, test_pkg, }, | 217 | [PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &evattr_cstate_pkg_c3 }, |
| 334 | [PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &evattr_cstate_pkg_c6, test_pkg, }, | 218 | [PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &evattr_cstate_pkg_c6 }, |
| 335 | [PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &evattr_cstate_pkg_c7, test_pkg, }, | 219 | [PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &evattr_cstate_pkg_c7 }, |
| 336 | [PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &evattr_cstate_pkg_c8, test_pkg, }, | 220 | [PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &evattr_cstate_pkg_c8 }, |
| 337 | [PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &evattr_cstate_pkg_c9, test_pkg, }, | 221 | [PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &evattr_cstate_pkg_c9 }, |
| 338 | [PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &evattr_cstate_pkg_c10, test_pkg, }, | 222 | [PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &evattr_cstate_pkg_c10 }, |
| 339 | }; | 223 | }; |
| 340 | 224 | ||
| 341 | static struct attribute *pkg_events_attrs[PERF_CSTATE_PKG_EVENT_MAX + 1] = { | 225 | static struct attribute *pkg_events_attrs[PERF_CSTATE_PKG_EVENT_MAX + 1] = { |
| @@ -366,8 +250,6 @@ static const struct attribute_group *pkg_attr_groups[] = { · 24 unmodified lines | |||
| 366 | NULL, | 250 | NULL, |
| 367 | }; | 251 | }; |
| 368 | 252 | ||
| 369 | /* cstate_pkg PMU end*/ | ||
| 370 | |||
| 371 | static ssize_t cstate_get_attr_cpumask(struct device *dev, | 253 | static ssize_t cstate_get_attr_cpumask(struct device *dev, |
| 372 | struct device_attribute *attr, | 254 | struct device_attribute *attr, |
| 373 | char *buf) | 255 | char *buf) |
| @@ -385,7 +267,7 @@ static ssize_t cstate_get_attr_cpumask(struct device *dev, · 11 unmodified lines | |||
| 385 | static int cstate_pmu_event_init(struct perf_event *event) | 267 | static int cstate_pmu_event_init(struct perf_event *event) |
| 386 | { | 268 | { |
| 387 | u64 cfg = event->attr.config; | 269 | u64 cfg = event->attr.config; |
| 388 | int ret = 0; | 270 | int cpu; |
| 389 | 271 | ||
| 390 | if (event->attr.type != event->pmu->type) | 272 | if (event->attr.type != event->pmu->type) |
| 391 | return -ENOENT; | 273 | return -ENOENT; |
| @@ -400,26 +282,36 @@ static int cstate_pmu_event_init(struct perf_event *event) · 8 unmodified lines | |||
| 400 | event->attr.sample_period) /* no sampling */ | 282 | event->attr.sample_period) /* no sampling */ |
| 401 | return -EINVAL; | 283 | return -EINVAL; |
| 402 | 284 | ||
| 285 | if (event->cpu < 0) | ||
| 286 | return -EINVAL; | ||
| 287 | |||
| 403 | if (event->pmu == &cstate_core_pmu) { | 288 | if (event->pmu == &cstate_core_pmu) { |
| 404 | if (cfg >= PERF_CSTATE_CORE_EVENT_MAX) | 289 | if (cfg >= PERF_CSTATE_CORE_EVENT_MAX) |
| 405 | return -EINVAL; | 290 | return -EINVAL; |
| 406 | if (!core_msr[cfg].attr) | 291 | if (!core_msr[cfg].attr) |
| 407 | return -EINVAL; | 292 | return -EINVAL; |
| 408 | event->hw.event_base = core_msr[cfg].msr; | 293 | event->hw.event_base = core_msr[cfg].msr; |
| 294 | cpu = cpumask_any_and(&cstate_core_cpu_mask, | ||
| 295 | topology_sibling_cpumask(event->cpu)); | ||
| 409 | } else if (event->pmu == &cstate_pkg_pmu) { | 296 | } else if (event->pmu == &cstate_pkg_pmu) { |
| 410 | if (cfg >= PERF_CSTATE_PKG_EVENT_MAX) | 297 | if (cfg >= PERF_CSTATE_PKG_EVENT_MAX) |
| 411 | return -EINVAL; | 298 | return -EINVAL; |
| 412 | if (!pkg_msr[cfg].attr) | 299 | if (!pkg_msr[cfg].attr) |
| 413 | return -EINVAL; | 300 | return -EINVAL; |
| 414 | event->hw.event_base = pkg_msr[cfg].msr; | 301 | event->hw.event_base = pkg_msr[cfg].msr; |
| 415 | } else | 302 | cpu = cpumask_any_and(&cstate_pkg_cpu_mask, |
| 303 | topology_core_cpumask(event->cpu)); | ||
| 304 | } else { | ||
| 416 | return -ENOENT; | 305 | return -ENOENT; |
| 306 | } | ||
| 307 | |||
| 308 | if (cpu >= nr_cpu_ids) | ||
| 309 | return -ENODEV; | ||
| 417 | 310 | ||
| 418 | /* must be done before validate_group */ | 311 | event->cpu = cpu; |
| 419 | event->hw.config = cfg; | 312 | event->hw.config = cfg; |
| 420 | event->hw.idx = -1; | 313 | event->hw.idx = -1; |
| 421 | 314 | return 0; | |
| 422 | return ret; | ||
| 423 | } | 315 | } |
| 424 | 316 | ||
| 425 | static inline u64 cstate_pmu_read_counter(struct perf_event *event) | 317 | static inline u64 cstate_pmu_read_counter(struct perf_event *event) |
| @@ -469,172 +361,91 @@ static int cstate_pmu_event_add(struct perf_event *event, int mode) · 43 unmodified lines | |||
| 469 | return 0; | 361 | return 0; |
| 470 | } | 362 | } |
| 471 | 363 | ||
| 364 | /* | ||
| 365 | * Check if exiting cpu is the designated reader. If so migrate the | ||
| 366 | * events when there is a valid target available | ||
| 367 | */ | ||
| 472 | static void cstate_cpu_exit(int cpu) | 368 | static void cstate_cpu_exit(int cpu) |
| 473 | { | 369 | { |
| 474 | int i, id, target; | 370 | unsigned int target; |
| 475 | 371 | ||
| 476 | /* cpu exit for cstate core */ | 372 | if (has_cstate_core && |
| 477 | if (has_cstate_core) { | 373 | cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask)) { |
| 478 | id = topology_core_id(cpu); | 374 | |
| 479 | target = -1; | 375 | target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu); |
| 480 | 376 | /* Migrate events if there is a valid target */ | |
| 481 | for_each_online_cpu(i) { | 377 | if (target < nr_cpu_ids) { |
| 482 | if (i == cpu) | ||
| 483 | continue; | ||
| 484 | if (id == topology_core_id(i)) { | ||
| 485 | target = i; | ||
| 486 | break; | ||
| 487 | } | ||
| 488 | } | ||
| 489 | if (cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask) && target >= 0) | ||
| 490 | cpumask_set_cpu(target, &cstate_core_cpu_mask); | 378 | cpumask_set_cpu(target, &cstate_core_cpu_mask); |
| 491 | WARN_ON(cpumask_empty(&cstate_core_cpu_mask)); | ||
| 492 | if (target >= 0) | ||
| 493 | perf_pmu_migrate_context(&cstate_core_pmu, cpu, target); | 379 | perf_pmu_migrate_context(&cstate_core_pmu, cpu, target); |
| 380 | } | ||
| 494 | } | 381 | } |
| 495 | 382 | ||
| 496 | /* cpu exit for cstate pkg */ | 383 | if (has_cstate_pkg && |
| 497 | if (has_cstate_pkg) { | 384 | cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) { |
| 498 | id = topology_physical_package_id(cpu); | 385 | |
| 499 | target = -1; | 386 | target = cpumask_any_but(topology_core_cpumask(cpu), cpu); |
| 500 | 387 | /* Migrate events if there is a valid target */ | |
| 501 | for_each_online_cpu(i) { | 388 | if (target < nr_cpu_ids) { |
| 502 | if (i == cpu) | ||
| 503 | continue; | ||
| 504 | if (id == topology_physical_package_id(i)) { | ||
| 505 | target = i; | ||
| 506 | break; | ||
| 507 | } | ||
| 508 | } | ||
| 509 | if (cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask) && target >= 0) | ||
| 510 | cpumask_set_cpu(target, &cstate_pkg_cpu_mask); | 389 | cpumask_set_cpu(target, &cstate_pkg_cpu_mask); |
| 511 | WARN_ON(cpumask_empty(&cstate_pkg_cpu_mask)); | ||
| 512 | if (target >= 0) | ||
| 513 | perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target); | 390 | perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target); |
| 391 | } | ||
| 514 | } | 392 | } |
| 515 | } | 393 | } |
| 516 | 394 | ||
| 517 | static void cstate_cpu_init(int cpu) | 395 | static void cstate_cpu_init(int cpu) |
| 518 | { | 396 | { |
| 519 | int i, id; | 397 | unsigned int target; |
| 520 | 398 | ||
| 521 | /* cpu init for cstate core */ | 399 | /* |
| 522 | if (has_cstate_core) { | 400 | * If this is the first online thread of that core, set it in |
| 523 | id = topology_core_id(cpu); | 401 | * the core cpu mask as the designated reader. |
| 524 | for_each_cpu(i, &cstate_core_cpu_mask) { | 402 | */ |
| 525 | if (id == topology_core_id(i)) | 403 | target = cpumask_any_and(&cstate_core_cpu_mask, |
| 526 | break; | 404 | topology_sibling_cpumask(cpu)); |
| 527 | } | ||
| 528 | if (i >= nr_cpu_ids) | ||
| 529 | cpumask_set_cpu(cpu, &cstate_core_cpu_mask); | ||
| 530 | } | ||
| 531 | 405 | ||
| 532 | /* cpu init for cstate pkg */ | 406 | if (has_cstate_core && target >= nr_cpu_ids) |
| 533 | if (has_cstate_pkg) { | 407 | cpumask_set_cpu(cpu, &cstate_core_cpu_mask); |
| 534 | id = topology_physical_package_id(cpu); | 408 | |
| 535 | for_each_cpu(i, &cstate_pkg_cpu_mask) { | 409 | /* |
| 536 | if (id == topology_physical_package_id(i)) | 410 | * If this is the first online thread of that package, set it |
| 537 | break; | 411 | * in the package cpu mask as the designated reader. |
| 538 | } | 412 | */ |
| 539 | if (i >= nr_cpu_ids) | 413 | target = cpumask_any_and(&cstate_pkg_cpu_mask, |
| 540 | cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask); | 414 | topology_core_cpumask(cpu)); |
| 541 | } | 415 | if (has_cstate_pkg && target >= nr_cpu_ids) |
| 416 | cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask); | ||
| 542 | } | 417 | } |
| 543 | 418 | ||
| 544 | static int cstate_cpu_notifier(struct notifier_block *self, | 419 | static int cstate_cpu_notifier(struct notifier_block *self, |
| 545 | unsigned long action, void *hcpu) | 420 | unsigned long action, void *hcpu) |
| 546 | { | 421 | { |
| 547 | unsigned int cpu = (long)hcpu; | 422 | unsigned int cpu = (long)hcpu; |
| 548 | 423 | ||
| 549 | switch (action & ~CPU_TASKS_FROZEN) { | 424 | switch (action & ~CPU_TASKS_FROZEN) { |
| 550 | case CPU_UP_PREPARE: | ||
| 551 | break; | ||
| 552 | case CPU_STARTING: | 425 | case CPU_STARTING: |
| 553 | cstate_cpu_init(cpu); | 426 | cstate_cpu_init(cpu); |
| 554 | break; | 427 | break; |
| 555 | case CPU_UP_CANCELED: | ||
| 556 | case CPU_DYING: | ||
| 557 | break; | ||
| 558 | case CPU_ONLINE: | ||
| 559 | case CPU_DEAD: | ||
| 560 | break; | ||
| 561 | case CPU_DOWN_PREPARE: | 428 | case CPU_DOWN_PREPARE: |
| 562 | cstate_cpu_exit(cpu); | 429 | cstate_cpu_exit(cpu); |
| 563 | break; | 430 | break; |
| 564 | default: | 431 | default: |
| 565 | break; | 432 | break; |
| 566 | } | 433 | } |
| 567 | |||
| 568 | return NOTIFY_OK; | 434 | return NOTIFY_OK; |
| 569 | } | 435 | } |
| 570 | 436 | ||
| 571 | /* | 437 | static struct notifier_block cstate_cpu_nb = { |
| 572 | * Probe the cstate events and insert the available one into sysfs attrs | 438 | .notifier_call = cstate_cpu_notifier, |
| 573 | * Return false if there is no available events. | 439 | .priority = CPU_PRI_PERF + 1, |
| 574 | */ | 440 | }; |
| 575 | static bool cstate_probe_msr(struct perf_cstate_msr *msr, | ||
| 576 | struct attribute **events_attrs, | ||
| 577 | int max_event_nr) | ||
| 578 | { | ||
| 579 | int i, j = 0; | ||
| 580 | u64 val; | ||
| 581 | |||
| 582 | /* Probe the cstate events. */ | ||
| 583 | for (i = 0; i < max_event_nr; i++) { | ||
| 584 | if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val)) | ||
| 585 | msr[i].attr = NULL; | ||
| 586 | } | ||
| 587 | |||
| 588 | /* List remaining events in the sysfs attrs. */ | ||
| 589 | for (i = 0; i < max_event_nr; i++) { | ||
| 590 | if (msr[i].attr) | ||
| 591 | events_attrs[j++] = &msr[i].attr->attr.attr; | ||
| 592 | } | ||
| 593 | events_attrs[j] = NULL; | ||
| 594 | |||
| 595 | return (j > 0) ? true : false; | ||
| 596 | } | ||
| 597 | |||
| 598 | static int __init cstate_init(void) | ||
| 599 | { | ||
| 600 | /* SLM has different MSR for PKG C6 */ | ||
| 601 | switch (boot_cpu_data.x86_model) { | ||
| 602 | case 55: | ||
| 603 | case 76: | ||
| 604 | case 77: | ||
| 605 | pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY; | ||
| 606 | } | ||
| 607 | |||
| 608 | if (cstate_probe_msr(core_msr, core_events_attrs, PERF_CSTATE_CORE_EVENT_MAX)) | ||
| 609 | has_cstate_core = true; | ||
| 610 | |||
| 611 | if (cstate_probe_msr(pkg_msr, pkg_events_attrs, PERF_CSTATE_PKG_EVENT_MAX)) | ||
| 612 | has_cstate_pkg = true; | ||
| 613 | |||
| 614 | return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV; | ||
| 615 | } | ||
| 616 | |||
| 617 | static void __init cstate_cpumask_init(void) | ||
| 618 | { | ||
| 619 | int cpu; | ||
| 620 | |||
| 621 | cpu_notifier_register_begin(); | ||
| 622 | |||
| 623 | for_each_online_cpu(cpu) | ||
| 624 | cstate_cpu_init(cpu); | ||
| 625 | |||
| 626 | __perf_cpu_notifier(cstate_cpu_notifier); | ||
| 627 | |||
| 628 | cpu_notifier_register_done(); | ||
| 629 | } | ||
| 630 | 441 | ||
| 631 | static struct pmu cstate_core_pmu = { | 442 | static struct pmu cstate_core_pmu = { |
| 632 | .attr_groups = core_attr_groups, | 443 | .attr_groups = core_attr_groups, |
| 633 | .name = "cstate_core", | 444 | .name = "cstate_core", |
| 634 | .task_ctx_nr = perf_invalid_context, | 445 | .task_ctx_nr = perf_invalid_context, |
| 635 | .event_init = cstate_pmu_event_init, | 446 | .event_init = cstate_pmu_event_init, |
| 636 | .add = cstate_pmu_event_add, /* must have */ | 447 | .add = cstate_pmu_event_add, |
| 637 | .del = cstate_pmu_event_del, /* must have */ | 448 | .del = cstate_pmu_event_del, |
| 638 | .start = cstate_pmu_event_start, | 449 | .start = cstate_pmu_event_start, |
| 639 | .stop = cstate_pmu_event_stop, | 450 | .stop = cstate_pmu_event_stop, |
| 640 | .read = cstate_pmu_event_update, | 451 | .read = cstate_pmu_event_update, |
| @@ -646,49 +457,203 @@ static struct pmu cstate_pkg_pmu = { · 5 unmodified lines | |||
| 646 | .name = "cstate_pkg", | 457 | .name = "cstate_pkg", |
| 647 | .task_ctx_nr = perf_invalid_context, | 458 | .task_ctx_nr = perf_invalid_context, |
| 648 | .event_init = cstate_pmu_event_init, | 459 | .event_init = cstate_pmu_event_init, |
| 649 | .add = cstate_pmu_event_add, /* must have */ | 460 | .add = cstate_pmu_event_add, |
| 650 | .del = cstate_pmu_event_del, /* must have */ | 461 | .del = cstate_pmu_event_del, |
| 651 | .start = cstate_pmu_event_start, | 462 | .start = cstate_pmu_event_start, |
| 652 | .stop = cstate_pmu_event_stop, | 463 | .stop = cstate_pmu_event_stop, |
| 653 | .read = cstate_pmu_event_update, | 464 | .read = cstate_pmu_event_update, |
| 654 | .capabilities = PERF_PMU_CAP_NO_INTERRUPT, | 465 | .capabilities = PERF_PMU_CAP_NO_INTERRUPT, |
| 655 | }; | 466 | }; |
| 656 | 467 | ||
| 657 | static void __init cstate_pmus_register(void) | 468 | static const struct cstate_model nhm_cstates __initconst = { |
| 469 | .core_events = BIT(PERF_CSTATE_CORE_C3_RES) | | ||
| 470 | BIT(PERF_CSTATE_CORE_C6_RES), | ||
| 471 | |||
| 472 | .pkg_events = BIT(PERF_CSTATE_PKG_C3_RES) | | ||
| 473 | BIT(PERF_CSTATE_PKG_C6_RES) | | ||
| 474 | BIT(PERF_CSTATE_PKG_C7_RES), | ||
| 475 | }; | ||
| 476 | |||
| 477 | static const struct cstate_model snb_cstates __initconst = { | ||
| 478 | .core_events = BIT(PERF_CSTATE_CORE_C3_RES) | | ||
| 479 | BIT(PERF_CSTATE_CORE_C6_RES) | | ||
| 480 | BIT(PERF_CSTATE_CORE_C7_RES), | ||
| 481 | |||
| 482 | .pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) | | ||
| 483 | BIT(PERF_CSTATE_PKG_C3_RES) | | ||
| 484 | BIT(PERF_CSTATE_PKG_C6_RES) | | ||
| 485 | BIT(PERF_CSTATE_PKG_C7_RES), | ||
| 486 | }; | ||
| 487 | |||
| 488 | static const struct cstate_model hswult_cstates __initconst = { | ||
| 489 | .core_events = BIT(PERF_CSTATE_CORE_C3_RES) | | ||
| 490 | BIT(PERF_CSTATE_CORE_C6_RES) | | ||
| 491 | BIT(PERF_CSTATE_CORE_C7_RES), | ||
| 492 | |||
| 493 | .pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) | | ||
| 494 | BIT(PERF_CSTATE_PKG_C3_RES) | | ||
| 495 | BIT(PERF_CSTATE_PKG_C6_RES) | | ||
| 496 | BIT(PERF_CSTATE_PKG_C7_RES) | | ||
| 497 | BIT(PERF_CSTATE_PKG_C8_RES) | | ||
| 498 | BIT(PERF_CSTATE_PKG_C9_RES) | | ||
| 499 | BIT(PERF_CSTATE_PKG_C10_RES), | ||
| 500 | }; | ||
| 501 | |||
| 502 | static const struct cstate_model slm_cstates __initconst = { | ||
| 503 | .core_events = BIT(PERF_CSTATE_CORE_C1_RES) | | ||
| 504 | BIT(PERF_CSTATE_CORE_C6_RES), | ||
| 505 | |||
| 506 | .pkg_events = BIT(PERF_CSTATE_PKG_C6_RES), | ||
| 507 | .quirks = SLM_PKG_C6_USE_C7_MSR, | ||
| 508 | }; | ||
| 509 | |||
| 510 | #define X86_CSTATES_MODEL(model, states) \ | ||
| 511 | { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long) &(states) } | ||
| 512 | |||
| 513 | static const struct x86_cpu_id intel_cstates_match[] __initconst = { | ||
| 514 | X86_CSTATES_MODEL(30, nhm_cstates), /* 45nm Nehalem */ | ||
| 515 | X86_CSTATES_MODEL(26, nhm_cstates), /* 45nm Nehalem-EP */ | ||
| 516 | X86_CSTATES_MODEL(46, nhm_cstates), /* 45nm Nehalem-EX */ | ||
| 517 | |||
| 518 | X86_CSTATES_MODEL(37, nhm_cstates), /* 32nm Westmere */ | ||
| 519 | X86_CSTATES_MODEL(44, nhm_cstates), /* 32nm Westmere-EP */ | ||
| 520 | X86_CSTATES_MODEL(47, nhm_cstates), /* 32nm Westmere-EX */ | ||
| 521 | |||
| 522 | X86_CSTATES_MODEL(42, snb_cstates), /* 32nm SandyBridge */ | ||
| 523 | X86_CSTATES_MODEL(45, snb_cstates), /* 32nm SandyBridge-E/EN/EP */ | ||
| 524 | |||
| 525 | X86_CSTATES_MODEL(58, snb_cstates), /* 22nm IvyBridge */ | ||
| 526 | X86_CSTATES_MODEL(62, snb_cstates), /* 22nm IvyBridge-EP/EX */ | ||
| 527 | |||
| 528 | X86_CSTATES_MODEL(60, snb_cstates), /* 22nm Haswell Core */ | ||
| 529 | X86_CSTATES_MODEL(63, snb_cstates), /* 22nm Haswell Server */ | ||
| 530 | X86_CSTATES_MODEL(70, snb_cstates), /* 22nm Haswell + GT3e */ | ||
| 531 | |||
| 532 | X86_CSTATES_MODEL(69, hswult_cstates), /* 22nm Haswell ULT */ | ||
| 533 | |||
| 534 | X86_CSTATES_MODEL(55, slm_cstates), /* 22nm Atom Silvermont */ | ||
| 535 | X86_CSTATES_MODEL(77, slm_cstates), /* 22nm Atom Avoton/Rangely */ | ||
| 536 | X86_CSTATES_MODEL(76, slm_cstates), /* 22nm Atom Airmont */ | ||
| 537 | |||
| 538 | X86_CSTATES_MODEL(61, snb_cstates), /* 14nm Broadwell Core-M */ | ||
| 539 | X86_CSTATES_MODEL(86, snb_cstates), /* 14nm Broadwell Xeon D */ | ||
| 540 | X86_CSTATES_MODEL(71, snb_cstates), /* 14nm Broadwell + GT3e */ | ||
| 541 | X86_CSTATES_MODEL(79, snb_cstates), /* 14nm Broadwell Server */ | ||
| 542 | |||
| 543 | X86_CSTATES_MODEL(78, snb_cstates), /* 14nm Skylake Mobile */ | ||
| 544 | X86_CSTATES_MODEL(94, snb_cstates), /* 14nm Skylake Desktop */ | ||
| 545 | { }, | ||
| 546 | }; | ||
| 547 | MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match); | ||
| 548 | |||
| 549 | /* | ||
| 550 | * Probe the cstate events and insert the available one into sysfs attrs | ||
| 551 | * Return false if there are no available events. | ||
| 552 | */ | ||
| 553 | static bool __init cstate_probe_msr(const unsigned long evmsk, int max, | ||
| 554 | struct perf_cstate_msr *msr, | ||
| 555 | struct attribute **attrs) | ||
| 658 | { | 556 | { |
| 659 | int err; | 557 | bool found = false; |
| 558 | unsigned int bit; | ||
| 559 | u64 val; | ||
| 560 | |||
| 561 | for (bit = 0; bit < max; bit++) { | ||
| 562 | if (test_bit(bit, &evmsk) && !rdmsrl_safe(msr[bit].msr, &val)) { | ||
| 563 | *attrs++ = &msr[bit].attr->attr.attr; | ||
| 564 | found = true; | ||
| 565 | } else { | ||
| 566 | msr[bit].attr = NULL; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | *attrs = NULL; | ||
| 570 | |||
| 571 | return found; | ||
| 572 | } | ||
| 573 | |||
| 574 | static int __init cstate_probe(const struct cstate_model *cm) | ||
| 575 | { | ||
| 576 | /* SLM has different MSR for PKG C6 */ | ||
| 577 | if (cm->quirks & SLM_PKG_C6_USE_C7_MSR) | ||
| 578 | pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY; | ||
| 579 | |||
| 580 | has_cstate_core = cstate_probe_msr(cm->core_events, | ||
| 581 | PERF_CSTATE_CORE_EVENT_MAX, | ||
| 582 | core_msr, core_events_attrs); | ||
| 583 | |||
| 584 | has_cstate_pkg = cstate_probe_msr(cm->pkg_events, | ||
| 585 | PERF_CSTATE_PKG_EVENT_MAX, | ||
| 586 | pkg_msr, pkg_events_attrs); | ||
| 587 | |||
| 588 | return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV; | ||
| 589 | } | ||
| 590 | |||
| 591 | static inline void cstate_cleanup(void) | ||
| 592 | { | ||
| 593 | if (has_cstate_core) | ||
| 594 | perf_pmu_unregister(&cstate_core_pmu); | ||
| 595 | |||
| 596 | if (has_cstate_pkg) | ||
| 597 | perf_pmu_unregister(&cstate_pkg_pmu); | ||
| 598 | } | ||
| 599 | |||
| 600 | static int __init cstate_init(void) | ||
| 601 | { | ||
| 602 | int cpu, err; | ||
| 603 | |||
| 604 | cpu_notifier_register_begin(); | ||
| 605 | for_each_online_cpu(cpu) | ||
| 606 | cstate_cpu_init(cpu); | ||
| 660 | 607 | ||
| 661 | if (has_cstate_core) { | 608 | if (has_cstate_core) { |
| 662 | err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1); | 609 | err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1); |
| 663 | if (WARN_ON(err)) | 610 | if (err) { |
| 664 | pr_info("Failed to register PMU %s error %d\n", | 611 | has_cstate_core = false; |
| 665 | cstate_core_pmu.name, err); | 612 | pr_info("Failed to register cstate core pmu\n"); |
| 613 | goto out; | ||
| 614 | } | ||
| 666 | } | 615 | } |
| 667 | 616 | ||
| 668 | if (has_cstate_pkg) { | 617 | if (has_cstate_pkg) { |
| 669 | err = perf_pmu_register(&cstate_pkg_pmu, cstate_pkg_pmu.name, -1); | 618 | err = perf_pmu_register(&cstate_pkg_pmu, cstate_pkg_pmu.name, -1); |
| 670 | if (WARN_ON(err)) | 619 | if (err) { |
| 671 | pr_info("Failed to register PMU %s error %d\n", | 620 | has_cstate_pkg = false; |
| 672 | cstate_pkg_pmu.name, err); | 621 | pr_info("Failed to register cstate pkg pmu\n"); |
| 622 | cstate_cleanup(); | ||
| 623 | goto out; | ||
| 624 | } | ||
| 673 | } | 625 | } |
| 626 | __register_cpu_notifier(&cstate_cpu_nb); | ||
| 627 | out: | ||
| 628 | cpu_notifier_register_done(); | ||
| 629 | return err; | ||
| 674 | } | 630 | } |
| 675 | 631 | ||
| 676 | static int __init cstate_pmu_init(void) | 632 | static int __init cstate_pmu_init(void) |
| 677 | { | 633 | { |
| 634 | const struct x86_cpu_id *id; | ||
| 678 | int err; | 635 | int err; |
| 679 | 636 | ||
| 680 | if (cpu_has_hypervisor) | 637 | if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) |
| 638 | return -ENODEV; | ||
| 639 | |||
| 640 | id = x86_match_cpu(intel_cstates_match); | ||
| 641 | if (!id) | ||
| 681 | return -ENODEV; | 642 | return -ENODEV; |
| 682 | 643 | ||
| 683 | err = cstate_init(); | 644 | err = cstate_probe((const struct cstate_model *) id->driver_data); |
| 684 | if (err) | 645 | if (err) |
| 685 | return err; | 646 | return err; |
| 686 | 647 | ||
| 687 | cstate_cpumask_init(); | 648 | return cstate_init(); |
| 688 | |||
| 689 | cstate_pmus_register(); | ||
| 690 | |||
| 691 | return 0; | ||
| 692 | } | 649 | } |
| 650 | module_init(cstate_pmu_init); | ||
| 693 | 651 | ||
| 694 | device_initcall(cstate_pmu_init); | 652 | static void __exit cstate_pmu_exit(void) |
| 653 | { | ||
| 654 | cpu_notifier_register_begin(); | ||
| 655 | __unregister_cpu_notifier(&cstate_cpu_nb); | ||
| 656 | cstate_cleanup(); | ||
| 657 | cpu_notifier_register_done(); | ||
| 658 | } | ||
| 659 | module_exit(cstate_pmu_exit); | ||
| @@ -645,6 +645,12 @@ struct event_constraint intel_slm_pebs_event_constraints[] = { · 644 unmodified lines | |||
| 645 | EVENT_CONSTRAINT_END | 645 | EVENT_CONSTRAINT_END |
| 646 | }; | 646 | }; |
| 647 | 647 | ||
| 648 | struct event_constraint intel_glm_pebs_event_constraints[] = { | ||
| 649 | /* Allow all events as PEBS with no flags */ | ||
| 650 | INTEL_ALL_EVENT_CONSTRAINT(0, 0x1), | ||
| 651 | EVENT_CONSTRAINT_END | ||
| 652 | }; | ||
| 653 | |||
| 648 | struct event_constraint intel_nehalem_pebs_event_constraints[] = { | 654 | struct event_constraint intel_nehalem_pebs_event_constraints[] = { |
| 649 | INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ | 655 | INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ |
| 650 | INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ | 656 | INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ |
| @@ -14,7 +14,8 @@ enum { · 13 unmodified lines | |||
| 14 | LBR_FORMAT_EIP_FLAGS = 0x03, | 14 | LBR_FORMAT_EIP_FLAGS = 0x03, |
| 15 | LBR_FORMAT_EIP_FLAGS2 = 0x04, | 15 | LBR_FORMAT_EIP_FLAGS2 = 0x04, |
| 16 | LBR_FORMAT_INFO = 0x05, | 16 | LBR_FORMAT_INFO = 0x05, |
| 17 | LBR_FORMAT_MAX_KNOWN = LBR_FORMAT_INFO, | 17 | LBR_FORMAT_TIME = 0x06, |
| 18 | LBR_FORMAT_MAX_KNOWN = LBR_FORMAT_TIME, | ||
| 18 | }; | 19 | }; |
| 19 | 20 | ||
| 20 | static enum { | 21 | static enum { |
| @@ -464,6 +465,16 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) · 443 unmodified lines | |||
| 464 | abort = !!(info & LBR_INFO_ABORT); | 465 | abort = !!(info & LBR_INFO_ABORT); |
| 465 | cycles = (info & LBR_INFO_CYCLES); | 466 | cycles = (info & LBR_INFO_CYCLES); |
| 466 | } | 467 | } |
| 468 | |||
| 469 | if (lbr_format == LBR_FORMAT_TIME) { | ||
| 470 | mis = !!(from & LBR_FROM_FLAG_MISPRED); | ||
| 471 | pred = !mis; | ||
| 472 | skip = 1; | ||
| 473 | cycles = ((to >> 48) & LBR_INFO_CYCLES); | ||
| 474 | |||
| 475 | to = (u64)((((s64)to) << 16) >> 16); | ||
| 476 | } | ||
| 477 | |||
| 467 | if (lbr_flags & LBR_EIP_FLAGS) { | 478 | if (lbr_flags & LBR_EIP_FLAGS) { |
| 468 | mis = !!(from & LBR_FROM_FLAG_MISPRED); | 479 | mis = !!(from & LBR_FROM_FLAG_MISPRED); |
| 469 | pred = !mis; | 480 | pred = !mis; |
| @@ -1049,6 +1060,24 @@ void __init intel_pmu_lbr_init_atom(void) · 579 unmodified lines | |||
| 1049 | pr_cont("8-deep LBR, "); | 1060 | pr_cont("8-deep LBR, "); |
| 1050 | } | 1061 | } |
| 1051 | 1062 | ||
| 1063 | /* slm */ | ||
| 1064 | void __init intel_pmu_lbr_init_slm(void) | ||
| 1065 | { | ||
| 1066 | x86_pmu.lbr_nr = 8; | ||
| 1067 | x86_pmu.lbr_tos = MSR_LBR_TOS; | ||
| 1068 | x86_pmu.lbr_from = MSR_LBR_CORE_FROM; | ||
| 1069 | x86_pmu.lbr_to = MSR_LBR_CORE_TO; | ||
| 1070 | |||
| 1071 | x86_pmu.lbr_sel_mask = LBR_SEL_MASK; | ||
| 1072 | x86_pmu.lbr_sel_map = nhm_lbr_sel_map; | ||
| 1073 | |||
| 1074 | /* | ||
| 1075 | * SW branch filter usage: | ||
| 1076 | * - compensate for lack of HW filter | ||
| 1077 | */ | ||
| 1078 | pr_cont("8-deep LBR, "); | ||
| 1079 | } | ||
| 1080 | |||
| 1052 | /* Knights Landing */ | 1081 | /* Knights Landing */ |
| 1053 | void intel_pmu_lbr_init_knl(void) | 1082 | void intel_pmu_lbr_init_knl(void) |
| 1054 | { | 1083 | { |
| @@ -67,11 +67,13 @@ static struct pt_cap_desc { · 66 unmodified lines | |||
| 67 | PT_CAP(max_subleaf, 0, CR_EAX, 0xffffffff), | 67 | PT_CAP(max_subleaf, 0, CR_EAX, 0xffffffff), |
| 68 | PT_CAP(cr3_filtering, 0, CR_EBX, BIT(0)), | 68 | PT_CAP(cr3_filtering, 0, CR_EBX, BIT(0)), |
| 69 | PT_CAP(psb_cyc, 0, CR_EBX, BIT(1)), | 69 | PT_CAP(psb_cyc, 0, CR_EBX, BIT(1)), |
| 70 | PT_CAP(ip_filtering, 0, CR_EBX, BIT(2)), | ||
| 70 | PT_CAP(mtc, 0, CR_EBX, BIT(3)), | 71 | PT_CAP(mtc, 0, CR_EBX, BIT(3)), |
| 71 | PT_CAP(topa_output, 0, CR_ECX, BIT(0)), | 72 | PT_CAP(topa_output, 0, CR_ECX, BIT(0)), |
| 72 | PT_CAP(topa_multiple_entries, 0, CR_ECX, BIT(1)), | 73 | PT_CAP(topa_multiple_entries, 0, CR_ECX, BIT(1)), |
| 73 | PT_CAP(single_range_output, 0, CR_ECX, BIT(2)), | 74 | PT_CAP(single_range_output, 0, CR_ECX, BIT(2)), |
| 74 | PT_CAP(payloads_lip, 0, CR_ECX, BIT(31)), | 75 | PT_CAP(payloads_lip, 0, CR_ECX, BIT(31)), |
| 76 | PT_CAP(num_address_ranges, 1, CR_EAX, 0x3), | ||
| 75 | PT_CAP(mtc_periods, 1, CR_EAX, 0xffff0000), | 77 | PT_CAP(mtc_periods, 1, CR_EAX, 0xffff0000), |
| 76 | PT_CAP(cycle_thresholds, 1, CR_EBX, 0xffff), | 78 | PT_CAP(cycle_thresholds, 1, CR_EBX, 0xffff), |
| 77 | PT_CAP(psb_periods, 1, CR_EBX, 0xffff0000), | 79 | PT_CAP(psb_periods, 1, CR_EBX, 0xffff0000), |
| @@ -125,9 +127,46 @@ static struct attribute_group pt_format_group = { · 47 unmodified lines | |||
| 125 | .attrs = pt_formats_attr, | 127 | .attrs = pt_formats_attr, |
| 126 | }; | 128 | }; |
| 127 | 129 | ||
| 130 | static ssize_t | ||
| 131 | pt_timing_attr_show(struct device *dev, struct device_attribute *attr, | ||
| 132 | char *page) | ||
| 133 | { | ||
| 134 | struct perf_pmu_events_attr *pmu_attr = | ||
| 135 | container_of(attr, struct perf_pmu_events_attr, attr); | ||
| 136 | |||
| 137 | switch (pmu_attr->id) { | ||
| 138 | case 0: | ||
| 139 | return sprintf(page, "%lu\n", pt_pmu.max_nonturbo_ratio); | ||
| 140 | case 1: | ||
| 141 | return sprintf(page, "%u:%u\n", | ||
| 142 | pt_pmu.tsc_art_num, | ||
| 143 | pt_pmu.tsc_art_den); | ||
| 144 | default: | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | |||
| 148 | return -EINVAL; | ||
| 149 | } | ||
| 150 | |||
| 151 | PMU_EVENT_ATTR(max_nonturbo_ratio, timing_attr_max_nonturbo_ratio, 0, | ||
| 152 | pt_timing_attr_show); | ||
| 153 | PMU_EVENT_ATTR(tsc_art_ratio, timing_attr_tsc_art_ratio, 1, | ||
| 154 | pt_timing_attr_show); | ||
| 155 | |||
| 156 | static struct attribute *pt_timing_attr[] = { | ||
| 157 | &timing_attr_max_nonturbo_ratio.attr.attr, | ||
| 158 | &timing_attr_tsc_art_ratio.attr.attr, | ||
| 159 | NULL, | ||
| 160 | }; | ||
| 161 | |||
| 162 | static struct attribute_group pt_timing_group = { | ||
| 163 | .attrs = pt_timing_attr, | ||
| 164 | }; | ||
| 165 | |||
| 128 | static const struct attribute_group *pt_attr_groups[] = { | 166 | static const struct attribute_group *pt_attr_groups[] = { |
| 129 | &pt_cap_group, | 167 | &pt_cap_group, |
| 130 | &pt_format_group, | 168 | &pt_format_group, |
| 169 | &pt_timing_group, | ||
| 131 | NULL, | 170 | NULL, |
| 132 | }; | 171 | }; |
| 133 | 172 | ||
| @@ -140,6 +179,23 @@ static int __init pt_pmu_hw_init(void) · 6 unmodified lines | |||
| 140 | int ret; | 179 | int ret; |
| 141 | long i; | 180 | long i; |
| 142 | 181 | ||
| 182 | rdmsrl(MSR_PLATFORM_INFO, reg); | ||
| 183 | pt_pmu.max_nonturbo_ratio = (reg & 0xff00) >> 8; | ||
| 184 | |||
| 185 | /* | ||
| 186 | * if available, read in TSC to core crystal clock ratio, | ||
| 187 | * otherwise, zero for numerator stands for "not enumerated" | ||
| 188 | * as per SDM | ||
| 189 | */ | ||
| 190 | if (boot_cpu_data.cpuid_level >= CPUID_TSC_LEAF) { | ||
| 191 | u32 eax, ebx, ecx, edx; | ||
| 192 | |||
| 193 | cpuid(CPUID_TSC_LEAF, &eax, &ebx, &ecx, &edx); | ||
| 194 | |||
| 195 | pt_pmu.tsc_art_num = ebx; | ||
| 196 | pt_pmu.tsc_art_den = eax; | ||
| 197 | } | ||
| 198 | |||
| 143 | if (boot_cpu_has(X86_FEATURE_VMX)) { | 199 | if (boot_cpu_has(X86_FEATURE_VMX)) { |
| 144 | /* | 200 | /* |
| 145 | * Intel SDM, 36.5 "Tracing post-VMXON" says that | 201 | * Intel SDM, 36.5 "Tracing post-VMXON" says that |
| @@ -263,6 +319,75 @@ static bool pt_event_valid(struct perf_event *event) · 117 unmodified lines | |||
| 263 | * These all are cpu affine and operate on a local PT | 319 | * These all are cpu affine and operate on a local PT |
| 264 | */ | 320 | */ |
| 265 | 321 | ||
| 322 | /* Address ranges and their corresponding msr configuration registers */ | ||
| 323 | static const struct pt_address_range { | ||
| 324 | unsigned long msr_a; | ||
| 325 | unsigned long msr_b; | ||
| 326 | unsigned int reg_off; | ||
| 327 | } pt_address_ranges[] = { | ||
| 328 | { | ||
| 329 | .msr_a = MSR_IA32_RTIT_ADDR0_A, | ||
| 330 | .msr_b = MSR_IA32_RTIT_ADDR0_B, | ||
| 331 | .reg_off = RTIT_CTL_ADDR0_OFFSET, | ||
| 332 | }, | ||
| 333 | { | ||
| 334 | .msr_a = MSR_IA32_RTIT_ADDR1_A, | ||
| 335 | .msr_b = MSR_IA32_RTIT_ADDR1_B, | ||
| 336 | .reg_off = RTIT_CTL_ADDR1_OFFSET, | ||
| 337 | }, | ||
| 338 | { | ||
| 339 | .msr_a = MSR_IA32_RTIT_ADDR2_A, | ||
| 340 | .msr_b = MSR_IA32_RTIT_ADDR2_B, | ||
| 341 | .reg_off = RTIT_CTL_ADDR2_OFFSET, | ||
| 342 | }, | ||
| 343 | { | ||
| 344 | .msr_a = MSR_IA32_RTIT_ADDR3_A, | ||
| 345 | .msr_b = MSR_IA32_RTIT_ADDR3_B, | ||
| 346 | .reg_off = RTIT_CTL_ADDR3_OFFSET, | ||
| 347 | } | ||
| 348 | }; | ||
| 349 | |||
| 350 | static u64 pt_config_filters(struct perf_event *event) | ||
| 351 | { | ||
| 352 | struct pt_filters *filters = event->hw.addr_filters; | ||
| 353 | struct pt *pt = this_cpu_ptr(&pt_ctx); | ||
| 354 | unsigned int range = 0; | ||
| 355 | u64 rtit_ctl = 0; | ||
| 356 | |||
| 357 | if (!filters) | ||
| 358 | return 0; | ||
| 359 | |||
| 360 | perf_event_addr_filters_sync(event); | ||
| 361 | |||
| 362 | for (range = 0; range < filters->nr_filters; range++) { | ||
| 363 | struct pt_filter *filter = &filters->filter[range]; | ||
| 364 | |||
| 365 | /* | ||
| 366 | * Note, if the range has zero start/end addresses due | ||
| 367 | * to its dynamic object not being loaded yet, we just | ||
| 368 | * go ahead and program zeroed range, which will simply | ||
| 369 | * produce no data. Note^2: if executable code at 0x0 | ||
| 370 | * is a concern, we can set up an "invalid" configuration | ||
| 371 | * such as msr_b < msr_a. | ||
| 372 | */ | ||
| 373 | |||
| 374 | /* avoid redundant msr writes */ | ||
| 375 | if (pt->filters.filter[range].msr_a != filter->msr_a) { | ||
| 376 | wrmsrl(pt_address_ranges[range].msr_a, filter->msr_a); | ||
| 377 | pt->filters.filter[range].msr_a = filter->msr_a; | ||
| 378 | } | ||
| 379 | |||
| 380 | if (pt->filters.filter[range].msr_b != filter->msr_b) { | ||
| 381 | wrmsrl(pt_address_ranges[range].msr_b, filter->msr_b); | ||
| 382 | pt->filters.filter[range].msr_b = filter->msr_b; | ||
| 383 | } | ||
| 384 | |||
| 385 | rtit_ctl |= filter->config << pt_address_ranges[range].reg_off; | ||
| 386 | } | ||
| 387 | |||
| 388 | return rtit_ctl; | ||
| 389 | } | ||
| 390 | |||
| 266 | static void pt_config(struct perf_event *event) | 391 | static void pt_config(struct perf_event *event) |
| 267 | { | 392 | { |
| 268 | u64 reg; | 393 | u64 reg; |
| @@ -272,7 +397,8 @@ static void pt_config(struct perf_event *event) · 3 unmodified lines | |||
| 272 | wrmsrl(MSR_IA32_RTIT_STATUS, 0); | 397 | wrmsrl(MSR_IA32_RTIT_STATUS, 0); |
| 273 | } | 398 | } |
| 274 | 399 | ||
| 275 | reg = RTIT_CTL_TOPA | RTIT_CTL_BRANCH_EN | RTIT_CTL_TRACEEN; | 400 | reg = pt_config_filters(event); |
| 401 | reg |= RTIT_CTL_TOPA | RTIT_CTL_BRANCH_EN | RTIT_CTL_TRACEEN; | ||
| 276 | 402 | ||
| 277 | if (!event->attr.exclude_kernel) | 403 | if (!event->attr.exclude_kernel) |
| 278 | reg |= RTIT_CTL_OS; | 404 | reg |= RTIT_CTL_OS; |
| @@ -921,24 +1047,80 @@ static void pt_buffer_free_aux(void *data) · 642 unmodified lines | |||
| 921 | kfree(buf); | 1047 | kfree(buf); |
| 922 | } | 1048 | } |
| 923 | 1049 | ||
| 924 | /** | 1050 | static int pt_addr_filters_init(struct perf_event *event) |
| 925 | * pt_buffer_is_full() - check if the buffer is full | ||
| 926 | * @buf: PT buffer. | ||
| 927 | * @pt: Per-cpu pt handle. | ||
| 928 | * | ||
| 929 | * If the user hasn't read data from the output region that aux_head | ||
| 930 | * points to, the buffer is considered full: the user needs to read at | ||
| 931 | * least this region and update aux_tail to point past it. | ||
| 932 | */ | ||
| 933 | static bool pt_buffer_is_full(struct pt_buffer *buf, struct pt *pt) | ||
| 934 | { | 1051 | { |
| 935 | if (buf->snapshot) | 1052 | struct pt_filters *filters; |
| 936 | return false; | 1053 | int node = event->cpu == -1 ? -1 : cpu_to_node(event->cpu); |
| 1054 | |||
| 1055 | if (!pt_cap_get(PT_CAP_num_address_ranges)) | ||
| 1056 | return 0; | ||
| 1057 | |||
| 1058 | filters = kzalloc_node(sizeof(struct pt_filters), GFP_KERNEL, node); | ||
| 1059 | if (!filters) | ||
| 1060 | return -ENOMEM; | ||
| 1061 | |||
| 1062 | if (event->parent) | ||
| 1063 | memcpy(filters, event->parent->hw.addr_filters, | ||
| 1064 | sizeof(*filters)); | ||
| 1065 | |||
| 1066 | event->hw.addr_filters = filters; | ||
| 1067 | |||
| 1068 | return 0; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | static void pt_addr_filters_fini(struct perf_event *event) | ||
| 1072 | { | ||
| 1073 | kfree(event->hw.addr_filters); | ||
| 1074 | event->hw.addr_filters = NULL; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | static int pt_event_addr_filters_validate(struct list_head *filters) | ||
| 1078 | { | ||
| 1079 | struct perf_addr_filter *filter; | ||
| 1080 | int range = 0; | ||
| 1081 | |||
| 1082 | list_for_each_entry(filter, filters, entry) { | ||
| 1083 | /* PT doesn't support single address triggers */ | ||
| 1084 | if (!filter->range) | ||
| 1085 | return -EOPNOTSUPP; | ||
| 1086 | |||
| 1087 | if (!filter->inode && !kernel_ip(filter->offset)) | ||
| 1088 | return -EINVAL; | ||
| 1089 | |||
| 1090 | if (++range > pt_cap_get(PT_CAP_num_address_ranges)) | ||
| 1091 | return -EOPNOTSUPP; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | return 0; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | static void pt_event_addr_filters_sync(struct perf_event *event) | ||
| 1098 | { | ||
| 1099 | struct perf_addr_filters_head *head = perf_event_addr_filters(event); | ||
| 1100 | unsigned long msr_a, msr_b, *offs = event->addr_filters_offs; | ||
| 1101 | struct pt_filters *filters = event->hw.addr_filters; | ||
| 1102 | struct perf_addr_filter *filter; | ||
| 1103 | int range = 0; | ||
| 1104 | |||
| 1105 | if (!filters) | ||
| 1106 | return; | ||
| 937 | 1107 | ||
| 938 | if (local_read(&buf->data_size) >= pt->handle.size) | 1108 | list_for_each_entry(filter, &head->list, entry) { |
| 939 | return true; | 1109 | if (filter->inode && !offs[range]) { |
| 1110 | msr_a = msr_b = 0; | ||
| 1111 | } else { | ||
| 1112 | /* apply the offset */ | ||
| 1113 | msr_a = filter->offset + offs[range]; | ||
| 1114 | msr_b = filter->size + msr_a; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | filters->filter[range].msr_a = msr_a; | ||
| 1118 | filters->filter[range].msr_b = msr_b; | ||
| 1119 | filters->filter[range].config = filter->filter ? 1 : 2; | ||
| 1120 | range++; | ||
| 1121 | } | ||
| 940 | 1122 | ||
| 941 | return false; | 1123 | filters->nr_filters = range; |
| 942 | } | 1124 | } |
| 943 | 1125 | ||
| 944 | /** | 1126 | /** |
| @@ -955,7 +1137,7 @@ void intel_pt_interrupt(void) · 10 unmodified lines | |||
| 955 | * after PT has been disabled by pt_event_stop(). Make sure we don't | 1137 | * after PT has been disabled by pt_event_stop(). Make sure we don't |
| 956 | * do anything (particularly, re-enable) for this event here. | 1138 | * do anything (particularly, re-enable) for this event here. |
| 957 | */ | 1139 | */ |
| 958 | if (!ACCESS_ONCE(pt->handle_nmi)) | 1140 | if (!READ_ONCE(pt->handle_nmi)) |
| 959 | return; | 1141 | return; |
| 960 | 1142 | ||
| 961 | /* | 1143 | /* |
| @@ -1040,23 +1222,36 @@ EXPORT_SYMBOL_GPL(intel_pt_handle_vmx); · 78 unmodified lines | |||
| 1040 | 1222 | ||
| 1041 | static void pt_event_start(struct perf_event *event, int mode) | 1223 | static void pt_event_start(struct perf_event *event, int mode) |
| 1042 | { | 1224 | { |
| 1225 | struct hw_perf_event *hwc = &event->hw; | ||
| 1043 | struct pt *pt = this_cpu_ptr(&pt_ctx); | 1226 | struct pt *pt = this_cpu_ptr(&pt_ctx); |
| 1044 | struct pt_buffer *buf = perf_get_aux(&pt->handle); | 1227 | struct pt_buffer *buf; |
| 1045 | 1228 | ||
| 1046 | if (READ_ONCE(pt->vmx_on)) | 1229 | if (READ_ONCE(pt->vmx_on)) |
| 1047 | return; | 1230 | return; |
| 1048 | 1231 | ||
| 1049 | if (!buf || pt_buffer_is_full(buf, pt)) { | 1232 | buf = perf_aux_output_begin(&pt->handle, event); |
| 1050 | event->hw.state = PERF_HES_STOPPED; | 1233 | if (!buf) |
| 1051 | return; | 1234 | goto fail_stop; |
| 1235 | |||
| 1236 | pt_buffer_reset_offsets(buf, pt->handle.head); | ||
| 1237 | if (!buf->snapshot) { | ||
| 1238 | if (pt_buffer_reset_markers(buf, &pt->handle)) | ||
| 1239 | goto fail_end_stop; | ||
| 1052 | } | 1240 | } |
| 1053 | 1241 | ||
| 1054 | ACCESS_ONCE(pt->handle_nmi) = 1; | 1242 | WRITE_ONCE(pt->handle_nmi, 1); |
| 1055 | event->hw.state = 0; | 1243 | hwc->state = 0; |
| 1056 | 1244 | ||
| 1057 | pt_config_buffer(buf->cur->table, buf->cur_idx, | 1245 | pt_config_buffer(buf->cur->table, buf->cur_idx, |
| 1058 | buf->output_off); | 1246 | buf->output_off); |
| 1059 | pt_config(event); | 1247 | pt_config(event); |
| 1248 | |||
| 1249 | return; | ||
| 1250 | |||
| 1251 | fail_end_stop: | ||
| 1252 | perf_aux_output_end(&pt->handle, 0, true); | ||
| 1253 | fail_stop: | ||
| 1254 | hwc->state = PERF_HES_STOPPED; | ||
| 1060 | } | 1255 | } |
| 1061 | 1256 | ||
| 1062 | static void pt_event_stop(struct perf_event *event, int mode) | 1257 | static void pt_event_stop(struct perf_event *event, int mode) |
| @@ -1067,7 +1262,7 @@ static void pt_event_stop(struct perf_event *event, int mode) · 4 unmodified lines | |||
| 1067 | * Protect against the PMI racing with disabling wrmsr, | 1262 | * Protect against the PMI racing with disabling wrmsr, |
| 1068 | * see comment in intel_pt_interrupt(). | 1263 | * see comment in intel_pt_interrupt(). |
| 1069 | */ | 1264 | */ |
| 1070 | ACCESS_ONCE(pt->handle_nmi) = 0; | 1265 | WRITE_ONCE(pt->handle_nmi, 0); |
| 1071 | 1266 | ||
| 1072 | pt_config_stop(event); | 1267 | pt_config_stop(event); |
| 1073 | 1268 | ||
| @@ -1090,19 +1285,7 @@ static void pt_event_stop(struct perf_event *event, int mode) · 16 unmodified lines | |||
| 1090 | pt_handle_status(pt); | 1285 | pt_handle_status(pt); |
| 1091 | 1286 | ||
| 1092 | pt_update_head(pt); | 1287 | pt_update_head(pt); |
| 1093 | } | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | static void pt_event_del(struct perf_event *event, int mode) | ||
| 1097 | { | ||
| 1098 | struct pt *pt = this_cpu_ptr(&pt_ctx); | ||
| 1099 | struct pt_buffer *buf; | ||
| 1100 | 1288 | ||
| 1101 | pt_event_stop(event, PERF_EF_UPDATE); | ||
| 1102 | |||
| 1103 | buf = perf_get_aux(&pt->handle); | ||
| 1104 | |||
| 1105 | if (buf) { | ||
| 1106 | if (buf->snapshot) | 1289 | if (buf->snapshot) |
| 1107 | pt->handle.head = | 1290 | pt->handle.head = |
| 1108 | local_xchg(&buf->data_size, | 1291 | local_xchg(&buf->data_size, |
| @@ -1112,9 +1295,13 @@ static void pt_event_del(struct perf_event *event, int mode) · 3 unmodified lines | |||
| 1112 | } | 1295 | } |
| 1113 | } | 1296 | } |
| 1114 | 1297 | ||
| 1298 | static void pt_event_del(struct perf_event *event, int mode) | ||
| 1299 | { | ||
| 1300 | pt_event_stop(event, PERF_EF_UPDATE); | ||
| 1301 | } | ||
| 1302 | |||
| 1115 | static int pt_event_add(struct perf_event *event, int mode) | 1303 | static int pt_event_add(struct perf_event *event, int mode) |
| 1116 | { | 1304 | { |
| 1117 | struct pt_buffer *buf; | ||
| 1118 | struct pt *pt = this_cpu_ptr(&pt_ctx); | 1305 | struct pt *pt = this_cpu_ptr(&pt_ctx); |
| 1119 | struct hw_perf_event *hwc = &event->hw; | 1306 | struct hw_perf_event *hwc = &event->hw; |
| 1120 | int ret = -EBUSY; | 1307 | int ret = -EBUSY; |
| @@ -1122,34 +1309,18 @@ static int pt_event_add(struct perf_event *event, int mode) · 1 unmodified line | |||
| 1122 | if (pt->handle.event) | 1309 | if (pt->handle.event) |
| 1123 | goto fail; | 1310 | goto fail; |
| 1124 | 1311 | ||
| 1125 | buf = perf_aux_output_begin(&pt->handle, event); | ||
| 1126 | ret = -EINVAL; | ||
| 1127 | if (!buf) | ||
| 1128 | goto fail_stop; | ||
| 1129 | |||
| 1130 | pt_buffer_reset_offsets(buf, pt->handle.head); | ||
| 1131 | if (!buf->snapshot) { | ||
| 1132 | ret = pt_buffer_reset_markers(buf, &pt->handle); | ||
| 1133 | if (ret) | ||
| 1134 | goto fail_end_stop; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | if (mode & PERF_EF_START) { | 1312 | if (mode & PERF_EF_START) { |
| 1138 | pt_event_start(event, 0); | 1313 | pt_event_start(event, 0); |
| 1139 | ret = -EBUSY; | 1314 | ret = -EINVAL; |
| 1140 | if (hwc->state == PERF_HES_STOPPED) | 1315 | if (hwc->state == PERF_HES_STOPPED) |
| 1141 | goto fail_end_stop; | 1316 | goto fail; |
| 1142 | } else { | 1317 | } else { |
| 1143 | hwc->state = PERF_HES_STOPPED; | 1318 | hwc->state = PERF_HES_STOPPED; |
| 1144 | } | 1319 | } |
| 1145 | 1320 | ||
| 1146 | return 0; | 1321 | ret = 0; |
| 1147 | |||
| 1148 | fail_end_stop: | ||
| 1149 | perf_aux_output_end(&pt->handle, 0, true); | ||
| 1150 | fail_stop: | ||
| 1151 | hwc->state = PERF_HES_STOPPED; | ||
| 1152 | fail: | 1322 | fail: |
| 1323 | |||
| 1153 | return ret; | 1324 | return ret; |
| 1154 | } | 1325 | } |
| 1155 | 1326 | ||
| @@ -1159,6 +1330,7 @@ static void pt_event_read(struct perf_event *event) · 3 unmodified lines | |||
| 1159 | 1330 | ||
| 1160 | static void pt_event_destroy(struct perf_event *event) | 1331 | static void pt_event_destroy(struct perf_event *event) |
| 1161 | { | 1332 | { |
| 1333 | pt_addr_filters_fini(event); | ||
| 1162 | x86_del_exclusive(x86_lbr_exclusive_pt); | 1334 | x86_del_exclusive(x86_lbr_exclusive_pt); |
| 1163 | } | 1335 | } |
| 1164 | 1336 | ||
| @@ -1173,6 +1345,11 @@ static int pt_event_init(struct perf_event *event) · 8 unmodified lines | |||
| 1173 | if (x86_add_exclusive(x86_lbr_exclusive_pt)) | 1345 | if (x86_add_exclusive(x86_lbr_exclusive_pt)) |
| 1174 | return -EBUSY; | 1346 | return -EBUSY; |
| 1175 | 1347 | ||
| 1348 | if (pt_addr_filters_init(event)) { | ||
| 1349 | x86_del_exclusive(x86_lbr_exclusive_pt); | ||
| 1350 | return -ENOMEM; | ||
| 1351 | } | ||
| 1352 | |||
| 1176 | event->destroy = pt_event_destroy; | 1353 | event->destroy = pt_event_destroy; |
| 1177 | 1354 | ||
| 1178 | return 0; | 1355 | return 0; |
| @@ -1192,7 +1369,7 @@ static __init int pt_init(void) · 13 unmodified lines | |||
| 1192 | 1369 | ||
| 1193 | BUILD_BUG_ON(sizeof(struct topa) > PAGE_SIZE); | 1370 | BUILD_BUG_ON(sizeof(struct topa) > PAGE_SIZE); |
| 1194 | 1371 | ||
| 1195 | if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT)) | 1372 | if (!boot_cpu_has(X86_FEATURE_INTEL_PT)) |
| 1196 | return -ENODEV; | 1373 | return -ENODEV; |
| 1197 | 1374 | ||
| 1198 | get_online_cpus(); | 1375 | get_online_cpus(); |
| @@ -1226,16 +1403,21 @@ static __init int pt_init(void) · 27 unmodified lines | |||
| 1226 | PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_SW_DOUBLEBUF; | 1403 | PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_SW_DOUBLEBUF; |
| 1227 | 1404 | ||
| 1228 | pt_pmu.pmu.capabilities |= PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE; | 1405 | pt_pmu.pmu.capabilities |= PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE; |
| 1229 | pt_pmu.pmu.attr_groups = pt_attr_groups; | 1406 | pt_pmu.pmu.attr_groups = pt_attr_groups; |
| 1230 | pt_pmu.pmu.task_ctx_nr = perf_sw_context; | 1407 | pt_pmu.pmu.task_ctx_nr = perf_sw_context; |
| 1231 | pt_pmu.pmu.event_init = pt_event_init; | 1408 | pt_pmu.pmu.event_init = pt_event_init; |
| 1232 | pt_pmu.pmu.add = pt_event_add; | 1409 | pt_pmu.pmu.add = pt_event_add; |
| 1233 | pt_pmu.pmu.del = pt_event_del; | 1410 | pt_pmu.pmu.del = pt_event_del; |
| 1234 | pt_pmu.pmu.start = pt_event_start; | 1411 | pt_pmu.pmu.start = pt_event_start; |
| 1235 | pt_pmu.pmu.stop = pt_event_stop; | 1412 | pt_pmu.pmu.stop = pt_event_stop; |
| 1236 | pt_pmu.pmu.read = pt_event_read; | 1413 | pt_pmu.pmu.read = pt_event_read; |
| 1237 | pt_pmu.pmu.setup_aux = pt_buffer_setup_aux; | 1414 | pt_pmu.pmu.setup_aux = pt_buffer_setup_aux; |
| 1238 | pt_pmu.pmu.free_aux = pt_buffer_free_aux; | 1415 | pt_pmu.pmu.free_aux = pt_buffer_free_aux; |
| 1416 | pt_pmu.pmu.addr_filters_sync = pt_event_addr_filters_sync; | ||
| 1417 | pt_pmu.pmu.addr_filters_validate = pt_event_addr_filters_validate; | ||
| 1418 | pt_pmu.pmu.nr_addr_filters = | ||
| 1419 | pt_cap_get(PT_CAP_num_address_ranges); | ||
| 1420 | |||
| 1239 | ret = perf_pmu_register(&pt_pmu.pmu, "intel_pt", -1); | 1421 | ret = perf_pmu_register(&pt_pmu.pmu, "intel_pt", -1); |
| 1240 | 1422 | ||
| 1241 | return ret; | 1423 | return ret; |
| @@ -19,6 +19,40 @@ · 18 unmodified lines | |||
| 19 | #ifndef __INTEL_PT_H__ | 19 | #ifndef __INTEL_PT_H__ |
| 20 | #define __INTEL_PT_H__ | 20 | #define __INTEL_PT_H__ |
| 21 | 21 | ||
| 22 | /* | ||
| 23 | * PT MSR bit definitions | ||
| 24 | */ | ||
| 25 | #define RTIT_CTL_TRACEEN BIT(0) | ||
| 26 | #define RTIT_CTL_CYCLEACC BIT(1) | ||
| 27 | #define RTIT_CTL_OS BIT(2) | ||
| 28 | #define RTIT_CTL_USR BIT(3) | ||
| 29 | #define RTIT_CTL_CR3EN BIT(7) | ||
| 30 | #define RTIT_CTL_TOPA BIT(8) | ||
| 31 | #define RTIT_CTL_MTC_EN BIT(9) | ||
| 32 | #define RTIT_CTL_TSC_EN BIT(10) | ||
| 33 | #define RTIT_CTL_DISRETC BIT(11) | ||
| 34 | #define RTIT_CTL_BRANCH_EN BIT(13) | ||
| 35 | #define RTIT_CTL_MTC_RANGE_OFFSET 14 | ||
| 36 | #define RTIT_CTL_MTC_RANGE (0x0full << RTIT_CTL_MTC_RANGE_OFFSET) | ||
| 37 | #define RTIT_CTL_CYC_THRESH_OFFSET 19 | ||
| 38 | #define RTIT_CTL_CYC_THRESH (0x0full << RTIT_CTL_CYC_THRESH_OFFSET) | ||
| 39 | #define RTIT_CTL_PSB_FREQ_OFFSET 24 | ||
| 40 | #define RTIT_CTL_PSB_FREQ (0x0full << RTIT_CTL_PSB_FREQ_OFFSET) | ||
| 41 | #define RTIT_CTL_ADDR0_OFFSET 32 | ||
| 42 | #define RTIT_CTL_ADDR0 (0x0full << RTIT_CTL_ADDR0_OFFSET) | ||
| 43 | #define RTIT_CTL_ADDR1_OFFSET 36 | ||
| 44 | #define RTIT_CTL_ADDR1 (0x0full << RTIT_CTL_ADDR1_OFFSET) | ||
| 45 | #define RTIT_CTL_ADDR2_OFFSET 40 | ||
| 46 | #define RTIT_CTL_ADDR2 (0x0full << RTIT_CTL_ADDR2_OFFSET) | ||
| 47 | #define RTIT_CTL_ADDR3_OFFSET 44 | ||
| 48 | #define RTIT_CTL_ADDR3 (0x0full << RTIT_CTL_ADDR3_OFFSET) | ||
| 49 | #define RTIT_STATUS_FILTEREN BIT(0) | ||
| 50 | #define RTIT_STATUS_CONTEXTEN BIT(1) | ||
| 51 | #define RTIT_STATUS_TRIGGEREN BIT(2) | ||
| 52 | #define RTIT_STATUS_BUFFOVF BIT(3) | ||
| 53 | #define RTIT_STATUS_ERROR BIT(4) | ||
| 54 | #define RTIT_STATUS_STOPPED BIT(5) | ||
| 55 | |||
| 22 | /* | 56 | /* |
| 23 | * Single-entry ToPA: when this close to region boundary, switch | 57 | * Single-entry ToPA: when this close to region boundary, switch |
| 24 | * buffers to avoid losing data. | 58 | * buffers to avoid losing data. |
| @@ -48,15 +82,20 @@ struct topa_entry { · 23 unmodified lines | |||
| 48 | #define PT_CPUID_LEAVES 2 | 82 | #define PT_CPUID_LEAVES 2 |
| 49 | #define PT_CPUID_REGS_NUM 4 /* number of regsters (eax, ebx, ecx, edx) */ | 83 | #define PT_CPUID_REGS_NUM 4 /* number of regsters (eax, ebx, ecx, edx) */ |
| 50 | 84 | ||
| 85 | /* TSC to Core Crystal Clock Ratio */ | ||
| 86 | #define CPUID_TSC_LEAF 0x15 | ||
| 87 | |||
| 51 | enum pt_capabilities { | 88 | enum pt_capabilities { |
| 52 | PT_CAP_max_subleaf = 0, | 89 | PT_CAP_max_subleaf = 0, |
| 53 | PT_CAP_cr3_filtering, | 90 | PT_CAP_cr3_filtering, |
| 54 | PT_CAP_psb_cyc, | 91 | PT_CAP_psb_cyc, |
| 92 | PT_CAP_ip_filtering, | ||
| 55 | PT_CAP_mtc, | 93 | PT_CAP_mtc, |
| 56 | PT_CAP_topa_output, | 94 | PT_CAP_topa_output, |
| 57 | PT_CAP_topa_multiple_entries, | 95 | PT_CAP_topa_multiple_entries, |
| 58 | PT_CAP_single_range_output, | 96 | PT_CAP_single_range_output, |
| 59 | PT_CAP_payloads_lip, | 97 | PT_CAP_payloads_lip, |
| 98 | PT_CAP_num_address_ranges, | ||
| 60 | PT_CAP_mtc_periods, | 99 | PT_CAP_mtc_periods, |
| 61 | PT_CAP_cycle_thresholds, | 100 | PT_CAP_cycle_thresholds, |
| 62 | PT_CAP_psb_periods, | 101 | PT_CAP_psb_periods, |
| @@ -66,6 +105,9 @@ struct pt_pmu { · 3 unmodified lines | |||
| 66 | struct pmu pmu; | 105 | struct pmu pmu; |
| 67 | u32 caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES]; | 106 | u32 caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES]; |
| 68 | bool vmx; | 107 | bool vmx; |
| 108 | unsigned long max_nonturbo_ratio; | ||
| 109 | unsigned int tsc_art_num; | ||
| 110 | unsigned int tsc_art_den; | ||
| 69 | }; | 111 | }; |
| 70 | 112 | ||
| 71 | /** | 113 | /** |
| @@ -104,14 +146,40 @@ struct pt_buffer { · 32 unmodified lines | |||
| 104 | struct topa_entry *topa_index[0]; | 146 | struct topa_entry *topa_index[0]; |
| 105 | }; | 147 | }; |
| 106 | 148 | ||
| 149 | #define PT_FILTERS_NUM 4 | ||
| 150 | |||
| 151 | /** | ||
| 152 | * struct pt_filter - IP range filter configuration | ||
| 153 | * @msr_a: range start, goes to RTIT_ADDRn_A | ||
| 154 | * @msr_b: range end, goes to RTIT_ADDRn_B | ||
| 155 | * @config: 4-bit field in RTIT_CTL | ||
| 156 | */ | ||
| 157 | struct pt_filter { | ||
| 158 | unsigned long msr_a; | ||
| 159 | unsigned long msr_b; | ||
| 160 | unsigned long config; | ||
| 161 | }; | ||
| 162 | |||
| 163 | /** | ||
| 164 | * struct pt_filters - IP range filtering context | ||
| 165 | * @filter: filters defined for this context | ||
| 166 | * @nr_filters: number of defined filters in the @filter array | ||
| 167 | */ | ||
| 168 | struct pt_filters { | ||
| 169 | struct pt_filter filter[PT_FILTERS_NUM]; | ||
| 170 | unsigned int nr_filters; | ||
| 171 | }; | ||
| 172 | |||
| 107 | /** | 173 | /** |
| 108 | * struct pt - per-cpu pt context | 174 | * struct pt - per-cpu pt context |
| 109 | * @handle: perf output handle | 175 | * @handle: perf output handle |
| 176 | * @filters: last configured filters | ||
| 110 | * @handle_nmi: do handle PT PMI on this cpu, there's an active event | 177 | * @handle_nmi: do handle PT PMI on this cpu, there's an active event |
| 111 | * @vmx_on: 1 if VMX is ON on this cpu | 178 | * @vmx_on: 1 if VMX is ON on this cpu |
| 112 | */ | 179 | */ |
| 113 | struct pt { | 180 | struct pt { |
| 114 | struct perf_output_handle handle; | 181 | struct perf_output_handle handle; |
| 182 | struct pt_filters filters; | ||
| 115 | int handle_nmi; | 183 | int handle_nmi; |
| 116 | int vmx_on; | 184 | int vmx_on; |
| 117 | }; | 185 | }; |
| @@ -27,10 +27,14 @@ · 26 unmodified lines | |||
| 27 | * event: rapl_energy_dram | 27 | * event: rapl_energy_dram |
| 28 | * perf code: 0x3 | 28 | * perf code: 0x3 |
| 29 | * | 29 | * |
| 30 | * dram counter: consumption of the builtin-gpu domain (client only) | 30 | * gpu counter: consumption of the builtin-gpu domain (client only) |
| 31 | * event: rapl_energy_gpu | 31 | * event: rapl_energy_gpu |
| 32 | * perf code: 0x4 | 32 | * perf code: 0x4 |
| 33 | * | 33 | * |
| 34 | * psys counter: consumption of the builtin-psys domain (client only) | ||
| 35 | * event: rapl_energy_psys | ||
| 36 | * perf code: 0x5 | ||
| 37 | * | ||
| 34 | * We manage those counters as free running (read-only). They may be | 38 | * We manage those counters as free running (read-only). They may be |
| 35 | * use simultaneously by other tools, such as turbostat. | 39 | * use simultaneously by other tools, such as turbostat. |
| 36 | * | 40 | * |
| @@ -53,6 +57,8 @@ · 16 unmodified lines | |||
| 53 | #include <asm/cpu_device_id.h> | 57 | #include <asm/cpu_device_id.h> |
| 54 | #include "../perf_event.h" | 58 | #include "../perf_event.h" |
| 55 | 59 | ||
| 60 | MODULE_LICENSE("GPL"); | ||
| 61 | |||
| 56 | /* | 62 | /* |
| 57 | * RAPL energy status counters | 63 | * RAPL energy status counters |
| 58 | */ | 64 | */ |
| @@ -64,13 +70,16 @@ · 5 unmodified lines | |||
| 64 | #define INTEL_RAPL_RAM 0x3 /* pseudo-encoding */ | 70 | #define INTEL_RAPL_RAM 0x3 /* pseudo-encoding */ |
| 65 | #define RAPL_IDX_PP1_NRG_STAT 3 /* gpu */ | 71 | #define RAPL_IDX_PP1_NRG_STAT 3 /* gpu */ |
| 66 | #define INTEL_RAPL_PP1 0x4 /* pseudo-encoding */ | 72 | #define INTEL_RAPL_PP1 0x4 /* pseudo-encoding */ |
| 73 | #define RAPL_IDX_PSYS_NRG_STAT 4 /* psys */ | ||
| 74 | #define INTEL_RAPL_PSYS 0x5 /* pseudo-encoding */ | ||
| 67 | 75 | ||
| 68 | #define NR_RAPL_DOMAINS 0x4 | 76 | #define NR_RAPL_DOMAINS 0x5 |
| 69 | static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = { | 77 | static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = { |
| 70 | "pp0-core", | 78 | "pp0-core", |
| 71 | "package", | 79 | "package", |
| 72 | "dram", | 80 | "dram", |
| 73 | "pp1-gpu", | 81 | "pp1-gpu", |
| 82 | "psys", | ||
| 74 | }; | 83 | }; |
| 75 | 84 | ||
| 76 | /* Clients have PP0, PKG */ | 85 | /* Clients have PP0, PKG */ |
| @@ -89,6 +98,13 @@ static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = { · 12 unmodified lines | |||
| 89 | 1<<RAPL_IDX_RAM_NRG_STAT|\ | 98 | 1<<RAPL_IDX_RAM_NRG_STAT|\ |
| 90 | 1<<RAPL_IDX_PP1_NRG_STAT) | 99 | 1<<RAPL_IDX_PP1_NRG_STAT) |
| 91 | 100 | ||
| 101 | /* SKL clients have PP0, PKG, RAM, PP1, PSYS */ | ||
| 102 | #define RAPL_IDX_SKL_CLN (1<<RAPL_IDX_PP0_NRG_STAT|\ | ||
| 103 | 1<<RAPL_IDX_PKG_NRG_STAT|\ | ||
| 104 | 1<<RAPL_IDX_RAM_NRG_STAT|\ | ||
| 105 | 1<<RAPL_IDX_PP1_NRG_STAT|\ | ||
| 106 | 1<<RAPL_IDX_PSYS_NRG_STAT) | ||
| 107 | |||
| 92 | /* Knights Landing has PKG, RAM */ | 108 | /* Knights Landing has PKG, RAM */ |
| 93 | #define RAPL_IDX_KNL (1<<RAPL_IDX_PKG_NRG_STAT|\ | 109 | #define RAPL_IDX_KNL (1<<RAPL_IDX_PKG_NRG_STAT|\ |
| 94 | 1<<RAPL_IDX_RAM_NRG_STAT) | 110 | 1<<RAPL_IDX_RAM_NRG_STAT) |
| @@ -360,6 +376,10 @@ static int rapl_pmu_event_init(struct perf_event *event) · 265 unmodified lines | |||
| 360 | bit = RAPL_IDX_PP1_NRG_STAT; | 376 | bit = RAPL_IDX_PP1_NRG_STAT; |
| 361 | msr = MSR_PP1_ENERGY_STATUS; | 377 | msr = MSR_PP1_ENERGY_STATUS; |
| 362 | break; | 378 | break; |
| 379 | case INTEL_RAPL_PSYS: | ||
| 380 | bit = RAPL_IDX_PSYS_NRG_STAT; | ||
| 381 | msr = MSR_PLATFORM_ENERGY_STATUS; | ||
| 382 | break; | ||
| 363 | default: | 383 | default: |
| 364 | return -EINVAL; | 384 | return -EINVAL; |
| 365 | } | 385 | } |
| @@ -414,11 +434,13 @@ RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01"); · 48 unmodified lines | |||
| 414 | RAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02"); | 434 | RAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02"); |
| 415 | RAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03"); | 435 | RAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03"); |
| 416 | RAPL_EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04"); | 436 | RAPL_EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04"); |
| 437 | RAPL_EVENT_ATTR_STR(energy-psys, rapl_psys, "event=0x05"); | ||
| 417 | 438 | ||
| 418 | RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules"); | 439 | RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules"); |
| 419 | RAPL_EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules"); | 440 | RAPL_EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules"); |
| 420 | RAPL_EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules"); | 441 | RAPL_EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules"); |
| 421 | RAPL_EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules"); | 442 | RAPL_EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules"); |
| 443 | RAPL_EVENT_ATTR_STR(energy-psys.unit, rapl_psys_unit, "Joules"); | ||
| 422 | 444 | ||
| 423 | /* | 445 | /* |
| 424 | * we compute in 0.23 nJ increments regardless of MSR | 446 | * we compute in 0.23 nJ increments regardless of MSR |
| @@ -427,6 +449,7 @@ RAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890 · 2 unmodified lines | |||
| 427 | RAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10"); | 449 | RAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10"); |
| 428 | RAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10"); | 450 | RAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10"); |
| 429 | RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10"); | 451 | RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10"); |
| 452 | RAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_psys_scale, "2.3283064365386962890625e-10"); | ||
| 430 | 453 | ||
| 431 | static struct attribute *rapl_events_srv_attr[] = { | 454 | static struct attribute *rapl_events_srv_attr[] = { |
| 432 | EVENT_PTR(rapl_cores), | 455 | EVENT_PTR(rapl_cores), |
| @@ -476,6 +499,27 @@ static struct attribute *rapl_events_hsw_attr[] = { · 43 unmodified lines | |||
| 476 | NULL, | 499 | NULL, |
| 477 | }; | 500 | }; |
| 478 | 501 | ||
| 502 | static struct attribute *rapl_events_skl_attr[] = { | ||
| 503 | EVENT_PTR(rapl_cores), | ||
| 504 | EVENT_PTR(rapl_pkg), | ||
| 505 | EVENT_PTR(rapl_gpu), | ||
| 506 | EVENT_PTR(rapl_ram), | ||
| 507 | EVENT_PTR(rapl_psys), | ||
| 508 | |||
| 509 | EVENT_PTR(rapl_cores_unit), | ||
| 510 | EVENT_PTR(rapl_pkg_unit), | ||
| 511 | EVENT_PTR(rapl_gpu_unit), | ||
| 512 | EVENT_PTR(rapl_ram_unit), | ||
| 513 | EVENT_PTR(rapl_psys_unit), | ||
| 514 | |||
| 515 | EVENT_PTR(rapl_cores_scale), | ||
| 516 | EVENT_PTR(rapl_pkg_scale), | ||
| 517 | EVENT_PTR(rapl_gpu_scale), | ||
| 518 | EVENT_PTR(rapl_ram_scale), | ||
| 519 | EVENT_PTR(rapl_psys_scale), | ||
| 520 | NULL, | ||
| 521 | }; | ||
| 522 | |||
| 479 | static struct attribute *rapl_events_knl_attr[] = { | 523 | static struct attribute *rapl_events_knl_attr[] = { |
| 480 | EVENT_PTR(rapl_pkg), | 524 | EVENT_PTR(rapl_pkg), |
| 481 | EVENT_PTR(rapl_ram), | 525 | EVENT_PTR(rapl_ram), |
| @@ -592,6 +636,11 @@ static int rapl_cpu_notifier(struct notifier_block *self, · 110 unmodified lines | |||
| 592 | return NOTIFY_OK; | 636 | return NOTIFY_OK; |
| 593 | } | 637 | } |
| 594 | 638 | ||
| 639 | static struct notifier_block rapl_cpu_nb = { | ||
| 640 | .notifier_call = rapl_cpu_notifier, | ||
| 641 | .priority = CPU_PRI_PERF + 1, | ||
| 642 | }; | ||
| 643 | |||
| 595 | static int rapl_check_hw_unit(bool apply_quirk) | 644 | static int rapl_check_hw_unit(bool apply_quirk) |
| 596 | { | 645 | { |
| 597 | u64 msr_rapl_power_unit_bits; | 646 | u64 msr_rapl_power_unit_bits; |
| @@ -660,7 +709,7 @@ static int __init rapl_prepare_cpus(void) · 62 unmodified lines | |||
| 660 | return 0; | 709 | return 0; |
| 661 | } | 710 | } |
| 662 | 711 | ||
| 663 | static void __init cleanup_rapl_pmus(void) | 712 | static void cleanup_rapl_pmus(void) |
| 664 | { | 713 | { |
| 665 | int i; | 714 | int i; |
| 666 | 715 | ||
| @@ -691,52 +740,92 @@ static int __init init_rapl_pmus(void) · 24 unmodified lines | |||
| 691 | return 0; | 740 | return 0; |
| 692 | } | 741 | } |
| 693 | 742 | ||
| 743 | #define X86_RAPL_MODEL_MATCH(model, init) \ | ||
| 744 | { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init } | ||
| 745 | |||
| 746 | struct intel_rapl_init_fun { | ||
| 747 | bool apply_quirk; | ||
| 748 | int cntr_mask; | ||
| 749 | struct attribute **attrs; | ||
| 750 | }; | ||
| 751 | |||
| 752 | static const struct intel_rapl_init_fun snb_rapl_init __initconst = { | ||
| 753 | .apply_quirk = false, | ||
| 754 | .cntr_mask = RAPL_IDX_CLN, | ||
| 755 | .attrs = rapl_events_cln_attr, | ||
| 756 | }; | ||
| 757 | |||
| 758 | static const struct intel_rapl_init_fun hsx_rapl_init __initconst = { | ||
| 759 | .apply_quirk = true, | ||
| 760 | .cntr_mask = RAPL_IDX_SRV, | ||
| 761 | .attrs = rapl_events_srv_attr, | ||
| 762 | }; | ||
| 763 | |||
| 764 | static const struct intel_rapl_init_fun hsw_rapl_init __initconst = { | ||
| 765 | .apply_quirk = false, | ||
| 766 | .cntr_mask = RAPL_IDX_HSW, | ||
| 767 | .attrs = rapl_events_hsw_attr, | ||
| 768 | }; | ||
| 769 | |||
| 770 | static const struct intel_rapl_init_fun snbep_rapl_init __initconst = { | ||
| 771 | .apply_quirk = false, | ||
| 772 | .cntr_mask = RAPL_IDX_SRV, | ||
| 773 | .attrs = rapl_events_srv_attr, | ||
| 774 | }; | ||
| 775 | |||
| 776 | static const struct intel_rapl_init_fun knl_rapl_init __initconst = { | ||
| 777 | .apply_quirk = true, | ||
| 778 | .cntr_mask = RAPL_IDX_KNL, | ||
| 779 | .attrs = rapl_events_knl_attr, | ||
| 780 | }; | ||
| 781 | |||
| 782 | static const struct intel_rapl_init_fun skl_rapl_init __initconst = { | ||
| 783 | .apply_quirk = false, | ||
| 784 | .cntr_mask = RAPL_IDX_SKL_CLN, | ||
| 785 | .attrs = rapl_events_skl_attr, | ||
| 786 | }; | ||
| 787 | |||
| 694 | static const struct x86_cpu_id rapl_cpu_match[] __initconst = { | 788 | static const struct x86_cpu_id rapl_cpu_match[] __initconst = { |
| 695 | [0] = { .vendor = X86_VENDOR_INTEL, .family = 6 }, | 789 | X86_RAPL_MODEL_MATCH(42, snb_rapl_init), /* Sandy Bridge */ |
| 696 | [1] = {}, | 790 | X86_RAPL_MODEL_MATCH(45, snbep_rapl_init), /* Sandy Bridge-EP */ |
| 791 | |||
| 792 | X86_RAPL_MODEL_MATCH(58, snb_rapl_init), /* Ivy Bridge */ | ||
| 793 | X86_RAPL_MODEL_MATCH(62, snbep_rapl_init), /* IvyTown */ | ||
| 794 | |||
| 795 | X86_RAPL_MODEL_MATCH(60, hsw_rapl_init), /* Haswell */ | ||
| 796 | X86_RAPL_MODEL_MATCH(63, hsx_rapl_init), /* Haswell-Server */ | ||
| 797 | X86_RAPL_MODEL_MATCH(69, hsw_rapl_init), /* Haswell-Celeron */ | ||
| 798 | X86_RAPL_MODEL_MATCH(70, hsw_rapl_init), /* Haswell GT3e */ | ||
| 799 | |||
| 800 | X86_RAPL_MODEL_MATCH(61, hsw_rapl_init), /* Broadwell */ | ||
| 801 | X86_RAPL_MODEL_MATCH(71, hsw_rapl_init), /* Broadwell-H */ | ||
| 802 | X86_RAPL_MODEL_MATCH(79, hsx_rapl_init), /* Broadwell-Server */ | ||
| 803 | X86_RAPL_MODEL_MATCH(86, hsx_rapl_init), /* Broadwell Xeon D */ | ||
| 804 | |||
| 805 | X86_RAPL_MODEL_MATCH(87, knl_rapl_init), /* Knights Landing */ | ||
| 806 | |||
| 807 | X86_RAPL_MODEL_MATCH(78, skl_rapl_init), /* Skylake */ | ||
| 808 | X86_RAPL_MODEL_MATCH(94, skl_rapl_init), /* Skylake H/S */ | ||
| 809 | {}, | ||
| 697 | }; | 810 | }; |
| 698 | 811 | ||
| 812 | MODULE_DEVICE_TABLE(x86cpu, rapl_cpu_match); | ||
| 813 | |||
| 699 | static int __init rapl_pmu_init(void) | 814 | static int __init rapl_pmu_init(void) |
| 700 | { | 815 | { |
| 701 | bool apply_quirk = false; | 816 | const struct x86_cpu_id *id; |
| 817 | struct intel_rapl_init_fun *rapl_init; | ||
| 818 | bool apply_quirk; | ||
| 702 | int ret; | 819 | int ret; |
| 703 | 820 | ||
| 704 | if (!x86_match_cpu(rapl_cpu_match)) | 821 | id = x86_match_cpu(rapl_cpu_match); |
| 822 | if (!id) | ||
| 705 | return -ENODEV; | 823 | return -ENODEV; |
| 706 | 824 | ||
| 707 | switch (boot_cpu_data.x86_model) { | 825 | rapl_init = (struct intel_rapl_init_fun *)id->driver_data; |
| 708 | case 42: /* Sandy Bridge */ | 826 | apply_quirk = rapl_init->apply_quirk; |
| 709 | case 58: /* Ivy Bridge */ | 827 | rapl_cntr_mask = rapl_init->cntr_mask; |
| 710 | rapl_cntr_mask = RAPL_IDX_CLN; | 828 | rapl_pmu_events_group.attrs = rapl_init->attrs; |
| 711 | rapl_pmu_events_group.attrs = rapl_events_cln_attr; | ||
| 712 | break; | ||
| 713 | case 63: /* Haswell-Server */ | ||
| 714 | case 79: /* Broadwell-Server */ | ||
| 715 | apply_quirk = true; | ||
| 716 | rapl_cntr_mask = RAPL_IDX_SRV; | ||
| 717 | rapl_pmu_events_group.attrs = rapl_events_srv_attr; | ||
| 718 | break; | ||
| 719 | case 60: /* Haswell */ | ||
| 720 | case 69: /* Haswell-Celeron */ | ||
| 721 | case 70: /* Haswell GT3e */ | ||
| 722 | case 61: /* Broadwell */ | ||
| 723 | case 71: /* Broadwell-H */ | ||
| 724 | rapl_cntr_mask = RAPL_IDX_HSW; | ||
| 725 | rapl_pmu_events_group.attrs = rapl_events_hsw_attr; | ||
| 726 | break; | ||
| 727 | case 45: /* Sandy Bridge-EP */ | ||
| 728 | case 62: /* IvyTown */ | ||
| 729 | rapl_cntr_mask = RAPL_IDX_SRV; | ||
| 730 | rapl_pmu_events_group.attrs = rapl_events_srv_attr; | ||
| 731 | break; | ||
| 732 | case 87: /* Knights Landing */ | ||
| 733 | apply_quirk = true; | ||
| 734 | rapl_cntr_mask = RAPL_IDX_KNL; | ||
| 735 | rapl_pmu_events_group.attrs = rapl_events_knl_attr; | ||
| 736 | break; | ||
| 737 | default: | ||
| 738 | return -ENODEV; | ||
| 739 | } | ||
| 740 | 829 | ||
| 741 | ret = rapl_check_hw_unit(apply_quirk); | 830 | ret = rapl_check_hw_unit(apply_quirk); |
| 742 | if (ret) | 831 | if (ret) |
| @@ -756,7 +845,7 @@ static int __init rapl_pmu_init(void) · 13 unmodified lines | |||
| 756 | if (ret) | 845 | if (ret) |
| 757 | goto out; | 846 | goto out; |
| 758 | 847 | ||
| 759 | __perf_cpu_notifier(rapl_cpu_notifier); | 848 | __register_cpu_notifier(&rapl_cpu_nb); |
| 760 | cpu_notifier_register_done(); | 849 | cpu_notifier_register_done(); |
| 761 | rapl_advertise(); | 850 | rapl_advertise(); |
| 762 | return 0; | 851 | return 0; |
| @@ -767,4 +856,14 @@ out: · 4 unmodified lines | |||
| 767 | cpu_notifier_register_done(); | 856 | cpu_notifier_register_done(); |
| 768 | return ret; | 857 | return ret; |
| 769 | } | 858 | } |
| 770 | device_initcall(rapl_pmu_init); | 859 | module_init(rapl_pmu_init); |
| 860 | |||
| 861 | static void __exit intel_rapl_exit(void) | ||
| 862 | { | ||
| 863 | cpu_notifier_register_begin(); | ||
| 864 | __unregister_cpu_notifier(&rapl_cpu_nb); | ||
| 865 | perf_pmu_unregister(&rapl_pmus->pmu); | ||
| 866 | cleanup_rapl_pmus(); | ||
| 867 | cpu_notifier_register_done(); | ||
| 868 | } | ||
| 869 | module_exit(intel_rapl_exit); | ||
| @@ -1,3 +1,4 @@ | |||
| 1 | #include <asm/cpu_device_id.h> | ||
| 1 | #include "uncore.h" | 2 | #include "uncore.h" |
| 2 | 3 | ||
| 3 | static struct intel_uncore_type *empty_uncore[] = { NULL, }; | 4 | static struct intel_uncore_type *empty_uncore[] = { NULL, }; |
| @@ -21,6 +22,8 @@ static struct event_constraint uncore_constraint_fixed = · 17 unmodified lines | |||
| 21 | struct event_constraint uncore_constraint_empty = | 22 | struct event_constraint uncore_constraint_empty = |
| 22 | EVENT_CONSTRAINT(0, 0, 0); | 23 | EVENT_CONSTRAINT(0, 0, 0); |
| 23 | 24 | ||
| 25 | MODULE_LICENSE("GPL"); | ||
| 26 | |||
| 24 | static int uncore_pcibus_to_physid(struct pci_bus *bus) | 27 | static int uncore_pcibus_to_physid(struct pci_bus *bus) |
| 25 | { | 28 | { |
| 26 | struct pci2phy_map *map; | 29 | struct pci2phy_map *map; |
| @@ -754,7 +757,7 @@ static void uncore_pmu_unregister(struct intel_uncore_pmu *pmu) · 727 unmodified lines | |||
| 754 | pmu->registered = false; | 757 | pmu->registered = false; |
| 755 | } | 758 | } |
| 756 | 759 | ||
| 757 | static void __init __uncore_exit_boxes(struct intel_uncore_type *type, int cpu) | 760 | static void __uncore_exit_boxes(struct intel_uncore_type *type, int cpu) |
| 758 | { | 761 | { |
| 759 | struct intel_uncore_pmu *pmu = type->pmus; | 762 | struct intel_uncore_pmu *pmu = type->pmus; |
| 760 | struct intel_uncore_box *box; | 763 | struct intel_uncore_box *box; |
| @@ -770,7 +773,7 @@ static void __init __uncore_exit_boxes(struct intel_uncore_type *type, int cpu) · 9 unmodified lines | |||
| 770 | } | 773 | } |
| 771 | } | 774 | } |
| 772 | 775 | ||
| 773 | static void __init uncore_exit_boxes(void *dummy) | 776 | static void uncore_exit_boxes(void *dummy) |
| 774 | { | 777 | { |
| 775 | struct intel_uncore_type **types; | 778 | struct intel_uncore_type **types; |
| 776 | 779 | ||
| @@ -787,7 +790,7 @@ static void uncore_free_boxes(struct intel_uncore_pmu *pmu) · 10 unmodified lines | |||
| 787 | kfree(pmu->boxes); | 790 | kfree(pmu->boxes); |
| 788 | } | 791 | } |
| 789 | 792 | ||
| 790 | static void __init uncore_type_exit(struct intel_uncore_type *type) | 793 | static void uncore_type_exit(struct intel_uncore_type *type) |
| 791 | { | 794 | { |
| 792 | struct intel_uncore_pmu *pmu = type->pmus; | 795 | struct intel_uncore_pmu *pmu = type->pmus; |
| 793 | int i; | 796 | int i; |
| @@ -804,7 +807,7 @@ static void __init uncore_type_exit(struct intel_uncore_type *type) · 10 unmodified lines | |||
| 804 | type->events_group = NULL; | 807 | type->events_group = NULL; |
| 805 | } | 808 | } |
| 806 | 809 | ||
| 807 | static void __init uncore_types_exit(struct intel_uncore_type **types) | 810 | static void uncore_types_exit(struct intel_uncore_type **types) |
| 808 | { | 811 | { |
| 809 | for (; *types; types++) | 812 | for (; *types; types++) |
| 810 | uncore_type_exit(*types); | 813 | uncore_type_exit(*types); |
| @@ -989,46 +992,6 @@ static int __init uncore_pci_init(void) · 178 unmodified lines | |||
| 989 | size_t size; | 992 | size_t size; |
| 990 | int ret; | 993 | int ret; |
| 991 | 994 | ||
| 992 | switch (boot_cpu_data.x86_model) { | ||
| 993 | case 45: /* Sandy Bridge-EP */ | ||
| 994 | ret = snbep_uncore_pci_init(); | ||
| 995 | break; | ||
| 996 | case 62: /* Ivy Bridge-EP */ | ||
| 997 | ret = ivbep_uncore_pci_init(); | ||
| 998 | break; | ||
| 999 | case 63: /* Haswell-EP */ | ||
| 1000 | ret = hswep_uncore_pci_init(); | ||
| 1001 | break; | ||
| 1002 | case 79: /* BDX-EP */ | ||
| 1003 | case 86: /* BDX-DE */ | ||
| 1004 | ret = bdx_uncore_pci_init(); | ||
| 1005 | break; | ||
| 1006 | case 42: /* Sandy Bridge */ | ||
| 1007 | ret = snb_uncore_pci_init(); | ||
| 1008 | break; | ||
| 1009 | case 58: /* Ivy Bridge */ | ||
| 1010 | ret = ivb_uncore_pci_init(); | ||
| 1011 | break; | ||
| 1012 | case 60: /* Haswell */ | ||
| 1013 | case 69: /* Haswell Celeron */ | ||
| 1014 | ret = hsw_uncore_pci_init(); | ||
| 1015 | break; | ||
| 1016 | case 61: /* Broadwell */ | ||
| 1017 | ret = bdw_uncore_pci_init(); | ||
| 1018 | break; | ||
| 1019 | case 87: /* Knights Landing */ | ||
| 1020 | ret = knl_uncore_pci_init(); | ||
| 1021 | break; | ||
| 1022 | case 94: /* SkyLake */ | ||
| 1023 | ret = skl_uncore_pci_init(); | ||
| 1024 | break; | ||
| 1025 | default: | ||
| 1026 | return -ENODEV; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | if (ret) | ||
| 1030 | return ret; | ||
| 1031 | |||
| 1032 | size = max_packages * sizeof(struct pci_extra_dev); | 995 | size = max_packages * sizeof(struct pci_extra_dev); |
| 1033 | uncore_extra_pci_dev = kzalloc(size, GFP_KERNEL); | 996 | uncore_extra_pci_dev = kzalloc(size, GFP_KERNEL); |
| 1034 | if (!uncore_extra_pci_dev) { | 997 | if (!uncore_extra_pci_dev) { |
| @@ -1060,7 +1023,7 @@ err: · 25 unmodified lines | |||
| 1060 | return ret; | 1023 | return ret; |
| 1061 | } | 1024 | } |
| 1062 | 1025 | ||
| 1063 | static void __init uncore_pci_exit(void) | 1026 | static void uncore_pci_exit(void) |
| 1064 | { | 1027 | { |
| 1065 | if (pcidrv_registered) { | 1028 | if (pcidrv_registered) { |
| 1066 | pcidrv_registered = false; | 1029 | pcidrv_registered = false; |
| @@ -1287,46 +1250,6 @@ static int __init uncore_cpu_init(void) · 220 unmodified lines | |||
| 1287 | { | 1250 | { |
| 1288 | int ret; | 1251 | int ret; |
| 1289 | 1252 | ||
| 1290 | switch (boot_cpu_data.x86_model) { | ||
| 1291 | case 26: /* Nehalem */ | ||
| 1292 | case 30: | ||
| 1293 | case 37: /* Westmere */ | ||
| 1294 | case 44: | ||
| 1295 | nhm_uncore_cpu_init(); | ||
| 1296 | break; | ||
| 1297 | case 42: /* Sandy Bridge */ | ||
| 1298 | case 58: /* Ivy Bridge */ | ||
| 1299 | case 60: /* Haswell */ | ||
| 1300 | case 69: /* Haswell */ | ||
| 1301 | case 70: /* Haswell */ | ||
| 1302 | case 61: /* Broadwell */ | ||
| 1303 | case 71: /* Broadwell */ | ||
| 1304 | snb_uncore_cpu_init(); | ||
| 1305 | break; | ||
| 1306 | case 45: /* Sandy Bridge-EP */ | ||
| 1307 | snbep_uncore_cpu_init(); | ||
| 1308 | break; | ||
| 1309 | case 46: /* Nehalem-EX */ | ||
| 1310 | case 47: /* Westmere-EX aka. Xeon E7 */ | ||
| 1311 | nhmex_uncore_cpu_init(); | ||
| 1312 | break; | ||
| 1313 | case 62: /* Ivy Bridge-EP */ | ||
| 1314 | ivbep_uncore_cpu_init(); | ||
| 1315 | break; | ||
| 1316 | case 63: /* Haswell-EP */ | ||
| 1317 | hswep_uncore_cpu_init(); | ||
| 1318 | break; | ||
| 1319 | case 79: /* BDX-EP */ | ||
| 1320 | case 86: /* BDX-DE */ | ||
| 1321 | bdx_uncore_cpu_init(); | ||
| 1322 | break; | ||
| 1323 | case 87: /* Knights Landing */ | ||
| 1324 | knl_uncore_cpu_init(); | ||
| 1325 | break; | ||
| 1326 | default: | ||
| 1327 | return -ENODEV; | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | ret = uncore_types_init(uncore_msr_uncores, true); | 1253 | ret = uncore_types_init(uncore_msr_uncores, true); |
| 1331 | if (ret) | 1254 | if (ret) |
| 1332 | goto err; | 1255 | goto err; |
| @@ -1376,11 +1299,105 @@ static int __init uncore_cpumask_init(bool msr) · 43 unmodified lines | |||
| 1376 | return 0; | 1299 | return 0; |
| 1377 | } | 1300 | } |
| 1378 | 1301 | ||
| 1302 | #define X86_UNCORE_MODEL_MATCH(model, init) \ | ||
| 1303 | { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init } | ||
| 1304 | |||
| 1305 | struct intel_uncore_init_fun { | ||
| 1306 | void (*cpu_init)(void); | ||
| 1307 | int (*pci_init)(void); | ||
| 1308 | }; | ||
| 1309 | |||
| 1310 | static const struct intel_uncore_init_fun nhm_uncore_init __initconst = { | ||
| 1311 | .cpu_init = nhm_uncore_cpu_init, | ||
| 1312 | }; | ||
| 1313 | |||
| 1314 | static const struct intel_uncore_init_fun snb_uncore_init __initconst = { | ||
| 1315 | .cpu_init = snb_uncore_cpu_init, | ||
| 1316 | .pci_init = snb_uncore_pci_init, | ||
| 1317 | }; | ||
| 1318 | |||
| 1319 | static const struct intel_uncore_init_fun ivb_uncore_init __initconst = { | ||
| 1320 | .cpu_init = snb_uncore_cpu_init, | ||
| 1321 | .pci_init = ivb_uncore_pci_init, | ||
| 1322 | }; | ||
| 1323 | |||
| 1324 | static const struct intel_uncore_init_fun hsw_uncore_init __initconst = { | ||
| 1325 | .cpu_init = snb_uncore_cpu_init, | ||
| 1326 | .pci_init = hsw_uncore_pci_init, | ||
| 1327 | }; | ||
| 1328 | |||
| 1329 | static const struct intel_uncore_init_fun bdw_uncore_init __initconst = { | ||
| 1330 | .cpu_init = snb_uncore_cpu_init, | ||
| 1331 | .pci_init = bdw_uncore_pci_init, | ||
| 1332 | }; | ||
| 1333 | |||
| 1334 | static const struct intel_uncore_init_fun snbep_uncore_init __initconst = { | ||
| 1335 | .cpu_init = snbep_uncore_cpu_init, | ||
| 1336 | .pci_init = snbep_uncore_pci_init, | ||
| 1337 | }; | ||
| 1338 | |||
| 1339 | static const struct intel_uncore_init_fun nhmex_uncore_init __initconst = { | ||
| 1340 | .cpu_init = nhmex_uncore_cpu_init, | ||
| 1341 | }; | ||
| 1342 | |||
| 1343 | static const struct intel_uncore_init_fun ivbep_uncore_init __initconst = { | ||
| 1344 | .cpu_init = ivbep_uncore_cpu_init, | ||
| 1345 | .pci_init = ivbep_uncore_pci_init, | ||
| 1346 | }; | ||
| 1347 | |||
| 1348 | static const struct intel_uncore_init_fun hswep_uncore_init __initconst = { | ||
| 1349 | .cpu_init = hswep_uncore_cpu_init, | ||
| 1350 | .pci_init = hswep_uncore_pci_init, | ||
| 1351 | }; | ||
| 1352 | |||
| 1353 | static const struct intel_uncore_init_fun bdx_uncore_init __initconst = { | ||
| 1354 | .cpu_init = bdx_uncore_cpu_init, | ||
| 1355 | .pci_init = bdx_uncore_pci_init, | ||
| 1356 | }; | ||
| 1357 | |||
| 1358 | static const struct intel_uncore_init_fun knl_uncore_init __initconst = { | ||
| 1359 | .cpu_init = knl_uncore_cpu_init, | ||
| 1360 | .pci_init = knl_uncore_pci_init, | ||
| 1361 | }; | ||
| 1362 | |||
| 1363 | static const struct intel_uncore_init_fun skl_uncore_init __initconst = { | ||
| 1364 | .pci_init = skl_uncore_pci_init, | ||
| 1365 | }; | ||
| 1366 | |||
| 1367 | static const struct x86_cpu_id intel_uncore_match[] __initconst = { | ||
| 1368 | X86_UNCORE_MODEL_MATCH(26, nhm_uncore_init), /* Nehalem */ | ||
| 1369 | X86_UNCORE_MODEL_MATCH(30, nhm_uncore_init), | ||
| 1370 | X86_UNCORE_MODEL_MATCH(37, nhm_uncore_init), /* Westmere */ | ||
| 1371 | X86_UNCORE_MODEL_MATCH(44, nhm_uncore_init), | ||
| 1372 | X86_UNCORE_MODEL_MATCH(42, snb_uncore_init), /* Sandy Bridge */ | ||
| 1373 | X86_UNCORE_MODEL_MATCH(58, ivb_uncore_init), /* Ivy Bridge */ | ||
| 1374 | X86_UNCORE_MODEL_MATCH(60, hsw_uncore_init), /* Haswell */ | ||
| 1375 | X86_UNCORE_MODEL_MATCH(69, hsw_uncore_init), /* Haswell Celeron */ | ||
| 1376 | X86_UNCORE_MODEL_MATCH(70, hsw_uncore_init), /* Haswell */ | ||
| 1377 | X86_UNCORE_MODEL_MATCH(61, bdw_uncore_init), /* Broadwell */ | ||
| 1378 | X86_UNCORE_MODEL_MATCH(71, bdw_uncore_init), /* Broadwell */ | ||
| 1379 | X86_UNCORE_MODEL_MATCH(45, snbep_uncore_init), /* Sandy Bridge-EP */ | ||
| 1380 | X86_UNCORE_MODEL_MATCH(46, nhmex_uncore_init), /* Nehalem-EX */ | ||
| 1381 | X86_UNCORE_MODEL_MATCH(47, nhmex_uncore_init), /* Westmere-EX aka. Xeon E7 */ | ||
| 1382 | X86_UNCORE_MODEL_MATCH(62, ivbep_uncore_init), /* Ivy Bridge-EP */ | ||
| 1383 | X86_UNCORE_MODEL_MATCH(63, hswep_uncore_init), /* Haswell-EP */ | ||
| 1384 | X86_UNCORE_MODEL_MATCH(79, bdx_uncore_init), /* BDX-EP */ | ||
| 1385 | X86_UNCORE_MODEL_MATCH(86, bdx_uncore_init), /* BDX-DE */ | ||
| 1386 | X86_UNCORE_MODEL_MATCH(87, knl_uncore_init), /* Knights Landing */ | ||
| 1387 | X86_UNCORE_MODEL_MATCH(94, skl_uncore_init), /* SkyLake */ | ||
| 1388 | {}, | ||
| 1389 | }; | ||
| 1390 | |||
| 1391 | MODULE_DEVICE_TABLE(x86cpu, intel_uncore_match); | ||
| 1392 | |||
| 1379 | static int __init intel_uncore_init(void) | 1393 | static int __init intel_uncore_init(void) |
| 1380 | { | 1394 | { |
| 1381 | int pret, cret, ret; | 1395 | const struct x86_cpu_id *id; |
| 1396 | struct intel_uncore_init_fun *uncore_init; | ||
| 1397 | int pret = 0, cret = 0, ret; | ||
| 1382 | 1398 | ||
| 1383 | if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) | 1399 | id = x86_match_cpu(intel_uncore_match); |
| 1400 | if (!id) | ||
| 1384 | return -ENODEV; | 1401 | return -ENODEV; |
| 1385 | 1402 | ||
| 1386 | if (cpu_has_hypervisor) | 1403 | if (cpu_has_hypervisor) |
| @@ -1388,8 +1405,17 @@ static int __init intel_uncore_init(void) · 1 unmodified line | |||
| 1388 | 1405 | ||
| 1389 | max_packages = topology_max_packages(); | 1406 | max_packages = topology_max_packages(); |
| 1390 | 1407 | ||
| 1391 | pret = uncore_pci_init(); | 1408 | uncore_init = (struct intel_uncore_init_fun *)id->driver_data; |
| 1392 | cret = uncore_cpu_init(); | 1409 | if (uncore_init->pci_init) { |
| 1410 | pret = uncore_init->pci_init(); | ||
| 1411 | if (!pret) | ||
| 1412 | pret = uncore_pci_init(); | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | if (uncore_init->cpu_init) { | ||
| 1416 | uncore_init->cpu_init(); | ||
| 1417 | cret = uncore_cpu_init(); | ||
| 1418 | } | ||
| 1393 | 1419 | ||
| 1394 | if (cret && pret) | 1420 | if (cret && pret) |
| 1395 | return -ENODEV; | 1421 | return -ENODEV; |
| @@ -1409,4 +1435,14 @@ err: · 13 unmodified lines | |||
| 1409 | cpu_notifier_register_done(); | 1435 | cpu_notifier_register_done(); |
| 1410 | return ret; | 1436 | return ret; |
| 1411 | } | 1437 | } |
| 1412 | device_initcall(intel_uncore_init); | 1438 | module_init(intel_uncore_init); |
| 1439 | |||
| 1440 | static void __exit intel_uncore_exit(void) | ||
| 1441 | { | ||
| 1442 | cpu_notifier_register_begin(); | ||
| 1443 | __unregister_cpu_notifier(&uncore_cpu_nb); | ||
| 1444 | uncore_types_exit(uncore_msr_uncores); | ||
| 1445 | uncore_pci_exit(); | ||
| 1446 | cpu_notifier_register_done(); | ||
| 1447 | } | ||
| 1448 | module_exit(intel_uncore_exit); | ||
| @@ -6,6 +6,8 @@ enum perf_msr_id { · 5 unmodified lines | |||
| 6 | PERF_MSR_MPERF = 2, | 6 | PERF_MSR_MPERF = 2, |
| 7 | PERF_MSR_PPERF = 3, | 7 | PERF_MSR_PPERF = 3, |
| 8 | PERF_MSR_SMI = 4, | 8 | PERF_MSR_SMI = 4, |
| 9 | PERF_MSR_PTSC = 5, | ||
| 10 | PERF_MSR_IRPERF = 6, | ||
| 9 | 11 | ||
| 10 | PERF_MSR_EVENT_MAX, | 12 | PERF_MSR_EVENT_MAX, |
| 11 | }; | 13 | }; |
| @@ -15,6 +17,16 @@ static bool test_aperfmperf(int idx) · 3 unmodified lines | |||
| 15 | return boot_cpu_has(X86_FEATURE_APERFMPERF); | 17 | return boot_cpu_has(X86_FEATURE_APERFMPERF); |
| 16 | } | 18 | } |
| 17 | 19 | ||
| 20 | static bool test_ptsc(int idx) | ||
| 21 | { | ||
| 22 | return boot_cpu_has(X86_FEATURE_PTSC); | ||
| 23 | } | ||
| 24 | |||
| 25 | static bool test_irperf(int idx) | ||
| 26 | { | ||
| 27 | return boot_cpu_has(X86_FEATURE_IRPERF); | ||
| 28 | } | ||
| 29 | |||
| 18 | static bool test_intel(int idx) | 30 | static bool test_intel(int idx) |
| 19 | { | 31 | { |
| 20 | if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || | 32 | if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || |
| @@ -69,18 +81,22 @@ struct perf_msr { · 48 unmodified lines | |||
| 69 | bool (*test)(int idx); | 81 | bool (*test)(int idx); |
| 70 | }; | 82 | }; |
| 71 | 83 | ||
| 72 | PMU_EVENT_ATTR_STRING(tsc, evattr_tsc, "event=0x00"); | 84 | PMU_EVENT_ATTR_STRING(tsc, evattr_tsc, "event=0x00"); |
| 73 | PMU_EVENT_ATTR_STRING(aperf, evattr_aperf, "event=0x01"); | 85 | PMU_EVENT_ATTR_STRING(aperf, evattr_aperf, "event=0x01"); |
| 74 | PMU_EVENT_ATTR_STRING(mperf, evattr_mperf, "event=0x02"); | 86 | PMU_EVENT_ATTR_STRING(mperf, evattr_mperf, "event=0x02"); |
| 75 | PMU_EVENT_ATTR_STRING(pperf, evattr_pperf, "event=0x03"); | 87 | PMU_EVENT_ATTR_STRING(pperf, evattr_pperf, "event=0x03"); |
| 76 | PMU_EVENT_ATTR_STRING(smi, evattr_smi, "event=0x04"); | 88 | PMU_EVENT_ATTR_STRING(smi, evattr_smi, "event=0x04"); |
| 89 | PMU_EVENT_ATTR_STRING(ptsc, evattr_ptsc, "event=0x05"); | ||
| 90 | PMU_EVENT_ATTR_STRING(irperf, evattr_irperf, "event=0x06"); | ||
| 77 | 91 | ||
| 78 | static struct perf_msr msr[] = { | 92 | static struct perf_msr msr[] = { |
| 79 | [PERF_MSR_TSC] = { 0, &evattr_tsc, NULL, }, | 93 | [PERF_MSR_TSC] = { 0, &evattr_tsc, NULL, }, |
| 80 | [PERF_MSR_APERF] = { MSR_IA32_APERF, &evattr_aperf, test_aperfmperf, }, | 94 | [PERF_MSR_APERF] = { MSR_IA32_APERF, &evattr_aperf, test_aperfmperf, }, |
| 81 | [PERF_MSR_MPERF] = { MSR_IA32_MPERF, &evattr_mperf, test_aperfmperf, }, | 95 | [PERF_MSR_MPERF] = { MSR_IA32_MPERF, &evattr_mperf, test_aperfmperf, }, |
| 82 | [PERF_MSR_PPERF] = { MSR_PPERF, &evattr_pperf, test_intel, }, | 96 | [PERF_MSR_PPERF] = { MSR_PPERF, &evattr_pperf, test_intel, }, |
| 83 | [PERF_MSR_SMI] = { MSR_SMI_COUNT, &evattr_smi, test_intel, }, | 97 | [PERF_MSR_SMI] = { MSR_SMI_COUNT, &evattr_smi, test_intel, }, |
| 98 | [PERF_MSR_PTSC] = { MSR_F15H_PTSC, &evattr_ptsc, test_ptsc, }, | ||
| 99 | [PERF_MSR_IRPERF] = { MSR_F17H_IRPERF, &evattr_irperf, test_irperf, }, | ||
| 84 | }; | 100 | }; |
| 85 | 101 | ||
| 86 | static struct attribute *events_attrs[PERF_MSR_EVENT_MAX + 1] = { | 102 | static struct attribute *events_attrs[PERF_MSR_EVENT_MAX + 1] = { |
| @@ -601,6 +601,7 @@ struct x86_pmu { · 600 unmodified lines | |||
| 601 | u64 lbr_sel_mask; /* LBR_SELECT valid bits */ | 601 | u64 lbr_sel_mask; /* LBR_SELECT valid bits */ |
| 602 | const int *lbr_sel_map; /* lbr_select mappings */ | 602 | const int *lbr_sel_map; /* lbr_select mappings */ |
| 603 | bool lbr_double_abort; /* duplicated lbr aborts */ | 603 | bool lbr_double_abort; /* duplicated lbr aborts */ |
| 604 | bool lbr_pt_coexist; /* LBR may coexist with PT */ | ||
| 604 | 605 | ||
| 605 | /* | 606 | /* |
| 606 | * Intel PT/LBR/BTS are exclusive | 607 | * Intel PT/LBR/BTS are exclusive |
| @@ -859,6 +860,8 @@ extern struct event_constraint intel_atom_pebs_event_constraints[]; · 252 unmodified lines | |||
| 859 | 860 | ||
| 860 | extern struct event_constraint intel_slm_pebs_event_constraints[]; | 861 | extern struct event_constraint intel_slm_pebs_event_constraints[]; |
| 861 | 862 | ||
| 863 | extern struct event_constraint intel_glm_pebs_event_constraints[]; | ||
| 864 | |||
| 862 | extern struct event_constraint intel_nehalem_pebs_event_constraints[]; | 865 | extern struct event_constraint intel_nehalem_pebs_event_constraints[]; |
| 863 | 866 | ||
| 864 | extern struct event_constraint intel_westmere_pebs_event_constraints[]; | 867 | extern struct event_constraint intel_westmere_pebs_event_constraints[]; |
| @@ -907,6 +910,8 @@ void intel_pmu_lbr_init_nhm(void); · 42 unmodified lines | |||
| 907 | 910 | ||
| 908 | void intel_pmu_lbr_init_atom(void); | 911 | void intel_pmu_lbr_init_atom(void); |
| 909 | 912 | ||
| 913 | void intel_pmu_lbr_init_slm(void); | ||
| 914 | |||
| 910 | void intel_pmu_lbr_init_snb(void); | 915 | void intel_pmu_lbr_init_snb(void); |
| 911 | 916 | ||
| 912 | void intel_pmu_lbr_init_hsw(void); | 917 | void intel_pmu_lbr_init_hsw(void); |
| @@ -177,6 +177,7 @@ · 176 unmodified lines | |||
| 177 | #define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ | 177 | #define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ |
| 178 | #define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ | 178 | #define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ |
| 179 | #define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */ | 179 | #define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */ |
| 180 | #define X86_FEATURE_PTSC ( 6*32+27) /* performance time-stamp counter */ | ||
| 180 | #define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */ | 181 | #define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */ |
| 181 | #define X86_FEATURE_MWAITX ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */ | 182 | #define X86_FEATURE_MWAITX ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */ |
| 182 | 183 | ||
| @@ -250,6 +251,7 @@ · 67 unmodified lines | |||
| 250 | 251 | ||
| 251 | /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ | 252 | /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ |
| 252 | #define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ | 253 | #define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ |
| 254 | #define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */ | ||
| 253 | 255 | ||
| 254 | /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ | 256 | /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ |
| 255 | #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ | 257 | #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ |
| @@ -89,27 +89,16 @@ · 88 unmodified lines | |||
| 89 | #define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 | 89 | #define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 |
| 90 | 90 | ||
| 91 | #define MSR_IA32_RTIT_CTL 0x00000570 | 91 | #define MSR_IA32_RTIT_CTL 0x00000570 |
| 92 | #define RTIT_CTL_TRACEEN BIT(0) | ||
| 93 | #define RTIT_CTL_CYCLEACC BIT(1) | ||
| 94 | #define RTIT_CTL_OS BIT(2) | ||
| 95 | #define RTIT_CTL_USR BIT(3) | ||
| 96 | #define RTIT_CTL_CR3EN BIT(7) | ||
| 97 | #define RTIT_CTL_TOPA BIT(8) | ||
| 98 | #define RTIT_CTL_MTC_EN BIT(9) | ||
| 99 | #define RTIT_CTL_TSC_EN BIT(10) | ||
| 100 | #define RTIT_CTL_DISRETC BIT(11) | ||
| 101 | #define RTIT_CTL_BRANCH_EN BIT(13) | ||
| 102 | #define RTIT_CTL_MTC_RANGE_OFFSET 14 | ||
| 103 | #define RTIT_CTL_MTC_RANGE (0x0full << RTIT_CTL_MTC_RANGE_OFFSET) | ||
| 104 | #define RTIT_CTL_CYC_THRESH_OFFSET 19 | ||
| 105 | #define RTIT_CTL_CYC_THRESH (0x0full << RTIT_CTL_CYC_THRESH_OFFSET) | ||
| 106 | #define RTIT_CTL_PSB_FREQ_OFFSET 24 | ||
| 107 | #define RTIT_CTL_PSB_FREQ (0x0full << RTIT_CTL_PSB_FREQ_OFFSET) | ||
| 108 | #define MSR_IA32_RTIT_STATUS 0x00000571 | 92 | #define MSR_IA32_RTIT_STATUS 0x00000571 |
| 109 | #define RTIT_STATUS_CONTEXTEN BIT(1) | 93 | #define MSR_IA32_RTIT_STATUS 0x00000571 |
| 110 | #define RTIT_STATUS_TRIGGEREN BIT(2) | 94 | #define MSR_IA32_RTIT_ADDR0_A 0x00000580 |
| 111 | #define RTIT_STATUS_ERROR BIT(4) | 95 | #define MSR_IA32_RTIT_ADDR0_B 0x00000581 |
| 112 | #define RTIT_STATUS_STOPPED BIT(5) | 96 | #define MSR_IA32_RTIT_ADDR1_A 0x00000582 |
| 97 | #define MSR_IA32_RTIT_ADDR1_B 0x00000583 | ||
| 98 | #define MSR_IA32_RTIT_ADDR2_A 0x00000584 | ||
| 99 | #define MSR_IA32_RTIT_ADDR2_B 0x00000585 | ||
| 100 | #define MSR_IA32_RTIT_ADDR3_A 0x00000586 | ||
| 101 | #define MSR_IA32_RTIT_ADDR3_B 0x00000587 | ||
| 113 | #define MSR_IA32_RTIT_CR3_MATCH 0x00000572 | 102 | #define MSR_IA32_RTIT_CR3_MATCH 0x00000572 |
| 114 | #define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560 | 103 | #define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560 |
| 115 | #define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561 | 104 | #define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561 |
| @@ -205,6 +194,8 @@ · 89 unmodified lines | |||
| 205 | #define MSR_CONFIG_TDP_CONTROL 0x0000064B | 194 | #define MSR_CONFIG_TDP_CONTROL 0x0000064B |
| 206 | #define MSR_TURBO_ACTIVATION_RATIO 0x0000064C | 195 | #define MSR_TURBO_ACTIVATION_RATIO 0x0000064C |
| 207 | 196 | ||
| 197 | #define MSR_PLATFORM_ENERGY_STATUS 0x0000064D | ||
| 198 | |||
| 208 | #define MSR_PKG_WEIGHTED_CORE_C0_RES 0x00000658 | 199 | #define MSR_PKG_WEIGHTED_CORE_C0_RES 0x00000658 |
| 209 | #define MSR_PKG_ANY_CORE_C0_RES 0x00000659 | 200 | #define MSR_PKG_ANY_CORE_C0_RES 0x00000659 |
| 210 | #define MSR_PKG_ANY_GFXE_C0_RES 0x0000065A | 201 | #define MSR_PKG_ANY_GFXE_C0_RES 0x0000065A |
| @@ -315,6 +306,9 @@ · 104 unmodified lines | |||
| 315 | #define MSR_AMD64_IBSOPDATA4 0xc001103d | 306 | #define MSR_AMD64_IBSOPDATA4 0xc001103d |
| 316 | #define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */ | 307 | #define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */ |
| 317 | 308 | ||
| 309 | /* Fam 17h MSRs */ | ||
| 310 | #define MSR_F17H_IRPERF 0xc00000e9 | ||
| 311 | |||
| 318 | /* Fam 16h MSRs */ | 312 | /* Fam 16h MSRs */ |
| 319 | #define MSR_F16H_L2I_PERF_CTL 0xc0010230 | 313 | #define MSR_F16H_L2I_PERF_CTL 0xc0010230 |
| 320 | #define MSR_F16H_L2I_PERF_CTR 0xc0010231 | 314 | #define MSR_F16H_L2I_PERF_CTR 0xc0010231 |
| @@ -328,6 +322,7 @@ · 7 unmodified lines | |||
| 328 | #define MSR_F15H_PERF_CTR 0xc0010201 | 322 | #define MSR_F15H_PERF_CTR 0xc0010201 |
| 329 | #define MSR_F15H_NB_PERF_CTL 0xc0010240 | 323 | #define MSR_F15H_NB_PERF_CTL 0xc0010240 |
| 330 | #define MSR_F15H_NB_PERF_CTR 0xc0010241 | 324 | #define MSR_F15H_NB_PERF_CTR 0xc0010241 |
| 325 | #define MSR_F15H_PTSC 0xc0010280 | ||
| 331 | #define MSR_F15H_IC_CFG 0xc0011021 | 326 | #define MSR_F15H_IC_CFG 0xc0011021 |
| 332 | 327 | ||
| 333 | /* Fam 10h MSRs */ | 328 | /* Fam 10h MSRs */ |
| @@ -578,7 +578,7 @@ static void default_abort_op(struct arch_uprobe *auprobe, struct pt_regs *regs) · 577 unmodified lines | |||
| 578 | riprel_post_xol(auprobe, regs); | 578 | riprel_post_xol(auprobe, regs); |
| 579 | } | 579 | } |
| 580 | 580 | ||
| 581 | static struct uprobe_xol_ops default_xol_ops = { | 581 | static const struct uprobe_xol_ops default_xol_ops = { |
| 582 | .pre_xol = default_pre_xol_op, | 582 | .pre_xol = default_pre_xol_op, |
| 583 | .post_xol = default_post_xol_op, | 583 | .post_xol = default_post_xol_op, |
| 584 | .abort = default_abort_op, | 584 | .abort = default_abort_op, |
| @@ -695,7 +695,7 @@ static void branch_clear_offset(struct arch_uprobe *auprobe, struct insn *insn) · 110 unmodified lines | |||
| 695 | 0, insn->immediate.nbytes); | 695 | 0, insn->immediate.nbytes); |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | static struct uprobe_xol_ops branch_xol_ops = { | 698 | static const struct uprobe_xol_ops branch_xol_ops = { |
| 699 | .emulate = branch_emulate_op, | 699 | .emulate = branch_emulate_op, |
| 700 | .post_xol = branch_post_xol_op, | 700 | .post_xol = branch_post_xol_op, |
| 701 | }; | 701 | }; |
| @@ -332,14 +332,14 @@ static int callchain_trace(struct stackframe *frame, void *data) · 331 unmodified lines | |||
| 332 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | 332 | void perf_callchain_kernel(struct perf_callchain_entry *entry, |
| 333 | struct pt_regs *regs) | 333 | struct pt_regs *regs) |
| 334 | { | 334 | { |
| 335 | xtensa_backtrace_kernel(regs, PERF_MAX_STACK_DEPTH, | 335 | xtensa_backtrace_kernel(regs, sysctl_perf_event_max_stack, |
| 336 | callchain_trace, NULL, entry); | 336 | callchain_trace, NULL, entry); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | void perf_callchain_user(struct perf_callchain_entry *entry, | 339 | void perf_callchain_user(struct perf_callchain_entry *entry, |
| 340 | struct pt_regs *regs) | 340 | struct pt_regs *regs) |
| 341 | { | 341 | { |
| 342 | xtensa_backtrace_user(regs, PERF_MAX_STACK_DEPTH, | 342 | xtensa_backtrace_user(regs, sysctl_perf_event_max_stack, |
| 343 | callchain_trace, entry); | 343 | callchain_trace, entry); |
| 344 | } | 344 | } |
| 345 | 345 | ||
| @@ -847,6 +847,14 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu) · 846 unmodified lines | |||
| 847 | if (!platform_get_irq(cpu_pmu->plat_device, 0)) | 847 | if (!platform_get_irq(cpu_pmu->plat_device, 0)) |
| 848 | cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; | 848 | cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; |
| 849 | 849 | ||
| 850 | /* | ||
| 851 | * This is a CPU PMU potentially in a heterogeneous configuration (e.g. | ||
| 852 | * big.LITTLE). This is not an uncore PMU, and we have taken ctx | ||
| 853 | * sharing into account (e.g. with our pmu::filter_match callback and | ||
| 854 | * pmu::event_init group validation). | ||
| 855 | */ | ||
| 856 | cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_HETEROGENEOUS_CPUS; | ||
| 857 | |||
| 850 | return 0; | 858 | return 0; |
| 851 | 859 | ||
| 852 | out_unregister: | 860 | out_unregister: |
| @@ -34,6 +34,9 @@ · 33 unmodified lines | |||
| 34 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
| 35 | #include <asm/cpu_device_id.h> | 35 | #include <asm/cpu_device_id.h> |
| 36 | 36 | ||
| 37 | /* Local defines */ | ||
| 38 | #define MSR_PLATFORM_POWER_LIMIT 0x0000065C | ||
| 39 | |||
| 37 | /* bitmasks for RAPL MSRs, used by primitive access functions */ | 40 | /* bitmasks for RAPL MSRs, used by primitive access functions */ |
| 38 | #define ENERGY_STATUS_MASK 0xffffffff | 41 | #define ENERGY_STATUS_MASK 0xffffffff |
| 39 | 42 | ||
| @@ -86,6 +89,7 @@ enum rapl_domain_type { · 46 unmodified lines | |||
| 86 | RAPL_DOMAIN_PP0, /* core power plane */ | 89 | RAPL_DOMAIN_PP0, /* core power plane */ |
| 87 | RAPL_DOMAIN_PP1, /* graphics uncore */ | 90 | RAPL_DOMAIN_PP1, /* graphics uncore */ |
| 88 | RAPL_DOMAIN_DRAM,/* DRAM control_type */ | 91 | RAPL_DOMAIN_DRAM,/* DRAM control_type */ |
| 92 | RAPL_DOMAIN_PLATFORM, /* PSys control_type */ | ||
| 89 | RAPL_DOMAIN_MAX, | 93 | RAPL_DOMAIN_MAX, |
| 90 | }; | 94 | }; |
| 91 | 95 | ||
| @@ -251,9 +255,11 @@ static const char * const rapl_domain_names[] = { · 159 unmodified lines | |||
| 251 | "core", | 255 | "core", |
| 252 | "uncore", | 256 | "uncore", |
| 253 | "dram", | 257 | "dram", |
| 258 | "psys", | ||
| 254 | }; | 259 | }; |
| 255 | 260 | ||
| 256 | static struct powercap_control_type *control_type; /* PowerCap Controller */ | 261 | static struct powercap_control_type *control_type; /* PowerCap Controller */ |
| 262 | static struct rapl_domain *platform_rapl_domain; /* Platform (PSys) domain */ | ||
| 257 | 263 | ||
| 258 | /* caller to ensure CPU hotplug lock is held */ | 264 | /* caller to ensure CPU hotplug lock is held */ |
| 259 | static struct rapl_package *find_package_by_id(int id) | 265 | static struct rapl_package *find_package_by_id(int id) |
| @@ -409,6 +415,14 @@ static const struct powercap_zone_ops zone_ops[] = { · 149 unmodified lines | |||
| 409 | .set_enable = set_domain_enable, | 415 | .set_enable = set_domain_enable, |
| 410 | .get_enable = get_domain_enable, | 416 | .get_enable = get_domain_enable, |
| 411 | }, | 417 | }, |
| 418 | /* RAPL_DOMAIN_PLATFORM */ | ||
| 419 | { | ||
| 420 | .get_energy_uj = get_energy_counter, | ||
| 421 | .get_max_energy_range_uj = get_max_energy_counter, | ||
| 422 | .release = release_zone, | ||
| 423 | .set_enable = set_domain_enable, | ||
| 424 | .get_enable = get_domain_enable, | ||
| 425 | }, | ||
| 412 | }; | 426 | }; |
| 413 | 427 | ||
| 414 | static int set_power_limit(struct powercap_zone *power_zone, int id, | 428 | static int set_power_limit(struct powercap_zone *power_zone, int id, |
| @@ -1160,6 +1174,13 @@ static int rapl_unregister_powercap(void) · 745 unmodified lines | |||
| 1160 | powercap_unregister_zone(control_type, | 1174 | powercap_unregister_zone(control_type, |
| 1161 | &rd_package->power_zone); | 1175 | &rd_package->power_zone); |
| 1162 | } | 1176 | } |
| 1177 | |||
| 1178 | if (platform_rapl_domain) { | ||
| 1179 | powercap_unregister_zone(control_type, | ||
| 1180 | &platform_rapl_domain->power_zone); | ||
| 1181 | kfree(platform_rapl_domain); | ||
| 1182 | } | ||
| 1183 | |||
| 1163 | powercap_unregister_control_type(control_type); | 1184 | powercap_unregister_control_type(control_type); |
| 1164 | 1185 | ||
| 1165 | return 0; | 1186 | return 0; |
| @@ -1239,6 +1260,47 @@ err_cleanup: · 73 unmodified lines | |||
| 1239 | return ret; | 1260 | return ret; |
| 1240 | } | 1261 | } |
| 1241 | 1262 | ||
| 1263 | static int rapl_register_psys(void) | ||
| 1264 | { | ||
| 1265 | struct rapl_domain *rd; | ||
| 1266 | struct powercap_zone *power_zone; | ||
| 1267 | u64 val; | ||
| 1268 | |||
| 1269 | if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_ENERGY_STATUS, &val) || !val) | ||
| 1270 | return -ENODEV; | ||
| 1271 | |||
| 1272 | if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_POWER_LIMIT, &val) || !val) | ||
| 1273 | return -ENODEV; | ||
| 1274 | |||
| 1275 | rd = kzalloc(sizeof(*rd), GFP_KERNEL); | ||
| 1276 | if (!rd) | ||
| 1277 | return -ENOMEM; | ||
| 1278 | |||
| 1279 | rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM]; | ||
| 1280 | rd->id = RAPL_DOMAIN_PLATFORM; | ||
| 1281 | rd->msrs[0] = MSR_PLATFORM_POWER_LIMIT; | ||
| 1282 | rd->msrs[1] = MSR_PLATFORM_ENERGY_STATUS; | ||
| 1283 | rd->rpl[0].prim_id = PL1_ENABLE; | ||
| 1284 | rd->rpl[0].name = pl1_name; | ||
| 1285 | rd->rpl[1].prim_id = PL2_ENABLE; | ||
| 1286 | rd->rpl[1].name = pl2_name; | ||
| 1287 | rd->rp = find_package_by_id(0); | ||
| 1288 | |||
| 1289 | power_zone = powercap_register_zone(&rd->power_zone, control_type, | ||
| 1290 | "psys", NULL, | ||
| 1291 | &zone_ops[RAPL_DOMAIN_PLATFORM], | ||
| 1292 | 2, &constraint_ops); | ||
| 1293 | |||
| 1294 | if (IS_ERR(power_zone)) { | ||
| 1295 | kfree(rd); | ||
| 1296 | return PTR_ERR(power_zone); | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | platform_rapl_domain = rd; | ||
| 1300 | |||
| 1301 | return 0; | ||
| 1302 | } | ||
| 1303 | |||
| 1242 | static int rapl_register_powercap(void) | 1304 | static int rapl_register_powercap(void) |
| 1243 | { | 1305 | { |
| 1244 | struct rapl_domain *rd; | 1306 | struct rapl_domain *rd; |
| @@ -1255,6 +1317,10 @@ static int rapl_register_powercap(void) · 10 unmodified lines | |||
| 1255 | list_for_each_entry(rp, &rapl_packages, plist) | 1317 | list_for_each_entry(rp, &rapl_packages, plist) |
| 1256 | if (rapl_package_register_powercap(rp)) | 1318 | if (rapl_package_register_powercap(rp)) |
| 1257 | goto err_cleanup_package; | 1319 | goto err_cleanup_package; |
| 1320 | |||
| 1321 | /* Don't bail out if PSys is not supported */ | ||
| 1322 | rapl_register_psys(); | ||
| 1323 | |||
| 1258 | return ret; | 1324 | return ret; |
| 1259 | 1325 | ||
| 1260 | err_cleanup_package: | 1326 | err_cleanup_package: |
| @@ -1289,6 +1355,9 @@ static int rapl_check_domain(int cpu, int domain) · 28 unmodified lines | |||
| 1289 | case RAPL_DOMAIN_DRAM: | 1355 | case RAPL_DOMAIN_DRAM: |
| 1290 | msr = MSR_DRAM_ENERGY_STATUS; | 1356 | msr = MSR_DRAM_ENERGY_STATUS; |
| 1291 | break; | 1357 | break; |
| 1358 | case RAPL_DOMAIN_PLATFORM: | ||
| 1359 | /* PSYS(PLATFORM) is not a CPU domain, so avoid printng error */ | ||
| 1360 | return -EINVAL; | ||
| 1292 | default: | 1361 | default: |
| 1293 | pr_err("invalid domain id %d\n", domain); | 1362 | pr_err("invalid domain id %d\n", domain); |
| 1294 | return -EINVAL; | 1363 | return -EINVAL; |
| @@ -58,7 +58,7 @@ struct perf_guest_info_callbacks { · 57 unmodified lines | |||
| 58 | 58 | ||
| 59 | struct perf_callchain_entry { | 59 | struct perf_callchain_entry { |
| 60 | __u64 nr; | 60 | __u64 nr; |
| 61 | __u64 ip[PERF_MAX_STACK_DEPTH]; | 61 | __u64 ip[0]; /* /proc/sys/kernel/perf_event_max_stack */ |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | struct perf_raw_record { | 64 | struct perf_raw_record { |
| @@ -151,6 +151,15 @@ struct hw_perf_event { · 86 unmodified lines | |||
| 151 | */ | 151 | */ |
| 152 | struct task_struct *target; | 152 | struct task_struct *target; |
| 153 | 153 | ||
| 154 | /* | ||
| 155 | * PMU would store hardware filter configuration | ||
| 156 | * here. | ||
| 157 | */ | ||
| 158 | void *addr_filters; | ||
| 159 | |||
| 160 | /* Last sync'ed generation of filters */ | ||
| 161 | unsigned long addr_filters_gen; | ||
| 162 | |||
| 154 | /* | 163 | /* |
| 155 | * hw_perf_event::state flags; used to track the PERF_EF_* state. | 164 | * hw_perf_event::state flags; used to track the PERF_EF_* state. |
| 156 | */ | 165 | */ |
| @@ -216,6 +225,7 @@ struct perf_event; · 59 unmodified lines | |||
| 216 | #define PERF_PMU_CAP_AUX_SW_DOUBLEBUF 0x08 | 225 | #define PERF_PMU_CAP_AUX_SW_DOUBLEBUF 0x08 |
| 217 | #define PERF_PMU_CAP_EXCLUSIVE 0x10 | 226 | #define PERF_PMU_CAP_EXCLUSIVE 0x10 |
| 218 | #define PERF_PMU_CAP_ITRACE 0x20 | 227 | #define PERF_PMU_CAP_ITRACE 0x20 |
| 228 | #define PERF_PMU_CAP_HETEROGENEOUS_CPUS 0x40 | ||
| 219 | 229 | ||
| 220 | /** | 230 | /** |
| 221 | * struct pmu - generic performance monitoring unit | 231 | * struct pmu - generic performance monitoring unit |
| @@ -240,6 +250,9 @@ struct pmu { · 18 unmodified lines | |||
| 240 | int task_ctx_nr; | 250 | int task_ctx_nr; |
| 241 | int hrtimer_interval_ms; | 251 | int hrtimer_interval_ms; |
| 242 | 252 | ||
| 253 | /* number of address filters this PMU can do */ | ||
| 254 | unsigned int nr_addr_filters; | ||
| 255 | |||
| 243 | /* | 256 | /* |
| 244 | * Fully disable/enable this PMU, can be used to protect from the PMI | 257 | * Fully disable/enable this PMU, can be used to protect from the PMI |
| 245 | * as well as for lazy/batch writing of the MSRs. | 258 | * as well as for lazy/batch writing of the MSRs. |
| @@ -392,12 +405,71 @@ struct pmu { · 146 unmodified lines | |||
| 392 | */ | 405 | */ |
| 393 | void (*free_aux) (void *aux); /* optional */ | 406 | void (*free_aux) (void *aux); /* optional */ |
| 394 | 407 | ||
| 408 | /* | ||
| 409 | * Validate address range filters: make sure the HW supports the | ||
| 410 | * requested configuration and number of filters; return 0 if the | ||
| 411 | * supplied filters are valid, -errno otherwise. | ||
| 412 | * | ||
| 413 | * Runs in the context of the ioctl()ing process and is not serialized | ||
| 414 | * with the rest of the PMU callbacks. | ||
| 415 | */ | ||
| 416 | int (*addr_filters_validate) (struct list_head *filters); | ||
| 417 | /* optional */ | ||
| 418 | |||
| 419 | /* | ||
| 420 | * Synchronize address range filter configuration: | ||
| 421 | * translate hw-agnostic filters into hardware configuration in | ||
| 422 | * event::hw::addr_filters. | ||
| 423 | * | ||
| 424 | * Runs as a part of filter sync sequence that is done in ->start() | ||
| 425 | * callback by calling perf_event_addr_filters_sync(). | ||
| 426 | * | ||
| 427 | * May (and should) traverse event::addr_filters::list, for which its | ||
| 428 | * caller provides necessary serialization. | ||
| 429 | */ | ||
| 430 | void (*addr_filters_sync) (struct perf_event *event); | ||
| 431 | /* optional */ | ||
| 432 | |||
| 395 | /* | 433 | /* |
| 396 | * Filter events for PMU-specific reasons. | 434 | * Filter events for PMU-specific reasons. |
| 397 | */ | 435 | */ |
| 398 | int (*filter_match) (struct perf_event *event); /* optional */ | 436 | int (*filter_match) (struct perf_event *event); /* optional */ |
| 399 | }; | 437 | }; |
| 400 | 438 | ||
| 439 | /** | ||
| 440 | * struct perf_addr_filter - address range filter definition | ||
| 441 | * @entry: event's filter list linkage | ||
| 442 | * @inode: object file's inode for file-based filters | ||
| 443 | * @offset: filter range offset | ||
| 444 | * @size: filter range size | ||
| 445 | * @range: 1: range, 0: address | ||
| 446 | * @filter: 1: filter/start, 0: stop | ||
| 447 | * | ||
| 448 | * This is a hardware-agnostic filter configuration as specified by the user. | ||
| 449 | */ | ||
| 450 | struct perf_addr_filter { | ||
| 451 | struct list_head entry; | ||
| 452 | struct inode *inode; | ||
| 453 | unsigned long offset; | ||
| 454 | unsigned long size; | ||
| 455 | unsigned int range : 1, | ||
| 456 | filter : 1; | ||
| 457 | }; | ||
| 458 | |||
| 459 | /** | ||
| 460 | * struct perf_addr_filters_head - container for address range filters | ||
| 461 | * @list: list of filters for this event | ||
| 462 | * @lock: spinlock that serializes accesses to the @list and event's | ||
| 463 | * (and its children's) filter generations. | ||
| 464 | * | ||
| 465 | * A child event will use parent's @list (and therefore @lock), so they are | ||
| 466 | * bundled together; see perf_event_addr_filters(). | ||
| 467 | */ | ||
| 468 | struct perf_addr_filters_head { | ||
| 469 | struct list_head list; | ||
| 470 | raw_spinlock_t lock; | ||
| 471 | }; | ||
| 472 | |||
| 401 | /** | 473 | /** |
| 402 | * enum perf_event_active_state - the states of a event | 474 | * enum perf_event_active_state - the states of a event |
| 403 | */ | 475 | */ |
| @@ -566,6 +638,12 @@ struct perf_event { · 162 unmodified lines | |||
| 566 | 638 | ||
| 567 | atomic_t event_limit; | 639 | atomic_t event_limit; |
| 568 | 640 | ||
| 641 | /* address range filters */ | ||
| 642 | struct perf_addr_filters_head addr_filters; | ||
| 643 | /* vma address array for file-based filders */ | ||
| 644 | unsigned long *addr_filters_offs; | ||
| 645 | unsigned long addr_filters_gen; | ||
| 646 | |||
| 569 | void (*destroy)(struct perf_event *); | 647 | void (*destroy)(struct perf_event *); |
| 570 | struct rcu_head rcu_head; | 648 | struct rcu_head rcu_head; |
| 571 | 649 | ||
| @@ -834,9 +912,25 @@ extern int perf_event_overflow(struct perf_event *event, · 262 unmodified lines | |||
| 834 | struct perf_sample_data *data, | 912 | struct perf_sample_data *data, |
| 835 | struct pt_regs *regs); | 913 | struct pt_regs *regs); |
| 836 | 914 | ||
| 915 | extern void perf_event_output_forward(struct perf_event *event, | ||
| 916 | struct perf_sample_data *data, | ||
| 917 | struct pt_regs *regs); | ||
| 918 | extern void perf_event_output_backward(struct perf_event *event, | ||
| 919 | struct perf_sample_data *data, | ||
| 920 | struct pt_regs *regs); | ||
| 837 | extern void perf_event_output(struct perf_event *event, | 921 | extern void perf_event_output(struct perf_event *event, |
| 838 | struct perf_sample_data *data, | 922 | struct perf_sample_data *data, |
| 839 | struct pt_regs *regs); | 923 | struct pt_regs *regs); |
| 924 | |||
| 925 | static inline bool | ||
| 926 | is_default_overflow_handler(struct perf_event *event) | ||
| 927 | { | ||
| 928 | if (likely(event->overflow_handler == perf_event_output_forward)) | ||
| 929 | return true; | ||
| 930 | if (unlikely(event->overflow_handler == perf_event_output_backward)) | ||
| 931 | return true; | ||
| 932 | return false; | ||
| 933 | } | ||
| 840 | 934 | ||
| 841 | extern void | 935 | extern void |
| 842 | perf_event_header__init_id(struct perf_event_header *header, | 936 | perf_event_header__init_id(struct perf_event_header *header, |
| @@ -977,9 +1071,11 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, · 134 unmodified lines | |||
| 977 | extern int get_callchain_buffers(void); | 1071 | extern int get_callchain_buffers(void); |
| 978 | extern void put_callchain_buffers(void); | 1072 | extern void put_callchain_buffers(void); |
| 979 | 1073 | ||
| 1074 | extern int sysctl_perf_event_max_stack; | ||
| 1075 | |||
| 980 | static inline int perf_callchain_store(struct perf_callchain_entry *entry, u64 ip) | 1076 | static inline int perf_callchain_store(struct perf_callchain_entry *entry, u64 ip) |
| 981 | { | 1077 | { |
| 982 | if (entry->nr < PERF_MAX_STACK_DEPTH) { | 1078 | if (entry->nr < sysctl_perf_event_max_stack) { |
| 983 | entry->ip[entry->nr++] = ip; | 1079 | entry->ip[entry->nr++] = ip; |
| 984 | return 0; | 1080 | return 0; |
| 985 | } else { | 1081 | } else { |
| @@ -1001,6 +1097,8 @@ extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, · 15 unmodified lines | |||
| 1001 | void __user *buffer, size_t *lenp, | 1097 | void __user *buffer, size_t *lenp, |
| 1002 | loff_t *ppos); | 1098 | loff_t *ppos); |
| 1003 | 1099 | ||
| 1100 | int perf_event_max_stack_handler(struct ctl_table *table, int write, | ||
| 1101 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
| 1004 | 1102 | ||
| 1005 | static inline bool perf_paranoid_tracepoint_raw(void) | 1103 | static inline bool perf_paranoid_tracepoint_raw(void) |
| 1006 | { | 1104 | { |
| @@ -1045,8 +1143,41 @@ static inline bool has_aux(struct perf_event *event) · 38 unmodified lines | |||
| 1045 | return event->pmu->setup_aux; | 1143 | return event->pmu->setup_aux; |
| 1046 | } | 1144 | } |
| 1047 | 1145 | ||
| 1146 | static inline bool is_write_backward(struct perf_event *event) | ||
| 1147 | { | ||
| 1148 | return !!event->attr.write_backward; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static inline bool has_addr_filter(struct perf_event *event) | ||
| 1152 | { | ||
| 1153 | return event->pmu->nr_addr_filters; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | /* | ||
| 1157 | * An inherited event uses parent's filters | ||
| 1158 | */ | ||
| 1159 | static inline struct perf_addr_filters_head * | ||
| 1160 | perf_event_addr_filters(struct perf_event *event) | ||
| 1161 | { | ||
| 1162 | struct perf_addr_filters_head *ifh = &event->addr_filters; | ||
| 1163 | |||
| 1164 | if (event->parent) | ||
| 1165 | ifh = &event->parent->addr_filters; | ||
| 1166 | |||
| 1167 | return ifh; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | extern void perf_event_addr_filters_sync(struct perf_event *event); | ||
| 1171 | |||
| 1048 | extern int perf_output_begin(struct perf_output_handle *handle, | 1172 | extern int perf_output_begin(struct perf_output_handle *handle, |
| 1049 | struct perf_event *event, unsigned int size); | 1173 | struct perf_event *event, unsigned int size); |
| 1174 | extern int perf_output_begin_forward(struct perf_output_handle *handle, | ||
| 1175 | struct perf_event *event, | ||
| 1176 | unsigned int size); | ||
| 1177 | extern int perf_output_begin_backward(struct perf_output_handle *handle, | ||
| 1178 | struct perf_event *event, | ||
| 1179 | unsigned int size); | ||
| 1180 | |||
| 1050 | extern void perf_output_end(struct perf_output_handle *handle); | 1181 | extern void perf_output_end(struct perf_output_handle *handle); |
| 1051 | extern unsigned int perf_output_copy(struct perf_output_handle *handle, | 1182 | extern unsigned int perf_output_copy(struct perf_output_handle *handle, |
| 1052 | const void *buf, unsigned int len); | 1183 | const void *buf, unsigned int len); |
| @@ -340,7 +340,8 @@ struct perf_event_attr { · 339 unmodified lines | |||
| 340 | comm_exec : 1, /* flag comm events that are due to an exec */ | 340 | comm_exec : 1, /* flag comm events that are due to an exec */ |
| 341 | use_clockid : 1, /* use @clockid for time fields */ | 341 | use_clockid : 1, /* use @clockid for time fields */ |
| 342 | context_switch : 1, /* context switch data */ | 342 | context_switch : 1, /* context switch data */ |
| 343 | __reserved_1 : 37; | 343 | write_backward : 1, /* Write ring buffer from end to beginning */ |
| 344 | __reserved_1 : 36; | ||
| 344 | 345 | ||
| 345 | union { | 346 | union { |
| 346 | __u32 wakeup_events; /* wakeup every n events */ | 347 | __u32 wakeup_events; /* wakeup every n events */ |
| @@ -401,6 +402,7 @@ struct perf_event_attr { · 54 unmodified lines | |||
| 401 | #define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) | 402 | #define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) |
| 402 | #define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) | 403 | #define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) |
| 403 | #define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) | 404 | #define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) |
| 405 | #define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32) | ||
| 404 | 406 | ||
| 405 | enum perf_event_ioc_flags { | 407 | enum perf_event_ioc_flags { |
| 406 | PERF_IOC_FLAG_GROUP = 1U << 0, | 408 | PERF_IOC_FLAG_GROUP = 1U << 0, |
| @@ -66,7 +66,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) · 65 unmodified lines | |||
| 66 | /* check sanity of attributes */ | 66 | /* check sanity of attributes */ |
| 67 | if (attr->max_entries == 0 || attr->key_size != 4 || | 67 | if (attr->max_entries == 0 || attr->key_size != 4 || |
| 68 | value_size < 8 || value_size % 8 || | 68 | value_size < 8 || value_size % 8 || |
| 69 | value_size / 8 > PERF_MAX_STACK_DEPTH) | 69 | value_size / 8 > sysctl_perf_event_max_stack) |
| 70 | return ERR_PTR(-EINVAL); | 70 | return ERR_PTR(-EINVAL); |
| 71 | 71 | ||
| 72 | /* hash table size must be power of 2 */ | 72 | /* hash table size must be power of 2 */ |
| @@ -124,8 +124,8 @@ static u64 bpf_get_stackid(u64 r1, u64 r2, u64 flags, u64 r4, u64 r5) · 51 unmodified lines | |||
| 124 | struct perf_callchain_entry *trace; | 124 | struct perf_callchain_entry *trace; |
| 125 | struct stack_map_bucket *bucket, *new_bucket, *old_bucket; | 125 | struct stack_map_bucket *bucket, *new_bucket, *old_bucket; |
| 126 | u32 max_depth = map->value_size / 8; | 126 | u32 max_depth = map->value_size / 8; |
| 127 | /* stack_map_alloc() checks that max_depth <= PERF_MAX_STACK_DEPTH */ | 127 | /* stack_map_alloc() checks that max_depth <= sysctl_perf_event_max_stack */ |
| 128 | u32 init_nr = PERF_MAX_STACK_DEPTH - max_depth; | 128 | u32 init_nr = sysctl_perf_event_max_stack - max_depth; |
| 129 | u32 skip = flags & BPF_F_SKIP_FIELD_MASK; | 129 | u32 skip = flags & BPF_F_SKIP_FIELD_MASK; |
| 130 | u32 hash, id, trace_nr, trace_len; | 130 | u32 hash, id, trace_nr, trace_len; |
| 131 | bool user = flags & BPF_F_USER_STACK; | 131 | bool user = flags & BPF_F_USER_STACK; |
| @@ -143,7 +143,7 @@ static u64 bpf_get_stackid(u64 r1, u64 r2, u64 flags, u64 r4, u64 r5) · 11 unmodified lines | |||
| 143 | return -EFAULT; | 143 | return -EFAULT; |
| 144 | 144 | ||
| 145 | /* get_perf_callchain() guarantees that trace->nr >= init_nr | 145 | /* get_perf_callchain() guarantees that trace->nr >= init_nr |
| 146 | * and trace-nr <= PERF_MAX_STACK_DEPTH, so trace_nr <= max_depth | 146 | * and trace-nr <= sysctl_perf_event_max_stack, so trace_nr <= max_depth |
| 147 | */ | 147 | */ |
| 148 | trace_nr = trace->nr - init_nr; | 148 | trace_nr = trace->nr - init_nr; |
| 149 | 149 | ||
| @@ -18,6 +18,14 @@ struct callchain_cpus_entries { · 17 unmodified lines | |||
| 18 | struct perf_callchain_entry *cpu_entries[0]; | 18 | struct perf_callchain_entry *cpu_entries[0]; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | int sysctl_perf_event_max_stack __read_mostly = PERF_MAX_STACK_DEPTH; | ||
| 22 | |||
| 23 | static inline size_t perf_callchain_entry__sizeof(void) | ||
| 24 | { | ||
| 25 | return (sizeof(struct perf_callchain_entry) + | ||
| 26 | sizeof(__u64) * sysctl_perf_event_max_stack); | ||
| 27 | } | ||
| 28 | |||
| 21 | static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); | 29 | static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); |
| 22 | static atomic_t nr_callchain_events; | 30 | static atomic_t nr_callchain_events; |
| 23 | static DEFINE_MUTEX(callchain_mutex); | 31 | static DEFINE_MUTEX(callchain_mutex); |
| @@ -73,7 +81,7 @@ static int alloc_callchain_buffers(void) · 49 unmodified lines | |||
| 73 | if (!entries) | 81 | if (!entries) |
| 74 | return -ENOMEM; | 82 | return -ENOMEM; |
| 75 | 83 | ||
| 76 | size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS; | 84 | size = perf_callchain_entry__sizeof() * PERF_NR_CONTEXTS; |
| 77 | 85 | ||
| 78 | for_each_possible_cpu(cpu) { | 86 | for_each_possible_cpu(cpu) { |
| 79 | entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, | 87 | entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, |
| @@ -147,7 +155,8 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx) · 67 unmodified lines | |||
| 147 | 155 | ||
| 148 | cpu = smp_processor_id(); | 156 | cpu = smp_processor_id(); |
| 149 | 157 | ||
| 150 | return &entries->cpu_entries[cpu][*rctx]; | 158 | return (((void *)entries->cpu_entries[cpu]) + |
| 159 | (*rctx * perf_callchain_entry__sizeof())); | ||
| 151 | } | 160 | } |
| 152 | 161 | ||
| 153 | static void | 162 | static void |
| @@ -215,3 +224,25 @@ exit_put: · 61 unmodified lines | |||
| 215 | 224 | ||
| 216 | return entry; | 225 | return entry; |
| 217 | } | 226 | } |
| 227 | |||
| 228 | int perf_event_max_stack_handler(struct ctl_table *table, int write, | ||
| 229 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 230 | { | ||
| 231 | int new_value = sysctl_perf_event_max_stack, ret; | ||
| 232 | struct ctl_table new_table = *table; | ||
| 233 | |||
| 234 | new_table.data = &new_value; | ||
| 235 | ret = proc_dointvec_minmax(&new_table, write, buffer, lenp, ppos); | ||
| 236 | if (ret || !write) | ||
| 237 | return ret; | ||
| 238 | |||
| 239 | mutex_lock(&callchain_mutex); | ||
| 240 | if (atomic_read(&nr_callchain_events)) | ||
| 241 | ret = -EBUSY; | ||
| 242 | else | ||
| 243 | sysctl_perf_event_max_stack = new_value; | ||
| 244 | |||
| 245 | mutex_unlock(&callchain_mutex); | ||
| 246 | |||
| 247 | return ret; | ||
| 248 | } | ||
| @@ -44,6 +44,8 @@ · 43 unmodified lines | |||
| 44 | #include <linux/compat.h> | 44 | #include <linux/compat.h> |
| 45 | #include <linux/bpf.h> | 45 | #include <linux/bpf.h> |
| 46 | #include <linux/filter.h> | 46 | #include <linux/filter.h> |
| 47 | #include <linux/namei.h> | ||
| 48 | #include <linux/parser.h> | ||
| 47 | 49 | ||
| 48 | #include "internal.h" | 50 | #include "internal.h" |
| 49 | 51 | ||
| @@ -1927,8 +1929,13 @@ event_sched_in(struct perf_event *event, · 1877 unmodified lines | |||
| 1927 | if (event->state <= PERF_EVENT_STATE_OFF) | 1929 | if (event->state <= PERF_EVENT_STATE_OFF) |
| 1928 | return 0; | 1930 | return 0; |
| 1929 | 1931 | ||
| 1930 | event->state = PERF_EVENT_STATE_ACTIVE; | 1932 | WRITE_ONCE(event->oncpu, smp_processor_id()); |
| 1931 | event->oncpu = smp_processor_id(); | 1933 | /* |
| 1934 | * Order event::oncpu write to happen before the ACTIVE state | ||
| 1935 | * is visible. | ||
| 1936 | */ | ||
| 1937 | smp_wmb(); | ||
| 1938 | WRITE_ONCE(event->state, PERF_EVENT_STATE_ACTIVE); | ||
| 1932 | 1939 | ||
| 1933 | /* | 1940 | /* |
| 1934 | * Unthrottle events, since we scheduled we might have missed several | 1941 | * Unthrottle events, since we scheduled we might have missed several |
| @@ -2360,6 +2367,112 @@ void perf_event_enable(struct perf_event *event) · 425 unmodified lines | |||
| 2360 | } | 2367 | } |
| 2361 | EXPORT_SYMBOL_GPL(perf_event_enable); | 2368 | EXPORT_SYMBOL_GPL(perf_event_enable); |
| 2362 | 2369 | ||
| 2370 | struct stop_event_data { | ||
| 2371 | struct perf_event *event; | ||
| 2372 | unsigned int restart; | ||
| 2373 | }; | ||
| 2374 | |||
| 2375 | static int __perf_event_stop(void *info) | ||
| 2376 | { | ||
| 2377 | struct stop_event_data *sd = info; | ||
| 2378 | struct perf_event *event = sd->event; | ||
| 2379 | |||
| 2380 | /* if it's already INACTIVE, do nothing */ | ||
| 2381 | if (READ_ONCE(event->state) != PERF_EVENT_STATE_ACTIVE) | ||
| 2382 | return 0; | ||
| 2383 | |||
| 2384 | /* matches smp_wmb() in event_sched_in() */ | ||
| 2385 | smp_rmb(); | ||
| 2386 | |||
| 2387 | /* | ||
| 2388 | * There is a window with interrupts enabled before we get here, | ||
| 2389 | * so we need to check again lest we try to stop another CPU's event. | ||
| 2390 | */ | ||
| 2391 | if (READ_ONCE(event->oncpu) != smp_processor_id()) | ||
| 2392 | return -EAGAIN; | ||
| 2393 | |||
| 2394 | event->pmu->stop(event, PERF_EF_UPDATE); | ||
| 2395 | |||
| 2396 | /* | ||
| 2397 | * May race with the actual stop (through perf_pmu_output_stop()), | ||
| 2398 | * but it is only used for events with AUX ring buffer, and such | ||
| 2399 | * events will refuse to restart because of rb::aux_mmap_count==0, | ||
| 2400 | * see comments in perf_aux_output_begin(). | ||
| 2401 | * | ||
| 2402 | * Since this is happening on a event-local CPU, no trace is lost | ||
| 2403 | * while restarting. | ||
| 2404 | */ | ||
| 2405 | if (sd->restart) | ||
| 2406 | event->pmu->start(event, PERF_EF_START); | ||
| 2407 | |||
| 2408 | return 0; | ||
| 2409 | } | ||
| 2410 | |||
| 2411 | static int perf_event_restart(struct perf_event *event) | ||
| 2412 | { | ||
| 2413 | struct stop_event_data sd = { | ||
| 2414 | .event = event, | ||
| 2415 | .restart = 1, | ||
| 2416 | }; | ||
| 2417 | int ret = 0; | ||
| 2418 | |||
| 2419 | do { | ||
| 2420 | if (READ_ONCE(event->state) != PERF_EVENT_STATE_ACTIVE) | ||
| 2421 | return 0; | ||
| 2422 | |||
| 2423 | /* matches smp_wmb() in event_sched_in() */ | ||
| 2424 | smp_rmb(); | ||
| 2425 | |||
| 2426 | /* | ||
| 2427 | * We only want to restart ACTIVE events, so if the event goes | ||
| 2428 | * inactive here (event->oncpu==-1), there's nothing more to do; | ||
| 2429 | * fall through with ret==-ENXIO. | ||
| 2430 | */ | ||
| 2431 | ret = cpu_function_call(READ_ONCE(event->oncpu), | ||
| 2432 | __perf_event_stop, &sd); | ||
| 2433 | } while (ret == -EAGAIN); | ||
| 2434 | |||
| 2435 | return ret; | ||
| 2436 | } | ||
| 2437 | |||
| 2438 | /* | ||
| 2439 | * In order to contain the amount of racy and tricky in the address filter | ||
| 2440 | * configuration management, it is a two part process: | ||
| 2441 | * | ||
| 2442 | * (p1) when userspace mappings change as a result of (1) or (2) or (3) below, | ||
| 2443 | * we update the addresses of corresponding vmas in | ||
| 2444 | * event::addr_filters_offs array and bump the event::addr_filters_gen; | ||
| 2445 | * (p2) when an event is scheduled in (pmu::add), it calls | ||
| 2446 | * perf_event_addr_filters_sync() which calls pmu::addr_filters_sync() | ||
| 2447 | * if the generation has changed since the previous call. | ||
| 2448 | * | ||
| 2449 | * If (p1) happens while the event is active, we restart it to force (p2). | ||
| 2450 | * | ||
| 2451 | * (1) perf_addr_filters_apply(): adjusting filters' offsets based on | ||
| 2452 | * pre-existing mappings, called once when new filters arrive via SET_FILTER | ||
| 2453 | * ioctl; | ||
| 2454 | * (2) perf_addr_filters_adjust(): adjusting filters' offsets based on newly | ||
| 2455 | * registered mapping, called for every new mmap(), with mm::mmap_sem down | ||
| 2456 | * for reading; | ||
| 2457 | * (3) perf_event_addr_filters_exec(): clearing filters' offsets in the process | ||
| 2458 | * of exec. | ||
| 2459 | */ | ||
| 2460 | void perf_event_addr_filters_sync(struct perf_event *event) | ||
| 2461 | { | ||
| 2462 | struct perf_addr_filters_head *ifh = perf_event_addr_filters(event); | ||
| 2463 | |||
| 2464 | if (!has_addr_filter(event)) | ||
| 2465 | return; | ||
| 2466 | |||
| 2467 | raw_spin_lock(&ifh->lock); | ||
| 2468 | if (event->addr_filters_gen != event->hw.addr_filters_gen) { | ||
| 2469 | event->pmu->addr_filters_sync(event); | ||
| 2470 | event->hw.addr_filters_gen = event->addr_filters_gen; | ||
| 2471 | } | ||
| 2472 | raw_spin_unlock(&ifh->lock); | ||
| 2473 | } | ||
| 2474 | EXPORT_SYMBOL_GPL(perf_event_addr_filters_sync); | ||
| 2475 | |||
| 2363 | static int _perf_event_refresh(struct perf_event *event, int refresh) | 2476 | static int _perf_event_refresh(struct perf_event *event, int refresh) |
| 2364 | { | 2477 | { |
| 2365 | /* | 2478 | /* |
| @@ -3209,16 +3322,6 @@ out: · 843 unmodified lines | |||
| 3209 | put_ctx(clone_ctx); | 3322 | put_ctx(clone_ctx); |
| 3210 | } | 3323 | } |
| 3211 | 3324 | ||
| 3212 | void perf_event_exec(void) | ||
| 3213 | { | ||
| 3214 | int ctxn; | ||
| 3215 | |||
| 3216 | rcu_read_lock(); | ||
| 3217 | for_each_task_context_nr(ctxn) | ||
| 3218 | perf_event_enable_on_exec(ctxn); | ||
| 3219 | rcu_read_unlock(); | ||
| 3220 | } | ||
| 3221 | |||
| 3222 | struct perf_read_data { | 3325 | struct perf_read_data { |
| 3223 | struct perf_event *event; | 3326 | struct perf_event *event; |
| 3224 | bool group; | 3327 | bool group; |
| @@ -3720,6 +3823,9 @@ static bool exclusive_event_installable(struct perf_event *event, · 495 unmodified lines | |||
| 3720 | return true; | 3823 | return true; |
| 3721 | } | 3824 | } |
| 3722 | 3825 | ||
| 3826 | static void perf_addr_filters_splice(struct perf_event *event, | ||
| 3827 | struct list_head *head); | ||
| 3828 | |||
| 3723 | static void _free_event(struct perf_event *event) | 3829 | static void _free_event(struct perf_event *event) |
| 3724 | { | 3830 | { |
| 3725 | irq_work_sync(&event->pending); | 3831 | irq_work_sync(&event->pending); |
| @@ -3747,6 +3853,8 @@ static void _free_event(struct perf_event *event) · 21 unmodified lines | |||
| 3747 | } | 3853 | } |
| 3748 | 3854 | ||
| 3749 | perf_event_free_bpf_prog(event); | 3855 | perf_event_free_bpf_prog(event); |
| 3856 | perf_addr_filters_splice(event, NULL); | ||
| 3857 | kfree(event->addr_filters_offs); | ||
| 3750 | 3858 | ||
| 3751 | if (event->destroy) | 3859 | if (event->destroy) |
| 3752 | event->destroy(event); | 3860 | event->destroy(event); |
| @@ -4343,6 +4451,19 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon · 590 unmodified lines | |||
| 4343 | case PERF_EVENT_IOC_SET_BPF: | 4451 | case PERF_EVENT_IOC_SET_BPF: |
| 4344 | return perf_event_set_bpf_prog(event, arg); | 4452 | return perf_event_set_bpf_prog(event, arg); |
| 4345 | 4453 | ||
| 4454 | case PERF_EVENT_IOC_PAUSE_OUTPUT: { | ||
| 4455 | struct ring_buffer *rb; | ||
| 4456 | |||
| 4457 | rcu_read_lock(); | ||
| 4458 | rb = rcu_dereference(event->rb); | ||
| 4459 | if (!rb || !rb->nr_pages) { | ||
| 4460 | rcu_read_unlock(); | ||
| 4461 | return -EINVAL; | ||
| 4462 | } | ||
| 4463 | rb_toggle_paused(rb, !!arg); | ||
| 4464 | rcu_read_unlock(); | ||
| 4465 | return 0; | ||
| 4466 | } | ||
| 4346 | default: | 4467 | default: |
| 4347 | return -ENOTTY; | 4468 | return -ENOTTY; |
| 4348 | } | 4469 | } |
| @@ -4659,6 +4780,8 @@ static void perf_mmap_open(struct vm_area_struct *vma) · 310 unmodified lines | |||
| 4659 | event->pmu->event_mapped(event); | 4780 | event->pmu->event_mapped(event); |
| 4660 | } | 4781 | } |
| 4661 | 4782 | ||
| 4783 | static void perf_pmu_output_stop(struct perf_event *event); | ||
| 4784 | |||
| 4662 | /* | 4785 | /* |
| 4663 | * A buffer can be mmap()ed multiple times; either directly through the same | 4786 | * A buffer can be mmap()ed multiple times; either directly through the same |
| 4664 | * event, or through other events by use of perf_event_set_output(). | 4787 | * event, or through other events by use of perf_event_set_output(). |
| @@ -4686,10 +4809,22 @@ static void perf_mmap_close(struct vm_area_struct *vma) · 21 unmodified lines | |||
| 4686 | */ | 4809 | */ |
| 4687 | if (rb_has_aux(rb) && vma->vm_pgoff == rb->aux_pgoff && | 4810 | if (rb_has_aux(rb) && vma->vm_pgoff == rb->aux_pgoff && |
| 4688 | atomic_dec_and_mutex_lock(&rb->aux_mmap_count, &event->mmap_mutex)) { | 4811 | atomic_dec_and_mutex_lock(&rb->aux_mmap_count, &event->mmap_mutex)) { |
| 4812 | /* | ||
| 4813 | * Stop all AUX events that are writing to this buffer, | ||
| 4814 | * so that we can free its AUX pages and corresponding PMU | ||
| 4815 | * data. Note that after rb::aux_mmap_count dropped to zero, | ||
| 4816 | * they won't start any more (see perf_aux_output_begin()). | ||
| 4817 | */ | ||
| 4818 | perf_pmu_output_stop(event); | ||
| 4819 | |||
| 4820 | /* now it's safe to free the pages */ | ||
| 4689 | atomic_long_sub(rb->aux_nr_pages, &mmap_user->locked_vm); | 4821 | atomic_long_sub(rb->aux_nr_pages, &mmap_user->locked_vm); |
| 4690 | vma->vm_mm->pinned_vm -= rb->aux_mmap_locked; | 4822 | vma->vm_mm->pinned_vm -= rb->aux_mmap_locked; |
| 4691 | 4823 | ||
| 4824 | /* this has to be the last one */ | ||
| 4692 | rb_free_aux(rb); | 4825 | rb_free_aux(rb); |
| 4826 | WARN_ON_ONCE(atomic_read(&rb->aux_refcount)); | ||
| 4827 | |||
| 4693 | mutex_unlock(&event->mmap_mutex); | 4828 | mutex_unlock(&event->mmap_mutex); |
| 4694 | } | 4829 | } |
| 4695 | 4830 | ||
| @@ -5630,9 +5765,13 @@ void perf_prepare_sample(struct perf_event_header *header, · 934 unmodified lines | |||
| 5630 | } | 5765 | } |
| 5631 | } | 5766 | } |
| 5632 | 5767 | ||
| 5633 | void perf_event_output(struct perf_event *event, | 5768 | static void __always_inline |
| 5634 | struct perf_sample_data *data, | 5769 | __perf_event_output(struct perf_event *event, |
| 5635 | struct pt_regs *regs) | 5770 | struct perf_sample_data *data, |
| 5771 | struct pt_regs *regs, | ||
| 5772 | int (*output_begin)(struct perf_output_handle *, | ||
| 5773 | struct perf_event *, | ||
| 5774 | unsigned int)) | ||
| 5636 | { | 5775 | { |
| 5637 | struct perf_output_handle handle; | 5776 | struct perf_output_handle handle; |
| 5638 | struct perf_event_header header; | 5777 | struct perf_event_header header; |
| @@ -5642,7 +5781,7 @@ void perf_event_output(struct perf_event *event, · 3 unmodified lines | |||
| 5642 | 5781 | ||
| 5643 | perf_prepare_sample(&header, data, event, regs); | 5782 | perf_prepare_sample(&header, data, event, regs); |
| 5644 | 5783 | ||
| 5645 | if (perf_output_begin(&handle, event, header.size)) | 5784 | if (output_begin(&handle, event, header.size)) |
| 5646 | goto exit; | 5785 | goto exit; |
| 5647 | 5786 | ||
| 5648 | perf_output_sample(&handle, &header, data, event); | 5787 | perf_output_sample(&handle, &header, data, event); |
| @@ -5653,6 +5792,30 @@ exit: · 4 unmodified lines | |||
| 5653 | rcu_read_unlock(); | 5792 | rcu_read_unlock(); |
| 5654 | } | 5793 | } |
| 5655 | 5794 | ||
| 5795 | void | ||
| 5796 | perf_event_output_forward(struct perf_event *event, | ||
| 5797 | struct perf_sample_data *data, | ||
| 5798 | struct pt_regs *regs) | ||
| 5799 | { | ||
| 5800 | __perf_event_output(event, data, regs, perf_output_begin_forward); | ||
| 5801 | } | ||
| 5802 | |||
| 5803 | void | ||
| 5804 | perf_event_output_backward(struct perf_event *event, | ||
| 5805 | struct perf_sample_data *data, | ||
| 5806 | struct pt_regs *regs) | ||
| 5807 | { | ||
| 5808 | __perf_event_output(event, data, regs, perf_output_begin_backward); | ||
| 5809 | } | ||
| 5810 | |||
| 5811 | void | ||
| 5812 | perf_event_output(struct perf_event *event, | ||
| 5813 | struct perf_sample_data *data, | ||
| 5814 | struct pt_regs *regs) | ||
| 5815 | { | ||
| 5816 | __perf_event_output(event, data, regs, perf_output_begin); | ||
| 5817 | } | ||
| 5818 | |||
| 5656 | /* | 5819 | /* |
| 5657 | * read event_id | 5820 | * read event_id |
| 5658 | */ | 5821 | */ |
| @@ -5698,15 +5861,18 @@ typedef void (perf_event_aux_output_cb)(struct perf_event *event, void *data); · 39 unmodified lines | |||
| 5698 | static void | 5861 | static void |
| 5699 | perf_event_aux_ctx(struct perf_event_context *ctx, | 5862 | perf_event_aux_ctx(struct perf_event_context *ctx, |
| 5700 | perf_event_aux_output_cb output, | 5863 | perf_event_aux_output_cb output, |
| 5701 | void *data) | 5864 | void *data, bool all) |
| 5702 | { | 5865 | { |
| 5703 | struct perf_event *event; | 5866 | struct perf_event *event; |
| 5704 | 5867 | ||
| 5705 | list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { | 5868 | list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { |
| 5706 | if (event->state < PERF_EVENT_STATE_INACTIVE) | 5869 | if (!all) { |
| 5707 | continue; | 5870 | if (event->state < PERF_EVENT_STATE_INACTIVE) |
| 5708 | if (!event_filter_match(event)) | 5871 | continue; |
| 5709 | continue; | 5872 | if (!event_filter_match(event)) |
| 5873 | continue; | ||
| 5874 | } | ||
| 5875 | |||
| 5710 | output(event, data); | 5876 | output(event, data); |
| 5711 | } | 5877 | } |
| 5712 | } | 5878 | } |
| @@ -5717,7 +5883,7 @@ perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data, · 4 unmodified lines | |||
| 5717 | { | 5883 | { |
| 5718 | rcu_read_lock(); | 5884 | rcu_read_lock(); |
| 5719 | preempt_disable(); | 5885 | preempt_disable(); |
| 5720 | perf_event_aux_ctx(task_ctx, output, data); | 5886 | perf_event_aux_ctx(task_ctx, output, data, false); |
| 5721 | preempt_enable(); | 5887 | preempt_enable(); |
| 5722 | rcu_read_unlock(); | 5888 | rcu_read_unlock(); |
| 5723 | } | 5889 | } |
| @@ -5747,19 +5913,147 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, · 23 unmodified lines | |||
| 5747 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 5913 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
| 5748 | if (cpuctx->unique_pmu != pmu) | 5914 | if (cpuctx->unique_pmu != pmu) |
| 5749 | goto next; | 5915 | goto next; |
| 5750 | perf_event_aux_ctx(&cpuctx->ctx, output, data); | 5916 | perf_event_aux_ctx(&cpuctx->ctx, output, data, false); |
| 5751 | ctxn = pmu->task_ctx_nr; | 5917 | ctxn = pmu->task_ctx_nr; |
| 5752 | if (ctxn < 0) | 5918 | if (ctxn < 0) |
| 5753 | goto next; | 5919 | goto next; |
| 5754 | ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); | 5920 | ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); |
| 5755 | if (ctx) | 5921 | if (ctx) |
| 5756 | perf_event_aux_ctx(ctx, output, data); | 5922 | perf_event_aux_ctx(ctx, output, data, false); |
| 5757 | next: | 5923 | next: |
| 5758 | put_cpu_ptr(pmu->pmu_cpu_context); | 5924 | put_cpu_ptr(pmu->pmu_cpu_context); |
| 5759 | } | 5925 | } |
| 5760 | rcu_read_unlock(); | 5926 | rcu_read_unlock(); |
| 5761 | } | 5927 | } |
| 5762 | 5928 | ||
| 5929 | /* | ||
| 5930 | * Clear all file-based filters at exec, they'll have to be | ||
| 5931 | * re-instated when/if these objects are mmapped again. | ||
| 5932 | */ | ||
| 5933 | static void perf_event_addr_filters_exec(struct perf_event *event, void *data) | ||
| 5934 | { | ||
| 5935 | struct perf_addr_filters_head *ifh = perf_event_addr_filters(event); | ||
| 5936 | struct perf_addr_filter *filter; | ||
| 5937 | unsigned int restart = 0, count = 0; | ||
| 5938 | unsigned long flags; | ||
| 5939 | |||
| 5940 | if (!has_addr_filter(event)) | ||
| 5941 | return; | ||
| 5942 | |||
| 5943 | raw_spin_lock_irqsave(&ifh->lock, flags); | ||
| 5944 | list_for_each_entry(filter, &ifh->list, entry) { | ||
| 5945 | if (filter->inode) { | ||
| 5946 | event->addr_filters_offs[count] = 0; | ||
| 5947 | restart++; | ||
| 5948 | } | ||
| 5949 | |||
| 5950 | count++; | ||
| 5951 | } | ||
| 5952 | |||
| 5953 | if (restart) | ||
| 5954 | event->addr_filters_gen++; | ||
| 5955 | raw_spin_unlock_irqrestore(&ifh->lock, flags); | ||
| 5956 | |||
| 5957 | if (restart) | ||
| 5958 | perf_event_restart(event); | ||
| 5959 | } | ||
| 5960 | |||
| 5961 | void perf_event_exec(void) | ||
| 5962 | { | ||
| 5963 | struct perf_event_context *ctx; | ||
| 5964 | int ctxn; | ||
| 5965 | |||
| 5966 | rcu_read_lock(); | ||
| 5967 | for_each_task_context_nr(ctxn) { | ||
| 5968 | ctx = current->perf_event_ctxp[ctxn]; | ||
| 5969 | if (!ctx) | ||
| 5970 | continue; | ||
| 5971 | |||
| 5972 | perf_event_enable_on_exec(ctxn); | ||
| 5973 | |||
| 5974 | perf_event_aux_ctx(ctx, perf_event_addr_filters_exec, NULL, | ||
| 5975 | true); | ||
| 5976 | } | ||
| 5977 | rcu_read_unlock(); | ||
| 5978 | } | ||
| 5979 | |||
| 5980 | struct remote_output { | ||
| 5981 | struct ring_buffer *rb; | ||
| 5982 | int err; | ||
| 5983 | }; | ||
| 5984 | |||
| 5985 | static void __perf_event_output_stop(struct perf_event *event, void *data) | ||
| 5986 | { | ||
| 5987 | struct perf_event *parent = event->parent; | ||
| 5988 | struct remote_output *ro = data; | ||
| 5989 | struct ring_buffer *rb = ro->rb; | ||
| 5990 | struct stop_event_data sd = { | ||
| 5991 | .event = event, | ||
| 5992 | }; | ||
| 5993 | |||
| 5994 | if (!has_aux(event)) | ||
| 5995 | return; | ||
| 5996 | |||
| 5997 | if (!parent) | ||
| 5998 | parent = event; | ||
| 5999 | |||
| 6000 | /* | ||
| 6001 | * In case of inheritance, it will be the parent that links to the | ||
| 6002 | * ring-buffer, but it will be the child that's actually using it: | ||
| 6003 | */ | ||
| 6004 | if (rcu_dereference(parent->rb) == rb) | ||
| 6005 | ro->err = __perf_event_stop(&sd); | ||
| 6006 | } | ||
| 6007 | |||
| 6008 | static int __perf_pmu_output_stop(void *info) | ||
| 6009 | { | ||
| 6010 | struct perf_event *event = info; | ||
| 6011 | struct pmu *pmu = event->pmu; | ||
| 6012 | struct perf_cpu_context *cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | ||
| 6013 | struct remote_output ro = { | ||
| 6014 | .rb = event->rb, | ||
| 6015 | }; | ||
| 6016 | |||
| 6017 | rcu_read_lock(); | ||
| 6018 | perf_event_aux_ctx(&cpuctx->ctx, __perf_event_output_stop, &ro, false); | ||
| 6019 | if (cpuctx->task_ctx) | ||
| 6020 | perf_event_aux_ctx(cpuctx->task_ctx, __perf_event_output_stop, | ||
| 6021 | &ro, false); | ||
| 6022 | rcu_read_unlock(); | ||
| 6023 | |||
| 6024 | return ro.err; | ||
| 6025 | } | ||
| 6026 | |||
| 6027 | static void perf_pmu_output_stop(struct perf_event *event) | ||
| 6028 | { | ||
| 6029 | struct perf_event *iter; | ||
| 6030 | int err, cpu; | ||
| 6031 | |||
| 6032 | restart: | ||
| 6033 | rcu_read_lock(); | ||
| 6034 | list_for_each_entry_rcu(iter, &event->rb->event_list, rb_entry) { | ||
| 6035 | /* | ||
| 6036 | * For per-CPU events, we need to make sure that neither they | ||
| 6037 | * nor their children are running; for cpu==-1 events it's | ||
| 6038 | * sufficient to stop the event itself if it's active, since | ||
| 6039 | * it can't have children. | ||
| 6040 | */ | ||
| 6041 | cpu = iter->cpu; | ||
| 6042 | if (cpu == -1) | ||
| 6043 | cpu = READ_ONCE(iter->oncpu); | ||
| 6044 | |||
| 6045 | if (cpu == -1) | ||
| 6046 | continue; | ||
| 6047 | |||
| 6048 | err = cpu_function_call(cpu, __perf_pmu_output_stop, event); | ||
| 6049 | if (err == -EAGAIN) { | ||
| 6050 | rcu_read_unlock(); | ||
| 6051 | goto restart; | ||
| 6052 | } | ||
| 6053 | } | ||
| 6054 | rcu_read_unlock(); | ||
| 6055 | } | ||
| 6056 | |||
| 5763 | /* | 6057 | /* |
| 5764 | * task tracking -- fork/exit | 6058 | * task tracking -- fork/exit |
| 5765 | * | 6059 | * |
| @@ -6169,6 +6463,87 @@ got_name: · 403 unmodified lines | |||
| 6169 | kfree(buf); | 6463 | kfree(buf); |
| 6170 | } | 6464 | } |
| 6171 | 6465 | ||
| 6466 | /* | ||
| 6467 | * Whether this @filter depends on a dynamic object which is not loaded | ||
| 6468 | * yet or its load addresses are not known. | ||
| 6469 | */ | ||
| 6470 | static bool perf_addr_filter_needs_mmap(struct perf_addr_filter *filter) | ||
| 6471 | { | ||
| 6472 | return filter->filter && filter->inode; | ||
| 6473 | } | ||
| 6474 | |||
| 6475 | /* | ||
| 6476 | * Check whether inode and address range match filter criteria. | ||
| 6477 | */ | ||
| 6478 | static bool perf_addr_filter_match(struct perf_addr_filter *filter, | ||
| 6479 | struct file *file, unsigned long offset, | ||
| 6480 | unsigned long size) | ||
| 6481 | { | ||
| 6482 | if (filter->inode != file->f_inode) | ||
| 6483 | return false; | ||
| 6484 | |||
| 6485 | if (filter->offset > offset + size) | ||
| 6486 | return false; | ||
| 6487 | |||
| 6488 | if (filter->offset + filter->size < offset) | ||
| 6489 | return false; | ||
| 6490 | |||
| 6491 | return true; | ||
| 6492 | } | ||
| 6493 | |||
| 6494 | static void __perf_addr_filters_adjust(struct perf_event *event, void *data) | ||
| 6495 | { | ||
| 6496 | struct perf_addr_filters_head *ifh = perf_event_addr_filters(event); | ||
| 6497 | struct vm_area_struct *vma = data; | ||
| 6498 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT, flags; | ||
| 6499 | struct file *file = vma->vm_file; | ||
| 6500 | struct perf_addr_filter *filter; | ||
| 6501 | unsigned int restart = 0, count = 0; | ||
| 6502 | |||
| 6503 | if (!has_addr_filter(event)) | ||
| 6504 | return; | ||
| 6505 | |||
| 6506 | if (!file) | ||
| 6507 | return; | ||
| 6508 | |||
| 6509 | raw_spin_lock_irqsave(&ifh->lock, flags); | ||
| 6510 | list_for_each_entry(filter, &ifh->list, entry) { | ||
| 6511 | if (perf_addr_filter_match(filter, file, off, | ||
| 6512 | vma->vm_end - vma->vm_start)) { | ||
| 6513 | event->addr_filters_offs[count] = vma->vm_start; | ||
| 6514 | restart++; | ||
| 6515 | } | ||
| 6516 | |||
| 6517 | count++; | ||
| 6518 | } | ||
| 6519 | |||
| 6520 | if (restart) | ||
| 6521 | event->addr_filters_gen++; | ||
| 6522 | raw_spin_unlock_irqrestore(&ifh->lock, flags); | ||
| 6523 | |||
| 6524 | if (restart) | ||
| 6525 | perf_event_restart(event); | ||
| 6526 | } | ||
| 6527 | |||
| 6528 | /* | ||
| 6529 | * Adjust all task's events' filters to the new vma | ||
| 6530 | */ | ||
| 6531 | static void perf_addr_filters_adjust(struct vm_area_struct *vma) | ||
| 6532 | { | ||
| 6533 | struct perf_event_context *ctx; | ||
| 6534 | int ctxn; | ||
| 6535 | |||
| 6536 | rcu_read_lock(); | ||
| 6537 | for_each_task_context_nr(ctxn) { | ||
| 6538 | ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); | ||
| 6539 | if (!ctx) | ||
| 6540 | continue; | ||
| 6541 | |||
| 6542 | perf_event_aux_ctx(ctx, __perf_addr_filters_adjust, vma, true); | ||
| 6543 | } | ||
| 6544 | rcu_read_unlock(); | ||
| 6545 | } | ||
| 6546 | |||
| 6172 | void perf_event_mmap(struct vm_area_struct *vma) | 6547 | void perf_event_mmap(struct vm_area_struct *vma) |
| 6173 | { | 6548 | { |
| 6174 | struct perf_mmap_event mmap_event; | 6549 | struct perf_mmap_event mmap_event; |
| @@ -6200,6 +6575,7 @@ void perf_event_mmap(struct vm_area_struct *vma) · 25 unmodified lines | |||
| 6200 | /* .flags (attr_mmap2 only) */ | 6575 | /* .flags (attr_mmap2 only) */ |
| 6201 | }; | 6576 | }; |
| 6202 | 6577 | ||
| 6578 | perf_addr_filters_adjust(vma); | ||
| 6203 | perf_event_mmap_event(&mmap_event); | 6579 | perf_event_mmap_event(&mmap_event); |
| 6204 | } | 6580 | } |
| 6205 | 6581 | ||
| @@ -6491,10 +6867,7 @@ static int __perf_event_overflow(struct perf_event *event, · 285 unmodified lines | |||
| 6491 | irq_work_queue(&event->pending); | 6867 | irq_work_queue(&event->pending); |
| 6492 | } | 6868 | } |
| 6493 | 6869 | ||
| 6494 | if (event->overflow_handler) | 6870 | event->overflow_handler(event, data, regs); |
| 6495 | event->overflow_handler(event, data, regs); | ||
| 6496 | else | ||
| 6497 | perf_event_output(event, data, regs); | ||
| 6498 | 6871 | ||
| 6499 | if (*perf_event_fasync(event) && event->pending_kill) { | 6872 | if (*perf_event_fasync(event) && event->pending_kill) { |
| 6500 | event->pending_wakeup = 1; | 6873 | event->pending_wakeup = 1; |
| @@ -7081,24 +7454,6 @@ static inline void perf_tp_register(void) · 580 unmodified lines | |||
| 7081 | perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT); | 7454 | perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT); |
| 7082 | } | 7455 | } |
| 7083 | 7456 | ||
| 7084 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | ||
| 7085 | { | ||
| 7086 | char *filter_str; | ||
| 7087 | int ret; | ||
| 7088 | |||
| 7089 | if (event->attr.type != PERF_TYPE_TRACEPOINT) | ||
| 7090 | return -EINVAL; | ||
| 7091 | |||
| 7092 | filter_str = strndup_user(arg, PAGE_SIZE); | ||
| 7093 | if (IS_ERR(filter_str)) | ||
| 7094 | return PTR_ERR(filter_str); | ||
| 7095 | |||
| 7096 | ret = ftrace_profile_set_filter(event, event->attr.config, filter_str); | ||
| 7097 | |||
| 7098 | kfree(filter_str); | ||
| 7099 | return ret; | ||
| 7100 | } | ||
| 7101 | |||
| 7102 | static void perf_event_free_filter(struct perf_event *event) | 7457 | static void perf_event_free_filter(struct perf_event *event) |
| 7103 | { | 7458 | { |
| 7104 | ftrace_profile_free_filter(event); | 7459 | ftrace_profile_free_filter(event); |
| @@ -7153,11 +7508,6 @@ static inline void perf_tp_register(void) · 48 unmodified lines | |||
| 7153 | { | 7508 | { |
| 7154 | } | 7509 | } |
| 7155 | 7510 | ||
| 7156 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | ||
| 7157 | { | ||
| 7158 | return -ENOENT; | ||
| 7159 | } | ||
| 7160 | |||
| 7161 | static void perf_event_free_filter(struct perf_event *event) | 7511 | static void perf_event_free_filter(struct perf_event *event) |
| 7162 | { | 7512 | { |
| 7163 | } | 7513 | } |
| @@ -7185,6 +7535,387 @@ void perf_bp_event(struct perf_event *bp, void *data) · 21 unmodified lines | |||
| 7185 | } | 7535 | } |
| 7186 | #endif | 7536 | #endif |
| 7187 | 7537 | ||
| 7538 | /* | ||
| 7539 | * Allocate a new address filter | ||
| 7540 | */ | ||
| 7541 | static struct perf_addr_filter * | ||
| 7542 | perf_addr_filter_new(struct perf_event *event, struct list_head *filters) | ||
| 7543 | { | ||
| 7544 | int node = cpu_to_node(event->cpu == -1 ? 0 : event->cpu); | ||
| 7545 | struct perf_addr_filter *filter; | ||
| 7546 | |||
| 7547 | filter = kzalloc_node(sizeof(*filter), GFP_KERNEL, node); | ||
| 7548 | if (!filter) | ||
| 7549 | return NULL; | ||
| 7550 | |||
| 7551 | INIT_LIST_HEAD(&filter->entry); | ||
| 7552 | list_add_tail(&filter->entry, filters); | ||
| 7553 | |||
| 7554 | return filter; | ||
| 7555 | } | ||
| 7556 | |||
| 7557 | static void free_filters_list(struct list_head *filters) | ||
| 7558 | { | ||
| 7559 | struct perf_addr_filter *filter, *iter; | ||
| 7560 | |||
| 7561 | list_for_each_entry_safe(filter, iter, filters, entry) { | ||
| 7562 | if (filter->inode) | ||
| 7563 | iput(filter->inode); | ||
| 7564 | list_del(&filter->entry); | ||
| 7565 | kfree(filter); | ||
| 7566 | } | ||
| 7567 | } | ||
| 7568 | |||
| 7569 | /* | ||
| 7570 | * Free existing address filters and optionally install new ones | ||
| 7571 | */ | ||
| 7572 | static void perf_addr_filters_splice(struct perf_event *event, | ||
| 7573 | struct list_head *head) | ||
| 7574 | { | ||
| 7575 | unsigned long flags; | ||
| 7576 | LIST_HEAD(list); | ||
| 7577 | |||
| 7578 | if (!has_addr_filter(event)) | ||
| 7579 | return; | ||
| 7580 | |||
| 7581 | /* don't bother with children, they don't have their own filters */ | ||
| 7582 | if (event->parent) | ||
| 7583 | return; | ||
| 7584 | |||
| 7585 | raw_spin_lock_irqsave(&event->addr_filters.lock, flags); | ||
| 7586 | |||
| 7587 | list_splice_init(&event->addr_filters.list, &list); | ||
| 7588 | if (head) | ||
| 7589 | list_splice(head, &event->addr_filters.list); | ||
| 7590 | |||
| 7591 | raw_spin_unlock_irqrestore(&event->addr_filters.lock, flags); | ||
| 7592 | |||
| 7593 | free_filters_list(&list); | ||
| 7594 | } | ||
| 7595 | |||
| 7596 | /* | ||
| 7597 | * Scan through mm's vmas and see if one of them matches the | ||
| 7598 | * @filter; if so, adjust filter's address range. | ||
| 7599 | * Called with mm::mmap_sem down for reading. | ||
| 7600 | */ | ||
| 7601 | static unsigned long perf_addr_filter_apply(struct perf_addr_filter *filter, | ||
| 7602 | struct mm_struct *mm) | ||
| 7603 | { | ||
| 7604 | struct vm_area_struct *vma; | ||
| 7605 | |||
| 7606 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
| 7607 | struct file *file = vma->vm_file; | ||
| 7608 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT; | ||
| 7609 | unsigned long vma_size = vma->vm_end - vma->vm_start; | ||
| 7610 | |||
| 7611 | if (!file) | ||
| 7612 | continue; | ||
| 7613 | |||
| 7614 | if (!perf_addr_filter_match(filter, file, off, vma_size)) | ||
| 7615 | continue; | ||
| 7616 | |||
| 7617 | return vma->vm_start; | ||
| 7618 | } | ||
| 7619 | |||
| 7620 | return 0; | ||
| 7621 | } | ||
| 7622 | |||
| 7623 | /* | ||
| 7624 | * Update event's address range filters based on the | ||
| 7625 | * task's existing mappings, if any. | ||
| 7626 | */ | ||
| 7627 | static void perf_event_addr_filters_apply(struct perf_event *event) | ||
| 7628 | { | ||
| 7629 | struct perf_addr_filters_head *ifh = perf_event_addr_filters(event); | ||
| 7630 | struct task_struct *task = READ_ONCE(event->ctx->task); | ||
| 7631 | struct perf_addr_filter *filter; | ||
| 7632 | struct mm_struct *mm = NULL; | ||
| 7633 | unsigned int count = 0; | ||
| 7634 | unsigned long flags; | ||
| 7635 | |||
| 7636 | /* | ||
| 7637 | * We may observe TASK_TOMBSTONE, which means that the event tear-down | ||
| 7638 | * will stop on the parent's child_mutex that our caller is also holding | ||
| 7639 | */ | ||
| 7640 | if (task == TASK_TOMBSTONE) | ||
| 7641 | return; | ||
| 7642 | |||
| 7643 | mm = get_task_mm(event->ctx->task); | ||
| 7644 | if (!mm) | ||
| 7645 | goto restart; | ||
| 7646 | |||
| 7647 | down_read(&mm->mmap_sem); | ||
| 7648 | |||
| 7649 | raw_spin_lock_irqsave(&ifh->lock, flags); | ||
| 7650 | list_for_each_entry(filter, &ifh->list, entry) { | ||
| 7651 | event->addr_filters_offs[count] = 0; | ||
| 7652 | |||
| 7653 | if (perf_addr_filter_needs_mmap(filter)) | ||
| 7654 | event->addr_filters_offs[count] = | ||
| 7655 | perf_addr_filter_apply(filter, mm); | ||
| 7656 | |||
| 7657 | count++; | ||
| 7658 | } | ||
| 7659 | |||
| 7660 | event->addr_filters_gen++; | ||
| 7661 | raw_spin_unlock_irqrestore(&ifh->lock, flags); | ||
| 7662 | |||
| 7663 | up_read(&mm->mmap_sem); | ||
| 7664 | |||
| 7665 | mmput(mm); | ||
| 7666 | |||
| 7667 | restart: | ||
| 7668 | perf_event_restart(event); | ||
| 7669 | } | ||
| 7670 | |||
| 7671 | /* | ||
| 7672 | * Address range filtering: limiting the data to certain | ||
| 7673 | * instruction address ranges. Filters are ioctl()ed to us from | ||
| 7674 | * userspace as ascii strings. | ||
| 7675 | * | ||
| 7676 | * Filter string format: | ||
| 7677 | * | ||
| 7678 | * ACTION RANGE_SPEC | ||
| 7679 | * where ACTION is one of the | ||
| 7680 | * * "filter": limit the trace to this region | ||
| 7681 | * * "start": start tracing from this address | ||
| 7682 | * * "stop": stop tracing at this address/region; | ||
| 7683 | * RANGE_SPEC is | ||
| 7684 | * * for kernel addresses: <start address>[/<size>] | ||
| 7685 | * * for object files: <start address>[/<size>]@</path/to/object/file> | ||
| 7686 | * | ||
| 7687 | * if <size> is not specified, the range is treated as a single address. | ||
| 7688 | */ | ||
| 7689 | enum { | ||
| 7690 | IF_ACT_FILTER, | ||
| 7691 | IF_ACT_START, | ||
| 7692 | IF_ACT_STOP, | ||
| 7693 | IF_SRC_FILE, | ||
| 7694 | IF_SRC_KERNEL, | ||
| 7695 | IF_SRC_FILEADDR, | ||
| 7696 | IF_SRC_KERNELADDR, | ||
| 7697 | }; | ||
| 7698 | |||
| 7699 | enum { | ||
| 7700 | IF_STATE_ACTION = 0, | ||
| 7701 | IF_STATE_SOURCE, | ||
| 7702 | IF_STATE_END, | ||
| 7703 | }; | ||
| 7704 | |||
| 7705 | static const match_table_t if_tokens = { | ||
| 7706 | { IF_ACT_FILTER, "filter" }, | ||
| 7707 | { IF_ACT_START, "start" }, | ||
| 7708 | { IF_ACT_STOP, "stop" }, | ||
| 7709 | { IF_SRC_FILE, "%u/%u@%s" }, | ||
| 7710 | { IF_SRC_KERNEL, "%u/%u" }, | ||
| 7711 | { IF_SRC_FILEADDR, "%u@%s" }, | ||
| 7712 | { IF_SRC_KERNELADDR, "%u" }, | ||
| 7713 | }; | ||
| 7714 | |||
| 7715 | /* | ||
| 7716 | * Address filter string parser | ||
| 7717 | */ | ||
| 7718 | static int | ||
| 7719 | perf_event_parse_addr_filter(struct perf_event *event, char *fstr, | ||
| 7720 | struct list_head *filters) | ||
| 7721 | { | ||
| 7722 | struct perf_addr_filter *filter = NULL; | ||
| 7723 | char *start, *orig, *filename = NULL; | ||
| 7724 | struct path path; | ||
| 7725 | substring_t args[MAX_OPT_ARGS]; | ||
| 7726 | int state = IF_STATE_ACTION, token; | ||
| 7727 | unsigned int kernel = 0; | ||
| 7728 | int ret = -EINVAL; | ||
| 7729 | |||
| 7730 | orig = fstr = kstrdup(fstr, GFP_KERNEL); | ||
| 7731 | if (!fstr) | ||
| 7732 | return -ENOMEM; | ||
| 7733 | |||
| 7734 | while ((start = strsep(&fstr, " ,\n")) != NULL) { | ||
| 7735 | ret = -EINVAL; | ||
| 7736 | |||
| 7737 | if (!*start) | ||
| 7738 | continue; | ||
| 7739 | |||
| 7740 | /* filter definition begins */ | ||
| 7741 | if (state == IF_STATE_ACTION) { | ||
| 7742 | filter = perf_addr_filter_new(event, filters); | ||
| 7743 | if (!filter) | ||
| 7744 | goto fail; | ||
| 7745 | } | ||
| 7746 | |||
| 7747 | token = match_token(start, if_tokens, args); | ||
| 7748 | switch (token) { | ||
| 7749 | case IF_ACT_FILTER: | ||
| 7750 | case IF_ACT_START: | ||
| 7751 | filter->filter = 1; | ||
| 7752 | |||
| 7753 | case IF_ACT_STOP: | ||
| 7754 | if (state != IF_STATE_ACTION) | ||
| 7755 | goto fail; | ||
| 7756 | |||
| 7757 | state = IF_STATE_SOURCE; | ||
| 7758 | break; | ||
| 7759 | |||
| 7760 | case IF_SRC_KERNELADDR: | ||
| 7761 | case IF_SRC_KERNEL: | ||
| 7762 | kernel = 1; | ||
| 7763 | |||
| 7764 | case IF_SRC_FILEADDR: | ||
| 7765 | case IF_SRC_FILE: | ||
| 7766 | if (state != IF_STATE_SOURCE) | ||
| 7767 | goto fail; | ||
| 7768 | |||
| 7769 | if (token == IF_SRC_FILE || token == IF_SRC_KERNEL) | ||
| 7770 | filter->range = 1; | ||
| 7771 | |||
| 7772 | *args[0].to = 0; | ||
| 7773 | ret = kstrtoul(args[0].from, 0, &filter->offset); | ||
| 7774 | if (ret) | ||
| 7775 | goto fail; | ||
| 7776 | |||
| 7777 | if (filter->range) { | ||
| 7778 | *args[1].to = 0; | ||
| 7779 | ret = kstrtoul(args[1].from, 0, &filter->size); | ||
| 7780 | if (ret) | ||
| 7781 | goto fail; | ||
| 7782 | } | ||
| 7783 | |||
| 7784 | if (token == IF_SRC_FILE) { | ||
| 7785 | filename = match_strdup(&args[2]); | ||
| 7786 | if (!filename) { | ||
| 7787 | ret = -ENOMEM; | ||
| 7788 | goto fail; | ||
| 7789 | } | ||
| 7790 | } | ||
| 7791 | |||
| 7792 | state = IF_STATE_END; | ||
| 7793 | break; | ||
| 7794 | |||
| 7795 | default: | ||
| 7796 | goto fail; | ||
| 7797 | } | ||
| 7798 | |||
| 7799 | /* | ||
| 7800 | * Filter definition is fully parsed, validate and install it. | ||
| 7801 | * Make sure that it doesn't contradict itself or the event's | ||
| 7802 | * attribute. | ||
| 7803 | */ | ||
| 7804 | if (state == IF_STATE_END) { | ||
| 7805 | if (kernel && event->attr.exclude_kernel) | ||
| 7806 | goto fail; | ||
| 7807 | |||
| 7808 | if (!kernel) { | ||
| 7809 | if (!filename) | ||
| 7810 | goto fail; | ||
| 7811 | |||
| 7812 | /* look up the path and grab its inode */ | ||
| 7813 | ret = kern_path(filename, LOOKUP_FOLLOW, &path); | ||
| 7814 | if (ret) | ||
| 7815 | goto fail_free_name; | ||
| 7816 | |||
| 7817 | filter->inode = igrab(d_inode(path.dentry)); | ||
| 7818 | path_put(&path); | ||
| 7819 | kfree(filename); | ||
| 7820 | filename = NULL; | ||
| 7821 | |||
| 7822 | ret = -EINVAL; | ||
| 7823 | if (!filter->inode || | ||
| 7824 | !S_ISREG(filter->inode->i_mode)) | ||
| 7825 | /* free_filters_list() will iput() */ | ||
| 7826 | goto fail; | ||
| 7827 | } | ||
| 7828 | |||
| 7829 | /* ready to consume more filters */ | ||
| 7830 | state = IF_STATE_ACTION; | ||
| 7831 | filter = NULL; | ||
| 7832 | } | ||
| 7833 | } | ||
| 7834 | |||
| 7835 | if (state != IF_STATE_ACTION) | ||
| 7836 | goto fail; | ||
| 7837 | |||
| 7838 | kfree(orig); | ||
| 7839 | |||
| 7840 | return 0; | ||
| 7841 | |||
| 7842 | fail_free_name: | ||
| 7843 | kfree(filename); | ||
| 7844 | fail: | ||
| 7845 | free_filters_list(filters); | ||
| 7846 | kfree(orig); | ||
| 7847 | |||
| 7848 | return ret; | ||
| 7849 | } | ||
| 7850 | |||
| 7851 | static int | ||
| 7852 | perf_event_set_addr_filter(struct perf_event *event, char *filter_str) | ||
| 7853 | { | ||
| 7854 | LIST_HEAD(filters); | ||
| 7855 | int ret; | ||
| 7856 | |||
| 7857 | /* | ||
| 7858 | * Since this is called in perf_ioctl() path, we're already holding | ||
| 7859 | * ctx::mutex. | ||
| 7860 | */ | ||
| 7861 | lockdep_assert_held(&event->ctx->mutex); | ||
| 7862 | |||
| 7863 | if (WARN_ON_ONCE(event->parent)) | ||
| 7864 | return -EINVAL; | ||
| 7865 | |||
| 7866 | /* | ||
| 7867 | * For now, we only support filtering in per-task events; doing so | ||
| 7868 | * for CPU-wide events requires additional context switching trickery, | ||
| 7869 | * since same object code will be mapped at different virtual | ||
| 7870 | * addresses in different processes. | ||
| 7871 | */ | ||
| 7872 | if (!event->ctx->task) | ||
| 7873 | return -EOPNOTSUPP; | ||
| 7874 | |||
| 7875 | ret = perf_event_parse_addr_filter(event, filter_str, &filters); | ||
| 7876 | if (ret) | ||
| 7877 | return ret; | ||
| 7878 | |||
| 7879 | ret = event->pmu->addr_filters_validate(&filters); | ||
| 7880 | if (ret) { | ||
| 7881 | free_filters_list(&filters); | ||
| 7882 | return ret; | ||
| 7883 | } | ||
| 7884 | |||
| 7885 | /* remove existing filters, if any */ | ||
| 7886 | perf_addr_filters_splice(event, &filters); | ||
| 7887 | |||
| 7888 | /* install new filters */ | ||
| 7889 | perf_event_for_each_child(event, perf_event_addr_filters_apply); | ||
| 7890 | |||
| 7891 | return ret; | ||
| 7892 | } | ||
| 7893 | |||
| 7894 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | ||
| 7895 | { | ||
| 7896 | char *filter_str; | ||
| 7897 | int ret = -EINVAL; | ||
| 7898 | |||
| 7899 | if ((event->attr.type != PERF_TYPE_TRACEPOINT || | ||
| 7900 | !IS_ENABLED(CONFIG_EVENT_TRACING)) && | ||
| 7901 | !has_addr_filter(event)) | ||
| 7902 | return -EINVAL; | ||
| 7903 | |||
| 7904 | filter_str = strndup_user(arg, PAGE_SIZE); | ||
| 7905 | if (IS_ERR(filter_str)) | ||
| 7906 | return PTR_ERR(filter_str); | ||
| 7907 | |||
| 7908 | if (IS_ENABLED(CONFIG_EVENT_TRACING) && | ||
| 7909 | event->attr.type == PERF_TYPE_TRACEPOINT) | ||
| 7910 | ret = ftrace_profile_set_filter(event, event->attr.config, | ||
| 7911 | filter_str); | ||
| 7912 | else if (has_addr_filter(event)) | ||
| 7913 | ret = perf_event_set_addr_filter(event, filter_str); | ||
| 7914 | |||
| 7915 | kfree(filter_str); | ||
| 7916 | return ret; | ||
| 7917 | } | ||
| 7918 | |||
| 7188 | /* | 7919 | /* |
| 7189 | * hrtimer based swevent callback | 7920 | * hrtimer based swevent callback |
| 7190 | */ | 7921 | */ |
| @@ -7542,6 +8273,20 @@ static void free_pmu_context(struct pmu *pmu) · 351 unmodified lines | |||
| 7542 | out: | 8273 | out: |
| 7543 | mutex_unlock(&pmus_lock); | 8274 | mutex_unlock(&pmus_lock); |
| 7544 | } | 8275 | } |
| 8276 | |||
| 8277 | /* | ||
| 8278 | * Let userspace know that this PMU supports address range filtering: | ||
| 8279 | */ | ||
| 8280 | static ssize_t nr_addr_filters_show(struct device *dev, | ||
| 8281 | struct device_attribute *attr, | ||
| 8282 | char *page) | ||
| 8283 | { | ||
| 8284 | struct pmu *pmu = dev_get_drvdata(dev); | ||
| 8285 | |||
| 8286 | return snprintf(page, PAGE_SIZE - 1, "%d\n", pmu->nr_addr_filters); | ||
| 8287 | } | ||
| 8288 | DEVICE_ATTR_RO(nr_addr_filters); | ||
| 8289 | |||
| 7545 | static struct idr pmu_idr; | 8290 | static struct idr pmu_idr; |
| 7546 | 8291 | ||
| 7547 | static ssize_t | 8292 | static ssize_t |
| @@ -7643,9 +8388,19 @@ static int pmu_dev_alloc(struct pmu *pmu) · 95 unmodified lines | |||
| 7643 | if (ret) | 8388 | if (ret) |
| 7644 | goto free_dev; | 8389 | goto free_dev; |
| 7645 | 8390 | ||
| 8391 | /* For PMUs with address filters, throw in an extra attribute: */ | ||
| 8392 | if (pmu->nr_addr_filters) | ||
| 8393 | ret = device_create_file(pmu->dev, &dev_attr_nr_addr_filters); | ||
| 8394 | |||
| 8395 | if (ret) | ||
| 8396 | goto del_dev; | ||
| 8397 | |||
| 7646 | out: | 8398 | out: |
| 7647 | return ret; | 8399 | return ret; |
| 7648 | 8400 | ||
| 8401 | del_dev: | ||
| 8402 | device_del(pmu->dev); | ||
| 8403 | |||
| 7649 | free_dev: | 8404 | free_dev: |
| 7650 | put_device(pmu->dev); | 8405 | put_device(pmu->dev); |
| 7651 | goto out; | 8406 | goto out; |
| @@ -7685,6 +8440,21 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type) · 33 unmodified lines | |||
| 7685 | } | 8440 | } |
| 7686 | 8441 | ||
| 7687 | skip_type: | 8442 | skip_type: |
| 8443 | if (pmu->task_ctx_nr == perf_hw_context) { | ||
| 8444 | static int hw_context_taken = 0; | ||
| 8445 | |||
| 8446 | /* | ||
| 8447 | * Other than systems with heterogeneous CPUs, it never makes | ||
| 8448 | * sense for two PMUs to share perf_hw_context. PMUs which are | ||
| 8449 | * uncore must use perf_invalid_context. | ||
| 8450 | */ | ||
| 8451 | if (WARN_ON_ONCE(hw_context_taken && | ||
| 8452 | !(pmu->capabilities & PERF_PMU_CAP_HETEROGENEOUS_CPUS))) | ||
| 8453 | pmu->task_ctx_nr = perf_invalid_context; | ||
| 8454 | |||
| 8455 | hw_context_taken = 1; | ||
| 8456 | } | ||
| 8457 | |||
| 7688 | pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); | 8458 | pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); |
| 7689 | if (pmu->pmu_cpu_context) | 8459 | if (pmu->pmu_cpu_context) |
| 7690 | goto got_cpu_context; | 8460 | goto got_cpu_context; |
| @@ -7772,6 +8542,8 @@ void perf_pmu_unregister(struct pmu *pmu) · 81 unmodified lines | |||
| 7772 | free_percpu(pmu->pmu_disable_count); | 8542 | free_percpu(pmu->pmu_disable_count); |
| 7773 | if (pmu->type >= PERF_TYPE_MAX) | 8543 | if (pmu->type >= PERF_TYPE_MAX) |
| 7774 | idr_remove(&pmu_idr, pmu->type); | 8544 | idr_remove(&pmu_idr, pmu->type); |
| 8545 | if (pmu->nr_addr_filters) | ||
| 8546 | device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); | ||
| 7775 | device_del(pmu->dev); | 8547 | device_del(pmu->dev); |
| 7776 | put_device(pmu->dev); | 8548 | put_device(pmu->dev); |
| 7777 | free_pmu_context(pmu); | 8549 | free_pmu_context(pmu); |
| @@ -7965,6 +8737,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, · 187 unmodified lines | |||
| 7965 | INIT_LIST_HEAD(&event->sibling_list); | 8737 | INIT_LIST_HEAD(&event->sibling_list); |
| 7966 | INIT_LIST_HEAD(&event->rb_entry); | 8738 | INIT_LIST_HEAD(&event->rb_entry); |
| 7967 | INIT_LIST_HEAD(&event->active_entry); | 8739 | INIT_LIST_HEAD(&event->active_entry); |
| 8740 | INIT_LIST_HEAD(&event->addr_filters.list); | ||
| 7968 | INIT_HLIST_NODE(&event->hlist_entry); | 8741 | INIT_HLIST_NODE(&event->hlist_entry); |
| 7969 | 8742 | ||
| 7970 | 8743 | ||
| @@ -7972,6 +8745,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, · 1 unmodified line | |||
| 7972 | init_irq_work(&event->pending, perf_pending_event); | 8745 | init_irq_work(&event->pending, perf_pending_event); |
| 7973 | 8746 | ||
| 7974 | mutex_init(&event->mmap_mutex); | 8747 | mutex_init(&event->mmap_mutex); |
| 8748 | raw_spin_lock_init(&event->addr_filters.lock); | ||
| 7975 | 8749 | ||
| 7976 | atomic_long_set(&event->refcount, 1); | 8750 | atomic_long_set(&event->refcount, 1); |
| 7977 | event->cpu = cpu; | 8751 | event->cpu = cpu; |
| @@ -8006,8 +8780,16 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, · 28 unmodified lines | |||
| 8006 | context = parent_event->overflow_handler_context; | 8780 | context = parent_event->overflow_handler_context; |
| 8007 | } | 8781 | } |
| 8008 | 8782 | ||
| 8009 | event->overflow_handler = overflow_handler; | 8783 | if (overflow_handler) { |
| 8010 | event->overflow_handler_context = context; | 8784 | event->overflow_handler = overflow_handler; |
| 8785 | event->overflow_handler_context = context; | ||
| 8786 | } else if (is_write_backward(event)){ | ||
| 8787 | event->overflow_handler = perf_event_output_backward; | ||
| 8788 | event->overflow_handler_context = NULL; | ||
| 8789 | } else { | ||
| 8790 | event->overflow_handler = perf_event_output_forward; | ||
| 8791 | event->overflow_handler_context = NULL; | ||
| 8792 | } | ||
| 8011 | 8793 | ||
| 8012 | perf_event__state_init(event); | 8794 | perf_event__state_init(event); |
| 8013 | 8795 | ||
| @@ -8048,11 +8830,22 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, · 34 unmodified lines | |||
| 8048 | if (err) | 8830 | if (err) |
| 8049 | goto err_pmu; | 8831 | goto err_pmu; |
| 8050 | 8832 | ||
| 8833 | if (has_addr_filter(event)) { | ||
| 8834 | event->addr_filters_offs = kcalloc(pmu->nr_addr_filters, | ||
| 8835 | sizeof(unsigned long), | ||
| 8836 | GFP_KERNEL); | ||
| 8837 | if (!event->addr_filters_offs) | ||
| 8838 | goto err_per_task; | ||
| 8839 | |||
| 8840 | /* force hw sync on the address filters */ | ||
| 8841 | event->addr_filters_gen = 1; | ||
| 8842 | } | ||
| 8843 | |||
| 8051 | if (!event->parent) { | 8844 | if (!event->parent) { |
| 8052 | if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { | 8845 | if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { |
| 8053 | err = get_callchain_buffers(); | 8846 | err = get_callchain_buffers(); |
| 8054 | if (err) | 8847 | if (err) |
| 8055 | goto err_per_task; | 8848 | goto err_addr_filters; |
| 8056 | } | 8849 | } |
| 8057 | } | 8850 | } |
| 8058 | 8851 | ||
| @@ -8061,6 +8854,9 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, · 2 unmodified lines | |||
| 8061 | 8854 | ||
| 8062 | return event; | 8855 | return event; |
| 8063 | 8856 | ||
| 8857 | err_addr_filters: | ||
| 8858 | kfree(event->addr_filters_offs); | ||
| 8859 | |||
| 8064 | err_per_task: | 8860 | err_per_task: |
| 8065 | exclusive_event_destroy(event); | 8861 | exclusive_event_destroy(event); |
| 8066 | 8862 | ||
| @@ -8239,6 +9035,13 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event) · 172 unmodified lines | |||
| 8239 | if (output_event->clock != event->clock) | 9035 | if (output_event->clock != event->clock) |
| 8240 | goto out; | 9036 | goto out; |
| 8241 | 9037 | ||
| 9038 | /* | ||
| 9039 | * Either writing ring buffer from beginning or from end. | ||
| 9040 | * Mixing is not allowed. | ||
| 9041 | */ | ||
| 9042 | if (is_write_backward(output_event) != is_write_backward(event)) | ||
| 9043 | goto out; | ||
| 9044 | |||
| 8242 | /* | 9045 | /* |
| 8243 | * If both events generate aux data, they must be on the same PMU | 9046 | * If both events generate aux data, they must be on the same PMU |
| 8244 | */ | 9047 | */ |
| @@ -11,13 +11,13 @@ · 10 unmodified lines | |||
| 11 | struct ring_buffer { | 11 | struct ring_buffer { |
| 12 | atomic_t refcount; | 12 | atomic_t refcount; |
| 13 | struct rcu_head rcu_head; | 13 | struct rcu_head rcu_head; |
| 14 | struct irq_work irq_work; | ||
| 15 | #ifdef CONFIG_PERF_USE_VMALLOC | 14 | #ifdef CONFIG_PERF_USE_VMALLOC |
| 16 | struct work_struct work; | 15 | struct work_struct work; |
| 17 | int page_order; /* allocation order */ | 16 | int page_order; /* allocation order */ |
| 18 | #endif | 17 | #endif |
| 19 | int nr_pages; /* nr of data pages */ | 18 | int nr_pages; /* nr of data pages */ |
| 20 | int overwrite; /* can overwrite itself */ | 19 | int overwrite; /* can overwrite itself */ |
| 20 | int paused; /* can write into ring buffer */ | ||
| 21 | 21 | ||
| 22 | atomic_t poll; /* POLL_ for wakeups */ | 22 | atomic_t poll; /* POLL_ for wakeups */ |
| 23 | 23 | ||
| @@ -65,6 +65,14 @@ static inline void rb_free_rcu(struct rcu_head *rcu_head) · 41 unmodified lines | |||
| 65 | rb_free(rb); | 65 | rb_free(rb); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | static inline void rb_toggle_paused(struct ring_buffer *rb, bool pause) | ||
| 69 | { | ||
| 70 | if (!pause && rb->nr_pages) | ||
| 71 | rb->paused = 0; | ||
| 72 | else | ||
| 73 | rb->paused = 1; | ||
| 74 | } | ||
| 75 | |||
| 68 | extern struct ring_buffer * | 76 | extern struct ring_buffer * |
| 69 | rb_alloc(int nr_pages, long watermark, int cpu, int flags); | 77 | rb_alloc(int nr_pages, long watermark, int cpu, int flags); |
| 70 | extern void perf_event_wakeup(struct perf_event *event); | 78 | extern void perf_event_wakeup(struct perf_event *event); |
| @@ -102,8 +102,21 @@ out: · 101 unmodified lines | |||
| 102 | preempt_enable(); | 102 | preempt_enable(); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | int perf_output_begin(struct perf_output_handle *handle, | 105 | static bool __always_inline |
| 106 | struct perf_event *event, unsigned int size) | 106 | ring_buffer_has_space(unsigned long head, unsigned long tail, |
| 107 | unsigned long data_size, unsigned int size, | ||
| 108 | bool backward) | ||
| 109 | { | ||
| 110 | if (!backward) | ||
| 111 | return CIRC_SPACE(head, tail, data_size) >= size; | ||
| 112 | else | ||
| 113 | return CIRC_SPACE(tail, head, data_size) >= size; | ||
| 114 | } | ||
| 115 | |||
| 116 | static int __always_inline | ||
| 117 | __perf_output_begin(struct perf_output_handle *handle, | ||
| 118 | struct perf_event *event, unsigned int size, | ||
| 119 | bool backward) | ||
| 107 | { | 120 | { |
| 108 | struct ring_buffer *rb; | 121 | struct ring_buffer *rb; |
| 109 | unsigned long tail, offset, head; | 122 | unsigned long tail, offset, head; |
| @@ -125,8 +138,11 @@ int perf_output_begin(struct perf_output_handle *handle, · 15 unmodified lines | |||
| 125 | if (unlikely(!rb)) | 138 | if (unlikely(!rb)) |
| 126 | goto out; | 139 | goto out; |
| 127 | 140 | ||
| 128 | if (unlikely(!rb->nr_pages)) | 141 | if (unlikely(rb->paused)) { |
| 142 | if (rb->nr_pages) | ||
| 143 | local_inc(&rb->lost); | ||
| 129 | goto out; | 144 | goto out; |
| 145 | } | ||
| 130 | 146 | ||
| 131 | handle->rb = rb; | 147 | handle->rb = rb; |
| 132 | handle->event = event; | 148 | handle->event = event; |
| @@ -143,9 +159,12 @@ int perf_output_begin(struct perf_output_handle *handle, · 10 unmodified lines | |||
| 143 | do { | 159 | do { |
| 144 | tail = READ_ONCE(rb->user_page->data_tail); | 160 | tail = READ_ONCE(rb->user_page->data_tail); |
| 145 | offset = head = local_read(&rb->head); | 161 | offset = head = local_read(&rb->head); |
| 146 | if (!rb->overwrite && | 162 | if (!rb->overwrite) { |
| 147 | unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size)) | 163 | if (unlikely(!ring_buffer_has_space(head, tail, |
| 148 | goto fail; | 164 | perf_data_size(rb), |
| 165 | size, backward))) | ||
| 166 | goto fail; | ||
| 167 | } | ||
| 149 | 168 | ||
| 150 | /* | 169 | /* |
| 151 | * The above forms a control dependency barrier separating the | 170 | * The above forms a control dependency barrier separating the |
| @@ -159,9 +178,17 @@ int perf_output_begin(struct perf_output_handle *handle, · 7 unmodified lines | |||
| 159 | * See perf_output_put_handle(). | 178 | * See perf_output_put_handle(). |
| 160 | */ | 179 | */ |
| 161 | 180 | ||
| 162 | head += size; | 181 | if (!backward) |
| 182 | head += size; | ||
| 183 | else | ||
| 184 | head -= size; | ||
| 163 | } while (local_cmpxchg(&rb->head, offset, head) != offset); | 185 | } while (local_cmpxchg(&rb->head, offset, head) != offset); |
| 164 | 186 | ||
| 187 | if (backward) { | ||
| 188 | offset = head; | ||
| 189 | head = (u64)(-head); | ||
| 190 | } | ||
| 191 | |||
| 165 | /* | 192 | /* |
| 166 | * We rely on the implied barrier() by local_cmpxchg() to ensure | 193 | * We rely on the implied barrier() by local_cmpxchg() to ensure |
| 167 | * none of the data stores below can be lifted up by the compiler. | 194 | * none of the data stores below can be lifted up by the compiler. |
| @@ -203,6 +230,26 @@ out: · 35 unmodified lines | |||
| 203 | return -ENOSPC; | 230 | return -ENOSPC; |
| 204 | } | 231 | } |
| 205 | 232 | ||
| 233 | int perf_output_begin_forward(struct perf_output_handle *handle, | ||
| 234 | struct perf_event *event, unsigned int size) | ||
| 235 | { | ||
| 236 | return __perf_output_begin(handle, event, size, false); | ||
| 237 | } | ||
| 238 | |||
| 239 | int perf_output_begin_backward(struct perf_output_handle *handle, | ||
| 240 | struct perf_event *event, unsigned int size) | ||
| 241 | { | ||
| 242 | return __perf_output_begin(handle, event, size, true); | ||
| 243 | } | ||
| 244 | |||
| 245 | int perf_output_begin(struct perf_output_handle *handle, | ||
| 246 | struct perf_event *event, unsigned int size) | ||
| 247 | { | ||
| 248 | |||
| 249 | return __perf_output_begin(handle, event, size, | ||
| 250 | unlikely(is_write_backward(event))); | ||
| 251 | } | ||
| 252 | |||
| 206 | unsigned int perf_output_copy(struct perf_output_handle *handle, | 253 | unsigned int perf_output_copy(struct perf_output_handle *handle, |
| 207 | const void *buf, unsigned int len) | 254 | const void *buf, unsigned int len) |
| 208 | { | 255 | { |
| @@ -221,8 +268,6 @@ void perf_output_end(struct perf_output_handle *handle) · 12 unmodified lines | |||
| 221 | rcu_read_unlock(); | 268 | rcu_read_unlock(); |
| 222 | } | 269 | } |
| 223 | 270 | ||
| 224 | static void rb_irq_work(struct irq_work *work); | ||
| 225 | |||
| 226 | static void | 271 | static void |
| 227 | ring_buffer_init(struct ring_buffer *rb, long watermark, int flags) | 272 | ring_buffer_init(struct ring_buffer *rb, long watermark, int flags) |
| 228 | { | 273 | { |
| @@ -243,16 +288,13 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags) · 14 unmodified lines | |||
| 243 | 288 | ||
| 244 | INIT_LIST_HEAD(&rb->event_list); | 289 | INIT_LIST_HEAD(&rb->event_list); |
| 245 | spin_lock_init(&rb->event_lock); | 290 | spin_lock_init(&rb->event_lock); |
| 246 | init_irq_work(&rb->irq_work, rb_irq_work); | ||
| 247 | } | ||
| 248 | 291 | ||
| 249 | static void ring_buffer_put_async(struct ring_buffer *rb) | 292 | /* |
| 250 | { | 293 | * perf_output_begin() only checks rb->paused, therefore |
| 251 | if (!atomic_dec_and_test(&rb->refcount)) | 294 | * rb->paused must be true if we have no pages for output. |
| 252 | return; | 295 | */ |
| 253 | 296 | if (!rb->nr_pages) | |
| 254 | rb->rcu_head.next = (void *)rb; | 297 | rb->paused = 1; |
| 255 | irq_work_queue(&rb->irq_work); | ||
| 256 | } | 298 | } |
| 257 | 299 | ||
| 258 | /* | 300 | /* |
| @@ -264,6 +306,10 @@ static void ring_buffer_put_async(struct ring_buffer *rb) · 5 unmodified lines | |||
| 264 | * The ordering is similar to that of perf_output_{begin,end}, with | 306 | * The ordering is similar to that of perf_output_{begin,end}, with |
| 265 | * the exception of (B), which should be taken care of by the pmu | 307 | * the exception of (B), which should be taken care of by the pmu |
| 266 | * driver, since ordering rules will differ depending on hardware. | 308 | * driver, since ordering rules will differ depending on hardware. |
| 309 | * | ||
| 310 | * Call this from pmu::start(); see the comment in perf_aux_output_end() | ||
| 311 | * about its use in pmu callbacks. Both can also be called from the PMI | ||
| 312 | * handler if needed. | ||
| 267 | */ | 313 | */ |
| 268 | void *perf_aux_output_begin(struct perf_output_handle *handle, | 314 | void *perf_aux_output_begin(struct perf_output_handle *handle, |
| 269 | struct perf_event *event) | 315 | struct perf_event *event) |
| @@ -287,6 +333,13 @@ void *perf_aux_output_begin(struct perf_output_handle *handle, · 17 unmodified lines | |||
| 287 | if (!rb_has_aux(rb) || !atomic_inc_not_zero(&rb->aux_refcount)) | 333 | if (!rb_has_aux(rb) || !atomic_inc_not_zero(&rb->aux_refcount)) |
| 288 | goto err; | 334 | goto err; |
| 289 | 335 | ||
| 336 | /* | ||
| 337 | * If rb::aux_mmap_count is zero (and rb_has_aux() above went through), | ||
| 338 | * the aux buffer is in perf_mmap_close(), about to get freed. | ||
| 339 | */ | ||
| 340 | if (!atomic_read(&rb->aux_mmap_count)) | ||
| 341 | goto err_put; | ||
| 342 | |||
| 290 | /* | 343 | /* |
| 291 | * Nesting is not supported for AUX area, make sure nested | 344 | * Nesting is not supported for AUX area, make sure nested |
| 292 | * writers are caught early | 345 | * writers are caught early |
| @@ -328,10 +381,11 @@ void *perf_aux_output_begin(struct perf_output_handle *handle, · 35 unmodified lines | |||
| 328 | return handle->rb->aux_priv; | 381 | return handle->rb->aux_priv; |
| 329 | 382 | ||
| 330 | err_put: | 383 | err_put: |
| 384 | /* can't be last */ | ||
| 331 | rb_free_aux(rb); | 385 | rb_free_aux(rb); |
| 332 | 386 | ||
| 333 | err: | 387 | err: |
| 334 | ring_buffer_put_async(rb); | 388 | ring_buffer_put(rb); |
| 335 | handle->event = NULL; | 389 | handle->event = NULL; |
| 336 | 390 | ||
| 337 | return NULL; | 391 | return NULL; |
| @@ -342,6 +396,10 @@ err: · 4 unmodified lines | |||
| 342 | * aux_head and posting a PERF_RECORD_AUX into the perf buffer. It is the | 396 | * aux_head and posting a PERF_RECORD_AUX into the perf buffer. It is the |
| 343 | * pmu driver's responsibility to observe ordering rules of the hardware, | 397 | * pmu driver's responsibility to observe ordering rules of the hardware, |
| 344 | * so that all the data is externally visible before this is called. | 398 | * so that all the data is externally visible before this is called. |
| 399 | * | ||
| 400 | * Note: this has to be called from pmu::stop() callback, as the assumption | ||
| 401 | * of the AUX buffer management code is that after pmu::stop(), the AUX | ||
| 402 | * transaction must be stopped and therefore drop the AUX reference count. | ||
| 345 | */ | 403 | */ |
| 346 | void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size, | 404 | void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size, |
| 347 | bool truncated) | 405 | bool truncated) |
| @@ -389,8 +447,9 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size, · 41 unmodified lines | |||
| 389 | handle->event = NULL; | 447 | handle->event = NULL; |
| 390 | 448 | ||
| 391 | local_set(&rb->aux_nest, 0); | 449 | local_set(&rb->aux_nest, 0); |
| 450 | /* can't be last */ | ||
| 392 | rb_free_aux(rb); | 451 | rb_free_aux(rb); |
| 393 | ring_buffer_put_async(rb); | 452 | ring_buffer_put(rb); |
| 394 | } | 453 | } |
| 395 | 454 | ||
| 396 | /* | 455 | /* |
| @@ -471,6 +530,14 @@ static void __rb_free_aux(struct ring_buffer *rb) · 74 unmodified lines | |||
| 471 | { | 530 | { |
| 472 | int pg; | 531 | int pg; |
| 473 | 532 | ||
| 533 | /* | ||
| 534 | * Should never happen, the last reference should be dropped from | ||
| 535 | * perf_mmap_close() path, which first stops aux transactions (which | ||
| 536 | * in turn are the atomic holders of aux_refcount) and then does the | ||
| 537 | * last rb_free_aux(). | ||
| 538 | */ | ||
| 539 | WARN_ON_ONCE(in_atomic()); | ||
| 540 | |||
| 474 | if (rb->aux_priv) { | 541 | if (rb->aux_priv) { |
| 475 | rb->free_aux(rb->aux_priv); | 542 | rb->free_aux(rb->aux_priv); |
| 476 | rb->free_aux = NULL; | 543 | rb->free_aux = NULL; |
| @@ -582,18 +649,7 @@ out: · 105 unmodified lines | |||
| 582 | void rb_free_aux(struct ring_buffer *rb) | 649 | void rb_free_aux(struct ring_buffer *rb) |
| 583 | { | 650 | { |
| 584 | if (atomic_dec_and_test(&rb->aux_refcount)) | 651 | if (atomic_dec_and_test(&rb->aux_refcount)) |
| 585 | irq_work_queue(&rb->irq_work); | ||
| 586 | } | ||
| 587 | |||
| 588 | static void rb_irq_work(struct irq_work *work) | ||
| 589 | { | ||
| 590 | struct ring_buffer *rb = container_of(work, struct ring_buffer, irq_work); | ||
| 591 | |||
| 592 | if (!atomic_read(&rb->aux_refcount)) | ||
| 593 | __rb_free_aux(rb); | 652 | __rb_free_aux(rb); |
| 594 | |||
| 595 | if (rb->rcu_head.next == (void *)rb) | ||
| 596 | call_rcu(&rb->rcu_head, rb_free_rcu); | ||
| 597 | } | 653 | } |
| 598 | 654 | ||
| 599 | #ifndef CONFIG_PERF_USE_VMALLOC | 655 | #ifndef CONFIG_PERF_USE_VMALLOC |
| @@ -130,6 +130,9 @@ static int one_thousand = 1000; · 129 unmodified lines | |||
| 130 | #ifdef CONFIG_PRINTK | 130 | #ifdef CONFIG_PRINTK |
| 131 | static int ten_thousand = 10000; | 131 | static int ten_thousand = 10000; |
| 132 | #endif | 132 | #endif |
| 133 | #ifdef CONFIG_PERF_EVENTS | ||
| 134 | static int six_hundred_forty_kb = 640 * 1024; | ||
| 135 | #endif | ||
| 133 | 136 | ||
| 134 | /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ | 137 | /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ |
| 135 | static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; | 138 | static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; |
| @@ -1144,6 +1147,15 @@ static struct ctl_table kern_table[] = { · 1008 unmodified lines | |||
| 1144 | .extra1 = &zero, | 1147 | .extra1 = &zero, |
| 1145 | .extra2 = &one_hundred, | 1148 | .extra2 = &one_hundred, |
| 1146 | }, | 1149 | }, |
| 1150 | { | ||
| 1151 | .procname = "perf_event_max_stack", | ||
| 1152 | .data = NULL, /* filled in by handler */ | ||
| 1153 | .maxlen = sizeof(sysctl_perf_event_max_stack), | ||
| 1154 | .mode = 0644, | ||
| 1155 | .proc_handler = perf_event_max_stack_handler, | ||
| 1156 | .extra1 = &zero, | ||
| 1157 | .extra2 = &six_hundred_forty_kb, | ||
| 1158 | }, | ||
| 1147 | #endif | 1159 | #endif |
| 1148 | #ifdef CONFIG_KMEMCHECK | 1160 | #ifdef CONFIG_KMEMCHECK |
| 1149 | { | 1161 | { |
| @@ -47,6 +47,9 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event, · 46 unmodified lines | |||
| 47 | if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) | 47 | if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) |
| 48 | return -EPERM; | 48 | return -EPERM; |
| 49 | 49 | ||
| 50 | if (!is_sampling_event(p_event)) | ||
| 51 | return 0; | ||
| 52 | |||
| 50 | /* | 53 | /* |
| 51 | * We don't allow user space callchains for function trace | 54 | * We don't allow user space callchains for function trace |
| 52 | * event, due to issues with page faults while tracing page | 55 | * event, due to issues with page faults while tracing page |
| @@ -137,7 +137,8 @@ libsubcmd_clean: · 136 unmodified lines | |||
| 137 | $(call descend,lib/subcmd,clean) | 137 | $(call descend,lib/subcmd,clean) |
| 138 | 138 | ||
| 139 | perf_clean: | 139 | perf_clean: |
| 140 | $(call descend,$(@:_clean=),clean) | 140 | $(Q)mkdir -p $(PERF_O) . |
| 141 | $(Q)$(MAKE) --no-print-directory -C perf O=$(PERF_O) subdir= clean | ||
| 141 | 142 | ||
| 142 | selftests_clean: | 143 | selftests_clean: |
| 143 | $(call descend,testing/$(@:_clean=),clean) | 144 | $(call descend,testing/$(@:_clean=),clean) |
| @@ -49,6 +49,10 @@ FEATURE_TESTS_BASIC := \ · 48 unmodified lines | |||
| 49 | libslang \ | 49 | libslang \ |
| 50 | libcrypto \ | 50 | libcrypto \ |
| 51 | libunwind \ | 51 | libunwind \ |
| 52 | libunwind-x86 \ | ||
| 53 | libunwind-x86_64 \ | ||
| 54 | libunwind-arm \ | ||
| 55 | libunwind-aarch64 \ | ||
| 52 | pthread-attr-setaffinity-np \ | 56 | pthread-attr-setaffinity-np \ |
| 53 | stackprotector-all \ | 57 | stackprotector-all \ |
| 54 | timerfd \ | 58 | timerfd \ |
| @@ -69,7 +73,9 @@ FEATURE_TESTS_EXTRA := \ · 14 unmodified lines | |||
| 69 | libbabeltrace \ | 73 | libbabeltrace \ |
| 70 | liberty \ | 74 | liberty \ |
| 71 | liberty-z \ | 75 | liberty-z \ |
| 72 | libunwind-debug-frame | 76 | libunwind-debug-frame \ |
| 77 | libunwind-debug-frame-arm \ | ||
| 78 | libunwind-debug-frame-aarch64 | ||
| 73 | 79 | ||
| 74 | FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC) | 80 | FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC) |
| 75 | 81 | ||
| @@ -27,6 +27,12 @@ FILES= \ · 26 unmodified lines | |||
| 27 | test-libcrypto.bin \ | 27 | test-libcrypto.bin \ |
| 28 | test-libunwind.bin \ | 28 | test-libunwind.bin \ |
| 29 | test-libunwind-debug-frame.bin \ | 29 | test-libunwind-debug-frame.bin \ |
| 30 | test-libunwind-x86.bin \ | ||
| 31 | test-libunwind-x86_64.bin \ | ||
| 32 | test-libunwind-arm.bin \ | ||
| 33 | test-libunwind-aarch64.bin \ | ||
| 34 | test-libunwind-debug-frame-arm.bin \ | ||
| 35 | test-libunwind-debug-frame-aarch64.bin \ | ||
| 30 | test-pthread-attr-setaffinity-np.bin \ | 36 | test-pthread-attr-setaffinity-np.bin \ |
| 31 | test-stackprotector-all.bin \ | 37 | test-stackprotector-all.bin \ |
| 32 | test-timerfd.bin \ | 38 | test-timerfd.bin \ |
| @@ -103,6 +109,23 @@ $(OUTPUT)test-libunwind.bin: · 70 unmodified lines | |||
| 103 | 109 | ||
| 104 | $(OUTPUT)test-libunwind-debug-frame.bin: | 110 | $(OUTPUT)test-libunwind-debug-frame.bin: |
| 105 | $(BUILD) -lelf | 111 | $(BUILD) -lelf |
| 112 | $(OUTPUT)test-libunwind-x86.bin: | ||
| 113 | $(BUILD) -lelf -lunwind-x86 | ||
| 114 | |||
| 115 | $(OUTPUT)test-libunwind-x86_64.bin: | ||
| 116 | $(BUILD) -lelf -lunwind-x86_64 | ||
| 117 | |||
| 118 | $(OUTPUT)test-libunwind-arm.bin: | ||
| 119 | $(BUILD) -lelf -lunwind-arm | ||
| 120 | |||
| 121 | $(OUTPUT)test-libunwind-aarch64.bin: | ||
| 122 | $(BUILD) -lelf -lunwind-aarch64 | ||
| 123 | |||
| 124 | $(OUTPUT)test-libunwind-debug-frame-arm.bin: | ||
| 125 | $(BUILD) -lelf -lunwind-arm | ||
| 126 | |||
| 127 | $(OUTPUT)test-libunwind-debug-frame-aarch64.bin: | ||
| 128 | $(BUILD) -lelf -lunwind-aarch64 | ||
| 106 | 129 | ||
| 107 | $(OUTPUT)test-libaudit.bin: | 130 | $(OUTPUT)test-libaudit.bin: |
| 108 | $(BUILD) -laudit | 131 | $(BUILD) -laudit |
| @@ -27,10 +27,9 @@ int main(void) · 26 unmodified lines | |||
| 27 | attr.log_level = 0; | 27 | attr.log_level = 0; |
| 28 | attr.kern_version = 0; | 28 | attr.kern_version = 0; |
| 29 | 29 | ||
| 30 | attr = attr; | ||
| 31 | /* | 30 | /* |
| 32 | * Test existence of __NR_bpf and BPF_PROG_LOAD. | 31 | * Test existence of __NR_bpf and BPF_PROG_LOAD. |
| 33 | * This call should fail if we run the testcase. | 32 | * This call should fail if we run the testcase. |
| 34 | */ | 33 | */ |
| 35 | return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr)); | 34 | return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); |
| 36 | } | 35 | } |
| @@ -0,0 +1,26 @@ | |||
| 1 | #include <libunwind-aarch64.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | |||
| 4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
| 5 | unw_word_t ip, | ||
| 6 | unw_dyn_info_t *di, | ||
| 7 | unw_proc_info_t *pi, | ||
| 8 | int need_unwind_info, void *arg); | ||
| 9 | |||
| 10 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
| 11 | |||
| 12 | static unw_accessors_t accessors; | ||
| 13 | |||
| 14 | int main(void) | ||
| 15 | { | ||
| 16 | unw_addr_space_t addr_space; | ||
| 17 | |||
| 18 | addr_space = unw_create_addr_space(&accessors, 0); | ||
| 19 | if (addr_space) | ||
| 20 | return 0; | ||
| 21 | |||
| 22 | unw_init_remote(NULL, addr_space, NULL); | ||
| 23 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
| 24 | |||
| 25 | return 0; | ||
| 26 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | #include <libunwind-arm.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | |||
| 4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
| 5 | unw_word_t ip, | ||
| 6 | unw_dyn_info_t *di, | ||
| 7 | unw_proc_info_t *pi, | ||
| 8 | int need_unwind_info, void *arg); | ||
| 9 | |||
| 10 | |||
| 11 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
| 12 | |||
| 13 | static unw_accessors_t accessors; | ||
| 14 | |||
| 15 | int main(void) | ||
| 16 | { | ||
| 17 | unw_addr_space_t addr_space; | ||
| 18 | |||
| 19 | addr_space = unw_create_addr_space(&accessors, 0); | ||
| 20 | if (addr_space) | ||
| 21 | return 0; | ||
| 22 | |||
| 23 | unw_init_remote(NULL, addr_space, NULL); | ||
| 24 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
| 25 | |||
| 26 | return 0; | ||
| 27 | } | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include <libunwind-aarch64.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | |||
| 4 | extern int | ||
| 5 | UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, | ||
| 6 | unw_word_t ip, unw_word_t segbase, | ||
| 7 | const char *obj_name, unw_word_t start, | ||
| 8 | unw_word_t end); | ||
| 9 | |||
| 10 | #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) | ||
| 11 | |||
| 12 | int main(void) | ||
| 13 | { | ||
| 14 | dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); | ||
| 15 | return 0; | ||
| 16 | } | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include <libunwind-arm.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | |||
| 4 | extern int | ||
| 5 | UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, | ||
| 6 | unw_word_t ip, unw_word_t segbase, | ||
| 7 | const char *obj_name, unw_word_t start, | ||
| 8 | unw_word_t end); | ||
| 9 | |||
| 10 | #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) | ||
| 11 | |||
| 12 | int main(void) | ||
| 13 | { | ||
| 14 | dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); | ||
| 15 | return 0; | ||
| 16 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | #include <libunwind-x86.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | |||
| 4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
| 5 | unw_word_t ip, | ||
| 6 | unw_dyn_info_t *di, | ||
| 7 | unw_proc_info_t *pi, | ||
| 8 | int need_unwind_info, void *arg); | ||
| 9 | |||
| 10 | |||
| 11 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
| 12 | |||
| 13 | static unw_accessors_t accessors; | ||
| 14 | |||
| 15 | int main(void) | ||
| 16 | { | ||
| 17 | unw_addr_space_t addr_space; | ||
| 18 | |||
| 19 | addr_space = unw_create_addr_space(&accessors, 0); | ||
| 20 | if (addr_space) | ||
| 21 | return 0; | ||
| 22 | |||
| 23 | unw_init_remote(NULL, addr_space, NULL); | ||
| 24 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
| 25 | |||
| 26 | return 0; | ||
| 27 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | #include <libunwind-x86_64.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | |||
| 4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
| 5 | unw_word_t ip, | ||
| 6 | unw_dyn_info_t *di, | ||
| 7 | unw_proc_info_t *pi, | ||
| 8 | int need_unwind_info, void *arg); | ||
| 9 | |||
| 10 | |||
| 11 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
| 12 | |||
| 13 | static unw_accessors_t accessors; | ||
| 14 | |||
| 15 | int main(void) | ||
| 16 | { | ||
| 17 | unw_addr_space_t addr_space; | ||
| 18 | |||
| 19 | addr_space = unw_create_addr_space(&accessors, 0); | ||
| 20 | if (addr_space) | ||
| 21 | return 0; | ||
| 22 | |||
| 23 | unw_init_remote(NULL, addr_space, NULL); | ||
| 24 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
| 25 | |||
| 26 | return 0; | ||
| 27 | } | ||
| @@ -351,6 +351,19 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) · 350 unmodified lines | |||
| 351 | return err; | 351 | return err; |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | int procfs__read_str(const char *entry, char **buf, size_t *sizep) | ||
| 355 | { | ||
| 356 | char path[PATH_MAX]; | ||
| 357 | const char *procfs = procfs__mountpoint(); | ||
| 358 | |||
| 359 | if (!procfs) | ||
| 360 | return -1; | ||
| 361 | |||
| 362 | snprintf(path, sizeof(path), "%s/%s", procfs, entry); | ||
| 363 | |||
| 364 | return filename__read_str(path, buf, sizep); | ||
| 365 | } | ||
| 366 | |||
| 354 | int sysfs__read_ull(const char *entry, unsigned long long *value) | 367 | int sysfs__read_ull(const char *entry, unsigned long long *value) |
| 355 | { | 368 | { |
| 356 | char path[PATH_MAX]; | 369 | char path[PATH_MAX]; |
| @@ -29,6 +29,8 @@ int filename__read_int(const char *filename, int *value); · 28 unmodified lines | |||
| 29 | int filename__read_ull(const char *filename, unsigned long long *value); | 29 | int filename__read_ull(const char *filename, unsigned long long *value); |
| 30 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | 30 | int filename__read_str(const char *filename, char **buf, size_t *sizep); |
| 31 | 31 | ||
| 32 | int procfs__read_str(const char *entry, char **buf, size_t *sizep); | ||
| 33 | |||
| 32 | int sysctl__read_int(const char *sysctl, int *value); | 34 | int sysctl__read_int(const char *sysctl, int *value); |
| 33 | int sysfs__read_int(const char *entry, int *value); | 35 | int sysfs__read_int(const char *entry, int *value); |
| 34 | int sysfs__read_ull(const char *entry, unsigned long long *value); | 36 | int sysfs__read_ull(const char *entry, unsigned long long *value); |
| @@ -672,6 +672,7 @@ The letters are: · 671 unmodified lines | |||
| 672 | d create a debug log | 672 | d create a debug log |
| 673 | g synthesize a call chain (use with i or x) | 673 | g synthesize a call chain (use with i or x) |
| 674 | l synthesize last branch entries (use with i or x) | 674 | l synthesize last branch entries (use with i or x) |
| 675 | s skip initial number of events | ||
| 675 | 676 | ||
| 676 | "Instructions" events look like they were recorded by "perf record -e | 677 | "Instructions" events look like they were recorded by "perf record -e |
| 677 | instructions". | 678 | instructions". |
| @@ -730,6 +731,12 @@ from one sample to the next. · 52 unmodified lines | |||
| 730 | 731 | ||
| 731 | To disable trace decoding entirely, use the option --no-itrace. | 732 | To disable trace decoding entirely, use the option --no-itrace. |
| 732 | 733 | ||
| 734 | It is also possible to skip events generated (instructions, branches, transactions) | ||
| 735 | at the beginning. This is useful to ignore initialization code. | ||
| 736 | |||
| 737 | --itrace=i0nss1000000 | ||
| 738 | |||
| 739 | skips the first million instructions. | ||
| 733 | 740 | ||
| 734 | dump option | 741 | dump option |
| 735 | ----------- | 742 | ----------- |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | d create a debug log | 7 | d create a debug log |
| 8 | g synthesize a call chain (use with i or x) | 8 | g synthesize a call chain (use with i or x) |
| 9 | l synthesize last branch entries (use with i or x) | 9 | l synthesize last branch entries (use with i or x) |
| 10 | s skip initial number of events | ||
| 10 | 11 | ||
| 11 | The default is all events i.e. the same as --itrace=ibxe | 12 | The default is all events i.e. the same as --itrace=ibxe |
| 12 | 13 | ||
| @@ -24,3 +25,10 @@ · 11 unmodified lines | |||
| 24 | 25 | ||
| 25 | Also the number of last branch entries (default 64, max. 1024) for | 26 | Also the number of last branch entries (default 64, max. 1024) for |
| 26 | instructions or transactions events can be specified. | 27 | instructions or transactions events can be specified. |
| 28 | |||
| 29 | It is also possible to skip events generated (instructions, branches, transactions) | ||
| 30 | at the beginning. This is useful to ignore initialization code. | ||
| 31 | |||
| 32 | --itrace=i0nss1000000 | ||
| 33 | |||
| 34 | skips the first million instructions. | ||
| @@ -33,7 +33,7 @@ OPTIONS · 32 unmodified lines | |||
| 33 | 33 | ||
| 34 | -f:: | 34 | -f:: |
| 35 | --force:: | 35 | --force:: |
| 36 | Don't complain, do it. | 36 | Don't do ownership validation. |
| 37 | 37 | ||
| 38 | -v:: | 38 | -v:: |
| 39 | --verbose:: | 39 | --verbose:: |
| @@ -75,7 +75,7 @@ OPTIONS · 74 unmodified lines | |||
| 75 | 75 | ||
| 76 | -f:: | 76 | -f:: |
| 77 | --force:: | 77 | --force:: |
| 78 | Don't complain, do it. | 78 | Don't do ownership validation. |
| 79 | 79 | ||
| 80 | --symfs=<directory>:: | 80 | --symfs=<directory>:: |
| 81 | Look for files with symbols relative to this directory. | 81 | Look for files with symbols relative to this directory. |
| @@ -93,6 +93,67 @@ raw encoding of 0x1A8 can be used: · 92 unmodified lines | |||
| 93 | You should refer to the processor specific documentation for getting these | 93 | You should refer to the processor specific documentation for getting these |
| 94 | details. Some of them are referenced in the SEE ALSO section below. | 94 | details. Some of them are referenced in the SEE ALSO section below. |
| 95 | 95 | ||
| 96 | ARBITRARY PMUS | ||
| 97 | -------------- | ||
| 98 | |||
| 99 | perf also supports an extended syntax for specifying raw parameters | ||
| 100 | to PMUs. Using this typically requires looking up the specific event | ||
| 101 | in the CPU vendor specific documentation. | ||
| 102 | |||
| 103 | The available PMUs and their raw parameters can be listed with | ||
| 104 | |||
| 105 | ls /sys/devices/*/format | ||
| 106 | |||
| 107 | For example the raw event "LSD.UOPS" core pmu event above could | ||
| 108 | be specified as | ||
| 109 | |||
| 110 | perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=1/ ... | ||
| 111 | |||
| 112 | PER SOCKET PMUS | ||
| 113 | --------------- | ||
| 114 | |||
| 115 | Some PMUs are not associated with a core, but with a whole CPU socket. | ||
| 116 | Events on these PMUs generally cannot be sampled, but only counted globally | ||
| 117 | with perf stat -a. They can be bound to one logical CPU, but will measure | ||
| 118 | all the CPUs in the same socket. | ||
| 119 | |||
| 120 | This example measures memory bandwidth every second | ||
| 121 | on the first memory controller on socket 0 of a Intel Xeon system | ||
| 122 | |||
| 123 | perf stat -C 0 -a uncore_imc_0/cas_count_read/,uncore_imc_0/cas_count_write/ -I 1000 ... | ||
| 124 | |||
| 125 | Each memory controller has its own PMU. Measuring the complete system | ||
| 126 | bandwidth would require specifying all imc PMUs (see perf list output), | ||
| 127 | and adding the values together. | ||
| 128 | |||
| 129 | This example measures the combined core power every second | ||
| 130 | |||
| 131 | perf stat -I 1000 -e power/energy-cores/ -a | ||
| 132 | |||
| 133 | ACCESS RESTRICTIONS | ||
| 134 | ------------------- | ||
| 135 | |||
| 136 | For non root users generally only context switched PMU events are available. | ||
| 137 | This is normally only the events in the cpu PMU, the predefined events | ||
| 138 | like cycles and instructions and some software events. | ||
| 139 | |||
| 140 | Other PMUs and global measurements are normally root only. | ||
| 141 | Some event qualifiers, such as "any", are also root only. | ||
| 142 | |||
| 143 | This can be overriden by setting the kernel.perf_event_paranoid | ||
| 144 | sysctl to -1, which allows non root to use these events. | ||
| 145 | |||
| 146 | For accessing trace point events perf needs to have read access to | ||
| 147 | /sys/kernel/debug/tracing, even when perf_event_paranoid is in a relaxed | ||
| 148 | setting. | ||
| 149 | |||
| 150 | TRACING | ||
| 151 | ------- | ||
| 152 | |||
| 153 | Some PMUs control advanced hardware tracing capabilities, such as Intel PT, | ||
| 154 | that allows low overhead execution tracing. These are described in a separate | ||
| 155 | intel-pt.txt document. | ||
| 156 | |||
| 96 | PARAMETERIZED EVENTS | 157 | PARAMETERIZED EVENTS |
| 97 | -------------------- | 158 | -------------------- |
| 98 | 159 | ||
| @@ -106,6 +167,50 @@ also be supplied. For example: · 7 unmodified lines | |||
| 106 | 167 | ||
| 107 | perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... | 168 | perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... |
| 108 | 169 | ||
| 170 | EVENT GROUPS | ||
| 171 | ------------ | ||
| 172 | |||
| 173 | Perf supports time based multiplexing of events, when the number of events | ||
| 174 | active exceeds the number of hardware performance counters. Multiplexing | ||
| 175 | can cause measurement errors when the workload changes its execution | ||
| 176 | profile. | ||
| 177 | |||
| 178 | When metrics are computed using formulas from event counts, it is useful to | ||
| 179 | ensure some events are always measured together as a group to minimize multiplexing | ||
| 180 | errors. Event groups can be specified using { }. | ||
| 181 | |||
| 182 | perf stat -e '{instructions,cycles}' ... | ||
| 183 | |||
| 184 | The number of available performance counters depend on the CPU. A group | ||
| 185 | cannot contain more events than available counters. | ||
| 186 | For example Intel Core CPUs typically have four generic performance counters | ||
| 187 | for the core, plus three fixed counters for instructions, cycles and | ||
| 188 | ref-cycles. Some special events have restrictions on which counter they | ||
| 189 | can schedule, and may not support multiple instances in a single group. | ||
| 190 | When too many events are specified in the group none of them will not | ||
| 191 | be measured. | ||
| 192 | |||
| 193 | Globally pinned events can limit the number of counters available for | ||
| 194 | other groups. On x86 systems, the NMI watchdog pins a counter by default. | ||
| 195 | The nmi watchdog can be disabled as root with | ||
| 196 | |||
| 197 | echo 0 > /proc/sys/kernel/nmi_watchdog | ||
| 198 | |||
| 199 | Events from multiple different PMUs cannot be mixed in a group, with | ||
| 200 | some exceptions for software events. | ||
| 201 | |||
| 202 | LEADER SAMPLING | ||
| 203 | --------------- | ||
| 204 | |||
| 205 | perf also supports group leader sampling using the :S specifier. | ||
| 206 | |||
| 207 | perf record -e '{cycles,instructions}:S' ... | ||
| 208 | perf report --group | ||
| 209 | |||
| 210 | Normally all events in a event group sample, but with :S only | ||
| 211 | the first event (the leader) samples, and it only reads the values of the | ||
| 212 | other events in the group. | ||
| 213 | |||
| 109 | OPTIONS | 214 | OPTIONS |
| 110 | ------- | 215 | ------- |
| 111 | 216 | ||
| @@ -143,5 +248,5 @@ SEE ALSO · 31 unmodified lines | |||
| 143 | -------- | 248 | -------- |
| 144 | linkperf:perf-stat[1], linkperf:perf-top[1], | 249 | linkperf:perf-stat[1], linkperf:perf-top[1], |
| 145 | linkperf:perf-record[1], | 250 | linkperf:perf-record[1], |
| 146 | http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide], | 251 | http://www.intel.com/sdm/[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide], |
| 147 | http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming] | 252 | http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming] |
| @@ -48,6 +48,14 @@ OPTIONS · 47 unmodified lines | |||
| 48 | option can be passed in record mode. It will be interpreted the same way as perf | 48 | option can be passed in record mode. It will be interpreted the same way as perf |
| 49 | record. | 49 | record. |
| 50 | 50 | ||
| 51 | -K:: | ||
| 52 | --all-kernel:: | ||
| 53 | Configure all used events to run in kernel space. | ||
| 54 | |||
| 55 | -U:: | ||
| 56 | --all-user:: | ||
| 57 | Configure all used events to run in user space. | ||
| 58 | |||
| 51 | SEE ALSO | 59 | SEE ALSO |
| 52 | -------- | 60 | -------- |
| 53 | linkperf:perf-record[1], linkperf:perf-report[1] | 61 | linkperf:perf-record[1], linkperf:perf-report[1] |
| @@ -347,6 +347,19 @@ Configure all used events to run in kernel space. · 346 unmodified lines | |||
| 347 | --all-user:: | 347 | --all-user:: |
| 348 | Configure all used events to run in user space. | 348 | Configure all used events to run in user space. |
| 349 | 349 | ||
| 350 | --timestamp-filename | ||
| 351 | Append timestamp to output file name. | ||
| 352 | |||
| 353 | --switch-output:: | ||
| 354 | Generate multiple perf.data files, timestamp prefixed, switching to a new one | ||
| 355 | when receiving a SIGUSR2. | ||
| 356 | |||
| 357 | A possible use case is to, given an external event, slice the perf.data file | ||
| 358 | that gets then processed, possibly via a perf script, to decide if that | ||
| 359 | particular perf.data snapshot should be kept or not. | ||
| 360 | |||
| 361 | Implies --timestamp-filename, --no-buildid and --no-buildid-cache. | ||
| 362 | |||
| 350 | SEE ALSO | 363 | SEE ALSO |
| 351 | -------- | 364 | -------- |
| 352 | linkperf:perf-stat[1], linkperf:perf-list[1] | 365 | linkperf:perf-stat[1], linkperf:perf-list[1] |
| @@ -248,7 +248,7 @@ OPTIONS · 247 unmodified lines | |||
| 248 | Note that when using the --itrace option the synthesized callchain size | 248 | Note that when using the --itrace option the synthesized callchain size |
| 249 | will override this value if the synthesized callchain size is bigger. | 249 | will override this value if the synthesized callchain size is bigger. |
| 250 | 250 | ||
| 251 | Default: 127 | 251 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
| 252 | 252 | ||
| 253 | -G:: | 253 | -G:: |
| 254 | --inverted:: | 254 | --inverted:: |
| @@ -285,7 +285,7 @@ OPTIONS · 30 unmodified lines | |||
| 285 | 285 | ||
| 286 | -f:: | 286 | -f:: |
| 287 | --force:: | 287 | --force:: |
| 288 | Don't complain, do it. | 288 | Don't do ownership validation. |
| 289 | 289 | ||
| 290 | --symfs=<directory>:: | 290 | --symfs=<directory>:: |
| 291 | Look for files with symbols relative to this directory. | 291 | Look for files with symbols relative to this directory. |
| @@ -50,6 +50,22 @@ OPTIONS · 49 unmodified lines | |||
| 50 | --dump-raw-trace=:: | 50 | --dump-raw-trace=:: |
| 51 | Display verbose dump of the sched data. | 51 | Display verbose dump of the sched data. |
| 52 | 52 | ||
| 53 | OPTIONS for 'perf sched map' | ||
| 54 | ---------------------------- | ||
| 55 | |||
| 56 | --compact:: | ||
| 57 | Show only CPUs with activity. Helps visualizing on high core | ||
| 58 | count systems. | ||
| 59 | |||
| 60 | --cpus:: | ||
| 61 | Show just entries with activities for the given CPUs. | ||
| 62 | |||
| 63 | --color-cpus:: | ||
| 64 | Highlight the given cpus. | ||
| 65 | |||
| 66 | --color-pids:: | ||
| 67 | Highlight the given pids. | ||
| 68 | |||
| 53 | SEE ALSO | 69 | SEE ALSO |
| 54 | -------- | 70 | -------- |
| 55 | linkperf:perf-record[1] | 71 | linkperf:perf-record[1] |
| @@ -259,9 +259,23 @@ include::itrace.txt[] · 258 unmodified lines | |||
| 259 | --full-source-path:: | 259 | --full-source-path:: |
| 260 | Show the full path for source files for srcline output. | 260 | Show the full path for source files for srcline output. |
| 261 | 261 | ||
| 262 | --max-stack:: | ||
| 263 | Set the stack depth limit when parsing the callchain, anything | ||
| 264 | beyond the specified depth will be ignored. This is a trade-off | ||
| 265 | between information loss and faster processing especially for | ||
| 266 | workloads that can have a very long callchain stack. | ||
| 267 | Note that when using the --itrace option the synthesized callchain size | ||
| 268 | will override this value if the synthesized callchain size is bigger. | ||
| 269 | |||
| 270 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. | ||
| 271 | |||
| 262 | --ns:: | 272 | --ns:: |
| 263 | Use 9 decimal places when displaying time (i.e. show the nanoseconds) | 273 | Use 9 decimal places when displaying time (i.e. show the nanoseconds) |
| 264 | 274 | ||
| 275 | -f:: | ||
| 276 | --force:: | ||
| 277 | Don't do ownership validation. | ||
| 278 | |||
| 265 | SEE ALSO | 279 | SEE ALSO |
| 266 | -------- | 280 | -------- |
| 267 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 281 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
| @@ -177,7 +177,7 @@ Default is to monitor all CPUS. · 176 unmodified lines | |||
| 177 | between information loss and faster processing especially for | 177 | between information loss and faster processing especially for |
| 178 | workloads that can have a very long callchain stack. | 178 | workloads that can have a very long callchain stack. |
| 179 | 179 | ||
| 180 | Default: 127 | 180 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
| 181 | 181 | ||
| 182 | --ignore-callees=<regex>:: | 182 | --ignore-callees=<regex>:: |
| 183 | Ignore callees of the function(s) matching the given regex. | 183 | Ignore callees of the function(s) matching the given regex. |
| @@ -117,9 +117,41 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. · 116 unmodified lines | |||
| 117 | --syscalls:: | 117 | --syscalls:: |
| 118 | Trace system calls. This options is enabled by default. | 118 | Trace system calls. This options is enabled by default. |
| 119 | 119 | ||
| 120 | --call-graph [mode,type,min[,limit],order[,key][,branch]]:: | ||
| 121 | Setup and enable call-graph (stack chain/backtrace) recording. | ||
| 122 | See `--call-graph` section in perf-record and perf-report | ||
| 123 | man pages for details. The ones that are most useful in 'perf trace' | ||
| 124 | are 'dwarf' and 'lbr', where available, try: 'perf trace --call-graph dwarf'. | ||
| 125 | |||
| 126 | Using this will, for the root user, bump the value of --mmap-pages to 4 | ||
| 127 | times the maximum for non-root users, based on the kernel.perf_event_mlock_kb | ||
| 128 | sysctl. This is done only if the user doesn't specify a --mmap-pages value. | ||
| 129 | |||
| 130 | --kernel-syscall-graph:: | ||
| 131 | Show the kernel callchains on the syscall exit path. | ||
| 132 | |||
| 120 | --event:: | 133 | --event:: |
| 121 | Trace other events, see 'perf list' for a complete list. | 134 | Trace other events, see 'perf list' for a complete list. |
| 122 | 135 | ||
| 136 | --max-stack:: | ||
| 137 | Set the stack depth limit when parsing the callchain, anything | ||
| 138 | beyond the specified depth will be ignored. Note that at this point | ||
| 139 | this is just about the presentation part, i.e. the kernel is still | ||
| 140 | not limiting, the overhead of callchains needs to be set via the | ||
| 141 | knobs in --call-graph dwarf. | ||
| 142 | |||
| 143 | Implies '--call-graph dwarf' when --call-graph not present on the | ||
| 144 | command line, on systems where DWARF unwinding was built in. | ||
| 145 | |||
| 146 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. | ||
| 147 | |||
| 148 | --min-stack:: | ||
| 149 | Set the stack depth limit when parsing the callchain, anything | ||
| 150 | below the specified depth will be ignored. Disabled by default. | ||
| 151 | |||
| 152 | Implies '--call-graph dwarf' when --call-graph not present on the | ||
| 153 | command line, on systems where DWARF unwinding was built in. | ||
| 154 | |||
| 123 | --proc-map-timeout:: | 155 | --proc-map-timeout:: |
| 124 | When processing pre-existing threads /proc/XXX/mmap, it may take a long time, | 156 | When processing pre-existing threads /proc/XXX/mmap, it may take a long time, |
| 125 | because the file may be huge. A time out is needed in such cases. | 157 | because the file may be huge. A time out is needed in such cases. |
| @@ -183,6 +183,11 @@ endif · 182 unmodified lines | |||
| 183 | include config/Makefile | 183 | include config/Makefile |
| 184 | endif | 184 | endif |
| 185 | 185 | ||
| 186 | ifeq ($(config),0) | ||
| 187 | include $(srctree)/tools/scripts/Makefile.arch | ||
| 188 | -include arch/$(ARCH)/Makefile | ||
| 189 | endif | ||
| 190 | |||
| 186 | # The FEATURE_DUMP_EXPORT holds location of the actual | 191 | # The FEATURE_DUMP_EXPORT holds location of the actual |
| 187 | # FEATURE_DUMP file to be used to bypass feature detection | 192 | # FEATURE_DUMP file to be used to bypass feature detection |
| 188 | # (for bpf or any other subproject) | 193 | # (for bpf or any other subproject) |
| @@ -297,8 +302,6 @@ endif · 108 unmodified lines | |||
| 297 | # because maintaining the nesting to match is a pain. If | 302 | # because maintaining the nesting to match is a pain. If |
| 298 | # we had "elif" things would have been much nicer... | 303 | # we had "elif" things would have been much nicer... |
| 299 | 304 | ||
| 300 | -include arch/$(ARCH)/Makefile | ||
| 301 | |||
| 302 | ifneq ($(OUTPUT),) | 305 | ifneq ($(OUTPUT),) |
| 303 | CFLAGS += -I$(OUTPUT) | 306 | CFLAGS += -I$(OUTPUT) |
| 304 | endif | 307 | endif |
| @@ -390,7 +393,7 @@ endif · 85 unmodified lines | |||
| 390 | __build-dir = $(subst $(OUTPUT),,$(dir $@)) | 393 | __build-dir = $(subst $(OUTPUT),,$(dir $@)) |
| 391 | build-dir = $(if $(__build-dir),$(__build-dir),.) | 394 | build-dir = $(if $(__build-dir),$(__build-dir),.) |
| 392 | 395 | ||
| 393 | prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep | 396 | prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep archheaders |
| 394 | 397 | ||
| 395 | $(OUTPUT)%.o: %.c prepare FORCE | 398 | $(OUTPUT)%.o: %.c prepare FORCE |
| 396 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 399 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
| @@ -430,7 +433,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) · 33 unmodified lines | |||
| 430 | 433 | ||
| 431 | LIBPERF_IN := $(OUTPUT)libperf-in.o | 434 | LIBPERF_IN := $(OUTPUT)libperf-in.o |
| 432 | 435 | ||
| 433 | $(LIBPERF_IN): fixdep FORCE | 436 | $(LIBPERF_IN): prepare fixdep FORCE |
| 434 | $(Q)$(MAKE) $(build)=libperf | 437 | $(Q)$(MAKE) $(build)=libperf |
| 435 | 438 | ||
| 436 | $(LIB_FILE): $(LIBPERF_IN) | 439 | $(LIB_FILE): $(LIBPERF_IN) |
| @@ -625,7 +628,7 @@ config-clean: · 188 unmodified lines | |||
| 625 | $(call QUIET_CLEAN, config) | 628 | $(call QUIET_CLEAN, config) |
| 626 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null | 629 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null |
| 627 | 630 | ||
| 628 | clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean | 631 | clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean |
| 629 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) | 632 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) |
| 630 | $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | 633 | $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete |
| 631 | $(Q)$(RM) $(OUTPUT).config-detected | 634 | $(Q)$(RM) $(OUTPUT).config-detected |
| @@ -662,5 +665,5 @@ FORCE: · 30 unmodified lines | |||
| 662 | .PHONY: all install clean config-clean strip install-gtk | 665 | .PHONY: all install clean config-clean strip install-gtk |
| 663 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell | 666 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell |
| 664 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare | 667 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare |
| 665 | .PHONY: libtraceevent_plugins | 668 | .PHONY: libtraceevent_plugins archheaders |
| 666 | 669 | ||
| @@ -3,4 +3,5 @@ PERF_HAVE_DWARF_REGS := 1 · 2 unmodified lines | |||
| 3 | endif | 3 | endif |
| 4 | 4 | ||
| 5 | HAVE_KVM_STAT_SUPPORT := 1 | 5 | HAVE_KVM_STAT_SUPPORT := 1 |
| 6 | PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 | ||
| 6 | PERF_HAVE_JITDUMP := 1 | 7 | PERF_HAVE_JITDUMP := 1 |
| @@ -10,19 +10,26 @@ · 9 unmodified lines | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <stddef.h> | 12 | #include <stddef.h> |
| 13 | #include <errno.h> | ||
| 14 | #include <string.h> | ||
| 13 | #include <dwarf-regs.h> | 15 | #include <dwarf-regs.h> |
| 14 | 16 | #include <linux/ptrace.h> | |
| 17 | #include <linux/kernel.h> | ||
| 18 | #include "util.h" | ||
| 15 | 19 | ||
| 16 | struct pt_regs_dwarfnum { | 20 | struct pt_regs_dwarfnum { |
| 17 | const char *name; | 21 | const char *name; |
| 18 | unsigned int dwarfnum; | 22 | unsigned int dwarfnum; |
| 23 | unsigned int ptregs_offset; | ||
| 19 | }; | 24 | }; |
| 20 | 25 | ||
| 21 | #define STR(s) #s | 26 | #define REG_DWARFNUM_NAME(r, num) \ |
| 22 | #define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} | 27 | {.name = STR(%)STR(r), .dwarfnum = num, \ |
| 23 | #define GPR_DWARFNUM_NAME(num) \ | 28 | .ptregs_offset = offsetof(struct pt_regs, r)} |
| 24 | {.name = STR(%gpr##num), .dwarfnum = num} | 29 | #define GPR_DWARFNUM_NAME(num) \ |
| 25 | #define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} | 30 | {.name = STR(%gpr##num), .dwarfnum = num, \ |
| 31 | .ptregs_offset = offsetof(struct pt_regs, gpr[num])} | ||
| 32 | #define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0, .ptregs_offset = 0} | ||
| 26 | 33 | ||
| 27 | /* | 34 | /* |
| 28 | * Reference: | 35 | * Reference: |
| @@ -61,12 +68,12 @@ static const struct pt_regs_dwarfnum regdwarfnum_table[] = { · 32 unmodified lines | |||
| 61 | GPR_DWARFNUM_NAME(29), | 68 | GPR_DWARFNUM_NAME(29), |
| 62 | GPR_DWARFNUM_NAME(30), | 69 | GPR_DWARFNUM_NAME(30), |
| 63 | GPR_DWARFNUM_NAME(31), | 70 | GPR_DWARFNUM_NAME(31), |
| 64 | REG_DWARFNUM_NAME("%msr", 66), | 71 | REG_DWARFNUM_NAME(msr, 66), |
| 65 | REG_DWARFNUM_NAME("%ctr", 109), | 72 | REG_DWARFNUM_NAME(ctr, 109), |
| 66 | REG_DWARFNUM_NAME("%link", 108), | 73 | REG_DWARFNUM_NAME(link, 108), |
| 67 | REG_DWARFNUM_NAME("%xer", 101), | 74 | REG_DWARFNUM_NAME(xer, 101), |
| 68 | REG_DWARFNUM_NAME("%dar", 119), | 75 | REG_DWARFNUM_NAME(dar, 119), |
| 69 | REG_DWARFNUM_NAME("%dsisr", 118), | 76 | REG_DWARFNUM_NAME(dsisr, 118), |
| 70 | REG_DWARFNUM_END, | 77 | REG_DWARFNUM_END, |
| 71 | }; | 78 | }; |
| 72 | 79 | ||
| @@ -86,3 +93,12 @@ const char *get_arch_regstr(unsigned int n) · 13 unmodified lines | |||
| 86 | return roff->name; | 93 | return roff->name; |
| 87 | return NULL; | 94 | return NULL; |
| 88 | } | 95 | } |
| 96 | |||
| 97 | int regs_query_register_offset(const char *name) | ||
| 98 | { | ||
| 99 | const struct pt_regs_dwarfnum *roff; | ||
| 100 | for (roff = regdwarfnum_table; roff->name != NULL; roff++) | ||
| 101 | if (!strcmp(roff->name, name)) | ||
| 102 | return roff->ptregs_offset; | ||
| 103 | return -EINVAL; | ||
| 104 | } | ||
| @@ -19,12 +19,6 @@ bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) · 18 unmodified lines | |||
| 19 | ehdr.e_type == ET_DYN; | 19 | ehdr.e_type == ET_DYN; |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | #if defined(_CALL_ELF) && _CALL_ELF == 2 | ||
| 23 | void arch__elf_sym_adjust(GElf_Sym *sym) | ||
| 24 | { | ||
| 25 | sym->st_value += PPC64_LOCAL_ENTRY_OFFSET(sym->st_other); | ||
| 26 | } | ||
| 27 | #endif | ||
| 28 | #endif | 22 | #endif |
| 29 | 23 | ||
| 30 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 | 24 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 |
| @@ -65,18 +59,45 @@ bool arch__prefers_symtab(void) · 34 unmodified lines | |||
| 65 | return true; | 59 | return true; |
| 66 | } | 60 | } |
| 67 | 61 | ||
| 62 | #ifdef HAVE_LIBELF_SUPPORT | ||
| 63 | void arch__sym_update(struct symbol *s, GElf_Sym *sym) | ||
| 64 | { | ||
| 65 | s->arch_sym = sym->st_other; | ||
| 66 | } | ||
| 67 | #endif | ||
| 68 | |||
| 68 | #define PPC64LE_LEP_OFFSET 8 | 69 | #define PPC64LE_LEP_OFFSET 8 |
| 69 | 70 | ||
| 70 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, | 71 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, |
| 71 | struct probe_trace_event *tev, struct map *map) | 72 | struct probe_trace_event *tev, struct map *map, |
| 73 | struct symbol *sym) | ||
| 72 | { | 74 | { |
| 75 | int lep_offset; | ||
| 76 | |||
| 73 | /* | 77 | /* |
| 74 | * ppc64 ABIv2 local entry point is currently always 2 instructions | 78 | * When probing at a function entry point, we normally always want the |
| 75 | * (8 bytes) after the global entry point. | 79 | * LEP since that catches calls to the function through both the GEP and |
| 80 | * the LEP. Hence, we would like to probe at an offset of 8 bytes if | ||
| 81 | * the user only specified the function entry. | ||
| 82 | * | ||
| 83 | * However, if the user specifies an offset, we fall back to using the | ||
| 84 | * GEP since all userspace applications (objdump/readelf) show function | ||
| 85 | * disassembly with offsets from the GEP. | ||
| 86 | * | ||
| 87 | * In addition, we shouldn't specify an offset for kretprobes. | ||
| 76 | */ | 88 | */ |
| 77 | if (!pev->uprobes && map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { | 89 | if (pev->point.offset || pev->point.retprobe || !map || !sym) |
| 78 | tev->point.address += PPC64LE_LEP_OFFSET; | 90 | return; |
| 91 | |||
| 92 | lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); | ||
| 93 | |||
| 94 | if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) | ||
| 79 | tev->point.offset += PPC64LE_LEP_OFFSET; | 95 | tev->point.offset += PPC64LE_LEP_OFFSET; |
| 96 | else if (lep_offset) { | ||
| 97 | if (pev->uprobes) | ||
| 98 | tev->point.address += lep_offset; | ||
| 99 | else | ||
| 100 | tev->point.offset += lep_offset; | ||
| 80 | } | 101 | } |
| 81 | } | 102 | } |
| 82 | #endif | 103 | #endif |
| @@ -4,3 +4,26 @@ endif · 3 unmodified lines | |||
| 4 | HAVE_KVM_STAT_SUPPORT := 1 | 4 | HAVE_KVM_STAT_SUPPORT := 1 |
| 5 | PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 | 5 | PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 |
| 6 | PERF_HAVE_JITDUMP := 1 | 6 | PERF_HAVE_JITDUMP := 1 |
| 7 | |||
| 8 | ### | ||
| 9 | # Syscall table generation | ||
| 10 | # | ||
| 11 | |||
| 12 | out := $(OUTPUT)arch/x86/include/generated/asm | ||
| 13 | header := $(out)/syscalls_64.c | ||
| 14 | sys := $(srctree)/tools/perf/arch/x86/entry/syscalls | ||
| 15 | systbl := $(sys)/syscalltbl.sh | ||
| 16 | |||
| 17 | # Create output directory if not already present | ||
| 18 | _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') | ||
| 19 | |||
| 20 | $(header): $(sys)/syscall_64.tbl $(systbl) | ||
| 21 | @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ | ||
| 22 | (diff -B arch/x86/entry/syscalls/syscall_64.tbl ../../arch/x86/entry/syscalls/syscall_64.tbl >/dev/null) \ | ||
| 23 | || echo "Warning: x86_64's syscall_64.tbl differs from kernel" >&2 )) || true | ||
| 24 | $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ | ||
| 25 | |||
| 26 | clean:: | ||
| 27 | $(call QUIET_CLEAN, x86) $(RM) $(header) | ||
| 28 | |||
| 29 | archheaders: $(header) | ||
| @@ -0,0 +1,376 @@ | |||
| 1 | # | ||
| 2 | # 64-bit system call numbers and entry vectors | ||
| 3 | # | ||
| 4 | # The format is: | ||
| 5 | # <number> <abi> <name> <entry point> | ||
| 6 | # | ||
| 7 | # The abi is "common", "64" or "x32" for this file. | ||
| 8 | # | ||
| 9 | 0 common read sys_read | ||
| 10 | 1 common write sys_write | ||
| 11 | 2 common open sys_open | ||
| 12 | 3 common close sys_close | ||
| 13 | 4 common stat sys_newstat | ||
| 14 | 5 common fstat sys_newfstat | ||
| 15 | 6 common lstat sys_newlstat | ||
| 16 | 7 common poll sys_poll | ||
| 17 | 8 common lseek sys_lseek | ||
| 18 | 9 common mmap sys_mmap | ||
| 19 | 10 common mprotect sys_mprotect | ||
| 20 | 11 common munmap sys_munmap | ||
| 21 | 12 common brk sys_brk | ||
| 22 | 13 64 rt_sigaction sys_rt_sigaction | ||
| 23 | 14 common rt_sigprocmask sys_rt_sigprocmask | ||
| 24 | 15 64 rt_sigreturn sys_rt_sigreturn/ptregs | ||
| 25 | 16 64 ioctl sys_ioctl | ||
| 26 | 17 common pread64 sys_pread64 | ||
| 27 | 18 common pwrite64 sys_pwrite64 | ||
| 28 | 19 64 readv sys_readv | ||
| 29 | 20 64 writev sys_writev | ||
| 30 | 21 common access sys_access | ||
| 31 | 22 common pipe sys_pipe | ||
| 32 | 23 common select sys_select | ||
| 33 | 24 common sched_yield sys_sched_yield | ||
| 34 | 25 common mremap sys_mremap | ||
| 35 | 26 common msync sys_msync | ||
| 36 | 27 common mincore sys_mincore | ||
| 37 | 28 common madvise sys_madvise | ||
| 38 | 29 common shmget sys_shmget | ||
| 39 | 30 common shmat sys_shmat | ||
| 40 | 31 common shmctl sys_shmctl | ||
| 41 | 32 common dup sys_dup | ||
| 42 | 33 common dup2 sys_dup2 | ||
| 43 | 34 common pause sys_pause | ||
| 44 | 35 common nanosleep sys_nanosleep | ||
| 45 | 36 common getitimer sys_getitimer | ||
| 46 | 37 common alarm sys_alarm | ||
| 47 | 38 common setitimer sys_setitimer | ||
| 48 | 39 common getpid sys_getpid | ||
| 49 | 40 common sendfile sys_sendfile64 | ||
| 50 | 41 common socket sys_socket | ||
| 51 | 42 common connect sys_connect | ||
| 52 | 43 common accept sys_accept | ||
| 53 | 44 common sendto sys_sendto | ||
| 54 | 45 64 recvfrom sys_recvfrom | ||
| 55 | 46 64 sendmsg sys_sendmsg | ||
| 56 | 47 64 recvmsg sys_recvmsg | ||
| 57 | 48 common shutdown sys_shutdown | ||
| 58 | 49 common bind sys_bind | ||
| 59 | 50 common listen sys_listen | ||
| 60 | 51 common getsockname sys_getsockname | ||
| 61 | 52 common getpeername sys_getpeername | ||
| 62 | 53 common socketpair sys_socketpair | ||
| 63 | 54 64 setsockopt sys_setsockopt | ||
| 64 | 55 64 getsockopt sys_getsockopt | ||
| 65 | 56 common clone sys_clone/ptregs | ||
| 66 | 57 common fork sys_fork/ptregs | ||
| 67 | 58 common vfork sys_vfork/ptregs | ||
| 68 | 59 64 execve sys_execve/ptregs | ||
| 69 | 60 common exit sys_exit | ||
| 70 | 61 common wait4 sys_wait4 | ||
| 71 | 62 common kill sys_kill | ||
| 72 | 63 common uname sys_newuname | ||
| 73 | 64 common semget sys_semget | ||
| 74 | 65 common semop sys_semop | ||
| 75 | 66 common semctl sys_semctl | ||
| 76 | 67 common shmdt sys_shmdt | ||
| 77 | 68 common msgget sys_msgget | ||
| 78 | 69 common msgsnd sys_msgsnd | ||
| 79 | 70 common msgrcv sys_msgrcv | ||
| 80 | 71 common msgctl sys_msgctl | ||
| 81 | 72 common fcntl sys_fcntl | ||
| 82 | 73 common flock sys_flock | ||
| 83 | 74 common fsync sys_fsync | ||
| 84 | 75 common fdatasync sys_fdatasync | ||
| 85 | 76 common truncate sys_truncate | ||
| 86 | 77 common ftruncate sys_ftruncate | ||
| 87 | 78 common getdents sys_getdents | ||
| 88 | 79 common getcwd sys_getcwd | ||
| 89 | 80 common chdir sys_chdir | ||
| 90 | 81 common fchdir sys_fchdir | ||
| 91 | 82 common rename sys_rename | ||
| 92 | 83 common mkdir sys_mkdir | ||
| 93 | 84 common rmdir sys_rmdir | ||
| 94 | 85 common creat sys_creat | ||
| 95 | 86 common link sys_link | ||
| 96 | 87 common unlink sys_unlink | ||
| 97 | 88 common symlink sys_symlink | ||
| 98 | 89 common readlink sys_readlink | ||
| 99 | 90 common chmod sys_chmod | ||
| 100 | 91 common fchmod sys_fchmod | ||
| 101 | 92 common chown sys_chown | ||
| 102 | 93 common fchown sys_fchown | ||
| 103 | 94 common lchown sys_lchown | ||
| 104 | 95 common umask sys_umask | ||
| 105 | 96 common gettimeofday sys_gettimeofday | ||
| 106 | 97 common getrlimit sys_getrlimit | ||
| 107 | 98 common getrusage sys_getrusage | ||
| 108 | 99 common sysinfo sys_sysinfo | ||
| 109 | 100 common times sys_times | ||
| 110 | 101 64 ptrace sys_ptrace | ||
| 111 | 102 common getuid sys_getuid | ||
| 112 | 103 common syslog sys_syslog | ||
| 113 | 104 common getgid sys_getgid | ||
| 114 | 105 common setuid sys_setuid | ||
| 115 | 106 common setgid sys_setgid | ||
| 116 | 107 common geteuid sys_geteuid | ||
| 117 | 108 common getegid sys_getegid | ||
| 118 | 109 common setpgid sys_setpgid | ||
| 119 | 110 common getppid sys_getppid | ||
| 120 | 111 common getpgrp sys_getpgrp | ||
| 121 | 112 common setsid sys_setsid | ||
| 122 | 113 common setreuid sys_setreuid | ||
| 123 | 114 common setregid sys_setregid | ||
| 124 | 115 common getgroups sys_getgroups | ||
| 125 | 116 common setgroups sys_setgroups | ||
| 126 | 117 common setresuid sys_setresuid | ||
| 127 | 118 common getresuid sys_getresuid | ||
| 128 | 119 common setresgid sys_setresgid | ||
| 129 | 120 common getresgid sys_getresgid | ||
| 130 | 121 common getpgid sys_getpgid | ||
| 131 | 122 common setfsuid sys_setfsuid | ||
| 132 | 123 common setfsgid sys_setfsgid | ||
| 133 | 124 common getsid sys_getsid | ||
| 134 | 125 common capget sys_capget | ||
| 135 | 126 common capset sys_capset | ||
| 136 | 127 64 rt_sigpending sys_rt_sigpending | ||
| 137 | 128 64 rt_sigtimedwait sys_rt_sigtimedwait | ||
| 138 | 129 64 rt_sigqueueinfo sys_rt_sigqueueinfo | ||
| 139 | 130 common rt_sigsuspend sys_rt_sigsuspend | ||
| 140 | 131 64 sigaltstack sys_sigaltstack | ||
| 141 | 132 common utime sys_utime | ||
| 142 | 133 common mknod sys_mknod | ||
| 143 | 134 64 uselib | ||
| 144 | 135 common personality sys_personality | ||
| 145 | 136 common ustat sys_ustat | ||
| 146 | 137 common statfs sys_statfs | ||
| 147 | 138 common fstatfs sys_fstatfs | ||
| 148 | 139 common sysfs sys_sysfs | ||
| 149 | 140 common getpriority sys_getpriority | ||
| 150 | 141 common setpriority sys_setpriority | ||
| 151 | 142 common sched_setparam sys_sched_setparam | ||
| 152 | 143 common sched_getparam sys_sched_getparam | ||
| 153 | 144 common sched_setscheduler sys_sched_setscheduler | ||
| 154 | 145 common sched_getscheduler sys_sched_getscheduler | ||
| 155 | 146 common sched_get_priority_max sys_sched_get_priority_max | ||
| 156 | 147 common sched_get_priority_min sys_sched_get_priority_min | ||
| 157 | 148 common sched_rr_get_interval sys_sched_rr_get_interval | ||
| 158 | 149 common mlock sys_mlock | ||
| 159 | 150 common munlock sys_munlock | ||
| 160 | 151 common mlockall sys_mlockall | ||
| 161 | 152 common munlockall sys_munlockall | ||
| 162 | 153 common vhangup sys_vhangup | ||
| 163 | 154 common modify_ldt sys_modify_ldt | ||
| 164 | 155 common pivot_root sys_pivot_root | ||
| 165 | 156 64 _sysctl sys_sysctl | ||
| 166 | 157 common prctl sys_prctl | ||
| 167 | 158 common arch_prctl sys_arch_prctl | ||
| 168 | 159 common adjtimex sys_adjtimex | ||
| 169 | 160 common setrlimit sys_setrlimit | ||
| 170 | 161 common chroot sys_chroot | ||
| 171 | 162 common sync sys_sync | ||
| 172 | 163 common acct sys_acct | ||
| 173 | 164 common settimeofday sys_settimeofday | ||
| 174 | 165 common mount sys_mount | ||
| 175 | 166 common umount2 sys_umount | ||
| 176 | 167 common swapon sys_swapon | ||
| 177 | 168 common swapoff sys_swapoff | ||
| 178 | 169 common reboot sys_reboot | ||
| 179 | 170 common sethostname sys_sethostname | ||
| 180 | 171 common setdomainname sys_setdomainname | ||
| 181 | 172 common iopl sys_iopl/ptregs | ||
| 182 | 173 common ioperm sys_ioperm | ||
| 183 | 174 64 create_module | ||
| 184 | 175 common init_module sys_init_module | ||
| 185 | 176 common delete_module sys_delete_module | ||
| 186 | 177 64 get_kernel_syms | ||
| 187 | 178 64 query_module | ||
| 188 | 179 common quotactl sys_quotactl | ||
| 189 | 180 64 nfsservctl | ||
| 190 | 181 common getpmsg | ||
| 191 | 182 common putpmsg | ||
| 192 | 183 common afs_syscall | ||
| 193 | 184 common tuxcall | ||
| 194 | 185 common security | ||
| 195 | 186 common gettid sys_gettid | ||
| 196 | 187 common readahead sys_readahead | ||
| 197 | 188 common setxattr sys_setxattr | ||
| 198 | 189 common lsetxattr sys_lsetxattr | ||
| 199 | 190 common fsetxattr sys_fsetxattr | ||
| 200 | 191 common getxattr sys_getxattr | ||
| 201 | 192 common lgetxattr sys_lgetxattr | ||
| 202 | 193 common fgetxattr sys_fgetxattr | ||
| 203 | 194 common listxattr sys_listxattr | ||
| 204 | 195 common llistxattr sys_llistxattr | ||
| 205 | 196 common flistxattr sys_flistxattr | ||
| 206 | 197 common removexattr sys_removexattr | ||
| 207 | 198 common lremovexattr sys_lremovexattr | ||
| 208 | 199 common fremovexattr sys_fremovexattr | ||
| 209 | 200 common tkill sys_tkill | ||
| 210 | 201 common time sys_time | ||
| 211 | 202 common futex sys_futex | ||
| 212 | 203 common sched_setaffinity sys_sched_setaffinity | ||
| 213 | 204 common sched_getaffinity sys_sched_getaffinity | ||
| 214 | 205 64 set_thread_area | ||
| 215 | 206 64 io_setup sys_io_setup | ||
| 216 | 207 common io_destroy sys_io_destroy | ||
| 217 | 208 common io_getevents sys_io_getevents | ||
| 218 | 209 64 io_submit sys_io_submit | ||
| 219 | 210 common io_cancel sys_io_cancel | ||
| 220 | 211 64 get_thread_area | ||
| 221 | 212 common lookup_dcookie sys_lookup_dcookie | ||
| 222 | 213 common epoll_create sys_epoll_create | ||
| 223 | 214 64 epoll_ctl_old | ||
| 224 | 215 64 epoll_wait_old | ||
| 225 | 216 common remap_file_pages sys_remap_file_pages | ||
| 226 | 217 common getdents64 sys_getdents64 | ||
| 227 | 218 common set_tid_address sys_set_tid_address | ||
| 228 | 219 common restart_syscall sys_restart_syscall | ||
| 229 | 220 common semtimedop sys_semtimedop | ||
| 230 | 221 common fadvise64 sys_fadvise64 | ||
| 231 | 222 64 timer_create sys_timer_create | ||
| 232 | 223 common timer_settime sys_timer_settime | ||
| 233 | 224 common timer_gettime sys_timer_gettime | ||
| 234 | 225 common timer_getoverrun sys_timer_getoverrun | ||
| 235 | 226 common timer_delete sys_timer_delete | ||
| 236 | 227 common clock_settime sys_clock_settime | ||
| 237 | 228 common clock_gettime sys_clock_gettime | ||
| 238 | 229 common clock_getres sys_clock_getres | ||
| 239 | 230 common clock_nanosleep sys_clock_nanosleep | ||
| 240 | 231 common exit_group sys_exit_group | ||
| 241 | 232 common epoll_wait sys_epoll_wait | ||
| 242 | 233 common epoll_ctl sys_epoll_ctl | ||
| 243 | 234 common tgkill sys_tgkill | ||
| 244 | 235 common utimes sys_utimes | ||
| 245 | 236 64 vserver | ||
| 246 | 237 common mbind sys_mbind | ||
| 247 | 238 common set_mempolicy sys_set_mempolicy | ||
| 248 | 239 common get_mempolicy sys_get_mempolicy | ||
| 249 | 240 common mq_open sys_mq_open | ||
| 250 | 241 common mq_unlink sys_mq_unlink | ||
| 251 | 242 common mq_timedsend sys_mq_timedsend | ||
| 252 | 243 common mq_timedreceive sys_mq_timedreceive | ||
| 253 | 244 64 mq_notify sys_mq_notify | ||
| 254 | 245 common mq_getsetattr sys_mq_getsetattr | ||
| 255 | 246 64 kexec_load sys_kexec_load | ||
| 256 | 247 64 waitid sys_waitid | ||
| 257 | 248 common add_key sys_add_key | ||
| 258 | 249 common request_key sys_request_key | ||
| 259 | 250 common keyctl sys_keyctl | ||
| 260 | 251 common ioprio_set sys_ioprio_set | ||
| 261 | 252 common ioprio_get sys_ioprio_get | ||
| 262 | 253 common inotify_init sys_inotify_init | ||
| 263 | 254 common inotify_add_watch sys_inotify_add_watch | ||
| 264 | 255 common inotify_rm_watch sys_inotify_rm_watch | ||
| 265 | 256 common migrate_pages sys_migrate_pages | ||
| 266 | 257 common openat sys_openat | ||
| 267 | 258 common mkdirat sys_mkdirat | ||
| 268 | 259 common mknodat sys_mknodat | ||
| 269 | 260 common fchownat sys_fchownat | ||
| 270 | 261 common futimesat sys_futimesat | ||
| 271 | 262 common newfstatat sys_newfstatat | ||
| 272 | 263 common unlinkat sys_unlinkat | ||
| 273 | 264 common renameat sys_renameat | ||
| 274 | 265 common linkat sys_linkat | ||
| 275 | 266 common symlinkat sys_symlinkat | ||
| 276 | 267 common readlinkat sys_readlinkat | ||
| 277 | 268 common fchmodat sys_fchmodat | ||
| 278 | 269 common faccessat sys_faccessat | ||
| 279 | 270 common pselect6 sys_pselect6 | ||
| 280 | 271 common ppoll sys_ppoll | ||
| 281 | 272 common unshare sys_unshare | ||
| 282 | 273 64 set_robust_list sys_set_robust_list | ||
| 283 | 274 64 get_robust_list sys_get_robust_list | ||
| 284 | 275 common splice sys_splice | ||
| 285 | 276 common tee sys_tee | ||
| 286 | 277 common sync_file_range sys_sync_file_range | ||
| 287 | 278 64 vmsplice sys_vmsplice | ||
| 288 | 279 64 move_pages sys_move_pages | ||
| 289 | 280 common utimensat sys_utimensat | ||
| 290 | 281 common epoll_pwait sys_epoll_pwait | ||
| 291 | 282 common signalfd sys_signalfd | ||
| 292 | 283 common timerfd_create sys_timerfd_create | ||
| 293 | 284 common eventfd sys_eventfd | ||
| 294 | 285 common fallocate sys_fallocate | ||
| 295 | 286 common timerfd_settime sys_timerfd_settime | ||
| 296 | 287 common timerfd_gettime sys_timerfd_gettime | ||
| 297 | 288 common accept4 sys_accept4 | ||
| 298 | 289 common signalfd4 sys_signalfd4 | ||
| 299 | 290 common eventfd2 sys_eventfd2 | ||
| 300 | 291 common epoll_create1 sys_epoll_create1 | ||
| 301 | 292 common dup3 sys_dup3 | ||
| 302 | 293 common pipe2 sys_pipe2 | ||
| 303 | 294 common inotify_init1 sys_inotify_init1 | ||
| 304 | 295 64 preadv sys_preadv | ||
| 305 | 296 64 pwritev sys_pwritev | ||
| 306 | 297 64 rt_tgsigqueueinfo sys_rt_tgsigqueueinfo | ||
| 307 | 298 common perf_event_open sys_perf_event_open | ||
| 308 | 299 64 recvmmsg sys_recvmmsg | ||
| 309 | 300 common fanotify_init sys_fanotify_init | ||
| 310 | 301 common fanotify_mark sys_fanotify_mark | ||
| 311 | 302 common prlimit64 sys_prlimit64 | ||
| 312 | 303 common name_to_handle_at sys_name_to_handle_at | ||
| 313 | 304 common open_by_handle_at sys_open_by_handle_at | ||
| 314 | 305 common clock_adjtime sys_clock_adjtime | ||
| 315 | 306 common syncfs sys_syncfs | ||
| 316 | 307 64 sendmmsg sys_sendmmsg | ||
| 317 | 308 common setns sys_setns | ||
| 318 | 309 common getcpu sys_getcpu | ||
| 319 | 310 64 process_vm_readv sys_process_vm_readv | ||
| 320 | 311 64 process_vm_writev sys_process_vm_writev | ||
| 321 | 312 common kcmp sys_kcmp | ||
| 322 | 313 common finit_module sys_finit_module | ||
| 323 | 314 common sched_setattr sys_sched_setattr | ||
| 324 | 315 common sched_getattr sys_sched_getattr | ||
| 325 | 316 common renameat2 sys_renameat2 | ||
| 326 | 317 common seccomp sys_seccomp | ||
| 327 | 318 common getrandom sys_getrandom | ||
| 328 | 319 common memfd_create sys_memfd_create | ||
| 329 | 320 common kexec_file_load sys_kexec_file_load | ||
| 330 | 321 common bpf sys_bpf | ||
| 331 | 322 64 execveat sys_execveat/ptregs | ||
| 332 | 323 common userfaultfd sys_userfaultfd | ||
| 333 | 324 common membarrier sys_membarrier | ||
| 334 | 325 common mlock2 sys_mlock2 | ||
| 335 | 326 common copy_file_range sys_copy_file_range | ||
| 336 | 327 64 preadv2 sys_preadv2 | ||
| 337 | 328 64 pwritev2 sys_pwritev2 | ||
| 338 | |||
| 339 | # | ||
| 340 | # x32-specific system call numbers start at 512 to avoid cache impact | ||
| 341 | # for native 64-bit operation. | ||
| 342 | # | ||
| 343 | 512 x32 rt_sigaction compat_sys_rt_sigaction | ||
| 344 | 513 x32 rt_sigreturn sys32_x32_rt_sigreturn | ||
| 345 | 514 x32 ioctl compat_sys_ioctl | ||
| 346 | 515 x32 readv compat_sys_readv | ||
| 347 | 516 x32 writev compat_sys_writev | ||
| 348 | 517 x32 recvfrom compat_sys_recvfrom | ||
| 349 | 518 x32 sendmsg compat_sys_sendmsg | ||
| 350 | 519 x32 recvmsg compat_sys_recvmsg | ||
| 351 | 520 x32 execve compat_sys_execve/ptregs | ||
| 352 | 521 x32 ptrace compat_sys_ptrace | ||
| 353 | 522 x32 rt_sigpending compat_sys_rt_sigpending | ||
| 354 | 523 x32 rt_sigtimedwait compat_sys_rt_sigtimedwait | ||
| 355 | 524 x32 rt_sigqueueinfo compat_sys_rt_sigqueueinfo | ||
| 356 | 525 x32 sigaltstack compat_sys_sigaltstack | ||
| 357 | 526 x32 timer_create compat_sys_timer_create | ||
| 358 | 527 x32 mq_notify compat_sys_mq_notify | ||
| 359 | 528 x32 kexec_load compat_sys_kexec_load | ||
| 360 | 529 x32 waitid compat_sys_waitid | ||
| 361 | 530 x32 set_robust_list compat_sys_set_robust_list | ||
| 362 | 531 x32 get_robust_list compat_sys_get_robust_list | ||
| 363 | 532 x32 vmsplice compat_sys_vmsplice | ||
| 364 | 533 x32 move_pages compat_sys_move_pages | ||
| 365 | 534 x32 preadv compat_sys_preadv64 | ||
| 366 | 535 x32 pwritev compat_sys_pwritev64 | ||
| 367 | 536 x32 rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo | ||
| 368 | 537 x32 recvmmsg compat_sys_recvmmsg | ||
| 369 | 538 x32 sendmmsg compat_sys_sendmmsg | ||
| 370 | 539 x32 process_vm_readv compat_sys_process_vm_readv | ||
| 371 | 540 x32 process_vm_writev compat_sys_process_vm_writev | ||
| 372 | 541 x32 setsockopt compat_sys_setsockopt | ||
| 373 | 542 x32 getsockopt compat_sys_getsockopt | ||
| 374 | 543 x32 io_setup compat_sys_io_setup | ||
| 375 | 544 x32 io_submit compat_sys_io_submit | ||
| 376 | 545 x32 execveat compat_sys_execveat/ptregs | ||
| @@ -0,0 +1,39 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | in="$1" | ||
| 4 | arch="$2" | ||
| 5 | |||
| 6 | syscall_macro() { | ||
| 7 | nr="$1" | ||
| 8 | name="$2" | ||
| 9 | |||
| 10 | echo " [$nr] = \"$name\"," | ||
| 11 | } | ||
| 12 | |||
| 13 | emit() { | ||
| 14 | nr="$1" | ||
| 15 | entry="$2" | ||
| 16 | |||
| 17 | syscall_macro "$nr" "$entry" | ||
| 18 | } | ||
| 19 | |||
| 20 | echo "static const char *syscalltbl_${arch}[] = {" | ||
| 21 | |||
| 22 | sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX) | ||
| 23 | grep '^[0-9]' "$in" | sort -n > $sorted_table | ||
| 24 | |||
| 25 | max_nr=0 | ||
| 26 | while read nr abi name entry compat; do | ||
| 27 | if [ $nr -ge 512 ] ; then # discard compat sycalls | ||
| 28 | break | ||
| 29 | fi | ||
| 30 | |||
| 31 | emit "$nr" "$name" | ||
| 32 | max_nr=$nr | ||
| 33 | done < $sorted_table | ||
| 34 | |||
| 35 | rm -f $sorted_table | ||
| 36 | |||
| 37 | echo "};" | ||
| 38 | |||
| 39 | echo "#define SYSCALLTBL_${arch}_MAX_ID ${max_nr}" | ||
| @@ -71,7 +71,7 @@ int test__perf_time_to_tsc(int subtest __maybe_unused) · 70 unmodified lines | |||
| 71 | 71 | ||
| 72 | CHECK__(parse_events(evlist, "cycles:u", NULL)); | 72 | CHECK__(parse_events(evlist, "cycles:u", NULL)); |
| 73 | 73 | ||
| 74 | perf_evlist__config(evlist, &opts); | 74 | perf_evlist__config(evlist, &opts, NULL); |
| 75 | 75 | ||
| 76 | evsel = perf_evlist__first(evlist); | 76 | evsel = perf_evlist__first(evlist); |
| 77 | 77 | ||
| @@ -438,6 +438,11 @@ struct auxtrace_record *intel_bts_recording_init(int *err) · 437 unmodified lines | |||
| 438 | if (!intel_bts_pmu) | 438 | if (!intel_bts_pmu) |
| 439 | return NULL; | 439 | return NULL; |
| 440 | 440 | ||
| 441 | if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) { | ||
| 442 | *err = -errno; | ||
| 443 | return NULL; | ||
| 444 | } | ||
| 445 | |||
| 441 | btsr = zalloc(sizeof(struct intel_bts_recording)); | 446 | btsr = zalloc(sizeof(struct intel_bts_recording)); |
| 442 | if (!btsr) { | 447 | if (!btsr) { |
| 443 | *err = -ENOMEM; | 448 | *err = -ENOMEM; |
| @@ -1027,6 +1027,11 @@ struct auxtrace_record *intel_pt_recording_init(int *err) · 1026 unmodified lines | |||
| 1027 | if (!intel_pt_pmu) | 1027 | if (!intel_pt_pmu) |
| 1028 | return NULL; | 1028 | return NULL; |
| 1029 | 1029 | ||
| 1030 | if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) { | ||
| 1031 | *err = -errno; | ||
| 1032 | return NULL; | ||
| 1033 | } | ||
| 1034 | |||
| 1030 | ptr = zalloc(sizeof(struct intel_pt_recording)); | 1035 | ptr = zalloc(sizeof(struct intel_pt_recording)); |
| 1031 | if (!ptr) { | 1036 | if (!ptr) { |
| 1032 | *err = -ENOMEM; | 1037 | *err = -ENOMEM; |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
| 8 | #include "../../util/debug.h" | 8 | #include "../../util/debug.h" |
| 9 | #include "../../util/tsc.h" | 9 | #include "../../util/tsc.h" |
| 10 | #include "tsc.h" | ||
| 11 | 10 | ||
| 12 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | 11 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, |
| 13 | struct perf_tsc_conversion *tc) | 12 | struct perf_tsc_conversion *tc) |
| @@ -46,3 +45,34 @@ u64 rdtsc(void) · 32 unmodified lines | |||
| 46 | 45 | ||
| 47 | return low | ((u64)high) << 32; | 46 | return low | ((u64)high) << 32; |
| 48 | } | 47 | } |
| 48 | |||
| 49 | int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, | ||
| 50 | struct perf_tool *tool, | ||
| 51 | perf_event__handler_t process, | ||
| 52 | struct machine *machine) | ||
| 53 | { | ||
| 54 | union perf_event event = { | ||
| 55 | .time_conv = { | ||
| 56 | .header = { | ||
| 57 | .type = PERF_RECORD_TIME_CONV, | ||
| 58 | .size = sizeof(struct time_conv_event), | ||
| 59 | }, | ||
| 60 | }, | ||
| 61 | }; | ||
| 62 | struct perf_tsc_conversion tc; | ||
| 63 | int err; | ||
| 64 | |||
| 65 | err = perf_read_tsc_conversion(pc, &tc); | ||
| 66 | if (err == -EOPNOTSUPP) | ||
| 67 | return 0; | ||
| 68 | if (err) | ||
| 69 | return err; | ||
| 70 | |||
| 71 | pr_debug2("Synthesizing TSC conversion information\n"); | ||
| 72 | |||
| 73 | event.time_conv.time_mult = tc.time_mult; | ||
| 74 | event.time_conv.time_shift = tc.time_shift; | ||
| 75 | event.time_conv.time_zero = tc.time_zero; | ||
| 76 | |||
| 77 | return process(tool, &event, NULL, machine); | ||
| 78 | } | ||
| @@ -1,17 +0,0 @@ | |||
| 1 | #ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ | ||
| 2 | #define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | |||
| 6 | struct perf_tsc_conversion { | ||
| 7 | u16 time_shift; | ||
| 8 | u32 time_mult; | ||
| 9 | u64 time_zero; | ||
| 10 | }; | ||
| 11 | |||
| 12 | struct perf_event_mmap_page; | ||
| 13 | |||
| 14 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | ||
| 15 | struct perf_tsc_conversion *tc); | ||
| 16 | |||
| 17 | #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ | ||
| @@ -83,7 +83,7 @@ static void *workerfn(void *arg) · 82 unmodified lines | |||
| 83 | do { | 83 | do { |
| 84 | int ret; | 84 | int ret; |
| 85 | again: | 85 | again: |
| 86 | ret = futex_lock_pi(w->futex, NULL, 0, futex_flag); | 86 | ret = futex_lock_pi(w->futex, NULL, futex_flag); |
| 87 | 87 | ||
| 88 | if (ret) { /* handle lock acquisition */ | 88 | if (ret) { /* handle lock acquisition */ |
| 89 | if (!silent) | 89 | if (!silent) |
| @@ -57,13 +57,11 @@ futex_wake(u_int32_t *uaddr, int nr_wake, int opflags) · 56 unmodified lines | |||
| 57 | 57 | ||
| 58 | /** | 58 | /** |
| 59 | * futex_lock_pi() - block on uaddr as a PI mutex | 59 | * futex_lock_pi() - block on uaddr as a PI mutex |
| 60 | * @detect: whether (1) or not (0) to perform deadlock detection | ||
| 61 | */ | 60 | */ |
| 62 | static inline int | 61 | static inline int |
| 63 | futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int detect, | 62 | futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int opflags) |
| 64 | int opflags) | ||
| 65 | { | 63 | { |
| 66 | return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags); | 64 | return futex(uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0, opflags); |
| 67 | } | 65 | } |
| 68 | 66 | ||
| 69 | /** | 67 | /** |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | 6 | * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include "debug.h" | ||
| 9 | #include "../perf.h" | 10 | #include "../perf.h" |
| 10 | #include "../util/util.h" | 11 | #include "../util/util.h" |
| 11 | #include <subcmd/parse-options.h> | 12 | #include <subcmd/parse-options.h> |
| @@ -63,14 +64,16 @@ static struct perf_event_attr cycle_attr = { · 51 unmodified lines | |||
| 63 | .config = PERF_COUNT_HW_CPU_CYCLES | 64 | .config = PERF_COUNT_HW_CPU_CYCLES |
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| 66 | static void init_cycles(void) | 67 | static int init_cycles(void) |
| 67 | { | 68 | { |
| 68 | cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); | 69 | cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); |
| 69 | 70 | ||
| 70 | if (cycles_fd < 0 && errno == ENOSYS) | 71 | if (cycles_fd < 0 && errno == ENOSYS) { |
| 71 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 72 | pr_debug("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
| 72 | else | 73 | return -1; |
| 73 | BUG_ON(cycles_fd < 0); | 74 | } |
| 75 | |||
| 76 | return cycles_fd; | ||
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | static u64 get_cycles(void) | 79 | static u64 get_cycles(void) |
| @@ -155,8 +158,13 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * · 78 unmodified lines | |||
| 155 | 158 | ||
| 156 | argc = parse_options(argc, argv, options, info->usage, 0); | 159 | argc = parse_options(argc, argv, options, info->usage, 0); |
| 157 | 160 | ||
| 158 | if (use_cycles) | 161 | if (use_cycles) { |
| 159 | init_cycles(); | 162 | i = init_cycles(); |
| 163 | if (i < 0) { | ||
| 164 | fprintf(stderr, "Failed to open cycles counter\n"); | ||
| 165 | return i; | ||
| 166 | } | ||
| 167 | } | ||
| 160 | 168 | ||
| 161 | size = (size_t)perf_atoll((char *)size_str); | 169 | size = (size_t)perf_atoll((char *)size_str); |
| 162 | size_total = (double)size * nr_loops; | 170 | size_total = (double)size * nr_loops; |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <subcmd/parse-options.h> | 12 | #include <subcmd/parse-options.h> |
| 13 | #include "util/util.h" | 13 | #include "util/util.h" |
| 14 | #include "util/debug.h" | 14 | #include "util/debug.h" |
| 15 | #include "util/config.h" | ||
| 15 | 16 | ||
| 16 | static bool use_system_config, use_user_config; | 17 | static bool use_system_config, use_user_config; |
| 17 | 18 | ||
| @@ -32,13 +33,28 @@ static struct option config_options[] = { · 14 unmodified lines | |||
| 32 | OPT_END() | 33 | OPT_END() |
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | static int show_config(const char *key, const char *value, | 36 | static int show_config(struct perf_config_set *set) |
| 36 | void *cb __maybe_unused) | ||
| 37 | { | 37 | { |
| 38 | if (value) | 38 | struct perf_config_section *section; |
| 39 | printf("%s=%s\n", key, value); | 39 | struct perf_config_item *item; |
| 40 | else | 40 | struct list_head *sections; |
| 41 | printf("%s\n", key); | 41 | |
| 42 | if (set == NULL) | ||
| 43 | return -1; | ||
| 44 | |||
| 45 | sections = &set->sections; | ||
| 46 | if (list_empty(sections)) | ||
| 47 | return -1; | ||
| 48 | |||
| 49 | list_for_each_entry(section, sections, node) { | ||
| 50 | list_for_each_entry(item, §ion->items, node) { | ||
| 51 | char *value = item->value; | ||
| 52 | |||
| 53 | if (value) | ||
| 54 | printf("%s.%s=%s\n", section->name, | ||
| 55 | item->name, value); | ||
| 56 | } | ||
| 57 | } | ||
| 42 | 58 | ||
| 43 | return 0; | 59 | return 0; |
| 44 | } | 60 | } |
| @@ -46,6 +62,7 @@ static int show_config(const char *key, const char *value, · 1 unmodified line | |||
| 46 | int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) | 62 | int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) |
| 47 | { | 63 | { |
| 48 | int ret = 0; | 64 | int ret = 0; |
| 65 | struct perf_config_set *set; | ||
| 49 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); | 66 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); |
| 50 | 67 | ||
| 51 | argc = parse_options(argc, argv, config_options, config_usage, | 68 | argc = parse_options(argc, argv, config_options, config_usage, |
| @@ -63,13 +80,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) · 11 unmodified lines | |||
| 63 | else if (use_user_config) | 80 | else if (use_user_config) |
| 64 | config_exclusive_filename = user_config; | 81 | config_exclusive_filename = user_config; |
| 65 | 82 | ||
| 83 | set = perf_config_set__new(); | ||
| 84 | if (!set) { | ||
| 85 | ret = -1; | ||
| 86 | goto out_err; | ||
| 87 | } | ||
| 88 | |||
| 66 | switch (actions) { | 89 | switch (actions) { |
| 67 | case ACTION_LIST: | 90 | case ACTION_LIST: |
| 68 | if (argc) { | 91 | if (argc) { |
| 69 | pr_err("Error: takes no arguments\n"); | 92 | pr_err("Error: takes no arguments\n"); |
| 70 | parse_options_usage(config_usage, config_options, "l", 1); | 93 | parse_options_usage(config_usage, config_options, "l", 1); |
| 71 | } else { | 94 | } else { |
| 72 | ret = perf_config(show_config, NULL); | 95 | ret = show_config(set); |
| 73 | if (ret < 0) { | 96 | if (ret < 0) { |
| 74 | const char * config_filename = config_exclusive_filename; | 97 | const char * config_filename = config_exclusive_filename; |
| 75 | if (!config_exclusive_filename) | 98 | if (!config_exclusive_filename) |
| @@ -83,5 +106,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) · 7 unmodified lines | |||
| 83 | usage_with_options(config_usage, config_options); | 106 | usage_with_options(config_usage, config_options); |
| 84 | } | 107 | } |
| 85 | 108 | ||
| 109 | perf_config_set__delete(set); | ||
| 110 | out_err: | ||
| 86 | return ret; | 111 | return ret; |
| 87 | } | 112 | } |
| @@ -428,7 +428,7 @@ static void hists__baseline_only(struct hists *hists) · 427 unmodified lines | |||
| 428 | struct rb_root *root; | 428 | struct rb_root *root; |
| 429 | struct rb_node *next; | 429 | struct rb_node *next; |
| 430 | 430 | ||
| 431 | if (sort__need_collapse) | 431 | if (hists__has(hists, need_collapse)) |
| 432 | root = &hists->entries_collapsed; | 432 | root = &hists->entries_collapsed; |
| 433 | else | 433 | else |
| 434 | root = hists->entries_in; | 434 | root = hists->entries_in; |
| @@ -450,7 +450,7 @@ static void hists__precompute(struct hists *hists) · 15 unmodified lines | |||
| 450 | struct rb_root *root; | 450 | struct rb_root *root; |
| 451 | struct rb_node *next; | 451 | struct rb_node *next; |
| 452 | 452 | ||
| 453 | if (sort__need_collapse) | 453 | if (hists__has(hists, need_collapse)) |
| 454 | root = &hists->entries_collapsed; | 454 | root = &hists->entries_collapsed; |
| 455 | else | 455 | else |
| 456 | root = hists->entries_in; | 456 | root = hists->entries_in; |
| @@ -61,6 +61,7 @@ static int check_emacsclient_version(void) · 60 unmodified lines | |||
| 61 | struct child_process ec_process; | 61 | struct child_process ec_process; |
| 62 | const char *argv_ec[] = { "emacsclient", "--version", NULL }; | 62 | const char *argv_ec[] = { "emacsclient", "--version", NULL }; |
| 63 | int version; | 63 | int version; |
| 64 | int ret = -1; | ||
| 64 | 65 | ||
| 65 | /* emacsclient prints its version number on stderr */ | 66 | /* emacsclient prints its version number on stderr */ |
| 66 | memset(&ec_process, 0, sizeof(ec_process)); | 67 | memset(&ec_process, 0, sizeof(ec_process)); |
| @@ -71,7 +72,10 @@ static int check_emacsclient_version(void) · 4 unmodified lines | |||
| 71 | fprintf(stderr, "Failed to start emacsclient.\n"); | 72 | fprintf(stderr, "Failed to start emacsclient.\n"); |
| 72 | return -1; | 73 | return -1; |
| 73 | } | 74 | } |
| 74 | strbuf_read(&buffer, ec_process.err, 20); | 75 | if (strbuf_read(&buffer, ec_process.err, 20) < 0) { |
| 76 | fprintf(stderr, "Failed to read emacsclient version\n"); | ||
| 77 | goto out; | ||
| 78 | } | ||
| 75 | close(ec_process.err); | 79 | close(ec_process.err); |
| 76 | 80 | ||
| 77 | /* | 81 | /* |
| @@ -82,8 +86,7 @@ static int check_emacsclient_version(void) · 4 unmodified lines | |||
| 82 | 86 | ||
| 83 | if (prefixcmp(buffer.buf, "emacsclient")) { | 87 | if (prefixcmp(buffer.buf, "emacsclient")) { |
| 84 | fprintf(stderr, "Failed to parse emacsclient version.\n"); | 88 | fprintf(stderr, "Failed to parse emacsclient version.\n"); |
| 85 | strbuf_release(&buffer); | 89 | goto out; |
| 86 | return -1; | ||
| 87 | } | 90 | } |
| 88 | 91 | ||
| 89 | version = atoi(buffer.buf + strlen("emacsclient")); | 92 | version = atoi(buffer.buf + strlen("emacsclient")); |
| @@ -92,12 +95,11 @@ static int check_emacsclient_version(void) · 2 unmodified lines | |||
| 92 | fprintf(stderr, | 95 | fprintf(stderr, |
| 93 | "emacsclient version '%d' too old (< 22).\n", | 96 | "emacsclient version '%d' too old (< 22).\n", |
| 94 | version); | 97 | version); |
| 95 | strbuf_release(&buffer); | 98 | } else |
| 96 | return -1; | 99 | ret = 0; |
| 97 | } | 100 | out: |
| 98 | |||
| 99 | strbuf_release(&buffer); | 101 | strbuf_release(&buffer); |
| 100 | return 0; | 102 | return ret; |
| 101 | } | 103 | } |
| 102 | 104 | ||
| 103 | static void exec_woman_emacs(const char *path, const char *page) | 105 | static void exec_woman_emacs(const char *path, const char *page) |
| @@ -748,6 +748,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) · 747 unmodified lines | |||
| 748 | .auxtrace_info = perf_event__repipe_op2_synth, | 748 | .auxtrace_info = perf_event__repipe_op2_synth, |
| 749 | .auxtrace = perf_event__repipe_auxtrace, | 749 | .auxtrace = perf_event__repipe_auxtrace, |
| 750 | .auxtrace_error = perf_event__repipe_op2_synth, | 750 | .auxtrace_error = perf_event__repipe_op2_synth, |
| 751 | .time_conv = perf_event__repipe_op2_synth, | ||
| 751 | .finished_round = perf_event__repipe_oe_synth, | 752 | .finished_round = perf_event__repipe_oe_synth, |
| 752 | .build_id = perf_event__repipe_op2_synth, | 753 | .build_id = perf_event__repipe_op2_synth, |
| 753 | .id_index = perf_event__repipe_op2_synth, | 754 | .id_index = perf_event__repipe_op2_synth, |
| @@ -375,7 +375,7 @@ static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample) · 374 unmodified lines | |||
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); | 377 | al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); |
| 378 | sample__resolve_callchain(sample, NULL, evsel, &al, 16); | 378 | sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16); |
| 379 | 379 | ||
| 380 | callchain_cursor_commit(&callchain_cursor); | 380 | callchain_cursor_commit(&callchain_cursor); |
| 381 | while (true) { | 381 | while (true) { |
| @@ -982,7 +982,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) · 981 unmodified lines | |||
| 982 | struct perf_evlist *evlist = kvm->evlist; | 982 | struct perf_evlist *evlist = kvm->evlist; |
| 983 | char sbuf[STRERR_BUFSIZE]; | 983 | char sbuf[STRERR_BUFSIZE]; |
| 984 | 984 | ||
| 985 | perf_evlist__config(evlist, &kvm->opts); | 985 | perf_evlist__config(evlist, &kvm->opts, NULL); |
| 986 | 986 | ||
| 987 | /* | 987 | /* |
| 988 | * Note: exclude_{guest,host} do not apply here. | 988 | * Note: exclude_{guest,host} do not apply here. |
| @@ -62,19 +62,22 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) · 61 unmodified lines | |||
| 62 | int rec_argc, i = 0, j; | 62 | int rec_argc, i = 0, j; |
| 63 | const char **rec_argv; | 63 | const char **rec_argv; |
| 64 | int ret; | 64 | int ret; |
| 65 | bool all_user = false, all_kernel = false; | ||
| 65 | struct option options[] = { | 66 | struct option options[] = { |
| 66 | OPT_CALLBACK('e', "event", &mem, "event", | 67 | OPT_CALLBACK('e', "event", &mem, "event", |
| 67 | "event selector. use 'perf mem record -e list' to list available events", | 68 | "event selector. use 'perf mem record -e list' to list available events", |
| 68 | parse_record_events), | 69 | parse_record_events), |
| 69 | OPT_INCR('v', "verbose", &verbose, | 70 | OPT_INCR('v', "verbose", &verbose, |
| 70 | "be more verbose (show counter open errors, etc)"), | 71 | "be more verbose (show counter open errors, etc)"), |
| 72 | OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), | ||
| 73 | OPT_BOOLEAN('K', "--all-kernel", &all_kernel, "collect only kernel level data"), | ||
| 71 | OPT_END() | 74 | OPT_END() |
| 72 | }; | 75 | }; |
| 73 | 76 | ||
| 74 | argc = parse_options(argc, argv, options, record_mem_usage, | 77 | argc = parse_options(argc, argv, options, record_mem_usage, |
| 75 | PARSE_OPT_STOP_AT_NON_OPTION); | 78 | PARSE_OPT_STOP_AT_NON_OPTION); |
| 76 | 79 | ||
| 77 | rec_argc = argc + 7; /* max number of arguments */ | 80 | rec_argc = argc + 9; /* max number of arguments */ |
| 78 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 81 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 79 | if (!rec_argv) | 82 | if (!rec_argv) |
| 80 | return -1; | 83 | return -1; |
| @@ -103,6 +106,12 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) · 22 unmodified lines | |||
| 103 | rec_argv[i++] = perf_mem_events__name(j); | 106 | rec_argv[i++] = perf_mem_events__name(j); |
| 104 | }; | 107 | }; |
| 105 | 108 | ||
| 109 | if (all_user) | ||
| 110 | rec_argv[i++] = "--all-user"; | ||
| 111 | |||
| 112 | if (all_kernel) | ||
| 113 | rec_argv[i++] = "--all-kernel"; | ||
| 114 | |||
| 106 | for (j = 0; j < argc; j++, i++) | 115 | for (j = 0; j < argc; j++, i++) |
| 107 | rec_argv[i] = argv[j]; | 116 | rec_argv[i] = argv[j]; |
| 108 | 117 | ||
| @@ -29,10 +29,12 @@ · 28 unmodified lines | |||
| 29 | #include "util/data.h" | 29 | #include "util/data.h" |
| 30 | #include "util/perf_regs.h" | 30 | #include "util/perf_regs.h" |
| 31 | #include "util/auxtrace.h" | 31 | #include "util/auxtrace.h" |
| 32 | #include "util/tsc.h" | ||
| 32 | #include "util/parse-branch-options.h" | 33 | #include "util/parse-branch-options.h" |
| 33 | #include "util/parse-regs-options.h" | 34 | #include "util/parse-regs-options.h" |
| 34 | #include "util/llvm-utils.h" | 35 | #include "util/llvm-utils.h" |
| 35 | #include "util/bpf-loader.h" | 36 | #include "util/bpf-loader.h" |
| 37 | #include "util/trigger.h" | ||
| 36 | #include "asm/bug.h" | 38 | #include "asm/bug.h" |
| 37 | 39 | ||
| 38 | #include <unistd.h> | 40 | #include <unistd.h> |
| @@ -55,6 +57,8 @@ struct record { · 16 unmodified lines | |||
| 55 | bool no_buildid_cache; | 57 | bool no_buildid_cache; |
| 56 | bool no_buildid_cache_set; | 58 | bool no_buildid_cache_set; |
| 57 | bool buildid_all; | 59 | bool buildid_all; |
| 60 | bool timestamp_filename; | ||
| 61 | bool switch_output; | ||
| 58 | unsigned long long samples; | 62 | unsigned long long samples; |
| 59 | }; | 63 | }; |
| 60 | 64 | ||
| @@ -124,9 +128,10 @@ out: · 63 unmodified lines | |||
| 124 | static volatile int done; | 128 | static volatile int done; |
| 125 | static volatile int signr = -1; | 129 | static volatile int signr = -1; |
| 126 | static volatile int child_finished; | 130 | static volatile int child_finished; |
| 127 | static volatile int auxtrace_snapshot_enabled; | 131 | |
| 128 | static volatile int auxtrace_snapshot_err; | ||
| 129 | static volatile int auxtrace_record__snapshot_started; | 132 | static volatile int auxtrace_record__snapshot_started; |
| 133 | static DEFINE_TRIGGER(auxtrace_snapshot_trigger); | ||
| 134 | static DEFINE_TRIGGER(switch_output_trigger); | ||
| 130 | 135 | ||
| 131 | static void sig_handler(int sig) | 136 | static void sig_handler(int sig) |
| 132 | { | 137 | { |
| @@ -244,11 +249,12 @@ static void record__read_auxtrace_snapshot(struct record *rec) · 111 unmodified lines | |||
| 244 | { | 249 | { |
| 245 | pr_debug("Recording AUX area tracing snapshot\n"); | 250 | pr_debug("Recording AUX area tracing snapshot\n"); |
| 246 | if (record__auxtrace_read_snapshot_all(rec) < 0) { | 251 | if (record__auxtrace_read_snapshot_all(rec) < 0) { |
| 247 | auxtrace_snapshot_err = -1; | 252 | trigger_error(&auxtrace_snapshot_trigger); |
| 248 | } else { | 253 | } else { |
| 249 | auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr); | 254 | if (auxtrace_record__snapshot_finish(rec->itr)) |
| 250 | if (!auxtrace_snapshot_err) | 255 | trigger_error(&auxtrace_snapshot_trigger); |
| 251 | auxtrace_snapshot_enabled = 1; | 256 | else |
| 257 | trigger_ready(&auxtrace_snapshot_trigger); | ||
| 252 | } | 258 | } |
| 253 | } | 259 | } |
| 254 | 260 | ||
| @@ -283,7 +289,7 @@ static int record__open(struct record *rec) · 28 unmodified lines | |||
| 283 | struct record_opts *opts = &rec->opts; | 289 | struct record_opts *opts = &rec->opts; |
| 284 | int rc = 0; | 290 | int rc = 0; |
| 285 | 291 | ||
| 286 | perf_evlist__config(evlist, opts); | 292 | perf_evlist__config(evlist, opts, &callchain_param); |
| 287 | 293 | ||
| 288 | evlist__for_each(evlist, pos) { | 294 | evlist__for_each(evlist, pos) { |
| 289 | try_again: | 295 | try_again: |
| @@ -494,6 +500,73 @@ record__finish_output(struct record *rec) · 204 unmodified lines | |||
| 494 | return; | 500 | return; |
| 495 | } | 501 | } |
| 496 | 502 | ||
| 503 | static int record__synthesize_workload(struct record *rec) | ||
| 504 | { | ||
| 505 | struct { | ||
| 506 | struct thread_map map; | ||
| 507 | struct thread_map_data map_data; | ||
| 508 | } thread_map; | ||
| 509 | |||
| 510 | thread_map.map.nr = 1; | ||
| 511 | thread_map.map.map[0].pid = rec->evlist->workload.pid; | ||
| 512 | thread_map.map.map[0].comm = NULL; | ||
| 513 | return perf_event__synthesize_thread_map(&rec->tool, &thread_map.map, | ||
| 514 | process_synthesized_event, | ||
| 515 | &rec->session->machines.host, | ||
| 516 | rec->opts.sample_address, | ||
| 517 | rec->opts.proc_map_timeout); | ||
| 518 | } | ||
| 519 | |||
| 520 | static int record__synthesize(struct record *rec); | ||
| 521 | |||
| 522 | static int | ||
| 523 | record__switch_output(struct record *rec, bool at_exit) | ||
| 524 | { | ||
| 525 | struct perf_data_file *file = &rec->file; | ||
| 526 | int fd, err; | ||
| 527 | |||
| 528 | /* Same Size: "2015122520103046"*/ | ||
| 529 | char timestamp[] = "InvalidTimestamp"; | ||
| 530 | |||
| 531 | rec->samples = 0; | ||
| 532 | record__finish_output(rec); | ||
| 533 | err = fetch_current_timestamp(timestamp, sizeof(timestamp)); | ||
| 534 | if (err) { | ||
| 535 | pr_err("Failed to get current timestamp\n"); | ||
| 536 | return -EINVAL; | ||
| 537 | } | ||
| 538 | |||
| 539 | fd = perf_data_file__switch(file, timestamp, | ||
| 540 | rec->session->header.data_offset, | ||
| 541 | at_exit); | ||
| 542 | if (fd >= 0 && !at_exit) { | ||
| 543 | rec->bytes_written = 0; | ||
| 544 | rec->session->header.data_size = 0; | ||
| 545 | } | ||
| 546 | |||
| 547 | if (!quiet) | ||
| 548 | fprintf(stderr, "[ perf record: Dump %s.%s ]\n", | ||
| 549 | file->path, timestamp); | ||
| 550 | |||
| 551 | /* Output tracking events */ | ||
| 552 | if (!at_exit) { | ||
| 553 | record__synthesize(rec); | ||
| 554 | |||
| 555 | /* | ||
| 556 | * In 'perf record --switch-output' without -a, | ||
| 557 | * record__synthesize() in record__switch_output() won't | ||
| 558 | * generate tracking events because there's no thread_map | ||
| 559 | * in evlist. Which causes newly created perf.data doesn't | ||
| 560 | * contain map and comm information. | ||
| 561 | * Create a fake thread_map and directly call | ||
| 562 | * perf_event__synthesize_thread_map() for those events. | ||
| 563 | */ | ||
| 564 | if (target__none(&rec->opts.target)) | ||
| 565 | record__synthesize_workload(rec); | ||
| 566 | } | ||
| 567 | return fd; | ||
| 568 | } | ||
| 569 | |||
| 497 | static volatile int workload_exec_errno; | 570 | static volatile int workload_exec_errno; |
| 498 | 571 | ||
| 499 | /* | 572 | /* |
| @@ -512,6 +585,15 @@ static void workload_exec_failed_signal(int signo __maybe_unused, · 12 unmodified lines | |||
| 512 | 585 | ||
| 513 | static void snapshot_sig_handler(int sig); | 586 | static void snapshot_sig_handler(int sig); |
| 514 | 587 | ||
| 588 | int __weak | ||
| 589 | perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused, | ||
| 590 | struct perf_tool *tool __maybe_unused, | ||
| 591 | perf_event__handler_t process __maybe_unused, | ||
| 592 | struct machine *machine __maybe_unused) | ||
| 593 | { | ||
| 594 | return 0; | ||
| 595 | } | ||
| 596 | |||
| 515 | static int record__synthesize(struct record *rec) | 597 | static int record__synthesize(struct record *rec) |
| 516 | { | 598 | { |
| 517 | struct perf_session *session = rec->session; | 599 | struct perf_session *session = rec->session; |
| @@ -549,6 +631,11 @@ static int record__synthesize(struct record *rec) · 31 unmodified lines | |||
| 549 | } | 631 | } |
| 550 | } | 632 | } |
| 551 | 633 | ||
| 634 | err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool, | ||
| 635 | process_synthesized_event, machine); | ||
| 636 | if (err) | ||
| 637 | goto out; | ||
| 638 | |||
| 552 | if (rec->opts.full_auxtrace) { | 639 | if (rec->opts.full_auxtrace) { |
| 553 | err = perf_event__synthesize_auxtrace_info(rec->itr, tool, | 640 | err = perf_event__synthesize_auxtrace_info(rec->itr, tool, |
| 554 | session, process_synthesized_event); | 641 | session, process_synthesized_event); |
| @@ -600,10 +687,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) · 45 unmodified lines | |||
| 600 | signal(SIGCHLD, sig_handler); | 687 | signal(SIGCHLD, sig_handler); |
| 601 | signal(SIGINT, sig_handler); | 688 | signal(SIGINT, sig_handler); |
| 602 | signal(SIGTERM, sig_handler); | 689 | signal(SIGTERM, sig_handler); |
| 603 | if (rec->opts.auxtrace_snapshot_mode) | 690 | |
| 691 | if (rec->opts.auxtrace_snapshot_mode || rec->switch_output) { | ||
| 604 | signal(SIGUSR2, snapshot_sig_handler); | 692 | signal(SIGUSR2, snapshot_sig_handler); |
| 605 | else | 693 | if (rec->opts.auxtrace_snapshot_mode) |
| 694 | trigger_on(&auxtrace_snapshot_trigger); | ||
| 695 | if (rec->switch_output) | ||
| 696 | trigger_on(&switch_output_trigger); | ||
| 697 | } else { | ||
| 606 | signal(SIGUSR2, SIG_IGN); | 698 | signal(SIGUSR2, SIG_IGN); |
| 699 | } | ||
| 607 | 700 | ||
| 608 | session = perf_session__new(file, false, tool); | 701 | session = perf_session__new(file, false, tool); |
| 609 | if (session == NULL) { | 702 | if (session == NULL) { |
| @@ -729,27 +822,45 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) · 119 unmodified lines | |||
| 729 | perf_evlist__enable(rec->evlist); | 822 | perf_evlist__enable(rec->evlist); |
| 730 | } | 823 | } |
| 731 | 824 | ||
| 732 | auxtrace_snapshot_enabled = 1; | 825 | trigger_ready(&auxtrace_snapshot_trigger); |
| 826 | trigger_ready(&switch_output_trigger); | ||
| 733 | for (;;) { | 827 | for (;;) { |
| 734 | unsigned long long hits = rec->samples; | 828 | unsigned long long hits = rec->samples; |
| 735 | 829 | ||
| 736 | if (record__mmap_read_all(rec) < 0) { | 830 | if (record__mmap_read_all(rec) < 0) { |
| 737 | auxtrace_snapshot_enabled = 0; | 831 | trigger_error(&auxtrace_snapshot_trigger); |
| 832 | trigger_error(&switch_output_trigger); | ||
| 738 | err = -1; | 833 | err = -1; |
| 739 | goto out_child; | 834 | goto out_child; |
| 740 | } | 835 | } |
| 741 | 836 | ||
| 742 | if (auxtrace_record__snapshot_started) { | 837 | if (auxtrace_record__snapshot_started) { |
| 743 | auxtrace_record__snapshot_started = 0; | 838 | auxtrace_record__snapshot_started = 0; |
| 744 | if (!auxtrace_snapshot_err) | 839 | if (!trigger_is_error(&auxtrace_snapshot_trigger)) |
| 745 | record__read_auxtrace_snapshot(rec); | 840 | record__read_auxtrace_snapshot(rec); |
| 746 | if (auxtrace_snapshot_err) { | 841 | if (trigger_is_error(&auxtrace_snapshot_trigger)) { |
| 747 | pr_err("AUX area tracing snapshot failed\n"); | 842 | pr_err("AUX area tracing snapshot failed\n"); |
| 748 | err = -1; | 843 | err = -1; |
| 749 | goto out_child; | 844 | goto out_child; |
| 750 | } | 845 | } |
| 751 | } | 846 | } |
| 752 | 847 | ||
| 848 | if (trigger_is_hit(&switch_output_trigger)) { | ||
| 849 | trigger_ready(&switch_output_trigger); | ||
| 850 | |||
| 851 | if (!quiet) | ||
| 852 | fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n", | ||
| 853 | waking); | ||
| 854 | waking = 0; | ||
| 855 | fd = record__switch_output(rec, false); | ||
| 856 | if (fd < 0) { | ||
| 857 | pr_err("Failed to switch to new file\n"); | ||
| 858 | trigger_error(&switch_output_trigger); | ||
| 859 | err = fd; | ||
| 860 | goto out_child; | ||
| 861 | } | ||
| 862 | } | ||
| 863 | |||
| 753 | if (hits == rec->samples) { | 864 | if (hits == rec->samples) { |
| 754 | if (done || draining) | 865 | if (done || draining) |
| 755 | break; | 866 | break; |
| @@ -772,12 +883,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) · 16 unmodified lines | |||
| 772 | * disable events in this case. | 883 | * disable events in this case. |
| 773 | */ | 884 | */ |
| 774 | if (done && !disabled && !target__none(&opts->target)) { | 885 | if (done && !disabled && !target__none(&opts->target)) { |
| 775 | auxtrace_snapshot_enabled = 0; | 886 | trigger_off(&auxtrace_snapshot_trigger); |
| 776 | perf_evlist__disable(rec->evlist); | 887 | perf_evlist__disable(rec->evlist); |
| 777 | disabled = true; | 888 | disabled = true; |
| 778 | } | 889 | } |
| 779 | } | 890 | } |
| 780 | auxtrace_snapshot_enabled = 0; | 891 | trigger_off(&auxtrace_snapshot_trigger); |
| 892 | trigger_off(&switch_output_trigger); | ||
| 781 | 893 | ||
| 782 | if (forks && workload_exec_errno) { | 894 | if (forks && workload_exec_errno) { |
| 783 | char msg[STRERR_BUFSIZE]; | 895 | char msg[STRERR_BUFSIZE]; |
| @@ -811,11 +923,22 @@ out_child: · 27 unmodified lines | |||
| 811 | /* this will be recalculated during process_buildids() */ | 923 | /* this will be recalculated during process_buildids() */ |
| 812 | rec->samples = 0; | 924 | rec->samples = 0; |
| 813 | 925 | ||
| 814 | if (!err) | 926 | if (!err) { |
| 815 | record__finish_output(rec); | 927 | if (!rec->timestamp_filename) { |
| 928 | record__finish_output(rec); | ||
| 929 | } else { | ||
| 930 | fd = record__switch_output(rec, true); | ||
| 931 | if (fd < 0) { | ||
| 932 | status = fd; | ||
| 933 | goto out_delete_session; | ||
| 934 | } | ||
| 935 | } | ||
| 936 | } | ||
| 816 | 937 | ||
| 817 | if (!err && !quiet) { | 938 | if (!err && !quiet) { |
| 818 | char samples[128]; | 939 | char samples[128]; |
| 940 | const char *postfix = rec->timestamp_filename ? | ||
| 941 | ".<timestamp>" : ""; | ||
| 819 | 942 | ||
| 820 | if (rec->samples && !rec->opts.full_auxtrace) | 943 | if (rec->samples && !rec->opts.full_auxtrace) |
| 821 | scnprintf(samples, sizeof(samples), | 944 | scnprintf(samples, sizeof(samples), |
| @@ -823,9 +946,9 @@ out_child: · 1 unmodified line | |||
| 823 | else | 946 | else |
| 824 | samples[0] = '\0'; | 947 | samples[0] = '\0'; |
| 825 | 948 | ||
| 826 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n", | 949 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n", |
| 827 | perf_data_file__size(file) / 1024.0 / 1024.0, | 950 | perf_data_file__size(file) / 1024.0 / 1024.0, |
| 828 | file->path, samples); | 951 | file->path, postfix, samples); |
| 829 | } | 952 | } |
| 830 | 953 | ||
| 831 | out_delete_session: | 954 | out_delete_session: |
| @@ -833,58 +956,61 @@ out_delete_session: · 1 unmodified line | |||
| 833 | return status; | 956 | return status; |
| 834 | } | 957 | } |
| 835 | 958 | ||
| 836 | static void callchain_debug(void) | 959 | static void callchain_debug(struct callchain_param *callchain) |
| 837 | { | 960 | { |
| 838 | static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" }; | 961 | static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" }; |
| 839 | 962 | ||
| 840 | pr_debug("callchain: type %s\n", str[callchain_param.record_mode]); | 963 | pr_debug("callchain: type %s\n", str[callchain->record_mode]); |
| 841 | 964 | ||
| 842 | if (callchain_param.record_mode == CALLCHAIN_DWARF) | 965 | if (callchain->record_mode == CALLCHAIN_DWARF) |
| 843 | pr_debug("callchain: stack dump size %d\n", | 966 | pr_debug("callchain: stack dump size %d\n", |
| 844 | callchain_param.dump_size); | 967 | callchain->dump_size); |
| 845 | } | 968 | } |
| 846 | 969 | ||
| 847 | int record_parse_callchain_opt(const struct option *opt, | 970 | int record_opts__parse_callchain(struct record_opts *record, |
| 848 | const char *arg, | 971 | struct callchain_param *callchain, |
| 849 | int unset) | 972 | const char *arg, bool unset) |
| 850 | { | 973 | { |
| 851 | int ret; | 974 | int ret; |
| 852 | struct record_opts *record = (struct record_opts *)opt->value; | 975 | callchain->enabled = !unset; |
| 853 | |||
| 854 | record->callgraph_set = true; | ||
| 855 | callchain_param.enabled = !unset; | ||
| 856 | 976 | ||
| 857 | /* --no-call-graph */ | 977 | /* --no-call-graph */ |
| 858 | if (unset) { | 978 | if (unset) { |
| 859 | callchain_param.record_mode = CALLCHAIN_NONE; | 979 | callchain->record_mode = CALLCHAIN_NONE; |
| 860 | pr_debug("callchain: disabled\n"); | 980 | pr_debug("callchain: disabled\n"); |
| 861 | return 0; | 981 | return 0; |
| 862 | } | 982 | } |
| 863 | 983 | ||
| 864 | ret = parse_callchain_record_opt(arg, &callchain_param); | 984 | ret = parse_callchain_record_opt(arg, callchain); |
| 865 | if (!ret) { | 985 | if (!ret) { |
| 866 | /* Enable data address sampling for DWARF unwind. */ | 986 | /* Enable data address sampling for DWARF unwind. */ |
| 867 | if (callchain_param.record_mode == CALLCHAIN_DWARF) | 987 | if (callchain->record_mode == CALLCHAIN_DWARF) |
| 868 | record->sample_address = true; | 988 | record->sample_address = true; |
| 869 | callchain_debug(); | 989 | callchain_debug(callchain); |
| 870 | } | 990 | } |
| 871 | 991 | ||
| 872 | return ret; | 992 | return ret; |
| 873 | } | 993 | } |
| 874 | 994 | ||
| 995 | int record_parse_callchain_opt(const struct option *opt, | ||
| 996 | const char *arg, | ||
| 997 | int unset) | ||
| 998 | { | ||
| 999 | return record_opts__parse_callchain(opt->value, &callchain_param, arg, unset); | ||
| 1000 | } | ||
| 1001 | |||
| 875 | int record_callchain_opt(const struct option *opt, | 1002 | int record_callchain_opt(const struct option *opt, |
| 876 | const char *arg __maybe_unused, | 1003 | const char *arg __maybe_unused, |
| 877 | int unset __maybe_unused) | 1004 | int unset __maybe_unused) |
| 878 | { | 1005 | { |
| 879 | struct record_opts *record = (struct record_opts *)opt->value; | 1006 | struct callchain_param *callchain = opt->value; |
| 880 | 1007 | ||
| 881 | record->callgraph_set = true; | 1008 | callchain->enabled = true; |
| 882 | callchain_param.enabled = true; | ||
| 883 | 1009 | ||
| 884 | if (callchain_param.record_mode == CALLCHAIN_NONE) | 1010 | if (callchain->record_mode == CALLCHAIN_NONE) |
| 885 | callchain_param.record_mode = CALLCHAIN_FP; | 1011 | callchain->record_mode = CALLCHAIN_FP; |
| 886 | 1012 | ||
| 887 | callchain_debug(); | 1013 | callchain_debug(callchain); |
| 888 | return 0; | 1014 | return 0; |
| 889 | } | 1015 | } |
| 890 | 1016 | ||
| @@ -1122,7 +1248,7 @@ struct option __record_options[] = { · 231 unmodified lines | |||
| 1122 | record__parse_mmap_pages), | 1248 | record__parse_mmap_pages), |
| 1123 | OPT_BOOLEAN(0, "group", &record.opts.group, | 1249 | OPT_BOOLEAN(0, "group", &record.opts.group, |
| 1124 | "put the counters into a counter group"), | 1250 | "put the counters into a counter group"), |
| 1125 | OPT_CALLBACK_NOOPT('g', NULL, &record.opts, | 1251 | OPT_CALLBACK_NOOPT('g', NULL, &callchain_param, |
| 1126 | NULL, "enables call-graph recording" , | 1252 | NULL, "enables call-graph recording" , |
| 1127 | &record_callchain_opt), | 1253 | &record_callchain_opt), |
| 1128 | OPT_CALLBACK(0, "call-graph", &record.opts, | 1254 | OPT_CALLBACK(0, "call-graph", &record.opts, |
| @@ -1195,6 +1321,10 @@ struct option __record_options[] = { · 66 unmodified lines | |||
| 1195 | "file", "vmlinux pathname"), | 1321 | "file", "vmlinux pathname"), |
| 1196 | OPT_BOOLEAN(0, "buildid-all", &record.buildid_all, | 1322 | OPT_BOOLEAN(0, "buildid-all", &record.buildid_all, |
| 1197 | "Record build-id of all DSOs regardless of hits"), | 1323 | "Record build-id of all DSOs regardless of hits"), |
| 1324 | OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename, | ||
| 1325 | "append timestamp to output filename"), | ||
| 1326 | OPT_BOOLEAN(0, "switch-output", &record.switch_output, | ||
| 1327 | "Switch output when receive SIGUSR2"), | ||
| 1198 | OPT_END() | 1328 | OPT_END() |
| 1199 | }; | 1329 | }; |
| 1200 | 1330 | ||
| @@ -1250,6 +1380,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) · 49 unmodified lines | |||
| 1250 | return -EINVAL; | 1380 | return -EINVAL; |
| 1251 | } | 1381 | } |
| 1252 | 1382 | ||
| 1383 | if (rec->switch_output) | ||
| 1384 | rec->timestamp_filename = true; | ||
| 1385 | |||
| 1253 | if (!rec->itr) { | 1386 | if (!rec->itr) { |
| 1254 | rec->itr = auxtrace_record__init(rec->evlist, &err); | 1387 | rec->itr = auxtrace_record__init(rec->evlist, &err); |
| 1255 | if (err) | 1388 | if (err) |
| @@ -1261,6 +1394,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) · 5 unmodified lines | |||
| 1261 | if (err) | 1394 | if (err) |
| 1262 | return err; | 1395 | return err; |
| 1263 | 1396 | ||
| 1397 | err = bpf__setup_stdout(rec->evlist); | ||
| 1398 | if (err) { | ||
| 1399 | bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf)); | ||
| 1400 | pr_err("ERROR: Setup BPF stdout failed: %s\n", | ||
| 1401 | errbuf); | ||
| 1402 | return err; | ||
| 1403 | } | ||
| 1404 | |||
| 1264 | err = -ENOMEM; | 1405 | err = -ENOMEM; |
| 1265 | 1406 | ||
| 1266 | symbol__init(NULL); | 1407 | symbol__init(NULL); |
| @@ -1275,8 +1416,36 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) · 8 unmodified lines | |||
| 1275 | "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" | 1416 | "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" |
| 1276 | "even with a suitable vmlinux or kallsyms file.\n\n"); | 1417 | "even with a suitable vmlinux or kallsyms file.\n\n"); |
| 1277 | 1418 | ||
| 1278 | if (rec->no_buildid_cache || rec->no_buildid) | 1419 | if (rec->no_buildid_cache || rec->no_buildid) { |
| 1279 | disable_buildid_cache(); | 1420 | disable_buildid_cache(); |
| 1421 | } else if (rec->switch_output) { | ||
| 1422 | /* | ||
| 1423 | * In 'perf record --switch-output', disable buildid | ||
| 1424 | * generation by default to reduce data file switching | ||
| 1425 | * overhead. Still generate buildid if they are required | ||
| 1426 | * explicitly using | ||
| 1427 | * | ||
| 1428 | * perf record --signal-trigger --no-no-buildid \ | ||
| 1429 | * --no-no-buildid-cache | ||
| 1430 | * | ||
| 1431 | * Following code equals to: | ||
| 1432 | * | ||
| 1433 | * if ((rec->no_buildid || !rec->no_buildid_set) && | ||
| 1434 | * (rec->no_buildid_cache || !rec->no_buildid_cache_set)) | ||
| 1435 | * disable_buildid_cache(); | ||
| 1436 | */ | ||
| 1437 | bool disable = true; | ||
| 1438 | |||
| 1439 | if (rec->no_buildid_set && !rec->no_buildid) | ||
| 1440 | disable = false; | ||
| 1441 | if (rec->no_buildid_cache_set && !rec->no_buildid_cache) | ||
| 1442 | disable = false; | ||
| 1443 | if (disable) { | ||
| 1444 | rec->no_buildid = true; | ||
| 1445 | rec->no_buildid_cache = true; | ||
| 1446 | disable_buildid_cache(); | ||
| 1447 | } | ||
| 1448 | } | ||
| 1280 | 1449 | ||
| 1281 | if (rec->evlist->nr_entries == 0 && | 1450 | if (rec->evlist->nr_entries == 0 && |
| 1282 | perf_evlist__add_default(rec->evlist) < 0) { | 1451 | perf_evlist__add_default(rec->evlist) < 0) { |
| @@ -1335,9 +1504,13 @@ out_symbol_exit: · 52 unmodified lines | |||
| 1335 | 1504 | ||
| 1336 | static void snapshot_sig_handler(int sig __maybe_unused) | 1505 | static void snapshot_sig_handler(int sig __maybe_unused) |
| 1337 | { | 1506 | { |
| 1338 | if (!auxtrace_snapshot_enabled) | 1507 | if (trigger_is_ready(&auxtrace_snapshot_trigger)) { |
| 1339 | return; | 1508 | trigger_hit(&auxtrace_snapshot_trigger); |
| 1340 | auxtrace_snapshot_enabled = 0; | 1509 | auxtrace_record__snapshot_started = 1; |
| 1341 | auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr); | 1510 | if (auxtrace_record__snapshot_start(record.itr)) |
| 1342 | auxtrace_record__snapshot_started = 1; | 1511 | trigger_error(&auxtrace_snapshot_trigger); |
| 1512 | } | ||
| 1513 | |||
| 1514 | if (trigger_is_ready(&switch_output_trigger)) | ||
| 1515 | trigger_hit(&switch_output_trigger); | ||
| 1343 | } | 1516 | } |
| @@ -47,7 +47,6 @@ struct report { · 46 unmodified lines | |||
| 47 | struct perf_tool tool; | 47 | struct perf_tool tool; |
| 48 | struct perf_session *session; | 48 | struct perf_session *session; |
| 49 | bool use_tui, use_gtk, use_stdio; | 49 | bool use_tui, use_gtk, use_stdio; |
| 50 | bool dont_use_callchains; | ||
| 51 | bool show_full_info; | 50 | bool show_full_info; |
| 52 | bool show_threads; | 51 | bool show_threads; |
| 53 | bool inverted_callchain; | 52 | bool inverted_callchain; |
| @@ -235,7 +234,7 @@ static int report__setup_sample_type(struct report *rep) · 181 unmodified lines | |||
| 235 | sample_type |= PERF_SAMPLE_BRANCH_STACK; | 234 | sample_type |= PERF_SAMPLE_BRANCH_STACK; |
| 236 | 235 | ||
| 237 | if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { | 236 | if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { |
| 238 | if (sort__has_parent) { | 237 | if (perf_hpp_list.parent) { |
| 239 | ui__error("Selected --sort parent, but no " | 238 | ui__error("Selected --sort parent, but no " |
| 240 | "callchain data. Did you call " | 239 | "callchain data. Did you call " |
| 241 | "'perf record' without -g?\n"); | 240 | "'perf record' without -g?\n"); |
| @@ -247,7 +246,7 @@ static int report__setup_sample_type(struct report *rep) · 5 unmodified lines | |||
| 247 | "you call 'perf record' without -g?\n"); | 246 | "you call 'perf record' without -g?\n"); |
| 248 | return -1; | 247 | return -1; |
| 249 | } | 248 | } |
| 250 | } else if (!rep->dont_use_callchains && | 249 | } else if (!callchain_param.enabled && |
| 251 | callchain_param.mode != CHAIN_NONE && | 250 | callchain_param.mode != CHAIN_NONE && |
| 252 | !symbol_conf.use_callchain) { | 251 | !symbol_conf.use_callchain) { |
| 253 | symbol_conf.use_callchain = true; | 252 | symbol_conf.use_callchain = true; |
| @@ -599,13 +598,15 @@ static int __cmd_report(struct report *rep) · 345 unmodified lines | |||
| 599 | static int | 598 | static int |
| 600 | report_parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 599 | report_parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
| 601 | { | 600 | { |
| 602 | struct report *rep = (struct report *)opt->value; | 601 | struct callchain_param *callchain = opt->value; |
| 603 | 602 | ||
| 603 | callchain->enabled = !unset; | ||
| 604 | /* | 604 | /* |
| 605 | * --no-call-graph | 605 | * --no-call-graph |
| 606 | */ | 606 | */ |
| 607 | if (unset) { | 607 | if (unset) { |
| 608 | rep->dont_use_callchains = true; | 608 | symbol_conf.use_callchain = false; |
| 609 | callchain->mode = CHAIN_NONE; | ||
| 609 | return 0; | 610 | return 0; |
| 610 | } | 611 | } |
| 611 | 612 | ||
| @@ -690,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) · 78 unmodified lines | |||
| 690 | .ordered_events = true, | 691 | .ordered_events = true, |
| 691 | .ordering_requires_timestamps = true, | 692 | .ordering_requires_timestamps = true, |
| 692 | }, | 693 | }, |
| 693 | .max_stack = PERF_MAX_STACK_DEPTH, | 694 | .max_stack = sysctl_perf_event_max_stack, |
| 694 | .pretty_printing_style = "normal", | 695 | .pretty_printing_style = "normal", |
| 695 | .socket_filter = -1, | 696 | .socket_filter = -1, |
| 696 | }; | 697 | }; |
| @@ -734,7 +735,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) · 37 unmodified lines | |||
| 734 | "regex filter to identify parent, see: '--sort parent'"), | 735 | "regex filter to identify parent, see: '--sort parent'"), |
| 735 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, | 736 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, |
| 736 | "Only display entries with parent-match"), | 737 | "Only display entries with parent-match"), |
| 737 | OPT_CALLBACK_DEFAULT('g', "call-graph", &report, | 738 | OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param, |
| 738 | "print_type,threshold[,print_limit],order,sort_key[,branch],value", | 739 | "print_type,threshold[,print_limit],order,sort_key[,branch],value", |
| 739 | report_callchain_help, &report_parse_callchain_opt, | 740 | report_callchain_help, &report_parse_callchain_opt, |
| 740 | callchain_default_opt), | 741 | callchain_default_opt), |
| @@ -743,7 +744,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) · 2 unmodified lines | |||
| 743 | OPT_INTEGER(0, "max-stack", &report.max_stack, | 744 | OPT_INTEGER(0, "max-stack", &report.max_stack, |
| 744 | "Set the maximum stack depth when parsing the callchain, " | 745 | "Set the maximum stack depth when parsing the callchain, " |
| 745 | "anything beyond the specified depth will be ignored. " | 746 | "anything beyond the specified depth will be ignored. " |
| 746 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 747 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
| 747 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, | 748 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, |
| 748 | "alias for inverted call graph"), | 749 | "alias for inverted call graph"), |
| 749 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 750 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
| @@ -935,7 +936,7 @@ repeat: · 185 unmodified lines | |||
| 935 | goto error; | 936 | goto error; |
| 936 | } | 937 | } |
| 937 | 938 | ||
| 938 | sort__need_collapse = true; | 939 | perf_hpp_list.need_collapse = true; |
| 939 | } | 940 | } |
| 940 | 941 | ||
| 941 | /* Force tty output for header output and per-thread stat. */ | 942 | /* Force tty output for header output and per-thread stat. */ |
| @@ -11,6 +11,8 @@ · 10 unmodified lines | |||
| 11 | #include "util/session.h" | 11 | #include "util/session.h" |
| 12 | #include "util/tool.h" | 12 | #include "util/tool.h" |
| 13 | #include "util/cloexec.h" | 13 | #include "util/cloexec.h" |
| 14 | #include "util/thread_map.h" | ||
| 15 | #include "util/color.h" | ||
| 14 | 16 | ||
| 15 | #include <subcmd/parse-options.h> | 17 | #include <subcmd/parse-options.h> |
| 16 | #include "util/trace-event.h" | 18 | #include "util/trace-event.h" |
| @@ -122,6 +124,21 @@ struct trace_sched_handler { · 105 unmodified lines | |||
| 122 | struct machine *machine); | 124 | struct machine *machine); |
| 123 | }; | 125 | }; |
| 124 | 126 | ||
| 127 | #define COLOR_PIDS PERF_COLOR_BLUE | ||
| 128 | #define COLOR_CPUS PERF_COLOR_BG_RED | ||
| 129 | |||
| 130 | struct perf_sched_map { | ||
| 131 | DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS); | ||
| 132 | int *comp_cpus; | ||
| 133 | bool comp; | ||
| 134 | struct thread_map *color_pids; | ||
| 135 | const char *color_pids_str; | ||
| 136 | struct cpu_map *color_cpus; | ||
| 137 | const char *color_cpus_str; | ||
| 138 | struct cpu_map *cpus; | ||
| 139 | const char *cpus_str; | ||
| 140 | }; | ||
| 141 | |||
| 125 | struct perf_sched { | 142 | struct perf_sched { |
| 126 | struct perf_tool tool; | 143 | struct perf_tool tool; |
| 127 | const char *sort_order; | 144 | const char *sort_order; |
| @@ -173,6 +190,7 @@ struct perf_sched { · 45 unmodified lines | |||
| 173 | struct list_head sort_list, cmp_pid; | 190 | struct list_head sort_list, cmp_pid; |
| 174 | bool force; | 191 | bool force; |
| 175 | bool skip_merge; | 192 | bool skip_merge; |
| 193 | struct perf_sched_map map; | ||
| 176 | }; | 194 | }; |
| 177 | 195 | ||
| 178 | static u64 get_nsecs(void) | 196 | static u64 get_nsecs(void) |
| @@ -1339,6 +1357,38 @@ static int process_sched_wakeup_event(struct perf_tool *tool, · 1160 unmodified lines | |||
| 1339 | return 0; | 1357 | return 0; |
| 1340 | } | 1358 | } |
| 1341 | 1359 | ||
| 1360 | union map_priv { | ||
| 1361 | void *ptr; | ||
| 1362 | bool color; | ||
| 1363 | }; | ||
| 1364 | |||
| 1365 | static bool thread__has_color(struct thread *thread) | ||
| 1366 | { | ||
| 1367 | union map_priv priv = { | ||
| 1368 | .ptr = thread__priv(thread), | ||
| 1369 | }; | ||
| 1370 | |||
| 1371 | return priv.color; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | static struct thread* | ||
| 1375 | map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid, pid_t tid) | ||
| 1376 | { | ||
| 1377 | struct thread *thread = machine__findnew_thread(machine, pid, tid); | ||
| 1378 | union map_priv priv = { | ||
| 1379 | .color = false, | ||
| 1380 | }; | ||
| 1381 | |||
| 1382 | if (!sched->map.color_pids || !thread || thread__priv(thread)) | ||
| 1383 | return thread; | ||
| 1384 | |||
| 1385 | if (thread_map__has(sched->map.color_pids, tid)) | ||
| 1386 | priv.color = true; | ||
| 1387 | |||
| 1388 | thread__set_priv(thread, priv.ptr); | ||
| 1389 | return thread; | ||
| 1390 | } | ||
| 1391 | |||
| 1342 | static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | 1392 | static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, |
| 1343 | struct perf_sample *sample, struct machine *machine) | 1393 | struct perf_sample *sample, struct machine *machine) |
| 1344 | { | 1394 | { |
| @@ -1347,13 +1397,25 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, · 2 unmodified lines | |||
| 1347 | int new_shortname; | 1397 | int new_shortname; |
| 1348 | u64 timestamp0, timestamp = sample->time; | 1398 | u64 timestamp0, timestamp = sample->time; |
| 1349 | s64 delta; | 1399 | s64 delta; |
| 1350 | int cpu, this_cpu = sample->cpu; | 1400 | int i, this_cpu = sample->cpu; |
| 1401 | int cpus_nr; | ||
| 1402 | bool new_cpu = false; | ||
| 1403 | const char *color = PERF_COLOR_NORMAL; | ||
| 1351 | 1404 | ||
| 1352 | BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); | 1405 | BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); |
| 1353 | 1406 | ||
| 1354 | if (this_cpu > sched->max_cpu) | 1407 | if (this_cpu > sched->max_cpu) |
| 1355 | sched->max_cpu = this_cpu; | 1408 | sched->max_cpu = this_cpu; |
| 1356 | 1409 | ||
| 1410 | if (sched->map.comp) { | ||
| 1411 | cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS); | ||
| 1412 | if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) { | ||
| 1413 | sched->map.comp_cpus[cpus_nr++] = this_cpu; | ||
| 1414 | new_cpu = true; | ||
| 1415 | } | ||
| 1416 | } else | ||
| 1417 | cpus_nr = sched->max_cpu; | ||
| 1418 | |||
| 1357 | timestamp0 = sched->cpu_last_switched[this_cpu]; | 1419 | timestamp0 = sched->cpu_last_switched[this_cpu]; |
| 1358 | sched->cpu_last_switched[this_cpu] = timestamp; | 1420 | sched->cpu_last_switched[this_cpu] = timestamp; |
| 1359 | if (timestamp0) | 1421 | if (timestamp0) |
| @@ -1366,7 +1428,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, · 6 unmodified lines | |||
| 1366 | return -1; | 1428 | return -1; |
| 1367 | } | 1429 | } |
| 1368 | 1430 | ||
| 1369 | sched_in = machine__findnew_thread(machine, -1, next_pid); | 1431 | sched_in = map__findnew_thread(sched, machine, -1, next_pid); |
| 1370 | if (sched_in == NULL) | 1432 | if (sched_in == NULL) |
| 1371 | return -1; | 1433 | return -1; |
| 1372 | 1434 | ||
| @@ -1400,26 +1462,52 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, · 27 unmodified lines | |||
| 1400 | new_shortname = 1; | 1462 | new_shortname = 1; |
| 1401 | } | 1463 | } |
| 1402 | 1464 | ||
| 1403 | for (cpu = 0; cpu <= sched->max_cpu; cpu++) { | 1465 | for (i = 0; i < cpus_nr; i++) { |
| 1466 | int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i; | ||
| 1467 | struct thread *curr_thread = sched->curr_thread[cpu]; | ||
| 1468 | const char *pid_color = color; | ||
| 1469 | const char *cpu_color = color; | ||
| 1470 | |||
| 1471 | if (curr_thread && thread__has_color(curr_thread)) | ||
| 1472 | pid_color = COLOR_PIDS; | ||
| 1473 | |||
| 1474 | if (sched->map.cpus && !cpu_map__has(sched->map.cpus, cpu)) | ||
| 1475 | continue; | ||
| 1476 | |||
| 1477 | if (sched->map.color_cpus && cpu_map__has(sched->map.color_cpus, cpu)) | ||
| 1478 | cpu_color = COLOR_CPUS; | ||
| 1479 | |||
| 1404 | if (cpu != this_cpu) | 1480 | if (cpu != this_cpu) |
| 1405 | printf(" "); | 1481 | color_fprintf(stdout, cpu_color, " "); |
| 1406 | else | 1482 | else |
| 1407 | printf("*"); | 1483 | color_fprintf(stdout, cpu_color, "*"); |
| 1408 | 1484 | ||
| 1409 | if (sched->curr_thread[cpu]) | 1485 | if (sched->curr_thread[cpu]) |
| 1410 | printf("%2s ", sched->curr_thread[cpu]->shortname); | 1486 | color_fprintf(stdout, pid_color, "%2s ", sched->curr_thread[cpu]->shortname); |
| 1411 | else | 1487 | else |
| 1412 | printf(" "); | 1488 | color_fprintf(stdout, color, " "); |
| 1413 | } | 1489 | } |
| 1414 | 1490 | ||
| 1415 | printf(" %12.6f secs ", (double)timestamp/1e9); | 1491 | if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu)) |
| 1492 | goto out; | ||
| 1493 | |||
| 1494 | color_fprintf(stdout, color, " %12.6f secs ", (double)timestamp/1e9); | ||
| 1416 | if (new_shortname) { | 1495 | if (new_shortname) { |
| 1417 | printf("%s => %s:%d\n", | 1496 | const char *pid_color = color; |
| 1497 | |||
| 1498 | if (thread__has_color(sched_in)) | ||
| 1499 | pid_color = COLOR_PIDS; | ||
| 1500 | |||
| 1501 | color_fprintf(stdout, pid_color, "%s => %s:%d", | ||
| 1418 | sched_in->shortname, thread__comm_str(sched_in), sched_in->tid); | 1502 | sched_in->shortname, thread__comm_str(sched_in), sched_in->tid); |
| 1419 | } else { | ||
| 1420 | printf("\n"); | ||
| 1421 | } | 1503 | } |
| 1422 | 1504 | ||
| 1505 | if (sched->map.comp && new_cpu) | ||
| 1506 | color_fprintf(stdout, color, " (CPU %d)", this_cpu); | ||
| 1507 | |||
| 1508 | out: | ||
| 1509 | color_fprintf(stdout, color, "\n"); | ||
| 1510 | |||
| 1423 | thread__put(sched_in); | 1511 | thread__put(sched_in); |
| 1424 | 1512 | ||
| 1425 | return 0; | 1513 | return 0; |
| @@ -1675,9 +1763,75 @@ static int perf_sched__lat(struct perf_sched *sched) · 249 unmodified lines | |||
| 1675 | return 0; | 1763 | return 0; |
| 1676 | } | 1764 | } |
| 1677 | 1765 | ||
| 1766 | static int setup_map_cpus(struct perf_sched *sched) | ||
| 1767 | { | ||
| 1768 | struct cpu_map *map; | ||
| 1769 | |||
| 1770 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | ||
| 1771 | |||
| 1772 | if (sched->map.comp) { | ||
| 1773 | sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int)); | ||
| 1774 | if (!sched->map.comp_cpus) | ||
| 1775 | return -1; | ||
| 1776 | } | ||
| 1777 | |||
| 1778 | if (!sched->map.cpus_str) | ||
| 1779 | return 0; | ||
| 1780 | |||
| 1781 | map = cpu_map__new(sched->map.cpus_str); | ||
| 1782 | if (!map) { | ||
| 1783 | pr_err("failed to get cpus map from %s\n", sched->map.cpus_str); | ||
| 1784 | return -1; | ||
| 1785 | } | ||
| 1786 | |||
| 1787 | sched->map.cpus = map; | ||
| 1788 | return 0; | ||
| 1789 | } | ||
| 1790 | |||
| 1791 | static int setup_color_pids(struct perf_sched *sched) | ||
| 1792 | { | ||
| 1793 | struct thread_map *map; | ||
| 1794 | |||
| 1795 | if (!sched->map.color_pids_str) | ||
| 1796 | return 0; | ||
| 1797 | |||
| 1798 | map = thread_map__new_by_tid_str(sched->map.color_pids_str); | ||
| 1799 | if (!map) { | ||
| 1800 | pr_err("failed to get thread map from %s\n", sched->map.color_pids_str); | ||
| 1801 | return -1; | ||
| 1802 | } | ||
| 1803 | |||
| 1804 | sched->map.color_pids = map; | ||
| 1805 | return 0; | ||
| 1806 | } | ||
| 1807 | |||
| 1808 | static int setup_color_cpus(struct perf_sched *sched) | ||
| 1809 | { | ||
| 1810 | struct cpu_map *map; | ||
| 1811 | |||
| 1812 | if (!sched->map.color_cpus_str) | ||
| 1813 | return 0; | ||
| 1814 | |||
| 1815 | map = cpu_map__new(sched->map.color_cpus_str); | ||
| 1816 | if (!map) { | ||
| 1817 | pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str); | ||
| 1818 | return -1; | ||
| 1819 | } | ||
| 1820 | |||
| 1821 | sched->map.color_cpus = map; | ||
| 1822 | return 0; | ||
| 1823 | } | ||
| 1824 | |||
| 1678 | static int perf_sched__map(struct perf_sched *sched) | 1825 | static int perf_sched__map(struct perf_sched *sched) |
| 1679 | { | 1826 | { |
| 1680 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1827 | if (setup_map_cpus(sched)) |
| 1828 | return -1; | ||
| 1829 | |||
| 1830 | if (setup_color_pids(sched)) | ||
| 1831 | return -1; | ||
| 1832 | |||
| 1833 | if (setup_color_cpus(sched)) | ||
| 1834 | return -1; | ||
| 1681 | 1835 | ||
| 1682 | setup_pager(); | 1836 | setup_pager(); |
| 1683 | if (perf_sched__read_events(sched)) | 1837 | if (perf_sched__read_events(sched)) |
| @@ -1831,6 +1985,17 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) · 147 unmodified lines | |||
| 1831 | "dump raw trace in ASCII"), | 1985 | "dump raw trace in ASCII"), |
| 1832 | OPT_END() | 1986 | OPT_END() |
| 1833 | }; | 1987 | }; |
| 1988 | const struct option map_options[] = { | ||
| 1989 | OPT_BOOLEAN(0, "compact", &sched.map.comp, | ||
| 1990 | "map output in compact mode"), | ||
| 1991 | OPT_STRING(0, "color-pids", &sched.map.color_pids_str, "pids", | ||
| 1992 | "highlight given pids in map"), | ||
| 1993 | OPT_STRING(0, "color-cpus", &sched.map.color_cpus_str, "cpus", | ||
| 1994 | "highlight given CPUs in map"), | ||
| 1995 | OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus", | ||
| 1996 | "display given CPUs in map"), | ||
| 1997 | OPT_END() | ||
| 1998 | }; | ||
| 1834 | const char * const latency_usage[] = { | 1999 | const char * const latency_usage[] = { |
| 1835 | "perf sched latency [<options>]", | 2000 | "perf sched latency [<options>]", |
| 1836 | NULL | 2001 | NULL |
| @@ -1839,6 +2004,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) · 2 unmodified lines | |||
| 1839 | "perf sched replay [<options>]", | 2004 | "perf sched replay [<options>]", |
| 1840 | NULL | 2005 | NULL |
| 1841 | }; | 2006 | }; |
| 2007 | const char * const map_usage[] = { | ||
| 2008 | "perf sched map [<options>]", | ||
| 2009 | NULL | ||
| 2010 | }; | ||
| 1842 | const char *const sched_subcommands[] = { "record", "latency", "map", | 2011 | const char *const sched_subcommands[] = { "record", "latency", "map", |
| 1843 | "replay", "script", NULL }; | 2012 | "replay", "script", NULL }; |
| 1844 | const char *sched_usage[] = { | 2013 | const char *sched_usage[] = { |
| @@ -1887,6 +2056,11 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) · 42 unmodified lines | |||
| 1887 | setup_sorting(&sched, latency_options, latency_usage); | 2056 | setup_sorting(&sched, latency_options, latency_usage); |
| 1888 | return perf_sched__lat(&sched); | 2057 | return perf_sched__lat(&sched); |
| 1889 | } else if (!strcmp(argv[0], "map")) { | 2058 | } else if (!strcmp(argv[0], "map")) { |
| 2059 | if (argc) { | ||
| 2060 | argc = parse_options(argc, argv, map_options, map_usage, 0); | ||
| 2061 | if (argc) | ||
| 2062 | usage_with_options(map_usage, map_options); | ||
| 2063 | } | ||
| 1890 | sched.tp_handler = &map_ops; | 2064 | sched.tp_handler = &map_ops; |
| 1891 | setup_sorting(&sched, latency_options, latency_usage); | 2065 | setup_sorting(&sched, latency_options, latency_usage); |
| 1892 | return perf_sched__map(&sched); | 2066 | return perf_sched__map(&sched); |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | |||
| 22 | #include "util/thread_map.h" | 22 | #include "util/thread_map.h" |
| 23 | #include "util/stat.h" | 23 | #include "util/stat.h" |
| 24 | #include <linux/bitmap.h> | 24 | #include <linux/bitmap.h> |
| 25 | #include <linux/stringify.h> | ||
| 25 | #include "asm/bug.h" | 26 | #include "asm/bug.h" |
| 26 | #include "util/mem-events.h" | 27 | #include "util/mem-events.h" |
| 27 | 28 | ||
| @@ -317,19 +318,19 @@ static void set_print_ip_opts(struct perf_event_attr *attr) · 289 unmodified lines | |||
| 317 | 318 | ||
| 318 | output[type].print_ip_opts = 0; | 319 | output[type].print_ip_opts = 0; |
| 319 | if (PRINT_FIELD(IP)) | 320 | if (PRINT_FIELD(IP)) |
| 320 | output[type].print_ip_opts |= PRINT_IP_OPT_IP; | 321 | output[type].print_ip_opts |= EVSEL__PRINT_IP; |
| 321 | 322 | ||
| 322 | if (PRINT_FIELD(SYM)) | 323 | if (PRINT_FIELD(SYM)) |
| 323 | output[type].print_ip_opts |= PRINT_IP_OPT_SYM; | 324 | output[type].print_ip_opts |= EVSEL__PRINT_SYM; |
| 324 | 325 | ||
| 325 | if (PRINT_FIELD(DSO)) | 326 | if (PRINT_FIELD(DSO)) |
| 326 | output[type].print_ip_opts |= PRINT_IP_OPT_DSO; | 327 | output[type].print_ip_opts |= EVSEL__PRINT_DSO; |
| 327 | 328 | ||
| 328 | if (PRINT_FIELD(SYMOFFSET)) | 329 | if (PRINT_FIELD(SYMOFFSET)) |
| 329 | output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; | 330 | output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET; |
| 330 | 331 | ||
| 331 | if (PRINT_FIELD(SRCLINE)) | 332 | if (PRINT_FIELD(SRCLINE)) |
| 332 | output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE; | 333 | output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE; |
| 333 | } | 334 | } |
| 334 | 335 | ||
| 335 | /* | 336 | /* |
| @@ -569,18 +570,23 @@ static void print_sample_bts(struct perf_sample *sample, · 233 unmodified lines | |||
| 569 | /* print branch_from information */ | 570 | /* print branch_from information */ |
| 570 | if (PRINT_FIELD(IP)) { | 571 | if (PRINT_FIELD(IP)) { |
| 571 | unsigned int print_opts = output[attr->type].print_ip_opts; | 572 | unsigned int print_opts = output[attr->type].print_ip_opts; |
| 573 | struct callchain_cursor *cursor = NULL; | ||
| 572 | 574 | ||
| 573 | if (symbol_conf.use_callchain && sample->callchain) { | 575 | if (symbol_conf.use_callchain && sample->callchain && |
| 574 | printf("\n"); | 576 | thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
| 575 | } else { | 577 | sample, NULL, NULL, scripting_max_stack) == 0) |
| 576 | printf(" "); | 578 | cursor = &callchain_cursor; |
| 577 | if (print_opts & PRINT_IP_OPT_SRCLINE) { | 579 | |
| 580 | if (cursor == NULL) { | ||
| 581 | putchar(' '); | ||
| 582 | if (print_opts & EVSEL__PRINT_SRCLINE) { | ||
| 578 | print_srcline_last = true; | 583 | print_srcline_last = true; |
| 579 | print_opts &= ~PRINT_IP_OPT_SRCLINE; | 584 | print_opts &= ~EVSEL__PRINT_SRCLINE; |
| 580 | } | 585 | } |
| 581 | } | 586 | } else |
| 582 | perf_evsel__print_ip(evsel, sample, al, print_opts, | 587 | putchar('\n'); |
| 583 | scripting_max_stack); | 588 | |
| 589 | sample__fprintf_sym(sample, al, 0, print_opts, cursor, stdout); | ||
| 584 | } | 590 | } |
| 585 | 591 | ||
| 586 | /* print branch_to information */ | 592 | /* print branch_to information */ |
| @@ -783,14 +789,15 @@ static void process_event(struct perf_script *script, · 196 unmodified lines | |||
| 783 | printf("%16" PRIu64, sample->weight); | 789 | printf("%16" PRIu64, sample->weight); |
| 784 | 790 | ||
| 785 | if (PRINT_FIELD(IP)) { | 791 | if (PRINT_FIELD(IP)) { |
| 786 | if (!symbol_conf.use_callchain) | 792 | struct callchain_cursor *cursor = NULL; |
| 787 | printf(" "); | 793 | |
| 788 | else | 794 | if (symbol_conf.use_callchain && sample->callchain && |
| 789 | printf("\n"); | 795 | thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
| 796 | sample, NULL, NULL, scripting_max_stack) == 0) | ||
| 797 | cursor = &callchain_cursor; | ||
| 790 | 798 | ||
| 791 | perf_evsel__print_ip(evsel, sample, al, | 799 | putchar(cursor ? '\n' : ' '); |
| 792 | output[attr->type].print_ip_opts, | 800 | sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); |
| 793 | scripting_max_stack); | ||
| 794 | } | 801 | } |
| 795 | 802 | ||
| 796 | if (PRINT_FIELD(IREGS)) | 803 | if (PRINT_FIELD(IREGS)) |
| @@ -1959,6 +1966,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) · 1162 unmodified lines | |||
| 1959 | .exit = perf_event__process_exit, | 1966 | .exit = perf_event__process_exit, |
| 1960 | .fork = perf_event__process_fork, | 1967 | .fork = perf_event__process_fork, |
| 1961 | .attr = process_attr, | 1968 | .attr = process_attr, |
| 1969 | .event_update = perf_event__process_event_update, | ||
| 1962 | .tracing_data = perf_event__process_tracing_data, | 1970 | .tracing_data = perf_event__process_tracing_data, |
| 1963 | .build_id = perf_event__process_build_id, | 1971 | .build_id = perf_event__process_build_id, |
| 1964 | .id_index = perf_event__process_id_index, | 1972 | .id_index = perf_event__process_id_index, |
| @@ -2020,6 +2028,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) · 55 unmodified lines | |||
| 2020 | "only consider symbols in these pids"), | 2028 | "only consider symbols in these pids"), |
| 2021 | OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]", | 2029 | OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]", |
| 2022 | "only consider symbols in these tids"), | 2030 | "only consider symbols in these tids"), |
| 2031 | OPT_UINTEGER(0, "max-stack", &scripting_max_stack, | ||
| 2032 | "Set the maximum stack depth when parsing the callchain, " | ||
| 2033 | "anything beyond the specified depth will be ignored. " | ||
| 2034 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), | ||
| 2023 | OPT_BOOLEAN('I', "show-info", &show_full_info, | 2035 | OPT_BOOLEAN('I', "show-info", &show_full_info, |
| 2024 | "display extended information from perf.data file"), | 2036 | "display extended information from perf.data file"), |
| 2025 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, | 2037 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, |
| @@ -2055,6 +2067,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) · 29 unmodified lines | |||
| 2055 | NULL | 2067 | NULL |
| 2056 | }; | 2068 | }; |
| 2057 | 2069 | ||
| 2070 | scripting_max_stack = sysctl_perf_event_max_stack; | ||
| 2071 | |||
| 2058 | setup_scripting(); | 2072 | setup_scripting(); |
| 2059 | 2073 | ||
| 2060 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, | 2074 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, |
| @@ -298,6 +298,14 @@ static int read_counter(struct perf_evsel *counter) · 297 unmodified lines | |||
| 298 | return -1; | 298 | return -1; |
| 299 | } | 299 | } |
| 300 | } | 300 | } |
| 301 | |||
| 302 | if (verbose > 1) { | ||
| 303 | fprintf(stat_config.output, | ||
| 304 | "%s: %d: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", | ||
| 305 | perf_evsel__name(counter), | ||
| 306 | cpu, | ||
| 307 | count->val, count->ena, count->run); | ||
| 308 | } | ||
| 301 | } | 309 | } |
| 302 | } | 310 | } |
| 303 | 311 | ||
| @@ -688,7 +688,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, · 687 unmodified lines | |||
| 688 | struct hist_entry *he = iter->he; | 688 | struct hist_entry *he = iter->he; |
| 689 | struct perf_evsel *evsel = iter->evsel; | 689 | struct perf_evsel *evsel = iter->evsel; |
| 690 | 690 | ||
| 691 | if (sort__has_sym && single) | 691 | if (perf_hpp_list.sym && single) |
| 692 | perf_top__record_precise_ip(top, he, evsel->idx, al->addr); | 692 | perf_top__record_precise_ip(top, he, evsel->idx, al->addr); |
| 693 | 693 | ||
| 694 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, | 694 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, |
| @@ -886,7 +886,7 @@ static int perf_top__start_counters(struct perf_top *top) · 191 unmodified lines | |||
| 886 | struct perf_evlist *evlist = top->evlist; | 886 | struct perf_evlist *evlist = top->evlist; |
| 887 | struct record_opts *opts = &top->record_opts; | 887 | struct record_opts *opts = &top->record_opts; |
| 888 | 888 | ||
| 889 | perf_evlist__config(evlist, opts); | 889 | perf_evlist__config(evlist, opts, &callchain_param); |
| 890 | 890 | ||
| 891 | evlist__for_each(evlist, counter) { | 891 | evlist__for_each(evlist, counter) { |
| 892 | try_again: | 892 | try_again: |
| @@ -917,15 +917,15 @@ out_err: · 24 unmodified lines | |||
| 917 | return -1; | 917 | return -1; |
| 918 | } | 918 | } |
| 919 | 919 | ||
| 920 | static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) | 920 | static int callchain_param__setup_sample_type(struct callchain_param *callchain) |
| 921 | { | 921 | { |
| 922 | if (!sort__has_sym) { | 922 | if (!perf_hpp_list.sym) { |
| 923 | if (symbol_conf.use_callchain) { | 923 | if (callchain->enabled) { |
| 924 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); | 924 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); |
| 925 | return -EINVAL; | 925 | return -EINVAL; |
| 926 | } | 926 | } |
| 927 | } else if (callchain_param.mode != CHAIN_NONE) { | 927 | } else if (callchain->mode != CHAIN_NONE) { |
| 928 | if (callchain_register_param(&callchain_param) < 0) { | 928 | if (callchain_register_param(callchain) < 0) { |
| 929 | ui__error("Can't register callchain params.\n"); | 929 | ui__error("Can't register callchain params.\n"); |
| 930 | return -EINVAL; | 930 | return -EINVAL; |
| 931 | } | 931 | } |
| @@ -952,7 +952,7 @@ static int __cmd_top(struct perf_top *top) · 20 unmodified lines | |||
| 952 | goto out_delete; | 952 | goto out_delete; |
| 953 | } | 953 | } |
| 954 | 954 | ||
| 955 | ret = perf_top__setup_sample_type(top); | 955 | ret = callchain_param__setup_sample_type(&callchain_param); |
| 956 | if (ret) | 956 | if (ret) |
| 957 | goto out_delete; | 957 | goto out_delete; |
| 958 | 958 | ||
| @@ -962,7 +962,7 @@ static int __cmd_top(struct perf_top *top) · 3 unmodified lines | |||
| 962 | machine__synthesize_threads(&top->session->machines.host, &opts->target, | 962 | machine__synthesize_threads(&top->session->machines.host, &opts->target, |
| 963 | top->evlist->threads, false, opts->proc_map_timeout); | 963 | top->evlist->threads, false, opts->proc_map_timeout); |
| 964 | 964 | ||
| 965 | if (sort__has_socket) { | 965 | if (perf_hpp_list.socket) { |
| 966 | ret = perf_env__read_cpu_topology_map(&perf_env); | 966 | ret = perf_env__read_cpu_topology_map(&perf_env); |
| 967 | if (ret < 0) | 967 | if (ret < 0) |
| 968 | goto out_err_cpu_topo; | 968 | goto out_err_cpu_topo; |
| @@ -1045,18 +1045,17 @@ callchain_opt(const struct option *opt, const char *arg, int unset) · 76 unmodified lines | |||
| 1045 | static int | 1045 | static int |
| 1046 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1046 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
| 1047 | { | 1047 | { |
| 1048 | struct record_opts *record = (struct record_opts *)opt->value; | 1048 | struct callchain_param *callchain = opt->value; |
| 1049 | 1049 | ||
| 1050 | record->callgraph_set = true; | 1050 | callchain->enabled = !unset; |
| 1051 | callchain_param.enabled = !unset; | 1051 | callchain->record_mode = CALLCHAIN_FP; |
| 1052 | callchain_param.record_mode = CALLCHAIN_FP; | ||
| 1053 | 1052 | ||
| 1054 | /* | 1053 | /* |
| 1055 | * --no-call-graph | 1054 | * --no-call-graph |
| 1056 | */ | 1055 | */ |
| 1057 | if (unset) { | 1056 | if (unset) { |
| 1058 | symbol_conf.use_callchain = false; | 1057 | symbol_conf.use_callchain = false; |
| 1059 | callchain_param.record_mode = CALLCHAIN_NONE; | 1058 | callchain->record_mode = CALLCHAIN_NONE; |
| 1060 | return 0; | 1059 | return 0; |
| 1061 | } | 1060 | } |
| 1062 | 1061 | ||
| @@ -1104,7 +1103,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) · 41 unmodified lines | |||
| 1104 | }, | 1103 | }, |
| 1105 | .proc_map_timeout = 500, | 1104 | .proc_map_timeout = 500, |
| 1106 | }, | 1105 | }, |
| 1107 | .max_stack = PERF_MAX_STACK_DEPTH, | 1106 | .max_stack = sysctl_perf_event_max_stack, |
| 1108 | .sym_pcnt_filter = 5, | 1107 | .sym_pcnt_filter = 5, |
| 1109 | }; | 1108 | }; |
| 1110 | struct record_opts *opts = &top.record_opts; | 1109 | struct record_opts *opts = &top.record_opts; |
| @@ -1162,17 +1161,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) · 51 unmodified lines | |||
| 1162 | "output field(s): overhead, period, sample plus all of sort keys"), | 1161 | "output field(s): overhead, period, sample plus all of sort keys"), |
| 1163 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1162 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
| 1164 | "Show a column with the number of samples"), | 1163 | "Show a column with the number of samples"), |
| 1165 | OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, | 1164 | OPT_CALLBACK_NOOPT('g', NULL, &callchain_param, |
| 1166 | NULL, "enables call-graph recording and display", | 1165 | NULL, "enables call-graph recording and display", |
| 1167 | &callchain_opt), | 1166 | &callchain_opt), |
| 1168 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | 1167 | OPT_CALLBACK(0, "call-graph", &callchain_param, |
| 1169 | "record_mode[,record_size],print_type,threshold[,print_limit],order,sort_key[,branch]", | 1168 | "record_mode[,record_size],print_type,threshold[,print_limit],order,sort_key[,branch]", |
| 1170 | top_callchain_help, &parse_callchain_opt), | 1169 | top_callchain_help, &parse_callchain_opt), |
| 1171 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, | 1170 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, |
| 1172 | "Accumulate callchains of children and show total overhead as well"), | 1171 | "Accumulate callchains of children and show total overhead as well"), |
| 1173 | OPT_INTEGER(0, "max-stack", &top.max_stack, | 1172 | OPT_INTEGER(0, "max-stack", &top.max_stack, |
| 1174 | "Set the maximum stack depth when parsing the callchain. " | 1173 | "Set the maximum stack depth when parsing the callchain. " |
| 1175 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 1174 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
| 1176 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 1175 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
| 1177 | "ignore callees of these functions in call graphs", | 1176 | "ignore callees of these functions in call graphs", |
| 1178 | report_parse_ignore_callees_opt), | 1177 | report_parse_ignore_callees_opt), |
| @@ -1256,7 +1255,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) · 77 unmodified lines | |||
| 1256 | 1255 | ||
| 1257 | sort__mode = SORT_MODE__TOP; | 1256 | sort__mode = SORT_MODE__TOP; |
| 1258 | /* display thread wants entries to be collapsed in a different tree */ | 1257 | /* display thread wants entries to be collapsed in a different tree */ |
| 1259 | sort__need_collapse = 1; | 1258 | perf_hpp_list.need_collapse = 1; |
| 1260 | 1259 | ||
| 1261 | if (top.use_stdio) | 1260 | if (top.use_stdio) |
| 1262 | use_browser = 0; | 1261 | use_browser = 0; |
| @@ -1312,7 +1311,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) · 49 unmodified lines | |||
| 1312 | 1311 | ||
| 1313 | top.sym_evsel = perf_evlist__first(top.evlist); | 1312 | top.sym_evsel = perf_evlist__first(top.evlist); |
| 1314 | 1313 | ||
| 1315 | if (!symbol_conf.use_callchain) { | 1314 | if (!callchain_param.enabled) { |
| 1316 | symbol_conf.cumulate_callchain = false; | 1315 | symbol_conf.cumulate_callchain = false; |
| 1317 | perf_hpp__cancel_cumulate(); | 1316 | perf_hpp__cancel_cumulate(); |
| 1318 | } | 1317 | } |
| @@ -34,79 +34,76 @@ · 33 unmodified lines | |||
| 34 | #include "trace-event.h" | 34 | #include "trace-event.h" |
| 35 | #include "util/parse-events.h" | 35 | #include "util/parse-events.h" |
| 36 | #include "util/bpf-loader.h" | 36 | #include "util/bpf-loader.h" |
| 37 | #include "callchain.h" | ||
| 38 | #include "syscalltbl.h" | ||
| 39 | #include "rb_resort.h" | ||
| 37 | 40 | ||
| 38 | #include <libaudit.h> | 41 | #include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ |
| 39 | #include <stdlib.h> | 42 | #include <stdlib.h> |
| 40 | #include <sys/mman.h> | ||
| 41 | #include <linux/futex.h> | ||
| 42 | #include <linux/err.h> | 43 | #include <linux/err.h> |
| 43 | 44 | #include <linux/filter.h> | |
| 44 | /* For older distros: */ | 45 | #include <linux/audit.h> |
| 45 | #ifndef MAP_STACK | 46 | #include <sys/ptrace.h> |
| 46 | # define MAP_STACK 0x20000 | 47 | #include <linux/random.h> |
| 47 | #endif | 48 | #include <linux/stringify.h> |
| 48 | |||
| 49 | #ifndef MADV_HWPOISON | ||
| 50 | # define MADV_HWPOISON 100 | ||
| 51 | |||
| 52 | #endif | ||
| 53 | |||
| 54 | #ifndef MADV_MERGEABLE | ||
| 55 | # define MADV_MERGEABLE 12 | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #ifndef MADV_UNMERGEABLE | ||
| 59 | # define MADV_UNMERGEABLE 13 | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #ifndef EFD_SEMAPHORE | ||
| 63 | # define EFD_SEMAPHORE 1 | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifndef EFD_NONBLOCK | ||
| 67 | # define EFD_NONBLOCK 00004000 | ||
| 68 | #endif | ||
| 69 | |||
| 70 | #ifndef EFD_CLOEXEC | ||
| 71 | # define EFD_CLOEXEC 02000000 | ||
| 72 | #endif | ||
| 73 | 49 | ||
| 74 | #ifndef O_CLOEXEC | 50 | #ifndef O_CLOEXEC |
| 75 | # define O_CLOEXEC 02000000 | 51 | # define O_CLOEXEC 02000000 |
| 76 | #endif | 52 | #endif |
| 77 | 53 | ||
| 78 | #ifndef SOCK_DCCP | 54 | struct trace { |
| 79 | # define SOCK_DCCP 6 | 55 | struct perf_tool tool; |
| 80 | #endif | 56 | struct syscalltbl *sctbl; |
| 81 | 57 | struct { | |
| 82 | #ifndef SOCK_CLOEXEC | 58 | int max; |
| 83 | # define SOCK_CLOEXEC 02000000 | 59 | struct syscall *table; |
| 84 | #endif | 60 | struct { |
| 85 | 61 | struct perf_evsel *sys_enter, | |
| 86 | #ifndef SOCK_NONBLOCK | 62 | *sys_exit; |
| 87 | # define SOCK_NONBLOCK 00004000 | 63 | } events; |
| 88 | #endif | 64 | } syscalls; |
| 89 | 65 | struct record_opts opts; | |
| 90 | #ifndef MSG_CMSG_CLOEXEC | 66 | struct perf_evlist *evlist; |
| 91 | # define MSG_CMSG_CLOEXEC 0x40000000 | 67 | struct machine *host; |
| 92 | #endif | 68 | struct thread *current; |
| 93 | 69 | u64 base_time; | |
| 94 | #ifndef PERF_FLAG_FD_NO_GROUP | 70 | FILE *output; |
| 95 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) | 71 | unsigned long nr_events; |
| 96 | #endif | 72 | struct strlist *ev_qualifier; |
| 97 | 73 | struct { | |
| 98 | #ifndef PERF_FLAG_FD_OUTPUT | 74 | size_t nr; |
| 99 | # define PERF_FLAG_FD_OUTPUT (1UL << 1) | 75 | int *entries; |
| 100 | #endif | 76 | } ev_qualifier_ids; |
| 101 | 77 | struct intlist *tid_list; | |
| 102 | #ifndef PERF_FLAG_PID_CGROUP | 78 | struct intlist *pid_list; |
| 103 | # define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ | 79 | struct { |
| 104 | #endif | 80 | size_t nr; |
| 105 | 81 | pid_t *entries; | |
| 106 | #ifndef PERF_FLAG_FD_CLOEXEC | 82 | } filter_pids; |
| 107 | # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ | 83 | double duration_filter; |
| 108 | #endif | 84 | double runtime_ms; |
| 109 | 85 | struct { | |
| 86 | u64 vfs_getname, | ||
| 87 | proc_getname; | ||
| 88 | } stats; | ||
| 89 | unsigned int max_stack; | ||
| 90 | unsigned int min_stack; | ||
| 91 | bool not_ev_qualifier; | ||
| 92 | bool live; | ||
| 93 | bool full_time; | ||
| 94 | bool sched; | ||
| 95 | bool multiple_threads; | ||
| 96 | bool summary; | ||
| 97 | bool summary_only; | ||
| 98 | bool show_comm; | ||
| 99 | bool show_tool_stats; | ||
| 100 | bool trace_syscalls; | ||
| 101 | bool kernel_syscallchains; | ||
| 102 | bool force; | ||
| 103 | bool vfs_getname; | ||
| 104 | int trace_pgfaults; | ||
| 105 | int open_id; | ||
| 106 | }; | ||
| 110 | 107 | ||
| 111 | struct tp_field { | 108 | struct tp_field { |
| 112 | int offset; | 109 | int offset; |
| @@ -371,221 +368,6 @@ static size_t syscall_arg__scnprintf_int(char *bf, size_t size, · 258 unmodified lines | |||
| 371 | 368 | ||
| 372 | #define SCA_INT syscall_arg__scnprintf_int | 369 | #define SCA_INT syscall_arg__scnprintf_int |
| 373 | 370 | ||
| 374 | static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, | ||
| 375 | struct syscall_arg *arg) | ||
| 376 | { | ||
| 377 | int printed = 0, prot = arg->val; | ||
| 378 | |||
| 379 | if (prot == PROT_NONE) | ||
| 380 | return scnprintf(bf, size, "NONE"); | ||
| 381 | #define P_MMAP_PROT(n) \ | ||
| 382 | if (prot & PROT_##n) { \ | ||
| 383 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 384 | prot &= ~PROT_##n; \ | ||
| 385 | } | ||
| 386 | |||
| 387 | P_MMAP_PROT(EXEC); | ||
| 388 | P_MMAP_PROT(READ); | ||
| 389 | P_MMAP_PROT(WRITE); | ||
| 390 | #ifdef PROT_SEM | ||
| 391 | P_MMAP_PROT(SEM); | ||
| 392 | #endif | ||
| 393 | P_MMAP_PROT(GROWSDOWN); | ||
| 394 | P_MMAP_PROT(GROWSUP); | ||
| 395 | #undef P_MMAP_PROT | ||
| 396 | |||
| 397 | if (prot) | ||
| 398 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot); | ||
| 399 | |||
| 400 | return printed; | ||
| 401 | } | ||
| 402 | |||
| 403 | #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot | ||
| 404 | |||
| 405 | static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | ||
| 406 | struct syscall_arg *arg) | ||
| 407 | { | ||
| 408 | int printed = 0, flags = arg->val; | ||
| 409 | |||
| 410 | #define P_MMAP_FLAG(n) \ | ||
| 411 | if (flags & MAP_##n) { \ | ||
| 412 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 413 | flags &= ~MAP_##n; \ | ||
| 414 | } | ||
| 415 | |||
| 416 | P_MMAP_FLAG(SHARED); | ||
| 417 | P_MMAP_FLAG(PRIVATE); | ||
| 418 | #ifdef MAP_32BIT | ||
| 419 | P_MMAP_FLAG(32BIT); | ||
| 420 | #endif | ||
| 421 | P_MMAP_FLAG(ANONYMOUS); | ||
| 422 | P_MMAP_FLAG(DENYWRITE); | ||
| 423 | P_MMAP_FLAG(EXECUTABLE); | ||
| 424 | P_MMAP_FLAG(FILE); | ||
| 425 | P_MMAP_FLAG(FIXED); | ||
| 426 | P_MMAP_FLAG(GROWSDOWN); | ||
| 427 | #ifdef MAP_HUGETLB | ||
| 428 | P_MMAP_FLAG(HUGETLB); | ||
| 429 | #endif | ||
| 430 | P_MMAP_FLAG(LOCKED); | ||
| 431 | P_MMAP_FLAG(NONBLOCK); | ||
| 432 | P_MMAP_FLAG(NORESERVE); | ||
| 433 | P_MMAP_FLAG(POPULATE); | ||
| 434 | P_MMAP_FLAG(STACK); | ||
| 435 | #ifdef MAP_UNINITIALIZED | ||
| 436 | P_MMAP_FLAG(UNINITIALIZED); | ||
| 437 | #endif | ||
| 438 | #undef P_MMAP_FLAG | ||
| 439 | |||
| 440 | if (flags) | ||
| 441 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 442 | |||
| 443 | return printed; | ||
| 444 | } | ||
| 445 | |||
| 446 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags | ||
| 447 | |||
| 448 | static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, | ||
| 449 | struct syscall_arg *arg) | ||
| 450 | { | ||
| 451 | int printed = 0, flags = arg->val; | ||
| 452 | |||
| 453 | #define P_MREMAP_FLAG(n) \ | ||
| 454 | if (flags & MREMAP_##n) { \ | ||
| 455 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 456 | flags &= ~MREMAP_##n; \ | ||
| 457 | } | ||
| 458 | |||
| 459 | P_MREMAP_FLAG(MAYMOVE); | ||
| 460 | #ifdef MREMAP_FIXED | ||
| 461 | P_MREMAP_FLAG(FIXED); | ||
| 462 | #endif | ||
| 463 | #undef P_MREMAP_FLAG | ||
| 464 | |||
| 465 | if (flags) | ||
| 466 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 467 | |||
| 468 | return printed; | ||
| 469 | } | ||
| 470 | |||
| 471 | #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags | ||
| 472 | |||
| 473 | static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, | ||
| 474 | struct syscall_arg *arg) | ||
| 475 | { | ||
| 476 | int behavior = arg->val; | ||
| 477 | |||
| 478 | switch (behavior) { | ||
| 479 | #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) | ||
| 480 | P_MADV_BHV(NORMAL); | ||
| 481 | P_MADV_BHV(RANDOM); | ||
| 482 | P_MADV_BHV(SEQUENTIAL); | ||
| 483 | P_MADV_BHV(WILLNEED); | ||
| 484 | P_MADV_BHV(DONTNEED); | ||
| 485 | P_MADV_BHV(REMOVE); | ||
| 486 | P_MADV_BHV(DONTFORK); | ||
| 487 | P_MADV_BHV(DOFORK); | ||
| 488 | P_MADV_BHV(HWPOISON); | ||
| 489 | #ifdef MADV_SOFT_OFFLINE | ||
| 490 | P_MADV_BHV(SOFT_OFFLINE); | ||
| 491 | #endif | ||
| 492 | P_MADV_BHV(MERGEABLE); | ||
| 493 | P_MADV_BHV(UNMERGEABLE); | ||
| 494 | #ifdef MADV_HUGEPAGE | ||
| 495 | P_MADV_BHV(HUGEPAGE); | ||
| 496 | #endif | ||
| 497 | #ifdef MADV_NOHUGEPAGE | ||
| 498 | P_MADV_BHV(NOHUGEPAGE); | ||
| 499 | #endif | ||
| 500 | #ifdef MADV_DONTDUMP | ||
| 501 | P_MADV_BHV(DONTDUMP); | ||
| 502 | #endif | ||
| 503 | #ifdef MADV_DODUMP | ||
| 504 | P_MADV_BHV(DODUMP); | ||
| 505 | #endif | ||
| 506 | #undef P_MADV_PHV | ||
| 507 | default: break; | ||
| 508 | } | ||
| 509 | |||
| 510 | return scnprintf(bf, size, "%#x", behavior); | ||
| 511 | } | ||
| 512 | |||
| 513 | #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior | ||
| 514 | |||
| 515 | static size_t syscall_arg__scnprintf_flock(char *bf, size_t size, | ||
| 516 | struct syscall_arg *arg) | ||
| 517 | { | ||
| 518 | int printed = 0, op = arg->val; | ||
| 519 | |||
| 520 | if (op == 0) | ||
| 521 | return scnprintf(bf, size, "NONE"); | ||
| 522 | #define P_CMD(cmd) \ | ||
| 523 | if ((op & LOCK_##cmd) == LOCK_##cmd) { \ | ||
| 524 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \ | ||
| 525 | op &= ~LOCK_##cmd; \ | ||
| 526 | } | ||
| 527 | |||
| 528 | P_CMD(SH); | ||
| 529 | P_CMD(EX); | ||
| 530 | P_CMD(NB); | ||
| 531 | P_CMD(UN); | ||
| 532 | P_CMD(MAND); | ||
| 533 | P_CMD(RW); | ||
| 534 | P_CMD(READ); | ||
| 535 | P_CMD(WRITE); | ||
| 536 | #undef P_OP | ||
| 537 | |||
| 538 | if (op) | ||
| 539 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op); | ||
| 540 | |||
| 541 | return printed; | ||
| 542 | } | ||
| 543 | |||
| 544 | #define SCA_FLOCK syscall_arg__scnprintf_flock | ||
| 545 | |||
| 546 | static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg) | ||
| 547 | { | ||
| 548 | enum syscall_futex_args { | ||
| 549 | SCF_UADDR = (1 << 0), | ||
| 550 | SCF_OP = (1 << 1), | ||
| 551 | SCF_VAL = (1 << 2), | ||
| 552 | SCF_TIMEOUT = (1 << 3), | ||
| 553 | SCF_UADDR2 = (1 << 4), | ||
| 554 | SCF_VAL3 = (1 << 5), | ||
| 555 | }; | ||
| 556 | int op = arg->val; | ||
| 557 | int cmd = op & FUTEX_CMD_MASK; | ||
| 558 | size_t printed = 0; | ||
| 559 | |||
| 560 | switch (cmd) { | ||
| 561 | #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n); | ||
| 562 | P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
| 563 | P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 564 | P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 565 | P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break; | ||
| 566 | P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break; | ||
| 567 | P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break; | ||
| 568 | P_FUTEX_OP(WAKE_OP); break; | ||
| 569 | P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 570 | P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 571 | P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
| 572 | P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break; | ||
| 573 | P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break; | ||
| 574 | P_FUTEX_OP(WAIT_REQUEUE_PI); break; | ||
| 575 | default: printed = scnprintf(bf, size, "%#x", cmd); break; | ||
| 576 | } | ||
| 577 | |||
| 578 | if (op & FUTEX_PRIVATE_FLAG) | ||
| 579 | printed += scnprintf(bf + printed, size - printed, "|PRIV"); | ||
| 580 | |||
| 581 | if (op & FUTEX_CLOCK_REALTIME) | ||
| 582 | printed += scnprintf(bf + printed, size - printed, "|CLKRT"); | ||
| 583 | |||
| 584 | return printed; | ||
| 585 | } | ||
| 586 | |||
| 587 | #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op | ||
| 588 | |||
| 589 | static const char *bpf_cmd[] = { | 371 | static const char *bpf_cmd[] = { |
| 590 | "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM", | 372 | "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM", |
| 591 | "MAP_GET_NEXT_KEY", "PROG_LOAD", | 373 | "MAP_GET_NEXT_KEY", "PROG_LOAD", |
| @@ -652,110 +434,6 @@ static const char *socket_families[] = { · 60 unmodified lines | |||
| 652 | }; | 434 | }; |
| 653 | static DEFINE_STRARRAY(socket_families); | 435 | static DEFINE_STRARRAY(socket_families); |
| 654 | 436 | ||
| 655 | #ifndef SOCK_TYPE_MASK | ||
| 656 | #define SOCK_TYPE_MASK 0xf | ||
| 657 | #endif | ||
| 658 | |||
| 659 | static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size, | ||
| 660 | struct syscall_arg *arg) | ||
| 661 | { | ||
| 662 | size_t printed; | ||
| 663 | int type = arg->val, | ||
| 664 | flags = type & ~SOCK_TYPE_MASK; | ||
| 665 | |||
| 666 | type &= SOCK_TYPE_MASK; | ||
| 667 | /* | ||
| 668 | * Can't use a strarray, MIPS may override for ABI reasons. | ||
| 669 | */ | ||
| 670 | switch (type) { | ||
| 671 | #define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break; | ||
| 672 | P_SK_TYPE(STREAM); | ||
| 673 | P_SK_TYPE(DGRAM); | ||
| 674 | P_SK_TYPE(RAW); | ||
| 675 | P_SK_TYPE(RDM); | ||
| 676 | P_SK_TYPE(SEQPACKET); | ||
| 677 | P_SK_TYPE(DCCP); | ||
| 678 | P_SK_TYPE(PACKET); | ||
| 679 | #undef P_SK_TYPE | ||
| 680 | default: | ||
| 681 | printed = scnprintf(bf, size, "%#x", type); | ||
| 682 | } | ||
| 683 | |||
| 684 | #define P_SK_FLAG(n) \ | ||
| 685 | if (flags & SOCK_##n) { \ | ||
| 686 | printed += scnprintf(bf + printed, size - printed, "|%s", #n); \ | ||
| 687 | flags &= ~SOCK_##n; \ | ||
| 688 | } | ||
| 689 | |||
| 690 | P_SK_FLAG(CLOEXEC); | ||
| 691 | P_SK_FLAG(NONBLOCK); | ||
| 692 | #undef P_SK_FLAG | ||
| 693 | |||
| 694 | if (flags) | ||
| 695 | printed += scnprintf(bf + printed, size - printed, "|%#x", flags); | ||
| 696 | |||
| 697 | return printed; | ||
| 698 | } | ||
| 699 | |||
| 700 | #define SCA_SK_TYPE syscall_arg__scnprintf_socket_type | ||
| 701 | |||
| 702 | #ifndef MSG_PROBE | ||
| 703 | #define MSG_PROBE 0x10 | ||
| 704 | #endif | ||
| 705 | #ifndef MSG_WAITFORONE | ||
| 706 | #define MSG_WAITFORONE 0x10000 | ||
| 707 | #endif | ||
| 708 | #ifndef MSG_SENDPAGE_NOTLAST | ||
| 709 | #define MSG_SENDPAGE_NOTLAST 0x20000 | ||
| 710 | #endif | ||
| 711 | #ifndef MSG_FASTOPEN | ||
| 712 | #define MSG_FASTOPEN 0x20000000 | ||
| 713 | #endif | ||
| 714 | |||
| 715 | static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, | ||
| 716 | struct syscall_arg *arg) | ||
| 717 | { | ||
| 718 | int printed = 0, flags = arg->val; | ||
| 719 | |||
| 720 | if (flags == 0) | ||
| 721 | return scnprintf(bf, size, "NONE"); | ||
| 722 | #define P_MSG_FLAG(n) \ | ||
| 723 | if (flags & MSG_##n) { \ | ||
| 724 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 725 | flags &= ~MSG_##n; \ | ||
| 726 | } | ||
| 727 | |||
| 728 | P_MSG_FLAG(OOB); | ||
| 729 | P_MSG_FLAG(PEEK); | ||
| 730 | P_MSG_FLAG(DONTROUTE); | ||
| 731 | P_MSG_FLAG(TRYHARD); | ||
| 732 | P_MSG_FLAG(CTRUNC); | ||
| 733 | P_MSG_FLAG(PROBE); | ||
| 734 | P_MSG_FLAG(TRUNC); | ||
| 735 | P_MSG_FLAG(DONTWAIT); | ||
| 736 | P_MSG_FLAG(EOR); | ||
| 737 | P_MSG_FLAG(WAITALL); | ||
| 738 | P_MSG_FLAG(FIN); | ||
| 739 | P_MSG_FLAG(SYN); | ||
| 740 | P_MSG_FLAG(CONFIRM); | ||
| 741 | P_MSG_FLAG(RST); | ||
| 742 | P_MSG_FLAG(ERRQUEUE); | ||
| 743 | P_MSG_FLAG(NOSIGNAL); | ||
| 744 | P_MSG_FLAG(MORE); | ||
| 745 | P_MSG_FLAG(WAITFORONE); | ||
| 746 | P_MSG_FLAG(SENDPAGE_NOTLAST); | ||
| 747 | P_MSG_FLAG(FASTOPEN); | ||
| 748 | P_MSG_FLAG(CMSG_CLOEXEC); | ||
| 749 | #undef P_MSG_FLAG | ||
| 750 | |||
| 751 | if (flags) | ||
| 752 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 753 | |||
| 754 | return printed; | ||
| 755 | } | ||
| 756 | |||
| 757 | #define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags | ||
| 758 | |||
| 759 | static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size, | 437 | static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size, |
| 760 | struct syscall_arg *arg) | 438 | struct syscall_arg *arg) |
| 761 | { | 439 | { |
| @@ -788,116 +466,6 @@ static size_t syscall_arg__scnprintf_filename(char *bf, size_t size, · 26 unmodified lines | |||
| 788 | 466 | ||
| 789 | #define SCA_FILENAME syscall_arg__scnprintf_filename | 467 | #define SCA_FILENAME syscall_arg__scnprintf_filename |
| 790 | 468 | ||
| 791 | static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, | ||
| 792 | struct syscall_arg *arg) | ||
| 793 | { | ||
| 794 | int printed = 0, flags = arg->val; | ||
| 795 | |||
| 796 | if (!(flags & O_CREAT)) | ||
| 797 | arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */ | ||
| 798 | |||
| 799 | if (flags == 0) | ||
| 800 | return scnprintf(bf, size, "RDONLY"); | ||
| 801 | #define P_FLAG(n) \ | ||
| 802 | if (flags & O_##n) { \ | ||
| 803 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 804 | flags &= ~O_##n; \ | ||
| 805 | } | ||
| 806 | |||
| 807 | P_FLAG(APPEND); | ||
| 808 | P_FLAG(ASYNC); | ||
| 809 | P_FLAG(CLOEXEC); | ||
| 810 | P_FLAG(CREAT); | ||
| 811 | P_FLAG(DIRECT); | ||
| 812 | P_FLAG(DIRECTORY); | ||
| 813 | P_FLAG(EXCL); | ||
| 814 | P_FLAG(LARGEFILE); | ||
| 815 | P_FLAG(NOATIME); | ||
| 816 | P_FLAG(NOCTTY); | ||
| 817 | #ifdef O_NONBLOCK | ||
| 818 | P_FLAG(NONBLOCK); | ||
| 819 | #elif O_NDELAY | ||
| 820 | P_FLAG(NDELAY); | ||
| 821 | #endif | ||
| 822 | #ifdef O_PATH | ||
| 823 | P_FLAG(PATH); | ||
| 824 | #endif | ||
| 825 | P_FLAG(RDWR); | ||
| 826 | #ifdef O_DSYNC | ||
| 827 | if ((flags & O_SYNC) == O_SYNC) | ||
| 828 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC"); | ||
| 829 | else { | ||
| 830 | P_FLAG(DSYNC); | ||
| 831 | } | ||
| 832 | #else | ||
| 833 | P_FLAG(SYNC); | ||
| 834 | #endif | ||
| 835 | P_FLAG(TRUNC); | ||
| 836 | P_FLAG(WRONLY); | ||
| 837 | #undef P_FLAG | ||
| 838 | |||
| 839 | if (flags) | ||
| 840 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 841 | |||
| 842 | return printed; | ||
| 843 | } | ||
| 844 | |||
| 845 | #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags | ||
| 846 | |||
| 847 | static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, | ||
| 848 | struct syscall_arg *arg) | ||
| 849 | { | ||
| 850 | int printed = 0, flags = arg->val; | ||
| 851 | |||
| 852 | if (flags == 0) | ||
| 853 | return 0; | ||
| 854 | |||
| 855 | #define P_FLAG(n) \ | ||
| 856 | if (flags & PERF_FLAG_##n) { \ | ||
| 857 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 858 | flags &= ~PERF_FLAG_##n; \ | ||
| 859 | } | ||
| 860 | |||
| 861 | P_FLAG(FD_NO_GROUP); | ||
| 862 | P_FLAG(FD_OUTPUT); | ||
| 863 | P_FLAG(PID_CGROUP); | ||
| 864 | P_FLAG(FD_CLOEXEC); | ||
| 865 | #undef P_FLAG | ||
| 866 | |||
| 867 | if (flags) | ||
| 868 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 869 | |||
| 870 | return printed; | ||
| 871 | } | ||
| 872 | |||
| 873 | #define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags | ||
| 874 | |||
| 875 | static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size, | ||
| 876 | struct syscall_arg *arg) | ||
| 877 | { | ||
| 878 | int printed = 0, flags = arg->val; | ||
| 879 | |||
| 880 | if (flags == 0) | ||
| 881 | return scnprintf(bf, size, "NONE"); | ||
| 882 | #define P_FLAG(n) \ | ||
| 883 | if (flags & EFD_##n) { \ | ||
| 884 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 885 | flags &= ~EFD_##n; \ | ||
| 886 | } | ||
| 887 | |||
| 888 | P_FLAG(SEMAPHORE); | ||
| 889 | P_FLAG(CLOEXEC); | ||
| 890 | P_FLAG(NONBLOCK); | ||
| 891 | #undef P_FLAG | ||
| 892 | |||
| 893 | if (flags) | ||
| 894 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 895 | |||
| 896 | return printed; | ||
| 897 | } | ||
| 898 | |||
| 899 | #define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags | ||
| 900 | |||
| 901 | static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, | 469 | static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, |
| 902 | struct syscall_arg *arg) | 470 | struct syscall_arg *arg) |
| 903 | { | 471 | { |
| @@ -921,59 +489,6 @@ static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, · 17 unmodified lines | |||
| 921 | 489 | ||
| 922 | #define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags | 490 | #define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags |
| 923 | 491 | ||
| 924 | static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) | ||
| 925 | { | ||
| 926 | int sig = arg->val; | ||
| 927 | |||
| 928 | switch (sig) { | ||
| 929 | #define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n) | ||
| 930 | P_SIGNUM(HUP); | ||
| 931 | P_SIGNUM(INT); | ||
| 932 | P_SIGNUM(QUIT); | ||
| 933 | P_SIGNUM(ILL); | ||
| 934 | P_SIGNUM(TRAP); | ||
| 935 | P_SIGNUM(ABRT); | ||
| 936 | P_SIGNUM(BUS); | ||
| 937 | P_SIGNUM(FPE); | ||
| 938 | P_SIGNUM(KILL); | ||
| 939 | P_SIGNUM(USR1); | ||
| 940 | P_SIGNUM(SEGV); | ||
| 941 | P_SIGNUM(USR2); | ||
| 942 | P_SIGNUM(PIPE); | ||
| 943 | P_SIGNUM(ALRM); | ||
| 944 | P_SIGNUM(TERM); | ||
| 945 | P_SIGNUM(CHLD); | ||
| 946 | P_SIGNUM(CONT); | ||
| 947 | P_SIGNUM(STOP); | ||
| 948 | P_SIGNUM(TSTP); | ||
| 949 | P_SIGNUM(TTIN); | ||
| 950 | P_SIGNUM(TTOU); | ||
| 951 | P_SIGNUM(URG); | ||
| 952 | P_SIGNUM(XCPU); | ||
| 953 | P_SIGNUM(XFSZ); | ||
| 954 | P_SIGNUM(VTALRM); | ||
| 955 | P_SIGNUM(PROF); | ||
| 956 | P_SIGNUM(WINCH); | ||
| 957 | P_SIGNUM(IO); | ||
| 958 | P_SIGNUM(PWR); | ||
| 959 | P_SIGNUM(SYS); | ||
| 960 | #ifdef SIGEMT | ||
| 961 | P_SIGNUM(EMT); | ||
| 962 | #endif | ||
| 963 | #ifdef SIGSTKFLT | ||
| 964 | P_SIGNUM(STKFLT); | ||
| 965 | #endif | ||
| 966 | #ifdef SIGSWI | ||
| 967 | P_SIGNUM(SWI); | ||
| 968 | #endif | ||
| 969 | default: break; | ||
| 970 | } | ||
| 971 | |||
| 972 | return scnprintf(bf, size, "%#x", sig); | ||
| 973 | } | ||
| 974 | |||
| 975 | #define SCA_SIGNUM syscall_arg__scnprintf_signum | ||
| 976 | |||
| 977 | #if defined(__i386__) || defined(__x86_64__) | 492 | #if defined(__i386__) || defined(__x86_64__) |
| 978 | /* | 493 | /* |
| 979 | * FIXME: Make this available to all arches. | 494 | * FIXME: Make this available to all arches. |
| @@ -1001,16 +516,62 @@ static const char *tioctls[] = { · 21 unmodified lines | |||
| 1001 | static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); | 516 | static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); |
| 1002 | #endif /* defined(__i386__) || defined(__x86_64__) */ | 517 | #endif /* defined(__i386__) || defined(__x86_64__) */ |
| 1003 | 518 | ||
| 519 | #ifndef GRND_NONBLOCK | ||
| 520 | #define GRND_NONBLOCK 0x0001 | ||
| 521 | #endif | ||
| 522 | #ifndef GRND_RANDOM | ||
| 523 | #define GRND_RANDOM 0x0002 | ||
| 524 | #endif | ||
| 525 | |||
| 526 | static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, | ||
| 527 | struct syscall_arg *arg) | ||
| 528 | { | ||
| 529 | int printed = 0, flags = arg->val; | ||
| 530 | |||
| 531 | #define P_FLAG(n) \ | ||
| 532 | if (flags & GRND_##n) { \ | ||
| 533 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 534 | flags &= ~GRND_##n; \ | ||
| 535 | } | ||
| 536 | |||
| 537 | P_FLAG(RANDOM); | ||
| 538 | P_FLAG(NONBLOCK); | ||
| 539 | #undef P_FLAG | ||
| 540 | |||
| 541 | if (flags) | ||
| 542 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 543 | |||
| 544 | return printed; | ||
| 545 | } | ||
| 546 | |||
| 547 | #define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags | ||
| 548 | |||
| 1004 | #define STRARRAY(arg, name, array) \ | 549 | #define STRARRAY(arg, name, array) \ |
| 1005 | .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ | 550 | .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ |
| 1006 | .arg_parm = { [arg] = &strarray__##array, } | 551 | .arg_parm = { [arg] = &strarray__##array, } |
| 1007 | 552 | ||
| 553 | #include "trace/beauty/eventfd.c" | ||
| 554 | #include "trace/beauty/flock.c" | ||
| 555 | #include "trace/beauty/futex_op.c" | ||
| 556 | #include "trace/beauty/mmap.c" | ||
| 557 | #include "trace/beauty/mode_t.c" | ||
| 558 | #include "trace/beauty/msg_flags.c" | ||
| 559 | #include "trace/beauty/open_flags.c" | ||
| 560 | #include "trace/beauty/perf_event_open.c" | ||
| 561 | #include "trace/beauty/pid.c" | ||
| 562 | #include "trace/beauty/sched_policy.c" | ||
| 563 | #include "trace/beauty/seccomp.c" | ||
| 564 | #include "trace/beauty/signum.c" | ||
| 565 | #include "trace/beauty/socket_type.c" | ||
| 566 | #include "trace/beauty/waitid_options.c" | ||
| 567 | |||
| 1008 | static struct syscall_fmt { | 568 | static struct syscall_fmt { |
| 1009 | const char *name; | 569 | const char *name; |
| 1010 | const char *alias; | 570 | const char *alias; |
| 1011 | size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg); | 571 | size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg); |
| 1012 | void *arg_parm[6]; | 572 | void *arg_parm[6]; |
| 1013 | bool errmsg; | 573 | bool errmsg; |
| 574 | bool errpid; | ||
| 1014 | bool timeout; | 575 | bool timeout; |
| 1015 | bool hexret; | 576 | bool hexret; |
| 1016 | } syscall_fmts[] = { | 577 | } syscall_fmts[] = { |
| @@ -1028,6 +589,7 @@ static struct syscall_fmt { · 11 unmodified lines | |||
| 1028 | { .name = "chroot", .errmsg = true, | 589 | { .name = "chroot", .errmsg = true, |
| 1029 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, | 590 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, |
| 1030 | { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, | 591 | { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, |
| 592 | { .name = "clone", .errpid = true, }, | ||
| 1031 | { .name = "close", .errmsg = true, | 593 | { .name = "close", .errmsg = true, |
| 1032 | .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, | 594 | .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, |
| 1033 | { .name = "connect", .errmsg = true, }, | 595 | { .name = "connect", .errmsg = true, }, |
| @@ -1093,6 +655,11 @@ static struct syscall_fmt { · 59 unmodified lines | |||
| 1093 | { .name = "getdents64", .errmsg = true, | 655 | { .name = "getdents64", .errmsg = true, |
| 1094 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 656 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
| 1095 | { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, | 657 | { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, |
| 658 | { .name = "getpid", .errpid = true, }, | ||
| 659 | { .name = "getpgid", .errpid = true, }, | ||
| 660 | { .name = "getppid", .errpid = true, }, | ||
| 661 | { .name = "getrandom", .errmsg = true, | ||
| 662 | .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, }, | ||
| 1096 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, | 663 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, |
| 1097 | { .name = "getxattr", .errmsg = true, | 664 | { .name = "getxattr", .errmsg = true, |
| 1098 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, | 665 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, |
| @@ -1186,8 +753,7 @@ static struct syscall_fmt { · 87 unmodified lines | |||
| 1186 | [1] = SCA_FILENAME, /* filename */ | 753 | [1] = SCA_FILENAME, /* filename */ |
| 1187 | [2] = SCA_OPEN_FLAGS, /* flags */ }, }, | 754 | [2] = SCA_OPEN_FLAGS, /* flags */ }, }, |
| 1188 | { .name = "perf_event_open", .errmsg = true, | 755 | { .name = "perf_event_open", .errmsg = true, |
| 1189 | .arg_scnprintf = { [1] = SCA_INT, /* pid */ | 756 | .arg_scnprintf = { [2] = SCA_INT, /* cpu */ |
| 1190 | [2] = SCA_INT, /* cpu */ | ||
| 1191 | [3] = SCA_FD, /* group_fd */ | 757 | [3] = SCA_FD, /* group_fd */ |
| 1192 | [4] = SCA_PERF_FLAGS, /* flags */ }, }, | 758 | [4] = SCA_PERF_FLAGS, /* flags */ }, }, |
| 1193 | { .name = "pipe2", .errmsg = true, | 759 | { .name = "pipe2", .errmsg = true, |
| @@ -1234,6 +800,11 @@ static struct syscall_fmt { · 40 unmodified lines | |||
| 1234 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, | 800 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, |
| 1235 | { .name = "rt_tgsigqueueinfo", .errmsg = true, | 801 | { .name = "rt_tgsigqueueinfo", .errmsg = true, |
| 1236 | .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, | 802 | .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, |
| 803 | { .name = "sched_setscheduler", .errmsg = true, | ||
| 804 | .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, }, | ||
| 805 | { .name = "seccomp", .errmsg = true, | ||
| 806 | .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */ | ||
| 807 | [1] = SCA_SECCOMP_FLAGS, /* flags */ }, }, | ||
| 1237 | { .name = "select", .errmsg = true, .timeout = true, }, | 808 | { .name = "select", .errmsg = true, .timeout = true, }, |
| 1238 | { .name = "sendmmsg", .errmsg = true, | 809 | { .name = "sendmmsg", .errmsg = true, |
| 1239 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 810 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
| @@ -1244,7 +815,9 @@ static struct syscall_fmt { · 4 unmodified lines | |||
| 1244 | { .name = "sendto", .errmsg = true, | 815 | { .name = "sendto", .errmsg = true, |
| 1245 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 816 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
| 1246 | [3] = SCA_MSG_FLAGS, /* flags */ }, }, | 817 | [3] = SCA_MSG_FLAGS, /* flags */ }, }, |
| 818 | { .name = "set_tid_address", .errpid = true, }, | ||
| 1247 | { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, | 819 | { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, |
| 820 | { .name = "setpgid", .errmsg = true, }, | ||
| 1248 | { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, | 821 | { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, |
| 1249 | { .name = "setxattr", .errmsg = true, | 822 | { .name = "setxattr", .errmsg = true, |
| 1250 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, | 823 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, |
| @@ -1287,6 +860,10 @@ static struct syscall_fmt { · 36 unmodified lines | |||
| 1287 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, | 860 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, |
| 1288 | { .name = "vmsplice", .errmsg = true, | 861 | { .name = "vmsplice", .errmsg = true, |
| 1289 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 862 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
| 863 | { .name = "wait4", .errpid = true, | ||
| 864 | .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, }, | ||
| 865 | { .name = "waitid", .errpid = true, | ||
| 866 | .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, }, | ||
| 1290 | { .name = "write", .errmsg = true, | 867 | { .name = "write", .errmsg = true, |
| 1291 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 868 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
| 1292 | { .name = "writev", .errmsg = true, | 869 | { .name = "writev", .errmsg = true, |
| @@ -1398,59 +975,6 @@ fail: · 105 unmodified lines | |||
| 1398 | 975 | ||
| 1399 | static const size_t trace__entry_str_size = 2048; | 976 | static const size_t trace__entry_str_size = 2048; |
| 1400 | 977 | ||
| 1401 | struct trace { | ||
| 1402 | struct perf_tool tool; | ||
| 1403 | struct { | ||
| 1404 | int machine; | ||
| 1405 | int open_id; | ||
| 1406 | } audit; | ||
| 1407 | struct { | ||
| 1408 | int max; | ||
| 1409 | struct syscall *table; | ||
| 1410 | struct { | ||
| 1411 | struct perf_evsel *sys_enter, | ||
| 1412 | *sys_exit; | ||
| 1413 | } events; | ||
| 1414 | } syscalls; | ||
| 1415 | struct record_opts opts; | ||
| 1416 | struct perf_evlist *evlist; | ||
| 1417 | struct machine *host; | ||
| 1418 | struct thread *current; | ||
| 1419 | u64 base_time; | ||
| 1420 | FILE *output; | ||
| 1421 | unsigned long nr_events; | ||
| 1422 | struct strlist *ev_qualifier; | ||
| 1423 | struct { | ||
| 1424 | size_t nr; | ||
| 1425 | int *entries; | ||
| 1426 | } ev_qualifier_ids; | ||
| 1427 | struct intlist *tid_list; | ||
| 1428 | struct intlist *pid_list; | ||
| 1429 | struct { | ||
| 1430 | size_t nr; | ||
| 1431 | pid_t *entries; | ||
| 1432 | } filter_pids; | ||
| 1433 | double duration_filter; | ||
| 1434 | double runtime_ms; | ||
| 1435 | struct { | ||
| 1436 | u64 vfs_getname, | ||
| 1437 | proc_getname; | ||
| 1438 | } stats; | ||
| 1439 | bool not_ev_qualifier; | ||
| 1440 | bool live; | ||
| 1441 | bool full_time; | ||
| 1442 | bool sched; | ||
| 1443 | bool multiple_threads; | ||
| 1444 | bool summary; | ||
| 1445 | bool summary_only; | ||
| 1446 | bool show_comm; | ||
| 1447 | bool show_tool_stats; | ||
| 1448 | bool trace_syscalls; | ||
| 1449 | bool force; | ||
| 1450 | bool vfs_getname; | ||
| 1451 | int trace_pgfaults; | ||
| 1452 | }; | ||
| 1453 | |||
| 1454 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) | 978 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) |
| 1455 | { | 979 | { |
| 1456 | struct thread_trace *ttrace = thread__priv(thread); | 980 | struct thread_trace *ttrace = thread__priv(thread); |
| @@ -1618,6 +1142,7 @@ static int trace__process_event(struct trace *trace, struct machine *machine, · 161 unmodified lines | |||
| 1618 | color_fprintf(trace->output, PERF_COLOR_RED, | 1142 | color_fprintf(trace->output, PERF_COLOR_RED, |
| 1619 | "LOST %" PRIu64 " events!\n", event->lost.lost); | 1143 | "LOST %" PRIu64 " events!\n", event->lost.lost); |
| 1620 | ret = machine__process_lost_event(machine, event, sample); | 1144 | ret = machine__process_lost_event(machine, event, sample); |
| 1145 | break; | ||
| 1621 | default: | 1146 | default: |
| 1622 | ret = machine__process_event(machine, event, sample); | 1147 | ret = machine__process_event(machine, event, sample); |
| 1623 | break; | 1148 | break; |
| @@ -1675,6 +1200,10 @@ static int syscall__set_arg_fmts(struct syscall *sc) · 51 unmodified lines | |||
| 1675 | sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; | 1200 | sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; |
| 1676 | else if (field->flags & FIELD_IS_POINTER) | 1201 | else if (field->flags & FIELD_IS_POINTER) |
| 1677 | sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; | 1202 | sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; |
| 1203 | else if (strcmp(field->type, "pid_t") == 0) | ||
| 1204 | sc->arg_scnprintf[idx] = SCA_PID; | ||
| 1205 | else if (strcmp(field->type, "umode_t") == 0) | ||
| 1206 | sc->arg_scnprintf[idx] = SCA_MODE_T; | ||
| 1678 | ++idx; | 1207 | ++idx; |
| 1679 | } | 1208 | } |
| 1680 | 1209 | ||
| @@ -1685,7 +1214,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) · 4 unmodified lines | |||
| 1685 | { | 1214 | { |
| 1686 | char tp_name[128]; | 1215 | char tp_name[128]; |
| 1687 | struct syscall *sc; | 1216 | struct syscall *sc; |
| 1688 | const char *name = audit_syscall_to_name(id, trace->audit.machine); | 1217 | const char *name = syscalltbl__name(trace->sctbl, id); |
| 1689 | 1218 | ||
| 1690 | if (name == NULL) | 1219 | if (name == NULL) |
| 1691 | return -1; | 1220 | return -1; |
| @@ -1760,7 +1289,7 @@ static int trace__validate_ev_qualifier(struct trace *trace) · 68 unmodified lines | |||
| 1760 | 1289 | ||
| 1761 | strlist__for_each(pos, trace->ev_qualifier) { | 1290 | strlist__for_each(pos, trace->ev_qualifier) { |
| 1762 | const char *sc = pos->s; | 1291 | const char *sc = pos->s; |
| 1763 | int id = audit_name_to_syscall(sc, trace->audit.machine); | 1292 | int id = syscalltbl__id(trace->sctbl, sc); |
| 1764 | 1293 | ||
| 1765 | if (id < 0) { | 1294 | if (id < 0) { |
| 1766 | if (err == 0) { | 1295 | if (err == 0) { |
| @@ -1846,7 +1375,12 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, · 79 unmodified lines | |||
| 1846 | "%ld", val); | 1375 | "%ld", val); |
| 1847 | } | 1376 | } |
| 1848 | } | 1377 | } |
| 1849 | } else { | 1378 | } else if (IS_ERR(sc->tp_format)) { |
| 1379 | /* | ||
| 1380 | * If we managed to read the tracepoint /format file, then we | ||
| 1381 | * may end up not having any args, like with gettid(), so only | ||
| 1382 | * print the raw args when we didn't manage to read it. | ||
| 1383 | */ | ||
| 1850 | int i = 0; | 1384 | int i = 0; |
| 1851 | 1385 | ||
| 1852 | while (i < 6) { | 1386 | while (i < 6) { |
| @@ -1987,7 +1521,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, · 134 unmodified lines | |||
| 1987 | goto out_put; | 1521 | goto out_put; |
| 1988 | } | 1522 | } |
| 1989 | 1523 | ||
| 1990 | if (!trace->summary_only) | 1524 | if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) |
| 1991 | trace__printf_interrupted_entry(trace, sample); | 1525 | trace__printf_interrupted_entry(trace, sample); |
| 1992 | 1526 | ||
| 1993 | ttrace->entry_time = sample->time; | 1527 | ttrace->entry_time = sample->time; |
| @@ -1998,7 +1532,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, · 4 unmodified lines | |||
| 1998 | args, trace, thread); | 1532 | args, trace, thread); |
| 1999 | 1533 | ||
| 2000 | if (sc->is_exit) { | 1534 | if (sc->is_exit) { |
| 2001 | if (!trace->duration_filter && !trace->summary_only) { | 1535 | if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { |
| 2002 | trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); | 1536 | trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); |
| 2003 | fprintf(trace->output, "%-70s\n", ttrace->entry_str); | 1537 | fprintf(trace->output, "%-70s\n", ttrace->entry_str); |
| 2004 | } | 1538 | } |
| @@ -2018,6 +1552,29 @@ out_put: · 13 unmodified lines | |||
| 2018 | return err; | 1552 | return err; |
| 2019 | } | 1553 | } |
| 2020 | 1554 | ||
| 1555 | static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, | ||
| 1556 | struct perf_sample *sample, | ||
| 1557 | struct callchain_cursor *cursor) | ||
| 1558 | { | ||
| 1559 | struct addr_location al; | ||
| 1560 | |||
| 1561 | if (machine__resolve(trace->host, &al, sample) < 0 || | ||
| 1562 | thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack)) | ||
| 1563 | return -1; | ||
| 1564 | |||
| 1565 | return 0; | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample) | ||
| 1569 | { | ||
| 1570 | /* TODO: user-configurable print_opts */ | ||
| 1571 | const unsigned int print_opts = EVSEL__PRINT_SYM | | ||
| 1572 | EVSEL__PRINT_DSO | | ||
| 1573 | EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
| 1574 | |||
| 1575 | return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output); | ||
| 1576 | } | ||
| 1577 | |||
| 2021 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | 1578 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, |
| 2022 | union perf_event *event __maybe_unused, | 1579 | union perf_event *event __maybe_unused, |
| 2023 | struct perf_sample *sample) | 1580 | struct perf_sample *sample) |
| @@ -2025,7 +1582,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, · 1 unmodified line | |||
| 2025 | long ret; | 1582 | long ret; |
| 2026 | u64 duration = 0; | 1583 | u64 duration = 0; |
| 2027 | struct thread *thread; | 1584 | struct thread *thread; |
| 2028 | int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; | 1585 | int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0; |
| 2029 | struct syscall *sc = trace__syscall_info(trace, evsel, id); | 1586 | struct syscall *sc = trace__syscall_info(trace, evsel, id); |
| 2030 | struct thread_trace *ttrace; | 1587 | struct thread_trace *ttrace; |
| 2031 | 1588 | ||
| @@ -2042,7 +1599,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, · 10 unmodified lines | |||
| 2042 | 1599 | ||
| 2043 | ret = perf_evsel__sc_tp_uint(evsel, ret, sample); | 1600 | ret = perf_evsel__sc_tp_uint(evsel, ret, sample); |
| 2044 | 1601 | ||
| 2045 | if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) { | 1602 | if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) { |
| 2046 | trace__set_fd_pathname(thread, ret, ttrace->filename.name); | 1603 | trace__set_fd_pathname(thread, ret, ttrace->filename.name); |
| 2047 | ttrace->filename.pending_open = false; | 1604 | ttrace->filename.pending_open = false; |
| 2048 | ++trace->stats.vfs_getname; | 1605 | ++trace->stats.vfs_getname; |
| @@ -2057,6 +1614,15 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, · 8 unmodified lines | |||
| 2057 | } else if (trace->duration_filter) | 1614 | } else if (trace->duration_filter) |
| 2058 | goto out; | 1615 | goto out; |
| 2059 | 1616 | ||
| 1617 | if (sample->callchain) { | ||
| 1618 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
| 1619 | if (callchain_ret == 0) { | ||
| 1620 | if (callchain_cursor.nr < trace->min_stack) | ||
| 1621 | goto out; | ||
| 1622 | callchain_ret = 1; | ||
| 1623 | } | ||
| 1624 | } | ||
| 1625 | |||
| 2060 | if (trace->summary_only) | 1626 | if (trace->summary_only) |
| 2061 | goto out; | 1627 | goto out; |
| 2062 | 1628 | ||
| @@ -2073,7 +1639,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, · 10 unmodified lines | |||
| 2073 | if (sc->fmt == NULL) { | 1639 | if (sc->fmt == NULL) { |
| 2074 | signed_print: | 1640 | signed_print: |
| 2075 | fprintf(trace->output, ") = %ld", ret); | 1641 | fprintf(trace->output, ") = %ld", ret); |
| 2076 | } else if (ret < 0 && sc->fmt->errmsg) { | 1642 | } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) { |
| 2077 | char bf[STRERR_BUFSIZE]; | 1643 | char bf[STRERR_BUFSIZE]; |
| 2078 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | 1644 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), |
| 2079 | *e = audit_errno_to_name(-ret); | 1645 | *e = audit_errno_to_name(-ret); |
| @@ -2083,10 +1649,24 @@ signed_print: · 3 unmodified lines | |||
| 2083 | fprintf(trace->output, ") = 0 Timeout"); | 1649 | fprintf(trace->output, ") = 0 Timeout"); |
| 2084 | else if (sc->fmt->hexret) | 1650 | else if (sc->fmt->hexret) |
| 2085 | fprintf(trace->output, ") = %#lx", ret); | 1651 | fprintf(trace->output, ") = %#lx", ret); |
| 2086 | else | 1652 | else if (sc->fmt->errpid) { |
| 1653 | struct thread *child = machine__find_thread(trace->host, ret, ret); | ||
| 1654 | |||
| 1655 | if (child != NULL) { | ||
| 1656 | fprintf(trace->output, ") = %ld", ret); | ||
| 1657 | if (child->comm_set) | ||
| 1658 | fprintf(trace->output, " (%s)", thread__comm_str(child)); | ||
| 1659 | thread__put(child); | ||
| 1660 | } | ||
| 1661 | } else | ||
| 2087 | goto signed_print; | 1662 | goto signed_print; |
| 2088 | 1663 | ||
| 2089 | fputc('\n', trace->output); | 1664 | fputc('\n', trace->output); |
| 1665 | |||
| 1666 | if (callchain_ret > 0) | ||
| 1667 | trace__fprintf_callchain(trace, sample); | ||
| 1668 | else if (callchain_ret < 0) | ||
| 1669 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | ||
| 2090 | out: | 1670 | out: |
| 2091 | ttrace->entry_pending = false; | 1671 | ttrace->entry_pending = false; |
| 2092 | err = 0; | 1672 | err = 0; |
| @@ -2217,6 +1797,17 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, · 124 unmodified lines | |||
| 2217 | union perf_event *event __maybe_unused, | 1797 | union perf_event *event __maybe_unused, |
| 2218 | struct perf_sample *sample) | 1798 | struct perf_sample *sample) |
| 2219 | { | 1799 | { |
| 1800 | int callchain_ret = 0; | ||
| 1801 | |||
| 1802 | if (sample->callchain) { | ||
| 1803 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
| 1804 | if (callchain_ret == 0) { | ||
| 1805 | if (callchain_cursor.nr < trace->min_stack) | ||
| 1806 | goto out; | ||
| 1807 | callchain_ret = 1; | ||
| 1808 | } | ||
| 1809 | } | ||
| 1810 | |||
| 2220 | trace__printf_interrupted_entry(trace, sample); | 1811 | trace__printf_interrupted_entry(trace, sample); |
| 2221 | trace__fprintf_tstamp(trace, sample->time, trace->output); | 1812 | trace__fprintf_tstamp(trace, sample->time, trace->output); |
| 2222 | 1813 | ||
| @@ -2234,6 +1825,12 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, · 11 unmodified lines | |||
| 2234 | } | 1825 | } |
| 2235 | 1826 | ||
| 2236 | fprintf(trace->output, ")\n"); | 1827 | fprintf(trace->output, ")\n"); |
| 1828 | |||
| 1829 | if (callchain_ret > 0) | ||
| 1830 | trace__fprintf_callchain(trace, sample); | ||
| 1831 | else if (callchain_ret < 0) | ||
| 1832 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | ||
| 1833 | out: | ||
| 2237 | return 0; | 1834 | return 0; |
| 2238 | } | 1835 | } |
| 2239 | 1836 | ||
| @@ -2264,8 +1861,19 @@ static int trace__pgfault(struct trace *trace, · 24 unmodified lines | |||
| 2264 | char map_type = 'd'; | 1861 | char map_type = 'd'; |
| 2265 | struct thread_trace *ttrace; | 1862 | struct thread_trace *ttrace; |
| 2266 | int err = -1; | 1863 | int err = -1; |
| 1864 | int callchain_ret = 0; | ||
| 2267 | 1865 | ||
| 2268 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); | 1866 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); |
| 1867 | |||
| 1868 | if (sample->callchain) { | ||
| 1869 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
| 1870 | if (callchain_ret == 0) { | ||
| 1871 | if (callchain_cursor.nr < trace->min_stack) | ||
| 1872 | goto out_put; | ||
| 1873 | callchain_ret = 1; | ||
| 1874 | } | ||
| 1875 | } | ||
| 1876 | |||
| 2269 | ttrace = thread__trace(thread, trace->output); | 1877 | ttrace = thread__trace(thread, trace->output); |
| 2270 | if (ttrace == NULL) | 1878 | if (ttrace == NULL) |
| 2271 | goto out_put; | 1879 | goto out_put; |
| @@ -2307,6 +1915,11 @@ static int trace__pgfault(struct trace *trace, · 35 unmodified lines | |||
| 2307 | print_location(trace->output, sample, &al, true, false); | 1915 | print_location(trace->output, sample, &al, true, false); |
| 2308 | 1916 | ||
| 2309 | fprintf(trace->output, " (%c%c)\n", map_type, al.level); | 1917 | fprintf(trace->output, " (%c%c)\n", map_type, al.level); |
| 1918 | |||
| 1919 | if (callchain_ret > 0) | ||
| 1920 | trace__fprintf_callchain(trace, sample); | ||
| 1921 | else if (callchain_ret < 0) | ||
| 1922 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | ||
| 2310 | out: | 1923 | out: |
| 2311 | err = 0; | 1924 | err = 0; |
| 2312 | out_put: | 1925 | out_put: |
| @@ -2326,6 +1939,23 @@ static bool skip_sample(struct trace *trace, struct perf_sample *sample) · 13 unmodified lines | |||
| 2326 | return false; | 1939 | return false; |
| 2327 | } | 1940 | } |
| 2328 | 1941 | ||
| 1942 | static void trace__set_base_time(struct trace *trace, | ||
| 1943 | struct perf_evsel *evsel, | ||
| 1944 | struct perf_sample *sample) | ||
| 1945 | { | ||
| 1946 | /* | ||
| 1947 | * BPF events were not setting PERF_SAMPLE_TIME, so be more robust | ||
| 1948 | * and don't use sample->time unconditionally, we may end up having | ||
| 1949 | * some other event in the future without PERF_SAMPLE_TIME for good | ||
| 1950 | * reason, i.e. we may not be interested in its timestamps, just in | ||
| 1951 | * it taking place, picking some piece of information when it | ||
| 1952 | * appears in our event stream (vfs_getname comes to mind). | ||
| 1953 | */ | ||
| 1954 | if (trace->base_time == 0 && !trace->full_time && | ||
| 1955 | (evsel->attr.sample_type & PERF_SAMPLE_TIME)) | ||
| 1956 | trace->base_time = sample->time; | ||
| 1957 | } | ||
| 1958 | |||
| 2329 | static int trace__process_sample(struct perf_tool *tool, | 1959 | static int trace__process_sample(struct perf_tool *tool, |
| 2330 | union perf_event *event, | 1960 | union perf_event *event, |
| 2331 | struct perf_sample *sample, | 1961 | struct perf_sample *sample, |
| @@ -2340,8 +1970,7 @@ static int trace__process_sample(struct perf_tool *tool, · 8 unmodified lines | |||
| 2340 | if (skip_sample(trace, sample)) | 1970 | if (skip_sample(trace, sample)) |
| 2341 | return 0; | 1971 | return 0; |
| 2342 | 1972 | ||
| 2343 | if (!trace->full_time && trace->base_time == 0) | 1973 | trace__set_base_time(trace, evsel, sample); |
| 2344 | trace->base_time = sample->time; | ||
| 2345 | 1974 | ||
| 2346 | if (handler) { | 1975 | if (handler) { |
| 2347 | ++trace->nr_events; | 1976 | ++trace->nr_events; |
| @@ -2450,8 +2079,7 @@ static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist) · 102 unmodified lines | |||
| 2450 | return true; | 2079 | return true; |
| 2451 | } | 2080 | } |
| 2452 | 2081 | ||
| 2453 | static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | 2082 | static struct perf_evsel *perf_evsel__new_pgfault(u64 config) |
| 2454 | u64 config) | ||
| 2455 | { | 2083 | { |
| 2456 | struct perf_evsel *evsel; | 2084 | struct perf_evsel *evsel; |
| 2457 | struct perf_event_attr attr = { | 2085 | struct perf_event_attr attr = { |
| @@ -2465,13 +2093,10 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist, · 7 unmodified lines | |||
| 2465 | event_attr_init(&attr); | 2093 | event_attr_init(&attr); |
| 2466 | 2094 | ||
| 2467 | evsel = perf_evsel__new(&attr); | 2095 | evsel = perf_evsel__new(&attr); |
| 2468 | if (!evsel) | 2096 | if (evsel) |
| 2469 | return -ENOMEM; | 2097 | evsel->handler = trace__pgfault; |
| 2470 | |||
| 2471 | evsel->handler = trace__pgfault; | ||
| 2472 | perf_evlist__add(evlist, evsel); | ||
| 2473 | 2098 | ||
| 2474 | return 0; | 2099 | return evsel; |
| 2475 | } | 2100 | } |
| 2476 | 2101 | ||
| 2477 | static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) | 2102 | static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) |
| @@ -2479,9 +2104,6 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st · 1 unmodified line | |||
| 2479 | const u32 type = event->header.type; | 2104 | const u32 type = event->header.type; |
| 2480 | struct perf_evsel *evsel; | 2105 | struct perf_evsel *evsel; |
| 2481 | 2106 | ||
| 2482 | if (!trace->full_time && trace->base_time == 0) | ||
| 2483 | trace->base_time = sample->time; | ||
| 2484 | |||
| 2485 | if (type != PERF_RECORD_SAMPLE) { | 2107 | if (type != PERF_RECORD_SAMPLE) { |
| 2486 | trace__process_event(trace, trace->host, event, sample); | 2108 | trace__process_event(trace, trace->host, event, sample); |
| 2487 | return; | 2109 | return; |
| @@ -2493,6 +2115,8 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st · 5 unmodified lines | |||
| 2493 | return; | 2115 | return; |
| 2494 | } | 2116 | } |
| 2495 | 2117 | ||
| 2118 | trace__set_base_time(trace, evsel, sample); | ||
| 2119 | |||
| 2496 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | 2120 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && |
| 2497 | sample->raw_data == NULL) { | 2121 | sample->raw_data == NULL) { |
| 2498 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | 2122 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", |
| @@ -2527,6 +2151,15 @@ static int trace__add_syscall_newtp(struct trace *trace) · 28 unmodified lines | |||
| 2527 | perf_evlist__add(evlist, sys_enter); | 2151 | perf_evlist__add(evlist, sys_enter); |
| 2528 | perf_evlist__add(evlist, sys_exit); | 2152 | perf_evlist__add(evlist, sys_exit); |
| 2529 | 2153 | ||
| 2154 | if (callchain_param.enabled && !trace->kernel_syscallchains) { | ||
| 2155 | /* | ||
| 2156 | * We're interested only in the user space callchain | ||
| 2157 | * leading to the syscall, allow overriding that for | ||
| 2158 | * debugging reasons using --kernel_syscall_callchains | ||
| 2159 | */ | ||
| 2160 | sys_exit->attr.exclude_callchain_kernel = 1; | ||
| 2161 | } | ||
| 2162 | |||
| 2530 | trace->syscalls.events.sys_enter = sys_enter; | 2163 | trace->syscalls.events.sys_enter = sys_enter; |
| 2531 | trace->syscalls.events.sys_exit = sys_exit; | 2164 | trace->syscalls.events.sys_exit = sys_exit; |
| 2532 | 2165 | ||
| @@ -2565,7 +2198,7 @@ out_enomem: · 32 unmodified lines | |||
| 2565 | static int trace__run(struct trace *trace, int argc, const char **argv) | 2198 | static int trace__run(struct trace *trace, int argc, const char **argv) |
| 2566 | { | 2199 | { |
| 2567 | struct perf_evlist *evlist = trace->evlist; | 2200 | struct perf_evlist *evlist = trace->evlist; |
| 2568 | struct perf_evsel *evsel; | 2201 | struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL; |
| 2569 | int err = -1, i; | 2202 | int err = -1, i; |
| 2570 | unsigned long before; | 2203 | unsigned long before; |
| 2571 | const bool forks = argc > 0; | 2204 | const bool forks = argc > 0; |
| @@ -2579,14 +2212,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv) · 7 unmodified lines | |||
| 2579 | if (trace->trace_syscalls) | 2212 | if (trace->trace_syscalls) |
| 2580 | trace->vfs_getname = perf_evlist__add_vfs_getname(evlist); | 2213 | trace->vfs_getname = perf_evlist__add_vfs_getname(evlist); |
| 2581 | 2214 | ||
| 2582 | if ((trace->trace_pgfaults & TRACE_PFMAJ) && | 2215 | if ((trace->trace_pgfaults & TRACE_PFMAJ)) { |
| 2583 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) { | 2216 | pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ); |
| 2584 | goto out_error_mem; | 2217 | if (pgfault_maj == NULL) |
| 2218 | goto out_error_mem; | ||
| 2219 | perf_evlist__add(evlist, pgfault_maj); | ||
| 2585 | } | 2220 | } |
| 2586 | 2221 | ||
| 2587 | if ((trace->trace_pgfaults & TRACE_PFMIN) && | 2222 | if ((trace->trace_pgfaults & TRACE_PFMIN)) { |
| 2588 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) | 2223 | pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN); |
| 2589 | goto out_error_mem; | 2224 | if (pgfault_min == NULL) |
| 2225 | goto out_error_mem; | ||
| 2226 | perf_evlist__add(evlist, pgfault_min); | ||
| 2227 | } | ||
| 2590 | 2228 | ||
| 2591 | if (trace->sched && | 2229 | if (trace->sched && |
| 2592 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", | 2230 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", |
| @@ -2605,7 +2243,45 @@ static int trace__run(struct trace *trace, int argc, const char **argv) · 12 unmodified lines | |||
| 2605 | goto out_delete_evlist; | 2243 | goto out_delete_evlist; |
| 2606 | } | 2244 | } |
| 2607 | 2245 | ||
| 2608 | perf_evlist__config(evlist, &trace->opts); | 2246 | perf_evlist__config(evlist, &trace->opts, NULL); |
| 2247 | |||
| 2248 | if (callchain_param.enabled) { | ||
| 2249 | bool use_identifier = false; | ||
| 2250 | |||
| 2251 | if (trace->syscalls.events.sys_exit) { | ||
| 2252 | perf_evsel__config_callchain(trace->syscalls.events.sys_exit, | ||
| 2253 | &trace->opts, &callchain_param); | ||
| 2254 | use_identifier = true; | ||
| 2255 | } | ||
| 2256 | |||
| 2257 | if (pgfault_maj) { | ||
| 2258 | perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param); | ||
| 2259 | use_identifier = true; | ||
| 2260 | } | ||
| 2261 | |||
| 2262 | if (pgfault_min) { | ||
| 2263 | perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param); | ||
| 2264 | use_identifier = true; | ||
| 2265 | } | ||
| 2266 | |||
| 2267 | if (use_identifier) { | ||
| 2268 | /* | ||
| 2269 | * Now we have evsels with different sample_ids, use | ||
| 2270 | * PERF_SAMPLE_IDENTIFIER to map from sample to evsel | ||
| 2271 | * from a fixed position in each ring buffer record. | ||
| 2272 | * | ||
| 2273 | * As of this the changeset introducing this comment, this | ||
| 2274 | * isn't strictly needed, as the fields that can come before | ||
| 2275 | * PERF_SAMPLE_ID are all used, but we'll probably disable | ||
| 2276 | * some of those for things like copying the payload of | ||
| 2277 | * pointer syscall arguments, and for vfs_getname we don't | ||
| 2278 | * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this | ||
| 2279 | * here as a warning we need to use PERF_SAMPLE_IDENTIFIER. | ||
| 2280 | */ | ||
| 2281 | perf_evlist__set_sample_bit(evlist, IDENTIFIER); | ||
| 2282 | perf_evlist__reset_sample_bit(evlist, ID); | ||
| 2283 | } | ||
| 2284 | } | ||
| 2609 | 2285 | ||
| 2610 | signal(SIGCHLD, sig_handler); | 2286 | signal(SIGCHLD, sig_handler); |
| 2611 | signal(SIGINT, sig_handler); | 2287 | signal(SIGINT, sig_handler); |
| @@ -2883,15 +2559,29 @@ static size_t trace__fprintf_threads_header(FILE *fp) · 271 unmodified lines | |||
| 2883 | return printed; | 2559 | return printed; |
| 2884 | } | 2560 | } |
| 2885 | 2561 | ||
| 2562 | DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs, | ||
| 2563 | struct stats *stats; | ||
| 2564 | double msecs; | ||
| 2565 | int syscall; | ||
| 2566 | ) | ||
| 2567 | { | ||
| 2568 | struct int_node *source = rb_entry(nd, struct int_node, rb_node); | ||
| 2569 | struct stats *stats = source->priv; | ||
| 2570 | |||
| 2571 | entry->syscall = source->i; | ||
| 2572 | entry->stats = stats; | ||
| 2573 | entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0; | ||
| 2574 | } | ||
| 2575 | |||
| 2886 | static size_t thread__dump_stats(struct thread_trace *ttrace, | 2576 | static size_t thread__dump_stats(struct thread_trace *ttrace, |
| 2887 | struct trace *trace, FILE *fp) | 2577 | struct trace *trace, FILE *fp) |
| 2888 | { | 2578 | { |
| 2889 | struct stats *stats; | ||
| 2890 | size_t printed = 0; | 2579 | size_t printed = 0; |
| 2891 | struct syscall *sc; | 2580 | struct syscall *sc; |
| 2892 | struct int_node *inode = intlist__first(ttrace->syscall_stats); | 2581 | struct rb_node *nd; |
| 2582 | DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats); | ||
| 2893 | 2583 | ||
| 2894 | if (inode == NULL) | 2584 | if (syscall_stats == NULL) |
| 2895 | return 0; | 2585 | return 0; |
| 2896 | 2586 | ||
| 2897 | printed += fprintf(fp, "\n"); | 2587 | printed += fprintf(fp, "\n"); |
| @@ -2900,9 +2590,8 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, · 2 unmodified lines | |||
| 2900 | printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); | 2590 | printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); |
| 2901 | printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); | 2591 | printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); |
| 2902 | 2592 | ||
| 2903 | /* each int_node is a syscall */ | 2593 | resort_rb__for_each(nd, syscall_stats) { |
| 2904 | while (inode) { | 2594 | struct stats *stats = syscall_stats_entry->stats; |
| 2905 | stats = inode->priv; | ||
| 2906 | if (stats) { | 2595 | if (stats) { |
| 2907 | double min = (double)(stats->min) / NSEC_PER_MSEC; | 2596 | double min = (double)(stats->min) / NSEC_PER_MSEC; |
| 2908 | double max = (double)(stats->max) / NSEC_PER_MSEC; | 2597 | double max = (double)(stats->max) / NSEC_PER_MSEC; |
| @@ -2913,34 +2602,23 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, · 4 unmodified lines | |||
| 2913 | pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0; | 2602 | pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0; |
| 2914 | avg /= NSEC_PER_MSEC; | 2603 | avg /= NSEC_PER_MSEC; |
| 2915 | 2604 | ||
| 2916 | sc = &trace->syscalls.table[inode->i]; | 2605 | sc = &trace->syscalls.table[syscall_stats_entry->syscall]; |
| 2917 | printed += fprintf(fp, " %-15s", sc->name); | 2606 | printed += fprintf(fp, " %-15s", sc->name); |
| 2918 | printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f", | 2607 | printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f", |
| 2919 | n, avg * n, min, avg); | 2608 | n, syscall_stats_entry->msecs, min, avg); |
| 2920 | printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct); | 2609 | printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct); |
| 2921 | } | 2610 | } |
| 2922 | |||
| 2923 | inode = intlist__next(inode); | ||
| 2924 | } | 2611 | } |
| 2925 | 2612 | ||
| 2613 | resort_rb__delete(syscall_stats); | ||
| 2926 | printed += fprintf(fp, "\n\n"); | 2614 | printed += fprintf(fp, "\n\n"); |
| 2927 | 2615 | ||
| 2928 | return printed; | 2616 | return printed; |
| 2929 | } | 2617 | } |
| 2930 | 2618 | ||
| 2931 | /* struct used to pass data to per-thread function */ | 2619 | static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace) |
| 2932 | struct summary_data { | ||
| 2933 | FILE *fp; | ||
| 2934 | struct trace *trace; | ||
| 2935 | size_t printed; | ||
| 2936 | }; | ||
| 2937 | |||
| 2938 | static int trace__fprintf_one_thread(struct thread *thread, void *priv) | ||
| 2939 | { | 2620 | { |
| 2940 | struct summary_data *data = priv; | 2621 | size_t printed = 0; |
| 2941 | FILE *fp = data->fp; | ||
| 2942 | size_t printed = data->printed; | ||
| 2943 | struct trace *trace = data->trace; | ||
| 2944 | struct thread_trace *ttrace = thread__priv(thread); | 2622 | struct thread_trace *ttrace = thread__priv(thread); |
| 2945 | double ratio; | 2623 | double ratio; |
| 2946 | 2624 | ||
| @@ -2956,25 +2634,45 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) · 9 unmodified lines | |||
| 2956 | printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj); | 2634 | printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj); |
| 2957 | if (ttrace->pfmin) | 2635 | if (ttrace->pfmin) |
| 2958 | printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin); | 2636 | printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin); |
| 2959 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); | 2637 | if (trace->sched) |
| 2638 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); | ||
| 2639 | else if (fputc('\n', fp) != EOF) | ||
| 2640 | ++printed; | ||
| 2641 | |||
| 2960 | printed += thread__dump_stats(ttrace, trace, fp); | 2642 | printed += thread__dump_stats(ttrace, trace, fp); |
| 2961 | 2643 | ||
| 2962 | data->printed += printed; | 2644 | return printed; |
| 2645 | } | ||
| 2963 | 2646 | ||
| 2964 | return 0; | 2647 | static unsigned long thread__nr_events(struct thread_trace *ttrace) |
| 2648 | { | ||
| 2649 | return ttrace ? ttrace->nr_events : 0; | ||
| 2650 | } | ||
| 2651 | |||
| 2652 | DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)), | ||
| 2653 | struct thread *thread; | ||
| 2654 | ) | ||
| 2655 | { | ||
| 2656 | entry->thread = rb_entry(nd, struct thread, rb_node); | ||
| 2965 | } | 2657 | } |
| 2966 | 2658 | ||
| 2967 | static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) | 2659 | static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) |
| 2968 | { | 2660 | { |
| 2969 | struct summary_data data = { | 2661 | DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host); |
| 2970 | .fp = fp, | 2662 | size_t printed = trace__fprintf_threads_header(fp); |
| 2971 | .trace = trace | 2663 | struct rb_node *nd; |
| 2972 | }; | 2664 | |
| 2973 | data.printed = trace__fprintf_threads_header(fp); | 2665 | if (threads == NULL) { |
| 2666 | fprintf(fp, "%s", "Error sorting output by nr_events!\n"); | ||
| 2667 | return 0; | ||
| 2668 | } | ||
| 2974 | 2669 | ||
| 2975 | machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data); | 2670 | resort_rb__for_each(nd, threads) |
| 2671 | printed += trace__fprintf_thread(fp, threads_entry->thread, trace); | ||
| 2976 | 2672 | ||
| 2977 | return data.printed; | 2673 | resort_rb__delete(threads); |
| 2674 | |||
| 2675 | return printed; | ||
| 2978 | } | 2676 | } |
| 2979 | 2677 | ||
| 2980 | static int trace__set_duration(const struct option *opt, const char *str, | 2678 | static int trace__set_duration(const struct option *opt, const char *str, |
| @@ -3070,10 +2768,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) · 89 unmodified lines | |||
| 3070 | NULL | 2768 | NULL |
| 3071 | }; | 2769 | }; |
| 3072 | struct trace trace = { | 2770 | struct trace trace = { |
| 3073 | .audit = { | ||
| 3074 | .machine = audit_detect_machine(), | ||
| 3075 | .open_id = audit_name_to_syscall("open", trace.audit.machine), | ||
| 3076 | }, | ||
| 3077 | .syscalls = { | 2771 | .syscalls = { |
| 3078 | . max = -1, | 2772 | . max = -1, |
| 3079 | }, | 2773 | }, |
| @@ -3091,6 +2785,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) · 11 unmodified lines | |||
| 3091 | .output = stderr, | 2785 | .output = stderr, |
| 3092 | .show_comm = true, | 2786 | .show_comm = true, |
| 3093 | .trace_syscalls = true, | 2787 | .trace_syscalls = true, |
| 2788 | .kernel_syscallchains = false, | ||
| 2789 | .max_stack = UINT_MAX, | ||
| 3094 | }; | 2790 | }; |
| 3095 | const char *output_name = NULL; | 2791 | const char *output_name = NULL; |
| 3096 | const char *ev_qualifier_str = NULL; | 2792 | const char *ev_qualifier_str = NULL; |
| @@ -3136,10 +2832,24 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) · 39 unmodified lines | |||
| 3136 | "Trace pagefaults", parse_pagefaults, "maj"), | 2832 | "Trace pagefaults", parse_pagefaults, "maj"), |
| 3137 | OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), | 2833 | OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), |
| 3138 | OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), | 2834 | OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), |
| 2835 | OPT_CALLBACK(0, "call-graph", &trace.opts, | ||
| 2836 | "record_mode[,record_size]", record_callchain_help, | ||
| 2837 | &record_parse_callchain_opt), | ||
| 2838 | OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, | ||
| 2839 | "Show the kernel callchains on the syscall exit path"), | ||
| 2840 | OPT_UINTEGER(0, "min-stack", &trace.min_stack, | ||
| 2841 | "Set the minimum stack depth when parsing the callchain, " | ||
| 2842 | "anything below the specified depth will be ignored."), | ||
| 2843 | OPT_UINTEGER(0, "max-stack", &trace.max_stack, | ||
| 2844 | "Set the maximum stack depth when parsing the callchain, " | ||
| 2845 | "anything beyond the specified depth will be ignored. " | ||
| 2846 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), | ||
| 3139 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, | 2847 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, |
| 3140 | "per thread proc mmap processing timeout in ms"), | 2848 | "per thread proc mmap processing timeout in ms"), |
| 3141 | OPT_END() | 2849 | OPT_END() |
| 3142 | }; | 2850 | }; |
| 2851 | bool __maybe_unused max_stack_user_set = true; | ||
| 2852 | bool mmap_pages_user_set = true; | ||
| 3143 | const char * const trace_subcommands[] = { "record", NULL }; | 2853 | const char * const trace_subcommands[] = { "record", NULL }; |
| 3144 | int err; | 2854 | int err; |
| 3145 | char bf[BUFSIZ]; | 2855 | char bf[BUFSIZ]; |
| @@ -3148,8 +2858,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) · 2 unmodified lines | |||
| 3148 | signal(SIGFPE, sighandler_dump_stack); | 2858 | signal(SIGFPE, sighandler_dump_stack); |
| 3149 | 2859 | ||
| 3150 | trace.evlist = perf_evlist__new(); | 2860 | trace.evlist = perf_evlist__new(); |
| 2861 | trace.sctbl = syscalltbl__new(); | ||
| 3151 | 2862 | ||
| 3152 | if (trace.evlist == NULL) { | 2863 | if (trace.evlist == NULL || trace.sctbl == NULL) { |
| 3153 | pr_err("Not enough memory to run!\n"); | 2864 | pr_err("Not enough memory to run!\n"); |
| 3154 | err = -ENOMEM; | 2865 | err = -ENOMEM; |
| 3155 | goto out; | 2866 | goto out; |
| @@ -3158,11 +2869,40 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) · 2 unmodified lines | |||
| 3158 | argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands, | 2869 | argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands, |
| 3159 | trace_usage, PARSE_OPT_STOP_AT_NON_OPTION); | 2870 | trace_usage, PARSE_OPT_STOP_AT_NON_OPTION); |
| 3160 | 2871 | ||
| 2872 | err = bpf__setup_stdout(trace.evlist); | ||
| 2873 | if (err) { | ||
| 2874 | bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf)); | ||
| 2875 | pr_err("ERROR: Setup BPF stdout failed: %s\n", bf); | ||
| 2876 | goto out; | ||
| 2877 | } | ||
| 2878 | |||
| 2879 | err = -1; | ||
| 2880 | |||
| 3161 | if (trace.trace_pgfaults) { | 2881 | if (trace.trace_pgfaults) { |
| 3162 | trace.opts.sample_address = true; | 2882 | trace.opts.sample_address = true; |
| 3163 | trace.opts.sample_time = true; | 2883 | trace.opts.sample_time = true; |
| 3164 | } | 2884 | } |
| 3165 | 2885 | ||
| 2886 | if (trace.opts.mmap_pages == UINT_MAX) | ||
| 2887 | mmap_pages_user_set = false; | ||
| 2888 | |||
| 2889 | if (trace.max_stack == UINT_MAX) { | ||
| 2890 | trace.max_stack = sysctl_perf_event_max_stack; | ||
| 2891 | max_stack_user_set = false; | ||
| 2892 | } | ||
| 2893 | |||
| 2894 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
| 2895 | if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) | ||
| 2896 | record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false); | ||
| 2897 | #endif | ||
| 2898 | |||
| 2899 | if (callchain_param.enabled) { | ||
| 2900 | if (!mmap_pages_user_set && geteuid() == 0) | ||
| 2901 | trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4; | ||
| 2902 | |||
| 2903 | symbol_conf.use_callchain = true; | ||
| 2904 | } | ||
| 2905 | |||
| 3166 | if (trace.evlist->nr_entries > 0) | 2906 | if (trace.evlist->nr_entries > 0) |
| 3167 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); | 2907 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); |
| 3168 | 2908 | ||
| @@ -3179,6 +2919,11 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) · 10 unmodified lines | |||
| 3179 | return -1; | 2919 | return -1; |
| 3180 | } | 2920 | } |
| 3181 | 2921 | ||
| 2922 | if (!trace.trace_syscalls && ev_qualifier_str) { | ||
| 2923 | pr_err("The -e option can't be used with --no-syscalls.\n"); | ||
| 2924 | goto out; | ||
| 2925 | } | ||
| 2926 | |||
| 3182 | if (output_name != NULL) { | 2927 | if (output_name != NULL) { |
| 3183 | err = trace__open_output(&trace, output_name); | 2928 | err = trace__open_output(&trace, output_name); |
| 3184 | if (err < 0) { | 2929 | if (err < 0) { |
| @@ -3187,6 +2932,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) · 2 unmodified lines | |||
| 3187 | } | 2932 | } |
| 3188 | } | 2933 | } |
| 3189 | 2934 | ||
| 2935 | trace.open_id = syscalltbl__id(trace.sctbl, "open"); | ||
| 2936 | |||
| 3190 | if (ev_qualifier_str != NULL) { | 2937 | if (ev_qualifier_str != NULL) { |
| 3191 | const char *s = ev_qualifier_str; | 2938 | const char *s = ev_qualifier_str; |
| 3192 | struct strlist_config slist_config = { | 2939 | struct strlist_config slist_config = { |
| @@ -27,7 +27,7 @@ NO_PERF_REGS := 1 · 26 unmodified lines | |||
| 27 | ifeq ($(ARCH),x86) | 27 | ifeq ($(ARCH),x86) |
| 28 | $(call detected,CONFIG_X86) | 28 | $(call detected,CONFIG_X86) |
| 29 | ifeq (${IS_64_BIT}, 1) | 29 | ifeq (${IS_64_BIT}, 1) |
| 30 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT | 30 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated |
| 31 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | 31 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S |
| 32 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | 32 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 |
| 33 | $(call detected,CONFIG_X86_64) | 33 | $(call detected,CONFIG_X86_64) |
| @@ -295,9 +295,6 @@ ifndef NO_LIBELF · 261 unmodified lines | |||
| 295 | CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT | 295 | CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT |
| 296 | endif | 296 | endif |
| 297 | 297 | ||
| 298 | # include ARCH specific config | ||
| 299 | -include $(src-perf)/arch/$(ARCH)/Makefile | ||
| 300 | |||
| 301 | ifndef NO_DWARF | 298 | ifndef NO_DWARF |
| 302 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | 299 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) |
| 303 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | 300 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); |
| @@ -92,6 +92,22 @@ error: · 91 unmodified lines | |||
| 92 | return ret; | 92 | return ret; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | static int use_arch_timestamp; | ||
| 96 | |||
| 97 | static inline uint64_t | ||
| 98 | get_arch_timestamp(void) | ||
| 99 | { | ||
| 100 | #if defined(__i386__) || defined(__x86_64__) | ||
| 101 | unsigned int low, high; | ||
| 102 | |||
| 103 | asm volatile("rdtsc" : "=a" (low), "=d" (high)); | ||
| 104 | |||
| 105 | return low | ((uint64_t)high) << 32; | ||
| 106 | #else | ||
| 107 | return 0; | ||
| 108 | #endif | ||
| 109 | } | ||
| 110 | |||
| 95 | #define NSEC_PER_SEC 1000000000 | 111 | #define NSEC_PER_SEC 1000000000 |
| 96 | static int perf_clk_id = CLOCK_MONOTONIC; | 112 | static int perf_clk_id = CLOCK_MONOTONIC; |
| 97 | 113 | ||
| @@ -107,6 +123,9 @@ perf_get_timestamp(void) · 9 unmodified lines | |||
| 107 | struct timespec ts; | 123 | struct timespec ts; |
| 108 | int ret; | 124 | int ret; |
| 109 | 125 | ||
| 126 | if (use_arch_timestamp) | ||
| 127 | return get_arch_timestamp(); | ||
| 128 | |||
| 110 | ret = clock_gettime(perf_clk_id, &ts); | 129 | ret = clock_gettime(perf_clk_id, &ts); |
| 111 | if (ret) | 130 | if (ret) |
| 112 | return 0; | 131 | return 0; |
| @@ -203,6 +222,17 @@ perf_close_marker_file(void) · 90 unmodified lines | |||
| 203 | munmap(marker_addr, pgsz); | 222 | munmap(marker_addr, pgsz); |
| 204 | } | 223 | } |
| 205 | 224 | ||
| 225 | static void | ||
| 226 | init_arch_timestamp(void) | ||
| 227 | { | ||
| 228 | char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP"); | ||
| 229 | |||
| 230 | if (!str || !*str || !strcmp(str, "0")) | ||
| 231 | return; | ||
| 232 | |||
| 233 | use_arch_timestamp = 1; | ||
| 234 | } | ||
| 235 | |||
| 206 | void *jvmti_open(void) | 236 | void *jvmti_open(void) |
| 207 | { | 237 | { |
| 208 | int pad_cnt; | 238 | int pad_cnt; |
| @@ -211,11 +241,17 @@ void *jvmti_open(void) · 2 unmodified lines | |||
| 211 | int fd; | 241 | int fd; |
| 212 | FILE *fp; | 242 | FILE *fp; |
| 213 | 243 | ||
| 244 | init_arch_timestamp(); | ||
| 245 | |||
| 214 | /* | 246 | /* |
| 215 | * check if clockid is supported | 247 | * check if clockid is supported |
| 216 | */ | 248 | */ |
| 217 | if (!perf_get_timestamp()) | 249 | if (!perf_get_timestamp()) { |
| 218 | warnx("jvmti: kernel does not support %d clock id", perf_clk_id); | 250 | if (use_arch_timestamp) |
| 251 | warnx("jvmti: arch timestamp not supported"); | ||
| 252 | else | ||
| 253 | warnx("jvmti: kernel does not support %d clock id", perf_clk_id); | ||
| 254 | } | ||
| 219 | 255 | ||
| 220 | memset(&header, 0, sizeof(header)); | 256 | memset(&header, 0, sizeof(header)); |
| 221 | 257 | ||
| @@ -263,6 +299,9 @@ void *jvmti_open(void) · 41 unmodified lines | |||
| 263 | 299 | ||
| 264 | header.timestamp = perf_get_timestamp(); | 300 | header.timestamp = perf_get_timestamp(); |
| 265 | 301 | ||
| 302 | if (use_arch_timestamp) | ||
| 303 | header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP; | ||
| 304 | |||
| 266 | if (!fwrite(&header, sizeof(header), 1, fp)) { | 305 | if (!fwrite(&header, sizeof(header), 1, fp)) { |
| 267 | warn("jvmti: cannot write dumpfile header"); | 306 | warn("jvmti: cannot write dumpfile header"); |
| 268 | goto error; | 307 | goto error; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include <subcmd/parse-options.h> | 17 | #include <subcmd/parse-options.h> |
| 18 | #include "util/bpf-loader.h" | 18 | #include "util/bpf-loader.h" |
| 19 | #include "util/debug.h" | 19 | #include "util/debug.h" |
| 20 | #include <api/fs/fs.h> | ||
| 20 | #include <api/fs/tracing_path.h> | 21 | #include <api/fs/tracing_path.h> |
| 21 | #include <pthread.h> | 22 | #include <pthread.h> |
| 22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
| @@ -308,9 +309,11 @@ static int handle_alias(int *argcp, const char ***argv) · 285 unmodified lines | |||
| 308 | if (*argcp > 1) { | 309 | if (*argcp > 1) { |
| 309 | struct strbuf buf; | 310 | struct strbuf buf; |
| 310 | 311 | ||
| 311 | strbuf_init(&buf, PATH_MAX); | 312 | if (strbuf_init(&buf, PATH_MAX) < 0 || |
| 312 | strbuf_addstr(&buf, alias_string); | 313 | strbuf_addstr(&buf, alias_string) < 0 || |
| 313 | sq_quote_argv(&buf, (*argv) + 1, PATH_MAX); | 314 | sq_quote_argv(&buf, (*argv) + 1, |
| 315 | PATH_MAX) < 0) | ||
| 316 | die("Failed to allocate memory."); | ||
| 314 | free(alias_string); | 317 | free(alias_string); |
| 315 | alias_string = buf.buf; | 318 | alias_string = buf.buf; |
| 316 | } | 319 | } |
| @@ -533,6 +536,7 @@ int main(int argc, const char **argv) · 216 unmodified lines | |||
| 533 | { | 536 | { |
| 534 | const char *cmd; | 537 | const char *cmd; |
| 535 | char sbuf[STRERR_BUFSIZE]; | 538 | char sbuf[STRERR_BUFSIZE]; |
| 539 | int value; | ||
| 536 | 540 | ||
| 537 | /* libsubcmd init */ | 541 | /* libsubcmd init */ |
| 538 | exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); | 542 | exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); |
| @@ -542,6 +546,9 @@ int main(int argc, const char **argv) · 3 unmodified lines | |||
| 542 | page_size = sysconf(_SC_PAGE_SIZE); | 546 | page_size = sysconf(_SC_PAGE_SIZE); |
| 543 | cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); | 547 | cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
| 544 | 548 | ||
| 549 | if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) | ||
| 550 | sysctl_perf_event_max_stack = value; | ||
| 551 | |||
| 545 | cmd = extract_argv0_path(argv[0]); | 552 | cmd = extract_argv0_path(argv[0]); |
| 546 | if (!cmd) | 553 | if (!cmd) |
| 547 | cmd = "perf-help"; | 554 | cmd = "perf-help"; |
| @@ -549,6 +556,7 @@ int main(int argc, const char **argv) · 1 unmodified line | |||
| 549 | srandom(time(NULL)); | 556 | srandom(time(NULL)); |
| 550 | 557 | ||
| 551 | perf_config(perf_default_config, NULL); | 558 | perf_config(perf_default_config, NULL); |
| 559 | set_buildid_dir(NULL); | ||
| 552 | 560 | ||
| 553 | /* get debugfs/tracefs mount point from /proc/mounts */ | 561 | /* get debugfs/tracefs mount point from /proc/mounts */ |
| 554 | tracing_path_mount(); | 562 | tracing_path_mount(); |
| @@ -572,7 +580,6 @@ int main(int argc, const char **argv) · 17 unmodified lines | |||
| 572 | } | 580 | } |
| 573 | if (!prefixcmp(cmd, "trace")) { | 581 | if (!prefixcmp(cmd, "trace")) { |
| 574 | #ifdef HAVE_LIBAUDIT_SUPPORT | 582 | #ifdef HAVE_LIBAUDIT_SUPPORT |
| 575 | set_buildid_dir(NULL); | ||
| 576 | setup_path(); | 583 | setup_path(); |
| 577 | argv[0] = "trace"; | 584 | argv[0] = "trace"; |
| 578 | return cmd_trace(argc, argv, NULL); | 585 | return cmd_trace(argc, argv, NULL); |
| @@ -587,7 +594,6 @@ int main(int argc, const char **argv) · 8 unmodified lines | |||
| 587 | argc--; | 594 | argc--; |
| 588 | handle_options(&argv, &argc, NULL); | 595 | handle_options(&argv, &argc, NULL); |
| 589 | commit_pager_choice(); | 596 | commit_pager_choice(); |
| 590 | set_buildid_dir(NULL); | ||
| 591 | 597 | ||
| 592 | if (argc > 0) { | 598 | if (argc > 0) { |
| 593 | if (!prefixcmp(argv[0], "--")) | 599 | if (!prefixcmp(argv[0], "--")) |
| @@ -52,7 +52,6 @@ struct record_opts { · 51 unmodified lines | |||
| 52 | bool sample_weight; | 52 | bool sample_weight; |
| 53 | bool sample_time; | 53 | bool sample_time; |
| 54 | bool sample_time_set; | 54 | bool sample_time_set; |
| 55 | bool callgraph_set; | ||
| 56 | bool period; | 55 | bool period; |
| 57 | bool running_time; | 56 | bool running_time; |
| 58 | bool full_auxtrace; | 57 | bool full_auxtrace; |
| @@ -34,10 +34,9 @@ import datetime · 33 unmodified lines | |||
| 34 | # | 34 | # |
| 35 | # ubuntu: | 35 | # ubuntu: |
| 36 | # | 36 | # |
| 37 | # $ sudo apt-get install postgresql | 37 | # $ sudo apt-get install postgresql python-pyside.qtsql libqt4-sql-psql |
| 38 | # $ sudo su - postgres | 38 | # $ sudo su - postgres |
| 39 | # $ createuser <your user id here> | 39 | # $ createuser -s <your user id here> |
| 40 | # Shall the new role be a superuser? (y/n) y | ||
| 41 | # | 40 | # |
| 42 | # An example of using this script with Intel PT: | 41 | # An example of using this script with Intel PT: |
| 43 | # | 42 | # |
| @@ -224,11 +223,14 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ · 180 unmodified lines | |||
| 224 | 223 | ||
| 225 | perf_db_export_mode = True | 224 | perf_db_export_mode = True |
| 226 | perf_db_export_calls = False | 225 | perf_db_export_calls = False |
| 226 | perf_db_export_callchains = False | ||
| 227 | |||
| 227 | 228 | ||
| 228 | def usage(): | 229 | def usage(): |
| 229 | print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>]" | 230 | print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]" |
| 230 | print >> sys.stderr, "where: columns 'all' or 'branches'" | 231 | print >> sys.stderr, "where: columns 'all' or 'branches'" |
| 231 | print >> sys.stderr, " calls 'calls' => create calls table" | 232 | print >> sys.stderr, " calls 'calls' => create calls and call_paths table" |
| 233 | print >> sys.stderr, " callchains 'callchains' => create call_paths table" | ||
| 232 | raise Exception("Too few arguments") | 234 | raise Exception("Too few arguments") |
| 233 | 235 | ||
| 234 | if (len(sys.argv) < 2): | 236 | if (len(sys.argv) < 2): |
| @@ -246,9 +248,11 @@ if columns not in ("all", "branches"): · 11 unmodified lines | |||
| 246 | 248 | ||
| 247 | branches = (columns == "branches") | 249 | branches = (columns == "branches") |
| 248 | 250 | ||
| 249 | if (len(sys.argv) >= 4): | 251 | for i in range(3,len(sys.argv)): |
| 250 | if (sys.argv[3] == "calls"): | 252 | if (sys.argv[i] == "calls"): |
| 251 | perf_db_export_calls = True | 253 | perf_db_export_calls = True |
| 254 | elif (sys.argv[i] == "callchains"): | ||
| 255 | perf_db_export_callchains = True | ||
| 252 | else: | 256 | else: |
| 253 | usage() | 257 | usage() |
| 254 | 258 | ||
| @@ -359,14 +363,16 @@ else: · 104 unmodified lines | |||
| 359 | 'transaction bigint,' | 363 | 'transaction bigint,' |
| 360 | 'data_src bigint,' | 364 | 'data_src bigint,' |
| 361 | 'branch_type integer,' | 365 | 'branch_type integer,' |
| 362 | 'in_tx boolean)') | 366 | 'in_tx boolean,' |
| 367 | 'call_path_id bigint)') | ||
| 363 | 368 | ||
| 364 | if perf_db_export_calls: | 369 | if perf_db_export_calls or perf_db_export_callchains: |
| 365 | do_query(query, 'CREATE TABLE call_paths (' | 370 | do_query(query, 'CREATE TABLE call_paths (' |
| 366 | 'id bigint NOT NULL,' | 371 | 'id bigint NOT NULL,' |
| 367 | 'parent_id bigint,' | 372 | 'parent_id bigint,' |
| 368 | 'symbol_id bigint,' | 373 | 'symbol_id bigint,' |
| 369 | 'ip bigint)') | 374 | 'ip bigint)') |
| 375 | if perf_db_export_calls: | ||
| 370 | do_query(query, 'CREATE TABLE calls (' | 376 | do_query(query, 'CREATE TABLE calls (' |
| 371 | 'id bigint NOT NULL,' | 377 | 'id bigint NOT NULL,' |
| 372 | 'thread_id bigint,' | 378 | 'thread_id bigint,' |
| @@ -428,7 +434,7 @@ do_query(query, 'CREATE VIEW comm_threads_view AS ' · 55 unmodified lines | |||
| 428 | '(SELECT tid FROM threads WHERE id = thread_id) AS tid' | 434 | '(SELECT tid FROM threads WHERE id = thread_id) AS tid' |
| 429 | ' FROM comm_threads') | 435 | ' FROM comm_threads') |
| 430 | 436 | ||
| 431 | if perf_db_export_calls: | 437 | if perf_db_export_calls or perf_db_export_callchains: |
| 432 | do_query(query, 'CREATE VIEW call_paths_view AS ' | 438 | do_query(query, 'CREATE VIEW call_paths_view AS ' |
| 433 | 'SELECT ' | 439 | 'SELECT ' |
| 434 | 'c.id,' | 440 | 'c.id,' |
| @@ -444,6 +450,7 @@ if perf_db_export_calls: · 9 unmodified lines | |||
| 444 | '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' | 450 | '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' |
| 445 | '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' | 451 | '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' |
| 446 | ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') | 452 | ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') |
| 453 | if perf_db_export_calls: | ||
| 447 | do_query(query, 'CREATE VIEW calls_view AS ' | 454 | do_query(query, 'CREATE VIEW calls_view AS ' |
| 448 | 'SELECT ' | 455 | 'SELECT ' |
| 449 | 'calls.id,' | 456 | 'calls.id,' |
| @@ -541,8 +548,9 @@ dso_file = open_output_file("dso_table.bin") · 91 unmodified lines | |||
| 541 | symbol_file = open_output_file("symbol_table.bin") | 548 | symbol_file = open_output_file("symbol_table.bin") |
| 542 | branch_type_file = open_output_file("branch_type_table.bin") | 549 | branch_type_file = open_output_file("branch_type_table.bin") |
| 543 | sample_file = open_output_file("sample_table.bin") | 550 | sample_file = open_output_file("sample_table.bin") |
| 544 | if perf_db_export_calls: | 551 | if perf_db_export_calls or perf_db_export_callchains: |
| 545 | call_path_file = open_output_file("call_path_table.bin") | 552 | call_path_file = open_output_file("call_path_table.bin") |
| 553 | if perf_db_export_calls: | ||
| 546 | call_file = open_output_file("call_table.bin") | 554 | call_file = open_output_file("call_table.bin") |
| 547 | 555 | ||
| 548 | def trace_begin(): | 556 | def trace_begin(): |
| @@ -554,8 +562,8 @@ def trace_begin(): · 5 unmodified lines | |||
| 554 | comm_table(0, "unknown") | 562 | comm_table(0, "unknown") |
| 555 | dso_table(0, 0, "unknown", "unknown", "") | 563 | dso_table(0, 0, "unknown", "unknown", "") |
| 556 | symbol_table(0, 0, 0, 0, 0, "unknown") | 564 | symbol_table(0, 0, 0, 0, 0, "unknown") |
| 557 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | 565 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
| 558 | if perf_db_export_calls: | 566 | if perf_db_export_calls or perf_db_export_callchains: |
| 559 | call_path_table(0, 0, 0, 0) | 567 | call_path_table(0, 0, 0, 0) |
| 560 | 568 | ||
| 561 | unhandled_count = 0 | 569 | unhandled_count = 0 |
| @@ -571,8 +579,9 @@ def trace_end(): · 9 unmodified lines | |||
| 571 | copy_output_file(symbol_file, "symbols") | 579 | copy_output_file(symbol_file, "symbols") |
| 572 | copy_output_file(branch_type_file, "branch_types") | 580 | copy_output_file(branch_type_file, "branch_types") |
| 573 | copy_output_file(sample_file, "samples") | 581 | copy_output_file(sample_file, "samples") |
| 574 | if perf_db_export_calls: | 582 | if perf_db_export_calls or perf_db_export_callchains: |
| 575 | copy_output_file(call_path_file, "call_paths") | 583 | copy_output_file(call_path_file, "call_paths") |
| 584 | if perf_db_export_calls: | ||
| 576 | copy_output_file(call_file, "calls") | 585 | copy_output_file(call_file, "calls") |
| 577 | 586 | ||
| 578 | print datetime.datetime.today(), "Removing intermediate files..." | 587 | print datetime.datetime.today(), "Removing intermediate files..." |
| @@ -585,8 +594,9 @@ def trace_end(): · 6 unmodified lines | |||
| 585 | remove_output_file(symbol_file) | 594 | remove_output_file(symbol_file) |
| 586 | remove_output_file(branch_type_file) | 595 | remove_output_file(branch_type_file) |
| 587 | remove_output_file(sample_file) | 596 | remove_output_file(sample_file) |
| 588 | if perf_db_export_calls: | 597 | if perf_db_export_calls or perf_db_export_callchains: |
| 589 | remove_output_file(call_path_file) | 598 | remove_output_file(call_path_file) |
| 599 | if perf_db_export_calls: | ||
| 590 | remove_output_file(call_file) | 600 | remove_output_file(call_file) |
| 591 | os.rmdir(output_dir_name) | 601 | os.rmdir(output_dir_name) |
| 592 | print datetime.datetime.today(), "Adding primary keys" | 602 | print datetime.datetime.today(), "Adding primary keys" |
| @@ -599,8 +609,9 @@ def trace_end(): · 6 unmodified lines | |||
| 599 | do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') | 609 | do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') |
| 600 | do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') | 610 | do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') |
| 601 | do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') | 611 | do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') |
| 602 | if perf_db_export_calls: | 612 | if perf_db_export_calls or perf_db_export_callchains: |
| 603 | do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)') | 613 | do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)') |
| 614 | if perf_db_export_calls: | ||
| 604 | do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') | 615 | do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') |
| 605 | 616 | ||
| 606 | print datetime.datetime.today(), "Adding foreign keys" | 617 | print datetime.datetime.today(), "Adding foreign keys" |
| @@ -623,10 +634,11 @@ def trace_end(): · 16 unmodified lines | |||
| 623 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' | 634 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' |
| 624 | 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' | 635 | 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' |
| 625 | 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') | 636 | 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') |
| 626 | if perf_db_export_calls: | 637 | if perf_db_export_calls or perf_db_export_callchains: |
| 627 | do_query(query, 'ALTER TABLE call_paths ' | 638 | do_query(query, 'ALTER TABLE call_paths ' |
| 628 | 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),' | 639 | 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),' |
| 629 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)') | 640 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)') |
| 641 | if perf_db_export_calls: | ||
| 630 | do_query(query, 'ALTER TABLE calls ' | 642 | do_query(query, 'ALTER TABLE calls ' |
| 631 | 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),' | 643 | 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),' |
| 632 | 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),' | 644 | 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),' |
| @@ -694,11 +706,11 @@ def branch_type_table(branch_type, name, *x): · 61 unmodified lines | |||
| 694 | value = struct.pack(fmt, 2, 4, branch_type, n, name) | 706 | value = struct.pack(fmt, 2, 4, branch_type, n, name) |
| 695 | branch_type_file.write(value) | 707 | branch_type_file.write(value) |
| 696 | 708 | ||
| 697 | def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x): | 709 | def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, call_path_id, *x): |
| 698 | if branches: | 710 | if branches: |
| 699 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx) | 711 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiBiq", 18, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx, 8, call_path_id) |
| 700 | else: | 712 | else: |
| 701 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx) | 713 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiBiq", 22, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx, 8, call_path_id) |
| 702 | sample_file.write(value) | 714 | sample_file.write(value) |
| 703 | 715 | ||
| 704 | def call_path_table(cp_id, parent_id, symbol_id, ip, *x): | 716 | def call_path_table(cp_id, parent_id, symbol_id, ip, *x): |
| @@ -37,6 +37,8 @@ perf-y += topology.o · 36 unmodified lines | |||
| 37 | perf-y += cpumap.o | 37 | perf-y += cpumap.o |
| 38 | perf-y += stat.o | 38 | perf-y += stat.o |
| 39 | perf-y += event_update.o | 39 | perf-y += event_update.o |
| 40 | perf-y += event-times.o | ||
| 41 | perf-y += backward-ring-buffer.o | ||
| 40 | 42 | ||
| 41 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build | 43 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build |
| 42 | $(call rule_mkdir) | 44 | $(call rule_mkdir) |
| @@ -0,0 +1,151 @@ | |||
| 1 | /* | ||
| 2 | * Test backward bit in event attribute, read ring buffer from end to | ||
| 3 | * beginning | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <perf.h> | ||
| 7 | #include <evlist.h> | ||
| 8 | #include <sys/prctl.h> | ||
| 9 | #include "tests.h" | ||
| 10 | #include "debug.h" | ||
| 11 | |||
| 12 | #define NR_ITERS 111 | ||
| 13 | |||
| 14 | static void testcase(void) | ||
| 15 | { | ||
| 16 | int i; | ||
| 17 | |||
| 18 | for (i = 0; i < NR_ITERS; i++) { | ||
| 19 | char proc_name[10]; | ||
| 20 | |||
| 21 | snprintf(proc_name, sizeof(proc_name), "p:%d\n", i); | ||
| 22 | prctl(PR_SET_NAME, proc_name); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | static int count_samples(struct perf_evlist *evlist, int *sample_count, | ||
| 27 | int *comm_count) | ||
| 28 | { | ||
| 29 | int i; | ||
| 30 | |||
| 31 | for (i = 0; i < evlist->nr_mmaps; i++) { | ||
| 32 | union perf_event *event; | ||
| 33 | |||
| 34 | perf_evlist__mmap_read_catchup(evlist, i); | ||
| 35 | while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) { | ||
| 36 | const u32 type = event->header.type; | ||
| 37 | |||
| 38 | switch (type) { | ||
| 39 | case PERF_RECORD_SAMPLE: | ||
| 40 | (*sample_count)++; | ||
| 41 | break; | ||
| 42 | case PERF_RECORD_COMM: | ||
| 43 | (*comm_count)++; | ||
| 44 | break; | ||
| 45 | default: | ||
| 46 | pr_err("Unexpected record of type %d\n", type); | ||
| 47 | return TEST_FAIL; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | } | ||
| 51 | return TEST_OK; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int do_test(struct perf_evlist *evlist, int mmap_pages, | ||
| 55 | int *sample_count, int *comm_count) | ||
| 56 | { | ||
| 57 | int err; | ||
| 58 | char sbuf[STRERR_BUFSIZE]; | ||
| 59 | |||
| 60 | err = perf_evlist__mmap(evlist, mmap_pages, true); | ||
| 61 | if (err < 0) { | ||
| 62 | pr_debug("perf_evlist__mmap: %s\n", | ||
| 63 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
| 64 | return TEST_FAIL; | ||
| 65 | } | ||
| 66 | |||
| 67 | perf_evlist__enable(evlist); | ||
| 68 | testcase(); | ||
| 69 | perf_evlist__disable(evlist); | ||
| 70 | |||
| 71 | err = count_samples(evlist, sample_count, comm_count); | ||
| 72 | perf_evlist__munmap(evlist); | ||
| 73 | return err; | ||
| 74 | } | ||
| 75 | |||
| 76 | |||
| 77 | int test__backward_ring_buffer(int subtest __maybe_unused) | ||
| 78 | { | ||
| 79 | int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0; | ||
| 80 | char pid[16], sbuf[STRERR_BUFSIZE]; | ||
| 81 | struct perf_evlist *evlist; | ||
| 82 | struct perf_evsel *evsel __maybe_unused; | ||
| 83 | struct parse_events_error parse_error; | ||
| 84 | struct record_opts opts = { | ||
| 85 | .target = { | ||
| 86 | .uid = UINT_MAX, | ||
| 87 | .uses_mmap = true, | ||
| 88 | }, | ||
| 89 | .freq = 0, | ||
| 90 | .mmap_pages = 256, | ||
| 91 | .default_interval = 1, | ||
| 92 | }; | ||
| 93 | |||
| 94 | snprintf(pid, sizeof(pid), "%d", getpid()); | ||
| 95 | pid[sizeof(pid) - 1] = '\0'; | ||
| 96 | opts.target.tid = opts.target.pid = pid; | ||
| 97 | |||
| 98 | evlist = perf_evlist__new(); | ||
| 99 | if (!evlist) { | ||
| 100 | pr_debug("No ehough memory to create evlist\n"); | ||
| 101 | return TEST_FAIL; | ||
| 102 | } | ||
| 103 | |||
| 104 | err = perf_evlist__create_maps(evlist, &opts.target); | ||
| 105 | if (err < 0) { | ||
| 106 | pr_debug("Not enough memory to create thread/cpu maps\n"); | ||
| 107 | goto out_delete_evlist; | ||
| 108 | } | ||
| 109 | |||
| 110 | bzero(&parse_error, sizeof(parse_error)); | ||
| 111 | err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error); | ||
| 112 | if (err) { | ||
| 113 | pr_debug("Failed to parse tracepoint event, try use root\n"); | ||
| 114 | ret = TEST_SKIP; | ||
| 115 | goto out_delete_evlist; | ||
| 116 | } | ||
| 117 | |||
| 118 | perf_evlist__config(evlist, &opts, NULL); | ||
| 119 | |||
| 120 | /* Set backward bit, ring buffer should be writing from end */ | ||
| 121 | evlist__for_each(evlist, evsel) | ||
| 122 | evsel->attr.write_backward = 1; | ||
| 123 | |||
| 124 | err = perf_evlist__open(evlist); | ||
| 125 | if (err < 0) { | ||
| 126 | pr_debug("perf_evlist__open: %s\n", | ||
| 127 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
| 128 | goto out_delete_evlist; | ||
| 129 | } | ||
| 130 | |||
| 131 | ret = TEST_FAIL; | ||
| 132 | err = do_test(evlist, opts.mmap_pages, &sample_count, | ||
| 133 | &comm_count); | ||
| 134 | if (err != TEST_OK) | ||
| 135 | goto out_delete_evlist; | ||
| 136 | |||
| 137 | if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) { | ||
| 138 | pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n", | ||
| 139 | sample_count, comm_count); | ||
| 140 | goto out_delete_evlist; | ||
| 141 | } | ||
| 142 | |||
| 143 | err = do_test(evlist, 1, &sample_count, &comm_count); | ||
| 144 | if (err != TEST_OK) | ||
| 145 | goto out_delete_evlist; | ||
| 146 | |||
| 147 | ret = TEST_OK; | ||
| 148 | out_delete_evlist: | ||
| 149 | perf_evlist__delete(evlist); | ||
| 150 | return ret; | ||
| 151 | } | ||
| @@ -138,7 +138,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), · 137 unmodified lines | |||
| 138 | perf_evlist__splice_list_tail(evlist, &parse_evlist.list); | 138 | perf_evlist__splice_list_tail(evlist, &parse_evlist.list); |
| 139 | evlist->nr_groups = parse_evlist.nr_groups; | 139 | evlist->nr_groups = parse_evlist.nr_groups; |
| 140 | 140 | ||
| 141 | perf_evlist__config(evlist, &opts); | 141 | perf_evlist__config(evlist, &opts, NULL); |
| 142 | 142 | ||
| 143 | err = perf_evlist__open(evlist); | 143 | err = perf_evlist__open(evlist); |
| 144 | if (err < 0) { | 144 | if (err < 0) { |
| @@ -203,6 +203,14 @@ static struct test generic_tests[] = { · 202 unmodified lines | |||
| 203 | .desc = "Test attr update synthesize", | 203 | .desc = "Test attr update synthesize", |
| 204 | .func = test__event_update, | 204 | .func = test__event_update, |
| 205 | }, | 205 | }, |
| 206 | { | ||
| 207 | .desc = "Test events times", | ||
| 208 | .func = test__event_times, | ||
| 209 | }, | ||
| 210 | { | ||
| 211 | .desc = "Test backward reading from ring buffer", | ||
| 212 | .func = test__backward_ring_buffer, | ||
| 213 | }, | ||
| 206 | { | 214 | { |
| 207 | .func = NULL, | 215 | .func = NULL, |
| 208 | }, | 216 | }, |
| @@ -532,7 +532,7 @@ static int do_test_code_reading(bool try_kcore) · 531 unmodified lines | |||
| 532 | goto out_put; | 532 | goto out_put; |
| 533 | } | 533 | } |
| 534 | 534 | ||
| 535 | perf_evlist__config(evlist, &opts); | 535 | perf_evlist__config(evlist, &opts, NULL); |
| 536 | 536 | ||
| 537 | evsel = perf_evlist__first(evlist); | 537 | evsel = perf_evlist__first(evlist); |
| 538 | 538 | ||
| @@ -202,7 +202,7 @@ static int dsos__create(int cnt, int size) · 201 unmodified lines | |||
| 202 | { | 202 | { |
| 203 | int i; | 203 | int i; |
| 204 | 204 | ||
| 205 | dsos = malloc(sizeof(dsos) * cnt); | 205 | dsos = malloc(sizeof(*dsos) * cnt); |
| 206 | TEST_ASSERT_VAL("failed to alloc dsos array", dsos); | 206 | TEST_ASSERT_VAL("failed to alloc dsos array", dsos); |
| 207 | 207 | ||
| 208 | for (i = 0; i < cnt; i++) { | 208 | for (i = 0; i < cnt; i++) { |
| @@ -0,0 +1,236 @@ | |||
| 1 | #include <linux/compiler.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include "tests.h" | ||
| 4 | #include "evlist.h" | ||
| 5 | #include "evsel.h" | ||
| 6 | #include "util.h" | ||
| 7 | #include "debug.h" | ||
| 8 | #include "thread_map.h" | ||
| 9 | #include "target.h" | ||
| 10 | |||
| 11 | static int attach__enable_on_exec(struct perf_evlist *evlist) | ||
| 12 | { | ||
| 13 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
| 14 | struct target target = { | ||
| 15 | .uid = UINT_MAX, | ||
| 16 | }; | ||
| 17 | const char *argv[] = { "true", NULL, }; | ||
| 18 | char sbuf[STRERR_BUFSIZE]; | ||
| 19 | int err; | ||
| 20 | |||
| 21 | pr_debug("attaching to spawned child, enable on exec\n"); | ||
| 22 | |||
| 23 | err = perf_evlist__create_maps(evlist, &target); | ||
| 24 | if (err < 0) { | ||
| 25 | pr_debug("Not enough memory to create thread/cpu maps\n"); | ||
| 26 | return err; | ||
| 27 | } | ||
| 28 | |||
| 29 | err = perf_evlist__prepare_workload(evlist, &target, argv, false, NULL); | ||
| 30 | if (err < 0) { | ||
| 31 | pr_debug("Couldn't run the workload!\n"); | ||
| 32 | return err; | ||
| 33 | } | ||
| 34 | |||
| 35 | evsel->attr.enable_on_exec = 1; | ||
| 36 | |||
| 37 | err = perf_evlist__open(evlist); | ||
| 38 | if (err < 0) { | ||
| 39 | pr_debug("perf_evlist__open: %s\n", | ||
| 40 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
| 41 | return err; | ||
| 42 | } | ||
| 43 | |||
| 44 | return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int detach__enable_on_exec(struct perf_evlist *evlist) | ||
| 48 | { | ||
| 49 | waitpid(evlist->workload.pid, NULL, 0); | ||
| 50 | return 0; | ||
| 51 | } | ||
| 52 | |||
| 53 | static int attach__current_disabled(struct perf_evlist *evlist) | ||
| 54 | { | ||
| 55 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
| 56 | struct thread_map *threads; | ||
| 57 | int err; | ||
| 58 | |||
| 59 | pr_debug("attaching to current thread as disabled\n"); | ||
| 60 | |||
| 61 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
| 62 | if (threads == NULL) { | ||
| 63 | pr_debug("thread_map__new\n"); | ||
| 64 | return -1; | ||
| 65 | } | ||
| 66 | |||
| 67 | evsel->attr.disabled = 1; | ||
| 68 | |||
| 69 | err = perf_evsel__open_per_thread(evsel, threads); | ||
| 70 | if (err) { | ||
| 71 | pr_debug("Failed to open event cpu-clock:u\n"); | ||
| 72 | return err; | ||
| 73 | } | ||
| 74 | |||
| 75 | thread_map__put(threads); | ||
| 76 | return perf_evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; | ||
| 77 | } | ||
| 78 | |||
| 79 | static int attach__current_enabled(struct perf_evlist *evlist) | ||
| 80 | { | ||
| 81 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
| 82 | struct thread_map *threads; | ||
| 83 | int err; | ||
| 84 | |||
| 85 | pr_debug("attaching to current thread as enabled\n"); | ||
| 86 | |||
| 87 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
| 88 | if (threads == NULL) { | ||
| 89 | pr_debug("failed to call thread_map__new\n"); | ||
| 90 | return -1; | ||
| 91 | } | ||
| 92 | |||
| 93 | err = perf_evsel__open_per_thread(evsel, threads); | ||
| 94 | |||
| 95 | thread_map__put(threads); | ||
| 96 | return err == 0 ? TEST_OK : TEST_FAIL; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int detach__disable(struct perf_evlist *evlist) | ||
| 100 | { | ||
| 101 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
| 102 | |||
| 103 | return perf_evsel__enable(evsel); | ||
| 104 | } | ||
| 105 | |||
| 106 | static int attach__cpu_disabled(struct perf_evlist *evlist) | ||
| 107 | { | ||
| 108 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
| 109 | struct cpu_map *cpus; | ||
| 110 | int err; | ||
| 111 | |||
| 112 | pr_debug("attaching to CPU 0 as enabled\n"); | ||
| 113 | |||
| 114 | cpus = cpu_map__new("0"); | ||
| 115 | if (cpus == NULL) { | ||
| 116 | pr_debug("failed to call cpu_map__new\n"); | ||
| 117 | return -1; | ||
| 118 | } | ||
| 119 | |||
| 120 | evsel->attr.disabled = 1; | ||
| 121 | |||
| 122 | err = perf_evsel__open_per_cpu(evsel, cpus); | ||
| 123 | if (err) { | ||
| 124 | if (err == -EACCES) | ||
| 125 | return TEST_SKIP; | ||
| 126 | |||
| 127 | pr_debug("Failed to open event cpu-clock:u\n"); | ||
| 128 | return err; | ||
| 129 | } | ||
| 130 | |||
| 131 | cpu_map__put(cpus); | ||
| 132 | return perf_evsel__enable(evsel); | ||
| 133 | } | ||
| 134 | |||
| 135 | static int attach__cpu_enabled(struct perf_evlist *evlist) | ||
| 136 | { | ||
| 137 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
| 138 | struct cpu_map *cpus; | ||
| 139 | int err; | ||
| 140 | |||
| 141 | pr_debug("attaching to CPU 0 as enabled\n"); | ||
| 142 | |||
| 143 | cpus = cpu_map__new("0"); | ||
| 144 | if (cpus == NULL) { | ||
| 145 | pr_debug("failed to call cpu_map__new\n"); | ||
| 146 | return -1; | ||
| 147 | } | ||
| 148 | |||
| 149 | err = perf_evsel__open_per_cpu(evsel, cpus); | ||
| 150 | if (err == -EACCES) | ||
| 151 | return TEST_SKIP; | ||
| 152 | |||
| 153 | cpu_map__put(cpus); | ||
| 154 | return err ? TEST_FAIL : TEST_OK; | ||
| 155 | } | ||
| 156 | |||
| 157 | static int test_times(int (attach)(struct perf_evlist *), | ||
| 158 | int (detach)(struct perf_evlist *)) | ||
| 159 | { | ||
| 160 | struct perf_counts_values count; | ||
| 161 | struct perf_evlist *evlist = NULL; | ||
| 162 | struct perf_evsel *evsel; | ||
| 163 | int err = -1, i; | ||
| 164 | |||
| 165 | evlist = perf_evlist__new(); | ||
| 166 | if (!evlist) { | ||
| 167 | pr_debug("failed to create event list\n"); | ||
| 168 | goto out_err; | ||
| 169 | } | ||
| 170 | |||
| 171 | err = parse_events(evlist, "cpu-clock:u", NULL); | ||
| 172 | if (err) { | ||
| 173 | pr_debug("failed to parse event cpu-clock:u\n"); | ||
| 174 | goto out_err; | ||
| 175 | } | ||
| 176 | |||
| 177 | evsel = perf_evlist__last(evlist); | ||
| 178 | evsel->attr.read_format |= | ||
| 179 | PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
| 180 | PERF_FORMAT_TOTAL_TIME_RUNNING; | ||
| 181 | |||
| 182 | err = attach(evlist); | ||
| 183 | if (err == TEST_SKIP) { | ||
| 184 | pr_debug(" SKIP : not enough rights\n"); | ||
| 185 | return err; | ||
| 186 | } | ||
| 187 | |||
| 188 | TEST_ASSERT_VAL("failed to attach", !err); | ||
| 189 | |||
| 190 | for (i = 0; i < 100000000; i++) { } | ||
| 191 | |||
| 192 | TEST_ASSERT_VAL("failed to detach", !detach(evlist)); | ||
| 193 | |||
| 194 | perf_evsel__read(evsel, 0, 0, &count); | ||
| 195 | |||
| 196 | err = !(count.ena == count.run); | ||
| 197 | |||
| 198 | pr_debug(" %s: ena %" PRIu64", run %" PRIu64"\n", | ||
| 199 | !err ? "OK " : "FAILED", | ||
| 200 | count.ena, count.run); | ||
| 201 | |||
| 202 | out_err: | ||
| 203 | if (evlist) | ||
| 204 | perf_evlist__delete(evlist); | ||
| 205 | return !err ? TEST_OK : TEST_FAIL; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * This test creates software event 'cpu-clock' | ||
| 210 | * attaches it in several ways (explained below) | ||
| 211 | * and checks that enabled and running times | ||
| 212 | * match. | ||
| 213 | */ | ||
| 214 | int test__event_times(int subtest __maybe_unused) | ||
| 215 | { | ||
| 216 | int err, ret = 0; | ||
| 217 | |||
| 218 | #define _T(attach, detach) \ | ||
| 219 | err = test_times(attach, detach); \ | ||
| 220 | if (err && (ret == TEST_OK || ret == TEST_SKIP)) \ | ||
| 221 | ret = err; | ||
| 222 | |||
| 223 | /* attach on newly spawned process after exec */ | ||
| 224 | _T(attach__enable_on_exec, detach__enable_on_exec) | ||
| 225 | /* attach on current process as enabled */ | ||
| 226 | _T(attach__current_enabled, detach__disable) | ||
| 227 | /* attach on current process as disabled */ | ||
| 228 | _T(attach__current_disabled, detach__disable) | ||
| 229 | /* attach on cpu as disabled */ | ||
| 230 | _T(attach__cpu_disabled, detach__disable) | ||
| 231 | /* attach on cpu as enabled */ | ||
| 232 | _T(attach__cpu_enabled, detach__disable) | ||
| 233 | |||
| 234 | #undef _T | ||
| 235 | return ret; | ||
| 236 | } | ||
| @@ -30,7 +30,7 @@ static int process_event_scale(struct perf_tool *tool __maybe_unused, · 29 unmodified lines | |||
| 30 | 30 | ||
| 31 | TEST_ASSERT_VAL("wrong id", ev->id == 123); | 31 | TEST_ASSERT_VAL("wrong id", ev->id == 123); |
| 32 | TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); | 32 | TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); |
| 33 | TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123); | 33 | TEST_ASSERT_VAL("wrong scale", ev_data->scale == 0.123); |
| 34 | return 0; | 34 | return 0; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| @@ -161,7 +161,7 @@ void print_hists_in(struct hists *hists) · 160 unmodified lines | |||
| 161 | struct rb_root *root; | 161 | struct rb_root *root; |
| 162 | struct rb_node *node; | 162 | struct rb_node *node; |
| 163 | 163 | ||
| 164 | if (sort__need_collapse) | 164 | if (hists__has(hists, need_collapse)) |
| 165 | root = &hists->entries_collapsed; | 165 | root = &hists->entries_collapsed; |
| 166 | else | 166 | else |
| 167 | root = hists->entries_in; | 167 | root = hists->entries_in; |
| @@ -101,7 +101,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) · 100 unmodified lines | |||
| 101 | if (machine__resolve(machine, &al, &sample) < 0) | 101 | if (machine__resolve(machine, &al, &sample) < 0) |
| 102 | goto out; | 102 | goto out; |
| 103 | 103 | ||
| 104 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, | 104 | if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack, |
| 105 | NULL) < 0) { | 105 | NULL) < 0) { |
| 106 | addr_location__put(&al); | 106 | addr_location__put(&al); |
| 107 | goto out; | 107 | goto out; |
| @@ -126,7 +126,7 @@ static void del_hist_entries(struct hists *hists) · 18 unmodified lines | |||
| 126 | struct rb_root *root_out; | 126 | struct rb_root *root_out; |
| 127 | struct rb_node *node; | 127 | struct rb_node *node; |
| 128 | 128 | ||
| 129 | if (sort__need_collapse) | 129 | if (hists__has(hists, need_collapse)) |
| 130 | root_in = &hists->entries_collapsed; | 130 | root_in = &hists->entries_collapsed; |
| 131 | else | 131 | else |
| 132 | root_in = hists->entries_in; | 132 | root_in = hists->entries_in; |
| @@ -81,7 +81,7 @@ static int add_hist_entries(struct perf_evlist *evlist, · 80 unmodified lines | |||
| 81 | 81 | ||
| 82 | al.socket = fake_samples[i].socket; | 82 | al.socket = fake_samples[i].socket; |
| 83 | if (hist_entry_iter__add(&iter, &al, | 83 | if (hist_entry_iter__add(&iter, &al, |
| 84 | PERF_MAX_STACK_DEPTH, NULL) < 0) { | 84 | sysctl_perf_event_max_stack, NULL) < 0) { |
| 85 | addr_location__put(&al); | 85 | addr_location__put(&al); |
| 86 | goto out; | 86 | goto out; |
| 87 | } | 87 | } |
| @@ -145,7 +145,7 @@ static int __validate_match(struct hists *hists) · 144 unmodified lines | |||
| 145 | /* | 145 | /* |
| 146 | * Only entries from fake_common_samples should have a pair. | 146 | * Only entries from fake_common_samples should have a pair. |
| 147 | */ | 147 | */ |
| 148 | if (sort__need_collapse) | 148 | if (hists__has(hists, need_collapse)) |
| 149 | root = &hists->entries_collapsed; | 149 | root = &hists->entries_collapsed; |
| 150 | else | 150 | else |
| 151 | root = hists->entries_in; | 151 | root = hists->entries_in; |
| @@ -197,7 +197,7 @@ static int __validate_link(struct hists *hists, int idx) · 45 unmodified lines | |||
| 197 | * and some entries will have no pair. However every entry | 197 | * and some entries will have no pair. However every entry |
| 198 | * in other hists should have (dummy) pair. | 198 | * in other hists should have (dummy) pair. |
| 199 | */ | 199 | */ |
| 200 | if (sort__need_collapse) | 200 | if (hists__has(hists, need_collapse)) |
| 201 | root = &hists->entries_collapsed; | 201 | root = &hists->entries_collapsed; |
| 202 | else | 202 | else |
| 203 | root = hists->entries_in; | 203 | root = hists->entries_in; |
| @@ -67,7 +67,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) · 66 unmodified lines | |||
| 67 | if (machine__resolve(machine, &al, &sample) < 0) | 67 | if (machine__resolve(machine, &al, &sample) < 0) |
| 68 | goto out; | 68 | goto out; |
| 69 | 69 | ||
| 70 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, | 70 | if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack, |
| 71 | NULL) < 0) { | 71 | NULL) < 0) { |
| 72 | addr_location__put(&al); | 72 | addr_location__put(&al); |
| 73 | goto out; | 73 | goto out; |
| @@ -92,7 +92,7 @@ static void del_hist_entries(struct hists *hists) · 18 unmodified lines | |||
| 92 | struct rb_root *root_out; | 92 | struct rb_root *root_out; |
| 93 | struct rb_node *node; | 93 | struct rb_node *node; |
| 94 | 94 | ||
| 95 | if (sort__need_collapse) | 95 | if (hists__has(hists, need_collapse)) |
| 96 | root_in = &hists->entries_collapsed; | 96 | root_in = &hists->entries_collapsed; |
| 97 | else | 97 | else |
| 98 | root_in = hists->entries_in; | 98 | root_in = hists->entries_in; |
| @@ -80,7 +80,7 @@ int test__keep_tracking(int subtest __maybe_unused) · 79 unmodified lines | |||
| 80 | CHECK__(parse_events(evlist, "dummy:u", NULL)); | 80 | CHECK__(parse_events(evlist, "dummy:u", NULL)); |
| 81 | CHECK__(parse_events(evlist, "cycles:u", NULL)); | 81 | CHECK__(parse_events(evlist, "cycles:u", NULL)); |
| 82 | 82 | ||
| 83 | perf_evlist__config(evlist, &opts); | 83 | perf_evlist__config(evlist, &opts, NULL); |
| 84 | 84 | ||
| 85 | evsel = perf_evlist__first(evlist); | 85 | evsel = perf_evlist__first(evlist); |
| 86 | 86 | ||
| @@ -44,7 +44,7 @@ int test__syscall_openat_tp_fields(int subtest __maybe_unused) · 43 unmodified lines | |||
| 44 | goto out_delete_evlist; | 44 | goto out_delete_evlist; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | perf_evsel__config(evsel, &opts); | 47 | perf_evsel__config(evsel, &opts, NULL); |
| 48 | 48 | ||
| 49 | thread_map__set_pid(evlist->threads, 0, getpid()); | 49 | thread_map__set_pid(evlist->threads, 0, getpid()); |
| 50 | 50 | ||
| @@ -99,7 +99,7 @@ int test__PERF_RECORD(int subtest __maybe_unused) · 98 unmodified lines | |||
| 99 | perf_evsel__set_sample_bit(evsel, CPU); | 99 | perf_evsel__set_sample_bit(evsel, CPU); |
| 100 | perf_evsel__set_sample_bit(evsel, TID); | 100 | perf_evsel__set_sample_bit(evsel, TID); |
| 101 | perf_evsel__set_sample_bit(evsel, TIME); | 101 | perf_evsel__set_sample_bit(evsel, TIME); |
| 102 | perf_evlist__config(evlist, &opts); | 102 | perf_evlist__config(evlist, &opts, NULL); |
| 103 | 103 | ||
| 104 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); | 104 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); |
| 105 | if (err < 0) { | 105 | if (err < 0) { |
| @@ -417,7 +417,7 @@ int test__switch_tracking(int subtest __maybe_unused) · 416 unmodified lines | |||
| 417 | perf_evsel__set_sample_bit(tracking_evsel, TIME); | 417 | perf_evsel__set_sample_bit(tracking_evsel, TIME); |
| 418 | 418 | ||
| 419 | /* Config events */ | 419 | /* Config events */ |
| 420 | perf_evlist__config(evlist, &opts); | 420 | perf_evlist__config(evlist, &opts, NULL); |
| 421 | 421 | ||
| 422 | /* Check moved event is still at the front */ | 422 | /* Check moved event is still at the front */ |
| 423 | if (cycles_evsel != perf_evlist__first(evlist)) { | 423 | if (cycles_evsel != perf_evlist__first(evlist)) { |
| @@ -85,6 +85,8 @@ int test__synthesize_stat_config(int subtest); · 84 unmodified lines | |||
| 85 | int test__synthesize_stat(int subtest); | 85 | int test__synthesize_stat(int subtest); |
| 86 | int test__synthesize_stat_round(int subtest); | 86 | int test__synthesize_stat_round(int subtest); |
| 87 | int test__event_update(int subtest); | 87 | int test__event_update(int subtest); |
| 88 | int test__event_times(int subtest); | ||
| 89 | int test__backward_ring_buffer(int subtest); | ||
| 88 | 90 | ||
| 89 | #if defined(__arm__) || defined(__aarch64__) | 91 | #if defined(__arm__) || defined(__aarch64__) |
| 90 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 92 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
| @@ -54,8 +54,14 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) · 53 unmodified lines | |||
| 54 | * Step 3: | 54 | * Step 3: |
| 55 | * | 55 | * |
| 56 | * Load and split /proc/kallsyms into multiple maps, one per module. | 56 | * Load and split /proc/kallsyms into multiple maps, one per module. |
| 57 | * Do not use kcore, as this test was designed before kcore support | ||
| 58 | * and has parts that only make sense if using the non-kcore code. | ||
| 59 | * XXX: extend it to stress the kcorre code as well, hint: the list | ||
| 60 | * of modules extracted from /proc/kcore, in its current form, can't | ||
| 61 | * be compacted against the list of modules found in the "vmlinux" | ||
| 62 | * code and with the one got from /proc/modules from the "kallsyms" code. | ||
| 57 | */ | 63 | */ |
| 58 | if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) { | 64 | if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true, NULL) <= 0) { |
| 59 | pr_debug("dso__load_kallsyms "); | 65 | pr_debug("dso__load_kallsyms "); |
| 60 | goto out; | 66 | goto out; |
| 61 | } | 67 | } |
| @@ -157,6 +163,9 @@ next_pair: · 95 unmodified lines | |||
| 157 | 163 | ||
| 158 | pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", | 164 | pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", |
| 159 | mem_start, sym->name, pair->name); | 165 | mem_start, sym->name, pair->name); |
| 166 | } else { | ||
| 167 | pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", | ||
| 168 | mem_start, sym->name, first_pair->name); | ||
| 160 | } | 169 | } |
| 161 | } | 170 | } |
| 162 | } else | 171 | } else |
| @@ -0,0 +1,38 @@ | |||
| 1 | #include <sys/eventfd.h> | ||
| 2 | |||
| 3 | #ifndef EFD_SEMAPHORE | ||
| 4 | #define EFD_SEMAPHORE 1 | ||
| 5 | #endif | ||
| 6 | |||
| 7 | #ifndef EFD_NONBLOCK | ||
| 8 | #define EFD_NONBLOCK 00004000 | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #ifndef EFD_CLOEXEC | ||
| 12 | #define EFD_CLOEXEC 02000000 | ||
| 13 | #endif | ||
| 14 | |||
| 15 | static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size, struct syscall_arg *arg) | ||
| 16 | { | ||
| 17 | int printed = 0, flags = arg->val; | ||
| 18 | |||
| 19 | if (flags == 0) | ||
| 20 | return scnprintf(bf, size, "NONE"); | ||
| 21 | #define P_FLAG(n) \ | ||
| 22 | if (flags & EFD_##n) { \ | ||
| 23 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 24 | flags &= ~EFD_##n; \ | ||
| 25 | } | ||
| 26 | |||
| 27 | P_FLAG(SEMAPHORE); | ||
| 28 | P_FLAG(CLOEXEC); | ||
| 29 | P_FLAG(NONBLOCK); | ||
| 30 | #undef P_FLAG | ||
| 31 | |||
| 32 | if (flags) | ||
| 33 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 34 | |||
| 35 | return printed; | ||
| 36 | } | ||
| 37 | |||
| 38 | #define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags | ||
| @@ -0,0 +1,31 @@ | |||
| 1 | |||
| 2 | static size_t syscall_arg__scnprintf_flock(char *bf, size_t size, | ||
| 3 | struct syscall_arg *arg) | ||
| 4 | { | ||
| 5 | int printed = 0, op = arg->val; | ||
| 6 | |||
| 7 | if (op == 0) | ||
| 8 | return scnprintf(bf, size, "NONE"); | ||
| 9 | #define P_CMD(cmd) \ | ||
| 10 | if ((op & LOCK_##cmd) == LOCK_##cmd) { \ | ||
| 11 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \ | ||
| 12 | op &= ~LOCK_##cmd; \ | ||
| 13 | } | ||
| 14 | |||
| 15 | P_CMD(SH); | ||
| 16 | P_CMD(EX); | ||
| 17 | P_CMD(NB); | ||
| 18 | P_CMD(UN); | ||
| 19 | P_CMD(MAND); | ||
| 20 | P_CMD(RW); | ||
| 21 | P_CMD(READ); | ||
| 22 | P_CMD(WRITE); | ||
| 23 | #undef P_OP | ||
| 24 | |||
| 25 | if (op) | ||
| 26 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op); | ||
| 27 | |||
| 28 | return printed; | ||
| 29 | } | ||
| 30 | |||
| 31 | #define SCA_FLOCK syscall_arg__scnprintf_flock | ||
| @@ -0,0 +1,44 @@ | |||
| 1 | #include <linux/futex.h> | ||
| 2 | |||
| 3 | static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg) | ||
| 4 | { | ||
| 5 | enum syscall_futex_args { | ||
| 6 | SCF_UADDR = (1 << 0), | ||
| 7 | SCF_OP = (1 << 1), | ||
| 8 | SCF_VAL = (1 << 2), | ||
| 9 | SCF_TIMEOUT = (1 << 3), | ||
| 10 | SCF_UADDR2 = (1 << 4), | ||
| 11 | SCF_VAL3 = (1 << 5), | ||
| 12 | }; | ||
| 13 | int op = arg->val; | ||
| 14 | int cmd = op & FUTEX_CMD_MASK; | ||
| 15 | size_t printed = 0; | ||
| 16 | |||
| 17 | switch (cmd) { | ||
| 18 | #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n); | ||
| 19 | P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
| 20 | P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 21 | P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 22 | P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break; | ||
| 23 | P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break; | ||
| 24 | P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break; | ||
| 25 | P_FUTEX_OP(WAKE_OP); break; | ||
| 26 | P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 27 | P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
| 28 | P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
| 29 | P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break; | ||
| 30 | P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break; | ||
| 31 | P_FUTEX_OP(WAIT_REQUEUE_PI); break; | ||
| 32 | default: printed = scnprintf(bf, size, "%#x", cmd); break; | ||
| 33 | } | ||
| 34 | |||
| 35 | if (op & FUTEX_PRIVATE_FLAG) | ||
| 36 | printed += scnprintf(bf + printed, size - printed, "|PRIV"); | ||
| 37 | |||
| 38 | if (op & FUTEX_CLOCK_REALTIME) | ||
| 39 | printed += scnprintf(bf + printed, size - printed, "|CLKRT"); | ||
| 40 | |||
| 41 | return printed; | ||
| 42 | } | ||
| 43 | |||
| 44 | #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op | ||
| @@ -0,0 +1,158 @@ | |||
| 1 | #include <sys/mman.h> | ||
| 2 | |||
| 3 | static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, | ||
| 4 | struct syscall_arg *arg) | ||
| 5 | { | ||
| 6 | int printed = 0, prot = arg->val; | ||
| 7 | |||
| 8 | if (prot == PROT_NONE) | ||
| 9 | return scnprintf(bf, size, "NONE"); | ||
| 10 | #define P_MMAP_PROT(n) \ | ||
| 11 | if (prot & PROT_##n) { \ | ||
| 12 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 13 | prot &= ~PROT_##n; \ | ||
| 14 | } | ||
| 15 | |||
| 16 | P_MMAP_PROT(EXEC); | ||
| 17 | P_MMAP_PROT(READ); | ||
| 18 | P_MMAP_PROT(WRITE); | ||
| 19 | #ifdef PROT_SEM | ||
| 20 | P_MMAP_PROT(SEM); | ||
| 21 | #endif | ||
| 22 | P_MMAP_PROT(GROWSDOWN); | ||
| 23 | P_MMAP_PROT(GROWSUP); | ||
| 24 | #undef P_MMAP_PROT | ||
| 25 | |||
| 26 | if (prot) | ||
| 27 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot); | ||
| 28 | |||
| 29 | return printed; | ||
| 30 | } | ||
| 31 | |||
| 32 | #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot | ||
| 33 | |||
| 34 | #ifndef MAP_STACK | ||
| 35 | # define MAP_STACK 0x20000 | ||
| 36 | #endif | ||
| 37 | |||
| 38 | static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | ||
| 39 | struct syscall_arg *arg) | ||
| 40 | { | ||
| 41 | int printed = 0, flags = arg->val; | ||
| 42 | |||
| 43 | #define P_MMAP_FLAG(n) \ | ||
| 44 | if (flags & MAP_##n) { \ | ||
| 45 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 46 | flags &= ~MAP_##n; \ | ||
| 47 | } | ||
| 48 | |||
| 49 | P_MMAP_FLAG(SHARED); | ||
| 50 | P_MMAP_FLAG(PRIVATE); | ||
| 51 | #ifdef MAP_32BIT | ||
| 52 | P_MMAP_FLAG(32BIT); | ||
| 53 | #endif | ||
| 54 | P_MMAP_FLAG(ANONYMOUS); | ||
| 55 | P_MMAP_FLAG(DENYWRITE); | ||
| 56 | P_MMAP_FLAG(EXECUTABLE); | ||
| 57 | P_MMAP_FLAG(FILE); | ||
| 58 | P_MMAP_FLAG(FIXED); | ||
| 59 | P_MMAP_FLAG(GROWSDOWN); | ||
| 60 | #ifdef MAP_HUGETLB | ||
| 61 | P_MMAP_FLAG(HUGETLB); | ||
| 62 | #endif | ||
| 63 | P_MMAP_FLAG(LOCKED); | ||
| 64 | P_MMAP_FLAG(NONBLOCK); | ||
| 65 | P_MMAP_FLAG(NORESERVE); | ||
| 66 | P_MMAP_FLAG(POPULATE); | ||
| 67 | P_MMAP_FLAG(STACK); | ||
| 68 | #ifdef MAP_UNINITIALIZED | ||
| 69 | P_MMAP_FLAG(UNINITIALIZED); | ||
| 70 | #endif | ||
| 71 | #undef P_MMAP_FLAG | ||
| 72 | |||
| 73 | if (flags) | ||
| 74 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 75 | |||
| 76 | return printed; | ||
| 77 | } | ||
| 78 | |||
| 79 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags | ||
| 80 | |||
| 81 | static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, | ||
| 82 | struct syscall_arg *arg) | ||
| 83 | { | ||
| 84 | int printed = 0, flags = arg->val; | ||
| 85 | |||
| 86 | #define P_MREMAP_FLAG(n) \ | ||
| 87 | if (flags & MREMAP_##n) { \ | ||
| 88 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 89 | flags &= ~MREMAP_##n; \ | ||
| 90 | } | ||
| 91 | |||
| 92 | P_MREMAP_FLAG(MAYMOVE); | ||
| 93 | #ifdef MREMAP_FIXED | ||
| 94 | P_MREMAP_FLAG(FIXED); | ||
| 95 | #endif | ||
| 96 | #undef P_MREMAP_FLAG | ||
| 97 | |||
| 98 | if (flags) | ||
| 99 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 100 | |||
| 101 | return printed; | ||
| 102 | } | ||
| 103 | |||
| 104 | #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags | ||
| 105 | |||
| 106 | #ifndef MADV_HWPOISON | ||
| 107 | #define MADV_HWPOISON 100 | ||
| 108 | #endif | ||
| 109 | |||
| 110 | #ifndef MADV_MERGEABLE | ||
| 111 | #define MADV_MERGEABLE 12 | ||
| 112 | #endif | ||
| 113 | |||
| 114 | #ifndef MADV_UNMERGEABLE | ||
| 115 | #define MADV_UNMERGEABLE 13 | ||
| 116 | #endif | ||
| 117 | |||
| 118 | static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, | ||
| 119 | struct syscall_arg *arg) | ||
| 120 | { | ||
| 121 | int behavior = arg->val; | ||
| 122 | |||
| 123 | switch (behavior) { | ||
| 124 | #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) | ||
| 125 | P_MADV_BHV(NORMAL); | ||
| 126 | P_MADV_BHV(RANDOM); | ||
| 127 | P_MADV_BHV(SEQUENTIAL); | ||
| 128 | P_MADV_BHV(WILLNEED); | ||
| 129 | P_MADV_BHV(DONTNEED); | ||
| 130 | P_MADV_BHV(REMOVE); | ||
| 131 | P_MADV_BHV(DONTFORK); | ||
| 132 | P_MADV_BHV(DOFORK); | ||
| 133 | P_MADV_BHV(HWPOISON); | ||
| 134 | #ifdef MADV_SOFT_OFFLINE | ||
| 135 | P_MADV_BHV(SOFT_OFFLINE); | ||
| 136 | #endif | ||
| 137 | P_MADV_BHV(MERGEABLE); | ||
| 138 | P_MADV_BHV(UNMERGEABLE); | ||
| 139 | #ifdef MADV_HUGEPAGE | ||
| 140 | P_MADV_BHV(HUGEPAGE); | ||
| 141 | #endif | ||
| 142 | #ifdef MADV_NOHUGEPAGE | ||
| 143 | P_MADV_BHV(NOHUGEPAGE); | ||
| 144 | #endif | ||
| 145 | #ifdef MADV_DONTDUMP | ||
| 146 | P_MADV_BHV(DONTDUMP); | ||
| 147 | #endif | ||
| 148 | #ifdef MADV_DODUMP | ||
| 149 | P_MADV_BHV(DODUMP); | ||
| 150 | #endif | ||
| 151 | #undef P_MADV_PHV | ||
| 152 | default: break; | ||
| 153 | } | ||
| 154 | |||
| 155 | return scnprintf(bf, size, "%#x", behavior); | ||
| 156 | } | ||
| 157 | |||
| 158 | #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior | ||
| @@ -0,0 +1,68 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include <unistd.h> | ||
| 4 | |||
| 5 | /* From include/linux/stat.h */ | ||
| 6 | #ifndef S_IRWXUGO | ||
| 7 | #define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) | ||
| 8 | #endif | ||
| 9 | #ifndef S_IALLUGO | ||
| 10 | #define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) | ||
| 11 | #endif | ||
| 12 | #ifndef S_IRUGO | ||
| 13 | #define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) | ||
| 14 | #endif | ||
| 15 | #ifndef S_IWUGO | ||
| 16 | #define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) | ||
| 17 | #endif | ||
| 18 | #ifndef S_IXUGO | ||
| 19 | #define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) | ||
| 20 | #endif | ||
| 21 | |||
| 22 | static size_t syscall_arg__scnprintf_mode_t(char *bf, size_t size, struct syscall_arg *arg) | ||
| 23 | { | ||
| 24 | int printed = 0, mode = arg->val; | ||
| 25 | |||
| 26 | #define P_MODE(n) \ | ||
| 27 | if ((mode & S_##n) == S_##n) { \ | ||
| 28 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 29 | mode &= ~S_##n; \ | ||
| 30 | } | ||
| 31 | |||
| 32 | P_MODE(IALLUGO); | ||
| 33 | P_MODE(IRWXUGO); | ||
| 34 | P_MODE(IRUGO); | ||
| 35 | P_MODE(IWUGO); | ||
| 36 | P_MODE(IXUGO); | ||
| 37 | P_MODE(IFMT); | ||
| 38 | P_MODE(IFSOCK); | ||
| 39 | P_MODE(IFLNK); | ||
| 40 | P_MODE(IFREG); | ||
| 41 | P_MODE(IFBLK); | ||
| 42 | P_MODE(IFDIR); | ||
| 43 | P_MODE(IFCHR); | ||
| 44 | P_MODE(IFIFO); | ||
| 45 | P_MODE(ISUID); | ||
| 46 | P_MODE(ISGID); | ||
| 47 | P_MODE(ISVTX); | ||
| 48 | P_MODE(IRWXU); | ||
| 49 | P_MODE(IRUSR); | ||
| 50 | P_MODE(IWUSR); | ||
| 51 | P_MODE(IXUSR); | ||
| 52 | P_MODE(IRWXG); | ||
| 53 | P_MODE(IRGRP); | ||
| 54 | P_MODE(IWGRP); | ||
| 55 | P_MODE(IXGRP); | ||
| 56 | P_MODE(IRWXO); | ||
| 57 | P_MODE(IROTH); | ||
| 58 | P_MODE(IWOTH); | ||
| 59 | P_MODE(IXOTH); | ||
| 60 | #undef P_MODE | ||
| 61 | |||
| 62 | if (mode) | ||
| 63 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", mode); | ||
| 64 | |||
| 65 | return printed; | ||
| 66 | } | ||
| 67 | |||
| 68 | #define SCA_MODE_T syscall_arg__scnprintf_mode_t | ||
| @@ -0,0 +1,62 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/socket.h> | ||
| 3 | |||
| 4 | #ifndef MSG_PROBE | ||
| 5 | #define MSG_PROBE 0x10 | ||
| 6 | #endif | ||
| 7 | #ifndef MSG_WAITFORONE | ||
| 8 | #define MSG_WAITFORONE 0x10000 | ||
| 9 | #endif | ||
| 10 | #ifndef MSG_SENDPAGE_NOTLAST | ||
| 11 | #define MSG_SENDPAGE_NOTLAST 0x20000 | ||
| 12 | #endif | ||
| 13 | #ifndef MSG_FASTOPEN | ||
| 14 | #define MSG_FASTOPEN 0x20000000 | ||
| 15 | #endif | ||
| 16 | #ifndef MSG_CMSG_CLOEXEC | ||
| 17 | # define MSG_CMSG_CLOEXEC 0x40000000 | ||
| 18 | #endif | ||
| 19 | |||
| 20 | static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, | ||
| 21 | struct syscall_arg *arg) | ||
| 22 | { | ||
| 23 | int printed = 0, flags = arg->val; | ||
| 24 | |||
| 25 | if (flags == 0) | ||
| 26 | return scnprintf(bf, size, "NONE"); | ||
| 27 | #define P_MSG_FLAG(n) \ | ||
| 28 | if (flags & MSG_##n) { \ | ||
| 29 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 30 | flags &= ~MSG_##n; \ | ||
| 31 | } | ||
| 32 | |||
| 33 | P_MSG_FLAG(OOB); | ||
| 34 | P_MSG_FLAG(PEEK); | ||
| 35 | P_MSG_FLAG(DONTROUTE); | ||
| 36 | P_MSG_FLAG(TRYHARD); | ||
| 37 | P_MSG_FLAG(CTRUNC); | ||
| 38 | P_MSG_FLAG(PROBE); | ||
| 39 | P_MSG_FLAG(TRUNC); | ||
| 40 | P_MSG_FLAG(DONTWAIT); | ||
| 41 | P_MSG_FLAG(EOR); | ||
| 42 | P_MSG_FLAG(WAITALL); | ||
| 43 | P_MSG_FLAG(FIN); | ||
| 44 | P_MSG_FLAG(SYN); | ||
| 45 | P_MSG_FLAG(CONFIRM); | ||
| 46 | P_MSG_FLAG(RST); | ||
| 47 | P_MSG_FLAG(ERRQUEUE); | ||
| 48 | P_MSG_FLAG(NOSIGNAL); | ||
| 49 | P_MSG_FLAG(MORE); | ||
| 50 | P_MSG_FLAG(WAITFORONE); | ||
| 51 | P_MSG_FLAG(SENDPAGE_NOTLAST); | ||
| 52 | P_MSG_FLAG(FASTOPEN); | ||
| 53 | P_MSG_FLAG(CMSG_CLOEXEC); | ||
| 54 | #undef P_MSG_FLAG | ||
| 55 | |||
| 56 | if (flags) | ||
| 57 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 58 | |||
| 59 | return printed; | ||
| 60 | } | ||
| 61 | |||
| 62 | #define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags | ||
| @@ -0,0 +1,56 @@ | |||
| 1 | |||
| 2 | static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, | ||
| 3 | struct syscall_arg *arg) | ||
| 4 | { | ||
| 5 | int printed = 0, flags = arg->val; | ||
| 6 | |||
| 7 | if (!(flags & O_CREAT)) | ||
| 8 | arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */ | ||
| 9 | |||
| 10 | if (flags == 0) | ||
| 11 | return scnprintf(bf, size, "RDONLY"); | ||
| 12 | #define P_FLAG(n) \ | ||
| 13 | if (flags & O_##n) { \ | ||
| 14 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 15 | flags &= ~O_##n; \ | ||
| 16 | } | ||
| 17 | |||
| 18 | P_FLAG(APPEND); | ||
| 19 | P_FLAG(ASYNC); | ||
| 20 | P_FLAG(CLOEXEC); | ||
| 21 | P_FLAG(CREAT); | ||
| 22 | P_FLAG(DIRECT); | ||
| 23 | P_FLAG(DIRECTORY); | ||
| 24 | P_FLAG(EXCL); | ||
| 25 | P_FLAG(LARGEFILE); | ||
| 26 | P_FLAG(NOATIME); | ||
| 27 | P_FLAG(NOCTTY); | ||
| 28 | #ifdef O_NONBLOCK | ||
| 29 | P_FLAG(NONBLOCK); | ||
| 30 | #elif O_NDELAY | ||
| 31 | P_FLAG(NDELAY); | ||
| 32 | #endif | ||
| 33 | #ifdef O_PATH | ||
| 34 | P_FLAG(PATH); | ||
| 35 | #endif | ||
| 36 | P_FLAG(RDWR); | ||
| 37 | #ifdef O_DSYNC | ||
| 38 | if ((flags & O_SYNC) == O_SYNC) | ||
| 39 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC"); | ||
| 40 | else { | ||
| 41 | P_FLAG(DSYNC); | ||
| 42 | } | ||
| 43 | #else | ||
| 44 | P_FLAG(SYNC); | ||
| 45 | #endif | ||
| 46 | P_FLAG(TRUNC); | ||
| 47 | P_FLAG(WRONLY); | ||
| 48 | #undef P_FLAG | ||
| 49 | |||
| 50 | if (flags) | ||
| 51 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 52 | |||
| 53 | return printed; | ||
| 54 | } | ||
| 55 | |||
| 56 | #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | #ifndef PERF_FLAG_FD_NO_GROUP | ||
| 2 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) | ||
| 3 | #endif | ||
| 4 | |||
| 5 | #ifndef PERF_FLAG_FD_OUTPUT | ||
| 6 | # define PERF_FLAG_FD_OUTPUT (1UL << 1) | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #ifndef PERF_FLAG_PID_CGROUP | ||
| 10 | # define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #ifndef PERF_FLAG_FD_CLOEXEC | ||
| 14 | # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ | ||
| 15 | #endif | ||
| 16 | |||
| 17 | static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, | ||
| 18 | struct syscall_arg *arg) | ||
| 19 | { | ||
| 20 | int printed = 0, flags = arg->val; | ||
| 21 | |||
| 22 | if (flags == 0) | ||
| 23 | return 0; | ||
| 24 | |||
| 25 | #define P_FLAG(n) \ | ||
| 26 | if (flags & PERF_FLAG_##n) { \ | ||
| 27 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 28 | flags &= ~PERF_FLAG_##n; \ | ||
| 29 | } | ||
| 30 | |||
| 31 | P_FLAG(FD_NO_GROUP); | ||
| 32 | P_FLAG(FD_OUTPUT); | ||
| 33 | P_FLAG(PID_CGROUP); | ||
| 34 | P_FLAG(FD_CLOEXEC); | ||
| 35 | #undef P_FLAG | ||
| 36 | |||
| 37 | if (flags) | ||
| 38 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 39 | |||
| 40 | return printed; | ||
| 41 | } | ||
| 42 | |||
| 43 | #define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | static size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg) | ||
| 2 | { | ||
| 3 | int pid = arg->val; | ||
| 4 | struct trace *trace = arg->trace; | ||
| 5 | size_t printed = scnprintf(bf, size, "%d", pid); | ||
| 6 | struct thread *thread = machine__findnew_thread(trace->host, pid, pid); | ||
| 7 | |||
| 8 | if (thread != NULL) { | ||
| 9 | if (!thread->comm_set) | ||
| 10 | thread__set_comm_from_proc(thread); | ||
| 11 | |||
| 12 | if (thread->comm_set) | ||
| 13 | printed += scnprintf(bf + printed, size - printed, | ||
| 14 | " (%s)", thread__comm_str(thread)); | ||
| 15 | thread__put(thread); | ||
| 16 | } | ||
| 17 | |||
| 18 | return printed; | ||
| 19 | } | ||
| 20 | |||
| 21 | #define SCA_PID syscall_arg__scnprintf_pid | ||
| @@ -0,0 +1,44 @@ | |||
| 1 | #include <sched.h> | ||
| 2 | |||
| 3 | /* | ||
| 4 | * Not defined anywhere else, probably, just to make sure we | ||
| 5 | * catch future flags | ||
| 6 | */ | ||
| 7 | #define SCHED_POLICY_MASK 0xff | ||
| 8 | |||
| 9 | #ifndef SCHED_DEADLINE | ||
| 10 | #define SCHED_DEADLINE 6 | ||
| 11 | #endif | ||
| 12 | |||
| 13 | static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size, | ||
| 14 | struct syscall_arg *arg) | ||
| 15 | { | ||
| 16 | const char *policies[] = { | ||
| 17 | "NORMAL", "FIFO", "RR", "BATCH", "ISO", "IDLE", "DEADLINE", | ||
| 18 | }; | ||
| 19 | size_t printed; | ||
| 20 | int policy = arg->val, | ||
| 21 | flags = policy & ~SCHED_POLICY_MASK; | ||
| 22 | |||
| 23 | policy &= SCHED_POLICY_MASK; | ||
| 24 | if (policy <= SCHED_DEADLINE) | ||
| 25 | printed = scnprintf(bf, size, "%s", policies[policy]); | ||
| 26 | else | ||
| 27 | printed = scnprintf(bf, size, "%#x", policy); | ||
| 28 | |||
| 29 | #define P_POLICY_FLAG(n) \ | ||
| 30 | if (flags & SCHED_##n) { \ | ||
| 31 | printed += scnprintf(bf + printed, size - printed, "|%s", #n); \ | ||
| 32 | flags &= ~SCHED_##n; \ | ||
| 33 | } | ||
| 34 | |||
| 35 | P_POLICY_FLAG(RESET_ON_FORK); | ||
| 36 | #undef P_POLICY_FLAG | ||
| 37 | |||
| 38 | if (flags) | ||
| 39 | printed += scnprintf(bf + printed, size - printed, "|%#x", flags); | ||
| 40 | |||
| 41 | return printed; | ||
| 42 | } | ||
| 43 | |||
| 44 | #define SCA_SCHED_POLICY syscall_arg__scnprintf_sched_policy | ||
| @@ -0,0 +1,52 @@ | |||
| 1 | #include <linux/seccomp.h> | ||
| 2 | |||
| 3 | #ifndef SECCOMP_SET_MODE_STRICT | ||
| 4 | #define SECCOMP_SET_MODE_STRICT 0 | ||
| 5 | #endif | ||
| 6 | #ifndef SECCOMP_SET_MODE_FILTER | ||
| 7 | #define SECCOMP_SET_MODE_FILTER 1 | ||
| 8 | #endif | ||
| 9 | |||
| 10 | static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg) | ||
| 11 | { | ||
| 12 | int op = arg->val; | ||
| 13 | size_t printed = 0; | ||
| 14 | |||
| 15 | switch (op) { | ||
| 16 | #define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break | ||
| 17 | P_SECCOMP_SET_MODE_OP(STRICT); | ||
| 18 | P_SECCOMP_SET_MODE_OP(FILTER); | ||
| 19 | #undef P_SECCOMP_SET_MODE_OP | ||
| 20 | default: printed = scnprintf(bf, size, "%#x", op); break; | ||
| 21 | } | ||
| 22 | |||
| 23 | return printed; | ||
| 24 | } | ||
| 25 | |||
| 26 | #define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op | ||
| 27 | |||
| 28 | #ifndef SECCOMP_FILTER_FLAG_TSYNC | ||
| 29 | #define SECCOMP_FILTER_FLAG_TSYNC 1 | ||
| 30 | #endif | ||
| 31 | |||
| 32 | static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size, | ||
| 33 | struct syscall_arg *arg) | ||
| 34 | { | ||
| 35 | int printed = 0, flags = arg->val; | ||
| 36 | |||
| 37 | #define P_FLAG(n) \ | ||
| 38 | if (flags & SECCOMP_FILTER_FLAG_##n) { \ | ||
| 39 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 40 | flags &= ~SECCOMP_FILTER_FLAG_##n; \ | ||
| 41 | } | ||
| 42 | |||
| 43 | P_FLAG(TSYNC); | ||
| 44 | #undef P_FLAG | ||
| 45 | |||
| 46 | if (flags) | ||
| 47 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 48 | |||
| 49 | return printed; | ||
| 50 | } | ||
| 51 | |||
| 52 | #define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | |||
| 2 | static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) | ||
| 3 | { | ||
| 4 | int sig = arg->val; | ||
| 5 | |||
| 6 | switch (sig) { | ||
| 7 | #define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n) | ||
| 8 | P_SIGNUM(HUP); | ||
| 9 | P_SIGNUM(INT); | ||
| 10 | P_SIGNUM(QUIT); | ||
| 11 | P_SIGNUM(ILL); | ||
| 12 | P_SIGNUM(TRAP); | ||
| 13 | P_SIGNUM(ABRT); | ||
| 14 | P_SIGNUM(BUS); | ||
| 15 | P_SIGNUM(FPE); | ||
| 16 | P_SIGNUM(KILL); | ||
| 17 | P_SIGNUM(USR1); | ||
| 18 | P_SIGNUM(SEGV); | ||
| 19 | P_SIGNUM(USR2); | ||
| 20 | P_SIGNUM(PIPE); | ||
| 21 | P_SIGNUM(ALRM); | ||
| 22 | P_SIGNUM(TERM); | ||
| 23 | P_SIGNUM(CHLD); | ||
| 24 | P_SIGNUM(CONT); | ||
| 25 | P_SIGNUM(STOP); | ||
| 26 | P_SIGNUM(TSTP); | ||
| 27 | P_SIGNUM(TTIN); | ||
| 28 | P_SIGNUM(TTOU); | ||
| 29 | P_SIGNUM(URG); | ||
| 30 | P_SIGNUM(XCPU); | ||
| 31 | P_SIGNUM(XFSZ); | ||
| 32 | P_SIGNUM(VTALRM); | ||
| 33 | P_SIGNUM(PROF); | ||
| 34 | P_SIGNUM(WINCH); | ||
| 35 | P_SIGNUM(IO); | ||
| 36 | P_SIGNUM(PWR); | ||
| 37 | P_SIGNUM(SYS); | ||
| 38 | #ifdef SIGEMT | ||
| 39 | P_SIGNUM(EMT); | ||
| 40 | #endif | ||
| 41 | #ifdef SIGSTKFLT | ||
| 42 | P_SIGNUM(STKFLT); | ||
| 43 | #endif | ||
| 44 | #ifdef SIGSWI | ||
| 45 | P_SIGNUM(SWI); | ||
| 46 | #endif | ||
| 47 | default: break; | ||
| 48 | } | ||
| 49 | |||
| 50 | return scnprintf(bf, size, "%#x", sig); | ||
| 51 | } | ||
| 52 | |||
| 53 | #define SCA_SIGNUM syscall_arg__scnprintf_signum | ||
| @@ -0,0 +1,60 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/socket.h> | ||
| 3 | |||
| 4 | #ifndef SOCK_DCCP | ||
| 5 | # define SOCK_DCCP 6 | ||
| 6 | #endif | ||
| 7 | |||
| 8 | #ifndef SOCK_CLOEXEC | ||
| 9 | # define SOCK_CLOEXEC 02000000 | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #ifndef SOCK_NONBLOCK | ||
| 13 | # define SOCK_NONBLOCK 00004000 | ||
| 14 | #endif | ||
| 15 | |||
| 16 | #ifndef SOCK_TYPE_MASK | ||
| 17 | #define SOCK_TYPE_MASK 0xf | ||
| 18 | #endif | ||
| 19 | |||
| 20 | static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size, struct syscall_arg *arg) | ||
| 21 | { | ||
| 22 | size_t printed; | ||
| 23 | int type = arg->val, | ||
| 24 | flags = type & ~SOCK_TYPE_MASK; | ||
| 25 | |||
| 26 | type &= SOCK_TYPE_MASK; | ||
| 27 | /* | ||
| 28 | * Can't use a strarray, MIPS may override for ABI reasons. | ||
| 29 | */ | ||
| 30 | switch (type) { | ||
| 31 | #define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break; | ||
| 32 | P_SK_TYPE(STREAM); | ||
| 33 | P_SK_TYPE(DGRAM); | ||
| 34 | P_SK_TYPE(RAW); | ||
| 35 | P_SK_TYPE(RDM); | ||
| 36 | P_SK_TYPE(SEQPACKET); | ||
| 37 | P_SK_TYPE(DCCP); | ||
| 38 | P_SK_TYPE(PACKET); | ||
| 39 | #undef P_SK_TYPE | ||
| 40 | default: | ||
| 41 | printed = scnprintf(bf, size, "%#x", type); | ||
| 42 | } | ||
| 43 | |||
| 44 | #define P_SK_FLAG(n) \ | ||
| 45 | if (flags & SOCK_##n) { \ | ||
| 46 | printed += scnprintf(bf + printed, size - printed, "|%s", #n); \ | ||
| 47 | flags &= ~SOCK_##n; \ | ||
| 48 | } | ||
| 49 | |||
| 50 | P_SK_FLAG(CLOEXEC); | ||
| 51 | P_SK_FLAG(NONBLOCK); | ||
| 52 | #undef P_SK_FLAG | ||
| 53 | |||
| 54 | if (flags) | ||
| 55 | printed += scnprintf(bf + printed, size - printed, "|%#x", flags); | ||
| 56 | |||
| 57 | return printed; | ||
| 58 | } | ||
| 59 | |||
| 60 | #define SCA_SK_TYPE syscall_arg__scnprintf_socket_type | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/wait.h> | ||
| 3 | |||
| 4 | static size_t syscall_arg__scnprintf_waitid_options(char *bf, size_t size, | ||
| 5 | struct syscall_arg *arg) | ||
| 6 | { | ||
| 7 | int printed = 0, options = arg->val; | ||
| 8 | |||
| 9 | #define P_OPTION(n) \ | ||
| 10 | if (options & W##n) { \ | ||
| 11 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 12 | options &= ~W##n; \ | ||
| 13 | } | ||
| 14 | |||
| 15 | P_OPTION(NOHANG); | ||
| 16 | P_OPTION(UNTRACED); | ||
| 17 | P_OPTION(CONTINUED); | ||
| 18 | #undef P_OPTION | ||
| 19 | |||
| 20 | if (options) | ||
| 21 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", options); | ||
| 22 | |||
| 23 | return printed; | ||
| 24 | } | ||
| 25 | |||
| 26 | #define SCA_WAITID_OPTIONS syscall_arg__scnprintf_waitid_options | ||
| @@ -1607,9 +1607,8 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows · 1606 unmodified lines | |||
| 1607 | 1607 | ||
| 1608 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 1608 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); |
| 1609 | dummy_hpp.buf[ret] = '\0'; | 1609 | dummy_hpp.buf[ret] = '\0'; |
| 1610 | rtrim(dummy_hpp.buf); | ||
| 1611 | 1610 | ||
| 1612 | start = ltrim(dummy_hpp.buf); | 1611 | start = trim(dummy_hpp.buf); |
| 1613 | ret = strlen(start); | 1612 | ret = strlen(start); |
| 1614 | 1613 | ||
| 1615 | if (start != dummy_hpp.buf) | 1614 | if (start != dummy_hpp.buf) |
| @@ -1897,11 +1896,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, · 281 unmodified lines | |||
| 1897 | bool first = true; | 1896 | bool first = true; |
| 1898 | int ret; | 1897 | int ret; |
| 1899 | 1898 | ||
| 1900 | if (symbol_conf.use_callchain) | 1899 | if (symbol_conf.use_callchain) { |
| 1901 | folded_sign = hist_entry__folded(he); | 1900 | folded_sign = hist_entry__folded(he); |
| 1902 | |||
| 1903 | if (symbol_conf.use_callchain) | ||
| 1904 | printed += fprintf(fp, "%c ", folded_sign); | 1901 | printed += fprintf(fp, "%c ", folded_sign); |
| 1902 | } | ||
| 1905 | 1903 | ||
| 1906 | hists__for_each_format(browser->hists, fmt) { | 1904 | hists__for_each_format(browser->hists, fmt) { |
| 1907 | if (perf_hpp__should_skip(fmt, he->hists)) | 1905 | if (perf_hpp__should_skip(fmt, he->hists)) |
| @@ -2137,7 +2135,7 @@ static int hists__browser_title(struct hists *hists, · 229 unmodified lines | |||
| 2137 | printed += snprintf(bf + printed, size - printed, | 2135 | printed += snprintf(bf + printed, size - printed, |
| 2138 | ", UID: %s", hists->uid_filter_str); | 2136 | ", UID: %s", hists->uid_filter_str); |
| 2139 | if (thread) { | 2137 | if (thread) { |
| 2140 | if (sort__has_thread) { | 2138 | if (hists__has(hists, thread)) { |
| 2141 | printed += scnprintf(bf + printed, size - printed, | 2139 | printed += scnprintf(bf + printed, size - printed, |
| 2142 | ", Thread: %s(%d)", | 2140 | ", Thread: %s(%d)", |
| 2143 | (thread->comm_set ? thread__comm_str(thread) : ""), | 2141 | (thread->comm_set ? thread__comm_str(thread) : ""), |
| @@ -2322,7 +2320,8 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act) · 178 unmodified lines | |||
| 2322 | { | 2320 | { |
| 2323 | struct thread *thread = act->thread; | 2321 | struct thread *thread = act->thread; |
| 2324 | 2322 | ||
| 2325 | if ((!sort__has_thread && !sort__has_comm) || thread == NULL) | 2323 | if ((!hists__has(browser->hists, thread) && |
| 2324 | !hists__has(browser->hists, comm)) || thread == NULL) | ||
| 2326 | return 0; | 2325 | return 0; |
| 2327 | 2326 | ||
| 2328 | if (browser->hists->thread_filter) { | 2327 | if (browser->hists->thread_filter) { |
| @@ -2331,7 +2330,7 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act) · 2 unmodified lines | |||
| 2331 | thread__zput(browser->hists->thread_filter); | 2330 | thread__zput(browser->hists->thread_filter); |
| 2332 | ui_helpline__pop(); | 2331 | ui_helpline__pop(); |
| 2333 | } else { | 2332 | } else { |
| 2334 | if (sort__has_thread) { | 2333 | if (hists__has(browser->hists, thread)) { |
| 2335 | ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", | 2334 | ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", |
| 2336 | thread->comm_set ? thread__comm_str(thread) : "", | 2335 | thread->comm_set ? thread__comm_str(thread) : "", |
| 2337 | thread->tid); | 2336 | thread->tid); |
| @@ -2356,10 +2355,11 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act, · 18 unmodified lines | |||
| 2356 | { | 2355 | { |
| 2357 | int ret; | 2356 | int ret; |
| 2358 | 2357 | ||
| 2359 | if ((!sort__has_thread && !sort__has_comm) || thread == NULL) | 2358 | if ((!hists__has(browser->hists, thread) && |
| 2359 | !hists__has(browser->hists, comm)) || thread == NULL) | ||
| 2360 | return 0; | 2360 | return 0; |
| 2361 | 2361 | ||
| 2362 | if (sort__has_thread) { | 2362 | if (hists__has(browser->hists, thread)) { |
| 2363 | ret = asprintf(optstr, "Zoom %s %s(%d) thread", | 2363 | ret = asprintf(optstr, "Zoom %s %s(%d) thread", |
| 2364 | browser->hists->thread_filter ? "out of" : "into", | 2364 | browser->hists->thread_filter ? "out of" : "into", |
| 2365 | thread->comm_set ? thread__comm_str(thread) : "", | 2365 | thread->comm_set ? thread__comm_str(thread) : "", |
| @@ -2382,7 +2382,7 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) · 16 unmodified lines | |||
| 2382 | { | 2382 | { |
| 2383 | struct map *map = act->ms.map; | 2383 | struct map *map = act->ms.map; |
| 2384 | 2384 | ||
| 2385 | if (!sort__has_dso || map == NULL) | 2385 | if (!hists__has(browser->hists, dso) || map == NULL) |
| 2386 | return 0; | 2386 | return 0; |
| 2387 | 2387 | ||
| 2388 | if (browser->hists->dso_filter) { | 2388 | if (browser->hists->dso_filter) { |
| @@ -2409,7 +2409,7 @@ static int · 20 unmodified lines | |||
| 2409 | add_dso_opt(struct hist_browser *browser, struct popup_action *act, | 2409 | add_dso_opt(struct hist_browser *browser, struct popup_action *act, |
| 2410 | char **optstr, struct map *map) | 2410 | char **optstr, struct map *map) |
| 2411 | { | 2411 | { |
| 2412 | if (!sort__has_dso || map == NULL) | 2412 | if (!hists__has(browser->hists, dso) || map == NULL) |
| 2413 | return 0; | 2413 | return 0; |
| 2414 | 2414 | ||
| 2415 | if (asprintf(optstr, "Zoom %s %s DSO", | 2415 | if (asprintf(optstr, "Zoom %s %s DSO", |
| @@ -2431,10 +2431,10 @@ do_browse_map(struct hist_browser *browser __maybe_unused, · 15 unmodified lines | |||
| 2431 | } | 2431 | } |
| 2432 | 2432 | ||
| 2433 | static int | 2433 | static int |
| 2434 | add_map_opt(struct hist_browser *browser __maybe_unused, | 2434 | add_map_opt(struct hist_browser *browser, |
| 2435 | struct popup_action *act, char **optstr, struct map *map) | 2435 | struct popup_action *act, char **optstr, struct map *map) |
| 2436 | { | 2436 | { |
| 2437 | if (!sort__has_dso || map == NULL) | 2437 | if (!hists__has(browser->hists, dso) || map == NULL) |
| 2438 | return 0; | 2438 | return 0; |
| 2439 | 2439 | ||
| 2440 | if (asprintf(optstr, "Browse map details") < 0) | 2440 | if (asprintf(optstr, "Browse map details") < 0) |
| @@ -2536,7 +2536,7 @@ add_exit_opt(struct hist_browser *browser __maybe_unused, · 95 unmodified lines | |||
| 2536 | static int | 2536 | static int |
| 2537 | do_zoom_socket(struct hist_browser *browser, struct popup_action *act) | 2537 | do_zoom_socket(struct hist_browser *browser, struct popup_action *act) |
| 2538 | { | 2538 | { |
| 2539 | if (!sort__has_socket || act->socket < 0) | 2539 | if (!hists__has(browser->hists, socket) || act->socket < 0) |
| 2540 | return 0; | 2540 | return 0; |
| 2541 | 2541 | ||
| 2542 | if (browser->hists->socket_filter > -1) { | 2542 | if (browser->hists->socket_filter > -1) { |
| @@ -2558,7 +2558,7 @@ static int · 15 unmodified lines | |||
| 2558 | add_socket_opt(struct hist_browser *browser, struct popup_action *act, | 2558 | add_socket_opt(struct hist_browser *browser, struct popup_action *act, |
| 2559 | char **optstr, int socket_id) | 2559 | char **optstr, int socket_id) |
| 2560 | { | 2560 | { |
| 2561 | if (!sort__has_socket || socket_id < 0) | 2561 | if (!hists__has(browser->hists, socket) || socket_id < 0) |
| 2562 | return 0; | 2562 | return 0; |
| 2563 | 2563 | ||
| 2564 | if (asprintf(optstr, "Zoom %s Processor Socket %d", | 2564 | if (asprintf(optstr, "Zoom %s Processor Socket %d", |
| @@ -2749,7 +2749,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, · 184 unmodified lines | |||
| 2749 | */ | 2749 | */ |
| 2750 | goto out_free_stack; | 2750 | goto out_free_stack; |
| 2751 | case 'a': | 2751 | case 'a': |
| 2752 | if (!sort__has_sym) { | 2752 | if (!hists__has(hists, sym)) { |
| 2753 | ui_browser__warning(&browser->b, delay_secs * 2, | 2753 | ui_browser__warning(&browser->b, delay_secs * 2, |
| 2754 | "Annotation is only available for symbolic views, " | 2754 | "Annotation is only available for symbolic views, " |
| 2755 | "include \"sym*\" in --sort to use it."); | 2755 | "include \"sym*\" in --sort to use it."); |
| @@ -2912,7 +2912,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, · 156 unmodified lines | |||
| 2912 | continue; | 2912 | continue; |
| 2913 | } | 2913 | } |
| 2914 | 2914 | ||
| 2915 | if (!sort__has_sym || browser->selection == NULL) | 2915 | if (!hists__has(hists, sym) || browser->selection == NULL) |
| 2916 | goto skip_annotation; | 2916 | goto skip_annotation; |
| 2917 | 2917 | ||
| 2918 | if (sort__mode == SORT_MODE__BRANCH) { | 2918 | if (sort__mode == SORT_MODE__BRANCH) { |
| @@ -2956,7 +2956,7 @@ skip_annotation: · 37 unmodified lines | |||
| 2956 | goto skip_scripting; | 2956 | goto skip_scripting; |
| 2957 | 2957 | ||
| 2958 | if (browser->he_selection) { | 2958 | if (browser->he_selection) { |
| 2959 | if (sort__has_thread && thread) { | 2959 | if (hists__has(hists, thread) && thread) { |
| 2960 | nr_options += add_script_opt(browser, | 2960 | nr_options += add_script_opt(browser, |
| 2961 | &actions[nr_options], | 2961 | &actions[nr_options], |
| 2962 | &options[nr_options], | 2962 | &options[nr_options], |
| @@ -2971,7 +2971,7 @@ skip_annotation: · 8 unmodified lines | |||
| 2971 | * | 2971 | * |
| 2972 | * See hist_browser__show_entry. | 2972 | * See hist_browser__show_entry. |
| 2973 | */ | 2973 | */ |
| 2974 | if (sort__has_sym && browser->selection->sym) { | 2974 | if (hists__has(hists, sym) && browser->selection->sym) { |
| 2975 | nr_options += add_script_opt(browser, | 2975 | nr_options += add_script_opt(browser, |
| 2976 | &actions[nr_options], | 2976 | &actions[nr_options], |
| 2977 | &options[nr_options], | 2977 | &options[nr_options], |
| @@ -379,7 +379,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, · 378 unmodified lines | |||
| 379 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); | 379 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | if (symbol_conf.use_callchain && sort__has_sym) { | 382 | if (symbol_conf.use_callchain && hists__has(hists, sym)) { |
| 383 | if (callchain_param.mode == CHAIN_GRAPH_REL) | 383 | if (callchain_param.mode == CHAIN_GRAPH_REL) |
| 384 | total = symbol_conf.cumulate_callchain ? | 384 | total = symbol_conf.cumulate_callchain ? |
| 385 | h->stat_acc->period : h->stat.period; | 385 | h->stat_acc->period : h->stat.period; |
| @@ -635,7 +635,7 @@ unsigned int hists__sort_list_width(struct hists *hists) · 634 unmodified lines | |||
| 635 | ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); | 635 | ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); |
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | if (verbose && sort__has_sym) /* Addr + origin */ | 638 | if (verbose && hists__has(hists, sym)) /* Addr + origin */ |
| 639 | ret += 3 + BITS_PER_LONG / 4; | 639 | ret += 3 + BITS_PER_LONG / 4; |
| 640 | 640 | ||
| 641 | return ret; | 641 | return ret; |
| @@ -569,9 +569,8 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, · 568 unmodified lines | |||
| 569 | first_col = false; | 569 | first_col = false; |
| 570 | 570 | ||
| 571 | fmt->header(fmt, hpp, hists_to_evsel(hists)); | 571 | fmt->header(fmt, hpp, hists_to_evsel(hists)); |
| 572 | rtrim(hpp->buf); | ||
| 573 | 572 | ||
| 574 | header_width += fprintf(fp, "%s", ltrim(hpp->buf)); | 573 | header_width += fprintf(fp, "%s", trim(hpp->buf)); |
| 575 | } | 574 | } |
| 576 | } | 575 | } |
| 577 | 576 | ||
| @@ -8,6 +8,7 @@ libperf-y += env.o · 7 unmodified lines | |||
| 8 | libperf-y += event.o | 8 | libperf-y += event.o |
| 9 | libperf-y += evlist.o | 9 | libperf-y += evlist.o |
| 10 | libperf-y += evsel.o | 10 | libperf-y += evsel.o |
| 11 | libperf-y += evsel_fprintf.o | ||
| 11 | libperf-y += find_bit.o | 12 | libperf-y += find_bit.o |
| 12 | libperf-y += kallsyms.o | 13 | libperf-y += kallsyms.o |
| 13 | libperf-y += levenshtein.o | 14 | libperf-y += levenshtein.o |
| @@ -26,9 +27,9 @@ libperf-y += strlist.o · 12 unmodified lines | |||
| 26 | libperf-y += strfilter.o | 27 | libperf-y += strfilter.o |
| 27 | libperf-y += top.o | 28 | libperf-y += top.o |
| 28 | libperf-y += usage.o | 29 | libperf-y += usage.o |
| 29 | libperf-y += wrapper.o | ||
| 30 | libperf-y += dso.o | 30 | libperf-y += dso.o |
| 31 | libperf-y += symbol.o | 31 | libperf-y += symbol.o |
| 32 | libperf-y += symbol_fprintf.o | ||
| 32 | libperf-y += color.o | 33 | libperf-y += color.o |
| 33 | libperf-y += header.o | 34 | libperf-y += header.o |
| 34 | libperf-y += callchain.o | 35 | libperf-y += callchain.o |
| @@ -38,6 +39,7 @@ libperf-y += machine.o · 3 unmodified lines | |||
| 38 | libperf-y += map.o | 39 | libperf-y += map.o |
| 39 | libperf-y += pstack.o | 40 | libperf-y += pstack.o |
| 40 | libperf-y += session.o | 41 | libperf-y += session.o |
| 42 | libperf-$(CONFIG_AUDIT) += syscalltbl.o | ||
| 41 | libperf-y += ordered-events.o | 43 | libperf-y += ordered-events.o |
| 42 | libperf-y += comm.o | 44 | libperf-y += comm.o |
| 43 | libperf-y += thread.o | 45 | libperf-y += thread.o |
| @@ -69,9 +71,9 @@ libperf-y += stat-shadow.o · 25 unmodified lines | |||
| 69 | libperf-y += record.o | 71 | libperf-y += record.o |
| 70 | libperf-y += srcline.o | 72 | libperf-y += srcline.o |
| 71 | libperf-y += data.o | 73 | libperf-y += data.o |
| 72 | libperf-$(CONFIG_X86) += tsc.o | 74 | libperf-y += tsc.o |
| 73 | libperf-$(CONFIG_AUXTRACE) += tsc.o | ||
| 74 | libperf-y += cloexec.o | 75 | libperf-y += cloexec.o |
| 76 | libperf-y += call-path.o | ||
| 75 | libperf-y += thread-stack.o | 77 | libperf-y += thread-stack.o |
| 76 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o | 78 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o |
| 77 | libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ | 79 | libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ |
| @@ -1138,7 +1138,7 @@ fallback: · 1137 unmodified lines | |||
| 1138 | 1138 | ||
| 1139 | if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && | 1139 | if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && |
| 1140 | !dso__is_kcore(dso)) { | 1140 | !dso__is_kcore(dso)) { |
| 1141 | char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; | 1141 | char bf[SBUILD_ID_SIZE + 15] = " with build id "; |
| 1142 | char *build_id_msg = NULL; | 1142 | char *build_id_msg = NULL; |
| 1143 | 1143 | ||
| 1144 | if (dso->annotate_warned) | 1144 | if (dso->annotate_warned) |
| @@ -1665,5 +1665,5 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize) · 520 unmodified lines | |||
| 1665 | 1665 | ||
| 1666 | bool ui__has_annotation(void) | 1666 | bool ui__has_annotation(void) |
| 1667 | { | 1667 | { |
| 1668 | return use_browser == 1 && sort__has_sym; | 1668 | return use_browser == 1 && perf_hpp_list.sym; |
| 1669 | } | 1669 | } |
| @@ -940,6 +940,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) · 939 unmodified lines | |||
| 940 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | 940 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
| 941 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; | 941 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; |
| 942 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; | 942 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; |
| 943 | synth_opts->initial_skip = 0; | ||
| 943 | } | 944 | } |
| 944 | 945 | ||
| 945 | /* | 946 | /* |
| @@ -1064,6 +1065,12 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, · 118 unmodified lines | |||
| 1064 | synth_opts->last_branch_sz = val; | 1065 | synth_opts->last_branch_sz = val; |
| 1065 | } | 1066 | } |
| 1066 | break; | 1067 | break; |
| 1068 | case 's': | ||
| 1069 | synth_opts->initial_skip = strtoul(p, &endptr, 10); | ||
| 1070 | if (p == endptr) | ||
| 1071 | goto out_err; | ||
| 1072 | p = endptr; | ||
| 1073 | break; | ||
| 1067 | case ' ': | 1074 | case ' ': |
| 1068 | case ',': | 1075 | case ',': |
| 1069 | break; | 1076 | break; |
| @@ -68,6 +68,7 @@ enum itrace_period_type { · 67 unmodified lines | |||
| 68 | * @last_branch_sz: branch context size | 68 | * @last_branch_sz: branch context size |
| 69 | * @period: 'instructions' events period | 69 | * @period: 'instructions' events period |
| 70 | * @period_type: 'instructions' events period type | 70 | * @period_type: 'instructions' events period type |
| 71 | * @initial_skip: skip N events at the beginning. | ||
| 71 | */ | 72 | */ |
| 72 | struct itrace_synth_opts { | 73 | struct itrace_synth_opts { |
| 73 | bool set; | 74 | bool set; |
| @@ -86,6 +87,7 @@ struct itrace_synth_opts { · 12 unmodified lines | |||
| 86 | unsigned int last_branch_sz; | 87 | unsigned int last_branch_sz; |
| 87 | unsigned long long period; | 88 | unsigned long long period; |
| 88 | enum itrace_period_type period_type; | 89 | enum itrace_period_type period_type; |
| 90 | unsigned long initial_skip; | ||
| 89 | }; | 91 | }; |
| 90 | 92 | ||
| 91 | /** | 93 | /** |
| @@ -842,6 +842,58 @@ bpf_map_op__new(struct parse_events_term *term) · 841 unmodified lines | |||
| 842 | return op; | 842 | return op; |
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | static struct bpf_map_op * | ||
| 846 | bpf_map_op__clone(struct bpf_map_op *op) | ||
| 847 | { | ||
| 848 | struct bpf_map_op *newop; | ||
| 849 | |||
| 850 | newop = memdup(op, sizeof(*op)); | ||
| 851 | if (!newop) { | ||
| 852 | pr_debug("Failed to alloc bpf_map_op\n"); | ||
| 853 | return NULL; | ||
| 854 | } | ||
| 855 | |||
| 856 | INIT_LIST_HEAD(&newop->list); | ||
| 857 | if (op->key_type == BPF_MAP_KEY_RANGES) { | ||
| 858 | size_t memsz = op->k.array.nr_ranges * | ||
| 859 | sizeof(op->k.array.ranges[0]); | ||
| 860 | |||
| 861 | newop->k.array.ranges = memdup(op->k.array.ranges, memsz); | ||
| 862 | if (!newop->k.array.ranges) { | ||
| 863 | pr_debug("Failed to alloc indices for map\n"); | ||
| 864 | free(newop); | ||
| 865 | return NULL; | ||
| 866 | } | ||
| 867 | } | ||
| 868 | |||
| 869 | return newop; | ||
| 870 | } | ||
| 871 | |||
| 872 | static struct bpf_map_priv * | ||
| 873 | bpf_map_priv__clone(struct bpf_map_priv *priv) | ||
| 874 | { | ||
| 875 | struct bpf_map_priv *newpriv; | ||
| 876 | struct bpf_map_op *pos, *newop; | ||
| 877 | |||
| 878 | newpriv = zalloc(sizeof(*newpriv)); | ||
| 879 | if (!newpriv) { | ||
| 880 | pr_debug("No enough memory to alloc map private\n"); | ||
| 881 | return NULL; | ||
| 882 | } | ||
| 883 | INIT_LIST_HEAD(&newpriv->ops_list); | ||
| 884 | |||
| 885 | list_for_each_entry(pos, &priv->ops_list, list) { | ||
| 886 | newop = bpf_map_op__clone(pos); | ||
| 887 | if (!newop) { | ||
| 888 | bpf_map_priv__purge(newpriv); | ||
| 889 | return NULL; | ||
| 890 | } | ||
| 891 | list_add_tail(&newop->list, &newpriv->ops_list); | ||
| 892 | } | ||
| 893 | |||
| 894 | return newpriv; | ||
| 895 | } | ||
| 896 | |||
| 845 | static int | 897 | static int |
| 846 | bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) | 898 | bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) |
| 847 | { | 899 | { |
| @@ -1417,6 +1469,89 @@ int bpf__apply_obj_config(void) · 569 unmodified lines | |||
| 1417 | return 0; | 1469 | return 0; |
| 1418 | } | 1470 | } |
| 1419 | 1471 | ||
| 1472 | #define bpf__for_each_map(pos, obj, objtmp) \ | ||
| 1473 | bpf_object__for_each_safe(obj, objtmp) \ | ||
| 1474 | bpf_map__for_each(pos, obj) | ||
| 1475 | |||
| 1476 | #define bpf__for_each_stdout_map(pos, obj, objtmp) \ | ||
| 1477 | bpf__for_each_map(pos, obj, objtmp) \ | ||
| 1478 | if (bpf_map__get_name(pos) && \ | ||
| 1479 | (strcmp("__bpf_stdout__", \ | ||
| 1480 | bpf_map__get_name(pos)) == 0)) | ||
| 1481 | |||
| 1482 | int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) | ||
| 1483 | { | ||
| 1484 | struct bpf_map_priv *tmpl_priv = NULL; | ||
| 1485 | struct bpf_object *obj, *tmp; | ||
| 1486 | struct perf_evsel *evsel = NULL; | ||
| 1487 | struct bpf_map *map; | ||
| 1488 | int err; | ||
| 1489 | bool need_init = false; | ||
| 1490 | |||
| 1491 | bpf__for_each_stdout_map(map, obj, tmp) { | ||
| 1492 | struct bpf_map_priv *priv; | ||
| 1493 | |||
| 1494 | err = bpf_map__get_private(map, (void **)&priv); | ||
| 1495 | if (err) | ||
| 1496 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
| 1497 | |||
| 1498 | /* | ||
| 1499 | * No need to check map type: type should have been | ||
| 1500 | * verified by kernel. | ||
| 1501 | */ | ||
| 1502 | if (!need_init && !priv) | ||
| 1503 | need_init = !priv; | ||
| 1504 | if (!tmpl_priv && priv) | ||
| 1505 | tmpl_priv = priv; | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | if (!need_init) | ||
| 1509 | return 0; | ||
| 1510 | |||
| 1511 | if (!tmpl_priv) { | ||
| 1512 | err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/", | ||
| 1513 | NULL); | ||
| 1514 | if (err) { | ||
| 1515 | pr_debug("ERROR: failed to create bpf-output event\n"); | ||
| 1516 | return -err; | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | evsel = perf_evlist__last(evlist); | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | bpf__for_each_stdout_map(map, obj, tmp) { | ||
| 1523 | struct bpf_map_priv *priv; | ||
| 1524 | |||
| 1525 | err = bpf_map__get_private(map, (void **)&priv); | ||
| 1526 | if (err) | ||
| 1527 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
| 1528 | if (priv) | ||
| 1529 | continue; | ||
| 1530 | |||
| 1531 | if (tmpl_priv) { | ||
| 1532 | priv = bpf_map_priv__clone(tmpl_priv); | ||
| 1533 | if (!priv) | ||
| 1534 | return -ENOMEM; | ||
| 1535 | |||
| 1536 | err = bpf_map__set_private(map, priv, bpf_map_priv__clear); | ||
| 1537 | if (err) { | ||
| 1538 | bpf_map_priv__clear(map, priv); | ||
| 1539 | return err; | ||
| 1540 | } | ||
| 1541 | } else if (evsel) { | ||
| 1542 | struct bpf_map_op *op; | ||
| 1543 | |||
| 1544 | op = bpf_map__add_newop(map, NULL); | ||
| 1545 | if (IS_ERR(op)) | ||
| 1546 | return PTR_ERR(op); | ||
| 1547 | op->op_type = BPF_MAP_OP_SET_EVSEL; | ||
| 1548 | op->v.evsel = evsel; | ||
| 1549 | } | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | return 0; | ||
| 1553 | } | ||
| 1554 | |||
| 1420 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) | 1555 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) |
| 1421 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) | 1556 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) |
| 1422 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) | 1557 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) |
| @@ -1590,3 +1725,11 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) · 167 unmodified lines | |||
| 1590 | bpf__strerror_end(buf, size); | 1725 | bpf__strerror_end(buf, size); |
| 1591 | return 0; | 1726 | return 0; |
| 1592 | } | 1727 | } |
| 1728 | |||
| 1729 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | ||
| 1730 | int err, char *buf, size_t size) | ||
| 1731 | { | ||
| 1732 | bpf__strerror_head(err, buf, size); | ||
| 1733 | bpf__strerror_end(buf, size); | ||
| 1734 | return 0; | ||
| 1735 | } | ||
| @@ -79,6 +79,11 @@ int bpf__strerror_config_obj(struct bpf_object *obj, · 78 unmodified lines | |||
| 79 | size_t size); | 79 | size_t size); |
| 80 | int bpf__apply_obj_config(void); | 80 | int bpf__apply_obj_config(void); |
| 81 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); | 81 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); |
| 82 | |||
| 83 | int bpf__setup_stdout(struct perf_evlist *evlist); | ||
| 84 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, | ||
| 85 | char *buf, size_t size); | ||
| 86 | |||
| 82 | #else | 87 | #else |
| 83 | static inline struct bpf_object * | 88 | static inline struct bpf_object * |
| 84 | bpf__prepare_load(const char *filename __maybe_unused, | 89 | bpf__prepare_load(const char *filename __maybe_unused, |
| @@ -124,6 +129,12 @@ bpf__apply_obj_config(void) · 39 unmodified lines | |||
| 124 | return 0; | 129 | return 0; |
| 125 | } | 130 | } |
| 126 | 131 | ||
| 132 | static inline int | ||
| 133 | bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) | ||
| 134 | { | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 127 | static inline int | 138 | static inline int |
| 128 | __bpf_strerror(char *buf, size_t size) | 139 | __bpf_strerror(char *buf, size_t size) |
| 129 | { | 140 | { |
| @@ -177,5 +188,13 @@ bpf__strerror_apply_obj_config(int err __maybe_unused, · 47 unmodified lines | |||
| 177 | { | 188 | { |
| 178 | return __bpf_strerror(buf, size); | 189 | return __bpf_strerror(buf, size); |
| 179 | } | 190 | } |
| 191 | |||
| 192 | static inline int | ||
| 193 | bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | ||
| 194 | int err __maybe_unused, char *buf, | ||
| 195 | size_t size) | ||
| 196 | { | ||
| 197 | return __bpf_strerror(buf, size); | ||
| 198 | } | ||
| 180 | #endif | 199 | #endif |
| 181 | #endif | 200 | #endif |
| @@ -261,14 +261,14 @@ static int machine__write_buildid_table(struct machine *machine, int fd) · 260 unmodified lines | |||
| 261 | 261 | ||
| 262 | if (dso__is_vdso(pos)) { | 262 | if (dso__is_vdso(pos)) { |
| 263 | name = pos->short_name; | 263 | name = pos->short_name; |
| 264 | name_len = pos->short_name_len + 1; | 264 | name_len = pos->short_name_len; |
| 265 | } else if (dso__is_kcore(pos)) { | 265 | } else if (dso__is_kcore(pos)) { |
| 266 | machine__mmap_name(machine, nm, sizeof(nm)); | 266 | machine__mmap_name(machine, nm, sizeof(nm)); |
| 267 | name = nm; | 267 | name = nm; |
| 268 | name_len = strlen(nm) + 1; | 268 | name_len = strlen(nm); |
| 269 | } else { | 269 | } else { |
| 270 | name = pos->long_name; | 270 | name = pos->long_name; |
| 271 | name_len = pos->long_name_len + 1; | 271 | name_len = pos->long_name_len; |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | in_kernel = pos->kernel || | 274 | in_kernel = pos->kernel || |
| @@ -365,39 +365,17 @@ static char *build_id_cache__dirname_from_path(const char *name, · 90 unmodified lines | |||
| 365 | int build_id_cache__list_build_ids(const char *pathname, | 365 | int build_id_cache__list_build_ids(const char *pathname, |
| 366 | struct strlist **result) | 366 | struct strlist **result) |
| 367 | { | 367 | { |
| 368 | struct strlist *list; | ||
| 369 | char *dir_name; | 368 | char *dir_name; |
| 370 | DIR *dir; | ||
| 371 | struct dirent *d; | ||
| 372 | int ret = 0; | 369 | int ret = 0; |
| 373 | 370 | ||
| 374 | list = strlist__new(NULL, NULL); | ||
| 375 | dir_name = build_id_cache__dirname_from_path(pathname, false, false); | 371 | dir_name = build_id_cache__dirname_from_path(pathname, false, false); |
| 376 | if (!list || !dir_name) { | 372 | if (!dir_name) |
| 377 | ret = -ENOMEM; | 373 | return -ENOMEM; |
| 378 | goto out; | ||
| 379 | } | ||
| 380 | 374 | ||
| 381 | /* List up all dirents */ | 375 | *result = lsdir(dir_name, lsdir_no_dot_filter); |
| 382 | dir = opendir(dir_name); | 376 | if (!*result) |
| 383 | if (!dir) { | ||
| 384 | ret = -errno; | 377 | ret = -errno; |
| 385 | goto out; | ||
| 386 | } | ||
| 387 | |||
| 388 | while ((d = readdir(dir)) != NULL) { | ||
| 389 | if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) | ||
| 390 | continue; | ||
| 391 | strlist__add(list, d->d_name); | ||
| 392 | } | ||
| 393 | closedir(dir); | ||
| 394 | |||
| 395 | out: | ||
| 396 | free(dir_name); | 378 | free(dir_name); |
| 397 | if (ret) | ||
| 398 | strlist__delete(list); | ||
| 399 | else | ||
| 400 | *result = list; | ||
| 401 | 379 | ||
| 402 | return ret; | 380 | return ret; |
| 403 | } | 381 | } |
| @@ -40,25 +40,6 @@ int split_cmdline(char *cmdline, const char ***argv); · 39 unmodified lines | |||
| 40 | 40 | ||
| 41 | #define alloc_nr(x) (((x)+16)*3/2) | 41 | #define alloc_nr(x) (((x)+16)*3/2) |
| 42 | 42 | ||
| 43 | /* | ||
| 44 | * Realloc the buffer pointed at by variable 'x' so that it can hold | ||
| 45 | * at least 'nr' entries; the number of entries currently allocated | ||
| 46 | * is 'alloc', using the standard growing factor alloc_nr() macro. | ||
| 47 | * | ||
| 48 | * DO NOT USE any expression with side-effect for 'x' or 'alloc'. | ||
| 49 | */ | ||
| 50 | #define ALLOC_GROW(x, nr, alloc) \ | ||
| 51 | do { \ | ||
| 52 | if ((nr) > alloc) { \ | ||
| 53 | if (alloc_nr(alloc) < (nr)) \ | ||
| 54 | alloc = (nr); \ | ||
| 55 | else \ | ||
| 56 | alloc = alloc_nr(alloc); \ | ||
| 57 | x = xrealloc((x), alloc * sizeof(*(x))); \ | ||
| 58 | } \ | ||
| 59 | } while(0) | ||
| 60 | |||
| 61 | |||
| 62 | static inline int is_absolute_path(const char *path) | 43 | static inline int is_absolute_path(const char *path) |
| 63 | { | 44 | { |
| 64 | return path[0] == '/'; | 45 | return path[0] == '/'; |
| @@ -0,0 +1,122 @@ | |||
| 1 | /* | ||
| 2 | * call-path.h: Manipulate a tree data structure containing function call paths | ||
| 3 | * Copyright (c) 2014, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/rbtree.h> | ||
| 17 | #include <linux/list.h> | ||
| 18 | |||
| 19 | #include "util.h" | ||
| 20 | #include "call-path.h" | ||
| 21 | |||
| 22 | static void call_path__init(struct call_path *cp, struct call_path *parent, | ||
| 23 | struct symbol *sym, u64 ip, bool in_kernel) | ||
| 24 | { | ||
| 25 | cp->parent = parent; | ||
| 26 | cp->sym = sym; | ||
| 27 | cp->ip = sym ? 0 : ip; | ||
| 28 | cp->db_id = 0; | ||
| 29 | cp->in_kernel = in_kernel; | ||
| 30 | RB_CLEAR_NODE(&cp->rb_node); | ||
| 31 | cp->children = RB_ROOT; | ||
| 32 | } | ||
| 33 | |||
| 34 | struct call_path_root *call_path_root__new(void) | ||
| 35 | { | ||
| 36 | struct call_path_root *cpr; | ||
| 37 | |||
| 38 | cpr = zalloc(sizeof(struct call_path_root)); | ||
| 39 | if (!cpr) | ||
| 40 | return NULL; | ||
| 41 | call_path__init(&cpr->call_path, NULL, NULL, 0, false); | ||
| 42 | INIT_LIST_HEAD(&cpr->blocks); | ||
| 43 | return cpr; | ||
| 44 | } | ||
| 45 | |||
| 46 | void call_path_root__free(struct call_path_root *cpr) | ||
| 47 | { | ||
| 48 | struct call_path_block *pos, *n; | ||
| 49 | |||
| 50 | list_for_each_entry_safe(pos, n, &cpr->blocks, node) { | ||
| 51 | list_del(&pos->node); | ||
| 52 | free(pos); | ||
| 53 | } | ||
| 54 | free(cpr); | ||
| 55 | } | ||
| 56 | |||
| 57 | static struct call_path *call_path__new(struct call_path_root *cpr, | ||
| 58 | struct call_path *parent, | ||
| 59 | struct symbol *sym, u64 ip, | ||
| 60 | bool in_kernel) | ||
| 61 | { | ||
| 62 | struct call_path_block *cpb; | ||
| 63 | struct call_path *cp; | ||
| 64 | size_t n; | ||
| 65 | |||
| 66 | if (cpr->next < cpr->sz) { | ||
| 67 | cpb = list_last_entry(&cpr->blocks, struct call_path_block, | ||
| 68 | node); | ||
| 69 | } else { | ||
| 70 | cpb = zalloc(sizeof(struct call_path_block)); | ||
| 71 | if (!cpb) | ||
| 72 | return NULL; | ||
| 73 | list_add_tail(&cpb->node, &cpr->blocks); | ||
| 74 | cpr->sz += CALL_PATH_BLOCK_SIZE; | ||
| 75 | } | ||
| 76 | |||
| 77 | n = cpr->next++ & CALL_PATH_BLOCK_MASK; | ||
| 78 | cp = &cpb->cp[n]; | ||
| 79 | |||
| 80 | call_path__init(cp, parent, sym, ip, in_kernel); | ||
| 81 | |||
| 82 | return cp; | ||
| 83 | } | ||
| 84 | |||
| 85 | struct call_path *call_path__findnew(struct call_path_root *cpr, | ||
| 86 | struct call_path *parent, | ||
| 87 | struct symbol *sym, u64 ip, u64 ks) | ||
| 88 | { | ||
| 89 | struct rb_node **p; | ||
| 90 | struct rb_node *node_parent = NULL; | ||
| 91 | struct call_path *cp; | ||
| 92 | bool in_kernel = ip >= ks; | ||
| 93 | |||
| 94 | if (sym) | ||
| 95 | ip = 0; | ||
| 96 | |||
| 97 | if (!parent) | ||
| 98 | return call_path__new(cpr, parent, sym, ip, in_kernel); | ||
| 99 | |||
| 100 | p = &parent->children.rb_node; | ||
| 101 | while (*p != NULL) { | ||
| 102 | node_parent = *p; | ||
| 103 | cp = rb_entry(node_parent, struct call_path, rb_node); | ||
| 104 | |||
| 105 | if (cp->sym == sym && cp->ip == ip) | ||
| 106 | return cp; | ||
| 107 | |||
| 108 | if (sym < cp->sym || (sym == cp->sym && ip < cp->ip)) | ||
| 109 | p = &(*p)->rb_left; | ||
| 110 | else | ||
| 111 | p = &(*p)->rb_right; | ||
| 112 | } | ||
| 113 | |||
| 114 | cp = call_path__new(cpr, parent, sym, ip, in_kernel); | ||
| 115 | if (!cp) | ||
| 116 | return NULL; | ||
| 117 | |||
| 118 | rb_link_node(&cp->rb_node, node_parent, p); | ||
| 119 | rb_insert_color(&cp->rb_node, &parent->children); | ||
| 120 | |||
| 121 | return cp; | ||
| 122 | } | ||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * call-path.h: Manipulate a tree data structure containing function call paths | ||
| 3 | * Copyright (c) 2014, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef __PERF_CALL_PATH_H | ||
| 17 | #define __PERF_CALL_PATH_H | ||
| 18 | |||
| 19 | #include <sys/types.h> | ||
| 20 | |||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/rbtree.h> | ||
| 23 | |||
| 24 | /** | ||
| 25 | * struct call_path - node in list of calls leading to a function call. | ||
| 26 | * @parent: call path to the parent function call | ||
| 27 | * @sym: symbol of function called | ||
| 28 | * @ip: only if sym is null, the ip of the function | ||
| 29 | * @db_id: id used for db-export | ||
| 30 | * @in_kernel: whether function is a in the kernel | ||
| 31 | * @rb_node: node in parent's tree of called functions | ||
| 32 | * @children: tree of call paths of functions called | ||
| 33 | * | ||
| 34 | * In combination with the call_return structure, the call_path structure | ||
| 35 | * defines a context-sensitve call-graph. | ||
| 36 | */ | ||
| 37 | struct call_path { | ||
| 38 | struct call_path *parent; | ||
| 39 | struct symbol *sym; | ||
| 40 | u64 ip; | ||
| 41 | u64 db_id; | ||
| 42 | bool in_kernel; | ||
| 43 | struct rb_node rb_node; | ||
| 44 | struct rb_root children; | ||
| 45 | }; | ||
| 46 | |||
| 47 | #define CALL_PATH_BLOCK_SHIFT 8 | ||
| 48 | #define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT) | ||
| 49 | #define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1) | ||
| 50 | |||
| 51 | struct call_path_block { | ||
| 52 | struct call_path cp[CALL_PATH_BLOCK_SIZE]; | ||
| 53 | struct list_head node; | ||
| 54 | }; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * struct call_path_root - root of all call paths. | ||
| 58 | * @call_path: root call path | ||
| 59 | * @blocks: list of blocks to store call paths | ||
| 60 | * @next: next free space | ||
| 61 | * @sz: number of spaces | ||
| 62 | */ | ||
| 63 | struct call_path_root { | ||
| 64 | struct call_path call_path; | ||
| 65 | struct list_head blocks; | ||
| 66 | size_t next; | ||
| 67 | size_t sz; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct call_path_root *call_path_root__new(void); | ||
| 71 | void call_path_root__free(struct call_path_root *cpr); | ||
| 72 | |||
| 73 | struct call_path *call_path__findnew(struct call_path_root *cpr, | ||
| 74 | struct call_path *parent, | ||
| 75 | struct symbol *sym, u64 ip, u64 ks); | ||
| 76 | |||
| 77 | #endif | ||
| @@ -109,6 +109,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt) · 108 unmodified lines | |||
| 109 | bool record_opt_set = false; | 109 | bool record_opt_set = false; |
| 110 | bool try_stack_size = false; | 110 | bool try_stack_size = false; |
| 111 | 111 | ||
| 112 | callchain_param.enabled = true; | ||
| 112 | symbol_conf.use_callchain = true; | 113 | symbol_conf.use_callchain = true; |
| 113 | 114 | ||
| 114 | if (!arg) | 115 | if (!arg) |
| @@ -117,6 +118,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt) · 2 unmodified lines | |||
| 117 | while ((tok = strtok((char *)arg, ",")) != NULL) { | 118 | while ((tok = strtok((char *)arg, ",")) != NULL) { |
| 118 | if (!strncmp(tok, "none", strlen(tok))) { | 119 | if (!strncmp(tok, "none", strlen(tok))) { |
| 119 | callchain_param.mode = CHAIN_NONE; | 120 | callchain_param.mode = CHAIN_NONE; |
| 121 | callchain_param.enabled = false; | ||
| 120 | symbol_conf.use_callchain = false; | 122 | symbol_conf.use_callchain = false; |
| 121 | return 0; | 123 | return 0; |
| 122 | } | 124 | } |
| @@ -788,7 +790,8 @@ int callchain_cursor_append(struct callchain_cursor *cursor, · 665 unmodified lines | |||
| 788 | return 0; | 790 | return 0; |
| 789 | } | 791 | } |
| 790 | 792 | ||
| 791 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | 793 | int sample__resolve_callchain(struct perf_sample *sample, |
| 794 | struct callchain_cursor *cursor, struct symbol **parent, | ||
| 792 | struct perf_evsel *evsel, struct addr_location *al, | 795 | struct perf_evsel *evsel, struct addr_location *al, |
| 793 | int max_stack) | 796 | int max_stack) |
| 794 | { | 797 | { |
| @@ -796,8 +799,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent · 1 unmodified line | |||
| 796 | return 0; | 799 | return 0; |
| 797 | 800 | ||
| 798 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || | 801 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || |
| 799 | sort__has_parent) { | 802 | perf_hpp_list.parent) { |
| 800 | return thread__resolve_callchain(al->thread, evsel, sample, | 803 | return thread__resolve_callchain(al->thread, cursor, evsel, sample, |
| 801 | parent, al, max_stack); | 804 | parent, al, max_stack); |
| 802 | } | 805 | } |
| 803 | return 0; | 806 | return 0; |
| @@ -212,7 +212,14 @@ struct hist_entry; · 211 unmodified lines | |||
| 212 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | 212 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); |
| 213 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); | 213 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); |
| 214 | 214 | ||
| 215 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | 215 | struct record_opts; |
| 216 | |||
| 217 | int record_opts__parse_callchain(struct record_opts *record, | ||
| 218 | struct callchain_param *callchain, | ||
| 219 | const char *arg, bool unset); | ||
| 220 | |||
| 221 | int sample__resolve_callchain(struct perf_sample *sample, | ||
| 222 | struct callchain_cursor *cursor, struct symbol **parent, | ||
| 216 | struct perf_evsel *evsel, struct addr_location *al, | 223 | struct perf_evsel *evsel, struct addr_location *al, |
| 217 | int max_stack); | 224 | int max_stack); |
| 218 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); | 225 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include <subcmd/exec-cmd.h> | 13 | #include <subcmd/exec-cmd.h> |
| 14 | #include "util/hist.h" /* perf_hist_config */ | 14 | #include "util/hist.h" /* perf_hist_config */ |
| 15 | #include "util/llvm-utils.h" /* perf_llvm_config */ | 15 | #include "util/llvm-utils.h" /* perf_llvm_config */ |
| 16 | #include "config.h" | ||
| 16 | 17 | ||
| 17 | #define MAXNAME (256) | 18 | #define MAXNAME (256) |
| 18 | 19 | ||
| @@ -377,6 +378,21 @@ const char *perf_config_dirname(const char *name, const char *value) · 358 unmodified lines | |||
| 377 | return value; | 378 | return value; |
| 378 | } | 379 | } |
| 379 | 380 | ||
| 381 | static int perf_buildid_config(const char *var, const char *value) | ||
| 382 | { | ||
| 383 | /* same dir for all commands */ | ||
| 384 | if (!strcmp(var, "buildid.dir")) { | ||
| 385 | const char *dir = perf_config_dirname(var, value); | ||
| 386 | |||
| 387 | if (!dir) | ||
| 388 | return -1; | ||
| 389 | strncpy(buildid_dir, dir, MAXPATHLEN-1); | ||
| 390 | buildid_dir[MAXPATHLEN-1] = '\0'; | ||
| 391 | } | ||
| 392 | |||
| 393 | return 0; | ||
| 394 | } | ||
| 395 | |||
| 380 | static int perf_default_core_config(const char *var __maybe_unused, | 396 | static int perf_default_core_config(const char *var __maybe_unused, |
| 381 | const char *value __maybe_unused) | 397 | const char *value __maybe_unused) |
| 382 | { | 398 | { |
| @@ -412,6 +428,9 @@ int perf_default_config(const char *var, const char *value, · 29 unmodified lines | |||
| 412 | if (!prefixcmp(var, "llvm.")) | 428 | if (!prefixcmp(var, "llvm.")) |
| 413 | return perf_llvm_config(var, value); | 429 | return perf_llvm_config(var, value); |
| 414 | 430 | ||
| 431 | if (!prefixcmp(var, "buildid.")) | ||
| 432 | return perf_buildid_config(var, value); | ||
| 433 | |||
| 415 | /* Add other config variables here. */ | 434 | /* Add other config variables here. */ |
| 416 | return 0; | 435 | return 0; |
| 417 | } | 436 | } |
| @@ -506,41 +525,185 @@ out: · 88 unmodified lines | |||
| 506 | return ret; | 525 | return ret; |
| 507 | } | 526 | } |
| 508 | 527 | ||
| 509 | /* | 528 | static struct perf_config_section *find_section(struct list_head *sections, |
| 510 | * Call this to report error for your variable that should not | 529 | const char *section_name) |
| 511 | * get a boolean value (i.e. "[my] var" means "true"). | ||
| 512 | */ | ||
| 513 | int config_error_nonbool(const char *var) | ||
| 514 | { | 530 | { |
| 515 | return error("Missing value for '%s'", var); | 531 | struct perf_config_section *section; |
| 532 | |||
| 533 | list_for_each_entry(section, sections, node) | ||
| 534 | if (!strcmp(section->name, section_name)) | ||
| 535 | return section; | ||
| 536 | |||
| 537 | return NULL; | ||
| 538 | } | ||
| 539 | |||
| 540 | static struct perf_config_item *find_config_item(const char *name, | ||
| 541 | struct perf_config_section *section) | ||
| 542 | { | ||
| 543 | struct perf_config_item *item; | ||
| 544 | |||
| 545 | list_for_each_entry(item, §ion->items, node) | ||
| 546 | if (!strcmp(item->name, name)) | ||
| 547 | return item; | ||
| 548 | |||
| 549 | return NULL; | ||
| 516 | } | 550 | } |
| 517 | 551 | ||
| 518 | struct buildid_dir_config { | 552 | static struct perf_config_section *add_section(struct list_head *sections, |
| 519 | char *dir; | 553 | const char *section_name) |
| 520 | }; | 554 | { |
| 555 | struct perf_config_section *section = zalloc(sizeof(*section)); | ||
| 556 | |||
| 557 | if (!section) | ||
| 558 | return NULL; | ||
| 559 | |||
| 560 | INIT_LIST_HEAD(§ion->items); | ||
| 561 | section->name = strdup(section_name); | ||
| 562 | if (!section->name) { | ||
| 563 | pr_debug("%s: strdup failed\n", __func__); | ||
| 564 | free(section); | ||
| 565 | return NULL; | ||
| 566 | } | ||
| 567 | |||
| 568 | list_add_tail(§ion->node, sections); | ||
| 569 | return section; | ||
| 570 | } | ||
| 521 | 571 | ||
| 522 | static int buildid_dir_command_config(const char *var, const char *value, | 572 | static struct perf_config_item *add_config_item(struct perf_config_section *section, |
| 523 | void *data) | 573 | const char *name) |
| 524 | { | 574 | { |
| 525 | struct buildid_dir_config *c = data; | 575 | struct perf_config_item *item = zalloc(sizeof(*item)); |
| 526 | const char *v; | ||
| 527 | 576 | ||
| 528 | /* same dir for all commands */ | 577 | if (!item) |
| 529 | if (!strcmp(var, "buildid.dir")) { | 578 | return NULL; |
| 530 | v = perf_config_dirname(var, value); | 579 | |
| 531 | if (!v) | 580 | item->name = strdup(name); |
| 532 | return -1; | 581 | if (!item->name) { |
| 533 | strncpy(c->dir, v, MAXPATHLEN-1); | 582 | pr_debug("%s: strdup failed\n", __func__); |
| 534 | c->dir[MAXPATHLEN-1] = '\0'; | 583 | free(item); |
| 584 | return NULL; | ||
| 535 | } | 585 | } |
| 586 | |||
| 587 | list_add_tail(&item->node, §ion->items); | ||
| 588 | return item; | ||
| 589 | } | ||
| 590 | |||
| 591 | static int set_value(struct perf_config_item *item, const char *value) | ||
| 592 | { | ||
| 593 | char *val = strdup(value); | ||
| 594 | |||
| 595 | if (!val) | ||
| 596 | return -1; | ||
| 597 | |||
| 598 | zfree(&item->value); | ||
| 599 | item->value = val; | ||
| 536 | return 0; | 600 | return 0; |
| 537 | } | 601 | } |
| 538 | 602 | ||
| 539 | static void check_buildid_dir_config(void) | 603 | static int collect_config(const char *var, const char *value, |
| 604 | void *perf_config_set) | ||
| 540 | { | 605 | { |
| 541 | struct buildid_dir_config c; | 606 | int ret = -1; |
| 542 | c.dir = buildid_dir; | 607 | char *ptr, *key; |
| 543 | perf_config(buildid_dir_command_config, &c); | 608 | char *section_name, *name; |
| 609 | struct perf_config_section *section = NULL; | ||
| 610 | struct perf_config_item *item = NULL; | ||
| 611 | struct perf_config_set *set = perf_config_set; | ||
| 612 | struct list_head *sections = &set->sections; | ||
| 613 | |||
| 614 | key = ptr = strdup(var); | ||
| 615 | if (!key) { | ||
| 616 | pr_debug("%s: strdup failed\n", __func__); | ||
| 617 | return -1; | ||
| 618 | } | ||
| 619 | |||
| 620 | section_name = strsep(&ptr, "."); | ||
| 621 | name = ptr; | ||
| 622 | if (name == NULL || value == NULL) | ||
| 623 | goto out_free; | ||
| 624 | |||
| 625 | section = find_section(sections, section_name); | ||
| 626 | if (!section) { | ||
| 627 | section = add_section(sections, section_name); | ||
| 628 | if (!section) | ||
| 629 | goto out_free; | ||
| 630 | } | ||
| 631 | |||
| 632 | item = find_config_item(name, section); | ||
| 633 | if (!item) { | ||
| 634 | item = add_config_item(section, name); | ||
| 635 | if (!item) | ||
| 636 | goto out_free; | ||
| 637 | } | ||
| 638 | |||
| 639 | ret = set_value(item, value); | ||
| 640 | return ret; | ||
| 641 | |||
| 642 | out_free: | ||
| 643 | free(key); | ||
| 644 | perf_config_set__delete(set); | ||
| 645 | return -1; | ||
| 646 | } | ||
| 647 | |||
| 648 | struct perf_config_set *perf_config_set__new(void) | ||
| 649 | { | ||
| 650 | struct perf_config_set *set = zalloc(sizeof(*set)); | ||
| 651 | |||
| 652 | if (set) { | ||
| 653 | INIT_LIST_HEAD(&set->sections); | ||
| 654 | perf_config(collect_config, set); | ||
| 655 | } | ||
| 656 | |||
| 657 | return set; | ||
| 658 | } | ||
| 659 | |||
| 660 | static void perf_config_item__delete(struct perf_config_item *item) | ||
| 661 | { | ||
| 662 | zfree(&item->name); | ||
| 663 | zfree(&item->value); | ||
| 664 | free(item); | ||
| 665 | } | ||
| 666 | |||
| 667 | static void perf_config_section__purge(struct perf_config_section *section) | ||
| 668 | { | ||
| 669 | struct perf_config_item *item, *tmp; | ||
| 670 | |||
| 671 | list_for_each_entry_safe(item, tmp, §ion->items, node) { | ||
| 672 | list_del_init(&item->node); | ||
| 673 | perf_config_item__delete(item); | ||
| 674 | } | ||
| 675 | } | ||
| 676 | |||
| 677 | static void perf_config_section__delete(struct perf_config_section *section) | ||
| 678 | { | ||
| 679 | perf_config_section__purge(section); | ||
| 680 | zfree(§ion->name); | ||
| 681 | free(section); | ||
| 682 | } | ||
| 683 | |||
| 684 | static void perf_config_set__purge(struct perf_config_set *set) | ||
| 685 | { | ||
| 686 | struct perf_config_section *section, *tmp; | ||
| 687 | |||
| 688 | list_for_each_entry_safe(section, tmp, &set->sections, node) { | ||
| 689 | list_del_init(§ion->node); | ||
| 690 | perf_config_section__delete(section); | ||
| 691 | } | ||
| 692 | } | ||
| 693 | |||
| 694 | void perf_config_set__delete(struct perf_config_set *set) | ||
| 695 | { | ||
| 696 | perf_config_set__purge(set); | ||
| 697 | free(set); | ||
| 698 | } | ||
| 699 | |||
| 700 | /* | ||
| 701 | * Call this to report error for your variable that should not | ||
| 702 | * get a boolean value (i.e. "[my] var" means "true"). | ||
| 703 | */ | ||
| 704 | int config_error_nonbool(const char *var) | ||
| 705 | { | ||
| 706 | return error("Missing value for '%s'", var); | ||
| 544 | } | 707 | } |
| 545 | 708 | ||
| 546 | void set_buildid_dir(const char *dir) | 709 | void set_buildid_dir(const char *dir) |
| @@ -548,16 +711,13 @@ void set_buildid_dir(const char *dir) · 1 unmodified line | |||
| 548 | if (dir) | 711 | if (dir) |
| 549 | scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir); | 712 | scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir); |
| 550 | 713 | ||
| 551 | /* try config file */ | ||
| 552 | if (buildid_dir[0] == '\0') | ||
| 553 | check_buildid_dir_config(); | ||
| 554 | |||
| 555 | /* default to $HOME/.debug */ | 714 | /* default to $HOME/.debug */ |
| 556 | if (buildid_dir[0] == '\0') { | 715 | if (buildid_dir[0] == '\0') { |
| 557 | char *v = getenv("HOME"); | 716 | char *home = getenv("HOME"); |
| 558 | if (v) { | 717 | |
| 718 | if (home) { | ||
| 559 | snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", | 719 | snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", |
| 560 | v, DEBUG_CACHE_DIR); | 720 | home, DEBUG_CACHE_DIR); |
| 561 | } else { | 721 | } else { |
| 562 | strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); | 722 | strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); |
| 563 | } | 723 | } |
| @@ -0,0 +1,26 @@ | |||
| 1 | #ifndef __PERF_CONFIG_H | ||
| 2 | #define __PERF_CONFIG_H | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include <linux/list.h> | ||
| 6 | |||
| 7 | struct perf_config_item { | ||
| 8 | char *name; | ||
| 9 | char *value; | ||
| 10 | struct list_head node; | ||
| 11 | }; | ||
| 12 | |||
| 13 | struct perf_config_section { | ||
| 14 | char *name; | ||
| 15 | struct list_head items; | ||
| 16 | struct list_head node; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct perf_config_set { | ||
| 20 | struct list_head sections; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct perf_config_set *perf_config_set__new(void); | ||
| 24 | void perf_config_set__delete(struct perf_config_set *set); | ||
| 25 | |||
| 26 | #endif /* __PERF_CONFIG_H */ | ||
| @@ -587,3 +587,15 @@ int cpu__setup_cpunode_map(void) · 586 unmodified lines | |||
| 587 | closedir(dir1); | 587 | closedir(dir1); |
| 588 | return 0; | 588 | return 0; |
| 589 | } | 589 | } |
| 590 | |||
| 591 | bool cpu_map__has(struct cpu_map *cpus, int cpu) | ||
| 592 | { | ||
| 593 | int i; | ||
| 594 | |||
| 595 | for (i = 0; i < cpus->nr; ++i) { | ||
| 596 | if (cpus->map[i] == cpu) | ||
| 597 | return true; | ||
| 598 | } | ||
| 599 | |||
| 600 | return false; | ||
| 601 | } | ||
| @@ -66,4 +66,6 @@ int cpu__get_node(int cpu); · 65 unmodified lines | |||
| 66 | int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, | 66 | int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, |
| 67 | int (*f)(struct cpu_map *map, int cpu, void *data), | 67 | int (*f)(struct cpu_map *map, int cpu, void *data), |
| 68 | void *data); | 68 | void *data); |
| 69 | |||
| 70 | bool cpu_map__has(struct cpu_map *cpus, int cpu); | ||
| 69 | #endif /* __PERF_CPUMAP_H */ | 71 | #endif /* __PERF_CPUMAP_H */ |
| @@ -136,3 +136,44 @@ ssize_t perf_data_file__write(struct perf_data_file *file, · 135 unmodified lines | |||
| 136 | { | 136 | { |
| 137 | return writen(file->fd, buf, size); | 137 | return writen(file->fd, buf, size); |
| 138 | } | 138 | } |
| 139 | |||
| 140 | int perf_data_file__switch(struct perf_data_file *file, | ||
| 141 | const char *postfix, | ||
| 142 | size_t pos, bool at_exit) | ||
| 143 | { | ||
| 144 | char *new_filepath; | ||
| 145 | int ret; | ||
| 146 | |||
| 147 | if (check_pipe(file)) | ||
| 148 | return -EINVAL; | ||
| 149 | if (perf_data_file__is_read(file)) | ||
| 150 | return -EINVAL; | ||
| 151 | |||
| 152 | if (asprintf(&new_filepath, "%s.%s", file->path, postfix) < 0) | ||
| 153 | return -ENOMEM; | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Only fire a warning, don't return error, continue fill | ||
| 157 | * original file. | ||
| 158 | */ | ||
| 159 | if (rename(file->path, new_filepath)) | ||
| 160 | pr_warning("Failed to rename %s to %s\n", file->path, new_filepath); | ||
| 161 | |||
| 162 | if (!at_exit) { | ||
| 163 | close(file->fd); | ||
| 164 | ret = perf_data_file__open(file); | ||
| 165 | if (ret < 0) | ||
| 166 | goto out; | ||
| 167 | |||
| 168 | if (lseek(file->fd, pos, SEEK_SET) == (off_t)-1) { | ||
| 169 | ret = -errno; | ||
| 170 | pr_debug("Failed to lseek to %zu: %s", | ||
| 171 | pos, strerror(errno)); | ||
| 172 | goto out; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | ret = file->fd; | ||
| 176 | out: | ||
| 177 | free(new_filepath); | ||
| 178 | return ret; | ||
| 179 | } | ||
| @@ -46,5 +46,14 @@ int perf_data_file__open(struct perf_data_file *file); · 45 unmodified lines | |||
| 46 | void perf_data_file__close(struct perf_data_file *file); | 46 | void perf_data_file__close(struct perf_data_file *file); |
| 47 | ssize_t perf_data_file__write(struct perf_data_file *file, | 47 | ssize_t perf_data_file__write(struct perf_data_file *file, |
| 48 | void *buf, size_t size); | 48 | void *buf, size_t size); |
| 49 | 49 | /* | |
| 50 | * If at_exit is set, only rename current perf.data to | ||
| 51 | * perf.data.<postfix>, continue write on original file. | ||
| 52 | * Set at_exit when flushing the last output. | ||
| 53 | * | ||
| 54 | * Return value is fd of new output. | ||
| 55 | */ | ||
| 56 | int perf_data_file__switch(struct perf_data_file *file, | ||
| 57 | const char *postfix, | ||
| 58 | size_t pos, bool at_exit); | ||
| 50 | #endif /* __PERF_DATA_H */ | 59 | #endif /* __PERF_DATA_H */ |
| @@ -23,6 +23,8 @@ · 22 unmodified lines | |||
| 23 | #include "event.h" | 23 | #include "event.h" |
| 24 | #include "util.h" | 24 | #include "util.h" |
| 25 | #include "thread-stack.h" | 25 | #include "thread-stack.h" |
| 26 | #include "callchain.h" | ||
| 27 | #include "call-path.h" | ||
| 26 | #include "db-export.h" | 28 | #include "db-export.h" |
| 27 | 29 | ||
| 28 | struct deferred_export { | 30 | struct deferred_export { |
| @@ -258,8 +260,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, · 229 unmodified lines | |||
| 258 | if (!al->sym) { | 260 | if (!al->sym) { |
| 259 | al->sym = symbol__new(al->addr, 0, 0, "unknown"); | 261 | al->sym = symbol__new(al->addr, 0, 0, "unknown"); |
| 260 | if (al->sym) | 262 | if (al->sym) |
| 261 | symbols__insert(&dso->symbols[al->map->type], | 263 | dso__insert_symbol(dso, al->map->type, al->sym); |
| 262 | al->sym); | ||
| 263 | } | 264 | } |
| 264 | 265 | ||
| 265 | if (al->sym) { | 266 | if (al->sym) { |
| @@ -276,6 +277,80 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, · 10 unmodified lines | |||
| 276 | return 0; | 277 | return 0; |
| 277 | } | 278 | } |
| 278 | 279 | ||
| 280 | static struct call_path *call_path_from_sample(struct db_export *dbe, | ||
| 281 | struct machine *machine, | ||
| 282 | struct thread *thread, | ||
| 283 | struct perf_sample *sample, | ||
| 284 | struct perf_evsel *evsel) | ||
| 285 | { | ||
| 286 | u64 kernel_start = machine__kernel_start(machine); | ||
| 287 | struct call_path *current = &dbe->cpr->call_path; | ||
| 288 | enum chain_order saved_order = callchain_param.order; | ||
| 289 | int err; | ||
| 290 | |||
| 291 | if (!symbol_conf.use_callchain || !sample->callchain) | ||
| 292 | return NULL; | ||
| 293 | |||
| 294 | /* | ||
| 295 | * Since the call path tree must be built starting with the root, we | ||
| 296 | * must use ORDER_CALL for call chain resolution, in order to process | ||
| 297 | * the callchain starting with the root node and ending with the leaf. | ||
| 298 | */ | ||
| 299 | callchain_param.order = ORDER_CALLER; | ||
| 300 | err = thread__resolve_callchain(thread, &callchain_cursor, evsel, | ||
| 301 | sample, NULL, NULL, | ||
| 302 | sysctl_perf_event_max_stack); | ||
| 303 | if (err) { | ||
| 304 | callchain_param.order = saved_order; | ||
| 305 | return NULL; | ||
| 306 | } | ||
| 307 | callchain_cursor_commit(&callchain_cursor); | ||
| 308 | |||
| 309 | while (1) { | ||
| 310 | struct callchain_cursor_node *node; | ||
| 311 | struct addr_location al; | ||
| 312 | u64 dso_db_id = 0, sym_db_id = 0, offset = 0; | ||
| 313 | |||
| 314 | memset(&al, 0, sizeof(al)); | ||
| 315 | |||
| 316 | node = callchain_cursor_current(&callchain_cursor); | ||
| 317 | if (!node) | ||
| 318 | break; | ||
| 319 | /* | ||
| 320 | * Handle export of symbol and dso for this node by | ||
| 321 | * constructing an addr_location struct and then passing it to | ||
| 322 | * db_ids_from_al() to perform the export. | ||
| 323 | */ | ||
| 324 | al.sym = node->sym; | ||
| 325 | al.map = node->map; | ||
| 326 | al.machine = machine; | ||
| 327 | al.addr = node->ip; | ||
| 328 | |||
| 329 | if (al.map && !al.sym) | ||
| 330 | al.sym = dso__find_symbol(al.map->dso, MAP__FUNCTION, | ||
| 331 | al.addr); | ||
| 332 | |||
| 333 | db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset); | ||
| 334 | |||
| 335 | /* add node to the call path tree if it doesn't exist */ | ||
| 336 | current = call_path__findnew(dbe->cpr, current, | ||
| 337 | al.sym, node->ip, | ||
| 338 | kernel_start); | ||
| 339 | |||
| 340 | callchain_cursor_advance(&callchain_cursor); | ||
| 341 | } | ||
| 342 | |||
| 343 | /* Reset the callchain order to its prior value. */ | ||
| 344 | callchain_param.order = saved_order; | ||
| 345 | |||
| 346 | if (current == &dbe->cpr->call_path) { | ||
| 347 | /* Bail because the callchain was empty. */ | ||
| 348 | return NULL; | ||
| 349 | } | ||
| 350 | |||
| 351 | return current; | ||
| 352 | } | ||
| 353 | |||
| 279 | int db_export__branch_type(struct db_export *dbe, u32 branch_type, | 354 | int db_export__branch_type(struct db_export *dbe, u32 branch_type, |
| 280 | const char *name) | 355 | const char *name) |
| 281 | { | 356 | { |
| @@ -329,6 +404,16 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, · 47 unmodified lines | |||
| 329 | if (err) | 404 | if (err) |
| 330 | goto out_put; | 405 | goto out_put; |
| 331 | 406 | ||
| 407 | if (dbe->cpr) { | ||
| 408 | struct call_path *cp = call_path_from_sample(dbe, al->machine, | ||
| 409 | thread, sample, | ||
| 410 | evsel); | ||
| 411 | if (cp) { | ||
| 412 | db_export__call_path(dbe, cp); | ||
| 413 | es.call_path_id = cp->db_id; | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 332 | if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 417 | if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
| 333 | sample_addr_correlates_sym(&evsel->attr)) { | 418 | sample_addr_correlates_sym(&evsel->attr)) { |
| 334 | struct addr_location addr_al; | 419 | struct addr_location addr_al; |
| @@ -27,6 +27,7 @@ struct dso; · 26 unmodified lines | |||
| 27 | struct perf_sample; | 27 | struct perf_sample; |
| 28 | struct addr_location; | 28 | struct addr_location; |
| 29 | struct call_return_processor; | 29 | struct call_return_processor; |
| 30 | struct call_path_root; | ||
| 30 | struct call_path; | 31 | struct call_path; |
| 31 | struct call_return; | 32 | struct call_return; |
| 32 | 33 | ||
| @@ -43,6 +44,7 @@ struct export_sample { · 10 unmodified lines | |||
| 43 | u64 addr_dso_db_id; | 44 | u64 addr_dso_db_id; |
| 44 | u64 addr_sym_db_id; | 45 | u64 addr_sym_db_id; |
| 45 | u64 addr_offset; /* addr offset from symbol start */ | 46 | u64 addr_offset; /* addr offset from symbol start */ |
| 47 | u64 call_path_id; | ||
| 46 | }; | 48 | }; |
| 47 | 49 | ||
| 48 | struct db_export { | 50 | struct db_export { |
| @@ -64,6 +66,7 @@ struct db_export { · 15 unmodified lines | |||
| 64 | int (*export_call_return)(struct db_export *dbe, | 66 | int (*export_call_return)(struct db_export *dbe, |
| 65 | struct call_return *cr); | 67 | struct call_return *cr); |
| 66 | struct call_return_processor *crp; | 68 | struct call_return_processor *crp; |
| 69 | struct call_path_root *cpr; | ||
| 67 | u64 evsel_last_db_id; | 70 | u64 evsel_last_db_id; |
| 68 | u64 machine_last_db_id; | 71 | u64 machine_last_db_id; |
| 69 | u64 thread_last_db_id; | 72 | u64 thread_last_db_id; |
| @@ -38,7 +38,7 @@ int dso__read_binary_type_filename(const struct dso *dso, · 37 unmodified lines | |||
| 38 | enum dso_binary_type type, | 38 | enum dso_binary_type type, |
| 39 | char *root_dir, char *filename, size_t size) | 39 | char *root_dir, char *filename, size_t size) |
| 40 | { | 40 | { |
| 41 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 41 | char build_id_hex[SBUILD_ID_SIZE]; |
| 42 | int ret = 0; | 42 | int ret = 0; |
| 43 | size_t len; | 43 | size_t len; |
| 44 | 44 | ||
| @@ -1301,7 +1301,7 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp) · 1256 unmodified lines | |||
| 1301 | 1301 | ||
| 1302 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) | 1302 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) |
| 1303 | { | 1303 | { |
| 1304 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1304 | char sbuild_id[SBUILD_ID_SIZE]; |
| 1305 | 1305 | ||
| 1306 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | 1306 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
| 1307 | return fprintf(fp, "%s", sbuild_id); | 1307 | return fprintf(fp, "%s", sbuild_id); |
| @@ -915,8 +915,7 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) · 914 unmodified lines | |||
| 915 | tmp = "*"; | 915 | tmp = "*"; |
| 916 | else if (tag == DW_TAG_subroutine_type) { | 916 | else if (tag == DW_TAG_subroutine_type) { |
| 917 | /* Function pointer */ | 917 | /* Function pointer */ |
| 918 | strbuf_add(buf, "(function_type)", 15); | 918 | return strbuf_add(buf, "(function_type)", 15); |
| 919 | return 0; | ||
| 920 | } else { | 919 | } else { |
| 921 | if (!dwarf_diename(&type)) | 920 | if (!dwarf_diename(&type)) |
| 922 | return -ENOENT; | 921 | return -ENOENT; |
| @@ -927,14 +926,10 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) · 4 unmodified lines | |||
| 927 | else if (tag == DW_TAG_enumeration_type) | 926 | else if (tag == DW_TAG_enumeration_type) |
| 928 | tmp = "enum "; | 927 | tmp = "enum "; |
| 929 | /* Write a base name */ | 928 | /* Write a base name */ |
| 930 | strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type)); | 929 | return strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type)); |
| 931 | return 0; | ||
| 932 | } | 930 | } |
| 933 | ret = die_get_typename(&type, buf); | 931 | ret = die_get_typename(&type, buf); |
| 934 | if (ret == 0) | 932 | return ret ? ret : strbuf_addstr(buf, tmp); |
| 935 | strbuf_addstr(buf, tmp); | ||
| 936 | |||
| 937 | return ret; | ||
| 938 | } | 933 | } |
| 939 | 934 | ||
| 940 | /** | 935 | /** |
| @@ -951,12 +946,10 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) · 10 unmodified lines | |||
| 951 | ret = die_get_typename(vr_die, buf); | 946 | ret = die_get_typename(vr_die, buf); |
| 952 | if (ret < 0) { | 947 | if (ret < 0) { |
| 953 | pr_debug("Failed to get type, make it unknown.\n"); | 948 | pr_debug("Failed to get type, make it unknown.\n"); |
| 954 | strbuf_add(buf, " (unknown_type)", 14); | 949 | ret = strbuf_add(buf, " (unknown_type)", 14); |
| 955 | } | 950 | } |
| 956 | 951 | ||
| 957 | strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); | 952 | return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); |
| 958 | |||
| 959 | return 0; | ||
| 960 | } | 953 | } |
| 961 | 954 | ||
| 962 | #ifdef HAVE_DWARF_GETLOCATIONS | 955 | #ifdef HAVE_DWARF_GETLOCATIONS |
| @@ -999,22 +992,24 @@ static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die, · 36 unmodified lines | |||
| 999 | } | 992 | } |
| 1000 | 993 | ||
| 1001 | while ((offset = dwarf_ranges(&scopes[1], offset, &base, | 994 | while ((offset = dwarf_ranges(&scopes[1], offset, &base, |
| 1002 | &start, &end)) > 0) { | 995 | &start, &end)) > 0) { |
| 1003 | start -= entry; | 996 | start -= entry; |
| 1004 | end -= entry; | 997 | end -= entry; |
| 1005 | 998 | ||
| 1006 | if (first) { | 999 | if (first) { |
| 1007 | strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, | 1000 | ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, |
| 1008 | name, start, end); | 1001 | name, start, end); |
| 1009 | first = false; | 1002 | first = false; |
| 1010 | } else { | 1003 | } else { |
| 1011 | strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, | 1004 | ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, |
| 1012 | start, end); | 1005 | start, end); |
| 1013 | } | 1006 | } |
| 1007 | if (ret < 0) | ||
| 1008 | goto out; | ||
| 1014 | } | 1009 | } |
| 1015 | 1010 | ||
| 1016 | if (!first) | 1011 | if (!first) |
| 1017 | strbuf_add(buf, "]>", 2); | 1012 | ret = strbuf_add(buf, "]>", 2); |
| 1018 | 1013 | ||
| 1019 | out: | 1014 | out: |
| 1020 | free(scopes); | 1015 | free(scopes); |
| @@ -1054,31 +1049,32 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) · 33 unmodified lines | |||
| 1054 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) | 1049 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) |
| 1055 | return -EINVAL; | 1050 | return -EINVAL; |
| 1056 | 1051 | ||
| 1057 | while ((offset = dwarf_getlocations( | 1052 | while ((offset = dwarf_getlocations(&attr, offset, &base, |
| 1058 | &attr, offset, &base, | 1053 | &start, &end, &op, &nops)) > 0) { |
| 1059 | &start, &end, &op, &nops)) > 0) { | ||
| 1060 | if (start == 0) { | 1054 | if (start == 0) { |
| 1061 | /* Single Location Descriptions */ | 1055 | /* Single Location Descriptions */ |
| 1062 | ret = die_get_var_innermost_scope(sp_die, vr_die, buf); | 1056 | ret = die_get_var_innermost_scope(sp_die, vr_die, buf); |
| 1063 | return ret; | 1057 | goto out; |
| 1064 | } | 1058 | } |
| 1065 | 1059 | ||
| 1066 | /* Location Lists */ | 1060 | /* Location Lists */ |
| 1067 | start -= entry; | 1061 | start -= entry; |
| 1068 | end -= entry; | 1062 | end -= entry; |
| 1069 | if (first) { | 1063 | if (first) { |
| 1070 | strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, | 1064 | ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, |
| 1071 | name, start, end); | 1065 | name, start, end); |
| 1072 | first = false; | 1066 | first = false; |
| 1073 | } else { | 1067 | } else { |
| 1074 | strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, | 1068 | ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, |
| 1075 | start, end); | 1069 | start, end); |
| 1076 | } | 1070 | } |
| 1071 | if (ret < 0) | ||
| 1072 | goto out; | ||
| 1077 | } | 1073 | } |
| 1078 | 1074 | ||
| 1079 | if (!first) | 1075 | if (!first) |
| 1080 | strbuf_add(buf, "]>", 2); | 1076 | ret = strbuf_add(buf, "]>", 2); |
| 1081 | 1077 | out: | |
| 1082 | return ret; | 1078 | return ret; |
| 1083 | } | 1079 | } |
| 1084 | #else | 1080 | #else |
| @@ -45,6 +45,7 @@ static const char *perf_event__names[] = { · 44 unmodified lines | |||
| 45 | [PERF_RECORD_STAT] = "STAT", | 45 | [PERF_RECORD_STAT] = "STAT", |
| 46 | [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", | 46 | [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", |
| 47 | [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", | 47 | [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", |
| 48 | [PERF_RECORD_TIME_CONV] = "TIME_CONV", | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | const char *perf_event__name(unsigned int id) | 51 | const char *perf_event__name(unsigned int id) |
| @@ -233,6 +233,7 @@ enum perf_user_event_type { /* above any possible kernel type */ · 232 unmodified lines | |||
| 233 | PERF_RECORD_STAT = 76, | 233 | PERF_RECORD_STAT = 76, |
| 234 | PERF_RECORD_STAT_ROUND = 77, | 234 | PERF_RECORD_STAT_ROUND = 77, |
| 235 | PERF_RECORD_EVENT_UPDATE = 78, | 235 | PERF_RECORD_EVENT_UPDATE = 78, |
| 236 | PERF_RECORD_TIME_CONV = 79, | ||
| 236 | PERF_RECORD_HEADER_MAX | 237 | PERF_RECORD_HEADER_MAX |
| 237 | }; | 238 | }; |
| 238 | 239 | ||
| @@ -469,6 +470,13 @@ struct stat_round_event { · 230 unmodified lines | |||
| 469 | u64 time; | 470 | u64 time; |
| 470 | }; | 471 | }; |
| 471 | 472 | ||
| 473 | struct time_conv_event { | ||
| 474 | struct perf_event_header header; | ||
| 475 | u64 time_shift; | ||
| 476 | u64 time_mult; | ||
| 477 | u64 time_zero; | ||
| 478 | }; | ||
| 479 | |||
| 472 | union perf_event { | 480 | union perf_event { |
| 473 | struct perf_event_header header; | 481 | struct perf_event_header header; |
| 474 | struct mmap_event mmap; | 482 | struct mmap_event mmap; |
| @@ -497,6 +505,7 @@ union perf_event { · 22 unmodified lines | |||
| 497 | struct stat_config_event stat_config; | 505 | struct stat_config_event stat_config; |
| 498 | struct stat_event stat; | 506 | struct stat_event stat; |
| 499 | struct stat_round_event stat_round; | 507 | struct stat_round_event stat_round; |
| 508 | struct time_conv_event time_conv; | ||
| 500 | }; | 509 | }; |
| 501 | 510 | ||
| 502 | void perf_event__print_totals(void); | 511 | void perf_event__print_totals(void); |
| @@ -679,53 +679,52 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, · 678 unmodified lines | |||
| 679 | return NULL; | 679 | return NULL; |
| 680 | } | 680 | } |
| 681 | 681 | ||
| 682 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | 682 | /* When check_messup is true, 'end' must points to a good entry */ |
| 683 | static union perf_event * | ||
| 684 | perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start, | ||
| 685 | u64 end, u64 *prev) | ||
| 683 | { | 686 | { |
| 684 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
| 685 | u64 head; | ||
| 686 | u64 old = md->prev; | ||
| 687 | unsigned char *data = md->base + page_size; | 687 | unsigned char *data = md->base + page_size; |
| 688 | union perf_event *event = NULL; | 688 | union perf_event *event = NULL; |
| 689 | int diff = end - start; | ||
| 689 | 690 | ||
| 690 | /* | 691 | if (check_messup) { |
| 691 | * Check if event was unmapped due to a POLLHUP/POLLERR. | ||
| 692 | */ | ||
| 693 | if (!atomic_read(&md->refcnt)) | ||
| 694 | return NULL; | ||
| 695 | |||
| 696 | head = perf_mmap__read_head(md); | ||
| 697 | if (evlist->overwrite) { | ||
| 698 | /* | 692 | /* |
| 699 | * If we're further behind than half the buffer, there's a chance | 693 | * If we're further behind than half the buffer, there's a chance |
| 700 | * the writer will bite our tail and mess up the samples under us. | 694 | * the writer will bite our tail and mess up the samples under us. |
| 701 | * | 695 | * |
| 702 | * If we somehow ended up ahead of the head, we got messed up. | 696 | * If we somehow ended up ahead of the 'end', we got messed up. |
| 703 | * | 697 | * |
| 704 | * In either case, truncate and restart at head. | 698 | * In either case, truncate and restart at 'end'. |
| 705 | */ | 699 | */ |
| 706 | int diff = head - old; | ||
| 707 | if (diff > md->mask / 2 || diff < 0) { | 700 | if (diff > md->mask / 2 || diff < 0) { |
| 708 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); | 701 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); |
| 709 | 702 | ||
| 710 | /* | 703 | /* |
| 711 | * head points to a known good entry, start there. | 704 | * 'end' points to a known good entry, start there. |
| 712 | */ | 705 | */ |
| 713 | old = head; | 706 | start = end; |
| 707 | diff = 0; | ||
| 714 | } | 708 | } |
| 715 | } | 709 | } |
| 716 | 710 | ||
| 717 | if (old != head) { | 711 | if (diff >= (int)sizeof(event->header)) { |
| 718 | size_t size; | 712 | size_t size; |
| 719 | 713 | ||
| 720 | event = (union perf_event *)&data[old & md->mask]; | 714 | event = (union perf_event *)&data[start & md->mask]; |
| 721 | size = event->header.size; | 715 | size = event->header.size; |
| 722 | 716 | ||
| 717 | if (size < sizeof(event->header) || diff < (int)size) { | ||
| 718 | event = NULL; | ||
| 719 | goto broken_event; | ||
| 720 | } | ||
| 721 | |||
| 723 | /* | 722 | /* |
| 724 | * Event straddles the mmap boundary -- header should always | 723 | * Event straddles the mmap boundary -- header should always |
| 725 | * be inside due to u64 alignment of output. | 724 | * be inside due to u64 alignment of output. |
| 726 | */ | 725 | */ |
| 727 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | 726 | if ((start & md->mask) + size != ((start + size) & md->mask)) { |
| 728 | unsigned int offset = old; | 727 | unsigned int offset = start; |
| 729 | unsigned int len = min(sizeof(*event), size), cpy; | 728 | unsigned int len = min(sizeof(*event), size), cpy; |
| 730 | void *dst = md->event_copy; | 729 | void *dst = md->event_copy; |
| 731 | 730 | ||
| @@ -740,14 +739,83 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) · 8 unmodified lines | |||
| 740 | event = (union perf_event *) md->event_copy; | 739 | event = (union perf_event *) md->event_copy; |
| 741 | } | 740 | } |
| 742 | 741 | ||
| 743 | old += size; | 742 | start += size; |
| 744 | } | 743 | } |
| 745 | 744 | ||
| 746 | md->prev = old; | 745 | broken_event: |
| 746 | if (prev) | ||
| 747 | *prev = start; | ||
| 747 | 748 | ||
| 748 | return event; | 749 | return event; |
| 749 | } | 750 | } |
| 750 | 751 | ||
| 752 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | ||
| 753 | { | ||
| 754 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
| 755 | u64 head; | ||
| 756 | u64 old = md->prev; | ||
| 757 | |||
| 758 | /* | ||
| 759 | * Check if event was unmapped due to a POLLHUP/POLLERR. | ||
| 760 | */ | ||
| 761 | if (!atomic_read(&md->refcnt)) | ||
| 762 | return NULL; | ||
| 763 | |||
| 764 | head = perf_mmap__read_head(md); | ||
| 765 | |||
| 766 | return perf_mmap__read(md, evlist->overwrite, old, head, &md->prev); | ||
| 767 | } | ||
| 768 | |||
| 769 | union perf_event * | ||
| 770 | perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) | ||
| 771 | { | ||
| 772 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
| 773 | u64 head, end; | ||
| 774 | u64 start = md->prev; | ||
| 775 | |||
| 776 | /* | ||
| 777 | * Check if event was unmapped due to a POLLHUP/POLLERR. | ||
| 778 | */ | ||
| 779 | if (!atomic_read(&md->refcnt)) | ||
| 780 | return NULL; | ||
| 781 | |||
| 782 | head = perf_mmap__read_head(md); | ||
| 783 | if (!head) | ||
| 784 | return NULL; | ||
| 785 | |||
| 786 | /* | ||
| 787 | * 'head' pointer starts from 0. Kernel minus sizeof(record) form | ||
| 788 | * it each time when kernel writes to it, so in fact 'head' is | ||
| 789 | * negative. 'end' pointer is made manually by adding the size of | ||
| 790 | * the ring buffer to 'head' pointer, means the validate data can | ||
| 791 | * read is the whole ring buffer. If 'end' is positive, the ring | ||
| 792 | * buffer has not fully filled, so we must adjust 'end' to 0. | ||
| 793 | * | ||
| 794 | * However, since both 'head' and 'end' is unsigned, we can't | ||
| 795 | * simply compare 'end' against 0. Here we compare '-head' and | ||
| 796 | * the size of the ring buffer, where -head is the number of bytes | ||
| 797 | * kernel write to the ring buffer. | ||
| 798 | */ | ||
| 799 | if (-head < (u64)(md->mask + 1)) | ||
| 800 | end = 0; | ||
| 801 | else | ||
| 802 | end = head + md->mask + 1; | ||
| 803 | |||
| 804 | return perf_mmap__read(md, false, start, end, &md->prev); | ||
| 805 | } | ||
| 806 | |||
| 807 | void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) | ||
| 808 | { | ||
| 809 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
| 810 | u64 head; | ||
| 811 | |||
| 812 | if (!atomic_read(&md->refcnt)) | ||
| 813 | return; | ||
| 814 | |||
| 815 | head = perf_mmap__read_head(md); | ||
| 816 | md->prev = head; | ||
| 817 | } | ||
| 818 | |||
| 751 | static bool perf_mmap__empty(struct perf_mmap *md) | 819 | static bool perf_mmap__empty(struct perf_mmap *md) |
| 752 | { | 820 | { |
| 753 | return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; | 821 | return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; |
| @@ -986,26 +1054,34 @@ out_unmap: · 232 unmodified lines | |||
| 986 | return -1; | 1054 | return -1; |
| 987 | } | 1055 | } |
| 988 | 1056 | ||
| 989 | static size_t perf_evlist__mmap_size(unsigned long pages) | 1057 | unsigned long perf_event_mlock_kb_in_pages(void) |
| 990 | { | 1058 | { |
| 991 | if (pages == UINT_MAX) { | 1059 | unsigned long pages; |
| 992 | int max; | 1060 | int max; |
| 993 | 1061 | ||
| 994 | if (sysctl__read_int("kernel/perf_event_mlock_kb", &max) < 0) { | 1062 | if (sysctl__read_int("kernel/perf_event_mlock_kb", &max) < 0) { |
| 995 | /* | 1063 | /* |
| 996 | * Pick a once upon a time good value, i.e. things look | 1064 | * Pick a once upon a time good value, i.e. things look |
| 997 | * strange since we can't read a sysctl value, but lets not | 1065 | * strange since we can't read a sysctl value, but lets not |
| 998 | * die yet... | 1066 | * die yet... |
| 999 | */ | 1067 | */ |
| 1000 | max = 512; | 1068 | max = 512; |
| 1001 | } else { | 1069 | } else { |
| 1002 | max -= (page_size / 1024); | 1070 | max -= (page_size / 1024); |
| 1003 | } | 1071 | } |
| 1004 | 1072 | ||
| 1005 | pages = (max * 1024) / page_size; | 1073 | pages = (max * 1024) / page_size; |
| 1006 | if (!is_power_of_2(pages)) | 1074 | if (!is_power_of_2(pages)) |
| 1007 | pages = rounddown_pow_of_two(pages); | 1075 | pages = rounddown_pow_of_two(pages); |
| 1008 | } else if (!is_power_of_2(pages)) | 1076 | |
| 1077 | return pages; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | static size_t perf_evlist__mmap_size(unsigned long pages) | ||
| 1081 | { | ||
| 1082 | if (pages == UINT_MAX) | ||
| 1083 | pages = perf_event_mlock_kb_in_pages(); | ||
| 1084 | else if (!is_power_of_2(pages)) | ||
| 1009 | return 0; | 1085 | return 0; |
| 1010 | 1086 | ||
| 1011 | return (pages + 1) * page_size; | 1087 | return (pages + 1) * page_size; |
| @@ -1192,6 +1268,24 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, · 180 unmodified lines | |||
| 1192 | perf_evlist__propagate_maps(evlist); | 1268 | perf_evlist__propagate_maps(evlist); |
| 1193 | } | 1269 | } |
| 1194 | 1270 | ||
| 1271 | void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, | ||
| 1272 | enum perf_event_sample_format bit) | ||
| 1273 | { | ||
| 1274 | struct perf_evsel *evsel; | ||
| 1275 | |||
| 1276 | evlist__for_each(evlist, evsel) | ||
| 1277 | __perf_evsel__set_sample_bit(evsel, bit); | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, | ||
| 1281 | enum perf_event_sample_format bit) | ||
| 1282 | { | ||
| 1283 | struct perf_evsel *evsel; | ||
| 1284 | |||
| 1285 | evlist__for_each(evlist, evsel) | ||
| 1286 | __perf_evsel__reset_sample_bit(evsel, bit); | ||
| 1287 | } | ||
| 1288 | |||
| 1195 | int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) | 1289 | int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) |
| 1196 | { | 1290 | { |
| 1197 | struct perf_evsel *evsel; | 1291 | struct perf_evsel *evsel; |
| @@ -87,6 +87,17 @@ int perf_evlist__add_dummy(struct perf_evlist *evlist); · 86 unmodified lines | |||
| 87 | int perf_evlist__add_newtp(struct perf_evlist *evlist, | 87 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
| 88 | const char *sys, const char *name, void *handler); | 88 | const char *sys, const char *name, void *handler); |
| 89 | 89 | ||
| 90 | void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, | ||
| 91 | enum perf_event_sample_format bit); | ||
| 92 | void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, | ||
| 93 | enum perf_event_sample_format bit); | ||
| 94 | |||
| 95 | #define perf_evlist__set_sample_bit(evlist, bit) \ | ||
| 96 | __perf_evlist__set_sample_bit(evlist, PERF_SAMPLE_##bit) | ||
| 97 | |||
| 98 | #define perf_evlist__reset_sample_bit(evlist, bit) \ | ||
| 99 | __perf_evlist__reset_sample_bit(evlist, PERF_SAMPLE_##bit) | ||
| 100 | |||
| 90 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); | 101 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); |
| 91 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); | 102 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); |
| 92 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); | 103 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); |
| @@ -118,16 +129,23 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); · 25 unmodified lines | |||
| 118 | 129 | ||
| 119 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); | 130 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); |
| 120 | 131 | ||
| 132 | union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, | ||
| 133 | int idx); | ||
| 134 | void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); | ||
| 135 | |||
| 121 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); | 136 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); |
| 122 | 137 | ||
| 123 | int perf_evlist__open(struct perf_evlist *evlist); | 138 | int perf_evlist__open(struct perf_evlist *evlist); |
| 124 | void perf_evlist__close(struct perf_evlist *evlist); | 139 | void perf_evlist__close(struct perf_evlist *evlist); |
| 125 | 140 | ||
| 141 | struct callchain_param; | ||
| 142 | |||
| 126 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); | 143 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); |
| 127 | bool perf_can_sample_identifier(void); | 144 | bool perf_can_sample_identifier(void); |
| 128 | bool perf_can_record_switch_events(void); | 145 | bool perf_can_record_switch_events(void); |
| 129 | bool perf_can_record_cpu_wide(void); | 146 | bool perf_can_record_cpu_wide(void); |
| 130 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts); | 147 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, |
| 148 | struct callchain_param *callchain); | ||
| 131 | int record_opts__config(struct record_opts *opts); | 149 | int record_opts__config(struct record_opts *opts); |
| 132 | 150 | ||
| 133 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 151 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
| @@ -144,6 +162,8 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, · 10 unmodified lines | |||
| 144 | const char *str, | 162 | const char *str, |
| 145 | int unset); | 163 | int unset); |
| 146 | 164 | ||
| 165 | unsigned long perf_event_mlock_kb_in_pages(void); | ||
| 166 | |||
| 147 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, | 167 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, |
| 148 | bool overwrite, unsigned int auxtrace_pages, | 168 | bool overwrite, unsigned int auxtrace_pages, |
| 149 | bool auxtrace_overwrite); | 169 | bool auxtrace_overwrite); |
| @@ -226,7 +226,8 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) · 225 unmodified lines | |||
| 226 | perf_evsel__init(evsel, attr, idx); | 226 | perf_evsel__init(evsel, attr, idx); |
| 227 | 227 | ||
| 228 | if (perf_evsel__is_bpf_output(evsel)) { | 228 | if (perf_evsel__is_bpf_output(evsel)) { |
| 229 | evsel->attr.sample_type |= PERF_SAMPLE_RAW; | 229 | evsel->attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | |
| 230 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD), | ||
| 230 | evsel->attr.sample_period = 1; | 231 | evsel->attr.sample_period = 1; |
| 231 | } | 232 | } |
| 232 | 233 | ||
| @@ -561,10 +562,9 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) · 328 unmodified lines | |||
| 561 | return ret; | 562 | return ret; |
| 562 | } | 563 | } |
| 563 | 564 | ||
| 564 | static void | 565 | void perf_evsel__config_callchain(struct perf_evsel *evsel, |
| 565 | perf_evsel__config_callgraph(struct perf_evsel *evsel, | 566 | struct record_opts *opts, |
| 566 | struct record_opts *opts, | 567 | struct callchain_param *param) |
| 567 | struct callchain_param *param) | ||
| 568 | { | 568 | { |
| 569 | bool function = perf_evsel__is_function_event(evsel); | 569 | bool function = perf_evsel__is_function_event(evsel); |
| 570 | struct perf_event_attr *attr = &evsel->attr; | 570 | struct perf_event_attr *attr = &evsel->attr; |
| @@ -704,7 +704,7 @@ static void apply_config_terms(struct perf_evsel *evsel, · 133 unmodified lines | |||
| 704 | 704 | ||
| 705 | /* set perf-event callgraph */ | 705 | /* set perf-event callgraph */ |
| 706 | if (param.enabled) | 706 | if (param.enabled) |
| 707 | perf_evsel__config_callgraph(evsel, opts, ¶m); | 707 | perf_evsel__config_callchain(evsel, opts, ¶m); |
| 708 | } | 708 | } |
| 709 | } | 709 | } |
| 710 | 710 | ||
| @@ -736,7 +736,8 @@ static void apply_config_terms(struct perf_evsel *evsel, · 25 unmodified lines | |||
| 736 | * enable/disable events specifically, as there's no | 736 | * enable/disable events specifically, as there's no |
| 737 | * initial traced exec call. | 737 | * initial traced exec call. |
| 738 | */ | 738 | */ |
| 739 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | 739 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, |
| 740 | struct callchain_param *callchain) | ||
| 740 | { | 741 | { |
| 741 | struct perf_evsel *leader = evsel->leader; | 742 | struct perf_evsel *leader = evsel->leader; |
| 742 | struct perf_event_attr *attr = &evsel->attr; | 743 | struct perf_event_attr *attr = &evsel->attr; |
| @@ -811,8 +812,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) · 68 unmodified lines | |||
| 811 | if (perf_evsel__is_function_event(evsel)) | 812 | if (perf_evsel__is_function_event(evsel)) |
| 812 | evsel->attr.exclude_callchain_user = 1; | 813 | evsel->attr.exclude_callchain_user = 1; |
| 813 | 814 | ||
| 814 | if (callchain_param.enabled && !evsel->no_aux_samples) | 815 | if (callchain && callchain->enabled && !evsel->no_aux_samples) |
| 815 | perf_evsel__config_callgraph(evsel, opts, &callchain_param); | 816 | perf_evsel__config_callchain(evsel, opts, callchain); |
| 816 | 817 | ||
| 817 | if (opts->sample_intr_regs) { | 818 | if (opts->sample_intr_regs) { |
| 818 | attr->sample_regs_intr = opts->sample_intr_regs; | 819 | attr->sample_regs_intr = opts->sample_intr_regs; |
| @@ -1230,6 +1231,21 @@ static void __p_sample_type(char *buf, size_t size, u64 value) · 411 unmodified lines | |||
| 1230 | __p_bits(buf, size, value, bits); | 1231 | __p_bits(buf, size, value, bits); |
| 1231 | } | 1232 | } |
| 1232 | 1233 | ||
| 1234 | static void __p_branch_sample_type(char *buf, size_t size, u64 value) | ||
| 1235 | { | ||
| 1236 | #define bit_name(n) { PERF_SAMPLE_BRANCH_##n, #n } | ||
| 1237 | struct bit_names bits[] = { | ||
| 1238 | bit_name(USER), bit_name(KERNEL), bit_name(HV), bit_name(ANY), | ||
| 1239 | bit_name(ANY_CALL), bit_name(ANY_RETURN), bit_name(IND_CALL), | ||
| 1240 | bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX), | ||
| 1241 | bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP), | ||
| 1242 | bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES), | ||
| 1243 | { .name = NULL, } | ||
| 1244 | }; | ||
| 1245 | #undef bit_name | ||
| 1246 | __p_bits(buf, size, value, bits); | ||
| 1247 | } | ||
| 1248 | |||
| 1233 | static void __p_read_format(char *buf, size_t size, u64 value) | 1249 | static void __p_read_format(char *buf, size_t size, u64 value) |
| 1234 | { | 1250 | { |
| 1235 | #define bit_name(n) { PERF_FORMAT_##n, #n } | 1251 | #define bit_name(n) { PERF_FORMAT_##n, #n } |
| @@ -1248,6 +1264,7 @@ static void __p_read_format(char *buf, size_t size, u64 value) · 12 unmodified lines | |||
| 1248 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) | 1264 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) |
| 1249 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) | 1265 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) |
| 1250 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) | 1266 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) |
| 1267 | #define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) | ||
| 1251 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) | 1268 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) |
| 1252 | 1269 | ||
| 1253 | #define PRINT_ATTRn(_n, _f, _p) \ | 1270 | #define PRINT_ATTRn(_n, _f, _p) \ |
| @@ -1299,12 +1316,13 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, · 45 unmodified lines | |||
| 1299 | PRINT_ATTRf(comm_exec, p_unsigned); | 1316 | PRINT_ATTRf(comm_exec, p_unsigned); |
| 1300 | PRINT_ATTRf(use_clockid, p_unsigned); | 1317 | PRINT_ATTRf(use_clockid, p_unsigned); |
| 1301 | PRINT_ATTRf(context_switch, p_unsigned); | 1318 | PRINT_ATTRf(context_switch, p_unsigned); |
| 1319 | PRINT_ATTRf(write_backward, p_unsigned); | ||
| 1302 | 1320 | ||
| 1303 | PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); | 1321 | PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); |
| 1304 | PRINT_ATTRf(bp_type, p_unsigned); | 1322 | PRINT_ATTRf(bp_type, p_unsigned); |
| 1305 | PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); | 1323 | PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); |
| 1306 | PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); | 1324 | PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); |
| 1307 | PRINT_ATTRf(branch_sample_type, p_unsigned); | 1325 | PRINT_ATTRf(branch_sample_type, p_branch_sample_type); |
| 1308 | PRINT_ATTRf(sample_regs_user, p_hex); | 1326 | PRINT_ATTRf(sample_regs_user, p_hex); |
| 1309 | PRINT_ATTRf(sample_stack_user, p_unsigned); | 1327 | PRINT_ATTRf(sample_stack_user, p_unsigned); |
| 1310 | PRINT_ATTRf(clockid, p_signed); | 1328 | PRINT_ATTRf(clockid, p_signed); |
| @@ -2253,95 +2271,6 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, · 942 unmodified lines | |||
| 2253 | return 0; | 2271 | return 0; |
| 2254 | } | 2272 | } |
| 2255 | 2273 | ||
| 2256 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | ||
| 2257 | { | ||
| 2258 | va_list args; | ||
| 2259 | int ret = 0; | ||
| 2260 | |||
| 2261 | if (!*first) { | ||
| 2262 | ret += fprintf(fp, ","); | ||
| 2263 | } else { | ||
| 2264 | ret += fprintf(fp, ":"); | ||
| 2265 | *first = false; | ||
| 2266 | } | ||
| 2267 | |||
| 2268 | va_start(args, fmt); | ||
| 2269 | ret += vfprintf(fp, fmt, args); | ||
| 2270 | va_end(args); | ||
| 2271 | return ret; | ||
| 2272 | } | ||
| 2273 | |||
| 2274 | static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv) | ||
| 2275 | { | ||
| 2276 | return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); | ||
| 2277 | } | ||
| 2278 | |||
| 2279 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
| 2280 | struct perf_attr_details *details, FILE *fp) | ||
| 2281 | { | ||
| 2282 | bool first = true; | ||
| 2283 | int printed = 0; | ||
| 2284 | |||
| 2285 | if (details->event_group) { | ||
| 2286 | struct perf_evsel *pos; | ||
| 2287 | |||
| 2288 | if (!perf_evsel__is_group_leader(evsel)) | ||
| 2289 | return 0; | ||
| 2290 | |||
| 2291 | if (evsel->nr_members > 1) | ||
| 2292 | printed += fprintf(fp, "%s{", evsel->group_name ?: ""); | ||
| 2293 | |||
| 2294 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
| 2295 | for_each_group_member(pos, evsel) | ||
| 2296 | printed += fprintf(fp, ",%s", perf_evsel__name(pos)); | ||
| 2297 | |||
| 2298 | if (evsel->nr_members > 1) | ||
| 2299 | printed += fprintf(fp, "}"); | ||
| 2300 | goto out; | ||
| 2301 | } | ||
| 2302 | |||
| 2303 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
| 2304 | |||
| 2305 | if (details->verbose) { | ||
| 2306 | printed += perf_event_attr__fprintf(fp, &evsel->attr, | ||
| 2307 | __print_attr__fprintf, &first); | ||
| 2308 | } else if (details->freq) { | ||
| 2309 | const char *term = "sample_freq"; | ||
| 2310 | |||
| 2311 | if (!evsel->attr.freq) | ||
| 2312 | term = "sample_period"; | ||
| 2313 | |||
| 2314 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, | ||
| 2315 | term, (u64)evsel->attr.sample_freq); | ||
| 2316 | } | ||
| 2317 | |||
| 2318 | if (details->trace_fields) { | ||
| 2319 | struct format_field *field; | ||
| 2320 | |||
| 2321 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
| 2322 | printed += comma_fprintf(fp, &first, " (not a tracepoint)"); | ||
| 2323 | goto out; | ||
| 2324 | } | ||
| 2325 | |||
| 2326 | field = evsel->tp_format->format.fields; | ||
| 2327 | if (field == NULL) { | ||
| 2328 | printed += comma_fprintf(fp, &first, " (no trace field)"); | ||
| 2329 | goto out; | ||
| 2330 | } | ||
| 2331 | |||
| 2332 | printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name); | ||
| 2333 | |||
| 2334 | field = field->next; | ||
| 2335 | while (field) { | ||
| 2336 | printed += comma_fprintf(fp, &first, "%s", field->name); | ||
| 2337 | field = field->next; | ||
| 2338 | } | ||
| 2339 | } | ||
| 2340 | out: | ||
| 2341 | fputc('\n', fp); | ||
| 2342 | return ++printed; | ||
| 2343 | } | ||
| 2344 | |||
| 2345 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | 2274 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, |
| 2346 | char *msg, size_t msgsize) | 2275 | char *msg, size_t msgsize) |
| 2347 | { | 2276 | { |
| @@ -2416,10 +2345,18 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, · 68 unmodified lines | |||
| 2416 | "Probably the maximum number of open file descriptors has been reached.\n" | 2345 | "Probably the maximum number of open file descriptors has been reached.\n" |
| 2417 | "Hint: Try again after reducing the number of events.\n" | 2346 | "Hint: Try again after reducing the number of events.\n" |
| 2418 | "Hint: Try increasing the limit with 'ulimit -n <limit>'"); | 2347 | "Hint: Try increasing the limit with 'ulimit -n <limit>'"); |
| 2348 | case ENOMEM: | ||
| 2349 | if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 && | ||
| 2350 | access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0) | ||
| 2351 | return scnprintf(msg, size, | ||
| 2352 | "Not enough memory to setup event with callchain.\n" | ||
| 2353 | "Hint: Try tweaking /proc/sys/kernel/perf_event_max_stack\n" | ||
| 2354 | "Hint: Current value: %d", sysctl_perf_event_max_stack); | ||
| 2355 | break; | ||
| 2419 | case ENODEV: | 2356 | case ENODEV: |
| 2420 | if (target->cpu_list) | 2357 | if (target->cpu_list) |
| 2421 | return scnprintf(msg, size, "%s", | 2358 | return scnprintf(msg, size, "%s", |
| 2422 | "No such device - did you specify an out-of-range profile CPU?\n"); | 2359 | "No such device - did you specify an out-of-range profile CPU?"); |
| 2423 | break; | 2360 | break; |
| 2424 | case EOPNOTSUPP: | 2361 | case EOPNOTSUPP: |
| 2425 | if (evsel->attr.precise_ip) | 2362 | if (evsel->attr.precise_ip) |
| @@ -2451,7 +2388,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, · 25 unmodified lines | |||
| 2451 | return scnprintf(msg, size, | 2388 | return scnprintf(msg, size, |
| 2452 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" | 2389 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" |
| 2453 | "/bin/dmesg may provide additional information.\n" | 2390 | "/bin/dmesg may provide additional information.\n" |
| 2454 | "No CONFIG_PERF_EVENTS=y kernel support configured?\n", | 2391 | "No CONFIG_PERF_EVENTS=y kernel support configured?", |
| 2455 | err, strerror_r(err, sbuf, sizeof(sbuf)), | 2392 | err, strerror_r(err, sbuf, sizeof(sbuf)), |
| 2456 | perf_evsel__name(evsel)); | 2393 | perf_evsel__name(evsel)); |
| 2457 | } | 2394 | } |
| @@ -178,8 +178,14 @@ void perf_evsel__init(struct perf_evsel *evsel, · 177 unmodified lines | |||
| 178 | void perf_evsel__exit(struct perf_evsel *evsel); | 178 | void perf_evsel__exit(struct perf_evsel *evsel); |
| 179 | void perf_evsel__delete(struct perf_evsel *evsel); | 179 | void perf_evsel__delete(struct perf_evsel *evsel); |
| 180 | 180 | ||
| 181 | struct callchain_param; | ||
| 182 | |||
| 181 | void perf_evsel__config(struct perf_evsel *evsel, | 183 | void perf_evsel__config(struct perf_evsel *evsel, |
| 182 | struct record_opts *opts); | 184 | struct record_opts *opts, |
| 185 | struct callchain_param *callchain); | ||
| 186 | void perf_evsel__config_callchain(struct perf_evsel *evsel, | ||
| 187 | struct record_opts *opts, | ||
| 188 | struct callchain_param *callchain); | ||
| 183 | 189 | ||
| 184 | int __perf_evsel__sample_size(u64 sample_type); | 190 | int __perf_evsel__sample_size(u64 sample_type); |
| 185 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); | 191 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); |
| @@ -381,6 +387,24 @@ struct perf_attr_details { · 195 unmodified lines | |||
| 381 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 387 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
| 382 | struct perf_attr_details *details, FILE *fp); | 388 | struct perf_attr_details *details, FILE *fp); |
| 383 | 389 | ||
| 390 | #define EVSEL__PRINT_IP (1<<0) | ||
| 391 | #define EVSEL__PRINT_SYM (1<<1) | ||
| 392 | #define EVSEL__PRINT_DSO (1<<2) | ||
| 393 | #define EVSEL__PRINT_SYMOFFSET (1<<3) | ||
| 394 | #define EVSEL__PRINT_ONELINE (1<<4) | ||
| 395 | #define EVSEL__PRINT_SRCLINE (1<<5) | ||
| 396 | #define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) | ||
| 397 | |||
| 398 | struct callchain_cursor; | ||
| 399 | |||
| 400 | int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, | ||
| 401 | unsigned int print_opts, | ||
| 402 | struct callchain_cursor *cursor, FILE *fp); | ||
| 403 | |||
| 404 | int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, | ||
| 405 | int left_alignment, unsigned int print_opts, | ||
| 406 | struct callchain_cursor *cursor, FILE *fp); | ||
| 407 | |||
| 384 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | 408 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, |
| 385 | char *msg, size_t msgsize); | 409 | char *msg, size_t msgsize); |
| 386 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | 410 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, |
| @@ -396,7 +420,7 @@ for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ · 9 unmodified lines | |||
| 396 | (_evsel) && (_evsel)->leader == (_leader); \ | 420 | (_evsel) && (_evsel)->leader == (_leader); \ |
| 397 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) | 421 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) |
| 398 | 422 | ||
| 399 | static inline bool has_branch_callstack(struct perf_evsel *evsel) | 423 | static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel) |
| 400 | { | 424 | { |
| 401 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; | 425 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; |
| 402 | } | 426 | } |
| @@ -0,0 +1,212 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <traceevent/event-parse.h> | ||
| 4 | #include "evsel.h" | ||
| 5 | #include "callchain.h" | ||
| 6 | #include "map.h" | ||
| 7 | #include "symbol.h" | ||
| 8 | |||
| 9 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | ||
| 10 | { | ||
| 11 | va_list args; | ||
| 12 | int ret = 0; | ||
| 13 | |||
| 14 | if (!*first) { | ||
| 15 | ret += fprintf(fp, ","); | ||
| 16 | } else { | ||
| 17 | ret += fprintf(fp, ":"); | ||
| 18 | *first = false; | ||
| 19 | } | ||
| 20 | |||
| 21 | va_start(args, fmt); | ||
| 22 | ret += vfprintf(fp, fmt, args); | ||
| 23 | va_end(args); | ||
| 24 | return ret; | ||
| 25 | } | ||
| 26 | |||
| 27 | static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv) | ||
| 28 | { | ||
| 29 | return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); | ||
| 30 | } | ||
| 31 | |||
| 32 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
| 33 | struct perf_attr_details *details, FILE *fp) | ||
| 34 | { | ||
| 35 | bool first = true; | ||
| 36 | int printed = 0; | ||
| 37 | |||
| 38 | if (details->event_group) { | ||
| 39 | struct perf_evsel *pos; | ||
| 40 | |||
| 41 | if (!perf_evsel__is_group_leader(evsel)) | ||
| 42 | return 0; | ||
| 43 | |||
| 44 | if (evsel->nr_members > 1) | ||
| 45 | printed += fprintf(fp, "%s{", evsel->group_name ?: ""); | ||
| 46 | |||
| 47 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
| 48 | for_each_group_member(pos, evsel) | ||
| 49 | printed += fprintf(fp, ",%s", perf_evsel__name(pos)); | ||
| 50 | |||
| 51 | if (evsel->nr_members > 1) | ||
| 52 | printed += fprintf(fp, "}"); | ||
| 53 | goto out; | ||
| 54 | } | ||
| 55 | |||
| 56 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
| 57 | |||
| 58 | if (details->verbose) { | ||
| 59 | printed += perf_event_attr__fprintf(fp, &evsel->attr, | ||
| 60 | __print_attr__fprintf, &first); | ||
| 61 | } else if (details->freq) { | ||
| 62 | const char *term = "sample_freq"; | ||
| 63 | |||
| 64 | if (!evsel->attr.freq) | ||
| 65 | term = "sample_period"; | ||
| 66 | |||
| 67 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, | ||
| 68 | term, (u64)evsel->attr.sample_freq); | ||
| 69 | } | ||
| 70 | |||
| 71 | if (details->trace_fields) { | ||
| 72 | struct format_field *field; | ||
| 73 | |||
| 74 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
| 75 | printed += comma_fprintf(fp, &first, " (not a tracepoint)"); | ||
| 76 | goto out; | ||
| 77 | } | ||
| 78 | |||
| 79 | field = evsel->tp_format->format.fields; | ||
| 80 | if (field == NULL) { | ||
| 81 | printed += comma_fprintf(fp, &first, " (no trace field)"); | ||
| 82 | goto out; | ||
| 83 | } | ||
| 84 | |||
| 85 | printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name); | ||
| 86 | |||
| 87 | field = field->next; | ||
| 88 | while (field) { | ||
| 89 | printed += comma_fprintf(fp, &first, "%s", field->name); | ||
| 90 | field = field->next; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | out: | ||
| 94 | fputc('\n', fp); | ||
| 95 | return ++printed; | ||
| 96 | } | ||
| 97 | |||
| 98 | int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, | ||
| 99 | unsigned int print_opts, struct callchain_cursor *cursor, | ||
| 100 | FILE *fp) | ||
| 101 | { | ||
| 102 | int printed = 0; | ||
| 103 | struct callchain_cursor_node *node; | ||
| 104 | int print_ip = print_opts & EVSEL__PRINT_IP; | ||
| 105 | int print_sym = print_opts & EVSEL__PRINT_SYM; | ||
| 106 | int print_dso = print_opts & EVSEL__PRINT_DSO; | ||
| 107 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | ||
| 108 | int print_oneline = print_opts & EVSEL__PRINT_ONELINE; | ||
| 109 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | ||
| 110 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
| 111 | char s = print_oneline ? ' ' : '\t'; | ||
| 112 | |||
| 113 | if (sample->callchain) { | ||
| 114 | struct addr_location node_al; | ||
| 115 | |||
| 116 | callchain_cursor_commit(cursor); | ||
| 117 | |||
| 118 | while (1) { | ||
| 119 | u64 addr = 0; | ||
| 120 | |||
| 121 | node = callchain_cursor_current(cursor); | ||
| 122 | if (!node) | ||
| 123 | break; | ||
| 124 | |||
| 125 | if (node->sym && node->sym->ignore) | ||
| 126 | goto next; | ||
| 127 | |||
| 128 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
| 129 | |||
| 130 | if (print_ip) | ||
| 131 | printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); | ||
| 132 | |||
| 133 | if (node->map) | ||
| 134 | addr = node->map->map_ip(node->map, node->ip); | ||
| 135 | |||
| 136 | if (print_sym) { | ||
| 137 | printed += fprintf(fp, " "); | ||
| 138 | node_al.addr = addr; | ||
| 139 | node_al.map = node->map; | ||
| 140 | |||
| 141 | if (print_symoffset) { | ||
| 142 | printed += __symbol__fprintf_symname_offs(node->sym, &node_al, | ||
| 143 | print_unknown_as_addr, fp); | ||
| 144 | } else { | ||
| 145 | printed += __symbol__fprintf_symname(node->sym, &node_al, | ||
| 146 | print_unknown_as_addr, fp); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | if (print_dso) { | ||
| 151 | printed += fprintf(fp, " ("); | ||
| 152 | printed += map__fprintf_dsoname(node->map, fp); | ||
| 153 | printed += fprintf(fp, ")"); | ||
| 154 | } | ||
| 155 | |||
| 156 | if (print_srcline) | ||
| 157 | printed += map__fprintf_srcline(node->map, addr, "\n ", fp); | ||
| 158 | |||
| 159 | if (!print_oneline) | ||
| 160 | printed += fprintf(fp, "\n"); | ||
| 161 | next: | ||
| 162 | callchain_cursor_advance(cursor); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | return printed; | ||
| 167 | } | ||
| 168 | |||
| 169 | int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, | ||
| 170 | int left_alignment, unsigned int print_opts, | ||
| 171 | struct callchain_cursor *cursor, FILE *fp) | ||
| 172 | { | ||
| 173 | int printed = 0; | ||
| 174 | int print_ip = print_opts & EVSEL__PRINT_IP; | ||
| 175 | int print_sym = print_opts & EVSEL__PRINT_SYM; | ||
| 176 | int print_dso = print_opts & EVSEL__PRINT_DSO; | ||
| 177 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | ||
| 178 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | ||
| 179 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
| 180 | |||
| 181 | if (cursor != NULL) { | ||
| 182 | printed += sample__fprintf_callchain(sample, left_alignment, | ||
| 183 | print_opts, cursor, fp); | ||
| 184 | } else if (!(al->sym && al->sym->ignore)) { | ||
| 185 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
| 186 | |||
| 187 | if (print_ip) | ||
| 188 | printed += fprintf(fp, "%16" PRIx64, sample->ip); | ||
| 189 | |||
| 190 | if (print_sym) { | ||
| 191 | printed += fprintf(fp, " "); | ||
| 192 | if (print_symoffset) { | ||
| 193 | printed += __symbol__fprintf_symname_offs(al->sym, al, | ||
| 194 | print_unknown_as_addr, fp); | ||
| 195 | } else { | ||
| 196 | printed += __symbol__fprintf_symname(al->sym, al, | ||
| 197 | print_unknown_as_addr, fp); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | if (print_dso) { | ||
| 202 | printed += fprintf(fp, " ("); | ||
| 203 | printed += map__fprintf_dsoname(al->map, fp); | ||
| 204 | printed += fprintf(fp, ")"); | ||
| 205 | } | ||
| 206 | |||
| 207 | if (print_srcline) | ||
| 208 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); | ||
| 209 | } | ||
| 210 | |||
| 211 | return printed; | ||
| 212 | } | ||
| @@ -1474,7 +1474,7 @@ static int __event_process_build_id(struct build_id_event *bev, · 1473 unmodified lines | |||
| 1474 | 1474 | ||
| 1475 | dso = machine__findnew_dso(machine, filename); | 1475 | dso = machine__findnew_dso(machine, filename); |
| 1476 | if (dso != NULL) { | 1476 | if (dso != NULL) { |
| 1477 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1477 | char sbuild_id[SBUILD_ID_SIZE]; |
| 1478 | 1478 | ||
| 1479 | dso__set_build_id(dso, &bev->build_id); | 1479 | dso__set_build_id(dso, &bev->build_id); |
| 1480 | 1480 | ||
| @@ -1819,7 +1819,8 @@ static int process_cpu_topology(struct perf_file_section *section, · 338 unmodified lines | |||
| 1819 | 1819 | ||
| 1820 | ph->env.nr_sibling_cores = nr; | 1820 | ph->env.nr_sibling_cores = nr; |
| 1821 | size += sizeof(u32); | 1821 | size += sizeof(u32); |
| 1822 | strbuf_init(&sb, 128); | 1822 | if (strbuf_init(&sb, 128) < 0) |
| 1823 | goto free_cpu; | ||
| 1823 | 1824 | ||
| 1824 | for (i = 0; i < nr; i++) { | 1825 | for (i = 0; i < nr; i++) { |
| 1825 | str = do_read_string(fd, ph); | 1826 | str = do_read_string(fd, ph); |
| @@ -1827,7 +1828,8 @@ static int process_cpu_topology(struct perf_file_section *section, · 1 unmodified line | |||
| 1827 | goto error; | 1828 | goto error; |
| 1828 | 1829 | ||
| 1829 | /* include a NULL character at the end */ | 1830 | /* include a NULL character at the end */ |
| 1830 | strbuf_add(&sb, str, strlen(str) + 1); | 1831 | if (strbuf_add(&sb, str, strlen(str) + 1) < 0) |
| 1832 | goto error; | ||
| 1831 | size += string_size(str); | 1833 | size += string_size(str); |
| 1832 | free(str); | 1834 | free(str); |
| 1833 | } | 1835 | } |
| @@ -1849,7 +1851,8 @@ static int process_cpu_topology(struct perf_file_section *section, · 15 unmodified lines | |||
| 1849 | goto error; | 1851 | goto error; |
| 1850 | 1852 | ||
| 1851 | /* include a NULL character at the end */ | 1853 | /* include a NULL character at the end */ |
| 1852 | strbuf_add(&sb, str, strlen(str) + 1); | 1854 | if (strbuf_add(&sb, str, strlen(str) + 1) < 0) |
| 1855 | goto error; | ||
| 1853 | size += string_size(str); | 1856 | size += string_size(str); |
| 1854 | free(str); | 1857 | free(str); |
| 1855 | } | 1858 | } |
| @@ -1912,13 +1915,14 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse · 56 unmodified lines | |||
| 1912 | /* nr nodes */ | 1915 | /* nr nodes */ |
| 1913 | ret = readn(fd, &nr, sizeof(nr)); | 1916 | ret = readn(fd, &nr, sizeof(nr)); |
| 1914 | if (ret != sizeof(nr)) | 1917 | if (ret != sizeof(nr)) |
| 1915 | goto error; | 1918 | return -1; |
| 1916 | 1919 | ||
| 1917 | if (ph->needs_swap) | 1920 | if (ph->needs_swap) |
| 1918 | nr = bswap_32(nr); | 1921 | nr = bswap_32(nr); |
| 1919 | 1922 | ||
| 1920 | ph->env.nr_numa_nodes = nr; | 1923 | ph->env.nr_numa_nodes = nr; |
| 1921 | strbuf_init(&sb, 256); | 1924 | if (strbuf_init(&sb, 256) < 0) |
| 1925 | return -1; | ||
| 1922 | 1926 | ||
| 1923 | for (i = 0; i < nr; i++) { | 1927 | for (i = 0; i < nr; i++) { |
| 1924 | /* node number */ | 1928 | /* node number */ |
| @@ -1940,15 +1944,17 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse · 15 unmodified lines | |||
| 1940 | mem_free = bswap_64(mem_free); | 1944 | mem_free = bswap_64(mem_free); |
| 1941 | } | 1945 | } |
| 1942 | 1946 | ||
| 1943 | strbuf_addf(&sb, "%u:%"PRIu64":%"PRIu64":", | 1947 | if (strbuf_addf(&sb, "%u:%"PRIu64":%"PRIu64":", |
| 1944 | node, mem_total, mem_free); | 1948 | node, mem_total, mem_free) < 0) |
| 1949 | goto error; | ||
| 1945 | 1950 | ||
| 1946 | str = do_read_string(fd, ph); | 1951 | str = do_read_string(fd, ph); |
| 1947 | if (!str) | 1952 | if (!str) |
| 1948 | goto error; | 1953 | goto error; |
| 1949 | 1954 | ||
| 1950 | /* include a NULL character at the end */ | 1955 | /* include a NULL character at the end */ |
| 1951 | strbuf_add(&sb, str, strlen(str) + 1); | 1956 | if (strbuf_add(&sb, str, strlen(str) + 1) < 0) |
| 1957 | goto error; | ||
| 1952 | free(str); | 1958 | free(str); |
| 1953 | } | 1959 | } |
| 1954 | ph->env.numa_nodes = strbuf_detach(&sb, NULL); | 1960 | ph->env.numa_nodes = strbuf_detach(&sb, NULL); |
| @@ -1982,7 +1988,8 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused · 27 unmodified lines | |||
| 1982 | } | 1988 | } |
| 1983 | 1989 | ||
| 1984 | ph->env.nr_pmu_mappings = pmu_num; | 1990 | ph->env.nr_pmu_mappings = pmu_num; |
| 1985 | strbuf_init(&sb, 128); | 1991 | if (strbuf_init(&sb, 128) < 0) |
| 1992 | return -1; | ||
| 1986 | 1993 | ||
| 1987 | while (pmu_num) { | 1994 | while (pmu_num) { |
| 1988 | if (readn(fd, &type, sizeof(type)) != sizeof(type)) | 1995 | if (readn(fd, &type, sizeof(type)) != sizeof(type)) |
| @@ -1994,9 +2001,11 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused · 5 unmodified lines | |||
| 1994 | if (!name) | 2001 | if (!name) |
| 1995 | goto error; | 2002 | goto error; |
| 1996 | 2003 | ||
| 1997 | strbuf_addf(&sb, "%u:%s", type, name); | 2004 | if (strbuf_addf(&sb, "%u:%s", type, name) < 0) |
| 2005 | goto error; | ||
| 1998 | /* include a NULL character at the end */ | 2006 | /* include a NULL character at the end */ |
| 1999 | strbuf_add(&sb, "", 1); | 2007 | if (strbuf_add(&sb, "", 1) < 0) |
| 2008 | goto error; | ||
| 2000 | 2009 | ||
| 2001 | if (!strcmp(name, "msr")) | 2010 | if (!strcmp(name, "msr")) |
| 2002 | ph->env.msr_pmu_type = type; | 2011 | ph->env.msr_pmu_type = type; |
| @@ -27,16 +27,27 @@ static int levenshtein_compare(const void *p1, const void *p2) · 26 unmodified lines | |||
| 27 | return l1 != l2 ? l1 - l2 : strcmp(s1, s2); | 27 | return l1 != l2 ? l1 - l2 : strcmp(s1, s2); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) | 30 | static int add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) |
| 31 | { | 31 | { |
| 32 | unsigned int i; | 32 | unsigned int i, nr = cmds->cnt + old->cnt; |
| 33 | 33 | void *tmp; | |
| 34 | ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc); | 34 | |
| 35 | 35 | if (nr > cmds->alloc) { | |
| 36 | /* Choose bigger one to alloc */ | ||
| 37 | if (alloc_nr(cmds->alloc) < nr) | ||
| 38 | cmds->alloc = nr; | ||
| 39 | else | ||
| 40 | cmds->alloc = alloc_nr(cmds->alloc); | ||
| 41 | tmp = realloc(cmds->names, cmds->alloc * sizeof(*cmds->names)); | ||
| 42 | if (!tmp) | ||
| 43 | return -1; | ||
| 44 | cmds->names = tmp; | ||
| 45 | } | ||
| 36 | for (i = 0; i < old->cnt; i++) | 46 | for (i = 0; i < old->cnt; i++) |
| 37 | cmds->names[cmds->cnt++] = old->names[i]; | 47 | cmds->names[cmds->cnt++] = old->names[i]; |
| 38 | zfree(&old->names); | 48 | zfree(&old->names); |
| 39 | old->cnt = 0; | 49 | old->cnt = 0; |
| 50 | return 0; | ||
| 40 | } | 51 | } |
| 41 | 52 | ||
| 42 | const char *help_unknown_cmd(const char *cmd) | 53 | const char *help_unknown_cmd(const char *cmd) |
| @@ -52,8 +63,11 @@ const char *help_unknown_cmd(const char *cmd) · 9 unmodified lines | |||
| 52 | 63 | ||
| 53 | load_command_list("perf-", &main_cmds, &other_cmds); | 64 | load_command_list("perf-", &main_cmds, &other_cmds); |
| 54 | 65 | ||
| 55 | add_cmd_list(&main_cmds, &aliases); | 66 | if (add_cmd_list(&main_cmds, &aliases) < 0 || |
| 56 | add_cmd_list(&main_cmds, &other_cmds); | 67 | add_cmd_list(&main_cmds, &other_cmds) < 0) { |
| 68 | fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n"); | ||
| 69 | goto end; | ||
| 70 | } | ||
| 57 | qsort(main_cmds.names, main_cmds.cnt, | 71 | qsort(main_cmds.names, main_cmds.cnt, |
| 58 | sizeof(main_cmds.names), cmdname_compare); | 72 | sizeof(main_cmds.names), cmdname_compare); |
| 59 | uniq(&main_cmds); | 73 | uniq(&main_cmds); |
| @@ -99,6 +113,6 @@ const char *help_unknown_cmd(const char *cmd) · 39 unmodified lines | |||
| 99 | for (i = 0; i < n; i++) | 113 | for (i = 0; i < n; i++) |
| 100 | fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); | 114 | fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); |
| 101 | } | 115 | } |
| 102 | 116 | end: | |
| 103 | exit(1); | 117 | exit(1); |
| 104 | } | 118 | } |
| @@ -295,7 +295,7 @@ static void hists__delete_entry(struct hists *hists, struct hist_entry *he) · 294 unmodified lines | |||
| 295 | root_in = &he->parent_he->hroot_in; | 295 | root_in = &he->parent_he->hroot_in; |
| 296 | root_out = &he->parent_he->hroot_out; | 296 | root_out = &he->parent_he->hroot_out; |
| 297 | } else { | 297 | } else { |
| 298 | if (sort__need_collapse) | 298 | if (hists__has(hists, need_collapse)) |
| 299 | root_in = &hists->entries_collapsed; | 299 | root_in = &hists->entries_collapsed; |
| 300 | else | 300 | else |
| 301 | root_in = hists->entries_in; | 301 | root_in = hists->entries_in; |
| @@ -953,7 +953,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, · 651 unmodified lines | |||
| 953 | { | 953 | { |
| 954 | int err, err2; | 954 | int err, err2; |
| 955 | 955 | ||
| 956 | err = sample__resolve_callchain(iter->sample, &iter->parent, | 956 | err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, |
| 957 | iter->evsel, al, max_stack_depth); | 957 | iter->evsel, al, max_stack_depth); |
| 958 | if (err) | 958 | if (err) |
| 959 | return err; | 959 | return err; |
| @@ -1295,8 +1295,9 @@ static int hists__hierarchy_insert_entry(struct hists *hists, · 335 unmodified lines | |||
| 1295 | return ret; | 1295 | return ret; |
| 1296 | } | 1296 | } |
| 1297 | 1297 | ||
| 1298 | int hists__collapse_insert_entry(struct hists *hists, struct rb_root *root, | 1298 | static int hists__collapse_insert_entry(struct hists *hists, |
| 1299 | struct hist_entry *he) | 1299 | struct rb_root *root, |
| 1300 | struct hist_entry *he) | ||
| 1300 | { | 1301 | { |
| 1301 | struct rb_node **p = &root->rb_node; | 1302 | struct rb_node **p = &root->rb_node; |
| 1302 | struct rb_node *parent = NULL; | 1303 | struct rb_node *parent = NULL; |
| @@ -1372,7 +1373,7 @@ int hists__collapse_resort(struct hists *hists, struct ui_progress *prog) · 69 unmodified lines | |||
| 1372 | struct hist_entry *n; | 1373 | struct hist_entry *n; |
| 1373 | int ret; | 1374 | int ret; |
| 1374 | 1375 | ||
| 1375 | if (!sort__need_collapse) | 1376 | if (!hists__has(hists, need_collapse)) |
| 1376 | return 0; | 1377 | return 0; |
| 1377 | 1378 | ||
| 1378 | hists->nr_entries = 0; | 1379 | hists->nr_entries = 0; |
| @@ -1631,7 +1632,7 @@ static void output_resort(struct hists *hists, struct ui_progress *prog, · 252 unmodified lines | |||
| 1631 | return; | 1632 | return; |
| 1632 | } | 1633 | } |
| 1633 | 1634 | ||
| 1634 | if (sort__need_collapse) | 1635 | if (hists__has(hists, need_collapse)) |
| 1635 | root = &hists->entries_collapsed; | 1636 | root = &hists->entries_collapsed; |
| 1636 | else | 1637 | else |
| 1637 | root = hists->entries_in; | 1638 | root = hists->entries_in; |
| @@ -2035,7 +2036,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, · 397 unmodified lines | |||
| 2035 | struct hist_entry *he; | 2036 | struct hist_entry *he; |
| 2036 | int64_t cmp; | 2037 | int64_t cmp; |
| 2037 | 2038 | ||
| 2038 | if (sort__need_collapse) | 2039 | if (hists__has(hists, need_collapse)) |
| 2039 | root = &hists->entries_collapsed; | 2040 | root = &hists->entries_collapsed; |
| 2040 | else | 2041 | else |
| 2041 | root = hists->entries_in; | 2042 | root = hists->entries_in; |
| @@ -2061,6 +2062,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, · 19 unmodified lines | |||
| 2061 | if (he) { | 2062 | if (he) { |
| 2062 | memset(&he->stat, 0, sizeof(he->stat)); | 2063 | memset(&he->stat, 0, sizeof(he->stat)); |
| 2063 | he->hists = hists; | 2064 | he->hists = hists; |
| 2065 | if (symbol_conf.cumulate_callchain) | ||
| 2066 | memset(he->stat_acc, 0, sizeof(he->stat)); | ||
| 2064 | rb_link_node(&he->rb_node_in, parent, p); | 2067 | rb_link_node(&he->rb_node_in, parent, p); |
| 2065 | rb_insert_color(&he->rb_node_in, root); | 2068 | rb_insert_color(&he->rb_node_in, root); |
| 2066 | hists__inc_stats(hists, he); | 2069 | hists__inc_stats(hists, he); |
| @@ -2075,7 +2078,7 @@ static struct hist_entry *hists__find_entry(struct hists *hists, · 8 unmodified lines | |||
| 2075 | { | 2078 | { |
| 2076 | struct rb_node *n; | 2079 | struct rb_node *n; |
| 2077 | 2080 | ||
| 2078 | if (sort__need_collapse) | 2081 | if (hists__has(hists, need_collapse)) |
| 2079 | n = hists->entries_collapsed.rb_node; | 2082 | n = hists->entries_collapsed.rb_node; |
| 2080 | else | 2083 | else |
| 2081 | n = hists->entries_in->rb_node; | 2084 | n = hists->entries_in->rb_node; |
| @@ -2104,7 +2107,7 @@ void hists__match(struct hists *leader, struct hists *other) · 22 unmodified lines | |||
| 2104 | struct rb_node *nd; | 2107 | struct rb_node *nd; |
| 2105 | struct hist_entry *pos, *pair; | 2108 | struct hist_entry *pos, *pair; |
| 2106 | 2109 | ||
| 2107 | if (sort__need_collapse) | 2110 | if (hists__has(leader, need_collapse)) |
| 2108 | root = &leader->entries_collapsed; | 2111 | root = &leader->entries_collapsed; |
| 2109 | else | 2112 | else |
| 2110 | root = leader->entries_in; | 2113 | root = leader->entries_in; |
| @@ -2129,7 +2132,7 @@ int hists__link(struct hists *leader, struct hists *other) · 18 unmodified lines | |||
| 2129 | struct rb_node *nd; | 2132 | struct rb_node *nd; |
| 2130 | struct hist_entry *pos, *pair; | 2133 | struct hist_entry *pos, *pair; |
| 2131 | 2134 | ||
| 2132 | if (sort__need_collapse) | 2135 | if (hists__has(other, need_collapse)) |
| 2133 | root = &other->entries_collapsed; | 2136 | root = &other->entries_collapsed; |
| 2134 | else | 2137 | else |
| 2135 | root = other->entries_in; | 2138 | root = other->entries_in; |
| @@ -82,6 +82,8 @@ struct hists { · 81 unmodified lines | |||
| 82 | int nr_hpp_node; | 82 | int nr_hpp_node; |
| 83 | }; | 83 | }; |
| 84 | 84 | ||
| 85 | #define hists__has(__h, __f) (__h)->hpp_list->__f | ||
| 86 | |||
| 85 | struct hist_entry_iter; | 87 | struct hist_entry_iter; |
| 86 | 88 | ||
| 87 | struct hist_iter_ops { | 89 | struct hist_iter_ops { |
| @@ -199,8 +201,6 @@ int hists__init(void); · 111 unmodified lines | |||
| 199 | int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); | 201 | int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); |
| 200 | 202 | ||
| 201 | struct rb_root *hists__get_rotate_entries_in(struct hists *hists); | 203 | struct rb_root *hists__get_rotate_entries_in(struct hists *hists); |
| 202 | int hists__collapse_insert_entry(struct hists *hists, | ||
| 203 | struct rb_root *root, struct hist_entry *he); | ||
| 204 | 204 | ||
| 205 | struct perf_hpp { | 205 | struct perf_hpp { |
| 206 | char *buf; | 206 | char *buf; |
| @@ -240,6 +240,14 @@ struct perf_hpp_fmt { · 33 unmodified lines | |||
| 240 | struct perf_hpp_list { | 240 | struct perf_hpp_list { |
| 241 | struct list_head fields; | 241 | struct list_head fields; |
| 242 | struct list_head sorts; | 242 | struct list_head sorts; |
| 243 | |||
| 244 | int need_collapse; | ||
| 245 | int parent; | ||
| 246 | int sym; | ||
| 247 | int dso; | ||
| 248 | int socket; | ||
| 249 | int thread; | ||
| 250 | int comm; | ||
| 243 | }; | 251 | }; |
| 244 | 252 | ||
| 245 | extern struct perf_hpp_list perf_hpp_list; | 253 | extern struct perf_hpp_list perf_hpp_list; |
| @@ -66,6 +66,7 @@ struct intel_bts { · 65 unmodified lines | |||
| 66 | u64 branches_id; | 66 | u64 branches_id; |
| 67 | size_t branches_event_size; | 67 | size_t branches_event_size; |
| 68 | bool synth_needs_swap; | 68 | bool synth_needs_swap; |
| 69 | unsigned long num_events; | ||
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 71 | struct intel_bts_queue { | 72 | struct intel_bts_queue { |
| @@ -275,6 +276,10 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, · 203 unmodified lines | |||
| 275 | union perf_event event; | 276 | union perf_event event; |
| 276 | struct perf_sample sample = { .ip = 0, }; | 277 | struct perf_sample sample = { .ip = 0, }; |
| 277 | 278 | ||
| 279 | if (bts->synth_opts.initial_skip && | ||
| 280 | bts->num_events++ <= bts->synth_opts.initial_skip) | ||
| 281 | return 0; | ||
| 282 | |||
| 278 | event.sample.header.type = PERF_RECORD_SAMPLE; | 283 | event.sample.header.type = PERF_RECORD_SAMPLE; |
| 279 | event.sample.header.misc = PERF_RECORD_MISC_USER; | 284 | event.sample.header.misc = PERF_RECORD_MISC_USER; |
| 280 | event.sample.header.size = sizeof(struct perf_event_header); | 285 | event.sample.header.size = sizeof(struct perf_event_header); |
| @@ -356,7 +356,7 @@ static const char *intel_pt_err_msgs[] = { · 355 unmodified lines | |||
| 356 | 356 | ||
| 357 | int intel_pt__strerror(int code, char *buf, size_t buflen) | 357 | int intel_pt__strerror(int code, char *buf, size_t buflen) |
| 358 | { | 358 | { |
| 359 | if (code < 1 || code > INTEL_PT_ERR_MAX) | 359 | if (code < 1 || code >= INTEL_PT_ERR_MAX) |
| 360 | code = INTEL_PT_ERR_UNK; | 360 | code = INTEL_PT_ERR_UNK; |
| 361 | strlcpy(buf, intel_pt_err_msgs[code], buflen); | 361 | strlcpy(buf, intel_pt_err_msgs[code], buflen); |
| 362 | return 0; | 362 | return 0; |
| @@ -100,6 +100,8 @@ struct intel_pt { · 99 unmodified lines | |||
| 100 | u64 cyc_bit; | 100 | u64 cyc_bit; |
| 101 | u64 noretcomp_bit; | 101 | u64 noretcomp_bit; |
| 102 | unsigned max_non_turbo_ratio; | 102 | unsigned max_non_turbo_ratio; |
| 103 | |||
| 104 | unsigned long num_events; | ||
| 103 | }; | 105 | }; |
| 104 | 106 | ||
| 105 | enum switch_state { | 107 | enum switch_state { |
| @@ -972,6 +974,10 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) · 866 unmodified lines | |||
| 972 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) | 974 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) |
| 973 | return 0; | 975 | return 0; |
| 974 | 976 | ||
| 977 | if (pt->synth_opts.initial_skip && | ||
| 978 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
| 979 | return 0; | ||
| 980 | |||
| 975 | event->sample.header.type = PERF_RECORD_SAMPLE; | 981 | event->sample.header.type = PERF_RECORD_SAMPLE; |
| 976 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 982 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
| 977 | event->sample.header.size = sizeof(struct perf_event_header); | 983 | event->sample.header.size = sizeof(struct perf_event_header); |
| @@ -1029,6 +1035,10 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) · 51 unmodified lines | |||
| 1029 | union perf_event *event = ptq->event_buf; | 1035 | union perf_event *event = ptq->event_buf; |
| 1030 | struct perf_sample sample = { .ip = 0, }; | 1036 | struct perf_sample sample = { .ip = 0, }; |
| 1031 | 1037 | ||
| 1038 | if (pt->synth_opts.initial_skip && | ||
| 1039 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
| 1040 | return 0; | ||
| 1041 | |||
| 1032 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1042 | event->sample.header.type = PERF_RECORD_SAMPLE; |
| 1033 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 1043 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
| 1034 | event->sample.header.size = sizeof(struct perf_event_header); | 1044 | event->sample.header.size = sizeof(struct perf_event_header); |
| @@ -1087,6 +1097,10 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) · 52 unmodified lines | |||
| 1087 | union perf_event *event = ptq->event_buf; | 1097 | union perf_event *event = ptq->event_buf; |
| 1088 | struct perf_sample sample = { .ip = 0, }; | 1098 | struct perf_sample sample = { .ip = 0, }; |
| 1089 | 1099 | ||
| 1100 | if (pt->synth_opts.initial_skip && | ||
| 1101 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
| 1102 | return 0; | ||
| 1103 | |||
| 1090 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1104 | event->sample.header.type = PERF_RECORD_SAMPLE; |
| 1091 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 1105 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
| 1092 | event->sample.header.size = sizeof(struct perf_event_header); | 1106 | event->sample.header.size = sizeof(struct perf_event_header); |
| @@ -1199,14 +1213,18 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) · 106 unmodified lines | |||
| 1199 | ptq->have_sample = false; | 1213 | ptq->have_sample = false; |
| 1200 | 1214 | ||
| 1201 | if (pt->sample_instructions && | 1215 | if (pt->sample_instructions && |
| 1202 | (state->type & INTEL_PT_INSTRUCTION)) { | 1216 | (state->type & INTEL_PT_INSTRUCTION) && |
| 1217 | (!pt->synth_opts.initial_skip || | ||
| 1218 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | ||
| 1203 | err = intel_pt_synth_instruction_sample(ptq); | 1219 | err = intel_pt_synth_instruction_sample(ptq); |
| 1204 | if (err) | 1220 | if (err) |
| 1205 | return err; | 1221 | return err; |
| 1206 | } | 1222 | } |
| 1207 | 1223 | ||
| 1208 | if (pt->sample_transactions && | 1224 | if (pt->sample_transactions && |
| 1209 | (state->type & INTEL_PT_TRANSACTION)) { | 1225 | (state->type & INTEL_PT_TRANSACTION) && |
| 1226 | (!pt->synth_opts.initial_skip || | ||
| 1227 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | ||
| 1210 | err = intel_pt_synth_transaction_sample(ptq); | 1228 | err = intel_pt_synth_transaction_sample(ptq); |
| 1211 | if (err) | 1229 | if (err) |
| 1212 | return err; | 1230 | return err; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include "strlist.h" | 17 | #include "strlist.h" |
| 18 | #include <elf.h> | 18 | #include <elf.h> |
| 19 | 19 | ||
| 20 | #include "tsc.h" | ||
| 20 | #include "session.h" | 21 | #include "session.h" |
| 21 | #include "jit.h" | 22 | #include "jit.h" |
| 22 | #include "jitdump.h" | 23 | #include "jitdump.h" |
| @@ -33,6 +34,7 @@ struct jit_buf_desc { · 10 unmodified lines | |||
| 33 | size_t bufsize; | 34 | size_t bufsize; |
| 34 | FILE *in; | 35 | FILE *in; |
| 35 | bool needs_bswap; /* handles cross-endianess */ | 36 | bool needs_bswap; /* handles cross-endianess */ |
| 37 | bool use_arch_timestamp; | ||
| 36 | void *debug_data; | 38 | void *debug_data; |
| 37 | size_t nr_debug_entries; | 39 | size_t nr_debug_entries; |
| 38 | uint32_t code_load_count; | 40 | uint32_t code_load_count; |
| @@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name) · 119 unmodified lines | |||
| 158 | header.flags = bswap_64(header.flags); | 160 | header.flags = bswap_64(header.flags); |
| 159 | } | 161 | } |
| 160 | 162 | ||
| 163 | jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP; | ||
| 164 | |||
| 161 | if (verbose > 2) | 165 | if (verbose > 2) |
| 162 | pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n", | 166 | pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n", |
| 163 | header.version, | 167 | header.version, |
| 164 | header.total_size, | 168 | header.total_size, |
| 165 | (unsigned long long)header.timestamp, | 169 | (unsigned long long)header.timestamp, |
| 166 | header.pid, | 170 | header.pid, |
| 167 | header.elf_mach); | 171 | header.elf_mach, |
| 172 | jd->use_arch_timestamp); | ||
| 168 | 173 | ||
| 169 | if (header.flags & JITDUMP_FLAGS_RESERVED) { | 174 | if (header.flags & JITDUMP_FLAGS_RESERVED) { |
| 170 | pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", | 175 | pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", |
| @@ -172,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name) · 1 unmodified line | |||
| 172 | goto error; | 177 | goto error; |
| 173 | } | 178 | } |
| 174 | 179 | ||
| 180 | if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) { | ||
| 181 | pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n"); | ||
| 182 | goto error; | ||
| 183 | } | ||
| 184 | |||
| 175 | /* | 185 | /* |
| 176 | * validate event is using the correct clockid | 186 | * validate event is using the correct clockid |
| 177 | */ | 187 | */ |
| 178 | if (jit_validate_events(jd->session)) { | 188 | if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) { |
| 179 | pr_err("error, jitted code must be sampled with perf record -k 1\n"); | 189 | pr_err("error, jitted code must be sampled with perf record -k 1\n"); |
| 180 | goto error; | 190 | goto error; |
| 181 | } | 191 | } |
| @@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event) · 147 unmodified lines | |||
| 329 | return 0; | 339 | return 0; |
| 330 | } | 340 | } |
| 331 | 341 | ||
| 342 | static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp) | ||
| 343 | { | ||
| 344 | struct perf_tsc_conversion tc; | ||
| 345 | |||
| 346 | if (!jd->use_arch_timestamp) | ||
| 347 | return timestamp; | ||
| 348 | |||
| 349 | tc.time_shift = jd->session->time_conv.time_shift; | ||
| 350 | tc.time_mult = jd->session->time_conv.time_mult; | ||
| 351 | tc.time_zero = jd->session->time_conv.time_zero; | ||
| 352 | |||
| 353 | if (!tc.time_mult) | ||
| 354 | return 0; | ||
| 355 | |||
| 356 | return tsc_to_perf_time(timestamp, &tc); | ||
| 357 | } | ||
| 358 | |||
| 332 | static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) | 359 | static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) |
| 333 | { | 360 | { |
| 334 | struct perf_sample sample; | 361 | struct perf_sample sample; |
| @@ -385,7 +412,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) · 50 unmodified lines | |||
| 385 | return -1; | 412 | return -1; |
| 386 | } | 413 | } |
| 387 | if (stat(filename, &st)) | 414 | if (stat(filename, &st)) |
| 388 | memset(&st, 0, sizeof(stat)); | 415 | memset(&st, 0, sizeof(st)); |
| 389 | 416 | ||
| 390 | event->mmap2.header.type = PERF_RECORD_MMAP2; | 417 | event->mmap2.header.type = PERF_RECORD_MMAP2; |
| 391 | event->mmap2.header.misc = PERF_RECORD_MISC_USER; | 418 | event->mmap2.header.misc = PERF_RECORD_MISC_USER; |
| @@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) · 18 unmodified lines | |||
| 410 | id->tid = tid; | 437 | id->tid = tid; |
| 411 | } | 438 | } |
| 412 | if (jd->sample_type & PERF_SAMPLE_TIME) | 439 | if (jd->sample_type & PERF_SAMPLE_TIME) |
| 413 | id->time = jr->load.p.timestamp; | 440 | id->time = convert_timestamp(jd, jr->load.p.timestamp); |
| 414 | 441 | ||
| 415 | /* | 442 | /* |
| 416 | * create pseudo sample to induce dso hit increment | 443 | * create pseudo sample to induce dso hit increment |
| @@ -473,7 +500,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr) · 56 unmodified lines | |||
| 473 | size++; /* for \0 */ | 500 | size++; /* for \0 */ |
| 474 | 501 | ||
| 475 | if (stat(filename, &st)) | 502 | if (stat(filename, &st)) |
| 476 | memset(&st, 0, sizeof(stat)); | 503 | memset(&st, 0, sizeof(st)); |
| 477 | 504 | ||
| 478 | size = PERF_ALIGN(size, sizeof(u64)); | 505 | size = PERF_ALIGN(size, sizeof(u64)); |
| 479 | 506 | ||
| @@ -499,7 +526,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr) · 19 unmodified lines | |||
| 499 | id->tid = tid; | 526 | id->tid = tid; |
| 500 | } | 527 | } |
| 501 | if (jd->sample_type & PERF_SAMPLE_TIME) | 528 | if (jd->sample_type & PERF_SAMPLE_TIME) |
| 502 | id->time = jr->load.p.timestamp; | 529 | id->time = convert_timestamp(jd, jr->load.p.timestamp); |
| 503 | 530 | ||
| 504 | /* | 531 | /* |
| 505 | * create pseudo sample to induce dso hit increment | 532 | * create pseudo sample to induce dso hit increment |
| @@ -23,9 +23,12 @@ · 22 unmodified lines | |||
| 23 | #define JITHEADER_VERSION 1 | 23 | #define JITHEADER_VERSION 1 |
| 24 | 24 | ||
| 25 | enum jitdump_flags_bits { | 25 | enum jitdump_flags_bits { |
| 26 | JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT, | ||
| 26 | JITDUMP_FLAGS_MAX_BIT, | 27 | JITDUMP_FLAGS_MAX_BIT, |
| 27 | }; | 28 | }; |
| 28 | 29 | ||
| 30 | #define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT) | ||
| 31 | |||
| 29 | #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \ | 32 | #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \ |
| 30 | (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0) | 33 | (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0) |
| 31 | 34 | ||
| @@ -32,6 +32,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) · 31 unmodified lines | |||
| 32 | 32 | ||
| 33 | machine->threads = RB_ROOT; | 33 | machine->threads = RB_ROOT; |
| 34 | pthread_rwlock_init(&machine->threads_lock, NULL); | 34 | pthread_rwlock_init(&machine->threads_lock, NULL); |
| 35 | machine->nr_threads = 0; | ||
| 35 | INIT_LIST_HEAD(&machine->dead_threads); | 36 | INIT_LIST_HEAD(&machine->dead_threads); |
| 36 | machine->last_match = NULL; | 37 | machine->last_match = NULL; |
| 37 | 38 | ||
| @@ -430,6 +431,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine, · 392 unmodified lines | |||
| 430 | */ | 431 | */ |
| 431 | thread__get(th); | 432 | thread__get(th); |
| 432 | machine->last_match = th; | 433 | machine->last_match = th; |
| 434 | ++machine->nr_threads; | ||
| 433 | } | 435 | } |
| 434 | 436 | ||
| 435 | return th; | 437 | return th; |
| @@ -681,11 +683,13 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) · 245 unmodified lines | |||
| 681 | 683 | ||
| 682 | size_t machine__fprintf(struct machine *machine, FILE *fp) | 684 | size_t machine__fprintf(struct machine *machine, FILE *fp) |
| 683 | { | 685 | { |
| 684 | size_t ret = 0; | 686 | size_t ret; |
| 685 | struct rb_node *nd; | 687 | struct rb_node *nd; |
| 686 | 688 | ||
| 687 | pthread_rwlock_rdlock(&machine->threads_lock); | 689 | pthread_rwlock_rdlock(&machine->threads_lock); |
| 688 | 690 | ||
| 691 | ret = fprintf(fp, "Threads: %u\n", machine->nr_threads); | ||
| 692 | |||
| 689 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | 693 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { |
| 690 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | 694 | struct thread *pos = rb_entry(nd, struct thread, rb_node); |
| 691 | 695 | ||
| @@ -908,11 +912,11 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid) · 216 unmodified lines | |||
| 908 | return machine__create_kernel_maps(machine); | 912 | return machine__create_kernel_maps(machine); |
| 909 | } | 913 | } |
| 910 | 914 | ||
| 911 | int machine__load_kallsyms(struct machine *machine, const char *filename, | 915 | int __machine__load_kallsyms(struct machine *machine, const char *filename, |
| 912 | enum map_type type, symbol_filter_t filter) | 916 | enum map_type type, bool no_kcore, symbol_filter_t filter) |
| 913 | { | 917 | { |
| 914 | struct map *map = machine__kernel_map(machine); | 918 | struct map *map = machine__kernel_map(machine); |
| 915 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | 919 | int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore, filter); |
| 916 | 920 | ||
| 917 | if (ret > 0) { | 921 | if (ret > 0) { |
| 918 | dso__set_loaded(map->dso, type); | 922 | dso__set_loaded(map->dso, type); |
| @@ -927,6 +931,12 @@ int machine__load_kallsyms(struct machine *machine, const char *filename, · 8 unmodified lines | |||
| 927 | return ret; | 931 | return ret; |
| 928 | } | 932 | } |
| 929 | 933 | ||
| 934 | int machine__load_kallsyms(struct machine *machine, const char *filename, | ||
| 935 | enum map_type type, symbol_filter_t filter) | ||
| 936 | { | ||
| 937 | return __machine__load_kallsyms(machine, filename, type, false, filter); | ||
| 938 | } | ||
| 939 | |||
| 930 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | 940 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
| 931 | symbol_filter_t filter) | 941 | symbol_filter_t filter) |
| 932 | { | 942 | { |
| @@ -1413,6 +1423,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th, · 480 unmodified lines | |||
| 1413 | pthread_rwlock_wrlock(&machine->threads_lock); | 1423 | pthread_rwlock_wrlock(&machine->threads_lock); |
| 1414 | rb_erase_init(&th->rb_node, &machine->threads); | 1424 | rb_erase_init(&th->rb_node, &machine->threads); |
| 1415 | RB_CLEAR_NODE(&th->rb_node); | 1425 | RB_CLEAR_NODE(&th->rb_node); |
| 1426 | --machine->nr_threads; | ||
| 1416 | /* | 1427 | /* |
| 1417 | * Move it first to the dead_threads list, then drop the reference, | 1428 | * Move it first to the dead_threads list, then drop the reference, |
| 1418 | * if this is the last reference, then the thread__delete destructor | 1429 | * if this is the last reference, then the thread__delete destructor |
| @@ -1599,6 +1610,7 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample, · 180 unmodified lines | |||
| 1599 | } | 1610 | } |
| 1600 | 1611 | ||
| 1601 | static int add_callchain_ip(struct thread *thread, | 1612 | static int add_callchain_ip(struct thread *thread, |
| 1613 | struct callchain_cursor *cursor, | ||
| 1602 | struct symbol **parent, | 1614 | struct symbol **parent, |
| 1603 | struct addr_location *root_al, | 1615 | struct addr_location *root_al, |
| 1604 | u8 *cpumode, | 1616 | u8 *cpumode, |
| @@ -1630,7 +1642,7 @@ static int add_callchain_ip(struct thread *thread, · 25 unmodified lines | |||
| 1630 | * It seems the callchain is corrupted. | 1642 | * It seems the callchain is corrupted. |
| 1631 | * Discard all. | 1643 | * Discard all. |
| 1632 | */ | 1644 | */ |
| 1633 | callchain_cursor_reset(&callchain_cursor); | 1645 | callchain_cursor_reset(cursor); |
| 1634 | return 1; | 1646 | return 1; |
| 1635 | } | 1647 | } |
| 1636 | return 0; | 1648 | return 0; |
| @@ -1640,7 +1652,7 @@ static int add_callchain_ip(struct thread *thread, · 3 unmodified lines | |||
| 1640 | } | 1652 | } |
| 1641 | 1653 | ||
| 1642 | if (al.sym != NULL) { | 1654 | if (al.sym != NULL) { |
| 1643 | if (sort__has_parent && !*parent && | 1655 | if (perf_hpp_list.parent && !*parent && |
| 1644 | symbol__match_regex(al.sym, &parent_regex)) | 1656 | symbol__match_regex(al.sym, &parent_regex)) |
| 1645 | *parent = al.sym; | 1657 | *parent = al.sym; |
| 1646 | else if (have_ignore_callees && root_al && | 1658 | else if (have_ignore_callees && root_al && |
| @@ -1648,13 +1660,13 @@ static int add_callchain_ip(struct thread *thread, · 1 unmodified line | |||
| 1648 | /* Treat this symbol as the root, | 1660 | /* Treat this symbol as the root, |
| 1649 | forgetting its callees. */ | 1661 | forgetting its callees. */ |
| 1650 | *root_al = al; | 1662 | *root_al = al; |
| 1651 | callchain_cursor_reset(&callchain_cursor); | 1663 | callchain_cursor_reset(cursor); |
| 1652 | } | 1664 | } |
| 1653 | } | 1665 | } |
| 1654 | 1666 | ||
| 1655 | if (symbol_conf.hide_unresolved && al.sym == NULL) | 1667 | if (symbol_conf.hide_unresolved && al.sym == NULL) |
| 1656 | return 0; | 1668 | return 0; |
| 1657 | return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); | 1669 | return callchain_cursor_append(cursor, al.addr, al.map, al.sym); |
| 1658 | } | 1670 | } |
| 1659 | 1671 | ||
| 1660 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | 1672 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, |
| @@ -1724,6 +1736,7 @@ static int remove_loops(struct branch_entry *l, int nr) · 63 unmodified lines | |||
| 1724 | * negative error code on other errors. | 1736 | * negative error code on other errors. |
| 1725 | */ | 1737 | */ |
| 1726 | static int resolve_lbr_callchain_sample(struct thread *thread, | 1738 | static int resolve_lbr_callchain_sample(struct thread *thread, |
| 1739 | struct callchain_cursor *cursor, | ||
| 1727 | struct perf_sample *sample, | 1740 | struct perf_sample *sample, |
| 1728 | struct symbol **parent, | 1741 | struct symbol **parent, |
| 1729 | struct addr_location *root_al, | 1742 | struct addr_location *root_al, |
| @@ -1756,7 +1769,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, · 26 unmodified lines | |||
| 1756 | */ | 1769 | */ |
| 1757 | int mix_chain_nr = i + 1 + lbr_nr + 1; | 1770 | int mix_chain_nr = i + 1 + lbr_nr + 1; |
| 1758 | 1771 | ||
| 1759 | if (mix_chain_nr > PERF_MAX_STACK_DEPTH + PERF_MAX_BRANCH_DEPTH) { | 1772 | if (mix_chain_nr > (int)sysctl_perf_event_max_stack + PERF_MAX_BRANCH_DEPTH) { |
| 1760 | pr_warning("corrupted callchain. skipping...\n"); | 1773 | pr_warning("corrupted callchain. skipping...\n"); |
| 1761 | return 0; | 1774 | return 0; |
| 1762 | } | 1775 | } |
| @@ -1778,7 +1791,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, · 15 unmodified lines | |||
| 1778 | ip = lbr_stack->entries[0].to; | 1791 | ip = lbr_stack->entries[0].to; |
| 1779 | } | 1792 | } |
| 1780 | 1793 | ||
| 1781 | err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); | 1794 | err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); |
| 1782 | if (err) | 1795 | if (err) |
| 1783 | return (err < 0) ? err : 0; | 1796 | return (err < 0) ? err : 0; |
| 1784 | } | 1797 | } |
| @@ -1789,6 +1802,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, · 4 unmodified lines | |||
| 1789 | } | 1802 | } |
| 1790 | 1803 | ||
| 1791 | static int thread__resolve_callchain_sample(struct thread *thread, | 1804 | static int thread__resolve_callchain_sample(struct thread *thread, |
| 1805 | struct callchain_cursor *cursor, | ||
| 1792 | struct perf_evsel *evsel, | 1806 | struct perf_evsel *evsel, |
| 1793 | struct perf_sample *sample, | 1807 | struct perf_sample *sample, |
| 1794 | struct symbol **parent, | 1808 | struct symbol **parent, |
| @@ -1803,10 +1817,8 @@ static int thread__resolve_callchain_sample(struct thread *thread, · 8 unmodified lines | |||
| 1803 | int skip_idx = -1; | 1817 | int skip_idx = -1; |
| 1804 | int first_call = 0; | 1818 | int first_call = 0; |
| 1805 | 1819 | ||
| 1806 | callchain_cursor_reset(&callchain_cursor); | 1820 | if (perf_evsel__has_branch_callstack(evsel)) { |
| 1807 | 1821 | err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, | |
| 1808 | if (has_branch_callstack(evsel)) { | ||
| 1809 | err = resolve_lbr_callchain_sample(thread, sample, parent, | ||
| 1810 | root_al, max_stack); | 1822 | root_al, max_stack); |
| 1811 | if (err) | 1823 | if (err) |
| 1812 | return (err < 0) ? err : 0; | 1824 | return (err < 0) ? err : 0; |
| @@ -1816,7 +1828,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, · 3 unmodified lines | |||
| 1816 | * Based on DWARF debug information, some architectures skip | 1828 | * Based on DWARF debug information, some architectures skip |
| 1817 | * a callchain entry saved by the kernel. | 1829 | * a callchain entry saved by the kernel. |
| 1818 | */ | 1830 | */ |
| 1819 | if (chain->nr < PERF_MAX_STACK_DEPTH) | 1831 | if (chain->nr < sysctl_perf_event_max_stack) |
| 1820 | skip_idx = arch_skip_callchain_idx(thread, chain); | 1832 | skip_idx = arch_skip_callchain_idx(thread, chain); |
| 1821 | 1833 | ||
| 1822 | /* | 1834 | /* |
| @@ -1863,10 +1875,10 @@ static int thread__resolve_callchain_sample(struct thread *thread, · 40 unmodified lines | |||
| 1863 | nr = remove_loops(be, nr); | 1875 | nr = remove_loops(be, nr); |
| 1864 | 1876 | ||
| 1865 | for (i = 0; i < nr; i++) { | 1877 | for (i = 0; i < nr; i++) { |
| 1866 | err = add_callchain_ip(thread, parent, root_al, | 1878 | err = add_callchain_ip(thread, cursor, parent, root_al, |
| 1867 | NULL, be[i].to); | 1879 | NULL, be[i].to); |
| 1868 | if (!err) | 1880 | if (!err) |
| 1869 | err = add_callchain_ip(thread, parent, root_al, | 1881 | err = add_callchain_ip(thread, cursor, parent, root_al, |
| 1870 | NULL, be[i].from); | 1882 | NULL, be[i].from); |
| 1871 | if (err == -EINVAL) | 1883 | if (err == -EINVAL) |
| 1872 | break; | 1884 | break; |
| @@ -1877,7 +1889,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, · 4 unmodified lines | |||
| 1877 | } | 1889 | } |
| 1878 | 1890 | ||
| 1879 | check_calls: | 1891 | check_calls: |
| 1880 | if (chain->nr > PERF_MAX_STACK_DEPTH && (int)chain->nr > max_stack) { | 1892 | if (chain->nr > sysctl_perf_event_max_stack && (int)chain->nr > max_stack) { |
| 1881 | pr_warning("corrupted callchain. skipping...\n"); | 1893 | pr_warning("corrupted callchain. skipping...\n"); |
| 1882 | return 0; | 1894 | return 0; |
| 1883 | } | 1895 | } |
| @@ -1896,7 +1908,7 @@ check_calls: · 12 unmodified lines | |||
| 1896 | #endif | 1908 | #endif |
| 1897 | ip = chain->ips[j]; | 1909 | ip = chain->ips[j]; |
| 1898 | 1910 | ||
| 1899 | err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); | 1911 | err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); |
| 1900 | 1912 | ||
| 1901 | if (err) | 1913 | if (err) |
| 1902 | return (err < 0) ? err : 0; | 1914 | return (err < 0) ? err : 0; |
| @@ -1915,19 +1927,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) · 12 unmodified lines | |||
| 1915 | entry->map, entry->sym); | 1927 | entry->map, entry->sym); |
| 1916 | } | 1928 | } |
| 1917 | 1929 | ||
| 1918 | int thread__resolve_callchain(struct thread *thread, | 1930 | static int thread__resolve_callchain_unwind(struct thread *thread, |
| 1919 | struct perf_evsel *evsel, | 1931 | struct callchain_cursor *cursor, |
| 1920 | struct perf_sample *sample, | 1932 | struct perf_evsel *evsel, |
| 1921 | struct symbol **parent, | 1933 | struct perf_sample *sample, |
| 1922 | struct addr_location *root_al, | 1934 | int max_stack) |
| 1923 | int max_stack) | ||
| 1924 | { | 1935 | { |
| 1925 | int ret = thread__resolve_callchain_sample(thread, evsel, | ||
| 1926 | sample, parent, | ||
| 1927 | root_al, max_stack); | ||
| 1928 | if (ret) | ||
| 1929 | return ret; | ||
| 1930 | |||
| 1931 | /* Can we do dwarf post unwind? */ | 1936 | /* Can we do dwarf post unwind? */ |
| 1932 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | 1937 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && |
| 1933 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | 1938 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) |
| @@ -1938,9 +1943,45 @@ int thread__resolve_callchain(struct thread *thread, · 4 unmodified lines | |||
| 1938 | (!sample->user_stack.size)) | 1943 | (!sample->user_stack.size)) |
| 1939 | return 0; | 1944 | return 0; |
| 1940 | 1945 | ||
| 1941 | return unwind__get_entries(unwind_entry, &callchain_cursor, | 1946 | return unwind__get_entries(unwind_entry, cursor, |
| 1942 | thread, sample, max_stack); | 1947 | thread, sample, max_stack); |
| 1948 | } | ||
| 1949 | |||
| 1950 | int thread__resolve_callchain(struct thread *thread, | ||
| 1951 | struct callchain_cursor *cursor, | ||
| 1952 | struct perf_evsel *evsel, | ||
| 1953 | struct perf_sample *sample, | ||
| 1954 | struct symbol **parent, | ||
| 1955 | struct addr_location *root_al, | ||
| 1956 | int max_stack) | ||
| 1957 | { | ||
| 1958 | int ret = 0; | ||
| 1959 | |||
| 1960 | callchain_cursor_reset(&callchain_cursor); | ||
| 1943 | 1961 | ||
| 1962 | if (callchain_param.order == ORDER_CALLEE) { | ||
| 1963 | ret = thread__resolve_callchain_sample(thread, cursor, | ||
| 1964 | evsel, sample, | ||
| 1965 | parent, root_al, | ||
| 1966 | max_stack); | ||
| 1967 | if (ret) | ||
| 1968 | return ret; | ||
| 1969 | ret = thread__resolve_callchain_unwind(thread, cursor, | ||
| 1970 | evsel, sample, | ||
| 1971 | max_stack); | ||
| 1972 | } else { | ||
| 1973 | ret = thread__resolve_callchain_unwind(thread, cursor, | ||
| 1974 | evsel, sample, | ||
| 1975 | max_stack); | ||
| 1976 | if (ret) | ||
| 1977 | return ret; | ||
| 1978 | ret = thread__resolve_callchain_sample(thread, cursor, | ||
| 1979 | evsel, sample, | ||
| 1980 | parent, root_al, | ||
| 1981 | max_stack); | ||
| 1982 | } | ||
| 1983 | |||
| 1984 | return ret; | ||
| 1944 | } | 1985 | } |
| 1945 | 1986 | ||
| 1946 | int machine__for_each_thread(struct machine *machine, | 1987 | int machine__for_each_thread(struct machine *machine, |
| @@ -31,6 +31,7 @@ struct machine { · 30 unmodified lines | |||
| 31 | char *root_dir; | 31 | char *root_dir; |
| 32 | struct rb_root threads; | 32 | struct rb_root threads; |
| 33 | pthread_rwlock_t threads_lock; | 33 | pthread_rwlock_t threads_lock; |
| 34 | unsigned int nr_threads; | ||
| 34 | struct list_head dead_threads; | 35 | struct list_head dead_threads; |
| 35 | struct thread *last_match; | 36 | struct thread *last_match; |
| 36 | struct vdso_info *vdso_info; | 37 | struct vdso_info *vdso_info; |
| @@ -141,7 +142,11 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample, · 104 unmodified lines | |||
| 141 | struct addr_location *al); | 142 | struct addr_location *al); |
| 142 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, | 143 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, |
| 143 | struct addr_location *al); | 144 | struct addr_location *al); |
| 145 | |||
| 146 | struct callchain_cursor; | ||
| 147 | |||
| 144 | int thread__resolve_callchain(struct thread *thread, | 148 | int thread__resolve_callchain(struct thread *thread, |
| 149 | struct callchain_cursor *cursor, | ||
| 145 | struct perf_evsel *evsel, | 150 | struct perf_evsel *evsel, |
| 146 | struct perf_sample *sample, | 151 | struct perf_sample *sample, |
| 147 | struct symbol **parent, | 152 | struct symbol **parent, |
| @@ -211,6 +216,8 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *machine, · 63 unmodified lines | |||
| 211 | struct map *machine__findnew_module_map(struct machine *machine, u64 start, | 216 | struct map *machine__findnew_module_map(struct machine *machine, u64 start, |
| 212 | const char *filename); | 217 | const char *filename); |
| 213 | 218 | ||
| 219 | int __machine__load_kallsyms(struct machine *machine, const char *filename, | ||
| 220 | enum map_type type, bool no_kcore, symbol_filter_t filter); | ||
| 214 | int machine__load_kallsyms(struct machine *machine, const char *filename, | 221 | int machine__load_kallsyms(struct machine *machine, const char *filename, |
| 215 | enum map_type type, symbol_filter_t filter); | 222 | enum map_type type, symbol_filter_t filter); |
| 216 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | 223 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
| @@ -289,7 +289,7 @@ int map__load(struct map *map, symbol_filter_t filter) · 288 unmodified lines | |||
| 289 | nr = dso__load(map->dso, map, filter); | 289 | nr = dso__load(map->dso, map, filter); |
| 290 | if (nr < 0) { | 290 | if (nr < 0) { |
| 291 | if (map->dso->has_build_id) { | 291 | if (map->dso->has_build_id) { |
| 292 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 292 | char sbuild_id[SBUILD_ID_SIZE]; |
| 293 | 293 | ||
| 294 | build_id__sprintf(map->dso->build_id, | 294 | build_id__sprintf(map->dso->build_id, |
| 295 | sizeof(map->dso->build_id), | 295 | sizeof(map->dso->build_id), |
| @@ -431,6 +431,13 @@ u64 map__rip_2objdump(struct map *map, u64 rip) · 135 unmodified lines | |||
| 431 | if (map->dso->rel) | 431 | if (map->dso->rel) |
| 432 | return rip - map->pgoff; | 432 | return rip - map->pgoff; |
| 433 | 433 | ||
| 434 | /* | ||
| 435 | * kernel modules also have DSO_TYPE_USER in dso->kernel, | ||
| 436 | * but all kernel modules are ET_REL, so won't get here. | ||
| 437 | */ | ||
| 438 | if (map->dso->kernel == DSO_TYPE_USER) | ||
| 439 | return rip + map->dso->text_offset; | ||
| 440 | |||
| 434 | return map->unmap_ip(map, rip) - map->reloc; | 441 | return map->unmap_ip(map, rip) - map->reloc; |
| 435 | } | 442 | } |
| 436 | 443 | ||
| @@ -454,6 +461,13 @@ u64 map__objdump_2mem(struct map *map, u64 ip) · 17 unmodified lines | |||
| 454 | if (map->dso->rel) | 461 | if (map->dso->rel) |
| 455 | return map->unmap_ip(map, ip + map->pgoff); | 462 | return map->unmap_ip(map, ip + map->pgoff); |
| 456 | 463 | ||
| 464 | /* | ||
| 465 | * kernel modules also have DSO_TYPE_USER in dso->kernel, | ||
| 466 | * but all kernel modules are ET_REL, so won't get here. | ||
| 467 | */ | ||
| 468 | if (map->dso->kernel == DSO_TYPE_USER) | ||
| 469 | return map->unmap_ip(map, ip - map->dso->text_offset); | ||
| 470 | |||
| 457 | return ip + map->reloc; | 471 | return ip + map->reloc; |
| 458 | } | 472 | } |
| 459 | 473 | ||
| @@ -308,3 +308,12 @@ void ordered_events__free(struct ordered_events *oe) · 307 unmodified lines | |||
| 308 | free(event); | 308 | free(event); |
| 309 | } | 309 | } |
| 310 | } | 310 | } |
| 311 | |||
| 312 | void ordered_events__reinit(struct ordered_events *oe) | ||
| 313 | { | ||
| 314 | ordered_events__deliver_t old_deliver = oe->deliver; | ||
| 315 | |||
| 316 | ordered_events__free(oe); | ||
| 317 | memset(oe, '\0', sizeof(*oe)); | ||
| 318 | ordered_events__init(oe, old_deliver); | ||
| 319 | } | ||
| @@ -49,6 +49,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve · 48 unmodified lines | |||
| 49 | int ordered_events__flush(struct ordered_events *oe, enum oe_flush how); | 49 | int ordered_events__flush(struct ordered_events *oe, enum oe_flush how); |
| 50 | void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver); | 50 | void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver); |
| 51 | void ordered_events__free(struct ordered_events *oe); | 51 | void ordered_events__free(struct ordered_events *oe); |
| 52 | void ordered_events__reinit(struct ordered_events *oe); | ||
| 52 | 53 | ||
| 53 | static inline | 54 | static inline |
| 54 | void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size) | 55 | void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size) |
| @@ -602,14 +602,13 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, · 601 unmodified lines | |||
| 602 | 602 | ||
| 603 | static __u64 pmu_format_max_value(const unsigned long *format) | 603 | static __u64 pmu_format_max_value(const unsigned long *format) |
| 604 | { | 604 | { |
| 605 | int w; | 605 | __u64 w = 0; |
| 606 | int fbit; | ||
| 606 | 607 | ||
| 607 | w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); | 608 | for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS) |
| 608 | if (!w) | 609 | w |= (1ULL << fbit); |
| 609 | return 0; | 610 | |
| 610 | if (w < 64) | 611 | return w; |
| 611 | return (1ULL << w) - 1; | ||
| 612 | return -1; | ||
| 613 | } | 612 | } |
| 614 | 613 | ||
| 615 | /* | 614 | /* |
| @@ -644,20 +643,20 @@ static int pmu_resolve_param_term(struct parse_events_term *term, · 28 unmodified lines | |||
| 644 | static char *pmu_formats_string(struct list_head *formats) | 643 | static char *pmu_formats_string(struct list_head *formats) |
| 645 | { | 644 | { |
| 646 | struct perf_pmu_format *format; | 645 | struct perf_pmu_format *format; |
| 647 | char *str; | 646 | char *str = NULL; |
| 648 | struct strbuf buf; | 647 | struct strbuf buf = STRBUF_INIT; |
| 649 | unsigned i = 0; | 648 | unsigned i = 0; |
| 650 | 649 | ||
| 651 | if (!formats) | 650 | if (!formats) |
| 652 | return NULL; | 651 | return NULL; |
| 653 | 652 | ||
| 654 | strbuf_init(&buf, 0); | ||
| 655 | /* sysfs exported terms */ | 653 | /* sysfs exported terms */ |
| 656 | list_for_each_entry(format, formats, list) | 654 | list_for_each_entry(format, formats, list) |
| 657 | strbuf_addf(&buf, i++ ? ",%s" : "%s", | 655 | if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) |
| 658 | format->name); | 656 | goto error; |
| 659 | 657 | ||
| 660 | str = strbuf_detach(&buf, NULL); | 658 | str = strbuf_detach(&buf, NULL); |
| 659 | error: | ||
| 661 | strbuf_release(&buf); | 660 | strbuf_release(&buf); |
| 662 | 661 | ||
| 663 | return str; | 662 | return str; |
| @@ -265,6 +265,65 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address) · 264 unmodified lines | |||
| 265 | return true; | 265 | return true; |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | /* | ||
| 269 | * NOTE: | ||
| 270 | * '.gnu.linkonce.this_module' section of kernel module elf directly | ||
| 271 | * maps to 'struct module' from linux/module.h. This section contains | ||
| 272 | * actual module name which will be used by kernel after loading it. | ||
| 273 | * But, we cannot use 'struct module' here since linux/module.h is not | ||
| 274 | * exposed to user-space. Offset of 'name' has remained same from long | ||
| 275 | * time, so hardcoding it here. | ||
| 276 | */ | ||
| 277 | #ifdef __LP64__ | ||
| 278 | #define MOD_NAME_OFFSET 24 | ||
| 279 | #else | ||
| 280 | #define MOD_NAME_OFFSET 12 | ||
| 281 | #endif | ||
| 282 | |||
| 283 | /* | ||
| 284 | * @module can be module name of module file path. In case of path, | ||
| 285 | * inspect elf and find out what is actual module name. | ||
| 286 | * Caller has to free mod_name after using it. | ||
| 287 | */ | ||
| 288 | static char *find_module_name(const char *module) | ||
| 289 | { | ||
| 290 | int fd; | ||
| 291 | Elf *elf; | ||
| 292 | GElf_Ehdr ehdr; | ||
| 293 | GElf_Shdr shdr; | ||
| 294 | Elf_Data *data; | ||
| 295 | Elf_Scn *sec; | ||
| 296 | char *mod_name = NULL; | ||
| 297 | |||
| 298 | fd = open(module, O_RDONLY); | ||
| 299 | if (fd < 0) | ||
| 300 | return NULL; | ||
| 301 | |||
| 302 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
| 303 | if (elf == NULL) | ||
| 304 | goto elf_err; | ||
| 305 | |||
| 306 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
| 307 | goto ret_err; | ||
| 308 | |||
| 309 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
| 310 | ".gnu.linkonce.this_module", NULL); | ||
| 311 | if (!sec) | ||
| 312 | goto ret_err; | ||
| 313 | |||
| 314 | data = elf_getdata(sec, NULL); | ||
| 315 | if (!data || !data->d_buf) | ||
| 316 | goto ret_err; | ||
| 317 | |||
| 318 | mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET); | ||
| 319 | |||
| 320 | ret_err: | ||
| 321 | elf_end(elf); | ||
| 322 | elf_err: | ||
| 323 | close(fd); | ||
| 324 | return mod_name; | ||
| 325 | } | ||
| 326 | |||
| 268 | #ifdef HAVE_DWARF_SUPPORT | 327 | #ifdef HAVE_DWARF_SUPPORT |
| 269 | 328 | ||
| 270 | static int kernel_get_module_dso(const char *module, struct dso **pdso) | 329 | static int kernel_get_module_dso(const char *module, struct dso **pdso) |
| @@ -486,8 +545,10 @@ static int get_text_start_address(const char *exec, unsigned long *address) · 215 unmodified lines | |||
| 486 | return -errno; | 545 | return -errno; |
| 487 | 546 | ||
| 488 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 547 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
| 489 | if (elf == NULL) | 548 | if (elf == NULL) { |
| 490 | return -EINVAL; | 549 | ret = -EINVAL; |
| 550 | goto out_close; | ||
| 551 | } | ||
| 491 | 552 | ||
| 492 | if (gelf_getehdr(elf, &ehdr) == NULL) | 553 | if (gelf_getehdr(elf, &ehdr) == NULL) |
| 493 | goto out; | 554 | goto out; |
| @@ -499,6 +560,9 @@ static int get_text_start_address(const char *exec, unsigned long *address) · 5 unmodified lines | |||
| 499 | ret = 0; | 560 | ret = 0; |
| 500 | out: | 561 | out: |
| 501 | elf_end(elf); | 562 | elf_end(elf); |
| 563 | out_close: | ||
| 564 | close(fd); | ||
| 565 | |||
| 502 | return ret; | 566 | return ret; |
| 503 | } | 567 | } |
| 504 | 568 | ||
| @@ -583,32 +647,23 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, · 78 unmodified lines | |||
| 583 | int ntevs, const char *module) | 647 | int ntevs, const char *module) |
| 584 | { | 648 | { |
| 585 | int i, ret = 0; | 649 | int i, ret = 0; |
| 586 | char *tmp; | 650 | char *mod_name = NULL; |
| 587 | 651 | ||
| 588 | if (!module) | 652 | if (!module) |
| 589 | return 0; | 653 | return 0; |
| 590 | 654 | ||
| 591 | tmp = strrchr(module, '/'); | 655 | mod_name = find_module_name(module); |
| 592 | if (tmp) { | ||
| 593 | /* This is a module path -- get the module name */ | ||
| 594 | module = strdup(tmp + 1); | ||
| 595 | if (!module) | ||
| 596 | return -ENOMEM; | ||
| 597 | tmp = strchr(module, '.'); | ||
| 598 | if (tmp) | ||
| 599 | *tmp = '\0'; | ||
| 600 | tmp = (char *)module; /* For free() */ | ||
| 601 | } | ||
| 602 | 656 | ||
| 603 | for (i = 0; i < ntevs; i++) { | 657 | for (i = 0; i < ntevs; i++) { |
| 604 | tevs[i].point.module = strdup(module); | 658 | tevs[i].point.module = |
| 659 | strdup(mod_name ? mod_name : module); | ||
| 605 | if (!tevs[i].point.module) { | 660 | if (!tevs[i].point.module) { |
| 606 | ret = -ENOMEM; | 661 | ret = -ENOMEM; |
| 607 | break; | 662 | break; |
| 608 | } | 663 | } |
| 609 | } | 664 | } |
| 610 | 665 | ||
| 611 | free(tmp); | 666 | free(mod_name); |
| 612 | return ret; | 667 | return ret; |
| 613 | } | 668 | } |
| 614 | 669 | ||
| @@ -1618,69 +1673,65 @@ out: · 1003 unmodified lines | |||
| 1618 | } | 1673 | } |
| 1619 | 1674 | ||
| 1620 | /* Compose only probe arg */ | 1675 | /* Compose only probe arg */ |
| 1621 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | 1676 | char *synthesize_perf_probe_arg(struct perf_probe_arg *pa) |
| 1622 | { | 1677 | { |
| 1623 | struct perf_probe_arg_field *field = pa->field; | 1678 | struct perf_probe_arg_field *field = pa->field; |
| 1624 | int ret; | 1679 | struct strbuf buf; |
| 1625 | char *tmp = buf; | 1680 | char *ret = NULL; |
| 1681 | int err; | ||
| 1682 | |||
| 1683 | if (strbuf_init(&buf, 64) < 0) | ||
| 1684 | return NULL; | ||
| 1626 | 1685 | ||
| 1627 | if (pa->name && pa->var) | 1686 | if (pa->name && pa->var) |
| 1628 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); | 1687 | err = strbuf_addf(&buf, "%s=%s", pa->name, pa->var); |
| 1629 | else | 1688 | else |
| 1630 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); | 1689 | err = strbuf_addstr(&buf, pa->name ?: pa->var); |
| 1631 | if (ret <= 0) | 1690 | if (err) |
| 1632 | goto error; | 1691 | goto out; |
| 1633 | tmp += ret; | ||
| 1634 | len -= ret; | ||
| 1635 | 1692 | ||
| 1636 | while (field) { | 1693 | while (field) { |
| 1637 | if (field->name[0] == '[') | 1694 | if (field->name[0] == '[') |
| 1638 | ret = e_snprintf(tmp, len, "%s", field->name); | 1695 | err = strbuf_addstr(&buf, field->name); |
| 1639 | else | 1696 | else |
| 1640 | ret = e_snprintf(tmp, len, "%s%s", | 1697 | err = strbuf_addf(&buf, "%s%s", field->ref ? "->" : ".", |
| 1641 | field->ref ? "->" : ".", field->name); | 1698 | field->name); |
| 1642 | if (ret <= 0) | ||
| 1643 | goto error; | ||
| 1644 | tmp += ret; | ||
| 1645 | len -= ret; | ||
| 1646 | field = field->next; | 1699 | field = field->next; |
| 1700 | if (err) | ||
| 1701 | goto out; | ||
| 1647 | } | 1702 | } |
| 1648 | 1703 | ||
| 1649 | if (pa->type) { | 1704 | if (pa->type) |
| 1650 | ret = e_snprintf(tmp, len, ":%s", pa->type); | 1705 | if (strbuf_addf(&buf, ":%s", pa->type) < 0) |
| 1651 | if (ret <= 0) | 1706 | goto out; |
| 1652 | goto error; | ||
| 1653 | tmp += ret; | ||
| 1654 | len -= ret; | ||
| 1655 | } | ||
| 1656 | 1707 | ||
| 1657 | return tmp - buf; | 1708 | ret = strbuf_detach(&buf, NULL); |
| 1658 | error: | 1709 | out: |
| 1659 | pr_debug("Failed to synthesize perf probe argument: %d\n", ret); | 1710 | strbuf_release(&buf); |
| 1660 | return ret; | 1711 | return ret; |
| 1661 | } | 1712 | } |
| 1662 | 1713 | ||
| 1663 | /* Compose only probe point (not argument) */ | 1714 | /* Compose only probe point (not argument) */ |
| 1664 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | 1715 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
| 1665 | { | 1716 | { |
| 1666 | char *buf, *tmp; | 1717 | struct strbuf buf; |
| 1667 | char offs[32] = "", line[32] = "", file[32] = ""; | 1718 | char *tmp, *ret = NULL; |
| 1668 | int ret, len; | 1719 | int len, err = 0; |
| 1669 | 1720 | ||
| 1670 | buf = zalloc(MAX_CMDLEN); | 1721 | if (strbuf_init(&buf, 64) < 0) |
| 1671 | if (buf == NULL) { | 1722 | return NULL; |
| 1672 | ret = -ENOMEM; | 1723 | |
| 1673 | goto error; | 1724 | if (pp->function) { |
| 1674 | } | 1725 | if (strbuf_addstr(&buf, pp->function) < 0) |
| 1675 | if (pp->offset) { | 1726 | goto out; |
| 1676 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); | 1727 | if (pp->offset) |
| 1677 | if (ret <= 0) | 1728 | err = strbuf_addf(&buf, "+%lu", pp->offset); |
| 1678 | goto error; | 1729 | else if (pp->line) |
| 1679 | } | 1730 | err = strbuf_addf(&buf, ":%d", pp->line); |
| 1680 | if (pp->line) { | 1731 | else if (pp->retprobe) |
| 1681 | ret = e_snprintf(line, 32, ":%d", pp->line); | 1732 | err = strbuf_addstr(&buf, "%return"); |
| 1682 | if (ret <= 0) | 1733 | if (err) |
| 1683 | goto error; | 1734 | goto out; |
| 1684 | } | 1735 | } |
| 1685 | if (pp->file) { | 1736 | if (pp->file) { |
| 1686 | tmp = pp->file; | 1737 | tmp = pp->file; |
| @@ -1689,25 +1740,15 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) · 2 unmodified lines | |||
| 1689 | tmp = strchr(pp->file + len - 30, '/'); | 1740 | tmp = strchr(pp->file + len - 30, '/'); |
| 1690 | tmp = tmp ? tmp + 1 : pp->file + len - 30; | 1741 | tmp = tmp ? tmp + 1 : pp->file + len - 30; |
| 1691 | } | 1742 | } |
| 1692 | ret = e_snprintf(file, 32, "@%s", tmp); | 1743 | err = strbuf_addf(&buf, "@%s", tmp); |
| 1693 | if (ret <= 0) | 1744 | if (!err && !pp->function && pp->line) |
| 1694 | goto error; | 1745 | err = strbuf_addf(&buf, ":%d", pp->line); |
| 1695 | } | 1746 | } |
| 1696 | 1747 | if (!err) | |
| 1697 | if (pp->function) | 1748 | ret = strbuf_detach(&buf, NULL); |
| 1698 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, | 1749 | out: |
| 1699 | offs, pp->retprobe ? "%return" : "", line, | 1750 | strbuf_release(&buf); |
| 1700 | file); | 1751 | return ret; |
| 1701 | else | ||
| 1702 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); | ||
| 1703 | if (ret <= 0) | ||
| 1704 | goto error; | ||
| 1705 | |||
| 1706 | return buf; | ||
| 1707 | error: | ||
| 1708 | pr_debug("Failed to synthesize perf probe point: %d\n", ret); | ||
| 1709 | free(buf); | ||
| 1710 | return NULL; | ||
| 1711 | } | 1752 | } |
| 1712 | 1753 | ||
| 1713 | #if 0 | 1754 | #if 0 |
| @@ -1736,45 +1777,32 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev) · 22 unmodified lines | |||
| 1736 | #endif | 1777 | #endif |
| 1737 | 1778 | ||
| 1738 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, | 1779 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, |
| 1739 | char **buf, size_t *buflen, | 1780 | struct strbuf *buf, int depth) |
| 1740 | int depth) | ||
| 1741 | { | 1781 | { |
| 1742 | int ret; | 1782 | int err; |
| 1743 | if (ref->next) { | 1783 | if (ref->next) { |
| 1744 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, | 1784 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, |
| 1745 | buflen, depth + 1); | 1785 | depth + 1); |
| 1746 | if (depth < 0) | 1786 | if (depth < 0) |
| 1747 | goto out; | 1787 | return depth; |
| 1748 | } | ||
| 1749 | |||
| 1750 | ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); | ||
| 1751 | if (ret < 0) | ||
| 1752 | depth = ret; | ||
| 1753 | else { | ||
| 1754 | *buf += ret; | ||
| 1755 | *buflen -= ret; | ||
| 1756 | } | 1788 | } |
| 1757 | out: | 1789 | err = strbuf_addf(buf, "%+ld(", ref->offset); |
| 1758 | return depth; | 1790 | return (err < 0) ? err : depth; |
| 1759 | |||
| 1760 | } | 1791 | } |
| 1761 | 1792 | ||
| 1762 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, | 1793 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, |
| 1763 | char *buf, size_t buflen) | 1794 | struct strbuf *buf) |
| 1764 | { | 1795 | { |
| 1765 | struct probe_trace_arg_ref *ref = arg->ref; | 1796 | struct probe_trace_arg_ref *ref = arg->ref; |
| 1766 | int ret, depth = 0; | 1797 | int depth = 0, err; |
| 1767 | char *tmp = buf; | ||
| 1768 | 1798 | ||
| 1769 | /* Argument name or separator */ | 1799 | /* Argument name or separator */ |
| 1770 | if (arg->name) | 1800 | if (arg->name) |
| 1771 | ret = e_snprintf(buf, buflen, " %s=", arg->name); | 1801 | err = strbuf_addf(buf, " %s=", arg->name); |
| 1772 | else | 1802 | else |
| 1773 | ret = e_snprintf(buf, buflen, " "); | 1803 | err = strbuf_addch(buf, ' '); |
| 1774 | if (ret < 0) | 1804 | if (err) |
| 1775 | return ret; | 1805 | return err; |
| 1776 | buf += ret; | ||
| 1777 | buflen -= ret; | ||
| 1778 | 1806 | ||
| 1779 | /* Special case: @XXX */ | 1807 | /* Special case: @XXX */ |
| 1780 | if (arg->value[0] == '@' && arg->ref) | 1808 | if (arg->value[0] == '@' && arg->ref) |
| @@ -1782,59 +1810,44 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, · 1 unmodified line | |||
| 1782 | 1810 | ||
| 1783 | /* Dereferencing arguments */ | 1811 | /* Dereferencing arguments */ |
| 1784 | if (ref) { | 1812 | if (ref) { |
| 1785 | depth = __synthesize_probe_trace_arg_ref(ref, &buf, | 1813 | depth = __synthesize_probe_trace_arg_ref(ref, buf, 1); |
| 1786 | &buflen, 1); | ||
| 1787 | if (depth < 0) | 1814 | if (depth < 0) |
| 1788 | return depth; | 1815 | return depth; |
| 1789 | } | 1816 | } |
| 1790 | 1817 | ||
| 1791 | /* Print argument value */ | 1818 | /* Print argument value */ |
| 1792 | if (arg->value[0] == '@' && arg->ref) | 1819 | if (arg->value[0] == '@' && arg->ref) |
| 1793 | ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, | 1820 | err = strbuf_addf(buf, "%s%+ld", arg->value, arg->ref->offset); |
| 1794 | arg->ref->offset); | ||
| 1795 | else | 1821 | else |
| 1796 | ret = e_snprintf(buf, buflen, "%s", arg->value); | 1822 | err = strbuf_addstr(buf, arg->value); |
| 1797 | if (ret < 0) | ||
| 1798 | return ret; | ||
| 1799 | buf += ret; | ||
| 1800 | buflen -= ret; | ||
| 1801 | 1823 | ||
| 1802 | /* Closing */ | 1824 | /* Closing */ |
| 1803 | while (depth--) { | 1825 | while (!err && depth--) |
| 1804 | ret = e_snprintf(buf, buflen, ")"); | 1826 | err = strbuf_addch(buf, ')'); |
| 1805 | if (ret < 0) | 1827 | |
| 1806 | return ret; | ||
| 1807 | buf += ret; | ||
| 1808 | buflen -= ret; | ||
| 1809 | } | ||
| 1810 | /* Print argument type */ | 1828 | /* Print argument type */ |
| 1811 | if (arg->type) { | 1829 | if (!err && arg->type) |
| 1812 | ret = e_snprintf(buf, buflen, ":%s", arg->type); | 1830 | err = strbuf_addf(buf, ":%s", arg->type); |
| 1813 | if (ret <= 0) | ||
| 1814 | return ret; | ||
| 1815 | buf += ret; | ||
| 1816 | } | ||
| 1817 | 1831 | ||
| 1818 | return buf - tmp; | 1832 | return err; |
| 1819 | } | 1833 | } |
| 1820 | 1834 | ||
| 1821 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) | 1835 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) |
| 1822 | { | 1836 | { |
| 1823 | struct probe_trace_point *tp = &tev->point; | 1837 | struct probe_trace_point *tp = &tev->point; |
| 1824 | char *buf; | 1838 | struct strbuf buf; |
| 1825 | int i, len, ret; | 1839 | char *ret = NULL; |
| 1840 | int i, err; | ||
| 1826 | 1841 | ||
| 1827 | buf = zalloc(MAX_CMDLEN); | 1842 | /* Uprobes must have tp->module */ |
| 1828 | if (buf == NULL) | 1843 | if (tev->uprobes && !tp->module) |
| 1829 | return NULL; | 1844 | return NULL; |
| 1830 | 1845 | ||
| 1831 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', | 1846 | if (strbuf_init(&buf, 32) < 0) |
| 1832 | tev->group, tev->event); | 1847 | return NULL; |
| 1833 | if (len <= 0) | ||
| 1834 | goto error; | ||
| 1835 | 1848 | ||
| 1836 | /* Uprobes must have tp->module */ | 1849 | if (strbuf_addf(&buf, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', |
| 1837 | if (tev->uprobes && !tp->module) | 1850 | tev->group, tev->event) < 0) |
| 1838 | goto error; | 1851 | goto error; |
| 1839 | /* | 1852 | /* |
| 1840 | * If tp->address == 0, then this point must be a | 1853 | * If tp->address == 0, then this point must be a |
| @@ -1849,34 +1862,25 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) · 8 unmodified lines | |||
| 1849 | 1862 | ||
| 1850 | /* Use the tp->address for uprobes */ | 1863 | /* Use the tp->address for uprobes */ |
| 1851 | if (tev->uprobes) | 1864 | if (tev->uprobes) |
| 1852 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", | 1865 | err = strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address); |
| 1853 | tp->module, tp->address); | ||
| 1854 | else if (!strncmp(tp->symbol, "0x", 2)) | 1866 | else if (!strncmp(tp->symbol, "0x", 2)) |
| 1855 | /* Absolute address. See try_to_find_absolute_address() */ | 1867 | /* Absolute address. See try_to_find_absolute_address() */ |
| 1856 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s0x%lx", | 1868 | err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", |
| 1857 | tp->module ?: "", tp->module ? ":" : "", | 1869 | tp->module ? ":" : "", tp->address); |
| 1858 | tp->address); | ||
| 1859 | else | 1870 | else |
| 1860 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", | 1871 | err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", |
| 1861 | tp->module ?: "", tp->module ? ":" : "", | 1872 | tp->module ? ":" : "", tp->symbol, tp->offset); |
| 1862 | tp->symbol, tp->offset); | 1873 | if (err) |
| 1863 | |||
| 1864 | if (ret <= 0) | ||
| 1865 | goto error; | 1874 | goto error; |
| 1866 | len += ret; | ||
| 1867 | 1875 | ||
| 1868 | for (i = 0; i < tev->nargs; i++) { | 1876 | for (i = 0; i < tev->nargs; i++) |
| 1869 | ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, | 1877 | if (synthesize_probe_trace_arg(&tev->args[i], &buf) < 0) |
| 1870 | MAX_CMDLEN - len); | ||
| 1871 | if (ret <= 0) | ||
| 1872 | goto error; | 1878 | goto error; |
| 1873 | len += ret; | ||
| 1874 | } | ||
| 1875 | 1879 | ||
| 1876 | return buf; | 1880 | ret = strbuf_detach(&buf, NULL); |
| 1877 | error: | 1881 | error: |
| 1878 | free(buf); | 1882 | strbuf_release(&buf); |
| 1879 | return NULL; | 1883 | return ret; |
| 1880 | } | 1884 | } |
| 1881 | 1885 | ||
| 1882 | static int find_perf_probe_point_from_map(struct probe_trace_point *tp, | 1886 | static int find_perf_probe_point_from_map(struct probe_trace_point *tp, |
| @@ -1958,7 +1962,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp, · 75 unmodified lines | |||
| 1958 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, | 1962 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, |
| 1959 | struct perf_probe_event *pev, bool is_kprobe) | 1963 | struct perf_probe_event *pev, bool is_kprobe) |
| 1960 | { | 1964 | { |
| 1961 | char buf[64] = ""; | 1965 | struct strbuf buf = STRBUF_INIT; |
| 1962 | int i, ret; | 1966 | int i, ret; |
| 1963 | 1967 | ||
| 1964 | /* Convert event/group name */ | 1968 | /* Convert event/group name */ |
| @@ -1981,14 +1985,15 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, · 16 unmodified lines | |||
| 1981 | if (tev->args[i].name) | 1985 | if (tev->args[i].name) |
| 1982 | pev->args[i].name = strdup(tev->args[i].name); | 1986 | pev->args[i].name = strdup(tev->args[i].name); |
| 1983 | else { | 1987 | else { |
| 1984 | ret = synthesize_probe_trace_arg(&tev->args[i], | 1988 | if ((ret = strbuf_init(&buf, 32)) < 0) |
| 1985 | buf, 64); | 1989 | goto error; |
| 1986 | pev->args[i].name = strdup(buf); | 1990 | ret = synthesize_probe_trace_arg(&tev->args[i], &buf); |
| 1991 | pev->args[i].name = strbuf_detach(&buf, NULL); | ||
| 1987 | } | 1992 | } |
| 1988 | if (pev->args[i].name == NULL && ret >= 0) | 1993 | if (pev->args[i].name == NULL && ret >= 0) |
| 1989 | ret = -ENOMEM; | 1994 | ret = -ENOMEM; |
| 1990 | } | 1995 | } |
| 1991 | 1996 | error: | |
| 1992 | if (ret < 0) | 1997 | if (ret < 0) |
| 1993 | clear_perf_probe_event(pev); | 1998 | clear_perf_probe_event(pev); |
| 1994 | 1999 | ||
| @@ -2162,35 +2167,38 @@ static int perf_probe_event__sprintf(const char *group, const char *event, · 167 unmodified lines | |||
| 2162 | struct strbuf *result) | 2167 | struct strbuf *result) |
| 2163 | { | 2168 | { |
| 2164 | int i, ret; | 2169 | int i, ret; |
| 2165 | char buf[128]; | 2170 | char *buf; |
| 2166 | char *place; | ||
| 2167 | 2171 | ||
| 2168 | /* Synthesize only event probe point */ | 2172 | if (asprintf(&buf, "%s:%s", group, event) < 0) |
| 2169 | place = synthesize_perf_probe_point(&pev->point); | 2173 | return -errno; |
| 2170 | if (!place) | 2174 | ret = strbuf_addf(result, " %-20s (on ", buf); |
| 2171 | return -EINVAL; | 2175 | free(buf); |
| 2176 | if (ret) | ||
| 2177 | return ret; | ||
| 2172 | 2178 | ||
| 2173 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | 2179 | /* Synthesize only event probe point */ |
| 2174 | if (ret < 0) | 2180 | buf = synthesize_perf_probe_point(&pev->point); |
| 2175 | goto out; | 2181 | if (!buf) |
| 2182 | return -ENOMEM; | ||
| 2183 | ret = strbuf_addstr(result, buf); | ||
| 2184 | free(buf); | ||
| 2176 | 2185 | ||
| 2177 | strbuf_addf(result, " %-20s (on %s", buf, place); | 2186 | if (!ret && module) |
| 2178 | if (module) | 2187 | ret = strbuf_addf(result, " in %s", module); |
| 2179 | strbuf_addf(result, " in %s", module); | ||
| 2180 | 2188 | ||
| 2181 | if (pev->nargs > 0) { | 2189 | if (!ret && pev->nargs > 0) { |
| 2182 | strbuf_add(result, " with", 5); | 2190 | ret = strbuf_add(result, " with", 5); |
| 2183 | for (i = 0; i < pev->nargs; i++) { | 2191 | for (i = 0; !ret && i < pev->nargs; i++) { |
| 2184 | ret = synthesize_perf_probe_arg(&pev->args[i], | 2192 | buf = synthesize_perf_probe_arg(&pev->args[i]); |
| 2185 | buf, 128); | 2193 | if (!buf) |
| 2186 | if (ret < 0) | 2194 | return -ENOMEM; |
| 2187 | goto out; | 2195 | ret = strbuf_addf(result, " %s", buf); |
| 2188 | strbuf_addf(result, " %s", buf); | 2196 | free(buf); |
| 2189 | } | 2197 | } |
| 2190 | } | 2198 | } |
| 2191 | strbuf_addch(result, ')'); | 2199 | if (!ret) |
| 2192 | out: | 2200 | ret = strbuf_addch(result, ')'); |
| 2193 | free(place); | 2201 | |
| 2194 | return ret; | 2202 | return ret; |
| 2195 | } | 2203 | } |
| 2196 | 2204 | ||
| @@ -2498,7 +2506,8 @@ static int find_probe_functions(struct map *map, char *name, · 301 unmodified lines | |||
| 2498 | 2506 | ||
| 2499 | void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, | 2507 | void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, |
| 2500 | struct probe_trace_event *tev __maybe_unused, | 2508 | struct probe_trace_event *tev __maybe_unused, |
| 2501 | struct map *map __maybe_unused) { } | 2509 | struct map *map __maybe_unused, |
| 2510 | struct symbol *sym __maybe_unused) { } | ||
| 2502 | 2511 | ||
| 2503 | /* | 2512 | /* |
| 2504 | * Find probe function addresses from map. | 2513 | * Find probe function addresses from map. |
| @@ -2516,6 +2525,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, · 11 unmodified lines | |||
| 2516 | struct probe_trace_point *tp; | 2525 | struct probe_trace_point *tp; |
| 2517 | int num_matched_functions; | 2526 | int num_matched_functions; |
| 2518 | int ret, i, j, skipped = 0; | 2527 | int ret, i, j, skipped = 0; |
| 2528 | char *mod_name; | ||
| 2519 | 2529 | ||
| 2520 | map = get_target_map(pev->target, pev->uprobes); | 2530 | map = get_target_map(pev->target, pev->uprobes); |
| 2521 | if (!map) { | 2531 | if (!map) { |
| @@ -2600,9 +2610,19 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, · 78 unmodified lines | |||
| 2600 | tp->realname = strdup_or_goto(sym->name, nomem_out); | 2610 | tp->realname = strdup_or_goto(sym->name, nomem_out); |
| 2601 | 2611 | ||
| 2602 | tp->retprobe = pp->retprobe; | 2612 | tp->retprobe = pp->retprobe; |
| 2603 | if (pev->target) | 2613 | if (pev->target) { |
| 2604 | tev->point.module = strdup_or_goto(pev->target, | 2614 | if (pev->uprobes) { |
| 2605 | nomem_out); | 2615 | tev->point.module = strdup_or_goto(pev->target, |
| 2616 | nomem_out); | ||
| 2617 | } else { | ||
| 2618 | mod_name = find_module_name(pev->target); | ||
| 2619 | tev->point.module = | ||
| 2620 | strdup(mod_name ? mod_name : pev->target); | ||
| 2621 | free(mod_name); | ||
| 2622 | if (!tev->point.module) | ||
| 2623 | goto nomem_out; | ||
| 2624 | } | ||
| 2625 | } | ||
| 2606 | tev->uprobes = pev->uprobes; | 2626 | tev->uprobes = pev->uprobes; |
| 2607 | tev->nargs = pev->nargs; | 2627 | tev->nargs = pev->nargs; |
| 2608 | if (tev->nargs) { | 2628 | if (tev->nargs) { |
| @@ -2624,7 +2644,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, · 15 unmodified lines | |||
| 2624 | strdup_or_goto(pev->args[i].type, | 2644 | strdup_or_goto(pev->args[i].type, |
| 2625 | nomem_out); | 2645 | nomem_out); |
| 2626 | } | 2646 | } |
| 2627 | arch__fix_tev_from_maps(pev, tev, map); | 2647 | arch__fix_tev_from_maps(pev, tev, map, sym); |
| 2628 | } | 2648 | } |
| 2629 | if (ret == skipped) { | 2649 | if (ret == skipped) { |
| 2630 | ret = -ENOENT; | 2650 | ret = -ENOENT; |
| @@ -2743,9 +2763,13 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, · 112 unmodified lines | |||
| 2743 | { | 2763 | { |
| 2744 | int ret; | 2764 | int ret; |
| 2745 | 2765 | ||
| 2746 | if (pev->uprobes && !pev->group) { | 2766 | if (!pev->group) { |
| 2747 | /* Replace group name if not given */ | 2767 | /* Set group name if not given */ |
| 2748 | ret = convert_exec_to_group(pev->target, &pev->group); | 2768 | if (!pev->uprobes) { |
| 2769 | pev->group = strdup(PERFPROBE_GROUP); | ||
| 2770 | ret = pev->group ? 0 : -ENOMEM; | ||
| 2771 | } else | ||
| 2772 | ret = convert_exec_to_group(pev->target, &pev->group); | ||
| 2749 | if (ret != 0) { | 2773 | if (ret != 0) { |
| 2750 | pr_warning("Failed to make a group name.\n"); | 2774 | pr_warning("Failed to make a group name.\n"); |
| 2751 | return ret; | 2775 | return ret; |
| @@ -120,7 +120,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev); · 119 unmodified lines | |||
| 120 | /* Events to command string */ | 120 | /* Events to command string */ |
| 121 | char *synthesize_perf_probe_command(struct perf_probe_event *pev); | 121 | char *synthesize_perf_probe_command(struct perf_probe_event *pev); |
| 122 | char *synthesize_probe_trace_command(struct probe_trace_event *tev); | 122 | char *synthesize_probe_trace_command(struct probe_trace_event *tev); |
| 123 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len); | 123 | char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); |
| 124 | 124 | ||
| 125 | /* Check the perf_probe_event needs debuginfo */ | 125 | /* Check the perf_probe_event needs debuginfo */ |
| 126 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); | 126 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); |
| @@ -154,7 +154,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, · 27 unmodified lines | |||
| 154 | int show_available_funcs(const char *module, struct strfilter *filter, bool user); | 154 | int show_available_funcs(const char *module, struct strfilter *filter, bool user); |
| 155 | bool arch__prefers_symtab(void); | 155 | bool arch__prefers_symtab(void); |
| 156 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, | 156 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, |
| 157 | struct probe_trace_event *tev, struct map *map); | 157 | struct probe_trace_event *tev, struct map *map, |
| 158 | struct symbol *sym); | ||
| 158 | 159 | ||
| 159 | /* If there is no space to write, returns -E2BIG. */ | 160 | /* If there is no space to write, returns -E2BIG. */ |
| 160 | int e_snprintf(char *str, size_t size, const char *format, ...) | 161 | int e_snprintf(char *str, size_t size, const char *format, ...) |
| @@ -220,8 +220,7 @@ int probe_file__add_event(int fd, struct probe_trace_event *tev) · 219 unmodified lines | |||
| 220 | 220 | ||
| 221 | pr_debug("Writing event: %s\n", buf); | 221 | pr_debug("Writing event: %s\n", buf); |
| 222 | if (!probe_event_dry_run) { | 222 | if (!probe_event_dry_run) { |
| 223 | ret = write(fd, buf, strlen(buf)); | 223 | if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) { |
| 224 | if (ret <= 0) { | ||
| 225 | ret = -errno; | 224 | ret = -errno; |
| 226 | pr_warning("Failed to write event: %s\n", | 225 | pr_warning("Failed to write event: %s\n", |
| 227 | strerror_r(errno, sbuf, sizeof(sbuf))); | 226 | strerror_r(errno, sbuf, sizeof(sbuf))); |
| @@ -553,7 +553,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) · 552 unmodified lines | |||
| 553 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | 553 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
| 554 | { | 554 | { |
| 555 | Dwarf_Die vr_die; | 555 | Dwarf_Die vr_die; |
| 556 | char buf[32], *ptr; | 556 | char *buf, *ptr; |
| 557 | int ret = 0; | 557 | int ret = 0; |
| 558 | 558 | ||
| 559 | /* Copy raw parameters */ | 559 | /* Copy raw parameters */ |
| @@ -563,13 +563,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) · 3 unmodified lines | |||
| 563 | if (pf->pvar->name) | 563 | if (pf->pvar->name) |
| 564 | pf->tvar->name = strdup(pf->pvar->name); | 564 | pf->tvar->name = strdup(pf->pvar->name); |
| 565 | else { | 565 | else { |
| 566 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); | 566 | buf = synthesize_perf_probe_arg(pf->pvar); |
| 567 | if (ret < 0) | 567 | if (!buf) |
| 568 | return ret; | 568 | return -ENOMEM; |
| 569 | ptr = strchr(buf, ':'); /* Change type separator to _ */ | 569 | ptr = strchr(buf, ':'); /* Change type separator to _ */ |
| 570 | if (ptr) | 570 | if (ptr) |
| 571 | *ptr = '_'; | 571 | *ptr = '_'; |
| 572 | pf->tvar->name = strdup(buf); | 572 | pf->tvar->name = buf; |
| 573 | } | 573 | } |
| 574 | if (pf->tvar->name == NULL) | 574 | if (pf->tvar->name == NULL) |
| 575 | return -ENOMEM; | 575 | return -ENOMEM; |
| @@ -1294,6 +1294,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) · 718 unmodified lines | |||
| 1294 | { | 1294 | { |
| 1295 | struct available_var_finder *af = data; | 1295 | struct available_var_finder *af = data; |
| 1296 | struct variable_list *vl; | 1296 | struct variable_list *vl; |
| 1297 | struct strbuf buf = STRBUF_INIT; | ||
| 1297 | int tag, ret; | 1298 | int tag, ret; |
| 1298 | 1299 | ||
| 1299 | vl = &af->vls[af->nvls - 1]; | 1300 | vl = &af->vls[af->nvls - 1]; |
| @@ -1307,25 +1308,26 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) · 7 unmodified lines | |||
| 1307 | if (ret == 0 || ret == -ERANGE) { | 1308 | if (ret == 0 || ret == -ERANGE) { |
| 1308 | int ret2; | 1309 | int ret2; |
| 1309 | bool externs = !af->child; | 1310 | bool externs = !af->child; |
| 1310 | struct strbuf buf; | ||
| 1311 | 1311 | ||
| 1312 | strbuf_init(&buf, 64); | 1312 | if (strbuf_init(&buf, 64) < 0) |
| 1313 | goto error; | ||
| 1313 | 1314 | ||
| 1314 | if (probe_conf.show_location_range) { | 1315 | if (probe_conf.show_location_range) { |
| 1315 | if (!externs) { | 1316 | if (!externs) |
| 1316 | if (ret) | 1317 | ret2 = strbuf_add(&buf, |
| 1317 | strbuf_add(&buf, "[INV]\t", 6); | 1318 | ret ? "[INV]\t" : "[VAL]\t", 6); |
| 1318 | else | 1319 | else |
| 1319 | strbuf_add(&buf, "[VAL]\t", 6); | 1320 | ret2 = strbuf_add(&buf, "[EXT]\t", 6); |
| 1320 | } else | 1321 | if (ret2) |
| 1321 | strbuf_add(&buf, "[EXT]\t", 6); | 1322 | goto error; |
| 1322 | } | 1323 | } |
| 1323 | 1324 | ||
| 1324 | ret2 = die_get_varname(die_mem, &buf); | 1325 | ret2 = die_get_varname(die_mem, &buf); |
| 1325 | 1326 | ||
| 1326 | if (!ret2 && probe_conf.show_location_range && | 1327 | if (!ret2 && probe_conf.show_location_range && |
| 1327 | !externs) { | 1328 | !externs) { |
| 1328 | strbuf_addch(&buf, '\t'); | 1329 | if (strbuf_addch(&buf, '\t') < 0) |
| 1330 | goto error; | ||
| 1329 | ret2 = die_get_var_range(&af->pf.sp_die, | 1331 | ret2 = die_get_var_range(&af->pf.sp_die, |
| 1330 | die_mem, &buf); | 1332 | die_mem, &buf); |
| 1331 | } | 1333 | } |
| @@ -1343,6 +1345,10 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) · 11 unmodified lines | |||
| 1343 | return DIE_FIND_CB_CONTINUE; | 1345 | return DIE_FIND_CB_CONTINUE; |
| 1344 | else | 1346 | else |
| 1345 | return DIE_FIND_CB_SIBLING; | 1347 | return DIE_FIND_CB_SIBLING; |
| 1348 | error: | ||
| 1349 | strbuf_release(&buf); | ||
| 1350 | pr_debug("Error in strbuf\n"); | ||
| 1351 | return DIE_FIND_CB_END; | ||
| 1346 | } | 1352 | } |
| 1347 | 1353 | ||
| 1348 | /* Add a found vars into available variables list */ | 1354 | /* Add a found vars into available variables list */ |
| @@ -23,3 +23,4 @@ util/strlist.c · 22 unmodified lines | |||
| 23 | util/trace-event.c | 23 | util/trace-event.c |
| 24 | ../lib/rbtree.c | 24 | ../lib/rbtree.c |
| 25 | util/string.c | 25 | util/string.c |
| 26 | util/symbol_fprintf.c | ||
| @@ -17,38 +17,42 @@ static inline int need_bs_quote(char c) · 16 unmodified lines | |||
| 17 | return (c == '\'' || c == '!'); | 17 | return (c == '\'' || c == '!'); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | static void sq_quote_buf(struct strbuf *dst, const char *src) | 20 | static int sq_quote_buf(struct strbuf *dst, const char *src) |
| 21 | { | 21 | { |
| 22 | char *to_free = NULL; | 22 | char *to_free = NULL; |
| 23 | int ret; | ||
| 23 | 24 | ||
| 24 | if (dst->buf == src) | 25 | if (dst->buf == src) |
| 25 | to_free = strbuf_detach(dst, NULL); | 26 | to_free = strbuf_detach(dst, NULL); |
| 26 | 27 | ||
| 27 | strbuf_addch(dst, '\''); | 28 | ret = strbuf_addch(dst, '\''); |
| 28 | while (*src) { | 29 | while (!ret && *src) { |
| 29 | size_t len = strcspn(src, "'!"); | 30 | size_t len = strcspn(src, "'!"); |
| 30 | strbuf_add(dst, src, len); | 31 | ret = strbuf_add(dst, src, len); |
| 31 | src += len; | 32 | src += len; |
| 32 | while (need_bs_quote(*src)) { | 33 | while (!ret && need_bs_quote(*src)) |
| 33 | strbuf_addstr(dst, "'\\"); | 34 | ret = strbuf_addf(dst, "'\\%c\'", *src++); |
| 34 | strbuf_addch(dst, *src++); | ||
| 35 | strbuf_addch(dst, '\''); | ||
| 36 | } | ||
| 37 | } | 35 | } |
| 38 | strbuf_addch(dst, '\''); | 36 | if (!ret) |
| 37 | ret = strbuf_addch(dst, '\''); | ||
| 39 | free(to_free); | 38 | free(to_free); |
| 39 | |||
| 40 | return ret; | ||
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) | 43 | int sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) |
| 43 | { | 44 | { |
| 44 | int i; | 45 | int i, ret; |
| 45 | 46 | ||
| 46 | /* Copy into destination buffer. */ | 47 | /* Copy into destination buffer. */ |
| 47 | strbuf_grow(dst, 255); | 48 | ret = strbuf_grow(dst, 255); |
| 48 | for (i = 0; argv[i]; ++i) { | 49 | for (i = 0; !ret && argv[i]; ++i) { |
| 49 | strbuf_addch(dst, ' '); | 50 | ret = strbuf_addch(dst, ' '); |
| 50 | sq_quote_buf(dst, argv[i]); | 51 | if (ret) |
| 52 | break; | ||
| 53 | ret = sq_quote_buf(dst, argv[i]); | ||
| 51 | if (maxlen && dst->len > maxlen) | 54 | if (maxlen && dst->len > maxlen) |
| 52 | die("Too many or long arguments"); | 55 | die("Too many or long arguments"); |
| 53 | } | 56 | } |
| 57 | return ret; | ||
| 54 | } | 58 | } |
| @@ -24,6 +24,6 @@ · 23 unmodified lines | |||
| 24 | * sq_quote() in a real application. | 24 | * sq_quote() in a real application. |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); | 27 | int sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); |
| 28 | 28 | ||
| 29 | #endif /* __PERF_QUOTE_H */ | 29 | #endif /* __PERF_QUOTE_H */ |
| @@ -0,0 +1,149 @@ | |||
| 1 | #ifndef _PERF_RESORT_RB_H_ | ||
| 2 | #define _PERF_RESORT_RB_H_ | ||
| 3 | /* | ||
| 4 | * Template for creating a class to resort an existing rb_tree according to | ||
| 5 | * a new sort criteria, that must be present in the entries of the source | ||
| 6 | * rb_tree. | ||
| 7 | * | ||
| 8 | * (c) 2016 Arnaldo Carvalho de Melo <acme@redhat.com> | ||
| 9 | * | ||
| 10 | * Quick example, resorting threads by its shortname: | ||
| 11 | * | ||
| 12 | * First define the prefix (threads) to be used for the functions and data | ||
| 13 | * structures created, and provide an expression for the sorting, then the | ||
| 14 | * fields to be present in each of the entries in the new, sorted, rb_tree. | ||
| 15 | * | ||
| 16 | * The body of the init function should collect the fields, maybe | ||
| 17 | * pre-calculating them from multiple entries in the original 'entry' from | ||
| 18 | * the rb_tree used as a source for the entries to be sorted: | ||
| 19 | |||
| 20 | DEFINE_RB_RESORT_RB(threads, strcmp(a->thread->shortname, | ||
| 21 | b->thread->shortname) < 0, | ||
| 22 | struct thread *thread; | ||
| 23 | ) | ||
| 24 | { | ||
| 25 | entry->thread = rb_entry(nd, struct thread, rb_node); | ||
| 26 | } | ||
| 27 | |||
| 28 | * After this it is just a matter of instantiating it and iterating it, | ||
| 29 | * for a few data structures with existing rb_trees, such as 'struct machine', | ||
| 30 | * helpers are available to get the rb_root and the nr_entries: | ||
| 31 | |||
| 32 | DECLARE_RESORT_RB_MACHINE_THREADS(threads, machine_ptr); | ||
| 33 | |||
| 34 | * This will instantiate the new rb_tree and a cursor for it, that can be used as: | ||
| 35 | |||
| 36 | struct rb_node *nd; | ||
| 37 | |||
| 38 | resort_rb__for_each(nd, threads) { | ||
| 39 | struct thread *t = threads_entry; | ||
| 40 | printf("%s: %d\n", t->shortname, t->tid); | ||
| 41 | } | ||
| 42 | |||
| 43 | * Then delete it: | ||
| 44 | |||
| 45 | resort_rb__delete(threads); | ||
| 46 | |||
| 47 | * The name of the data structures and functions will have a _sorted suffix | ||
| 48 | * right before the method names, i.e. will look like: | ||
| 49 | * | ||
| 50 | * struct threads_sorted_entry {} | ||
| 51 | * threads_sorted__insert() | ||
| 52 | */ | ||
| 53 | |||
| 54 | #define DEFINE_RESORT_RB(__name, __comp, ...) \ | ||
| 55 | struct __name##_sorted_entry { \ | ||
| 56 | struct rb_node rb_node; \ | ||
| 57 | __VA_ARGS__ \ | ||
| 58 | }; \ | ||
| 59 | static void __name##_sorted__init_entry(struct rb_node *nd, \ | ||
| 60 | struct __name##_sorted_entry *entry); \ | ||
| 61 | \ | ||
| 62 | static int __name##_sorted__cmp(struct rb_node *nda, struct rb_node *ndb) \ | ||
| 63 | { \ | ||
| 64 | struct __name##_sorted_entry *a, *b; \ | ||
| 65 | a = rb_entry(nda, struct __name##_sorted_entry, rb_node); \ | ||
| 66 | b = rb_entry(ndb, struct __name##_sorted_entry, rb_node); \ | ||
| 67 | return __comp; \ | ||
| 68 | } \ | ||
| 69 | \ | ||
| 70 | struct __name##_sorted { \ | ||
| 71 | struct rb_root entries; \ | ||
| 72 | struct __name##_sorted_entry nd[0]; \ | ||
| 73 | }; \ | ||
| 74 | \ | ||
| 75 | static void __name##_sorted__insert(struct __name##_sorted *sorted, \ | ||
| 76 | struct rb_node *sorted_nd) \ | ||
| 77 | { \ | ||
| 78 | struct rb_node **p = &sorted->entries.rb_node, *parent = NULL; \ | ||
| 79 | while (*p != NULL) { \ | ||
| 80 | parent = *p; \ | ||
| 81 | if (__name##_sorted__cmp(sorted_nd, parent)) \ | ||
| 82 | p = &(*p)->rb_left; \ | ||
| 83 | else \ | ||
| 84 | p = &(*p)->rb_right; \ | ||
| 85 | } \ | ||
| 86 | rb_link_node(sorted_nd, parent, p); \ | ||
| 87 | rb_insert_color(sorted_nd, &sorted->entries); \ | ||
| 88 | } \ | ||
| 89 | \ | ||
| 90 | static void __name##_sorted__sort(struct __name##_sorted *sorted, \ | ||
| 91 | struct rb_root *entries) \ | ||
| 92 | { \ | ||
| 93 | struct rb_node *nd; \ | ||
| 94 | unsigned int i = 0; \ | ||
| 95 | for (nd = rb_first(entries); nd; nd = rb_next(nd)) { \ | ||
| 96 | struct __name##_sorted_entry *snd = &sorted->nd[i++]; \ | ||
| 97 | __name##_sorted__init_entry(nd, snd); \ | ||
| 98 | __name##_sorted__insert(sorted, &snd->rb_node); \ | ||
| 99 | } \ | ||
| 100 | } \ | ||
| 101 | \ | ||
| 102 | static struct __name##_sorted *__name##_sorted__new(struct rb_root *entries, \ | ||
| 103 | int nr_entries) \ | ||
| 104 | { \ | ||
| 105 | struct __name##_sorted *sorted; \ | ||
| 106 | sorted = malloc(sizeof(*sorted) + sizeof(sorted->nd[0]) * nr_entries); \ | ||
| 107 | if (sorted) { \ | ||
| 108 | sorted->entries = RB_ROOT; \ | ||
| 109 | __name##_sorted__sort(sorted, entries); \ | ||
| 110 | } \ | ||
| 111 | return sorted; \ | ||
| 112 | } \ | ||
| 113 | \ | ||
| 114 | static void __name##_sorted__delete(struct __name##_sorted *sorted) \ | ||
| 115 | { \ | ||
| 116 | free(sorted); \ | ||
| 117 | } \ | ||
| 118 | \ | ||
| 119 | static void __name##_sorted__init_entry(struct rb_node *nd, \ | ||
| 120 | struct __name##_sorted_entry *entry) | ||
| 121 | |||
| 122 | #define DECLARE_RESORT_RB(__name) \ | ||
| 123 | struct __name##_sorted_entry *__name##_entry; \ | ||
| 124 | struct __name##_sorted *__name = __name##_sorted__new | ||
| 125 | |||
| 126 | #define resort_rb__for_each(__nd, __name) \ | ||
| 127 | for (__nd = rb_first(&__name->entries); \ | ||
| 128 | __name##_entry = rb_entry(__nd, struct __name##_sorted_entry, \ | ||
| 129 | rb_node), __nd; \ | ||
| 130 | __nd = rb_next(__nd)) | ||
| 131 | |||
| 132 | #define resort_rb__delete(__name) \ | ||
| 133 | __name##_sorted__delete(__name), __name = NULL | ||
| 134 | |||
| 135 | /* | ||
| 136 | * Helpers for other classes that contains both an rbtree and the | ||
| 137 | * number of entries in it: | ||
| 138 | */ | ||
| 139 | |||
| 140 | /* For 'struct intlist' */ | ||
| 141 | #define DECLARE_RESORT_RB_INTLIST(__name, __ilist) \ | ||
| 142 | DECLARE_RESORT_RB(__name)(&__ilist->rblist.entries, \ | ||
| 143 | __ilist->rblist.nr_entries) | ||
| 144 | |||
| 145 | /* For 'struct machine->threads' */ | ||
| 146 | #define DECLARE_RESORT_RB_MACHINE_THREADS(__name, __machine) \ | ||
| 147 | DECLARE_RESORT_RB(__name)(&__machine->threads, __machine->nr_threads) | ||
| 148 | |||
| 149 | #endif /* _PERF_RESORT_RB_H_ */ | ||
| @@ -129,7 +129,8 @@ bool perf_can_record_cpu_wide(void) · 128 unmodified lines | |||
| 129 | return true; | 129 | return true; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | 132 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, |
| 133 | struct callchain_param *callchain) | ||
| 133 | { | 134 | { |
| 134 | struct perf_evsel *evsel; | 135 | struct perf_evsel *evsel; |
| 135 | bool use_sample_identifier = false; | 136 | bool use_sample_identifier = false; |
| @@ -148,7 +149,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) · 12 unmodified lines | |||
| 148 | use_comm_exec = perf_can_comm_exec(); | 149 | use_comm_exec = perf_can_comm_exec(); |
| 149 | 150 | ||
| 150 | evlist__for_each(evlist, evsel) { | 151 | evlist__for_each(evlist, evsel) { |
| 151 | perf_evsel__config(evsel, opts); | 152 | perf_evsel__config(evsel, opts, callchain); |
| 152 | if (evsel->tracking && use_comm_exec) | 153 | if (evsel->tracking && use_comm_exec) |
| 153 | evsel->attr.comm_exec = 1; | 154 | evsel->attr.comm_exec = 1; |
| 154 | } | 155 | } |
| @@ -31,6 +31,8 @@ · 30 unmodified lines | |||
| 31 | #include <perl.h> | 31 | #include <perl.h> |
| 32 | 32 | ||
| 33 | #include "../../perf.h" | 33 | #include "../../perf.h" |
| 34 | #include "../callchain.h" | ||
| 35 | #include "../machine.h" | ||
| 34 | #include "../thread.h" | 36 | #include "../thread.h" |
| 35 | #include "../event.h" | 37 | #include "../event.h" |
| 36 | #include "../trace-event.h" | 38 | #include "../trace-event.h" |
| @@ -248,10 +250,90 @@ static void define_event_symbols(struct event_format *event, · 211 unmodified lines | |||
| 248 | define_event_symbols(event, ev_name, args->next); | 250 | define_event_symbols(event, ev_name, args->next); |
| 249 | } | 251 | } |
| 250 | 252 | ||
| 253 | static SV *perl_process_callchain(struct perf_sample *sample, | ||
| 254 | struct perf_evsel *evsel, | ||
| 255 | struct addr_location *al) | ||
| 256 | { | ||
| 257 | AV *list; | ||
| 258 | |||
| 259 | list = newAV(); | ||
| 260 | if (!list) | ||
| 261 | goto exit; | ||
| 262 | |||
| 263 | if (!symbol_conf.use_callchain || !sample->callchain) | ||
| 264 | goto exit; | ||
| 265 | |||
| 266 | if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, | ||
| 267 | sample, NULL, NULL, | ||
| 268 | sysctl_perf_event_max_stack) != 0) { | ||
| 269 | pr_err("Failed to resolve callchain. Skipping\n"); | ||
| 270 | goto exit; | ||
| 271 | } | ||
| 272 | callchain_cursor_commit(&callchain_cursor); | ||
| 273 | |||
| 274 | |||
| 275 | while (1) { | ||
| 276 | HV *elem; | ||
| 277 | struct callchain_cursor_node *node; | ||
| 278 | node = callchain_cursor_current(&callchain_cursor); | ||
| 279 | if (!node) | ||
| 280 | break; | ||
| 281 | |||
| 282 | elem = newHV(); | ||
| 283 | if (!elem) | ||
| 284 | goto exit; | ||
| 285 | |||
| 286 | if (!hv_stores(elem, "ip", newSVuv(node->ip))) { | ||
| 287 | hv_undef(elem); | ||
| 288 | goto exit; | ||
| 289 | } | ||
| 290 | |||
| 291 | if (node->sym) { | ||
| 292 | HV *sym = newHV(); | ||
| 293 | if (!sym) { | ||
| 294 | hv_undef(elem); | ||
| 295 | goto exit; | ||
| 296 | } | ||
| 297 | if (!hv_stores(sym, "start", newSVuv(node->sym->start)) || | ||
| 298 | !hv_stores(sym, "end", newSVuv(node->sym->end)) || | ||
| 299 | !hv_stores(sym, "binding", newSVuv(node->sym->binding)) || | ||
| 300 | !hv_stores(sym, "name", newSVpvn(node->sym->name, | ||
| 301 | node->sym->namelen)) || | ||
| 302 | !hv_stores(elem, "sym", newRV_noinc((SV*)sym))) { | ||
| 303 | hv_undef(sym); | ||
| 304 | hv_undef(elem); | ||
| 305 | goto exit; | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | if (node->map) { | ||
| 310 | struct map *map = node->map; | ||
| 311 | const char *dsoname = "[unknown]"; | ||
| 312 | if (map && map->dso && (map->dso->name || map->dso->long_name)) { | ||
| 313 | if (symbol_conf.show_kernel_path && map->dso->long_name) | ||
| 314 | dsoname = map->dso->long_name; | ||
| 315 | else if (map->dso->name) | ||
| 316 | dsoname = map->dso->name; | ||
| 317 | } | ||
| 318 | if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) { | ||
| 319 | hv_undef(elem); | ||
| 320 | goto exit; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | callchain_cursor_advance(&callchain_cursor); | ||
| 325 | av_push(list, newRV_noinc((SV*)elem)); | ||
| 326 | } | ||
| 327 | |||
| 328 | exit: | ||
| 329 | return newRV_noinc((SV*)list); | ||
| 330 | } | ||
| 331 | |||
| 251 | static void perl_process_tracepoint(struct perf_sample *sample, | 332 | static void perl_process_tracepoint(struct perf_sample *sample, |
| 252 | struct perf_evsel *evsel, | 333 | struct perf_evsel *evsel, |
| 253 | struct thread *thread) | 334 | struct addr_location *al) |
| 254 | { | 335 | { |
| 336 | struct thread *thread = al->thread; | ||
| 255 | struct event_format *event = evsel->tp_format; | 337 | struct event_format *event = evsel->tp_format; |
| 256 | struct format_field *field; | 338 | struct format_field *field; |
| 257 | static char handler[256]; | 339 | static char handler[256]; |
| @@ -295,6 +377,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, · 37 unmodified lines | |||
| 295 | XPUSHs(sv_2mortal(newSVuv(ns))); | 377 | XPUSHs(sv_2mortal(newSVuv(ns))); |
| 296 | XPUSHs(sv_2mortal(newSViv(pid))); | 378 | XPUSHs(sv_2mortal(newSViv(pid))); |
| 297 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); | 379 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); |
| 380 | XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); | ||
| 298 | 381 | ||
| 299 | /* common fields other than pid can be accessed via xsub fns */ | 382 | /* common fields other than pid can be accessed via xsub fns */ |
| 300 | 383 | ||
| @@ -329,6 +412,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, · 28 unmodified lines | |||
| 329 | XPUSHs(sv_2mortal(newSVuv(nsecs))); | 412 | XPUSHs(sv_2mortal(newSVuv(nsecs))); |
| 330 | XPUSHs(sv_2mortal(newSViv(pid))); | 413 | XPUSHs(sv_2mortal(newSViv(pid))); |
| 331 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); | 414 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); |
| 415 | XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); | ||
| 332 | call_pv("main::trace_unhandled", G_SCALAR); | 416 | call_pv("main::trace_unhandled", G_SCALAR); |
| 333 | } | 417 | } |
| 334 | SPAGAIN; | 418 | SPAGAIN; |
| @@ -366,7 +450,7 @@ static void perl_process_event(union perf_event *event, · 31 unmodified lines | |||
| 366 | struct perf_evsel *evsel, | 450 | struct perf_evsel *evsel, |
| 367 | struct addr_location *al) | 451 | struct addr_location *al) |
| 368 | { | 452 | { |
| 369 | perl_process_tracepoint(sample, evsel, al->thread); | 453 | perl_process_tracepoint(sample, evsel, al); |
| 370 | perl_process_event_generic(event, sample, evsel); | 454 | perl_process_event_generic(event, sample, evsel); |
| 371 | } | 455 | } |
| 372 | 456 | ||
| @@ -490,7 +574,27 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) · 117 unmodified lines | |||
| 490 | fprintf(ofp, "use Perf::Trace::Util;\n\n"); | 574 | fprintf(ofp, "use Perf::Trace::Util;\n\n"); |
| 491 | 575 | ||
| 492 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); | 576 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); |
| 493 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); | 577 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n"); |
| 578 | |||
| 579 | |||
| 580 | fprintf(ofp, "\n\ | ||
| 581 | sub print_backtrace\n\ | ||
| 582 | {\n\ | ||
| 583 | my $callchain = shift;\n\ | ||
| 584 | for my $node (@$callchain)\n\ | ||
| 585 | {\n\ | ||
| 586 | if(exists $node->{sym})\n\ | ||
| 587 | {\n\ | ||
| 588 | printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\ | ||
| 589 | }\n\ | ||
| 590 | else\n\ | ||
| 591 | {\n\ | ||
| 592 | printf( \"\\t[\\%%x]\\n\", $node{ip});\n\ | ||
| 593 | }\n\ | ||
| 594 | }\n\ | ||
| 595 | }\n\n\ | ||
| 596 | "); | ||
| 597 | |||
| 494 | 598 | ||
| 495 | while ((event = trace_find_next_event(pevent, event))) { | 599 | while ((event = trace_find_next_event(pevent, event))) { |
| 496 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); | 600 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); |
| @@ -502,7 +606,8 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) · 5 unmodified lines | |||
| 502 | fprintf(ofp, "$common_secs, "); | 606 | fprintf(ofp, "$common_secs, "); |
| 503 | fprintf(ofp, "$common_nsecs,\n"); | 607 | fprintf(ofp, "$common_nsecs,\n"); |
| 504 | fprintf(ofp, "\t $common_pid, "); | 608 | fprintf(ofp, "\t $common_pid, "); |
| 505 | fprintf(ofp, "$common_comm,\n\t "); | 609 | fprintf(ofp, "$common_comm, "); |
| 610 | fprintf(ofp, "$common_callchain,\n\t "); | ||
| 506 | 611 | ||
| 507 | not_first = 0; | 612 | not_first = 0; |
| 508 | count = 0; | 613 | count = 0; |
| @@ -519,7 +624,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) · 10 unmodified lines | |||
| 519 | 624 | ||
| 520 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " | 625 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " |
| 521 | "$common_secs, $common_nsecs,\n\t " | 626 | "$common_secs, $common_nsecs,\n\t " |
| 522 | "$common_pid, $common_comm);\n\n"); | 627 | "$common_pid, $common_comm, $common_callchain);\n\n"); |
| 523 | 628 | ||
| 524 | fprintf(ofp, "\tprintf(\""); | 629 | fprintf(ofp, "\tprintf(\""); |
| 525 | 630 | ||
| @@ -581,17 +686,22 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) · 55 unmodified lines | |||
| 581 | fprintf(ofp, "$%s", f->name); | 686 | fprintf(ofp, "$%s", f->name); |
| 582 | } | 687 | } |
| 583 | 688 | ||
| 584 | fprintf(ofp, ");\n"); | 689 | fprintf(ofp, ");\n\n"); |
| 690 | |||
| 691 | fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); | ||
| 692 | |||
| 585 | fprintf(ofp, "}\n\n"); | 693 | fprintf(ofp, "}\n\n"); |
| 586 | } | 694 | } |
| 587 | 695 | ||
| 588 | fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " | 696 | fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " |
| 589 | "$common_cpu, $common_secs, $common_nsecs,\n\t " | 697 | "$common_cpu, $common_secs, $common_nsecs,\n\t " |
| 590 | "$common_pid, $common_comm) = @_;\n\n"); | 698 | "$common_pid, $common_comm, $common_callchain) = @_;\n\n"); |
| 591 | 699 | ||
| 592 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " | 700 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " |
| 593 | "$common_secs, $common_nsecs,\n\t $common_pid, " | 701 | "$common_secs, $common_nsecs,\n\t $common_pid, " |
| 594 | "$common_comm);\n}\n\n"); | 702 | "$common_comm, $common_callchain);\n"); |
| 703 | fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); | ||
| 704 | fprintf(ofp, "}\n\n"); | ||
| 595 | 705 | ||
| 596 | fprintf(ofp, "sub print_header\n{\n" | 706 | fprintf(ofp, "sub print_header\n{\n" |
| 597 | "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" | 707 | "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" |
| @@ -41,6 +41,7 @@ · 40 unmodified lines | |||
| 41 | #include "../thread-stack.h" | 41 | #include "../thread-stack.h" |
| 42 | #include "../trace-event.h" | 42 | #include "../trace-event.h" |
| 43 | #include "../machine.h" | 43 | #include "../machine.h" |
| 44 | #include "../call-path.h" | ||
| 44 | #include "thread_map.h" | 45 | #include "thread_map.h" |
| 45 | #include "cpumap.h" | 46 | #include "cpumap.h" |
| 46 | #include "stat.h" | 47 | #include "stat.h" |
| @@ -323,7 +324,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample, · 276 unmodified lines | |||
| 323 | if (!symbol_conf.use_callchain || !sample->callchain) | 324 | if (!symbol_conf.use_callchain || !sample->callchain) |
| 324 | goto exit; | 325 | goto exit; |
| 325 | 326 | ||
| 326 | if (thread__resolve_callchain(al->thread, evsel, | 327 | if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
| 327 | sample, NULL, NULL, | 328 | sample, NULL, NULL, |
| 328 | scripting_max_stack) != 0) { | 329 | scripting_max_stack) != 0) { |
| 329 | pr_err("Failed to resolve callchain. Skipping\n"); | 330 | pr_err("Failed to resolve callchain. Skipping\n"); |
| @@ -407,8 +408,11 @@ static void python_process_tracepoint(struct perf_sample *sample, · 77 unmodified lines | |||
| 407 | if (!t) | 408 | if (!t) |
| 408 | Py_FatalError("couldn't create Python tuple"); | 409 | Py_FatalError("couldn't create Python tuple"); |
| 409 | 410 | ||
| 410 | if (!event) | 411 | if (!event) { |
| 411 | die("ug! no event found for type %d", (int)evsel->attr.config); | 412 | snprintf(handler_name, sizeof(handler_name), |
| 413 | "ug! no event found for type %" PRIu64, (u64)evsel->attr.config); | ||
| 414 | Py_FatalError(handler_name); | ||
| 415 | } | ||
| 412 | 416 | ||
| 413 | pid = raw_field_value(event, "common_pid", data); | 417 | pid = raw_field_value(event, "common_pid", data); |
| 414 | 418 | ||
| @@ -614,7 +618,7 @@ static int python_export_dso(struct db_export *dbe, struct dso *dso, · 199 unmodified lines | |||
| 614 | struct machine *machine) | 618 | struct machine *machine) |
| 615 | { | 619 | { |
| 616 | struct tables *tables = container_of(dbe, struct tables, dbe); | 620 | struct tables *tables = container_of(dbe, struct tables, dbe); |
| 617 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 621 | char sbuild_id[SBUILD_ID_SIZE]; |
| 618 | PyObject *t; | 622 | PyObject *t; |
| 619 | 623 | ||
| 620 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | 624 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
| @@ -681,7 +685,7 @@ static int python_export_sample(struct db_export *dbe, · 60 unmodified lines | |||
| 681 | struct tables *tables = container_of(dbe, struct tables, dbe); | 685 | struct tables *tables = container_of(dbe, struct tables, dbe); |
| 682 | PyObject *t; | 686 | PyObject *t; |
| 683 | 687 | ||
| 684 | t = tuple_new(21); | 688 | t = tuple_new(22); |
| 685 | 689 | ||
| 686 | tuple_set_u64(t, 0, es->db_id); | 690 | tuple_set_u64(t, 0, es->db_id); |
| 687 | tuple_set_u64(t, 1, es->evsel->db_id); | 691 | tuple_set_u64(t, 1, es->evsel->db_id); |
| @@ -704,6 +708,7 @@ static int python_export_sample(struct db_export *dbe, · 16 unmodified lines | |||
| 704 | tuple_set_u64(t, 18, es->sample->data_src); | 708 | tuple_set_u64(t, 18, es->sample->data_src); |
| 705 | tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK); | 709 | tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK); |
| 706 | tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX)); | 710 | tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX)); |
| 711 | tuple_set_u64(t, 21, es->call_path_id); | ||
| 707 | 712 | ||
| 708 | call_object(tables->sample_handler, t, "sample_table"); | 713 | call_object(tables->sample_handler, t, "sample_table"); |
| 709 | 714 | ||
| @@ -998,8 +1003,10 @@ static void set_table_handlers(struct tables *tables) · 288 unmodified lines | |||
| 998 | { | 1003 | { |
| 999 | const char *perf_db_export_mode = "perf_db_export_mode"; | 1004 | const char *perf_db_export_mode = "perf_db_export_mode"; |
| 1000 | const char *perf_db_export_calls = "perf_db_export_calls"; | 1005 | const char *perf_db_export_calls = "perf_db_export_calls"; |
| 1001 | PyObject *db_export_mode, *db_export_calls; | 1006 | const char *perf_db_export_callchains = "perf_db_export_callchains"; |
| 1007 | PyObject *db_export_mode, *db_export_calls, *db_export_callchains; | ||
| 1002 | bool export_calls = false; | 1008 | bool export_calls = false; |
| 1009 | bool export_callchains = false; | ||
| 1003 | int ret; | 1010 | int ret; |
| 1004 | 1011 | ||
| 1005 | memset(tables, 0, sizeof(struct tables)); | 1012 | memset(tables, 0, sizeof(struct tables)); |
| @@ -1016,6 +1023,7 @@ static void set_table_handlers(struct tables *tables) · 10 unmodified lines | |||
| 1016 | if (!ret) | 1023 | if (!ret) |
| 1017 | return; | 1024 | return; |
| 1018 | 1025 | ||
| 1026 | /* handle export calls */ | ||
| 1019 | tables->dbe.crp = NULL; | 1027 | tables->dbe.crp = NULL; |
| 1020 | db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls); | 1028 | db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls); |
| 1021 | if (db_export_calls) { | 1029 | if (db_export_calls) { |
| @@ -1033,6 +1041,33 @@ static void set_table_handlers(struct tables *tables) · 11 unmodified lines | |||
| 1033 | Py_FatalError("failed to create calls processor"); | 1041 | Py_FatalError("failed to create calls processor"); |
| 1034 | } | 1042 | } |
| 1035 | 1043 | ||
| 1044 | /* handle export callchains */ | ||
| 1045 | tables->dbe.cpr = NULL; | ||
| 1046 | db_export_callchains = PyDict_GetItemString(main_dict, | ||
| 1047 | perf_db_export_callchains); | ||
| 1048 | if (db_export_callchains) { | ||
| 1049 | ret = PyObject_IsTrue(db_export_callchains); | ||
| 1050 | if (ret == -1) | ||
| 1051 | handler_call_die(perf_db_export_callchains); | ||
| 1052 | export_callchains = !!ret; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | if (export_callchains) { | ||
| 1056 | /* | ||
| 1057 | * Attempt to use the call path root from the call return | ||
| 1058 | * processor, if the call return processor is in use. Otherwise, | ||
| 1059 | * we allocate a new call path root. This prevents exporting | ||
| 1060 | * duplicate call path ids when both are in use simultaniously. | ||
| 1061 | */ | ||
| 1062 | if (tables->dbe.crp) | ||
| 1063 | tables->dbe.cpr = tables->dbe.crp->cpr; | ||
| 1064 | else | ||
| 1065 | tables->dbe.cpr = call_path_root__new(); | ||
| 1066 | |||
| 1067 | if (!tables->dbe.cpr) | ||
| 1068 | Py_FatalError("failed to create call path root"); | ||
| 1069 | } | ||
| 1070 | |||
| 1036 | tables->db_export_mode = true; | 1071 | tables->db_export_mode = true; |
| 1037 | /* | 1072 | /* |
| 1038 | * Reserve per symbol space for symbol->db_id via symbol__priv() | 1073 | * Reserve per symbol space for symbol->db_id via symbol__priv() |
| @@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) · 408 unmodified lines | |||
| 409 | tool->stat = process_stat_stub; | 409 | tool->stat = process_stat_stub; |
| 410 | if (tool->stat_round == NULL) | 410 | if (tool->stat_round == NULL) |
| 411 | tool->stat_round = process_stat_round_stub; | 411 | tool->stat_round = process_stat_round_stub; |
| 412 | if (tool->time_conv == NULL) | ||
| 413 | tool->time_conv = process_event_op2_stub; | ||
| 412 | } | 414 | } |
| 413 | 415 | ||
| 414 | static void swap_sample_id_all(union perf_event *event, void *data) | 416 | static void swap_sample_id_all(union perf_event *event, void *data) |
| @@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { · 379 unmodified lines | |||
| 794 | [PERF_RECORD_STAT] = perf_event__stat_swap, | 796 | [PERF_RECORD_STAT] = perf_event__stat_swap, |
| 795 | [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap, | 797 | [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap, |
| 796 | [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap, | 798 | [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap, |
| 799 | [PERF_RECORD_TIME_CONV] = perf_event__all64_swap, | ||
| 797 | [PERF_RECORD_HEADER_MAX] = NULL, | 800 | [PERF_RECORD_HEADER_MAX] = NULL, |
| 798 | }; | 801 | }; |
| 799 | 802 | ||
| @@ -904,7 +907,7 @@ static void callchain__printf(struct perf_evsel *evsel, · 104 unmodified lines | |||
| 904 | unsigned int i; | 907 | unsigned int i; |
| 905 | struct ip_callchain *callchain = sample->callchain; | 908 | struct ip_callchain *callchain = sample->callchain; |
| 906 | 909 | ||
| 907 | if (has_branch_callstack(evsel)) | 910 | if (perf_evsel__has_branch_callstack(evsel)) |
| 908 | callchain__lbr_callstack_printf(sample); | 911 | callchain__lbr_callstack_printf(sample); |
| 909 | 912 | ||
| 910 | printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr); | 913 | printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr); |
| @@ -1078,7 +1081,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, · 167 unmodified lines | |||
| 1078 | if (sample_type & PERF_SAMPLE_CALLCHAIN) | 1081 | if (sample_type & PERF_SAMPLE_CALLCHAIN) |
| 1079 | callchain__printf(evsel, sample); | 1082 | callchain__printf(evsel, sample); |
| 1080 | 1083 | ||
| 1081 | if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !has_branch_callstack(evsel)) | 1084 | if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) |
| 1082 | branch_stack__printf(sample); | 1085 | branch_stack__printf(sample); |
| 1083 | 1086 | ||
| 1084 | if (sample_type & PERF_SAMPLE_REGS_USER) | 1087 | if (sample_type & PERF_SAMPLE_REGS_USER) |
| @@ -1341,6 +1344,9 @@ static s64 perf_session__process_user_event(struct perf_session *session, · 256 unmodified lines | |||
| 1341 | return tool->stat(tool, event, session); | 1344 | return tool->stat(tool, event, session); |
| 1342 | case PERF_RECORD_STAT_ROUND: | 1345 | case PERF_RECORD_STAT_ROUND: |
| 1343 | return tool->stat_round(tool, event, session); | 1346 | return tool->stat_round(tool, event, session); |
| 1347 | case PERF_RECORD_TIME_CONV: | ||
| 1348 | session->time_conv = event->time_conv; | ||
| 1349 | return tool->time_conv(tool, event, session); | ||
| 1344 | default: | 1350 | default: |
| 1345 | return -EINVAL; | 1351 | return -EINVAL; |
| 1346 | } | 1352 | } |
| @@ -1830,7 +1836,11 @@ out: · 483 unmodified lines | |||
| 1830 | out_err: | 1836 | out_err: |
| 1831 | ui_progress__finish(); | 1837 | ui_progress__finish(); |
| 1832 | perf_session__warn_about_errors(session); | 1838 | perf_session__warn_about_errors(session); |
| 1833 | ordered_events__free(&session->ordered_events); | 1839 | /* |
| 1840 | * We may switching perf.data output, make ordered_events | ||
| 1841 | * reusable. | ||
| 1842 | */ | ||
| 1843 | ordered_events__reinit(&session->ordered_events); | ||
| 1834 | auxtrace__free_events(session); | 1844 | auxtrace__free_events(session); |
| 1835 | session->one_mmap = false; | 1845 | session->one_mmap = false; |
| 1836 | return err; | 1846 | return err; |
| @@ -1947,105 +1957,6 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, · 110 unmodified lines | |||
| 1947 | return NULL; | 1957 | return NULL; |
| 1948 | } | 1958 | } |
| 1949 | 1959 | ||
| 1950 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | ||
| 1951 | struct addr_location *al, | ||
| 1952 | unsigned int print_opts, unsigned int stack_depth) | ||
| 1953 | { | ||
| 1954 | struct callchain_cursor_node *node; | ||
| 1955 | int print_ip = print_opts & PRINT_IP_OPT_IP; | ||
| 1956 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | ||
| 1957 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | ||
| 1958 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | ||
| 1959 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | ||
| 1960 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
| 1961 | char s = print_oneline ? ' ' : '\t'; | ||
| 1962 | |||
| 1963 | if (symbol_conf.use_callchain && sample->callchain) { | ||
| 1964 | struct addr_location node_al; | ||
| 1965 | |||
| 1966 | if (thread__resolve_callchain(al->thread, evsel, | ||
| 1967 | sample, NULL, NULL, | ||
| 1968 | stack_depth) != 0) { | ||
| 1969 | if (verbose) | ||
| 1970 | error("Failed to resolve callchain. Skipping\n"); | ||
| 1971 | return; | ||
| 1972 | } | ||
| 1973 | callchain_cursor_commit(&callchain_cursor); | ||
| 1974 | |||
| 1975 | if (print_symoffset) | ||
| 1976 | node_al = *al; | ||
| 1977 | |||
| 1978 | while (stack_depth) { | ||
| 1979 | u64 addr = 0; | ||
| 1980 | |||
| 1981 | node = callchain_cursor_current(&callchain_cursor); | ||
| 1982 | if (!node) | ||
| 1983 | break; | ||
| 1984 | |||
| 1985 | if (node->sym && node->sym->ignore) | ||
| 1986 | goto next; | ||
| 1987 | |||
| 1988 | if (print_ip) | ||
| 1989 | printf("%c%16" PRIx64, s, node->ip); | ||
| 1990 | |||
| 1991 | if (node->map) | ||
| 1992 | addr = node->map->map_ip(node->map, node->ip); | ||
| 1993 | |||
| 1994 | if (print_sym) { | ||
| 1995 | printf(" "); | ||
| 1996 | if (print_symoffset) { | ||
| 1997 | node_al.addr = addr; | ||
| 1998 | node_al.map = node->map; | ||
| 1999 | symbol__fprintf_symname_offs(node->sym, &node_al, stdout); | ||
| 2000 | } else | ||
| 2001 | symbol__fprintf_symname(node->sym, stdout); | ||
| 2002 | } | ||
| 2003 | |||
| 2004 | if (print_dso) { | ||
| 2005 | printf(" ("); | ||
| 2006 | map__fprintf_dsoname(node->map, stdout); | ||
| 2007 | printf(")"); | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | if (print_srcline) | ||
| 2011 | map__fprintf_srcline(node->map, addr, "\n ", | ||
| 2012 | stdout); | ||
| 2013 | |||
| 2014 | if (!print_oneline) | ||
| 2015 | printf("\n"); | ||
| 2016 | |||
| 2017 | stack_depth--; | ||
| 2018 | next: | ||
| 2019 | callchain_cursor_advance(&callchain_cursor); | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | } else { | ||
| 2023 | if (al->sym && al->sym->ignore) | ||
| 2024 | return; | ||
| 2025 | |||
| 2026 | if (print_ip) | ||
| 2027 | printf("%16" PRIx64, sample->ip); | ||
| 2028 | |||
| 2029 | if (print_sym) { | ||
| 2030 | printf(" "); | ||
| 2031 | if (print_symoffset) | ||
| 2032 | symbol__fprintf_symname_offs(al->sym, al, | ||
| 2033 | stdout); | ||
| 2034 | else | ||
| 2035 | symbol__fprintf_symname(al->sym, stdout); | ||
| 2036 | } | ||
| 2037 | |||
| 2038 | if (print_dso) { | ||
| 2039 | printf(" ("); | ||
| 2040 | map__fprintf_dsoname(al->map, stdout); | ||
| 2041 | printf(")"); | ||
| 2042 | } | ||
| 2043 | |||
| 2044 | if (print_srcline) | ||
| 2045 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | ||
| 2046 | } | ||
| 2047 | } | ||
| 2048 | |||
| 2049 | int perf_session__cpu_bitmap(struct perf_session *session, | 1960 | int perf_session__cpu_bitmap(struct perf_session *session, |
| 2050 | const char *cpu_list, unsigned long *cpu_bitmap) | 1961 | const char *cpu_list, unsigned long *cpu_bitmap) |
| 2051 | { | 1962 | { |
| @@ -26,6 +26,7 @@ struct perf_session { · 25 unmodified lines | |||
| 26 | struct itrace_synth_opts *itrace_synth_opts; | 26 | struct itrace_synth_opts *itrace_synth_opts; |
| 27 | struct list_head auxtrace_index; | 27 | struct list_head auxtrace_index; |
| 28 | struct trace_event tevent; | 28 | struct trace_event tevent; |
| 29 | struct time_conv_event time_conv; | ||
| 29 | bool repipe; | 30 | bool repipe; |
| 30 | bool one_mmap; | 31 | bool one_mmap; |
| 31 | void *one_mmap_addr; | 32 | void *one_mmap_addr; |
| @@ -35,13 +36,6 @@ struct perf_session { · 3 unmodified lines | |||
| 35 | struct perf_tool *tool; | 36 | struct perf_tool *tool; |
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 38 | #define PRINT_IP_OPT_IP (1<<0) | ||
| 39 | #define PRINT_IP_OPT_SYM (1<<1) | ||
| 40 | #define PRINT_IP_OPT_DSO (1<<2) | ||
| 41 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) | ||
| 42 | #define PRINT_IP_OPT_ONELINE (1<<4) | ||
| 43 | #define PRINT_IP_OPT_SRCLINE (1<<5) | ||
| 44 | |||
| 45 | struct perf_tool; | 39 | struct perf_tool; |
| 46 | 40 | ||
| 47 | struct perf_session *perf_session__new(struct perf_data_file *file, | 41 | struct perf_session *perf_session__new(struct perf_data_file *file, |
| @@ -103,10 +97,6 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); · 55 unmodified lines | |||
| 103 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 97 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
| 104 | unsigned int type); | 98 | unsigned int type); |
| 105 | 99 | ||
| 106 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | ||
| 107 | struct addr_location *al, | ||
| 108 | unsigned int print_opts, unsigned int stack_depth); | ||
| 109 | |||
| 110 | int perf_session__cpu_bitmap(struct perf_session *session, | 100 | int perf_session__cpu_bitmap(struct perf_session *session, |
| 111 | const char *cpu_list, unsigned long *cpu_bitmap); | 101 | const char *cpu_list, unsigned long *cpu_bitmap); |
| 112 | 102 | ||
| @@ -21,13 +21,6 @@ const char *sort_order; · 20 unmodified lines | |||
| 21 | const char *field_order; | 21 | const char *field_order; |
| 22 | regex_t ignore_callees_regex; | 22 | regex_t ignore_callees_regex; |
| 23 | int have_ignore_callees = 0; | 23 | int have_ignore_callees = 0; |
| 24 | int sort__need_collapse = 0; | ||
| 25 | int sort__has_parent = 0; | ||
| 26 | int sort__has_sym = 0; | ||
| 27 | int sort__has_dso = 0; | ||
| 28 | int sort__has_socket = 0; | ||
| 29 | int sort__has_thread = 0; | ||
| 30 | int sort__has_comm = 0; | ||
| 31 | enum sort_mode sort__mode = SORT_MODE__NORMAL; | 24 | enum sort_mode sort__mode = SORT_MODE__NORMAL; |
| 32 | 25 | ||
| 33 | /* | 26 | /* |
| @@ -244,7 +237,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) · 210 unmodified lines | |||
| 244 | * comparing symbol address alone is not enough since it's a | 237 | * comparing symbol address alone is not enough since it's a |
| 245 | * relative address within a dso. | 238 | * relative address within a dso. |
| 246 | */ | 239 | */ |
| 247 | if (!sort__has_dso) { | 240 | if (!hists__has(left->hists, dso) || hists__has(right->hists, dso)) { |
| 248 | ret = sort__dso_cmp(left, right); | 241 | ret = sort__dso_cmp(left, right); |
| 249 | if (ret != 0) | 242 | if (ret != 0) |
| 250 | return ret; | 243 | return ret; |
| @@ -2163,7 +2156,7 @@ static int __sort_dimension__add(struct sort_dimension *sd, · 1912 unmodified lines | |||
| 2163 | return -1; | 2156 | return -1; |
| 2164 | 2157 | ||
| 2165 | if (sd->entry->se_collapse) | 2158 | if (sd->entry->se_collapse) |
| 2166 | sort__need_collapse = 1; | 2159 | list->need_collapse = 1; |
| 2167 | 2160 | ||
| 2168 | sd->taken = 1; | 2161 | sd->taken = 1; |
| 2169 | 2162 | ||
| @@ -2245,9 +2238,9 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, · 75 unmodified lines | |||
| 2245 | pr_err("Invalid regex: %s\n%s", parent_pattern, err); | 2238 | pr_err("Invalid regex: %s\n%s", parent_pattern, err); |
| 2246 | return -EINVAL; | 2239 | return -EINVAL; |
| 2247 | } | 2240 | } |
| 2248 | sort__has_parent = 1; | 2241 | list->parent = 1; |
| 2249 | } else if (sd->entry == &sort_sym) { | 2242 | } else if (sd->entry == &sort_sym) { |
| 2250 | sort__has_sym = 1; | 2243 | list->sym = 1; |
| 2251 | /* | 2244 | /* |
| 2252 | * perf diff displays the performance difference amongst | 2245 | * perf diff displays the performance difference amongst |
| 2253 | * two or more perf.data files. Those files could come | 2246 | * two or more perf.data files. Those files could come |
| @@ -2258,13 +2251,13 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, · 4 unmodified lines | |||
| 2258 | sd->entry->se_collapse = sort__sym_sort; | 2251 | sd->entry->se_collapse = sort__sym_sort; |
| 2259 | 2252 | ||
| 2260 | } else if (sd->entry == &sort_dso) { | 2253 | } else if (sd->entry == &sort_dso) { |
| 2261 | sort__has_dso = 1; | 2254 | list->dso = 1; |
| 2262 | } else if (sd->entry == &sort_socket) { | 2255 | } else if (sd->entry == &sort_socket) { |
| 2263 | sort__has_socket = 1; | 2256 | list->socket = 1; |
| 2264 | } else if (sd->entry == &sort_thread) { | 2257 | } else if (sd->entry == &sort_thread) { |
| 2265 | sort__has_thread = 1; | 2258 | list->thread = 1; |
| 2266 | } else if (sd->entry == &sort_comm) { | 2259 | } else if (sd->entry == &sort_comm) { |
| 2267 | sort__has_comm = 1; | 2260 | list->comm = 1; |
| 2268 | } | 2261 | } |
| 2269 | 2262 | ||
| 2270 | return __sort_dimension__add(sd, list, level); | 2263 | return __sort_dimension__add(sd, list, level); |
| @@ -2289,7 +2282,7 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, · 18 unmodified lines | |||
| 2289 | return -EINVAL; | 2282 | return -EINVAL; |
| 2290 | 2283 | ||
| 2291 | if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) | 2284 | if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) |
| 2292 | sort__has_sym = 1; | 2285 | list->sym = 1; |
| 2293 | 2286 | ||
| 2294 | __sort_dimension__add(sd, list, level); | 2287 | __sort_dimension__add(sd, list, level); |
| 2295 | return 0; | 2288 | return 0; |
| @@ -2305,7 +2298,7 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, · 9 unmodified lines | |||
| 2305 | return -EINVAL; | 2298 | return -EINVAL; |
| 2306 | 2299 | ||
| 2307 | if (sd->entry == &sort_mem_daddr_sym) | 2300 | if (sd->entry == &sort_mem_daddr_sym) |
| 2308 | sort__has_sym = 1; | 2301 | list->sym = 1; |
| 2309 | 2302 | ||
| 2310 | __sort_dimension__add(sd, list, level); | 2303 | __sort_dimension__add(sd, list, level); |
| 2311 | return 0; | 2304 | return 0; |
| @@ -2749,10 +2742,10 @@ int setup_sorting(struct perf_evlist *evlist) · 437 unmodified lines | |||
| 2749 | 2742 | ||
| 2750 | void reset_output_field(void) | 2743 | void reset_output_field(void) |
| 2751 | { | 2744 | { |
| 2752 | sort__need_collapse = 0; | 2745 | perf_hpp_list.need_collapse = 0; |
| 2753 | sort__has_parent = 0; | 2746 | perf_hpp_list.parent = 0; |
| 2754 | sort__has_sym = 0; | 2747 | perf_hpp_list.sym = 0; |
| 2755 | sort__has_dso = 0; | 2748 | perf_hpp_list.dso = 0; |
| 2756 | 2749 | ||
| 2757 | field_order = NULL; | 2750 | field_order = NULL; |
| 2758 | sort_order = NULL; | 2751 | sort_order = NULL; |
| @@ -31,13 +31,6 @@ extern const char *parent_pattern; · 30 unmodified lines | |||
| 31 | extern const char default_sort_order[]; | 31 | extern const char default_sort_order[]; |
| 32 | extern regex_t ignore_callees_regex; | 32 | extern regex_t ignore_callees_regex; |
| 33 | extern int have_ignore_callees; | 33 | extern int have_ignore_callees; |
| 34 | extern int sort__need_collapse; | ||
| 35 | extern int sort__has_dso; | ||
| 36 | extern int sort__has_parent; | ||
| 37 | extern int sort__has_sym; | ||
| 38 | extern int sort__has_socket; | ||
| 39 | extern int sort__has_thread; | ||
| 40 | extern int sort__has_comm; | ||
| 41 | extern enum sort_mode sort__mode; | 34 | extern enum sort_mode sort__mode; |
| 42 | extern struct sort_entry sort_comm; | 35 | extern struct sort_entry sort_comm; |
| 43 | extern struct sort_entry sort_dso; | 36 | extern struct sort_entry sort_dso; |
| @@ -307,6 +307,7 @@ int perf_stat_process_counter(struct perf_stat_config *config, · 306 unmodified lines | |||
| 307 | struct perf_counts_values *aggr = &counter->counts->aggr; | 307 | struct perf_counts_values *aggr = &counter->counts->aggr; |
| 308 | struct perf_stat_evsel *ps = counter->priv; | 308 | struct perf_stat_evsel *ps = counter->priv; |
| 309 | u64 *count = counter->counts->aggr.values; | 309 | u64 *count = counter->counts->aggr.values; |
| 310 | u64 val; | ||
| 310 | int i, ret; | 311 | int i, ret; |
| 311 | 312 | ||
| 312 | aggr->val = aggr->ena = aggr->run = 0; | 313 | aggr->val = aggr->ena = aggr->run = 0; |
| @@ -346,7 +347,8 @@ int perf_stat_process_counter(struct perf_stat_config *config, · 33 unmodified lines | |||
| 346 | /* | 347 | /* |
| 347 | * Save the full runtime - to allow normalization during printout: | 348 | * Save the full runtime - to allow normalization during printout: |
| 348 | */ | 349 | */ |
| 349 | perf_stat__update_shadow_stats(counter, count, 0); | 350 | val = counter->scale * *count; |
| 351 | perf_stat__update_shadow_stats(counter, &val, 0); | ||
| 350 | 352 | ||
| 351 | return 0; | 353 | return 0; |
| 352 | } | 354 | } |
| @@ -1,3 +1,4 @@ | |||
| 1 | #include "debug.h" | ||
| 1 | #include "cache.h" | 2 | #include "cache.h" |
| 2 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
| 3 | 4 | ||
| @@ -17,12 +18,13 @@ int prefixcmp(const char *str, const char *prefix) · 13 unmodified lines | |||
| 17 | */ | 18 | */ |
| 18 | char strbuf_slopbuf[1]; | 19 | char strbuf_slopbuf[1]; |
| 19 | 20 | ||
| 20 | void strbuf_init(struct strbuf *sb, ssize_t hint) | 21 | int strbuf_init(struct strbuf *sb, ssize_t hint) |
| 21 | { | 22 | { |
| 22 | sb->alloc = sb->len = 0; | 23 | sb->alloc = sb->len = 0; |
| 23 | sb->buf = strbuf_slopbuf; | 24 | sb->buf = strbuf_slopbuf; |
| 24 | if (hint) | 25 | if (hint) |
| 25 | strbuf_grow(sb, hint); | 26 | return strbuf_grow(sb, hint); |
| 27 | return 0; | ||
| 26 | } | 28 | } |
| 27 | 29 | ||
| 28 | void strbuf_release(struct strbuf *sb) | 30 | void strbuf_release(struct strbuf *sb) |
| @@ -42,67 +44,104 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz) · 13 unmodified lines | |||
| 42 | return res; | 44 | return res; |
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | void strbuf_grow(struct strbuf *sb, size_t extra) | 47 | int strbuf_grow(struct strbuf *sb, size_t extra) |
| 46 | { | 48 | { |
| 47 | if (sb->len + extra + 1 <= sb->len) | 49 | char *buf; |
| 48 | die("you want to use way too much memory"); | 50 | size_t nr = sb->len + extra + 1; |
| 49 | if (!sb->alloc) | 51 | |
| 50 | sb->buf = NULL; | 52 | if (nr < sb->alloc) |
| 51 | ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); | 53 | return 0; |
| 54 | |||
| 55 | if (nr <= sb->len) | ||
| 56 | return -E2BIG; | ||
| 57 | |||
| 58 | if (alloc_nr(sb->alloc) > nr) | ||
| 59 | nr = alloc_nr(sb->alloc); | ||
| 60 | |||
| 61 | /* | ||
| 62 | * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is | ||
| 63 | * a static variable. Thus we have to avoid passing it to realloc. | ||
| 64 | */ | ||
| 65 | buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf)); | ||
| 66 | if (!buf) | ||
| 67 | return -ENOMEM; | ||
| 68 | |||
| 69 | sb->buf = buf; | ||
| 70 | sb->alloc = nr; | ||
| 71 | return 0; | ||
| 52 | } | 72 | } |
| 53 | 73 | ||
| 54 | void strbuf_addch(struct strbuf *sb, int c) | 74 | int strbuf_addch(struct strbuf *sb, int c) |
| 55 | { | 75 | { |
| 56 | strbuf_grow(sb, 1); | 76 | int ret = strbuf_grow(sb, 1); |
| 77 | if (ret) | ||
| 78 | return ret; | ||
| 79 | |||
| 57 | sb->buf[sb->len++] = c; | 80 | sb->buf[sb->len++] = c; |
| 58 | sb->buf[sb->len] = '\0'; | 81 | sb->buf[sb->len] = '\0'; |
| 82 | return 0; | ||
| 59 | } | 83 | } |
| 60 | 84 | ||
| 61 | void strbuf_add(struct strbuf *sb, const void *data, size_t len) | 85 | int strbuf_add(struct strbuf *sb, const void *data, size_t len) |
| 62 | { | 86 | { |
| 63 | strbuf_grow(sb, len); | 87 | int ret = strbuf_grow(sb, len); |
| 88 | if (ret) | ||
| 89 | return ret; | ||
| 90 | |||
| 64 | memcpy(sb->buf + sb->len, data, len); | 91 | memcpy(sb->buf + sb->len, data, len); |
| 65 | strbuf_setlen(sb, sb->len + len); | 92 | return strbuf_setlen(sb, sb->len + len); |
| 66 | } | 93 | } |
| 67 | 94 | ||
| 68 | static void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) | 95 | static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) |
| 69 | { | 96 | { |
| 70 | int len; | 97 | int len, ret; |
| 71 | va_list ap_saved; | 98 | va_list ap_saved; |
| 72 | 99 | ||
| 73 | if (!strbuf_avail(sb)) | 100 | if (!strbuf_avail(sb)) { |
| 74 | strbuf_grow(sb, 64); | 101 | ret = strbuf_grow(sb, 64); |
| 102 | if (ret) | ||
| 103 | return ret; | ||
| 104 | } | ||
| 75 | 105 | ||
| 76 | va_copy(ap_saved, ap); | 106 | va_copy(ap_saved, ap); |
| 77 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); | 107 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); |
| 78 | if (len < 0) | 108 | if (len < 0) |
| 79 | die("your vsnprintf is broken"); | 109 | return len; |
| 80 | if (len > strbuf_avail(sb)) { | 110 | if (len > strbuf_avail(sb)) { |
| 81 | strbuf_grow(sb, len); | 111 | ret = strbuf_grow(sb, len); |
| 112 | if (ret) | ||
| 113 | return ret; | ||
| 82 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); | 114 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); |
| 83 | va_end(ap_saved); | 115 | va_end(ap_saved); |
| 84 | if (len > strbuf_avail(sb)) { | 116 | if (len > strbuf_avail(sb)) { |
| 85 | die("this should not happen, your vsnprintf is broken"); | 117 | pr_debug("this should not happen, your vsnprintf is broken"); |
| 118 | return -EINVAL; | ||
| 86 | } | 119 | } |
| 87 | } | 120 | } |
| 88 | strbuf_setlen(sb, sb->len + len); | 121 | return strbuf_setlen(sb, sb->len + len); |
| 89 | } | 122 | } |
| 90 | 123 | ||
| 91 | void strbuf_addf(struct strbuf *sb, const char *fmt, ...) | 124 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...) |
| 92 | { | 125 | { |
| 93 | va_list ap; | 126 | va_list ap; |
| 127 | int ret; | ||
| 94 | 128 | ||
| 95 | va_start(ap, fmt); | 129 | va_start(ap, fmt); |
| 96 | strbuf_addv(sb, fmt, ap); | 130 | ret = strbuf_addv(sb, fmt, ap); |
| 97 | va_end(ap); | 131 | va_end(ap); |
| 132 | return ret; | ||
| 98 | } | 133 | } |
| 99 | 134 | ||
| 100 | ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) | 135 | ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) |
| 101 | { | 136 | { |
| 102 | size_t oldlen = sb->len; | 137 | size_t oldlen = sb->len; |
| 103 | size_t oldalloc = sb->alloc; | 138 | size_t oldalloc = sb->alloc; |
| 139 | int ret; | ||
| 140 | |||
| 141 | ret = strbuf_grow(sb, hint ? hint : 8192); | ||
| 142 | if (ret) | ||
| 143 | return ret; | ||
| 104 | 144 | ||
| 105 | strbuf_grow(sb, hint ? hint : 8192); | ||
| 106 | for (;;) { | 145 | for (;;) { |
| 107 | ssize_t cnt; | 146 | ssize_t cnt; |
| 108 | 147 | ||
| @@ -112,12 +151,14 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) · 3 unmodified lines | |||
| 112 | strbuf_release(sb); | 151 | strbuf_release(sb); |
| 113 | else | 152 | else |
| 114 | strbuf_setlen(sb, oldlen); | 153 | strbuf_setlen(sb, oldlen); |
| 115 | return -1; | 154 | return cnt; |
| 116 | } | 155 | } |
| 117 | if (!cnt) | 156 | if (!cnt) |
| 118 | break; | 157 | break; |
| 119 | sb->len += cnt; | 158 | sb->len += cnt; |
| 120 | strbuf_grow(sb, 8192); | 159 | ret = strbuf_grow(sb, 8192); |
| 160 | if (ret) | ||
| 161 | return ret; | ||
| 121 | } | 162 | } |
| 122 | 163 | ||
| 123 | sb->buf[sb->len] = '\0'; | 164 | sb->buf[sb->len] = '\0'; |
| @@ -51,7 +51,7 @@ struct strbuf { · 50 unmodified lines | |||
| 51 | #define STRBUF_INIT { 0, 0, strbuf_slopbuf } | 51 | #define STRBUF_INIT { 0, 0, strbuf_slopbuf } |
| 52 | 52 | ||
| 53 | /*----- strbuf life cycle -----*/ | 53 | /*----- strbuf life cycle -----*/ |
| 54 | void strbuf_init(struct strbuf *buf, ssize_t hint); | 54 | int strbuf_init(struct strbuf *buf, ssize_t hint); |
| 55 | void strbuf_release(struct strbuf *buf); | 55 | void strbuf_release(struct strbuf *buf); |
| 56 | char *strbuf_detach(struct strbuf *buf, size_t *); | 56 | char *strbuf_detach(struct strbuf *buf, size_t *); |
| 57 | 57 | ||
| @@ -60,26 +60,31 @@ static inline ssize_t strbuf_avail(const struct strbuf *sb) { · 2 unmodified lines | |||
| 60 | return sb->alloc ? sb->alloc - sb->len - 1 : 0; | 60 | return sb->alloc ? sb->alloc - sb->len - 1 : 0; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | void strbuf_grow(struct strbuf *buf, size_t); | 63 | int strbuf_grow(struct strbuf *buf, size_t); |
| 64 | 64 | ||
| 65 | static inline void strbuf_setlen(struct strbuf *sb, size_t len) { | 65 | static inline int strbuf_setlen(struct strbuf *sb, size_t len) { |
| 66 | if (!sb->alloc) | 66 | int ret; |
| 67 | strbuf_grow(sb, 0); | 67 | if (!sb->alloc) { |
| 68 | ret = strbuf_grow(sb, 0); | ||
| 69 | if (ret) | ||
| 70 | return ret; | ||
| 71 | } | ||
| 68 | assert(len < sb->alloc); | 72 | assert(len < sb->alloc); |
| 69 | sb->len = len; | 73 | sb->len = len; |
| 70 | sb->buf[len] = '\0'; | 74 | sb->buf[len] = '\0'; |
| 75 | return 0; | ||
| 71 | } | 76 | } |
| 72 | 77 | ||
| 73 | /*----- add data in your buffer -----*/ | 78 | /*----- add data in your buffer -----*/ |
| 74 | void strbuf_addch(struct strbuf *sb, int c); | 79 | int strbuf_addch(struct strbuf *sb, int c); |
| 75 | 80 | ||
| 76 | void strbuf_add(struct strbuf *buf, const void *, size_t); | 81 | int strbuf_add(struct strbuf *buf, const void *, size_t); |
| 77 | static inline void strbuf_addstr(struct strbuf *sb, const char *s) { | 82 | static inline int strbuf_addstr(struct strbuf *sb, const char *s) { |
| 78 | strbuf_add(sb, s, strlen(s)); | 83 | return strbuf_add(sb, s, strlen(s)); |
| 79 | } | 84 | } |
| 80 | 85 | ||
| 81 | __attribute__((format(printf,2,3))) | 86 | __attribute__((format(printf,2,3))) |
| 82 | void strbuf_addf(struct strbuf *sb, const char *fmt, ...); | 87 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...); |
| 83 | 88 | ||
| 84 | /* XXX: if read fails, any partial read is undone */ | 89 | /* XXX: if read fails, any partial read is undone */ |
| 85 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); | 90 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); |
| @@ -709,17 +709,10 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, · 708 unmodified lines | |||
| 709 | if (ss->opdshdr.sh_type != SHT_PROGBITS) | 709 | if (ss->opdshdr.sh_type != SHT_PROGBITS) |
| 710 | ss->opdsec = NULL; | 710 | ss->opdsec = NULL; |
| 711 | 711 | ||
| 712 | if (dso->kernel == DSO_TYPE_USER) { | 712 | if (dso->kernel == DSO_TYPE_USER) |
| 713 | GElf_Shdr shdr; | 713 | ss->adjust_symbols = true; |
| 714 | ss->adjust_symbols = (ehdr.e_type == ET_EXEC || | 714 | else |
| 715 | ehdr.e_type == ET_REL || | ||
| 716 | dso__is_vdso(dso) || | ||
| 717 | elf_section_by_name(elf, &ehdr, &shdr, | ||
| 718 | ".gnu.prelink_undo", | ||
| 719 | NULL) != NULL); | ||
| 720 | } else { | ||
| 721 | ss->adjust_symbols = elf__needs_adjust_symbols(ehdr); | 715 | ss->adjust_symbols = elf__needs_adjust_symbols(ehdr); |
| 722 | } | ||
| 723 | 716 | ||
| 724 | ss->name = strdup(name); | 717 | ss->name = strdup(name); |
| 725 | if (!ss->name) { | 718 | if (!ss->name) { |
| @@ -777,7 +770,8 @@ static bool want_demangle(bool is_kernel_sym) · 51 unmodified lines | |||
| 777 | return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; | 770 | return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; |
| 778 | } | 771 | } |
| 779 | 772 | ||
| 780 | void __weak arch__elf_sym_adjust(GElf_Sym *sym __maybe_unused) { } | 773 | void __weak arch__sym_update(struct symbol *s __maybe_unused, |
| 774 | GElf_Sym *sym __maybe_unused) { } | ||
| 781 | 775 | ||
| 782 | int dso__load_sym(struct dso *dso, struct map *map, | 776 | int dso__load_sym(struct dso *dso, struct map *map, |
| 783 | struct symsrc *syms_ss, struct symsrc *runtime_ss, | 777 | struct symsrc *syms_ss, struct symsrc *runtime_ss, |
| @@ -954,8 +948,6 @@ int dso__load_sym(struct dso *dso, struct map *map, · 170 unmodified lines | |||
| 954 | (sym.st_value & 1)) | 948 | (sym.st_value & 1)) |
| 955 | --sym.st_value; | 949 | --sym.st_value; |
| 956 | 950 | ||
| 957 | arch__elf_sym_adjust(&sym); | ||
| 958 | |||
| 959 | if (dso->kernel || kmodule) { | 951 | if (dso->kernel || kmodule) { |
| 960 | char dso_name[PATH_MAX]; | 952 | char dso_name[PATH_MAX]; |
| 961 | 953 | ||
| @@ -1089,6 +1081,8 @@ new_symbol: · 127 unmodified lines | |||
| 1089 | if (!f) | 1081 | if (!f) |
| 1090 | goto out_elf_end; | 1082 | goto out_elf_end; |
| 1091 | 1083 | ||
| 1084 | arch__sym_update(f, &sym); | ||
| 1085 | |||
| 1092 | if (filter && filter(curr_map, f)) | 1086 | if (filter && filter(curr_map, f)) |
| 1093 | symbol__delete(f); | 1087 | symbol__delete(f); |
| 1094 | else { | 1088 | else { |
| @@ -255,40 +255,6 @@ void symbol__delete(struct symbol *sym) · 254 unmodified lines | |||
| 255 | free(((void *)sym) - symbol_conf.priv_size); | 255 | free(((void *)sym) - symbol_conf.priv_size); |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | size_t symbol__fprintf(struct symbol *sym, FILE *fp) | ||
| 259 | { | ||
| 260 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", | ||
| 261 | sym->start, sym->end, | ||
| 262 | sym->binding == STB_GLOBAL ? 'g' : | ||
| 263 | sym->binding == STB_LOCAL ? 'l' : 'w', | ||
| 264 | sym->name); | ||
| 265 | } | ||
| 266 | |||
| 267 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | ||
| 268 | const struct addr_location *al, FILE *fp) | ||
| 269 | { | ||
| 270 | unsigned long offset; | ||
| 271 | size_t length; | ||
| 272 | |||
| 273 | if (sym && sym->name) { | ||
| 274 | length = fprintf(fp, "%s", sym->name); | ||
| 275 | if (al) { | ||
| 276 | if (al->addr < sym->end) | ||
| 277 | offset = al->addr - sym->start; | ||
| 278 | else | ||
| 279 | offset = al->addr - al->map->start - sym->start; | ||
| 280 | length += fprintf(fp, "+0x%lx", offset); | ||
| 281 | } | ||
| 282 | return length; | ||
| 283 | } else | ||
| 284 | return fprintf(fp, "[unknown]"); | ||
| 285 | } | ||
| 286 | |||
| 287 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) | ||
| 288 | { | ||
| 289 | return symbol__fprintf_symname_offs(sym, NULL, fp); | ||
| 290 | } | ||
| 291 | |||
| 292 | void symbols__delete(struct rb_root *symbols) | 258 | void symbols__delete(struct rb_root *symbols) |
| 293 | { | 259 | { |
| 294 | struct symbol *pos; | 260 | struct symbol *pos; |
| @@ -335,7 +301,7 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) · 40 unmodified lines | |||
| 335 | 301 | ||
| 336 | if (ip < s->start) | 302 | if (ip < s->start) |
| 337 | n = n->rb_left; | 303 | n = n->rb_left; |
| 338 | else if (ip >= s->end) | 304 | else if (ip > s->end || (ip == s->end && ip != s->start)) |
| 339 | n = n->rb_right; | 305 | n = n->rb_right; |
| 340 | else | 306 | else |
| 341 | return s; | 307 | return s; |
| @@ -364,11 +330,6 @@ static struct symbol *symbols__next(struct symbol *sym) · 22 unmodified lines | |||
| 364 | return NULL; | 330 | return NULL; |
| 365 | } | 331 | } |
| 366 | 332 | ||
| 367 | struct symbol_name_rb_node { | ||
| 368 | struct rb_node rb_node; | ||
| 369 | struct symbol sym; | ||
| 370 | }; | ||
| 371 | |||
| 372 | static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) | 333 | static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) |
| 373 | { | 334 | { |
| 374 | struct rb_node **p = &symbols->rb_node; | 335 | struct rb_node **p = &symbols->rb_node; |
| @@ -452,6 +413,18 @@ void dso__reset_find_symbol_cache(struct dso *dso) · 77 unmodified lines | |||
| 452 | } | 413 | } |
| 453 | } | 414 | } |
| 454 | 415 | ||
| 416 | void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym) | ||
| 417 | { | ||
| 418 | symbols__insert(&dso->symbols[type], sym); | ||
| 419 | |||
| 420 | /* update the symbol cache if necessary */ | ||
| 421 | if (dso->last_find_result[type].addr >= sym->start && | ||
| 422 | (dso->last_find_result[type].addr < sym->end || | ||
| 423 | sym->start == sym->end)) { | ||
| 424 | dso->last_find_result[type].symbol = sym; | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 455 | struct symbol *dso__find_symbol(struct dso *dso, | 428 | struct symbol *dso__find_symbol(struct dso *dso, |
| 456 | enum map_type type, u64 addr) | 429 | enum map_type type, u64 addr) |
| 457 | { | 430 | { |
| @@ -497,21 +470,6 @@ void dso__sort_by_name(struct dso *dso, enum map_type type) · 39 unmodified lines | |||
| 497 | &dso->symbols[type]); | 470 | &dso->symbols[type]); |
| 498 | } | 471 | } |
| 499 | 472 | ||
| 500 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | ||
| 501 | enum map_type type, FILE *fp) | ||
| 502 | { | ||
| 503 | size_t ret = 0; | ||
| 504 | struct rb_node *nd; | ||
| 505 | struct symbol_name_rb_node *pos; | ||
| 506 | |||
| 507 | for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { | ||
| 508 | pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); | ||
| 509 | fprintf(fp, "%s\n", pos->sym.name); | ||
| 510 | } | ||
| 511 | |||
| 512 | return ret; | ||
| 513 | } | ||
| 514 | |||
| 515 | int modules__parse(const char *filename, void *arg, | 473 | int modules__parse(const char *filename, void *arg, |
| 516 | int (*process_module)(void *arg, const char *name, | 474 | int (*process_module)(void *arg, const char *name, |
| 517 | u64 start)) | 475 | u64 start)) |
| @@ -1262,8 +1220,8 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) · 744 unmodified lines | |||
| 1262 | return 0; | 1220 | return 0; |
| 1263 | } | 1221 | } |
| 1264 | 1222 | ||
| 1265 | int dso__load_kallsyms(struct dso *dso, const char *filename, | 1223 | int __dso__load_kallsyms(struct dso *dso, const char *filename, |
| 1266 | struct map *map, symbol_filter_t filter) | 1224 | struct map *map, bool no_kcore, symbol_filter_t filter) |
| 1267 | { | 1225 | { |
| 1268 | u64 delta = 0; | 1226 | u64 delta = 0; |
| 1269 | 1227 | ||
| @@ -1284,12 +1242,18 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, · 14 unmodified lines | |||
| 1284 | else | 1242 | else |
| 1285 | dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; | 1243 | dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; |
| 1286 | 1244 | ||
| 1287 | if (!dso__load_kcore(dso, map, filename)) | 1245 | if (!no_kcore && !dso__load_kcore(dso, map, filename)) |
| 1288 | return dso__split_kallsyms_for_kcore(dso, map, filter); | 1246 | return dso__split_kallsyms_for_kcore(dso, map, filter); |
| 1289 | else | 1247 | else |
| 1290 | return dso__split_kallsyms(dso, map, delta, filter); | 1248 | return dso__split_kallsyms(dso, map, delta, filter); |
| 1291 | } | 1249 | } |
| 1292 | 1250 | ||
| 1251 | int dso__load_kallsyms(struct dso *dso, const char *filename, | ||
| 1252 | struct map *map, symbol_filter_t filter) | ||
| 1253 | { | ||
| 1254 | return __dso__load_kallsyms(dso, filename, map, false, filter); | ||
| 1255 | } | ||
| 1256 | |||
| 1293 | static int dso__load_perf_map(struct dso *dso, struct map *map, | 1257 | static int dso__load_perf_map(struct dso *dso, struct map *map, |
| 1294 | symbol_filter_t filter) | 1258 | symbol_filter_t filter) |
| 1295 | { | 1259 | { |
| @@ -1644,25 +1608,27 @@ out: · 348 unmodified lines | |||
| 1644 | return err; | 1608 | return err; |
| 1645 | } | 1609 | } |
| 1646 | 1610 | ||
| 1611 | static bool visible_dir_filter(const char *name, struct dirent *d) | ||
| 1612 | { | ||
| 1613 | if (d->d_type != DT_DIR) | ||
| 1614 | return false; | ||
| 1615 | return lsdir_no_dot_filter(name, d); | ||
| 1616 | } | ||
| 1617 | |||
| 1647 | static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | 1618 | static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) |
| 1648 | { | 1619 | { |
| 1649 | char kallsyms_filename[PATH_MAX]; | 1620 | char kallsyms_filename[PATH_MAX]; |
| 1650 | struct dirent *dent; | ||
| 1651 | int ret = -1; | 1621 | int ret = -1; |
| 1652 | DIR *d; | 1622 | struct strlist *dirs; |
| 1623 | struct str_node *nd; | ||
| 1653 | 1624 | ||
| 1654 | d = opendir(dir); | 1625 | dirs = lsdir(dir, visible_dir_filter); |
| 1655 | if (!d) | 1626 | if (!dirs) |
| 1656 | return -1; | 1627 | return -1; |
| 1657 | 1628 | ||
| 1658 | while (1) { | 1629 | strlist__for_each(nd, dirs) { |
| 1659 | dent = readdir(d); | ||
| 1660 | if (!dent) | ||
| 1661 | break; | ||
| 1662 | if (dent->d_type != DT_DIR) | ||
| 1663 | continue; | ||
| 1664 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), | 1630 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), |
| 1665 | "%s/%s/kallsyms", dir, dent->d_name); | 1631 | "%s/%s/kallsyms", dir, nd->s); |
| 1666 | if (!validate_kcore_addresses(kallsyms_filename, map)) { | 1632 | if (!validate_kcore_addresses(kallsyms_filename, map)) { |
| 1667 | strlcpy(dir, kallsyms_filename, dir_sz); | 1633 | strlcpy(dir, kallsyms_filename, dir_sz); |
| 1668 | ret = 0; | 1634 | ret = 0; |
| @@ -1670,7 +1636,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) · 1 unmodified line | |||
| 1670 | } | 1636 | } |
| 1671 | } | 1637 | } |
| 1672 | 1638 | ||
| 1673 | closedir(d); | 1639 | strlist__delete(dirs); |
| 1674 | 1640 | ||
| 1675 | return ret; | 1641 | return ret; |
| 1676 | } | 1642 | } |
| @@ -1678,7 +1644,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) · 1 unmodified line | |||
| 1678 | static char *dso__find_kallsyms(struct dso *dso, struct map *map) | 1644 | static char *dso__find_kallsyms(struct dso *dso, struct map *map) |
| 1679 | { | 1645 | { |
| 1680 | u8 host_build_id[BUILD_ID_SIZE]; | 1646 | u8 host_build_id[BUILD_ID_SIZE]; |
| 1681 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1647 | char sbuild_id[SBUILD_ID_SIZE]; |
| 1682 | bool is_host = false; | 1648 | bool is_host = false; |
| 1683 | char path[PATH_MAX]; | 1649 | char path[PATH_MAX]; |
| 1684 | 1650 | ||
| @@ -55,6 +55,7 @@ struct symbol { · 54 unmodified lines | |||
| 55 | u16 namelen; | 55 | u16 namelen; |
| 56 | u8 binding; | 56 | u8 binding; |
| 57 | bool ignore; | 57 | bool ignore; |
| 58 | u8 arch_sym; | ||
| 58 | char name[0]; | 59 | char name[0]; |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| @@ -140,6 +141,11 @@ struct symbol_conf { · 79 unmodified lines | |||
| 140 | 141 | ||
| 141 | extern struct symbol_conf symbol_conf; | 142 | extern struct symbol_conf symbol_conf; |
| 142 | 143 | ||
| 144 | struct symbol_name_rb_node { | ||
| 145 | struct rb_node rb_node; | ||
| 146 | struct symbol sym; | ||
| 147 | }; | ||
| 148 | |||
| 143 | static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) | 149 | static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) |
| 144 | { | 150 | { |
| 145 | return path__join(bf, size, symbol_conf.symfs, path); | 151 | return path__join(bf, size, symbol_conf.symfs, path); |
| @@ -235,9 +241,14 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, · 89 unmodified lines | |||
| 235 | symbol_filter_t filter); | 241 | symbol_filter_t filter); |
| 236 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, | 242 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, |
| 237 | symbol_filter_t filter); | 243 | symbol_filter_t filter); |
| 244 | int __dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | ||
| 245 | bool no_kcore, symbol_filter_t filter); | ||
| 238 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | 246 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, |
| 239 | symbol_filter_t filter); | 247 | symbol_filter_t filter); |
| 240 | 248 | ||
| 249 | void dso__insert_symbol(struct dso *dso, enum map_type type, | ||
| 250 | struct symbol *sym); | ||
| 251 | |||
| 241 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, | 252 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, |
| 242 | u64 addr); | 253 | u64 addr); |
| 243 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 254 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
| @@ -262,8 +273,14 @@ int symbol__init(struct perf_env *env); · 18 unmodified lines | |||
| 262 | void symbol__exit(void); | 273 | void symbol__exit(void); |
| 263 | void symbol__elf_init(void); | 274 | void symbol__elf_init(void); |
| 264 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); | 275 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); |
| 276 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, | ||
| 277 | const struct addr_location *al, | ||
| 278 | bool unknown_as_addr, FILE *fp); | ||
| 265 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | 279 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, |
| 266 | const struct addr_location *al, FILE *fp); | 280 | const struct addr_location *al, FILE *fp); |
| 281 | size_t __symbol__fprintf_symname(const struct symbol *sym, | ||
| 282 | const struct addr_location *al, | ||
| 283 | bool unknown_as_addr, FILE *fp); | ||
| 267 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); | 284 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); |
| 268 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); | 285 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); |
| 269 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 286 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
| @@ -310,7 +327,7 @@ int setup_intlist(struct intlist **list, const char *list_str, · 40 unmodified lines | |||
| 310 | 327 | ||
| 311 | #ifdef HAVE_LIBELF_SUPPORT | 328 | #ifdef HAVE_LIBELF_SUPPORT |
| 312 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); | 329 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); |
| 313 | void arch__elf_sym_adjust(GElf_Sym *sym); | 330 | void arch__sym_update(struct symbol *s, GElf_Sym *sym); |
| 314 | #endif | 331 | #endif |
| 315 | 332 | ||
| 316 | #define SYMBOL_A 0 | 333 | #define SYMBOL_A 0 |
| @@ -0,0 +1,71 @@ | |||
| 1 | #include <elf.h> | ||
| 2 | #include <inttypes.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | |||
| 5 | #include "symbol.h" | ||
| 6 | |||
| 7 | size_t symbol__fprintf(struct symbol *sym, FILE *fp) | ||
| 8 | { | ||
| 9 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", | ||
| 10 | sym->start, sym->end, | ||
| 11 | sym->binding == STB_GLOBAL ? 'g' : | ||
| 12 | sym->binding == STB_LOCAL ? 'l' : 'w', | ||
| 13 | sym->name); | ||
| 14 | } | ||
| 15 | |||
| 16 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, | ||
| 17 | const struct addr_location *al, | ||
| 18 | bool unknown_as_addr, FILE *fp) | ||
| 19 | { | ||
| 20 | unsigned long offset; | ||
| 21 | size_t length; | ||
| 22 | |||
| 23 | if (sym && sym->name) { | ||
| 24 | length = fprintf(fp, "%s", sym->name); | ||
| 25 | if (al) { | ||
| 26 | if (al->addr < sym->end) | ||
| 27 | offset = al->addr - sym->start; | ||
| 28 | else | ||
| 29 | offset = al->addr - al->map->start - sym->start; | ||
| 30 | length += fprintf(fp, "+0x%lx", offset); | ||
| 31 | } | ||
| 32 | return length; | ||
| 33 | } else if (al && unknown_as_addr) | ||
| 34 | return fprintf(fp, "[%#" PRIx64 "]", al->addr); | ||
| 35 | else | ||
| 36 | return fprintf(fp, "[unknown]"); | ||
| 37 | } | ||
| 38 | |||
| 39 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | ||
| 40 | const struct addr_location *al, | ||
| 41 | FILE *fp) | ||
| 42 | { | ||
| 43 | return __symbol__fprintf_symname_offs(sym, al, false, fp); | ||
| 44 | } | ||
| 45 | |||
| 46 | size_t __symbol__fprintf_symname(const struct symbol *sym, | ||
| 47 | const struct addr_location *al, | ||
| 48 | bool unknown_as_addr, FILE *fp) | ||
| 49 | { | ||
| 50 | return __symbol__fprintf_symname_offs(sym, al, unknown_as_addr, fp); | ||
| 51 | } | ||
| 52 | |||
| 53 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) | ||
| 54 | { | ||
| 55 | return __symbol__fprintf_symname_offs(sym, NULL, false, fp); | ||
| 56 | } | ||
| 57 | |||
| 58 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | ||
| 59 | enum map_type type, FILE *fp) | ||
| 60 | { | ||
| 61 | size_t ret = 0; | ||
| 62 | struct rb_node *nd; | ||
| 63 | struct symbol_name_rb_node *pos; | ||
| 64 | |||
| 65 | for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { | ||
| 66 | pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); | ||
| 67 | fprintf(fp, "%s\n", pos->sym.name); | ||
| 68 | } | ||
| 69 | |||
| 70 | return ret; | ||
| 71 | } | ||
| @@ -0,0 +1,134 @@ | |||
| 1 | /* | ||
| 2 | * System call table mapper | ||
| 3 | * | ||
| 4 | * (C) 2016 Arnaldo Carvalho de Melo <acme@redhat.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include "syscalltbl.h" | ||
| 17 | #include <stdlib.h> | ||
| 18 | |||
| 19 | #ifdef HAVE_SYSCALL_TABLE | ||
| 20 | #include <linux/compiler.h> | ||
| 21 | #include <string.h> | ||
| 22 | #include "util.h" | ||
| 23 | |||
| 24 | #if defined(__x86_64__) | ||
| 25 | #include <asm/syscalls_64.c> | ||
| 26 | const int syscalltbl_native_max_id = SYSCALLTBL_x86_64_MAX_ID; | ||
| 27 | static const char **syscalltbl_native = syscalltbl_x86_64; | ||
| 28 | #endif | ||
| 29 | |||
| 30 | struct syscall { | ||
| 31 | int id; | ||
| 32 | const char *name; | ||
| 33 | }; | ||
| 34 | |||
| 35 | static int syscallcmpname(const void *vkey, const void *ventry) | ||
| 36 | { | ||
| 37 | const char *key = vkey; | ||
| 38 | const struct syscall *entry = ventry; | ||
| 39 | |||
| 40 | return strcmp(key, entry->name); | ||
| 41 | } | ||
| 42 | |||
| 43 | static int syscallcmp(const void *va, const void *vb) | ||
| 44 | { | ||
| 45 | const struct syscall *a = va, *b = vb; | ||
| 46 | |||
| 47 | return strcmp(a->name, b->name); | ||
| 48 | } | ||
| 49 | |||
| 50 | static int syscalltbl__init_native(struct syscalltbl *tbl) | ||
| 51 | { | ||
| 52 | int nr_entries = 0, i, j; | ||
| 53 | struct syscall *entries; | ||
| 54 | |||
| 55 | for (i = 0; i <= syscalltbl_native_max_id; ++i) | ||
| 56 | if (syscalltbl_native[i]) | ||
| 57 | ++nr_entries; | ||
| 58 | |||
| 59 | entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries); | ||
| 60 | if (tbl->syscalls.entries == NULL) | ||
| 61 | return -1; | ||
| 62 | |||
| 63 | for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) { | ||
| 64 | if (syscalltbl_native[i]) { | ||
| 65 | entries[j].name = syscalltbl_native[i]; | ||
| 66 | entries[j].id = i; | ||
| 67 | ++j; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp); | ||
| 72 | tbl->syscalls.nr_entries = nr_entries; | ||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | struct syscalltbl *syscalltbl__new(void) | ||
| 77 | { | ||
| 78 | struct syscalltbl *tbl = malloc(sizeof(*tbl)); | ||
| 79 | if (tbl) { | ||
| 80 | if (syscalltbl__init_native(tbl)) { | ||
| 81 | free(tbl); | ||
| 82 | return NULL; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | return tbl; | ||
| 86 | } | ||
| 87 | |||
| 88 | void syscalltbl__delete(struct syscalltbl *tbl) | ||
| 89 | { | ||
| 90 | zfree(&tbl->syscalls.entries); | ||
| 91 | free(tbl); | ||
| 92 | } | ||
| 93 | |||
| 94 | const char *syscalltbl__name(const struct syscalltbl *tbl __maybe_unused, int id) | ||
| 95 | { | ||
| 96 | return id <= syscalltbl_native_max_id ? syscalltbl_native[id]: NULL; | ||
| 97 | } | ||
| 98 | |||
| 99 | int syscalltbl__id(struct syscalltbl *tbl, const char *name) | ||
| 100 | { | ||
| 101 | struct syscall *sc = bsearch(name, tbl->syscalls.entries, | ||
| 102 | tbl->syscalls.nr_entries, sizeof(*sc), | ||
| 103 | syscallcmpname); | ||
| 104 | |||
| 105 | return sc ? sc->id : -1; | ||
| 106 | } | ||
| 107 | |||
| 108 | #else /* HAVE_SYSCALL_TABLE */ | ||
| 109 | |||
| 110 | #include <libaudit.h> | ||
| 111 | |||
| 112 | struct syscalltbl *syscalltbl__new(void) | ||
| 113 | { | ||
| 114 | struct syscalltbl *tbl = malloc(sizeof(*tbl)); | ||
| 115 | if (tbl) | ||
| 116 | tbl->audit_machine = audit_detect_machine(); | ||
| 117 | return tbl; | ||
| 118 | } | ||
| 119 | |||
| 120 | void syscalltbl__delete(struct syscalltbl *tbl) | ||
| 121 | { | ||
| 122 | free(tbl); | ||
| 123 | } | ||
| 124 | |||
| 125 | const char *syscalltbl__name(const struct syscalltbl *tbl, int id) | ||
| 126 | { | ||
| 127 | return audit_syscall_to_name(id, tbl->audit_machine); | ||
| 128 | } | ||
| 129 | |||
| 130 | int syscalltbl__id(struct syscalltbl *tbl, const char *name) | ||
| 131 | { | ||
| 132 | return audit_name_to_syscall(name, tbl->audit_machine); | ||
| 133 | } | ||
| 134 | #endif /* HAVE_SYSCALL_TABLE */ | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef __PERF_SYSCALLTBL_H | ||
| 2 | #define __PERF_SYSCALLTBL_H | ||
| 3 | |||
| 4 | struct syscalltbl { | ||
| 5 | union { | ||
| 6 | int audit_machine; | ||
| 7 | struct { | ||
| 8 | int nr_entries; | ||
| 9 | void *entries; | ||
| 10 | } syscalls; | ||
| 11 | }; | ||
| 12 | }; | ||
| 13 | |||
| 14 | struct syscalltbl *syscalltbl__new(void); | ||
| 15 | void syscalltbl__delete(struct syscalltbl *tbl); | ||
| 16 | |||
| 17 | const char *syscalltbl__name(const struct syscalltbl *tbl, int id); | ||
| 18 | int syscalltbl__id(struct syscalltbl *tbl, const char *name); | ||
| 19 | |||
| 20 | #endif /* __PERF_SYSCALLTBL_H */ | ||
| @@ -22,44 +22,9 @@ · 21 unmodified lines | |||
| 22 | #include "debug.h" | 22 | #include "debug.h" |
| 23 | #include "symbol.h" | 23 | #include "symbol.h" |
| 24 | #include "comm.h" | 24 | #include "comm.h" |
| 25 | #include "call-path.h" | ||
| 25 | #include "thread-stack.h" | 26 | #include "thread-stack.h" |
| 26 | 27 | ||
| 27 | #define CALL_PATH_BLOCK_SHIFT 8 | ||
| 28 | #define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT) | ||
| 29 | #define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1) | ||
| 30 | |||
| 31 | struct call_path_block { | ||
| 32 | struct call_path cp[CALL_PATH_BLOCK_SIZE]; | ||
| 33 | struct list_head node; | ||
| 34 | }; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * struct call_path_root - root of all call paths. | ||
| 38 | * @call_path: root call path | ||
| 39 | * @blocks: list of blocks to store call paths | ||
| 40 | * @next: next free space | ||
| 41 | * @sz: number of spaces | ||
| 42 | */ | ||
| 43 | struct call_path_root { | ||
| 44 | struct call_path call_path; | ||
| 45 | struct list_head blocks; | ||
| 46 | size_t next; | ||
| 47 | size_t sz; | ||
| 48 | }; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * struct call_return_processor - provides a call-back to consume call-return | ||
| 52 | * information. | ||
| 53 | * @cpr: call path root | ||
| 54 | * @process: call-back that accepts call/return information | ||
| 55 | * @data: anonymous data for call-back | ||
| 56 | */ | ||
| 57 | struct call_return_processor { | ||
| 58 | struct call_path_root *cpr; | ||
| 59 | int (*process)(struct call_return *cr, void *data); | ||
| 60 | void *data; | ||
| 61 | }; | ||
| 62 | |||
| 63 | #define STACK_GROWTH 2048 | 28 | #define STACK_GROWTH 2048 |
| 64 | 29 | ||
| 65 | /** | 30 | /** |
| @@ -335,108 +300,6 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, · 269 unmodified lines | |||
| 335 | chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; | 300 | chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; |
| 336 | } | 301 | } |
| 337 | 302 | ||
| 338 | static void call_path__init(struct call_path *cp, struct call_path *parent, | ||
| 339 | struct symbol *sym, u64 ip, bool in_kernel) | ||
| 340 | { | ||
| 341 | cp->parent = parent; | ||
| 342 | cp->sym = sym; | ||
| 343 | cp->ip = sym ? 0 : ip; | ||
| 344 | cp->db_id = 0; | ||
| 345 | cp->in_kernel = in_kernel; | ||
| 346 | RB_CLEAR_NODE(&cp->rb_node); | ||
| 347 | cp->children = RB_ROOT; | ||
| 348 | } | ||
| 349 | |||
| 350 | static struct call_path_root *call_path_root__new(void) | ||
| 351 | { | ||
| 352 | struct call_path_root *cpr; | ||
| 353 | |||
| 354 | cpr = zalloc(sizeof(struct call_path_root)); | ||
| 355 | if (!cpr) | ||
| 356 | return NULL; | ||
| 357 | call_path__init(&cpr->call_path, NULL, NULL, 0, false); | ||
| 358 | INIT_LIST_HEAD(&cpr->blocks); | ||
| 359 | return cpr; | ||
| 360 | } | ||
| 361 | |||
| 362 | static void call_path_root__free(struct call_path_root *cpr) | ||
| 363 | { | ||
| 364 | struct call_path_block *pos, *n; | ||
| 365 | |||
| 366 | list_for_each_entry_safe(pos, n, &cpr->blocks, node) { | ||
| 367 | list_del(&pos->node); | ||
| 368 | free(pos); | ||
| 369 | } | ||
| 370 | free(cpr); | ||
| 371 | } | ||
| 372 | |||
| 373 | static struct call_path *call_path__new(struct call_path_root *cpr, | ||
| 374 | struct call_path *parent, | ||
| 375 | struct symbol *sym, u64 ip, | ||
| 376 | bool in_kernel) | ||
| 377 | { | ||
| 378 | struct call_path_block *cpb; | ||
| 379 | struct call_path *cp; | ||
| 380 | size_t n; | ||
| 381 | |||
| 382 | if (cpr->next < cpr->sz) { | ||
| 383 | cpb = list_last_entry(&cpr->blocks, struct call_path_block, | ||
| 384 | node); | ||
| 385 | } else { | ||
| 386 | cpb = zalloc(sizeof(struct call_path_block)); | ||
| 387 | if (!cpb) | ||
| 388 | return NULL; | ||
| 389 | list_add_tail(&cpb->node, &cpr->blocks); | ||
| 390 | cpr->sz += CALL_PATH_BLOCK_SIZE; | ||
| 391 | } | ||
| 392 | |||
| 393 | n = cpr->next++ & CALL_PATH_BLOCK_MASK; | ||
| 394 | cp = &cpb->cp[n]; | ||
| 395 | |||
| 396 | call_path__init(cp, parent, sym, ip, in_kernel); | ||
| 397 | |||
| 398 | return cp; | ||
| 399 | } | ||
| 400 | |||
| 401 | static struct call_path *call_path__findnew(struct call_path_root *cpr, | ||
| 402 | struct call_path *parent, | ||
| 403 | struct symbol *sym, u64 ip, u64 ks) | ||
| 404 | { | ||
| 405 | struct rb_node **p; | ||
| 406 | struct rb_node *node_parent = NULL; | ||
| 407 | struct call_path *cp; | ||
| 408 | bool in_kernel = ip >= ks; | ||
| 409 | |||
| 410 | if (sym) | ||
| 411 | ip = 0; | ||
| 412 | |||
| 413 | if (!parent) | ||
| 414 | return call_path__new(cpr, parent, sym, ip, in_kernel); | ||
| 415 | |||
| 416 | p = &parent->children.rb_node; | ||
| 417 | while (*p != NULL) { | ||
| 418 | node_parent = *p; | ||
| 419 | cp = rb_entry(node_parent, struct call_path, rb_node); | ||
| 420 | |||
| 421 | if (cp->sym == sym && cp->ip == ip) | ||
| 422 | return cp; | ||
| 423 | |||
| 424 | if (sym < cp->sym || (sym == cp->sym && ip < cp->ip)) | ||
| 425 | p = &(*p)->rb_left; | ||
| 426 | else | ||
| 427 | p = &(*p)->rb_right; | ||
| 428 | } | ||
| 429 | |||
| 430 | cp = call_path__new(cpr, parent, sym, ip, in_kernel); | ||
| 431 | if (!cp) | ||
| 432 | return NULL; | ||
| 433 | |||
| 434 | rb_link_node(&cp->rb_node, node_parent, p); | ||
| 435 | rb_insert_color(&cp->rb_node, &parent->children); | ||
| 436 | |||
| 437 | return cp; | ||
| 438 | } | ||
| 439 | |||
| 440 | struct call_return_processor * | 303 | struct call_return_processor * |
| 441 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), | 304 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), |
| 442 | void *data) | 305 | void *data) |
| @@ -19,17 +19,16 @@ · 18 unmodified lines | |||
| 19 | #include <sys/types.h> | 19 | #include <sys/types.h> |
| 20 | 20 | ||
| 21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
| 22 | #include <linux/rbtree.h> | ||
| 23 | 22 | ||
| 24 | struct thread; | 23 | struct thread; |
| 25 | struct comm; | 24 | struct comm; |
| 26 | struct ip_callchain; | 25 | struct ip_callchain; |
| 27 | struct symbol; | 26 | struct symbol; |
| 28 | struct dso; | 27 | struct dso; |
| 29 | struct call_return_processor; | ||
| 30 | struct comm; | 28 | struct comm; |
| 31 | struct perf_sample; | 29 | struct perf_sample; |
| 32 | struct addr_location; | 30 | struct addr_location; |
| 31 | struct call_path; | ||
| 33 | 32 | ||
| 34 | /* | 33 | /* |
| 35 | * Call/Return flags. | 34 | * Call/Return flags. |
| @@ -69,26 +68,16 @@ struct call_return { · 33 unmodified lines | |||
| 69 | }; | 68 | }; |
| 70 | 69 | ||
| 71 | /** | 70 | /** |
| 72 | * struct call_path - node in list of calls leading to a function call. | 71 | * struct call_return_processor - provides a call-back to consume call-return |
| 73 | * @parent: call path to the parent function call | 72 | * information. |
| 74 | * @sym: symbol of function called | 73 | * @cpr: call path root |
| 75 | * @ip: only if sym is null, the ip of the function | 74 | * @process: call-back that accepts call/return information |
| 76 | * @db_id: id used for db-export | 75 | * @data: anonymous data for call-back |
| 77 | * @in_kernel: whether function is a in the kernel | ||
| 78 | * @rb_node: node in parent's tree of called functions | ||
| 79 | * @children: tree of call paths of functions called | ||
| 80 | * | ||
| 81 | * In combination with the call_return structure, the call_path structure | ||
| 82 | * defines a context-sensitve call-graph. | ||
| 83 | */ | 76 | */ |
| 84 | struct call_path { | 77 | struct call_return_processor { |
| 85 | struct call_path *parent; | 78 | struct call_path_root *cpr; |
| 86 | struct symbol *sym; | 79 | int (*process)(struct call_return *cr, void *data); |
| 87 | u64 ip; | 80 | void *data; |
| 88 | u64 db_id; | ||
| 89 | bool in_kernel; | ||
| 90 | struct rb_node rb_node; | ||
| 91 | struct rb_root children; | ||
| 92 | }; | 81 | }; |
| 93 | 82 | ||
| 94 | int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, | 83 | int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, |
| @@ -10,6 +10,8 @@ · 9 unmodified lines | |||
| 10 | #include "comm.h" | 10 | #include "comm.h" |
| 11 | #include "unwind.h" | 11 | #include "unwind.h" |
| 12 | 12 | ||
| 13 | #include <api/fs/fs.h> | ||
| 14 | |||
| 13 | int thread__init_map_groups(struct thread *thread, struct machine *machine) | 15 | int thread__init_map_groups(struct thread *thread, struct machine *machine) |
| 14 | { | 16 | { |
| 15 | struct thread *leader; | 17 | struct thread *leader; |
| @@ -153,6 +155,23 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, · 137 unmodified lines | |||
| 153 | return 0; | 155 | return 0; |
| 154 | } | 156 | } |
| 155 | 157 | ||
| 158 | int thread__set_comm_from_proc(struct thread *thread) | ||
| 159 | { | ||
| 160 | char path[64]; | ||
| 161 | char *comm = NULL; | ||
| 162 | size_t sz; | ||
| 163 | int err = -1; | ||
| 164 | |||
| 165 | if (!(snprintf(path, sizeof(path), "%d/task/%d/comm", | ||
| 166 | thread->pid_, thread->tid) >= (int)sizeof(path)) && | ||
| 167 | procfs__read_str(path, &comm, &sz) == 0) { | ||
| 168 | comm[sz - 1] = '\0'; | ||
| 169 | err = thread__set_comm(thread, comm, 0); | ||
| 170 | } | ||
| 171 | |||
| 172 | return err; | ||
| 173 | } | ||
| 174 | |||
| 156 | const char *thread__comm_str(const struct thread *thread) | 175 | const char *thread__comm_str(const struct thread *thread) |
| 157 | { | 176 | { |
| 158 | const struct comm *comm = thread__comm(thread); | 177 | const struct comm *comm = thread__comm(thread); |
| @@ -233,7 +252,7 @@ void thread__find_cpumode_addr_location(struct thread *thread, · 74 unmodified lines | |||
| 233 | struct addr_location *al) | 252 | struct addr_location *al) |
| 234 | { | 253 | { |
| 235 | size_t i; | 254 | size_t i; |
| 236 | const u8 const cpumodes[] = { | 255 | const u8 cpumodes[] = { |
| 237 | PERF_RECORD_MISC_USER, | 256 | PERF_RECORD_MISC_USER, |
| 238 | PERF_RECORD_MISC_KERNEL, | 257 | PERF_RECORD_MISC_KERNEL, |
| 239 | PERF_RECORD_MISC_GUEST_USER, | 258 | PERF_RECORD_MISC_GUEST_USER, |
| @@ -9,6 +9,9 @@ · 8 unmodified lines | |||
| 9 | #include "symbol.h" | 9 | #include "symbol.h" |
| 10 | #include <strlist.h> | 10 | #include <strlist.h> |
| 11 | #include <intlist.h> | 11 | #include <intlist.h> |
| 12 | #ifdef HAVE_LIBUNWIND_SUPPORT | ||
| 13 | #include <libunwind.h> | ||
| 14 | #endif | ||
| 12 | 15 | ||
| 13 | struct thread_stack; | 16 | struct thread_stack; |
| 14 | 17 | ||
| @@ -32,6 +35,9 @@ struct thread { · 17 unmodified lines | |||
| 32 | 35 | ||
| 33 | void *priv; | 36 | void *priv; |
| 34 | struct thread_stack *ts; | 37 | struct thread_stack *ts; |
| 38 | #ifdef HAVE_LIBUNWIND_SUPPORT | ||
| 39 | unw_addr_space_t addr_space; | ||
| 40 | #endif | ||
| 35 | }; | 41 | }; |
| 36 | 42 | ||
| 37 | struct machine; | 43 | struct machine; |
| @@ -65,6 +71,8 @@ static inline int thread__set_comm(struct thread *thread, const char *comm, · 27 unmodified lines | |||
| 65 | return __thread__set_comm(thread, comm, timestamp, false); | 71 | return __thread__set_comm(thread, comm, timestamp, false); |
| 66 | } | 72 | } |
| 67 | 73 | ||
| 74 | int thread__set_comm_from_proc(struct thread *thread); | ||
| 75 | |||
| 68 | int thread__comm_len(struct thread *thread); | 76 | int thread__comm_len(struct thread *thread); |
| 69 | struct comm *thread__comm(const struct thread *thread); | 77 | struct comm *thread__comm(const struct thread *thread); |
| 70 | struct comm *thread__exec_comm(const struct thread *thread); | 78 | struct comm *thread__exec_comm(const struct thread *thread); |
| @@ -260,7 +260,7 @@ struct thread_map *thread_map__new_dummy(void) · 259 unmodified lines | |||
| 260 | return threads; | 260 | return threads; |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) | 263 | struct thread_map *thread_map__new_by_tid_str(const char *tid_str) |
| 264 | { | 264 | { |
| 265 | struct thread_map *threads = NULL, *nt; | 265 | struct thread_map *threads = NULL, *nt; |
| 266 | int ntasks = 0; | 266 | int ntasks = 0; |
| @@ -436,3 +436,15 @@ struct thread_map *thread_map__new_event(struct thread_map_event *event) · 169 unmodified lines | |||
| 436 | 436 | ||
| 437 | return threads; | 437 | return threads; |
| 438 | } | 438 | } |
| 439 | |||
| 440 | bool thread_map__has(struct thread_map *threads, pid_t pid) | ||
| 441 | { | ||
| 442 | int i; | ||
| 443 | |||
| 444 | for (i = 0; i < threads->nr; ++i) { | ||
| 445 | if (threads->map[i].pid == pid) | ||
| 446 | return true; | ||
| 447 | } | ||
| 448 | |||
| 449 | return false; | ||
| 450 | } | ||
| @@ -31,6 +31,8 @@ void thread_map__put(struct thread_map *map); · 30 unmodified lines | |||
| 31 | struct thread_map *thread_map__new_str(const char *pid, | 31 | struct thread_map *thread_map__new_str(const char *pid, |
| 32 | const char *tid, uid_t uid); | 32 | const char *tid, uid_t uid); |
| 33 | 33 | ||
| 34 | struct thread_map *thread_map__new_by_tid_str(const char *tid_str); | ||
| 35 | |||
| 34 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 36 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); |
| 35 | 37 | ||
| 36 | static inline int thread_map__nr(struct thread_map *threads) | 38 | static inline int thread_map__nr(struct thread_map *threads) |
| @@ -55,4 +57,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread) · 18 unmodified lines | |||
| 55 | } | 57 | } |
| 56 | 58 | ||
| 57 | void thread_map__read_comms(struct thread_map *threads); | 59 | void thread_map__read_comms(struct thread_map *threads); |
| 60 | bool thread_map__has(struct thread_map *threads, pid_t pid); | ||
| 58 | #endif /* __PERF_THREAD_MAP_H */ | 61 | #endif /* __PERF_THREAD_MAP_H */ |
| @@ -57,6 +57,7 @@ struct perf_tool { · 56 unmodified lines | |||
| 57 | id_index, | 57 | id_index, |
| 58 | auxtrace_info, | 58 | auxtrace_info, |
| 59 | auxtrace_error, | 59 | auxtrace_error, |
| 60 | time_conv, | ||
| 60 | thread_map, | 61 | thread_map, |
| 61 | cpu_map, | 62 | cpu_map, |
| 62 | stat_config, | 63 | stat_config, |
| @@ -0,0 +1,94 @@ | |||
| 1 | #ifndef __TRIGGER_H_ | ||
| 2 | #define __TRIGGER_H_ 1 | ||
| 3 | |||
| 4 | #include "util/debug.h" | ||
| 5 | #include "asm/bug.h" | ||
| 6 | |||
| 7 | /* | ||
| 8 | * Use trigger to model operations which need to be executed when | ||
| 9 | * an event (a signal, for example) is observed. | ||
| 10 | * | ||
| 11 | * States and transits: | ||
| 12 | * | ||
| 13 | * | ||
| 14 | * OFF--(on)--> READY --(hit)--> HIT | ||
| 15 | * ^ | | ||
| 16 | * | (ready) | ||
| 17 | * | | | ||
| 18 | * \_____________/ | ||
| 19 | * | ||
| 20 | * is_hit and is_ready are two key functions to query the state of | ||
| 21 | * a trigger. is_hit means the event already happen; is_ready means the | ||
| 22 | * trigger is waiting for the event. | ||
| 23 | */ | ||
| 24 | |||
| 25 | struct trigger { | ||
| 26 | volatile enum { | ||
| 27 | TRIGGER_ERROR = -2, | ||
| 28 | TRIGGER_OFF = -1, | ||
| 29 | TRIGGER_READY = 0, | ||
| 30 | TRIGGER_HIT = 1, | ||
| 31 | } state; | ||
| 32 | const char *name; | ||
| 33 | }; | ||
| 34 | |||
| 35 | #define TRIGGER_WARN_ONCE(t, exp) \ | ||
| 36 | WARN_ONCE(t->state != exp, "trigger '%s' state transist error: %d in %s()\n", \ | ||
| 37 | t->name, t->state, __func__) | ||
| 38 | |||
| 39 | static inline bool trigger_is_available(struct trigger *t) | ||
| 40 | { | ||
| 41 | return t->state >= 0; | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline bool trigger_is_error(struct trigger *t) | ||
| 45 | { | ||
| 46 | return t->state <= TRIGGER_ERROR; | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline void trigger_on(struct trigger *t) | ||
| 50 | { | ||
| 51 | TRIGGER_WARN_ONCE(t, TRIGGER_OFF); | ||
| 52 | t->state = TRIGGER_READY; | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline void trigger_ready(struct trigger *t) | ||
| 56 | { | ||
| 57 | if (!trigger_is_available(t)) | ||
| 58 | return; | ||
| 59 | t->state = TRIGGER_READY; | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline void trigger_hit(struct trigger *t) | ||
| 63 | { | ||
| 64 | if (!trigger_is_available(t)) | ||
| 65 | return; | ||
| 66 | TRIGGER_WARN_ONCE(t, TRIGGER_READY); | ||
| 67 | t->state = TRIGGER_HIT; | ||
| 68 | } | ||
| 69 | |||
| 70 | static inline void trigger_off(struct trigger *t) | ||
| 71 | { | ||
| 72 | if (!trigger_is_available(t)) | ||
| 73 | return; | ||
| 74 | t->state = TRIGGER_OFF; | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline void trigger_error(struct trigger *t) | ||
| 78 | { | ||
| 79 | t->state = TRIGGER_ERROR; | ||
| 80 | } | ||
| 81 | |||
| 82 | static inline bool trigger_is_ready(struct trigger *t) | ||
| 83 | { | ||
| 84 | return t->state == TRIGGER_READY; | ||
| 85 | } | ||
| 86 | |||
| 87 | static inline bool trigger_is_hit(struct trigger *t) | ||
| 88 | { | ||
| 89 | return t->state == TRIGGER_HIT; | ||
| 90 | } | ||
| 91 | |||
| 92 | #define DEFINE_TRIGGER(n) \ | ||
| 93 | struct trigger n = {.state = TRIGGER_OFF, .name = #n} | ||
| 94 | #endif | ||
| @@ -3,10 +3,29 @@ · 2 unmodified lines | |||
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | 5 | ||
| 6 | #include "../arch/x86/util/tsc.h" | 6 | #include "event.h" |
| 7 | |||
| 8 | struct perf_tsc_conversion { | ||
| 9 | u16 time_shift; | ||
| 10 | u32 time_mult; | ||
| 11 | u64 time_zero; | ||
| 12 | }; | ||
| 13 | struct perf_event_mmap_page; | ||
| 14 | |||
| 15 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | ||
| 16 | struct perf_tsc_conversion *tc); | ||
| 7 | 17 | ||
| 8 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); | 18 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); |
| 9 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); | 19 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); |
| 10 | u64 rdtsc(void); | 20 | u64 rdtsc(void); |
| 11 | 21 | ||
| 22 | struct perf_event_mmap_page; | ||
| 23 | struct perf_tool; | ||
| 24 | struct machine; | ||
| 25 | |||
| 26 | int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, | ||
| 27 | struct perf_tool *tool, | ||
| 28 | perf_event__handler_t process, | ||
| 29 | struct machine *machine); | ||
| 30 | |||
| 12 | #endif | 31 | #endif |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | |||
| 32 | #include "symbol.h" | 32 | #include "symbol.h" |
| 33 | #include "util.h" | 33 | #include "util.h" |
| 34 | #include "debug.h" | 34 | #include "debug.h" |
| 35 | #include "asm/bug.h" | ||
| 35 | 36 | ||
| 36 | extern int | 37 | extern int |
| 37 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | 38 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, |
| @@ -580,43 +581,33 @@ static unw_accessors_t accessors = { · 542 unmodified lines | |||
| 580 | 581 | ||
| 581 | int unwind__prepare_access(struct thread *thread) | 582 | int unwind__prepare_access(struct thread *thread) |
| 582 | { | 583 | { |
| 583 | unw_addr_space_t addr_space; | ||
| 584 | |||
| 585 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 584 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
| 586 | return 0; | 585 | return 0; |
| 587 | 586 | ||
| 588 | addr_space = unw_create_addr_space(&accessors, 0); | 587 | thread->addr_space = unw_create_addr_space(&accessors, 0); |
| 589 | if (!addr_space) { | 588 | if (!thread->addr_space) { |
| 590 | pr_err("unwind: Can't create unwind address space.\n"); | 589 | pr_err("unwind: Can't create unwind address space.\n"); |
| 591 | return -ENOMEM; | 590 | return -ENOMEM; |
| 592 | } | 591 | } |
| 593 | 592 | ||
| 594 | unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); | 593 | unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL); |
| 595 | thread__set_priv(thread, addr_space); | ||
| 596 | |||
| 597 | return 0; | 594 | return 0; |
| 598 | } | 595 | } |
| 599 | 596 | ||
| 600 | void unwind__flush_access(struct thread *thread) | 597 | void unwind__flush_access(struct thread *thread) |
| 601 | { | 598 | { |
| 602 | unw_addr_space_t addr_space; | ||
| 603 | |||
| 604 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 599 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
| 605 | return; | 600 | return; |
| 606 | 601 | ||
| 607 | addr_space = thread__priv(thread); | 602 | unw_flush_cache(thread->addr_space, 0, 0); |
| 608 | unw_flush_cache(addr_space, 0, 0); | ||
| 609 | } | 603 | } |
| 610 | 604 | ||
| 611 | void unwind__finish_access(struct thread *thread) | 605 | void unwind__finish_access(struct thread *thread) |
| 612 | { | 606 | { |
| 613 | unw_addr_space_t addr_space; | ||
| 614 | |||
| 615 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 607 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
| 616 | return; | 608 | return; |
| 617 | 609 | ||
| 618 | addr_space = thread__priv(thread); | 610 | unw_destroy_addr_space(thread->addr_space); |
| 619 | unw_destroy_addr_space(addr_space); | ||
| 620 | } | 611 | } |
| 621 | 612 | ||
| 622 | static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, | 613 | static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, |
| @@ -639,7 +630,9 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, · 16 unmodified lines | |||
| 639 | * unwind itself. | 630 | * unwind itself. |
| 640 | */ | 631 | */ |
| 641 | if (max_stack - 1 > 0) { | 632 | if (max_stack - 1 > 0) { |
| 642 | addr_space = thread__priv(ui->thread); | 633 | WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); |
| 634 | addr_space = ui->thread->addr_space; | ||
| 635 | |||
| 643 | if (addr_space == NULL) | 636 | if (addr_space == NULL) |
| 644 | return -1; | 637 | return -1; |
| 645 | 638 | ||
| @@ -33,6 +33,8 @@ struct callchain_param callchain_param = { · 32 unmodified lines | |||
| 33 | unsigned int page_size; | 33 | unsigned int page_size; |
| 34 | int cacheline_size; | 34 | int cacheline_size; |
| 35 | 35 | ||
| 36 | unsigned int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; | ||
| 37 | |||
| 36 | bool test_attr__enabled; | 38 | bool test_attr__enabled; |
| 37 | 39 | ||
| 38 | bool perf_host = true; | 40 | bool perf_host = true; |
| @@ -117,6 +119,40 @@ int rm_rf(char *path) · 78 unmodified lines | |||
| 117 | return rmdir(path); | 119 | return rmdir(path); |
| 118 | } | 120 | } |
| 119 | 121 | ||
| 122 | /* A filter which removes dot files */ | ||
| 123 | bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d) | ||
| 124 | { | ||
| 125 | return d->d_name[0] != '.'; | ||
| 126 | } | ||
| 127 | |||
| 128 | /* lsdir reads a directory and store it in strlist */ | ||
| 129 | struct strlist *lsdir(const char *name, | ||
| 130 | bool (*filter)(const char *, struct dirent *)) | ||
| 131 | { | ||
| 132 | struct strlist *list = NULL; | ||
| 133 | DIR *dir; | ||
| 134 | struct dirent *d; | ||
| 135 | |||
| 136 | dir = opendir(name); | ||
| 137 | if (!dir) | ||
| 138 | return NULL; | ||
| 139 | |||
| 140 | list = strlist__new(NULL, NULL); | ||
| 141 | if (!list) { | ||
| 142 | errno = ENOMEM; | ||
| 143 | goto out; | ||
| 144 | } | ||
| 145 | |||
| 146 | while ((d = readdir(dir)) != NULL) { | ||
| 147 | if (!filter || filter(name, d)) | ||
| 148 | strlist__add(list, d->d_name); | ||
| 149 | } | ||
| 150 | |||
| 151 | out: | ||
| 152 | closedir(dir); | ||
| 153 | return list; | ||
| 154 | } | ||
| 155 | |||
| 120 | static int slow_copyfile(const char *from, const char *to) | 156 | static int slow_copyfile(const char *from, const char *to) |
| 121 | { | 157 | { |
| 122 | int err = -1; | 158 | int err = -1; |
| @@ -471,7 +507,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) · 348 unmodified lines | |||
| 471 | "needed for --call-graph fp\n"); | 507 | "needed for --call-graph fp\n"); |
| 472 | break; | 508 | break; |
| 473 | 509 | ||
| 474 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
| 475 | /* Dwarf style */ | 510 | /* Dwarf style */ |
| 476 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { | 511 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { |
| 477 | const unsigned long default_stack_dump_size = 8192; | 512 | const unsigned long default_stack_dump_size = 8192; |
| @@ -487,7 +522,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) · 9 unmodified lines | |||
| 487 | ret = get_stack_size(tok, &size); | 522 | ret = get_stack_size(tok, &size); |
| 488 | param->dump_size = size; | 523 | param->dump_size = size; |
| 489 | } | 524 | } |
| 490 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
| 491 | } else if (!strncmp(name, "lbr", sizeof("lbr"))) { | 525 | } else if (!strncmp(name, "lbr", sizeof("lbr"))) { |
| 492 | if (!strtok_r(NULL, ",", &saveptr)) { | 526 | if (!strtok_r(NULL, ",", &saveptr)) { |
| 493 | param->record_mode = CALLCHAIN_LBR; | 527 | param->record_mode = CALLCHAIN_LBR; |
| @@ -79,6 +79,7 @@ · 78 unmodified lines | |||
| 79 | #include <termios.h> | 79 | #include <termios.h> |
| 80 | #include <linux/bitops.h> | 80 | #include <linux/bitops.h> |
| 81 | #include <termios.h> | 81 | #include <termios.h> |
| 82 | #include "strlist.h" | ||
| 82 | 83 | ||
| 83 | extern const char *graph_line; | 84 | extern const char *graph_line; |
| 84 | extern const char *graph_dotted_line; | 85 | extern const char *graph_dotted_line; |
| @@ -159,12 +160,6 @@ static inline char *gitstrchrnul(const char *s, int c) · 74 unmodified lines | |||
| 159 | } | 160 | } |
| 160 | #endif | 161 | #endif |
| 161 | 162 | ||
| 162 | /* | ||
| 163 | * Wrappers: | ||
| 164 | */ | ||
| 165 | void *xrealloc(void *ptr, size_t size) __attribute__((weak)); | ||
| 166 | |||
| 167 | |||
| 168 | static inline void *zalloc(size_t size) | 163 | static inline void *zalloc(size_t size) |
| 169 | { | 164 | { |
| 170 | return calloc(1, size); | 165 | return calloc(1, size); |
| @@ -222,6 +217,8 @@ static inline int sane_case(int x, int high) · 51 unmodified lines | |||
| 222 | 217 | ||
| 223 | int mkdir_p(char *path, mode_t mode); | 218 | int mkdir_p(char *path, mode_t mode); |
| 224 | int rm_rf(char *path); | 219 | int rm_rf(char *path); |
| 220 | struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); | ||
| 221 | bool lsdir_no_dot_filter(const char *name, struct dirent *d); | ||
| 225 | int copyfile(const char *from, const char *to); | 222 | int copyfile(const char *from, const char *to); |
| 226 | int copyfile_mode(const char *from, const char *to, mode_t mode); | 223 | int copyfile_mode(const char *from, const char *to, mode_t mode); |
| 227 | int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); | 224 | int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); |
| @@ -254,11 +251,17 @@ int hex2u64(const char *ptr, u64 *val); · 26 unmodified lines | |||
| 254 | char *ltrim(char *s); | 251 | char *ltrim(char *s); |
| 255 | char *rtrim(char *s); | 252 | char *rtrim(char *s); |
| 256 | 253 | ||
| 254 | static inline char *trim(char *s) | ||
| 255 | { | ||
| 256 | return ltrim(rtrim(s)); | ||
| 257 | } | ||
| 258 | |||
| 257 | void dump_stack(void); | 259 | void dump_stack(void); |
| 258 | void sighandler_dump_stack(int sig); | 260 | void sighandler_dump_stack(int sig); |
| 259 | 261 | ||
| 260 | extern unsigned int page_size; | 262 | extern unsigned int page_size; |
| 261 | extern int cacheline_size; | 263 | extern int cacheline_size; |
| 264 | extern unsigned int sysctl_perf_event_max_stack; | ||
| 262 | 265 | ||
| 263 | struct parse_tag { | 266 | struct parse_tag { |
| 264 | char tag; | 267 | char tag; |
| @@ -1,29 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Various trivial helper wrappers around standard functions | ||
| 3 | */ | ||
| 4 | #include "cache.h" | ||
| 5 | |||
| 6 | /* | ||
| 7 | * There's no pack memory to release - but stay close to the Git | ||
| 8 | * version so wrap this away: | ||
| 9 | */ | ||
| 10 | static inline void release_pack_memory(size_t size __maybe_unused, | ||
| 11 | int flag __maybe_unused) | ||
| 12 | { | ||
| 13 | } | ||
| 14 | |||
| 15 | void *xrealloc(void *ptr, size_t size) | ||
| 16 | { | ||
| 17 | void *ret = realloc(ptr, size); | ||
| 18 | if (!ret && !size) | ||
| 19 | ret = realloc(ptr, 1); | ||
| 20 | if (!ret) { | ||
| 21 | release_pack_memory(size, -1); | ||
| 22 | ret = realloc(ptr, size); | ||
| 23 | if (!ret && !size) | ||
| 24 | ret = realloc(ptr, 1); | ||
| 25 | if (!ret) | ||
| 26 | die("Out of memory, realloc failed"); | ||
| 27 | } | ||
| 28 | return ret; | ||
| 29 | } | ||