diff options
40 files changed, 877 insertions, 564 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 731318e5ac1d..bc01e3ebfeb2 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
@@ -187,8 +187,8 @@ config HAVE_MMIOTRACE_SUPPORT | |||
187 | def_bool y | 187 | def_bool y |
188 | 188 | ||
189 | config X86_DECODER_SELFTEST | 189 | config X86_DECODER_SELFTEST |
190 | bool "x86 instruction decoder selftest" | 190 | bool "x86 instruction decoder selftest" |
191 | depends on DEBUG_KERNEL | 191 | depends on DEBUG_KERNEL && KPROBES |
192 | ---help--- | 192 | ---help--- |
193 | Perform x86 instruction decoder selftests at build time. | 193 | Perform x86 instruction decoder selftests at build time. |
194 | This option is useful for checking the sanity of x86 instruction | 194 | This option is useful for checking the sanity of x86 instruction |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index ab1a8a89b984..45506d5dd8df 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1632,6 +1632,7 @@ static void intel_pmu_drain_bts_buffer(struct cpu_hw_events *cpuc) | |||
1632 | 1632 | ||
1633 | data.period = event->hw.last_period; | 1633 | data.period = event->hw.last_period; |
1634 | data.addr = 0; | 1634 | data.addr = 0; |
1635 | data.raw = NULL; | ||
1635 | regs.ip = 0; | 1636 | regs.ip = 0; |
1636 | 1637 | ||
1637 | /* | 1638 | /* |
@@ -1749,6 +1750,7 @@ static int p6_pmu_handle_irq(struct pt_regs *regs) | |||
1749 | u64 val; | 1750 | u64 val; |
1750 | 1751 | ||
1751 | data.addr = 0; | 1752 | data.addr = 0; |
1753 | data.raw = NULL; | ||
1752 | 1754 | ||
1753 | cpuc = &__get_cpu_var(cpu_hw_events); | 1755 | cpuc = &__get_cpu_var(cpu_hw_events); |
1754 | 1756 | ||
@@ -1794,6 +1796,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) | |||
1794 | u64 ack, status; | 1796 | u64 ack, status; |
1795 | 1797 | ||
1796 | data.addr = 0; | 1798 | data.addr = 0; |
1799 | data.raw = NULL; | ||
1797 | 1800 | ||
1798 | cpuc = &__get_cpu_var(cpu_hw_events); | 1801 | cpuc = &__get_cpu_var(cpu_hw_events); |
1799 | 1802 | ||
@@ -1857,6 +1860,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) | |||
1857 | u64 val; | 1860 | u64 val; |
1858 | 1861 | ||
1859 | data.addr = 0; | 1862 | data.addr = 0; |
1863 | data.raw = NULL; | ||
1860 | 1864 | ||
1861 | cpuc = &__get_cpu_var(cpu_hw_events); | 1865 | cpuc = &__get_cpu_var(cpu_hw_events); |
1862 | 1866 | ||
@@ -2062,12 +2066,6 @@ static __init int p6_pmu_init(void) | |||
2062 | 2066 | ||
2063 | x86_pmu = p6_pmu; | 2067 | x86_pmu = p6_pmu; |
2064 | 2068 | ||
2065 | if (!cpu_has_apic) { | ||
2066 | pr_info("no APIC, boot with the \"lapic\" boot parameter to force-enable it.\n"); | ||
2067 | pr_info("no hardware sampling interrupt available.\n"); | ||
2068 | x86_pmu.apic = 0; | ||
2069 | } | ||
2070 | |||
2071 | return 0; | 2069 | return 0; |
2072 | } | 2070 | } |
2073 | 2071 | ||
@@ -2159,6 +2157,16 @@ static __init int amd_pmu_init(void) | |||
2159 | return 0; | 2157 | return 0; |
2160 | } | 2158 | } |
2161 | 2159 | ||
2160 | static void __init pmu_check_apic(void) | ||
2161 | { | ||
2162 | if (cpu_has_apic) | ||
2163 | return; | ||
2164 | |||
2165 | x86_pmu.apic = 0; | ||
2166 | pr_info("no APIC, boot with the \"lapic\" boot parameter to force-enable it.\n"); | ||
2167 | pr_info("no hardware sampling interrupt available.\n"); | ||
2168 | } | ||
2169 | |||
2162 | void __init init_hw_perf_events(void) | 2170 | void __init init_hw_perf_events(void) |
2163 | { | 2171 | { |
2164 | int err; | 2172 | int err; |
@@ -2180,6 +2188,8 @@ void __init init_hw_perf_events(void) | |||
2180 | return; | 2188 | return; |
2181 | } | 2189 | } |
2182 | 2190 | ||
2191 | pmu_check_apic(); | ||
2192 | |||
2183 | pr_cont("%s PMU driver.\n", x86_pmu.name); | 2193 | pr_cont("%s PMU driver.\n", x86_pmu.name); |
2184 | 2194 | ||
2185 | if (x86_pmu.num_events > X86_PMC_MAX_GENERIC) { | 2195 | if (x86_pmu.num_events > X86_PMC_MAX_GENERIC) { |
@@ -2287,7 +2297,7 @@ void callchain_store(struct perf_callchain_entry *entry, u64 ip) | |||
2287 | 2297 | ||
2288 | static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry); | 2298 | static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry); |
2289 | static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry); | 2299 | static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry); |
2290 | static DEFINE_PER_CPU(int, in_nmi_frame); | 2300 | static DEFINE_PER_CPU(int, in_ignored_frame); |
2291 | 2301 | ||
2292 | 2302 | ||
2293 | static void | 2303 | static void |
@@ -2303,8 +2313,9 @@ static void backtrace_warning(void *data, char *msg) | |||
2303 | 2313 | ||
2304 | static int backtrace_stack(void *data, char *name) | 2314 | static int backtrace_stack(void *data, char *name) |
2305 | { | 2315 | { |
2306 | per_cpu(in_nmi_frame, smp_processor_id()) = | 2316 | per_cpu(in_ignored_frame, smp_processor_id()) = |
2307 | x86_is_stack_id(NMI_STACK, name); | 2317 | x86_is_stack_id(NMI_STACK, name) || |
2318 | x86_is_stack_id(DEBUG_STACK, name); | ||
2308 | 2319 | ||
2309 | return 0; | 2320 | return 0; |
2310 | } | 2321 | } |
@@ -2313,7 +2324,7 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) | |||
2313 | { | 2324 | { |
2314 | struct perf_callchain_entry *entry = data; | 2325 | struct perf_callchain_entry *entry = data; |
2315 | 2326 | ||
2316 | if (per_cpu(in_nmi_frame, smp_processor_id())) | 2327 | if (per_cpu(in_ignored_frame, smp_processor_id())) |
2317 | return; | 2328 | return; |
2318 | 2329 | ||
2319 | if (reliable) | 2330 | if (reliable) |
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 8e740934bd1f..b13af53883aa 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
@@ -103,6 +103,35 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
103 | return NULL; | 103 | return NULL; |
104 | } | 104 | } |
105 | 105 | ||
106 | static inline int | ||
107 | in_irq_stack(unsigned long *stack, unsigned long *irq_stack, | ||
108 | unsigned long *irq_stack_end) | ||
109 | { | ||
110 | return (stack >= irq_stack && stack < irq_stack_end); | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * We are returning from the irq stack and go to the previous one. | ||
115 | * If the previous stack is also in the irq stack, then bp in the first | ||
116 | * frame of the irq stack points to the previous, interrupted one. | ||
117 | * Otherwise we have another level of indirection: We first save | ||
118 | * the bp of the previous stack, then we switch the stack to the irq one | ||
119 | * and save a new bp that links to the previous one. | ||
120 | * (See save_args()) | ||
121 | */ | ||
122 | static inline unsigned long | ||
123 | fixup_bp_irq_link(unsigned long bp, unsigned long *stack, | ||
124 | unsigned long *irq_stack, unsigned long *irq_stack_end) | ||
125 | { | ||
126 | #ifdef CONFIG_FRAME_POINTER | ||
127 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
128 | |||
129 | if (!in_irq_stack(stack, irq_stack, irq_stack_end)) | ||
130 | return (unsigned long)frame->next_frame; | ||
131 | #endif | ||
132 | return bp; | ||
133 | } | ||
134 | |||
106 | /* | 135 | /* |
107 | * x86-64 can have up to three kernel stacks: | 136 | * x86-64 can have up to three kernel stacks: |
108 | * process stack | 137 | * process stack |
@@ -175,7 +204,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
175 | irq_stack = irq_stack_end - | 204 | irq_stack = irq_stack_end - |
176 | (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack); | 205 | (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack); |
177 | 206 | ||
178 | if (stack >= irq_stack && stack < irq_stack_end) { | 207 | if (in_irq_stack(stack, irq_stack, irq_stack_end)) { |
179 | if (ops->stack(data, "IRQ") < 0) | 208 | if (ops->stack(data, "IRQ") < 0) |
180 | break; | 209 | break; |
181 | bp = print_context_stack(tinfo, stack, bp, | 210 | bp = print_context_stack(tinfo, stack, bp, |
@@ -186,6 +215,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
186 | * pointer (index -1 to end) in the IRQ stack: | 215 | * pointer (index -1 to end) in the IRQ stack: |
187 | */ | 216 | */ |
188 | stack = (unsigned long *) (irq_stack_end[-1]); | 217 | stack = (unsigned long *) (irq_stack_end[-1]); |
218 | bp = fixup_bp_irq_link(bp, stack, irq_stack, | ||
219 | irq_stack_end); | ||
189 | irq_stack_end = NULL; | 220 | irq_stack_end = NULL; |
190 | ops->stack(data, "EOI"); | 221 | ops->stack(data, "EOI"); |
191 | continue; | 222 | continue; |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 63bca794c8f9..673f693fb451 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -1076,10 +1076,10 @@ ENTRY(\sym) | |||
1076 | TRACE_IRQS_OFF | 1076 | TRACE_IRQS_OFF |
1077 | movq %rsp,%rdi /* pt_regs pointer */ | 1077 | movq %rsp,%rdi /* pt_regs pointer */ |
1078 | xorl %esi,%esi /* no error code */ | 1078 | xorl %esi,%esi /* no error code */ |
1079 | PER_CPU(init_tss, %rbp) | 1079 | PER_CPU(init_tss, %r12) |
1080 | subq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%rbp) | 1080 | subq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12) |
1081 | call \do_sym | 1081 | call \do_sym |
1082 | addq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%rbp) | 1082 | addq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12) |
1083 | jmp paranoid_exit /* %ebx: no swapgs flag */ | 1083 | jmp paranoid_exit /* %ebx: no swapgs flag */ |
1084 | CFI_ENDPROC | 1084 | CFI_ENDPROC |
1085 | END(\sym) | 1085 | END(\sym) |
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index d42f65ac4927..05d5fec64a94 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c | |||
@@ -362,8 +362,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp, | |||
362 | return ret; | 362 | return ret; |
363 | } | 363 | } |
364 | 364 | ||
365 | if (bp->callback) | 365 | ret = arch_store_info(bp); |
366 | ret = arch_store_info(bp); | ||
367 | 366 | ||
368 | if (ret < 0) | 367 | if (ret < 0) |
369 | return ret; | 368 | return ret; |
@@ -519,7 +518,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) | |||
519 | break; | 518 | break; |
520 | } | 519 | } |
521 | 520 | ||
522 | (bp->callback)(bp, args->regs); | 521 | perf_bp_event(bp, args->regs); |
523 | 522 | ||
524 | rcu_read_unlock(); | 523 | rcu_read_unlock(); |
525 | } | 524 | } |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 04d182a7cfdb..7079ddaf0731 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -555,7 +555,9 @@ static int genregs_set(struct task_struct *target, | |||
555 | return ret; | 555 | return ret; |
556 | } | 556 | } |
557 | 557 | ||
558 | static void ptrace_triggered(struct perf_event *bp, void *data) | 558 | static void ptrace_triggered(struct perf_event *bp, int nmi, |
559 | struct perf_sample_data *data, | ||
560 | struct pt_regs *regs) | ||
559 | { | 561 | { |
560 | int i; | 562 | int i; |
561 | struct thread_struct *thread = &(current->thread); | 563 | struct thread_struct *thread = &(current->thread); |
@@ -593,13 +595,13 @@ static unsigned long ptrace_get_dr7(struct perf_event *bp[]) | |||
593 | return dr7; | 595 | return dr7; |
594 | } | 596 | } |
595 | 597 | ||
596 | static struct perf_event * | 598 | static int |
597 | ptrace_modify_breakpoint(struct perf_event *bp, int len, int type, | 599 | ptrace_modify_breakpoint(struct perf_event *bp, int len, int type, |
598 | struct task_struct *tsk, int disabled) | 600 | struct task_struct *tsk, int disabled) |
599 | { | 601 | { |
600 | int err; | 602 | int err; |
601 | int gen_len, gen_type; | 603 | int gen_len, gen_type; |
602 | DEFINE_BREAKPOINT_ATTR(attr); | 604 | struct perf_event_attr attr; |
603 | 605 | ||
604 | /* | 606 | /* |
605 | * We shoud have at least an inactive breakpoint at this | 607 | * We shoud have at least an inactive breakpoint at this |
@@ -607,18 +609,18 @@ ptrace_modify_breakpoint(struct perf_event *bp, int len, int type, | |||
607 | * written the address register first | 609 | * written the address register first |
608 | */ | 610 | */ |
609 | if (!bp) | 611 | if (!bp) |
610 | return ERR_PTR(-EINVAL); | 612 | return -EINVAL; |
611 | 613 | ||
612 | err = arch_bp_generic_fields(len, type, &gen_len, &gen_type); | 614 | err = arch_bp_generic_fields(len, type, &gen_len, &gen_type); |
613 | if (err) | 615 | if (err) |
614 | return ERR_PTR(err); | 616 | return err; |
615 | 617 | ||
616 | attr = bp->attr; | 618 | attr = bp->attr; |
617 | attr.bp_len = gen_len; | 619 | attr.bp_len = gen_len; |
618 | attr.bp_type = gen_type; | 620 | attr.bp_type = gen_type; |
619 | attr.disabled = disabled; | 621 | attr.disabled = disabled; |
620 | 622 | ||
621 | return modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk); | 623 | return modify_user_hw_breakpoint(bp, &attr); |
622 | } | 624 | } |
623 | 625 | ||
624 | /* | 626 | /* |
@@ -656,28 +658,17 @@ restore: | |||
656 | if (!second_pass) | 658 | if (!second_pass) |
657 | continue; | 659 | continue; |
658 | 660 | ||
659 | thread->ptrace_bps[i] = NULL; | 661 | rc = ptrace_modify_breakpoint(bp, len, type, |
660 | bp = ptrace_modify_breakpoint(bp, len, type, | ||
661 | tsk, 1); | 662 | tsk, 1); |
662 | if (IS_ERR(bp)) { | 663 | if (rc) |
663 | rc = PTR_ERR(bp); | ||
664 | thread->ptrace_bps[i] = NULL; | ||
665 | break; | 664 | break; |
666 | } | ||
667 | thread->ptrace_bps[i] = bp; | ||
668 | } | 665 | } |
669 | continue; | 666 | continue; |
670 | } | 667 | } |
671 | 668 | ||
672 | bp = ptrace_modify_breakpoint(bp, len, type, tsk, 0); | 669 | rc = ptrace_modify_breakpoint(bp, len, type, tsk, 0); |
673 | 670 | if (rc) | |
674 | /* Incorrect bp, or we have a bug in bp API */ | ||
675 | if (IS_ERR(bp)) { | ||
676 | rc = PTR_ERR(bp); | ||
677 | thread->ptrace_bps[i] = NULL; | ||
678 | break; | 671 | break; |
679 | } | ||
680 | thread->ptrace_bps[i] = bp; | ||
681 | } | 672 | } |
682 | /* | 673 | /* |
683 | * Make a second pass to free the remaining unused breakpoints | 674 | * Make a second pass to free the remaining unused breakpoints |
@@ -721,9 +712,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, | |||
721 | { | 712 | { |
722 | struct perf_event *bp; | 713 | struct perf_event *bp; |
723 | struct thread_struct *t = &tsk->thread; | 714 | struct thread_struct *t = &tsk->thread; |
724 | DEFINE_BREAKPOINT_ATTR(attr); | 715 | struct perf_event_attr attr; |
725 | 716 | ||
726 | if (!t->ptrace_bps[nr]) { | 717 | if (!t->ptrace_bps[nr]) { |
718 | hw_breakpoint_init(&attr); | ||
727 | /* | 719 | /* |
728 | * Put stub len and type to register (reserve) an inactive but | 720 | * Put stub len and type to register (reserve) an inactive but |
729 | * correct bp | 721 | * correct bp |
@@ -734,26 +726,32 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, | |||
734 | attr.disabled = 1; | 726 | attr.disabled = 1; |
735 | 727 | ||
736 | bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk); | 728 | bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk); |
729 | |||
730 | /* | ||
731 | * CHECKME: the previous code returned -EIO if the addr wasn't | ||
732 | * a valid task virtual addr. The new one will return -EINVAL in | ||
733 | * this case. | ||
734 | * -EINVAL may be what we want for in-kernel breakpoints users, | ||
735 | * but -EIO looks better for ptrace, since we refuse a register | ||
736 | * writing for the user. And anyway this is the previous | ||
737 | * behaviour. | ||
738 | */ | ||
739 | if (IS_ERR(bp)) | ||
740 | return PTR_ERR(bp); | ||
741 | |||
742 | t->ptrace_bps[nr] = bp; | ||
737 | } else { | 743 | } else { |
744 | int err; | ||
745 | |||
738 | bp = t->ptrace_bps[nr]; | 746 | bp = t->ptrace_bps[nr]; |
739 | t->ptrace_bps[nr] = NULL; | ||
740 | 747 | ||
741 | attr = bp->attr; | 748 | attr = bp->attr; |
742 | attr.bp_addr = addr; | 749 | attr.bp_addr = addr; |
743 | bp = modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk); | 750 | err = modify_user_hw_breakpoint(bp, &attr); |
751 | if (err) | ||
752 | return err; | ||
744 | } | 753 | } |
745 | /* | ||
746 | * CHECKME: the previous code returned -EIO if the addr wasn't a | ||
747 | * valid task virtual addr. The new one will return -EINVAL in this | ||
748 | * case. | ||
749 | * -EINVAL may be what we want for in-kernel breakpoints users, but | ||
750 | * -EIO looks better for ptrace, since we refuse a register writing | ||
751 | * for the user. And anyway this is the previous behaviour. | ||
752 | */ | ||
753 | if (IS_ERR(bp)) | ||
754 | return PTR_ERR(bp); | ||
755 | 754 | ||
756 | t->ptrace_bps[nr] = bp; | ||
757 | 755 | ||
758 | return 0; | 756 | return 0; |
759 | } | 757 | } |
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index a2d6472895fb..45b20e486c2f 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk | 5 | inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk |
6 | inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt | 6 | inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt |
7 | quiet_cmd_inat_tables = GEN $@ | 7 | quiet_cmd_inat_tables = GEN $@ |
8 | cmd_inat_tables = $(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ | 8 | cmd_inat_tables = $(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ || rm -f $@ |
9 | 9 | ||
10 | $(obj)/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) | 10 | $(obj)/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) |
11 | $(call cmd,inat_tables) | 11 | $(call cmd,inat_tables) |
@@ -20,7 +20,7 @@ lib-y := delay.o | |||
20 | lib-y += thunk_$(BITS).o | 20 | lib-y += thunk_$(BITS).o |
21 | lib-y += usercopy_$(BITS).o getuser.o putuser.o | 21 | lib-y += usercopy_$(BITS).o getuser.o putuser.o |
22 | lib-y += memcpy_$(BITS).o | 22 | lib-y += memcpy_$(BITS).o |
23 | lib-y += insn.o inat.o | 23 | lib-$(CONFIG_KPROBES) += insn.o inat.o |
24 | 24 | ||
25 | obj-y += msr-reg.o msr-reg-export.o | 25 | obj-y += msr-reg.o msr-reg-export.o |
26 | 26 | ||
diff --git a/arch/x86/tools/test_get_len.c b/arch/x86/tools/test_get_len.c index d8214dc03fa7..bee8d6ac2691 100644 --- a/arch/x86/tools/test_get_len.c +++ b/arch/x86/tools/test_get_len.c | |||
@@ -113,7 +113,7 @@ int main(int argc, char **argv) | |||
113 | char line[BUFSIZE], sym[BUFSIZE] = "<unknown>"; | 113 | char line[BUFSIZE], sym[BUFSIZE] = "<unknown>"; |
114 | unsigned char insn_buf[16]; | 114 | unsigned char insn_buf[16]; |
115 | struct insn insn; | 115 | struct insn insn; |
116 | int insns = 0, c; | 116 | int insns = 0; |
117 | int warnings = 0; | 117 | int warnings = 0; |
118 | 118 | ||
119 | parse_args(argc, argv); | 119 | parse_args(argc, argv); |
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h index a03daed08c59..69f07a9f1277 100644 --- a/include/linux/hw_breakpoint.h +++ b/include/linux/hw_breakpoint.h | |||
@@ -20,19 +20,18 @@ enum { | |||
20 | 20 | ||
21 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 21 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
22 | 22 | ||
23 | /* As it's for in-kernel or ptrace use, we want it to be pinned */ | ||
24 | #define DEFINE_BREAKPOINT_ATTR(name) \ | ||
25 | struct perf_event_attr name = { \ | ||
26 | .type = PERF_TYPE_BREAKPOINT, \ | ||
27 | .size = sizeof(name), \ | ||
28 | .pinned = 1, \ | ||
29 | }; | ||
30 | |||
31 | static inline void hw_breakpoint_init(struct perf_event_attr *attr) | 23 | static inline void hw_breakpoint_init(struct perf_event_attr *attr) |
32 | { | 24 | { |
25 | memset(attr, 0, sizeof(*attr)); | ||
26 | |||
33 | attr->type = PERF_TYPE_BREAKPOINT; | 27 | attr->type = PERF_TYPE_BREAKPOINT; |
34 | attr->size = sizeof(*attr); | 28 | attr->size = sizeof(*attr); |
29 | /* | ||
30 | * As it's for in-kernel or ptrace use, we want it to be pinned | ||
31 | * and to call its callback every hits. | ||
32 | */ | ||
35 | attr->pinned = 1; | 33 | attr->pinned = 1; |
34 | attr->sample_period = 1; | ||
36 | } | 35 | } |
37 | 36 | ||
38 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) | 37 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) |
@@ -52,27 +51,24 @@ static inline int hw_breakpoint_len(struct perf_event *bp) | |||
52 | 51 | ||
53 | extern struct perf_event * | 52 | extern struct perf_event * |
54 | register_user_hw_breakpoint(struct perf_event_attr *attr, | 53 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
55 | perf_callback_t triggered, | 54 | perf_overflow_handler_t triggered, |
56 | struct task_struct *tsk); | 55 | struct task_struct *tsk); |
57 | 56 | ||
58 | /* FIXME: only change from the attr, and don't unregister */ | 57 | /* FIXME: only change from the attr, and don't unregister */ |
59 | extern struct perf_event * | 58 | extern int |
60 | modify_user_hw_breakpoint(struct perf_event *bp, | 59 | modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr); |
61 | struct perf_event_attr *attr, | ||
62 | perf_callback_t triggered, | ||
63 | struct task_struct *tsk); | ||
64 | 60 | ||
65 | /* | 61 | /* |
66 | * Kernel breakpoints are not associated with any particular thread. | 62 | * Kernel breakpoints are not associated with any particular thread. |
67 | */ | 63 | */ |
68 | extern struct perf_event * | 64 | extern struct perf_event * |
69 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, | 65 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
70 | perf_callback_t triggered, | 66 | perf_overflow_handler_t triggered, |
71 | int cpu); | 67 | int cpu); |
72 | 68 | ||
73 | extern struct perf_event ** | 69 | extern struct perf_event ** |
74 | register_wide_hw_breakpoint(struct perf_event_attr *attr, | 70 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
75 | perf_callback_t triggered); | 71 | perf_overflow_handler_t triggered); |
76 | 72 | ||
77 | extern int register_perf_hw_breakpoint(struct perf_event *bp); | 73 | extern int register_perf_hw_breakpoint(struct perf_event *bp); |
78 | extern int __register_perf_hw_breakpoint(struct perf_event *bp); | 74 | extern int __register_perf_hw_breakpoint(struct perf_event *bp); |
@@ -93,20 +89,18 @@ static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) | |||
93 | 89 | ||
94 | static inline struct perf_event * | 90 | static inline struct perf_event * |
95 | register_user_hw_breakpoint(struct perf_event_attr *attr, | 91 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
96 | perf_callback_t triggered, | 92 | perf_overflow_handler_t triggered, |
97 | struct task_struct *tsk) { return NULL; } | 93 | struct task_struct *tsk) { return NULL; } |
98 | static inline struct perf_event * | 94 | static inline int |
99 | modify_user_hw_breakpoint(struct perf_event *bp, | 95 | modify_user_hw_breakpoint(struct perf_event *bp, |
100 | struct perf_event_attr *attr, | 96 | struct perf_event_attr *attr) { return NULL; } |
101 | perf_callback_t triggered, | ||
102 | struct task_struct *tsk) { return NULL; } | ||
103 | static inline struct perf_event * | 97 | static inline struct perf_event * |
104 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, | 98 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
105 | perf_callback_t triggered, | 99 | perf_overflow_handler_t triggered, |
106 | int cpu) { return NULL; } | 100 | int cpu) { return NULL; } |
107 | static inline struct perf_event ** | 101 | static inline struct perf_event ** |
108 | register_wide_hw_breakpoint(struct perf_event_attr *attr, | 102 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
109 | perf_callback_t triggered) { return NULL; } | 103 | perf_overflow_handler_t triggered) { return NULL; } |
110 | static inline int | 104 | static inline int |
111 | register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } | 105 | register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } |
112 | static inline int | 106 | static inline int |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 43adbd7f0010..64a53f74c9a9 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -18,10 +18,6 @@ | |||
18 | #include <linux/ioctl.h> | 18 | #include <linux/ioctl.h> |
19 | #include <asm/byteorder.h> | 19 | #include <asm/byteorder.h> |
20 | 20 | ||
21 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
22 | #include <asm/hw_breakpoint.h> | ||
23 | #endif | ||
24 | |||
25 | /* | 21 | /* |
26 | * User-space ABI bits: | 22 | * User-space ABI bits: |
27 | */ | 23 | */ |
@@ -215,12 +211,12 @@ struct perf_event_attr { | |||
215 | __u32 wakeup_watermark; /* bytes before wakeup */ | 211 | __u32 wakeup_watermark; /* bytes before wakeup */ |
216 | }; | 212 | }; |
217 | 213 | ||
218 | union { | 214 | struct { /* Hardware breakpoint info */ |
219 | struct { /* Hardware breakpoint info */ | 215 | __u64 bp_addr; |
220 | __u64 bp_addr; | 216 | __u32 bp_type; |
221 | __u32 bp_type; | 217 | __u32 bp_len; |
222 | __u32 bp_len; | 218 | __u64 __bp_reserved_1; |
223 | }; | 219 | __u64 __bp_reserved_2; |
224 | }; | 220 | }; |
225 | 221 | ||
226 | __u32 __reserved_2; | 222 | __u32 __reserved_2; |
@@ -451,6 +447,10 @@ enum perf_callchain_context { | |||
451 | # include <asm/perf_event.h> | 447 | # include <asm/perf_event.h> |
452 | #endif | 448 | #endif |
453 | 449 | ||
450 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
451 | #include <asm/hw_breakpoint.h> | ||
452 | #endif | ||
453 | |||
454 | #include <linux/list.h> | 454 | #include <linux/list.h> |
455 | #include <linux/mutex.h> | 455 | #include <linux/mutex.h> |
456 | #include <linux/rculist.h> | 456 | #include <linux/rculist.h> |
@@ -565,10 +565,12 @@ struct perf_pending_entry { | |||
565 | void (*func)(struct perf_pending_entry *); | 565 | void (*func)(struct perf_pending_entry *); |
566 | }; | 566 | }; |
567 | 567 | ||
568 | typedef void (*perf_callback_t)(struct perf_event *, void *); | ||
569 | |||
570 | struct perf_sample_data; | 568 | struct perf_sample_data; |
571 | 569 | ||
570 | typedef void (*perf_overflow_handler_t)(struct perf_event *, int, | ||
571 | struct perf_sample_data *, | ||
572 | struct pt_regs *regs); | ||
573 | |||
572 | /** | 574 | /** |
573 | * struct perf_event - performance event kernel representation: | 575 | * struct perf_event - performance event kernel representation: |
574 | */ | 576 | */ |
@@ -660,18 +662,12 @@ struct perf_event { | |||
660 | struct pid_namespace *ns; | 662 | struct pid_namespace *ns; |
661 | u64 id; | 663 | u64 id; |
662 | 664 | ||
663 | void (*overflow_handler)(struct perf_event *event, | 665 | perf_overflow_handler_t overflow_handler; |
664 | int nmi, struct perf_sample_data *data, | ||
665 | struct pt_regs *regs); | ||
666 | 666 | ||
667 | #ifdef CONFIG_EVENT_PROFILE | 667 | #ifdef CONFIG_EVENT_PROFILE |
668 | struct event_filter *filter; | 668 | struct event_filter *filter; |
669 | #endif | 669 | #endif |
670 | 670 | ||
671 | perf_callback_t callback; | ||
672 | |||
673 | perf_callback_t event_callback; | ||
674 | |||
675 | #endif /* CONFIG_PERF_EVENTS */ | 671 | #endif /* CONFIG_PERF_EVENTS */ |
676 | }; | 672 | }; |
677 | 673 | ||
@@ -781,7 +777,7 @@ extern struct perf_event * | |||
781 | perf_event_create_kernel_counter(struct perf_event_attr *attr, | 777 | perf_event_create_kernel_counter(struct perf_event_attr *attr, |
782 | int cpu, | 778 | int cpu, |
783 | pid_t pid, | 779 | pid_t pid, |
784 | perf_callback_t callback); | 780 | perf_overflow_handler_t callback); |
785 | extern u64 perf_event_read_value(struct perf_event *event, | 781 | extern u64 perf_event_read_value(struct perf_event *event, |
786 | u64 *enabled, u64 *running); | 782 | u64 *enabled, u64 *running); |
787 | 783 | ||
@@ -876,6 +872,8 @@ extern void perf_output_copy(struct perf_output_handle *handle, | |||
876 | const void *buf, unsigned int len); | 872 | const void *buf, unsigned int len); |
877 | extern int perf_swevent_get_recursion_context(void); | 873 | extern int perf_swevent_get_recursion_context(void); |
878 | extern void perf_swevent_put_recursion_context(int rctx); | 874 | extern void perf_swevent_put_recursion_context(int rctx); |
875 | extern void perf_event_enable(struct perf_event *event); | ||
876 | extern void perf_event_disable(struct perf_event *event); | ||
879 | #else | 877 | #else |
880 | static inline void | 878 | static inline void |
881 | perf_event_task_sched_in(struct task_struct *task, int cpu) { } | 879 | perf_event_task_sched_in(struct task_struct *task, int cpu) { } |
@@ -906,7 +904,8 @@ static inline void perf_event_fork(struct task_struct *tsk) { } | |||
906 | static inline void perf_event_init(void) { } | 904 | static inline void perf_event_init(void) { } |
907 | static inline int perf_swevent_get_recursion_context(void) { return -1; } | 905 | static inline int perf_swevent_get_recursion_context(void) { return -1; } |
908 | static inline void perf_swevent_put_recursion_context(int rctx) { } | 906 | static inline void perf_swevent_put_recursion_context(int rctx) { } |
909 | 907 | static inline void perf_event_enable(struct perf_event *event) { } | |
908 | static inline void perf_event_disable(struct perf_event *event) { } | ||
910 | #endif | 909 | #endif |
911 | 910 | ||
912 | #define perf_output_put(handle, x) \ | 911 | #define perf_output_put(handle, x) \ |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 89115ec7d43f..3f4fa73b512a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1840,7 +1840,8 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask) | |||
1840 | extern int sched_clock_stable; | 1840 | extern int sched_clock_stable; |
1841 | #endif | 1841 | #endif |
1842 | 1842 | ||
1843 | extern unsigned long long sched_clock(void); | 1843 | /* ftrace calls sched_clock() directly */ |
1844 | extern unsigned long long notrace sched_clock(void); | ||
1844 | 1845 | ||
1845 | extern void sched_clock_init(void); | 1846 | extern void sched_clock_init(void); |
1846 | extern u64 sched_clock_cpu(int cpu); | 1847 | extern u64 sched_clock_cpu(int cpu); |
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c index cf5ee1628411..366eedf949c0 100644 --- a/kernel/hw_breakpoint.c +++ b/kernel/hw_breakpoint.c | |||
@@ -52,7 +52,7 @@ | |||
52 | static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned); | 52 | static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned); |
53 | 53 | ||
54 | /* Number of pinned task breakpoints in a cpu */ | 54 | /* Number of pinned task breakpoints in a cpu */ |
55 | static DEFINE_PER_CPU(unsigned int, task_bp_pinned[HBP_NUM]); | 55 | static DEFINE_PER_CPU(unsigned int, nr_task_bp_pinned[HBP_NUM]); |
56 | 56 | ||
57 | /* Number of non-pinned cpu/task breakpoints in a cpu */ | 57 | /* Number of non-pinned cpu/task breakpoints in a cpu */ |
58 | static DEFINE_PER_CPU(unsigned int, nr_bp_flexible); | 58 | static DEFINE_PER_CPU(unsigned int, nr_bp_flexible); |
@@ -73,7 +73,7 @@ static DEFINE_MUTEX(nr_bp_mutex); | |||
73 | static unsigned int max_task_bp_pinned(int cpu) | 73 | static unsigned int max_task_bp_pinned(int cpu) |
74 | { | 74 | { |
75 | int i; | 75 | int i; |
76 | unsigned int *tsk_pinned = per_cpu(task_bp_pinned, cpu); | 76 | unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned, cpu); |
77 | 77 | ||
78 | for (i = HBP_NUM -1; i >= 0; i--) { | 78 | for (i = HBP_NUM -1; i >= 0; i--) { |
79 | if (tsk_pinned[i] > 0) | 79 | if (tsk_pinned[i] > 0) |
@@ -83,15 +83,51 @@ static unsigned int max_task_bp_pinned(int cpu) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | static int task_bp_pinned(struct task_struct *tsk) | ||
87 | { | ||
88 | struct perf_event_context *ctx = tsk->perf_event_ctxp; | ||
89 | struct list_head *list; | ||
90 | struct perf_event *bp; | ||
91 | unsigned long flags; | ||
92 | int count = 0; | ||
93 | |||
94 | if (WARN_ONCE(!ctx, "No perf context for this task")) | ||
95 | return 0; | ||
96 | |||
97 | list = &ctx->event_list; | ||
98 | |||
99 | spin_lock_irqsave(&ctx->lock, flags); | ||
100 | |||
101 | /* | ||
102 | * The current breakpoint counter is not included in the list | ||
103 | * at the open() callback time | ||
104 | */ | ||
105 | list_for_each_entry(bp, list, event_entry) { | ||
106 | if (bp->attr.type == PERF_TYPE_BREAKPOINT) | ||
107 | count++; | ||
108 | } | ||
109 | |||
110 | spin_unlock_irqrestore(&ctx->lock, flags); | ||
111 | |||
112 | return count; | ||
113 | } | ||
114 | |||
86 | /* | 115 | /* |
87 | * Report the number of pinned/un-pinned breakpoints we have in | 116 | * Report the number of pinned/un-pinned breakpoints we have in |
88 | * a given cpu (cpu > -1) or in all of them (cpu = -1). | 117 | * a given cpu (cpu > -1) or in all of them (cpu = -1). |
89 | */ | 118 | */ |
90 | static void fetch_bp_busy_slots(struct bp_busy_slots *slots, int cpu) | 119 | static void |
120 | fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp) | ||
91 | { | 121 | { |
122 | int cpu = bp->cpu; | ||
123 | struct task_struct *tsk = bp->ctx->task; | ||
124 | |||
92 | if (cpu >= 0) { | 125 | if (cpu >= 0) { |
93 | slots->pinned = per_cpu(nr_cpu_bp_pinned, cpu); | 126 | slots->pinned = per_cpu(nr_cpu_bp_pinned, cpu); |
94 | slots->pinned += max_task_bp_pinned(cpu); | 127 | if (!tsk) |
128 | slots->pinned += max_task_bp_pinned(cpu); | ||
129 | else | ||
130 | slots->pinned += task_bp_pinned(tsk); | ||
95 | slots->flexible = per_cpu(nr_bp_flexible, cpu); | 131 | slots->flexible = per_cpu(nr_bp_flexible, cpu); |
96 | 132 | ||
97 | return; | 133 | return; |
@@ -101,7 +137,10 @@ static void fetch_bp_busy_slots(struct bp_busy_slots *slots, int cpu) | |||
101 | unsigned int nr; | 137 | unsigned int nr; |
102 | 138 | ||
103 | nr = per_cpu(nr_cpu_bp_pinned, cpu); | 139 | nr = per_cpu(nr_cpu_bp_pinned, cpu); |
104 | nr += max_task_bp_pinned(cpu); | 140 | if (!tsk) |
141 | nr += max_task_bp_pinned(cpu); | ||
142 | else | ||
143 | nr += task_bp_pinned(tsk); | ||
105 | 144 | ||
106 | if (nr > slots->pinned) | 145 | if (nr > slots->pinned) |
107 | slots->pinned = nr; | 146 | slots->pinned = nr; |
@@ -118,35 +157,12 @@ static void fetch_bp_busy_slots(struct bp_busy_slots *slots, int cpu) | |||
118 | */ | 157 | */ |
119 | static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable) | 158 | static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable) |
120 | { | 159 | { |
121 | int count = 0; | ||
122 | struct perf_event *bp; | ||
123 | struct perf_event_context *ctx = tsk->perf_event_ctxp; | ||
124 | unsigned int *tsk_pinned; | 160 | unsigned int *tsk_pinned; |
125 | struct list_head *list; | 161 | int count = 0; |
126 | unsigned long flags; | ||
127 | |||
128 | if (WARN_ONCE(!ctx, "No perf context for this task")) | ||
129 | return; | ||
130 | |||
131 | list = &ctx->event_list; | ||
132 | |||
133 | spin_lock_irqsave(&ctx->lock, flags); | ||
134 | |||
135 | /* | ||
136 | * The current breakpoint counter is not included in the list | ||
137 | * at the open() callback time | ||
138 | */ | ||
139 | list_for_each_entry(bp, list, event_entry) { | ||
140 | if (bp->attr.type == PERF_TYPE_BREAKPOINT) | ||
141 | count++; | ||
142 | } | ||
143 | 162 | ||
144 | spin_unlock_irqrestore(&ctx->lock, flags); | 163 | count = task_bp_pinned(tsk); |
145 | 164 | ||
146 | if (WARN_ONCE(count < 0, "No breakpoint counter found in the counter list")) | 165 | tsk_pinned = per_cpu(nr_task_bp_pinned, cpu); |
147 | return; | ||
148 | |||
149 | tsk_pinned = per_cpu(task_bp_pinned, cpu); | ||
150 | if (enable) { | 166 | if (enable) { |
151 | tsk_pinned[count]++; | 167 | tsk_pinned[count]++; |
152 | if (count > 0) | 168 | if (count > 0) |
@@ -193,7 +209,7 @@ static void toggle_bp_slot(struct perf_event *bp, bool enable) | |||
193 | * - If attached to a single cpu, check: | 209 | * - If attached to a single cpu, check: |
194 | * | 210 | * |
195 | * (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu) | 211 | * (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu) |
196 | * + max(per_cpu(task_bp_pinned, cpu)))) < HBP_NUM | 212 | * + max(per_cpu(nr_task_bp_pinned, cpu)))) < HBP_NUM |
197 | * | 213 | * |
198 | * -> If there are already non-pinned counters in this cpu, it means | 214 | * -> If there are already non-pinned counters in this cpu, it means |
199 | * there is already a free slot for them. | 215 | * there is already a free slot for them. |
@@ -204,7 +220,7 @@ static void toggle_bp_slot(struct perf_event *bp, bool enable) | |||
204 | * - If attached to every cpus, check: | 220 | * - If attached to every cpus, check: |
205 | * | 221 | * |
206 | * (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *)) | 222 | * (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *)) |
207 | * + max(per_cpu(task_bp_pinned, *)))) < HBP_NUM | 223 | * + max(per_cpu(nr_task_bp_pinned, *)))) < HBP_NUM |
208 | * | 224 | * |
209 | * -> This is roughly the same, except we check the number of per cpu | 225 | * -> This is roughly the same, except we check the number of per cpu |
210 | * bp for every cpu and we keep the max one. Same for the per tasks | 226 | * bp for every cpu and we keep the max one. Same for the per tasks |
@@ -216,7 +232,7 @@ static void toggle_bp_slot(struct perf_event *bp, bool enable) | |||
216 | * - If attached to a single cpu, check: | 232 | * - If attached to a single cpu, check: |
217 | * | 233 | * |
218 | * ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu) | 234 | * ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu) |
219 | * + max(per_cpu(task_bp_pinned, cpu))) < HBP_NUM | 235 | * + max(per_cpu(nr_task_bp_pinned, cpu))) < HBP_NUM |
220 | * | 236 | * |
221 | * -> Same checks as before. But now the nr_bp_flexible, if any, must keep | 237 | * -> Same checks as before. But now the nr_bp_flexible, if any, must keep |
222 | * one register at least (or they will never be fed). | 238 | * one register at least (or they will never be fed). |
@@ -224,7 +240,7 @@ static void toggle_bp_slot(struct perf_event *bp, bool enable) | |||
224 | * - If attached to every cpus, check: | 240 | * - If attached to every cpus, check: |
225 | * | 241 | * |
226 | * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *)) | 242 | * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *)) |
227 | * + max(per_cpu(task_bp_pinned, *))) < HBP_NUM | 243 | * + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM |
228 | */ | 244 | */ |
229 | int reserve_bp_slot(struct perf_event *bp) | 245 | int reserve_bp_slot(struct perf_event *bp) |
230 | { | 246 | { |
@@ -233,7 +249,7 @@ int reserve_bp_slot(struct perf_event *bp) | |||
233 | 249 | ||
234 | mutex_lock(&nr_bp_mutex); | 250 | mutex_lock(&nr_bp_mutex); |
235 | 251 | ||
236 | fetch_bp_busy_slots(&slots, bp->cpu); | 252 | fetch_bp_busy_slots(&slots, bp); |
237 | 253 | ||
238 | /* Flexible counters need to keep at least one slot */ | 254 | /* Flexible counters need to keep at least one slot */ |
239 | if (slots.pinned + (!!slots.flexible) == HBP_NUM) { | 255 | if (slots.pinned + (!!slots.flexible) == HBP_NUM) { |
@@ -259,7 +275,7 @@ void release_bp_slot(struct perf_event *bp) | |||
259 | } | 275 | } |
260 | 276 | ||
261 | 277 | ||
262 | int __register_perf_hw_breakpoint(struct perf_event *bp) | 278 | int register_perf_hw_breakpoint(struct perf_event *bp) |
263 | { | 279 | { |
264 | int ret; | 280 | int ret; |
265 | 281 | ||
@@ -276,19 +292,12 @@ int __register_perf_hw_breakpoint(struct perf_event *bp) | |||
276 | * This is a quick hack that will be removed soon, once we remove | 292 | * This is a quick hack that will be removed soon, once we remove |
277 | * the tmp breakpoints from ptrace | 293 | * the tmp breakpoints from ptrace |
278 | */ | 294 | */ |
279 | if (!bp->attr.disabled || bp->callback == perf_bp_event) | 295 | if (!bp->attr.disabled || !bp->overflow_handler) |
280 | ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task); | 296 | ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task); |
281 | 297 | ||
282 | return ret; | 298 | return ret; |
283 | } | 299 | } |
284 | 300 | ||
285 | int register_perf_hw_breakpoint(struct perf_event *bp) | ||
286 | { | ||
287 | bp->callback = perf_bp_event; | ||
288 | |||
289 | return __register_perf_hw_breakpoint(bp); | ||
290 | } | ||
291 | |||
292 | /** | 301 | /** |
293 | * register_user_hw_breakpoint - register a hardware breakpoint for user space | 302 | * register_user_hw_breakpoint - register a hardware breakpoint for user space |
294 | * @attr: breakpoint attributes | 303 | * @attr: breakpoint attributes |
@@ -297,7 +306,7 @@ int register_perf_hw_breakpoint(struct perf_event *bp) | |||
297 | */ | 306 | */ |
298 | struct perf_event * | 307 | struct perf_event * |
299 | register_user_hw_breakpoint(struct perf_event_attr *attr, | 308 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
300 | perf_callback_t triggered, | 309 | perf_overflow_handler_t triggered, |
301 | struct task_struct *tsk) | 310 | struct task_struct *tsk) |
302 | { | 311 | { |
303 | return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered); | 312 | return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered); |
@@ -311,19 +320,40 @@ EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); | |||
311 | * @triggered: callback to trigger when we hit the breakpoint | 320 | * @triggered: callback to trigger when we hit the breakpoint |
312 | * @tsk: pointer to 'task_struct' of the process to which the address belongs | 321 | * @tsk: pointer to 'task_struct' of the process to which the address belongs |
313 | */ | 322 | */ |
314 | struct perf_event * | 323 | int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) |
315 | modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr, | ||
316 | perf_callback_t triggered, | ||
317 | struct task_struct *tsk) | ||
318 | { | 324 | { |
319 | /* | 325 | u64 old_addr = bp->attr.bp_addr; |
320 | * FIXME: do it without unregistering | 326 | int old_type = bp->attr.bp_type; |
321 | * - We don't want to lose our slot | 327 | int old_len = bp->attr.bp_len; |
322 | * - If the new bp is incorrect, don't lose the older one | 328 | int err = 0; |
323 | */ | ||
324 | unregister_hw_breakpoint(bp); | ||
325 | 329 | ||
326 | return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered); | 330 | perf_event_disable(bp); |
331 | |||
332 | bp->attr.bp_addr = attr->bp_addr; | ||
333 | bp->attr.bp_type = attr->bp_type; | ||
334 | bp->attr.bp_len = attr->bp_len; | ||
335 | |||
336 | if (attr->disabled) | ||
337 | goto end; | ||
338 | |||
339 | err = arch_validate_hwbkpt_settings(bp, bp->ctx->task); | ||
340 | if (!err) | ||
341 | perf_event_enable(bp); | ||
342 | |||
343 | if (err) { | ||
344 | bp->attr.bp_addr = old_addr; | ||
345 | bp->attr.bp_type = old_type; | ||
346 | bp->attr.bp_len = old_len; | ||
347 | if (!bp->attr.disabled) | ||
348 | perf_event_enable(bp); | ||
349 | |||
350 | return err; | ||
351 | } | ||
352 | |||
353 | end: | ||
354 | bp->attr.disabled = attr->disabled; | ||
355 | |||
356 | return 0; | ||
327 | } | 357 | } |
328 | EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); | 358 | EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); |
329 | 359 | ||
@@ -348,7 +378,7 @@ EXPORT_SYMBOL_GPL(unregister_hw_breakpoint); | |||
348 | */ | 378 | */ |
349 | struct perf_event ** | 379 | struct perf_event ** |
350 | register_wide_hw_breakpoint(struct perf_event_attr *attr, | 380 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
351 | perf_callback_t triggered) | 381 | perf_overflow_handler_t triggered) |
352 | { | 382 | { |
353 | struct perf_event **cpu_events, **pevent, *bp; | 383 | struct perf_event **cpu_events, **pevent, *bp; |
354 | long err; | 384 | long err; |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 40a996ec39fa..e73e53c7582f 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -36,7 +36,7 @@ | |||
36 | /* | 36 | /* |
37 | * Each CPU has a list of per CPU events: | 37 | * Each CPU has a list of per CPU events: |
38 | */ | 38 | */ |
39 | DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context); | 39 | static DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context); |
40 | 40 | ||
41 | int perf_max_events __read_mostly = 1; | 41 | int perf_max_events __read_mostly = 1; |
42 | static int perf_reserved_percpu __read_mostly; | 42 | static int perf_reserved_percpu __read_mostly; |
@@ -567,7 +567,7 @@ static void __perf_event_disable(void *info) | |||
567 | * is the current context on this CPU and preemption is disabled, | 567 | * is the current context on this CPU and preemption is disabled, |
568 | * hence we can't get into perf_event_task_sched_out for this context. | 568 | * hence we can't get into perf_event_task_sched_out for this context. |
569 | */ | 569 | */ |
570 | static void perf_event_disable(struct perf_event *event) | 570 | void perf_event_disable(struct perf_event *event) |
571 | { | 571 | { |
572 | struct perf_event_context *ctx = event->ctx; | 572 | struct perf_event_context *ctx = event->ctx; |
573 | struct task_struct *task = ctx->task; | 573 | struct task_struct *task = ctx->task; |
@@ -971,7 +971,7 @@ static void __perf_event_enable(void *info) | |||
971 | * perf_event_for_each_child or perf_event_for_each as described | 971 | * perf_event_for_each_child or perf_event_for_each as described |
972 | * for perf_event_disable. | 972 | * for perf_event_disable. |
973 | */ | 973 | */ |
974 | static void perf_event_enable(struct perf_event *event) | 974 | void perf_event_enable(struct perf_event *event) |
975 | { | 975 | { |
976 | struct perf_event_context *ctx = event->ctx; | 976 | struct perf_event_context *ctx = event->ctx; |
977 | struct task_struct *task = ctx->task; | 977 | struct task_struct *task = ctx->task; |
@@ -1579,7 +1579,6 @@ static void | |||
1579 | __perf_event_init_context(struct perf_event_context *ctx, | 1579 | __perf_event_init_context(struct perf_event_context *ctx, |
1580 | struct task_struct *task) | 1580 | struct task_struct *task) |
1581 | { | 1581 | { |
1582 | memset(ctx, 0, sizeof(*ctx)); | ||
1583 | spin_lock_init(&ctx->lock); | 1582 | spin_lock_init(&ctx->lock); |
1584 | mutex_init(&ctx->mutex); | 1583 | mutex_init(&ctx->mutex); |
1585 | INIT_LIST_HEAD(&ctx->group_list); | 1584 | INIT_LIST_HEAD(&ctx->group_list); |
@@ -1654,7 +1653,7 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu) | |||
1654 | } | 1653 | } |
1655 | 1654 | ||
1656 | if (!ctx) { | 1655 | if (!ctx) { |
1657 | ctx = kmalloc(sizeof(struct perf_event_context), GFP_KERNEL); | 1656 | ctx = kzalloc(sizeof(struct perf_event_context), GFP_KERNEL); |
1658 | err = -ENOMEM; | 1657 | err = -ENOMEM; |
1659 | if (!ctx) | 1658 | if (!ctx) |
1660 | goto errout; | 1659 | goto errout; |
@@ -4011,6 +4010,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) | |||
4011 | event->pmu->read(event); | 4010 | event->pmu->read(event); |
4012 | 4011 | ||
4013 | data.addr = 0; | 4012 | data.addr = 0; |
4013 | data.raw = NULL; | ||
4014 | data.period = event->hw.last_period; | 4014 | data.period = event->hw.last_period; |
4015 | regs = get_irq_regs(); | 4015 | regs = get_irq_regs(); |
4016 | /* | 4016 | /* |
@@ -4080,8 +4080,7 @@ static void cpu_clock_perf_event_update(struct perf_event *event) | |||
4080 | u64 now; | 4080 | u64 now; |
4081 | 4081 | ||
4082 | now = cpu_clock(cpu); | 4082 | now = cpu_clock(cpu); |
4083 | prev = atomic64_read(&event->hw.prev_count); | 4083 | prev = atomic64_xchg(&event->hw.prev_count, now); |
4084 | atomic64_set(&event->hw.prev_count, now); | ||
4085 | atomic64_add(now - prev, &event->count); | 4084 | atomic64_add(now - prev, &event->count); |
4086 | } | 4085 | } |
4087 | 4086 | ||
@@ -4286,15 +4285,8 @@ static void bp_perf_event_destroy(struct perf_event *event) | |||
4286 | static const struct pmu *bp_perf_event_init(struct perf_event *bp) | 4285 | static const struct pmu *bp_perf_event_init(struct perf_event *bp) |
4287 | { | 4286 | { |
4288 | int err; | 4287 | int err; |
4289 | /* | 4288 | |
4290 | * The breakpoint is already filled if we haven't created the counter | 4289 | err = register_perf_hw_breakpoint(bp); |
4291 | * through perf syscall | ||
4292 | * FIXME: manage to get trigerred to NULL if it comes from syscalls | ||
4293 | */ | ||
4294 | if (!bp->callback) | ||
4295 | err = register_perf_hw_breakpoint(bp); | ||
4296 | else | ||
4297 | err = __register_perf_hw_breakpoint(bp); | ||
4298 | if (err) | 4290 | if (err) |
4299 | return ERR_PTR(err); | 4291 | return ERR_PTR(err); |
4300 | 4292 | ||
@@ -4308,6 +4300,7 @@ void perf_bp_event(struct perf_event *bp, void *data) | |||
4308 | struct perf_sample_data sample; | 4300 | struct perf_sample_data sample; |
4309 | struct pt_regs *regs = data; | 4301 | struct pt_regs *regs = data; |
4310 | 4302 | ||
4303 | sample.raw = NULL; | ||
4311 | sample.addr = bp->attr.bp_addr; | 4304 | sample.addr = bp->attr.bp_addr; |
4312 | 4305 | ||
4313 | if (!perf_exclude_event(bp, regs)) | 4306 | if (!perf_exclude_event(bp, regs)) |
@@ -4390,7 +4383,7 @@ perf_event_alloc(struct perf_event_attr *attr, | |||
4390 | struct perf_event_context *ctx, | 4383 | struct perf_event_context *ctx, |
4391 | struct perf_event *group_leader, | 4384 | struct perf_event *group_leader, |
4392 | struct perf_event *parent_event, | 4385 | struct perf_event *parent_event, |
4393 | perf_callback_t callback, | 4386 | perf_overflow_handler_t overflow_handler, |
4394 | gfp_t gfpflags) | 4387 | gfp_t gfpflags) |
4395 | { | 4388 | { |
4396 | const struct pmu *pmu; | 4389 | const struct pmu *pmu; |
@@ -4433,10 +4426,10 @@ perf_event_alloc(struct perf_event_attr *attr, | |||
4433 | 4426 | ||
4434 | event->state = PERF_EVENT_STATE_INACTIVE; | 4427 | event->state = PERF_EVENT_STATE_INACTIVE; |
4435 | 4428 | ||
4436 | if (!callback && parent_event) | 4429 | if (!overflow_handler && parent_event) |
4437 | callback = parent_event->callback; | 4430 | overflow_handler = parent_event->overflow_handler; |
4438 | 4431 | ||
4439 | event->callback = callback; | 4432 | event->overflow_handler = overflow_handler; |
4440 | 4433 | ||
4441 | if (attr->disabled) | 4434 | if (attr->disabled) |
4442 | event->state = PERF_EVENT_STATE_OFF; | 4435 | event->state = PERF_EVENT_STATE_OFF; |
@@ -4776,7 +4769,8 @@ err_put_context: | |||
4776 | */ | 4769 | */ |
4777 | struct perf_event * | 4770 | struct perf_event * |
4778 | perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, | 4771 | perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, |
4779 | pid_t pid, perf_callback_t callback) | 4772 | pid_t pid, |
4773 | perf_overflow_handler_t overflow_handler) | ||
4780 | { | 4774 | { |
4781 | struct perf_event *event; | 4775 | struct perf_event *event; |
4782 | struct perf_event_context *ctx; | 4776 | struct perf_event_context *ctx; |
@@ -4793,7 +4787,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, | |||
4793 | } | 4787 | } |
4794 | 4788 | ||
4795 | event = perf_event_alloc(attr, cpu, ctx, NULL, | 4789 | event = perf_event_alloc(attr, cpu, ctx, NULL, |
4796 | NULL, callback, GFP_KERNEL); | 4790 | NULL, overflow_handler, GFP_KERNEL); |
4797 | if (IS_ERR(event)) { | 4791 | if (IS_ERR(event)) { |
4798 | err = PTR_ERR(event); | 4792 | err = PTR_ERR(event); |
4799 | goto err_put_context; | 4793 | goto err_put_context; |
@@ -5090,7 +5084,7 @@ again: | |||
5090 | */ | 5084 | */ |
5091 | int perf_event_init_task(struct task_struct *child) | 5085 | int perf_event_init_task(struct task_struct *child) |
5092 | { | 5086 | { |
5093 | struct perf_event_context *child_ctx, *parent_ctx; | 5087 | struct perf_event_context *child_ctx = NULL, *parent_ctx; |
5094 | struct perf_event_context *cloned_ctx; | 5088 | struct perf_event_context *cloned_ctx; |
5095 | struct perf_event *event; | 5089 | struct perf_event *event; |
5096 | struct task_struct *parent = current; | 5090 | struct task_struct *parent = current; |
@@ -5106,20 +5100,6 @@ int perf_event_init_task(struct task_struct *child) | |||
5106 | return 0; | 5100 | return 0; |
5107 | 5101 | ||
5108 | /* | 5102 | /* |
5109 | * This is executed from the parent task context, so inherit | ||
5110 | * events that have been marked for cloning. | ||
5111 | * First allocate and initialize a context for the child. | ||
5112 | */ | ||
5113 | |||
5114 | child_ctx = kmalloc(sizeof(struct perf_event_context), GFP_KERNEL); | ||
5115 | if (!child_ctx) | ||
5116 | return -ENOMEM; | ||
5117 | |||
5118 | __perf_event_init_context(child_ctx, child); | ||
5119 | child->perf_event_ctxp = child_ctx; | ||
5120 | get_task_struct(child); | ||
5121 | |||
5122 | /* | ||
5123 | * If the parent's context is a clone, pin it so it won't get | 5103 | * If the parent's context is a clone, pin it so it won't get |
5124 | * swapped under us. | 5104 | * swapped under us. |
5125 | */ | 5105 | */ |
@@ -5149,6 +5129,26 @@ int perf_event_init_task(struct task_struct *child) | |||
5149 | continue; | 5129 | continue; |
5150 | } | 5130 | } |
5151 | 5131 | ||
5132 | if (!child->perf_event_ctxp) { | ||
5133 | /* | ||
5134 | * This is executed from the parent task context, so | ||
5135 | * inherit events that have been marked for cloning. | ||
5136 | * First allocate and initialize a context for the | ||
5137 | * child. | ||
5138 | */ | ||
5139 | |||
5140 | child_ctx = kzalloc(sizeof(struct perf_event_context), | ||
5141 | GFP_KERNEL); | ||
5142 | if (!child_ctx) { | ||
5143 | ret = -ENOMEM; | ||
5144 | goto exit; | ||
5145 | } | ||
5146 | |||
5147 | __perf_event_init_context(child_ctx, child); | ||
5148 | child->perf_event_ctxp = child_ctx; | ||
5149 | get_task_struct(child); | ||
5150 | } | ||
5151 | |||
5152 | ret = inherit_group(event, parent, parent_ctx, | 5152 | ret = inherit_group(event, parent, parent_ctx, |
5153 | child, child_ctx); | 5153 | child, child_ctx); |
5154 | if (ret) { | 5154 | if (ret) { |
@@ -5177,6 +5177,7 @@ int perf_event_init_task(struct task_struct *child) | |||
5177 | get_ctx(child_ctx->parent_ctx); | 5177 | get_ctx(child_ctx->parent_ctx); |
5178 | } | 5178 | } |
5179 | 5179 | ||
5180 | exit: | ||
5180 | mutex_unlock(&parent_ctx->mutex); | 5181 | mutex_unlock(&parent_ctx->mutex); |
5181 | 5182 | ||
5182 | perf_unpin_context(parent_ctx); | 5183 | perf_unpin_context(parent_ctx); |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index aff5f80b59b8..b52d397e57eb 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -606,23 +606,22 @@ static int create_trace_probe(int argc, char **argv) | |||
606 | */ | 606 | */ |
607 | struct trace_probe *tp; | 607 | struct trace_probe *tp; |
608 | int i, ret = 0; | 608 | int i, ret = 0; |
609 | int is_return = 0; | 609 | int is_return = 0, is_delete = 0; |
610 | char *symbol = NULL, *event = NULL, *arg = NULL, *group = NULL; | 610 | char *symbol = NULL, *event = NULL, *arg = NULL, *group = NULL; |
611 | unsigned long offset = 0; | 611 | unsigned long offset = 0; |
612 | void *addr = NULL; | 612 | void *addr = NULL; |
613 | char buf[MAX_EVENT_NAME_LEN]; | 613 | char buf[MAX_EVENT_NAME_LEN]; |
614 | 614 | ||
615 | if (argc < 2) { | 615 | /* argc must be >= 1 */ |
616 | pr_info("Probe point is not specified.\n"); | ||
617 | return -EINVAL; | ||
618 | } | ||
619 | |||
620 | if (argv[0][0] == 'p') | 616 | if (argv[0][0] == 'p') |
621 | is_return = 0; | 617 | is_return = 0; |
622 | else if (argv[0][0] == 'r') | 618 | else if (argv[0][0] == 'r') |
623 | is_return = 1; | 619 | is_return = 1; |
620 | else if (argv[0][0] == '-') | ||
621 | is_delete = 1; | ||
624 | else { | 622 | else { |
625 | pr_info("Probe definition must be started with 'p' or 'r'.\n"); | 623 | pr_info("Probe definition must be started with 'p', 'r' or" |
624 | " '-'.\n"); | ||
626 | return -EINVAL; | 625 | return -EINVAL; |
627 | } | 626 | } |
628 | 627 | ||
@@ -642,7 +641,29 @@ static int create_trace_probe(int argc, char **argv) | |||
642 | return -EINVAL; | 641 | return -EINVAL; |
643 | } | 642 | } |
644 | } | 643 | } |
644 | if (!group) | ||
645 | group = KPROBE_EVENT_SYSTEM; | ||
645 | 646 | ||
647 | if (is_delete) { | ||
648 | if (!event) { | ||
649 | pr_info("Delete command needs an event name.\n"); | ||
650 | return -EINVAL; | ||
651 | } | ||
652 | tp = find_probe_event(event, group); | ||
653 | if (!tp) { | ||
654 | pr_info("Event %s/%s doesn't exist.\n", group, event); | ||
655 | return -ENOENT; | ||
656 | } | ||
657 | /* delete an event */ | ||
658 | unregister_trace_probe(tp); | ||
659 | free_trace_probe(tp); | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | if (argc < 2) { | ||
664 | pr_info("Probe point is not specified.\n"); | ||
665 | return -EINVAL; | ||
666 | } | ||
646 | if (isdigit(argv[1][0])) { | 667 | if (isdigit(argv[1][0])) { |
647 | if (is_return) { | 668 | if (is_return) { |
648 | pr_info("Return probe point must be a symbol.\n"); | 669 | pr_info("Return probe point must be a symbol.\n"); |
@@ -671,8 +692,6 @@ static int create_trace_probe(int argc, char **argv) | |||
671 | argc -= 2; argv += 2; | 692 | argc -= 2; argv += 2; |
672 | 693 | ||
673 | /* setup a probe */ | 694 | /* setup a probe */ |
674 | if (!group) | ||
675 | group = KPROBE_EVENT_SYSTEM; | ||
676 | if (!event) { | 695 | if (!event) { |
677 | /* Make a new event name */ | 696 | /* Make a new event name */ |
678 | if (symbol) | 697 | if (symbol) |
@@ -1114,7 +1133,7 @@ static int kprobe_event_define_fields(struct ftrace_event_call *event_call) | |||
1114 | struct trace_probe *tp = (struct trace_probe *)event_call->data; | 1133 | struct trace_probe *tp = (struct trace_probe *)event_call->data; |
1115 | 1134 | ||
1116 | ret = trace_define_common_fields(event_call); | 1135 | ret = trace_define_common_fields(event_call); |
1117 | if (!ret) | 1136 | if (ret) |
1118 | return ret; | 1137 | return ret; |
1119 | 1138 | ||
1120 | DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); | 1139 | DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); |
@@ -1132,7 +1151,7 @@ static int kretprobe_event_define_fields(struct ftrace_event_call *event_call) | |||
1132 | struct trace_probe *tp = (struct trace_probe *)event_call->data; | 1151 | struct trace_probe *tp = (struct trace_probe *)event_call->data; |
1133 | 1152 | ||
1134 | ret = trace_define_common_fields(event_call); | 1153 | ret = trace_define_common_fields(event_call); |
1135 | if (!ret) | 1154 | if (ret) |
1136 | return ret; | 1155 | return ret; |
1137 | 1156 | ||
1138 | DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0); | 1157 | DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0); |
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c index ddfa0fd43bc0..acb87d4a4ac1 100644 --- a/kernel/trace/trace_ksym.c +++ b/kernel/trace/trace_ksym.c | |||
@@ -79,11 +79,12 @@ void ksym_collect_stats(unsigned long hbp_hit_addr) | |||
79 | } | 79 | } |
80 | #endif /* CONFIG_PROFILE_KSYM_TRACER */ | 80 | #endif /* CONFIG_PROFILE_KSYM_TRACER */ |
81 | 81 | ||
82 | void ksym_hbp_handler(struct perf_event *hbp, void *data) | 82 | void ksym_hbp_handler(struct perf_event *hbp, int nmi, |
83 | struct perf_sample_data *data, | ||
84 | struct pt_regs *regs) | ||
83 | { | 85 | { |
84 | struct ring_buffer_event *event; | 86 | struct ring_buffer_event *event; |
85 | struct ksym_trace_entry *entry; | 87 | struct ksym_trace_entry *entry; |
86 | struct pt_regs *regs = data; | ||
87 | struct ring_buffer *buffer; | 88 | struct ring_buffer *buffer; |
88 | int pc; | 89 | int pc; |
89 | 90 | ||
diff --git a/samples/hw_breakpoint/data_breakpoint.c b/samples/hw_breakpoint/data_breakpoint.c index 29525500df00..c69cbe9b2426 100644 --- a/samples/hw_breakpoint/data_breakpoint.c +++ b/samples/hw_breakpoint/data_breakpoint.c | |||
@@ -41,7 +41,9 @@ module_param_string(ksym, ksym_name, KSYM_NAME_LEN, S_IRUGO); | |||
41 | MODULE_PARM_DESC(ksym, "Kernel symbol to monitor; this module will report any" | 41 | MODULE_PARM_DESC(ksym, "Kernel symbol to monitor; this module will report any" |
42 | " write operations on the kernel symbol"); | 42 | " write operations on the kernel symbol"); |
43 | 43 | ||
44 | static void sample_hbp_handler(struct perf_event *temp, void *data) | 44 | static void sample_hbp_handler(struct perf_event *bp, int nmi, |
45 | struct perf_sample_data *data, | ||
46 | struct pt_regs *regs) | ||
45 | { | 47 | { |
46 | printk(KERN_INFO "%s value is changed\n", ksym_name); | 48 | printk(KERN_INFO "%s value is changed\n", ksym_name); |
47 | dump_stack(); | 49 | dump_stack(); |
@@ -51,8 +53,9 @@ static void sample_hbp_handler(struct perf_event *temp, void *data) | |||
51 | static int __init hw_break_module_init(void) | 53 | static int __init hw_break_module_init(void) |
52 | { | 54 | { |
53 | int ret; | 55 | int ret; |
54 | DEFINE_BREAKPOINT_ATTR(attr); | 56 | struct perf_event_attr attr; |
55 | 57 | ||
58 | hw_breakpoint_init(&attr); | ||
56 | attr.bp_addr = kallsyms_lookup_name(ksym_name); | 59 | attr.bp_addr = kallsyms_lookup_name(ksym_name); |
57 | attr.bp_len = HW_BREAKPOINT_LEN_4; | 60 | attr.bp_len = HW_BREAKPOINT_LEN_4; |
58 | attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R; | 61 | attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R; |
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt index 44b0ce35c28a..eac4d852e7cd 100644 --- a/tools/perf/Documentation/perf-kmem.txt +++ b/tools/perf/Documentation/perf-kmem.txt | |||
@@ -8,16 +8,16 @@ perf-kmem - Tool to trace/measure kernel memory(slab) properties | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf kmem' {record} [<options>] | 11 | 'perf kmem' {record|stat} [<options>] |
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
15 | There's two variants of perf kmem: | 15 | There are two variants of perf kmem: |
16 | 16 | ||
17 | 'perf kmem record <command>' to record the kmem events | 17 | 'perf kmem record <command>' to record the kmem events |
18 | of an arbitrary workload. | 18 | of an arbitrary workload. |
19 | 19 | ||
20 | 'perf kmem' to report kernel memory statistics. | 20 | 'perf kmem stat' to report kernel memory statistics. |
21 | 21 | ||
22 | OPTIONS | 22 | OPTIONS |
23 | ------- | 23 | ------- |
@@ -25,8 +25,11 @@ OPTIONS | |||
25 | --input=<file>:: | 25 | --input=<file>:: |
26 | Select the input file (default: perf.data) | 26 | Select the input file (default: perf.data) |
27 | 27 | ||
28 | --stat=<caller|alloc>:: | 28 | --caller:: |
29 | Select per callsite or per allocation statistics | 29 | Show per-callsite statistics |
30 | |||
31 | --alloc:: | ||
32 | Show per-allocation statistics | ||
30 | 33 | ||
31 | -s <key[,key2...]>:: | 34 | -s <key[,key2...]>:: |
32 | --sort=<key[,key2...]>:: | 35 | --sort=<key[,key2...]>:: |
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 9270594e6dfd..8fa6bf99fcb5 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -8,10 +8,13 @@ perf-probe - Define new dynamic tracepoints | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf probe' [options] --add 'PROBE' [--add 'PROBE' ...] | 11 | 'perf probe' [options] --add='PROBE' [...] |
12 | or | 12 | or |
13 | 'perf probe' [options] 'PROBE' ['PROBE' ...] | 13 | 'perf probe' [options] PROBE |
14 | 14 | or | |
15 | 'perf probe' [options] --del='[GROUP:]EVENT' [...] | ||
16 | or | ||
17 | 'perf probe' --list | ||
15 | 18 | ||
16 | DESCRIPTION | 19 | DESCRIPTION |
17 | ----------- | 20 | ----------- |
@@ -31,8 +34,16 @@ OPTIONS | |||
31 | Be more verbose (show parsed arguments, etc). | 34 | Be more verbose (show parsed arguments, etc). |
32 | 35 | ||
33 | -a:: | 36 | -a:: |
34 | --add:: | 37 | --add=:: |
35 | Define a probe point (see PROBE SYNTAX for detail) | 38 | Define a probe event (see PROBE SYNTAX for detail). |
39 | |||
40 | -d:: | ||
41 | --del=:: | ||
42 | Delete a probe event. | ||
43 | |||
44 | -l:: | ||
45 | --list:: | ||
46 | List up current probe events. | ||
36 | 47 | ||
37 | PROBE SYNTAX | 48 | PROBE SYNTAX |
38 | ------------ | 49 | ------------ |
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 7dee9d19ab7a..dcb6143a0002 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
@@ -19,7 +19,7 @@ static char const *input_name = "perf.data"; | |||
19 | static int force; | 19 | static int force; |
20 | 20 | ||
21 | static const char *const buildid_list_usage[] = { | 21 | static const char *const buildid_list_usage[] = { |
22 | "perf report [<options>]", | 22 | "perf buildid-list [<options>]", |
23 | NULL | 23 | NULL |
24 | }; | 24 | }; |
25 | 25 | ||
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 047fef74bd52..5f209514f657 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -57,11 +57,6 @@ static struct rb_root root_caller_sorted; | |||
57 | static unsigned long total_requested, total_allocated; | 57 | static unsigned long total_requested, total_allocated; |
58 | static unsigned long nr_allocs, nr_cross_allocs; | 58 | static unsigned long nr_allocs, nr_cross_allocs; |
59 | 59 | ||
60 | struct raw_event_sample { | ||
61 | u32 size; | ||
62 | char data[0]; | ||
63 | }; | ||
64 | |||
65 | #define PATH_SYS_NODE "/sys/devices/system/node" | 60 | #define PATH_SYS_NODE "/sys/devices/system/node" |
66 | 61 | ||
67 | static void init_cpunode_map(void) | 62 | static void init_cpunode_map(void) |
@@ -201,7 +196,7 @@ static void insert_caller_stat(unsigned long call_site, | |||
201 | } | 196 | } |
202 | } | 197 | } |
203 | 198 | ||
204 | static void process_alloc_event(struct raw_event_sample *raw, | 199 | static void process_alloc_event(void *data, |
205 | struct event *event, | 200 | struct event *event, |
206 | int cpu, | 201 | int cpu, |
207 | u64 timestamp __used, | 202 | u64 timestamp __used, |
@@ -214,10 +209,10 @@ static void process_alloc_event(struct raw_event_sample *raw, | |||
214 | int bytes_alloc; | 209 | int bytes_alloc; |
215 | int node1, node2; | 210 | int node1, node2; |
216 | 211 | ||
217 | ptr = raw_field_value(event, "ptr", raw->data); | 212 | ptr = raw_field_value(event, "ptr", data); |
218 | call_site = raw_field_value(event, "call_site", raw->data); | 213 | call_site = raw_field_value(event, "call_site", data); |
219 | bytes_req = raw_field_value(event, "bytes_req", raw->data); | 214 | bytes_req = raw_field_value(event, "bytes_req", data); |
220 | bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data); | 215 | bytes_alloc = raw_field_value(event, "bytes_alloc", data); |
221 | 216 | ||
222 | insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); | 217 | insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); |
223 | insert_caller_stat(call_site, bytes_req, bytes_alloc); | 218 | insert_caller_stat(call_site, bytes_req, bytes_alloc); |
@@ -227,7 +222,7 @@ static void process_alloc_event(struct raw_event_sample *raw, | |||
227 | 222 | ||
228 | if (node) { | 223 | if (node) { |
229 | node1 = cpunode_map[cpu]; | 224 | node1 = cpunode_map[cpu]; |
230 | node2 = raw_field_value(event, "node", raw->data); | 225 | node2 = raw_field_value(event, "node", data); |
231 | if (node1 != node2) | 226 | if (node1 != node2) |
232 | nr_cross_allocs++; | 227 | nr_cross_allocs++; |
233 | } | 228 | } |
@@ -262,7 +257,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr, | |||
262 | return NULL; | 257 | return NULL; |
263 | } | 258 | } |
264 | 259 | ||
265 | static void process_free_event(struct raw_event_sample *raw, | 260 | static void process_free_event(void *data, |
266 | struct event *event, | 261 | struct event *event, |
267 | int cpu, | 262 | int cpu, |
268 | u64 timestamp __used, | 263 | u64 timestamp __used, |
@@ -271,7 +266,7 @@ static void process_free_event(struct raw_event_sample *raw, | |||
271 | unsigned long ptr; | 266 | unsigned long ptr; |
272 | struct alloc_stat *s_alloc, *s_caller; | 267 | struct alloc_stat *s_alloc, *s_caller; |
273 | 268 | ||
274 | ptr = raw_field_value(event, "ptr", raw->data); | 269 | ptr = raw_field_value(event, "ptr", data); |
275 | 270 | ||
276 | s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); | 271 | s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); |
277 | if (!s_alloc) | 272 | if (!s_alloc) |
@@ -289,66 +284,53 @@ static void process_free_event(struct raw_event_sample *raw, | |||
289 | } | 284 | } |
290 | 285 | ||
291 | static void | 286 | static void |
292 | process_raw_event(event_t *raw_event __used, void *more_data, | 287 | process_raw_event(event_t *raw_event __used, void *data, |
293 | int cpu, u64 timestamp, struct thread *thread) | 288 | int cpu, u64 timestamp, struct thread *thread) |
294 | { | 289 | { |
295 | struct raw_event_sample *raw = more_data; | ||
296 | struct event *event; | 290 | struct event *event; |
297 | int type; | 291 | int type; |
298 | 292 | ||
299 | type = trace_parse_common_type(raw->data); | 293 | type = trace_parse_common_type(data); |
300 | event = trace_find_event(type); | 294 | event = trace_find_event(type); |
301 | 295 | ||
302 | if (!strcmp(event->name, "kmalloc") || | 296 | if (!strcmp(event->name, "kmalloc") || |
303 | !strcmp(event->name, "kmem_cache_alloc")) { | 297 | !strcmp(event->name, "kmem_cache_alloc")) { |
304 | process_alloc_event(raw, event, cpu, timestamp, thread, 0); | 298 | process_alloc_event(data, event, cpu, timestamp, thread, 0); |
305 | return; | 299 | return; |
306 | } | 300 | } |
307 | 301 | ||
308 | if (!strcmp(event->name, "kmalloc_node") || | 302 | if (!strcmp(event->name, "kmalloc_node") || |
309 | !strcmp(event->name, "kmem_cache_alloc_node")) { | 303 | !strcmp(event->name, "kmem_cache_alloc_node")) { |
310 | process_alloc_event(raw, event, cpu, timestamp, thread, 1); | 304 | process_alloc_event(data, event, cpu, timestamp, thread, 1); |
311 | return; | 305 | return; |
312 | } | 306 | } |
313 | 307 | ||
314 | if (!strcmp(event->name, "kfree") || | 308 | if (!strcmp(event->name, "kfree") || |
315 | !strcmp(event->name, "kmem_cache_free")) { | 309 | !strcmp(event->name, "kmem_cache_free")) { |
316 | process_free_event(raw, event, cpu, timestamp, thread); | 310 | process_free_event(data, event, cpu, timestamp, thread); |
317 | return; | 311 | return; |
318 | } | 312 | } |
319 | } | 313 | } |
320 | 314 | ||
321 | static int process_sample_event(event_t *event) | 315 | static int process_sample_event(event_t *event) |
322 | { | 316 | { |
323 | u64 ip = event->ip.ip; | 317 | struct sample_data data; |
324 | u64 timestamp = -1; | 318 | struct thread *thread; |
325 | u32 cpu = -1; | ||
326 | u64 period = 1; | ||
327 | void *more_data = event->ip.__more_data; | ||
328 | struct thread *thread = threads__findnew(event->ip.pid); | ||
329 | 319 | ||
330 | if (sample_type & PERF_SAMPLE_TIME) { | 320 | memset(&data, 0, sizeof(data)); |
331 | timestamp = *(u64 *)more_data; | 321 | data.time = -1; |
332 | more_data += sizeof(u64); | 322 | data.cpu = -1; |
333 | } | 323 | data.period = 1; |
334 | |||
335 | if (sample_type & PERF_SAMPLE_CPU) { | ||
336 | cpu = *(u32 *)more_data; | ||
337 | more_data += sizeof(u32); | ||
338 | more_data += sizeof(u32); /* reserved */ | ||
339 | } | ||
340 | 324 | ||
341 | if (sample_type & PERF_SAMPLE_PERIOD) { | 325 | event__parse_sample(event, sample_type, &data); |
342 | period = *(u64 *)more_data; | ||
343 | more_data += sizeof(u64); | ||
344 | } | ||
345 | 326 | ||
346 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 327 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
347 | event->header.misc, | 328 | event->header.misc, |
348 | event->ip.pid, event->ip.tid, | 329 | data.pid, data.tid, |
349 | (void *)(long)ip, | 330 | (void *)(long)data.ip, |
350 | (long long)period); | 331 | (long long)data.period); |
351 | 332 | ||
333 | thread = threads__findnew(event->ip.pid); | ||
352 | if (thread == NULL) { | 334 | if (thread == NULL) { |
353 | pr_debug("problem processing %d event, skipping it.\n", | 335 | pr_debug("problem processing %d event, skipping it.\n", |
354 | event->header.type); | 336 | event->header.type); |
@@ -357,7 +339,8 @@ static int process_sample_event(event_t *event) | |||
357 | 339 | ||
358 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 340 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
359 | 341 | ||
360 | process_raw_event(event, more_data, cpu, timestamp, thread); | 342 | process_raw_event(event, data.raw_data, data.cpu, |
343 | data.time, thread); | ||
361 | 344 | ||
362 | return 0; | 345 | return 0; |
363 | } | 346 | } |
@@ -543,7 +526,7 @@ static int __cmd_kmem(void) | |||
543 | } | 526 | } |
544 | 527 | ||
545 | static const char * const kmem_usage[] = { | 528 | static const char * const kmem_usage[] = { |
546 | "perf kmem [<options>] {record}", | 529 | "perf kmem [<options>] {record|stat}", |
547 | NULL | 530 | NULL |
548 | }; | 531 | }; |
549 | 532 | ||
@@ -703,18 +686,17 @@ static int parse_sort_opt(const struct option *opt __used, | |||
703 | return 0; | 686 | return 0; |
704 | } | 687 | } |
705 | 688 | ||
706 | static int parse_stat_opt(const struct option *opt __used, | 689 | static int parse_caller_opt(const struct option *opt __used, |
707 | const char *arg, int unset __used) | 690 | const char *arg __used, int unset __used) |
708 | { | 691 | { |
709 | if (!arg) | 692 | caller_flag = (alloc_flag + 1); |
710 | return -1; | 693 | return 0; |
694 | } | ||
711 | 695 | ||
712 | if (strcmp(arg, "alloc") == 0) | 696 | static int parse_alloc_opt(const struct option *opt __used, |
713 | alloc_flag = (caller_flag + 1); | 697 | const char *arg __used, int unset __used) |
714 | else if (strcmp(arg, "caller") == 0) | 698 | { |
715 | caller_flag = (alloc_flag + 1); | 699 | alloc_flag = (caller_flag + 1); |
716 | else | ||
717 | return -1; | ||
718 | return 0; | 700 | return 0; |
719 | } | 701 | } |
720 | 702 | ||
@@ -739,14 +721,17 @@ static int parse_line_opt(const struct option *opt __used, | |||
739 | static const struct option kmem_options[] = { | 721 | static const struct option kmem_options[] = { |
740 | OPT_STRING('i', "input", &input_name, "file", | 722 | OPT_STRING('i', "input", &input_name, "file", |
741 | "input file name"), | 723 | "input file name"), |
742 | OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>", | 724 | OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, |
743 | "stat selector, Pass 'alloc' or 'caller'.", | 725 | "show per-callsite statistics", |
744 | parse_stat_opt), | 726 | parse_caller_opt), |
727 | OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, | ||
728 | "show per-allocation statistics", | ||
729 | parse_alloc_opt), | ||
745 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", | 730 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", |
746 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", | 731 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", |
747 | parse_sort_opt), | 732 | parse_sort_opt), |
748 | OPT_CALLBACK('l', "line", NULL, "num", | 733 | OPT_CALLBACK('l', "line", NULL, "num", |
749 | "show n lins", | 734 | "show n lines", |
750 | parse_line_opt), | 735 | parse_line_opt), |
751 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), | 736 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), |
752 | OPT_END() | 737 | OPT_END() |
@@ -790,18 +775,22 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used) | |||
790 | 775 | ||
791 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); | 776 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); |
792 | 777 | ||
793 | if (argc && !strncmp(argv[0], "rec", 3)) | 778 | if (!argc) |
794 | return __cmd_record(argc, argv); | ||
795 | else if (argc) | ||
796 | usage_with_options(kmem_usage, kmem_options); | 779 | usage_with_options(kmem_usage, kmem_options); |
797 | 780 | ||
798 | if (list_empty(&caller_sort)) | 781 | if (!strncmp(argv[0], "rec", 3)) { |
799 | setup_sorting(&caller_sort, default_sort_order); | 782 | return __cmd_record(argc, argv); |
800 | if (list_empty(&alloc_sort)) | 783 | } else if (!strcmp(argv[0], "stat")) { |
801 | setup_sorting(&alloc_sort, default_sort_order); | 784 | setup_cpunode_map(); |
785 | |||
786 | if (list_empty(&caller_sort)) | ||
787 | setup_sorting(&caller_sort, default_sort_order); | ||
788 | if (list_empty(&alloc_sort)) | ||
789 | setup_sorting(&alloc_sort, default_sort_order); | ||
802 | 790 | ||
803 | setup_cpunode_map(); | 791 | return __cmd_kmem(); |
792 | } | ||
804 | 793 | ||
805 | return __cmd_kmem(); | 794 | return 0; |
806 | } | 795 | } |
807 | 796 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index a58e11b7ea80..5a47c1e11f77 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "perf.h" | 35 | #include "perf.h" |
36 | #include "builtin.h" | 36 | #include "builtin.h" |
37 | #include "util/util.h" | 37 | #include "util/util.h" |
38 | #include "util/strlist.h" | ||
38 | #include "util/event.h" | 39 | #include "util/event.h" |
39 | #include "util/debug.h" | 40 | #include "util/debug.h" |
40 | #include "util/parse-options.h" | 41 | #include "util/parse-options.h" |
@@ -43,11 +44,12 @@ | |||
43 | #include "util/probe-event.h" | 44 | #include "util/probe-event.h" |
44 | 45 | ||
45 | /* Default vmlinux search paths */ | 46 | /* Default vmlinux search paths */ |
46 | #define NR_SEARCH_PATH 3 | 47 | #define NR_SEARCH_PATH 4 |
47 | const char *default_search_path[NR_SEARCH_PATH] = { | 48 | const char *default_search_path[NR_SEARCH_PATH] = { |
48 | "/lib/modules/%s/build/vmlinux", /* Custom build kernel */ | 49 | "/lib/modules/%s/build/vmlinux", /* Custom build kernel */ |
49 | "/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */ | 50 | "/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */ |
50 | "/boot/vmlinux-debug-%s", /* Ubuntu */ | 51 | "/boot/vmlinux-debug-%s", /* Ubuntu */ |
52 | "./vmlinux", /* CWD */ | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | #define MAX_PATH_LEN 256 | 55 | #define MAX_PATH_LEN 256 |
@@ -60,6 +62,7 @@ static struct { | |||
60 | int need_dwarf; | 62 | int need_dwarf; |
61 | int nr_probe; | 63 | int nr_probe; |
62 | struct probe_point probes[MAX_PROBES]; | 64 | struct probe_point probes[MAX_PROBES]; |
65 | struct strlist *dellist; | ||
63 | } session; | 66 | } session; |
64 | 67 | ||
65 | static bool listing; | 68 | static bool listing; |
@@ -79,6 +82,25 @@ static void parse_probe_event(const char *str) | |||
79 | pr_debug("%d arguments\n", pp->nr_args); | 82 | pr_debug("%d arguments\n", pp->nr_args); |
80 | } | 83 | } |
81 | 84 | ||
85 | static void parse_probe_event_argv(int argc, const char **argv) | ||
86 | { | ||
87 | int i, len; | ||
88 | char *buf; | ||
89 | |||
90 | /* Bind up rest arguments */ | ||
91 | len = 0; | ||
92 | for (i = 0; i < argc; i++) | ||
93 | len += strlen(argv[i]) + 1; | ||
94 | buf = zalloc(len + 1); | ||
95 | if (!buf) | ||
96 | die("Failed to allocate memory for binding arguments."); | ||
97 | len = 0; | ||
98 | for (i = 0; i < argc; i++) | ||
99 | len += sprintf(&buf[len], "%s ", argv[i]); | ||
100 | parse_probe_event(buf); | ||
101 | free(buf); | ||
102 | } | ||
103 | |||
82 | static int opt_add_probe_event(const struct option *opt __used, | 104 | static int opt_add_probe_event(const struct option *opt __used, |
83 | const char *str, int unset __used) | 105 | const char *str, int unset __used) |
84 | { | 106 | { |
@@ -87,6 +109,17 @@ static int opt_add_probe_event(const struct option *opt __used, | |||
87 | return 0; | 109 | return 0; |
88 | } | 110 | } |
89 | 111 | ||
112 | static int opt_del_probe_event(const struct option *opt __used, | ||
113 | const char *str, int unset __used) | ||
114 | { | ||
115 | if (str) { | ||
116 | if (!session.dellist) | ||
117 | session.dellist = strlist__new(true, NULL); | ||
118 | strlist__add(session.dellist, str); | ||
119 | } | ||
120 | return 0; | ||
121 | } | ||
122 | |||
90 | #ifndef NO_LIBDWARF | 123 | #ifndef NO_LIBDWARF |
91 | static int open_default_vmlinux(void) | 124 | static int open_default_vmlinux(void) |
92 | { | 125 | { |
@@ -121,6 +154,7 @@ static int open_default_vmlinux(void) | |||
121 | static const char * const probe_usage[] = { | 154 | static const char * const probe_usage[] = { |
122 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", | 155 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", |
123 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", | 156 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", |
157 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | ||
124 | "perf probe --list", | 158 | "perf probe --list", |
125 | NULL | 159 | NULL |
126 | }; | 160 | }; |
@@ -132,7 +166,9 @@ static const struct option options[] = { | |||
132 | OPT_STRING('k', "vmlinux", &session.vmlinux, "file", | 166 | OPT_STRING('k', "vmlinux", &session.vmlinux, "file", |
133 | "vmlinux/module pathname"), | 167 | "vmlinux/module pathname"), |
134 | #endif | 168 | #endif |
135 | OPT_BOOLEAN('l', "list", &listing, "list up current probes"), | 169 | OPT_BOOLEAN('l', "list", &listing, "list up current probe events"), |
170 | OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", | ||
171 | opt_del_probe_event), | ||
136 | OPT_CALLBACK('a', "add", NULL, | 172 | OPT_CALLBACK('a', "add", NULL, |
137 | #ifdef NO_LIBDWARF | 173 | #ifdef NO_LIBDWARF |
138 | "FUNC[+OFFS|%return] [ARG ...]", | 174 | "FUNC[+OFFS|%return] [ARG ...]", |
@@ -160,7 +196,7 @@ static const struct option options[] = { | |||
160 | 196 | ||
161 | int cmd_probe(int argc, const char **argv, const char *prefix __used) | 197 | int cmd_probe(int argc, const char **argv, const char *prefix __used) |
162 | { | 198 | { |
163 | int i, j, ret; | 199 | int i, ret; |
164 | #ifndef NO_LIBDWARF | 200 | #ifndef NO_LIBDWARF |
165 | int fd; | 201 | int fd; |
166 | #endif | 202 | #endif |
@@ -168,40 +204,52 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
168 | 204 | ||
169 | argc = parse_options(argc, argv, options, probe_usage, | 205 | argc = parse_options(argc, argv, options, probe_usage, |
170 | PARSE_OPT_STOP_AT_NON_OPTION); | 206 | PARSE_OPT_STOP_AT_NON_OPTION); |
171 | for (i = 0; i < argc; i++) | 207 | if (argc > 0) |
172 | parse_probe_event(argv[i]); | 208 | parse_probe_event_argv(argc, argv); |
173 | 209 | ||
174 | if ((session.nr_probe == 0 && !listing) || | 210 | if ((session.nr_probe == 0 && !session.dellist && !listing)) |
175 | (session.nr_probe != 0 && listing)) | ||
176 | usage_with_options(probe_usage, options); | 211 | usage_with_options(probe_usage, options); |
177 | 212 | ||
178 | if (listing) { | 213 | if (listing) { |
214 | if (session.nr_probe != 0 || session.dellist) { | ||
215 | pr_warning(" Error: Don't use --list with" | ||
216 | " --add/--del.\n"); | ||
217 | usage_with_options(probe_usage, options); | ||
218 | } | ||
179 | show_perf_probe_events(); | 219 | show_perf_probe_events(); |
180 | return 0; | 220 | return 0; |
181 | } | 221 | } |
182 | 222 | ||
223 | if (session.dellist) { | ||
224 | del_trace_kprobe_events(session.dellist); | ||
225 | strlist__delete(session.dellist); | ||
226 | if (session.nr_probe == 0) | ||
227 | return 0; | ||
228 | } | ||
229 | |||
183 | if (session.need_dwarf) | 230 | if (session.need_dwarf) |
184 | #ifdef NO_LIBDWARF | 231 | #ifdef NO_LIBDWARF |
185 | die("Debuginfo-analysis is not supported"); | 232 | die("Debuginfo-analysis is not supported"); |
186 | #else /* !NO_LIBDWARF */ | 233 | #else /* !NO_LIBDWARF */ |
187 | pr_debug("Some probes require debuginfo.\n"); | 234 | pr_debug("Some probes require debuginfo.\n"); |
188 | 235 | ||
189 | if (session.vmlinux) | 236 | if (session.vmlinux) { |
237 | pr_debug("Try to open %s.", session.vmlinux); | ||
190 | fd = open(session.vmlinux, O_RDONLY); | 238 | fd = open(session.vmlinux, O_RDONLY); |
191 | else | 239 | } else |
192 | fd = open_default_vmlinux(); | 240 | fd = open_default_vmlinux(); |
193 | if (fd < 0) { | 241 | if (fd < 0) { |
194 | if (session.need_dwarf) | 242 | if (session.need_dwarf) |
195 | die("Could not open vmlinux/module file."); | 243 | die("Could not open debuginfo file."); |
196 | 244 | ||
197 | pr_warning("Could not open vmlinux/module file." | 245 | pr_debug("Could not open vmlinux/module file." |
198 | " Try to use symbols.\n"); | 246 | " Try to use symbols.\n"); |
199 | goto end_dwarf; | 247 | goto end_dwarf; |
200 | } | 248 | } |
201 | 249 | ||
202 | /* Searching probe points */ | 250 | /* Searching probe points */ |
203 | for (j = 0; j < session.nr_probe; j++) { | 251 | for (i = 0; i < session.nr_probe; i++) { |
204 | pp = &session.probes[j]; | 252 | pp = &session.probes[i]; |
205 | if (pp->found) | 253 | if (pp->found) |
206 | continue; | 254 | continue; |
207 | 255 | ||
@@ -223,8 +271,8 @@ end_dwarf: | |||
223 | #endif /* !NO_LIBDWARF */ | 271 | #endif /* !NO_LIBDWARF */ |
224 | 272 | ||
225 | /* Synthesize probes without dwarf */ | 273 | /* Synthesize probes without dwarf */ |
226 | for (j = 0; j < session.nr_probe; j++) { | 274 | for (i = 0; i < session.nr_probe; i++) { |
227 | pp = &session.probes[j]; | 275 | pp = &session.probes[i]; |
228 | if (pp->found) /* This probe is already found. */ | 276 | if (pp->found) /* This probe is already found. */ |
229 | continue; | 277 | continue; |
230 | 278 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 383c4ab4f9af..2b9eb3a553ed 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -605,44 +605,41 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) | |||
605 | 605 | ||
606 | static int process_sample_event(event_t *event) | 606 | static int process_sample_event(event_t *event) |
607 | { | 607 | { |
608 | u64 ip = event->ip.ip; | 608 | struct sample_data data; |
609 | u64 period = 1; | ||
610 | void *more_data = event->ip.__more_data; | ||
611 | struct ip_callchain *chain = NULL; | ||
612 | int cpumode; | 609 | int cpumode; |
613 | struct addr_location al; | 610 | struct addr_location al; |
614 | struct thread *thread = threads__findnew(event->ip.pid); | 611 | struct thread *thread; |
615 | 612 | ||
616 | if (sample_type & PERF_SAMPLE_PERIOD) { | 613 | memset(&data, 0, sizeof(data)); |
617 | period = *(u64 *)more_data; | 614 | data.period = 1; |
618 | more_data += sizeof(u64); | 615 | |
619 | } | 616 | event__parse_sample(event, sample_type, &data); |
620 | 617 | ||
621 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 618 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
622 | event->header.misc, | 619 | event->header.misc, |
623 | event->ip.pid, event->ip.tid, | 620 | data.pid, data.tid, |
624 | (void *)(long)ip, | 621 | (void *)(long)data.ip, |
625 | (long long)period); | 622 | (long long)data.period); |
626 | 623 | ||
627 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { | 624 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { |
628 | unsigned int i; | 625 | unsigned int i; |
629 | 626 | ||
630 | chain = (void *)more_data; | 627 | dump_printf("... chain: nr:%Lu\n", data.callchain->nr); |
631 | |||
632 | dump_printf("... chain: nr:%Lu\n", chain->nr); | ||
633 | 628 | ||
634 | if (validate_chain(chain, event) < 0) { | 629 | if (validate_chain(data.callchain, event) < 0) { |
635 | pr_debug("call-chain problem with event, " | 630 | pr_debug("call-chain problem with event, " |
636 | "skipping it.\n"); | 631 | "skipping it.\n"); |
637 | return 0; | 632 | return 0; |
638 | } | 633 | } |
639 | 634 | ||
640 | if (dump_trace) { | 635 | if (dump_trace) { |
641 | for (i = 0; i < chain->nr; i++) | 636 | for (i = 0; i < data.callchain->nr; i++) |
642 | dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); | 637 | dump_printf("..... %2d: %016Lx\n", |
638 | i, data.callchain->ips[i]); | ||
643 | } | 639 | } |
644 | } | 640 | } |
645 | 641 | ||
642 | thread = threads__findnew(data.pid); | ||
646 | if (thread == NULL) { | 643 | if (thread == NULL) { |
647 | pr_debug("problem processing %d event, skipping it.\n", | 644 | pr_debug("problem processing %d event, skipping it.\n", |
648 | event->header.type); | 645 | event->header.type); |
@@ -657,7 +654,7 @@ static int process_sample_event(event_t *event) | |||
657 | cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 654 | cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
658 | 655 | ||
659 | thread__find_addr_location(thread, cpumode, | 656 | thread__find_addr_location(thread, cpumode, |
660 | MAP__FUNCTION, ip, &al, NULL); | 657 | MAP__FUNCTION, data.ip, &al, NULL); |
661 | /* | 658 | /* |
662 | * We have to do this here as we may have a dso with no symbol hit that | 659 | * We have to do this here as we may have a dso with no symbol hit that |
663 | * has a name longer than the ones with symbols sampled. | 660 | * has a name longer than the ones with symbols sampled. |
@@ -675,12 +672,12 @@ static int process_sample_event(event_t *event) | |||
675 | if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) | 672 | if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) |
676 | return 0; | 673 | return 0; |
677 | 674 | ||
678 | if (hist_entry__add(&al, chain, period)) { | 675 | if (hist_entry__add(&al, data.callchain, data.period)) { |
679 | pr_debug("problem incrementing symbol count, skipping event\n"); | 676 | pr_debug("problem incrementing symbol count, skipping event\n"); |
680 | return -1; | 677 | return -1; |
681 | } | 678 | } |
682 | 679 | ||
683 | event__stats.total += period; | 680 | event__stats.total += data.period; |
684 | 681 | ||
685 | return 0; | 682 | return 0; |
686 | } | 683 | } |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 26b782f26ee1..7cca7c15b40a 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include "util/debug.h" | 13 | #include "util/debug.h" |
14 | #include "util/data_map.h" | 14 | #include "util/data_map.h" |
15 | 15 | ||
16 | #include <sys/types.h> | ||
17 | #include <sys/prctl.h> | 16 | #include <sys/prctl.h> |
18 | 17 | ||
19 | #include <semaphore.h> | 18 | #include <semaphore.h> |
@@ -141,6 +140,7 @@ struct work_atoms { | |||
141 | struct thread *thread; | 140 | struct thread *thread; |
142 | struct rb_node node; | 141 | struct rb_node node; |
143 | u64 max_lat; | 142 | u64 max_lat; |
143 | u64 max_lat_at; | ||
144 | u64 total_lat; | 144 | u64 total_lat; |
145 | u64 nb_atoms; | 145 | u64 nb_atoms; |
146 | u64 total_runtime; | 146 | u64 total_runtime; |
@@ -414,34 +414,33 @@ static u64 get_cpu_usage_nsec_parent(void) | |||
414 | return sum; | 414 | return sum; |
415 | } | 415 | } |
416 | 416 | ||
417 | static u64 get_cpu_usage_nsec_self(void) | 417 | static int self_open_counters(void) |
418 | { | 418 | { |
419 | char filename [] = "/proc/1234567890/sched"; | 419 | struct perf_event_attr attr; |
420 | unsigned long msecs, nsecs; | 420 | int fd; |
421 | char *line = NULL; | ||
422 | u64 total = 0; | ||
423 | size_t len = 0; | ||
424 | ssize_t chars; | ||
425 | FILE *file; | ||
426 | int ret; | ||
427 | 421 | ||
428 | sprintf(filename, "/proc/%d/sched", getpid()); | 422 | memset(&attr, 0, sizeof(attr)); |
429 | file = fopen(filename, "r"); | ||
430 | BUG_ON(!file); | ||
431 | 423 | ||
432 | while ((chars = getline(&line, &len, file)) != -1) { | 424 | attr.type = PERF_TYPE_SOFTWARE; |
433 | ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", | 425 | attr.config = PERF_COUNT_SW_TASK_CLOCK; |
434 | &msecs, &nsecs); | 426 | |
435 | if (ret == 2) { | 427 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); |
436 | total = msecs*1e6 + nsecs; | ||
437 | break; | ||
438 | } | ||
439 | } | ||
440 | if (line) | ||
441 | free(line); | ||
442 | fclose(file); | ||
443 | 428 | ||
444 | return total; | 429 | if (fd < 0) |
430 | die("Error: sys_perf_event_open() syscall returned" | ||
431 | "with %d (%s)\n", fd, strerror(errno)); | ||
432 | return fd; | ||
433 | } | ||
434 | |||
435 | static u64 get_cpu_usage_nsec_self(int fd) | ||
436 | { | ||
437 | u64 runtime; | ||
438 | int ret; | ||
439 | |||
440 | ret = read(fd, &runtime, sizeof(runtime)); | ||
441 | BUG_ON(ret != sizeof(runtime)); | ||
442 | |||
443 | return runtime; | ||
445 | } | 444 | } |
446 | 445 | ||
447 | static void *thread_func(void *ctx) | 446 | static void *thread_func(void *ctx) |
@@ -450,9 +449,11 @@ static void *thread_func(void *ctx) | |||
450 | u64 cpu_usage_0, cpu_usage_1; | 449 | u64 cpu_usage_0, cpu_usage_1; |
451 | unsigned long i, ret; | 450 | unsigned long i, ret; |
452 | char comm2[22]; | 451 | char comm2[22]; |
452 | int fd; | ||
453 | 453 | ||
454 | sprintf(comm2, ":%s", this_task->comm); | 454 | sprintf(comm2, ":%s", this_task->comm); |
455 | prctl(PR_SET_NAME, comm2); | 455 | prctl(PR_SET_NAME, comm2); |
456 | fd = self_open_counters(); | ||
456 | 457 | ||
457 | again: | 458 | again: |
458 | ret = sem_post(&this_task->ready_for_work); | 459 | ret = sem_post(&this_task->ready_for_work); |
@@ -462,16 +463,15 @@ again: | |||
462 | ret = pthread_mutex_unlock(&start_work_mutex); | 463 | ret = pthread_mutex_unlock(&start_work_mutex); |
463 | BUG_ON(ret); | 464 | BUG_ON(ret); |
464 | 465 | ||
465 | cpu_usage_0 = get_cpu_usage_nsec_self(); | 466 | cpu_usage_0 = get_cpu_usage_nsec_self(fd); |
466 | 467 | ||
467 | for (i = 0; i < this_task->nr_events; i++) { | 468 | for (i = 0; i < this_task->nr_events; i++) { |
468 | this_task->curr_event = i; | 469 | this_task->curr_event = i; |
469 | process_sched_event(this_task, this_task->atoms[i]); | 470 | process_sched_event(this_task, this_task->atoms[i]); |
470 | } | 471 | } |
471 | 472 | ||
472 | cpu_usage_1 = get_cpu_usage_nsec_self(); | 473 | cpu_usage_1 = get_cpu_usage_nsec_self(fd); |
473 | this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; | 474 | this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; |
474 | |||
475 | ret = sem_post(&this_task->work_done_sem); | 475 | ret = sem_post(&this_task->work_done_sem); |
476 | BUG_ON(ret); | 476 | BUG_ON(ret); |
477 | 477 | ||
@@ -628,11 +628,6 @@ static void test_calibrations(void) | |||
628 | printf("the sleep test took %Ld nsecs\n", T1-T0); | 628 | printf("the sleep test took %Ld nsecs\n", T1-T0); |
629 | } | 629 | } |
630 | 630 | ||
631 | struct raw_event_sample { | ||
632 | u32 size; | ||
633 | char data[0]; | ||
634 | }; | ||
635 | |||
636 | #define FILL_FIELD(ptr, field, event, data) \ | 631 | #define FILL_FIELD(ptr, field, event, data) \ |
637 | ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) | 632 | ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) |
638 | 633 | ||
@@ -1019,8 +1014,10 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp) | |||
1019 | 1014 | ||
1020 | delta = atom->sched_in_time - atom->wake_up_time; | 1015 | delta = atom->sched_in_time - atom->wake_up_time; |
1021 | atoms->total_lat += delta; | 1016 | atoms->total_lat += delta; |
1022 | if (delta > atoms->max_lat) | 1017 | if (delta > atoms->max_lat) { |
1023 | atoms->max_lat = delta; | 1018 | atoms->max_lat = delta; |
1019 | atoms->max_lat_at = timestamp; | ||
1020 | } | ||
1024 | atoms->nb_atoms++; | 1021 | atoms->nb_atoms++; |
1025 | } | 1022 | } |
1026 | 1023 | ||
@@ -1216,10 +1213,11 @@ static void output_lat_thread(struct work_atoms *work_list) | |||
1216 | 1213 | ||
1217 | avg = work_list->total_lat / work_list->nb_atoms; | 1214 | avg = work_list->total_lat / work_list->nb_atoms; |
1218 | 1215 | ||
1219 | printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n", | 1216 | printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n", |
1220 | (double)work_list->total_runtime / 1e6, | 1217 | (double)work_list->total_runtime / 1e6, |
1221 | work_list->nb_atoms, (double)avg / 1e6, | 1218 | work_list->nb_atoms, (double)avg / 1e6, |
1222 | (double)work_list->max_lat / 1e6); | 1219 | (double)work_list->max_lat / 1e6, |
1220 | (double)work_list->max_lat_at / 1e9); | ||
1223 | } | 1221 | } |
1224 | 1222 | ||
1225 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) | 1223 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) |
@@ -1356,7 +1354,7 @@ static void sort_lat(void) | |||
1356 | static struct trace_sched_handler *trace_handler; | 1354 | static struct trace_sched_handler *trace_handler; |
1357 | 1355 | ||
1358 | static void | 1356 | static void |
1359 | process_sched_wakeup_event(struct raw_event_sample *raw, | 1357 | process_sched_wakeup_event(void *data, |
1360 | struct event *event, | 1358 | struct event *event, |
1361 | int cpu __used, | 1359 | int cpu __used, |
1362 | u64 timestamp __used, | 1360 | u64 timestamp __used, |
@@ -1364,13 +1362,13 @@ process_sched_wakeup_event(struct raw_event_sample *raw, | |||
1364 | { | 1362 | { |
1365 | struct trace_wakeup_event wakeup_event; | 1363 | struct trace_wakeup_event wakeup_event; |
1366 | 1364 | ||
1367 | FILL_COMMON_FIELDS(wakeup_event, event, raw->data); | 1365 | FILL_COMMON_FIELDS(wakeup_event, event, data); |
1368 | 1366 | ||
1369 | FILL_ARRAY(wakeup_event, comm, event, raw->data); | 1367 | FILL_ARRAY(wakeup_event, comm, event, data); |
1370 | FILL_FIELD(wakeup_event, pid, event, raw->data); | 1368 | FILL_FIELD(wakeup_event, pid, event, data); |
1371 | FILL_FIELD(wakeup_event, prio, event, raw->data); | 1369 | FILL_FIELD(wakeup_event, prio, event, data); |
1372 | FILL_FIELD(wakeup_event, success, event, raw->data); | 1370 | FILL_FIELD(wakeup_event, success, event, data); |
1373 | FILL_FIELD(wakeup_event, cpu, event, raw->data); | 1371 | FILL_FIELD(wakeup_event, cpu, event, data); |
1374 | 1372 | ||
1375 | if (trace_handler->wakeup_event) | 1373 | if (trace_handler->wakeup_event) |
1376 | trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); | 1374 | trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); |
@@ -1469,7 +1467,7 @@ map_switch_event(struct trace_switch_event *switch_event, | |||
1469 | 1467 | ||
1470 | 1468 | ||
1471 | static void | 1469 | static void |
1472 | process_sched_switch_event(struct raw_event_sample *raw, | 1470 | process_sched_switch_event(void *data, |
1473 | struct event *event, | 1471 | struct event *event, |
1474 | int this_cpu, | 1472 | int this_cpu, |
1475 | u64 timestamp __used, | 1473 | u64 timestamp __used, |
@@ -1477,15 +1475,15 @@ process_sched_switch_event(struct raw_event_sample *raw, | |||
1477 | { | 1475 | { |
1478 | struct trace_switch_event switch_event; | 1476 | struct trace_switch_event switch_event; |
1479 | 1477 | ||
1480 | FILL_COMMON_FIELDS(switch_event, event, raw->data); | 1478 | FILL_COMMON_FIELDS(switch_event, event, data); |
1481 | 1479 | ||
1482 | FILL_ARRAY(switch_event, prev_comm, event, raw->data); | 1480 | FILL_ARRAY(switch_event, prev_comm, event, data); |
1483 | FILL_FIELD(switch_event, prev_pid, event, raw->data); | 1481 | FILL_FIELD(switch_event, prev_pid, event, data); |
1484 | FILL_FIELD(switch_event, prev_prio, event, raw->data); | 1482 | FILL_FIELD(switch_event, prev_prio, event, data); |
1485 | FILL_FIELD(switch_event, prev_state, event, raw->data); | 1483 | FILL_FIELD(switch_event, prev_state, event, data); |
1486 | FILL_ARRAY(switch_event, next_comm, event, raw->data); | 1484 | FILL_ARRAY(switch_event, next_comm, event, data); |
1487 | FILL_FIELD(switch_event, next_pid, event, raw->data); | 1485 | FILL_FIELD(switch_event, next_pid, event, data); |
1488 | FILL_FIELD(switch_event, next_prio, event, raw->data); | 1486 | FILL_FIELD(switch_event, next_prio, event, data); |
1489 | 1487 | ||
1490 | if (curr_pid[this_cpu] != (u32)-1) { | 1488 | if (curr_pid[this_cpu] != (u32)-1) { |
1491 | /* | 1489 | /* |
@@ -1502,7 +1500,7 @@ process_sched_switch_event(struct raw_event_sample *raw, | |||
1502 | } | 1500 | } |
1503 | 1501 | ||
1504 | static void | 1502 | static void |
1505 | process_sched_runtime_event(struct raw_event_sample *raw, | 1503 | process_sched_runtime_event(void *data, |
1506 | struct event *event, | 1504 | struct event *event, |
1507 | int cpu __used, | 1505 | int cpu __used, |
1508 | u64 timestamp __used, | 1506 | u64 timestamp __used, |
@@ -1510,17 +1508,17 @@ process_sched_runtime_event(struct raw_event_sample *raw, | |||
1510 | { | 1508 | { |
1511 | struct trace_runtime_event runtime_event; | 1509 | struct trace_runtime_event runtime_event; |
1512 | 1510 | ||
1513 | FILL_ARRAY(runtime_event, comm, event, raw->data); | 1511 | FILL_ARRAY(runtime_event, comm, event, data); |
1514 | FILL_FIELD(runtime_event, pid, event, raw->data); | 1512 | FILL_FIELD(runtime_event, pid, event, data); |
1515 | FILL_FIELD(runtime_event, runtime, event, raw->data); | 1513 | FILL_FIELD(runtime_event, runtime, event, data); |
1516 | FILL_FIELD(runtime_event, vruntime, event, raw->data); | 1514 | FILL_FIELD(runtime_event, vruntime, event, data); |
1517 | 1515 | ||
1518 | if (trace_handler->runtime_event) | 1516 | if (trace_handler->runtime_event) |
1519 | trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); | 1517 | trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); |
1520 | } | 1518 | } |
1521 | 1519 | ||
1522 | static void | 1520 | static void |
1523 | process_sched_fork_event(struct raw_event_sample *raw, | 1521 | process_sched_fork_event(void *data, |
1524 | struct event *event, | 1522 | struct event *event, |
1525 | int cpu __used, | 1523 | int cpu __used, |
1526 | u64 timestamp __used, | 1524 | u64 timestamp __used, |
@@ -1528,12 +1526,12 @@ process_sched_fork_event(struct raw_event_sample *raw, | |||
1528 | { | 1526 | { |
1529 | struct trace_fork_event fork_event; | 1527 | struct trace_fork_event fork_event; |
1530 | 1528 | ||
1531 | FILL_COMMON_FIELDS(fork_event, event, raw->data); | 1529 | FILL_COMMON_FIELDS(fork_event, event, data); |
1532 | 1530 | ||
1533 | FILL_ARRAY(fork_event, parent_comm, event, raw->data); | 1531 | FILL_ARRAY(fork_event, parent_comm, event, data); |
1534 | FILL_FIELD(fork_event, parent_pid, event, raw->data); | 1532 | FILL_FIELD(fork_event, parent_pid, event, data); |
1535 | FILL_ARRAY(fork_event, child_comm, event, raw->data); | 1533 | FILL_ARRAY(fork_event, child_comm, event, data); |
1536 | FILL_FIELD(fork_event, child_pid, event, raw->data); | 1534 | FILL_FIELD(fork_event, child_pid, event, data); |
1537 | 1535 | ||
1538 | if (trace_handler->fork_event) | 1536 | if (trace_handler->fork_event) |
1539 | trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); | 1537 | trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); |
@@ -1550,7 +1548,7 @@ process_sched_exit_event(struct event *event, | |||
1550 | } | 1548 | } |
1551 | 1549 | ||
1552 | static void | 1550 | static void |
1553 | process_sched_migrate_task_event(struct raw_event_sample *raw, | 1551 | process_sched_migrate_task_event(void *data, |
1554 | struct event *event, | 1552 | struct event *event, |
1555 | int cpu __used, | 1553 | int cpu __used, |
1556 | u64 timestamp __used, | 1554 | u64 timestamp __used, |
@@ -1558,80 +1556,66 @@ process_sched_migrate_task_event(struct raw_event_sample *raw, | |||
1558 | { | 1556 | { |
1559 | struct trace_migrate_task_event migrate_task_event; | 1557 | struct trace_migrate_task_event migrate_task_event; |
1560 | 1558 | ||
1561 | FILL_COMMON_FIELDS(migrate_task_event, event, raw->data); | 1559 | FILL_COMMON_FIELDS(migrate_task_event, event, data); |
1562 | 1560 | ||
1563 | FILL_ARRAY(migrate_task_event, comm, event, raw->data); | 1561 | FILL_ARRAY(migrate_task_event, comm, event, data); |
1564 | FILL_FIELD(migrate_task_event, pid, event, raw->data); | 1562 | FILL_FIELD(migrate_task_event, pid, event, data); |
1565 | FILL_FIELD(migrate_task_event, prio, event, raw->data); | 1563 | FILL_FIELD(migrate_task_event, prio, event, data); |
1566 | FILL_FIELD(migrate_task_event, cpu, event, raw->data); | 1564 | FILL_FIELD(migrate_task_event, cpu, event, data); |
1567 | 1565 | ||
1568 | if (trace_handler->migrate_task_event) | 1566 | if (trace_handler->migrate_task_event) |
1569 | trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); | 1567 | trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); |
1570 | } | 1568 | } |
1571 | 1569 | ||
1572 | static void | 1570 | static void |
1573 | process_raw_event(event_t *raw_event __used, void *more_data, | 1571 | process_raw_event(event_t *raw_event __used, void *data, |
1574 | int cpu, u64 timestamp, struct thread *thread) | 1572 | int cpu, u64 timestamp, struct thread *thread) |
1575 | { | 1573 | { |
1576 | struct raw_event_sample *raw = more_data; | ||
1577 | struct event *event; | 1574 | struct event *event; |
1578 | int type; | 1575 | int type; |
1579 | 1576 | ||
1580 | type = trace_parse_common_type(raw->data); | 1577 | |
1578 | type = trace_parse_common_type(data); | ||
1581 | event = trace_find_event(type); | 1579 | event = trace_find_event(type); |
1582 | 1580 | ||
1583 | if (!strcmp(event->name, "sched_switch")) | 1581 | if (!strcmp(event->name, "sched_switch")) |
1584 | process_sched_switch_event(raw, event, cpu, timestamp, thread); | 1582 | process_sched_switch_event(data, event, cpu, timestamp, thread); |
1585 | if (!strcmp(event->name, "sched_stat_runtime")) | 1583 | if (!strcmp(event->name, "sched_stat_runtime")) |
1586 | process_sched_runtime_event(raw, event, cpu, timestamp, thread); | 1584 | process_sched_runtime_event(data, event, cpu, timestamp, thread); |
1587 | if (!strcmp(event->name, "sched_wakeup")) | 1585 | if (!strcmp(event->name, "sched_wakeup")) |
1588 | process_sched_wakeup_event(raw, event, cpu, timestamp, thread); | 1586 | process_sched_wakeup_event(data, event, cpu, timestamp, thread); |
1589 | if (!strcmp(event->name, "sched_wakeup_new")) | 1587 | if (!strcmp(event->name, "sched_wakeup_new")) |
1590 | process_sched_wakeup_event(raw, event, cpu, timestamp, thread); | 1588 | process_sched_wakeup_event(data, event, cpu, timestamp, thread); |
1591 | if (!strcmp(event->name, "sched_process_fork")) | 1589 | if (!strcmp(event->name, "sched_process_fork")) |
1592 | process_sched_fork_event(raw, event, cpu, timestamp, thread); | 1590 | process_sched_fork_event(data, event, cpu, timestamp, thread); |
1593 | if (!strcmp(event->name, "sched_process_exit")) | 1591 | if (!strcmp(event->name, "sched_process_exit")) |
1594 | process_sched_exit_event(event, cpu, timestamp, thread); | 1592 | process_sched_exit_event(event, cpu, timestamp, thread); |
1595 | if (!strcmp(event->name, "sched_migrate_task")) | 1593 | if (!strcmp(event->name, "sched_migrate_task")) |
1596 | process_sched_migrate_task_event(raw, event, cpu, timestamp, thread); | 1594 | process_sched_migrate_task_event(data, event, cpu, timestamp, thread); |
1597 | } | 1595 | } |
1598 | 1596 | ||
1599 | static int process_sample_event(event_t *event) | 1597 | static int process_sample_event(event_t *event) |
1600 | { | 1598 | { |
1599 | struct sample_data data; | ||
1601 | struct thread *thread; | 1600 | struct thread *thread; |
1602 | u64 ip = event->ip.ip; | ||
1603 | u64 timestamp = -1; | ||
1604 | u32 cpu = -1; | ||
1605 | u64 period = 1; | ||
1606 | void *more_data = event->ip.__more_data; | ||
1607 | 1601 | ||
1608 | if (!(sample_type & PERF_SAMPLE_RAW)) | 1602 | if (!(sample_type & PERF_SAMPLE_RAW)) |
1609 | return 0; | 1603 | return 0; |
1610 | 1604 | ||
1611 | thread = threads__findnew(event->ip.pid); | 1605 | memset(&data, 0, sizeof(data)); |
1606 | data.time = -1; | ||
1607 | data.cpu = -1; | ||
1608 | data.period = -1; | ||
1612 | 1609 | ||
1613 | if (sample_type & PERF_SAMPLE_TIME) { | 1610 | event__parse_sample(event, sample_type, &data); |
1614 | timestamp = *(u64 *)more_data; | ||
1615 | more_data += sizeof(u64); | ||
1616 | } | ||
1617 | |||
1618 | if (sample_type & PERF_SAMPLE_CPU) { | ||
1619 | cpu = *(u32 *)more_data; | ||
1620 | more_data += sizeof(u32); | ||
1621 | more_data += sizeof(u32); /* reserved */ | ||
1622 | } | ||
1623 | |||
1624 | if (sample_type & PERF_SAMPLE_PERIOD) { | ||
1625 | period = *(u64 *)more_data; | ||
1626 | more_data += sizeof(u64); | ||
1627 | } | ||
1628 | 1611 | ||
1629 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 1612 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
1630 | event->header.misc, | 1613 | event->header.misc, |
1631 | event->ip.pid, event->ip.tid, | 1614 | data.pid, data.tid, |
1632 | (void *)(long)ip, | 1615 | (void *)(long)data.ip, |
1633 | (long long)period); | 1616 | (long long)data.period); |
1634 | 1617 | ||
1618 | thread = threads__findnew(data.pid); | ||
1635 | if (thread == NULL) { | 1619 | if (thread == NULL) { |
1636 | pr_debug("problem processing %d event, skipping it.\n", | 1620 | pr_debug("problem processing %d event, skipping it.\n", |
1637 | event->header.type); | 1621 | event->header.type); |
@@ -1640,10 +1624,10 @@ static int process_sample_event(event_t *event) | |||
1640 | 1624 | ||
1641 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 1625 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
1642 | 1626 | ||
1643 | if (profile_cpu != -1 && profile_cpu != (int) cpu) | 1627 | if (profile_cpu != -1 && profile_cpu != (int)data.cpu) |
1644 | return 0; | 1628 | return 0; |
1645 | 1629 | ||
1646 | process_raw_event(event, more_data, cpu, timestamp, thread); | 1630 | process_raw_event(event, data.raw_data, data.cpu, data.time, thread); |
1647 | 1631 | ||
1648 | return 0; | 1632 | return 0; |
1649 | } | 1633 | } |
@@ -1724,9 +1708,9 @@ static void __cmd_lat(void) | |||
1724 | read_events(); | 1708 | read_events(); |
1725 | sort_lat(); | 1709 | sort_lat(); |
1726 | 1710 | ||
1727 | printf("\n -----------------------------------------------------------------------------------------\n"); | 1711 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); |
1728 | printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); | 1712 | printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n"); |
1729 | printf(" -----------------------------------------------------------------------------------------\n"); | 1713 | printf(" ---------------------------------------------------------------------------------------------------------------\n"); |
1730 | 1714 | ||
1731 | next = rb_first(&sorted_atom_root); | 1715 | next = rb_first(&sorted_atom_root); |
1732 | 1716 | ||
@@ -1902,13 +1886,18 @@ static int __cmd_record(int argc, const char **argv) | |||
1902 | 1886 | ||
1903 | int cmd_sched(int argc, const char **argv, const char *prefix __used) | 1887 | int cmd_sched(int argc, const char **argv, const char *prefix __used) |
1904 | { | 1888 | { |
1905 | symbol__init(0); | ||
1906 | |||
1907 | argc = parse_options(argc, argv, sched_options, sched_usage, | 1889 | argc = parse_options(argc, argv, sched_options, sched_usage, |
1908 | PARSE_OPT_STOP_AT_NON_OPTION); | 1890 | PARSE_OPT_STOP_AT_NON_OPTION); |
1909 | if (!argc) | 1891 | if (!argc) |
1910 | usage_with_options(sched_usage, sched_options); | 1892 | usage_with_options(sched_usage, sched_options); |
1911 | 1893 | ||
1894 | /* | ||
1895 | * Aliased to 'perf trace' for now: | ||
1896 | */ | ||
1897 | if (!strcmp(argv[0], "trace")) | ||
1898 | return cmd_trace(argc, argv, prefix); | ||
1899 | |||
1900 | symbol__init(0); | ||
1912 | if (!strncmp(argv[0], "rec", 3)) { | 1901 | if (!strncmp(argv[0], "rec", 3)) { |
1913 | return __cmd_record(argc, argv); | 1902 | return __cmd_record(argc, argv); |
1914 | } else if (!strncmp(argv[0], "lat", 3)) { | 1903 | } else if (!strncmp(argv[0], "lat", 3)) { |
@@ -1932,11 +1921,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used) | |||
1932 | usage_with_options(replay_usage, replay_options); | 1921 | usage_with_options(replay_usage, replay_options); |
1933 | } | 1922 | } |
1934 | __cmd_replay(); | 1923 | __cmd_replay(); |
1935 | } else if (!strcmp(argv[0], "trace")) { | ||
1936 | /* | ||
1937 | * Aliased to 'perf trace' for now: | ||
1938 | */ | ||
1939 | return cmd_trace(argc, argv, prefix); | ||
1940 | } else { | 1924 | } else { |
1941 | usage_with_options(sched_usage, sched_options); | 1925 | usage_with_options(sched_usage, sched_options); |
1942 | } | 1926 | } |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index cb58b6605fcc..f472df9561ee 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -302,12 +302,11 @@ process_exit_event(event_t *event) | |||
302 | } | 302 | } |
303 | 303 | ||
304 | struct trace_entry { | 304 | struct trace_entry { |
305 | u32 size; | ||
306 | unsigned short type; | 305 | unsigned short type; |
307 | unsigned char flags; | 306 | unsigned char flags; |
308 | unsigned char preempt_count; | 307 | unsigned char preempt_count; |
309 | int pid; | 308 | int pid; |
310 | int tgid; | 309 | int lock_depth; |
311 | }; | 310 | }; |
312 | 311 | ||
313 | struct power_entry { | 312 | struct power_entry { |
@@ -484,43 +483,22 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
484 | static int | 483 | static int |
485 | process_sample_event(event_t *event) | 484 | process_sample_event(event_t *event) |
486 | { | 485 | { |
487 | int cursor = 0; | 486 | struct sample_data data; |
488 | u64 addr = 0; | ||
489 | u64 stamp = 0; | ||
490 | u32 cpu = 0; | ||
491 | u32 pid = 0; | ||
492 | struct trace_entry *te; | 487 | struct trace_entry *te; |
493 | 488 | ||
494 | if (sample_type & PERF_SAMPLE_IP) | 489 | memset(&data, 0, sizeof(data)); |
495 | cursor++; | ||
496 | |||
497 | if (sample_type & PERF_SAMPLE_TID) { | ||
498 | pid = event->sample.array[cursor]>>32; | ||
499 | cursor++; | ||
500 | } | ||
501 | if (sample_type & PERF_SAMPLE_TIME) { | ||
502 | stamp = event->sample.array[cursor++]; | ||
503 | 490 | ||
504 | if (!first_time || first_time > stamp) | 491 | event__parse_sample(event, sample_type, &data); |
505 | first_time = stamp; | ||
506 | if (last_time < stamp) | ||
507 | last_time = stamp; | ||
508 | 492 | ||
493 | if (sample_type & PERF_SAMPLE_TIME) { | ||
494 | if (!first_time || first_time > data.time) | ||
495 | first_time = data.time; | ||
496 | if (last_time < data.time) | ||
497 | last_time = data.time; | ||
509 | } | 498 | } |
510 | if (sample_type & PERF_SAMPLE_ADDR) | ||
511 | addr = event->sample.array[cursor++]; | ||
512 | if (sample_type & PERF_SAMPLE_ID) | ||
513 | cursor++; | ||
514 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
515 | cursor++; | ||
516 | if (sample_type & PERF_SAMPLE_CPU) | ||
517 | cpu = event->sample.array[cursor++] & 0xFFFFFFFF; | ||
518 | if (sample_type & PERF_SAMPLE_PERIOD) | ||
519 | cursor++; | ||
520 | |||
521 | te = (void *)&event->sample.array[cursor]; | ||
522 | 499 | ||
523 | if (sample_type & PERF_SAMPLE_RAW && te->size > 0) { | 500 | te = (void *)data.raw_data; |
501 | if (sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { | ||
524 | char *event_str; | 502 | char *event_str; |
525 | struct power_entry *pe; | 503 | struct power_entry *pe; |
526 | 504 | ||
@@ -532,19 +510,19 @@ process_sample_event(event_t *event) | |||
532 | return 0; | 510 | return 0; |
533 | 511 | ||
534 | if (strcmp(event_str, "power:power_start") == 0) | 512 | if (strcmp(event_str, "power:power_start") == 0) |
535 | c_state_start(cpu, stamp, pe->value); | 513 | c_state_start(data.cpu, data.time, pe->value); |
536 | 514 | ||
537 | if (strcmp(event_str, "power:power_end") == 0) | 515 | if (strcmp(event_str, "power:power_end") == 0) |
538 | c_state_end(cpu, stamp); | 516 | c_state_end(data.cpu, data.time); |
539 | 517 | ||
540 | if (strcmp(event_str, "power:power_frequency") == 0) | 518 | if (strcmp(event_str, "power:power_frequency") == 0) |
541 | p_state_change(cpu, stamp, pe->value); | 519 | p_state_change(data.cpu, data.time, pe->value); |
542 | 520 | ||
543 | if (strcmp(event_str, "sched:sched_wakeup") == 0) | 521 | if (strcmp(event_str, "sched:sched_wakeup") == 0) |
544 | sched_wakeup(cpu, stamp, pid, te); | 522 | sched_wakeup(data.cpu, data.time, data.pid, te); |
545 | 523 | ||
546 | if (strcmp(event_str, "sched:sched_switch") == 0) | 524 | if (strcmp(event_str, "sched:sched_switch") == 0) |
547 | sched_switch(cpu, stamp, te); | 525 | sched_switch(data.cpu, data.time, te); |
548 | } | 526 | } |
549 | return 0; | 527 | return 0; |
550 | } | 528 | } |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index abb914aa7be6..c2fcc34486f5 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -66,58 +66,40 @@ static u64 sample_type; | |||
66 | 66 | ||
67 | static int process_sample_event(event_t *event) | 67 | static int process_sample_event(event_t *event) |
68 | { | 68 | { |
69 | u64 ip = event->ip.ip; | 69 | struct sample_data data; |
70 | u64 timestamp = -1; | 70 | struct thread *thread; |
71 | u32 cpu = -1; | ||
72 | u64 period = 1; | ||
73 | void *more_data = event->ip.__more_data; | ||
74 | struct thread *thread = threads__findnew(event->ip.pid); | ||
75 | |||
76 | if (sample_type & PERF_SAMPLE_TIME) { | ||
77 | timestamp = *(u64 *)more_data; | ||
78 | more_data += sizeof(u64); | ||
79 | } | ||
80 | 71 | ||
81 | if (sample_type & PERF_SAMPLE_CPU) { | 72 | memset(&data, 0, sizeof(data)); |
82 | cpu = *(u32 *)more_data; | 73 | data.time = -1; |
83 | more_data += sizeof(u32); | 74 | data.cpu = -1; |
84 | more_data += sizeof(u32); /* reserved */ | 75 | data.period = 1; |
85 | } | ||
86 | 76 | ||
87 | if (sample_type & PERF_SAMPLE_PERIOD) { | 77 | event__parse_sample(event, sample_type, &data); |
88 | period = *(u64 *)more_data; | ||
89 | more_data += sizeof(u64); | ||
90 | } | ||
91 | 78 | ||
92 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", | 79 | dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", |
93 | event->header.misc, | 80 | event->header.misc, |
94 | event->ip.pid, event->ip.tid, | 81 | data.pid, data.tid, |
95 | (void *)(long)ip, | 82 | (void *)(long)data.ip, |
96 | (long long)period); | 83 | (long long)data.period); |
97 | 84 | ||
85 | thread = threads__findnew(event->ip.pid); | ||
98 | if (thread == NULL) { | 86 | if (thread == NULL) { |
99 | pr_debug("problem processing %d event, skipping it.\n", | 87 | pr_debug("problem processing %d event, skipping it.\n", |
100 | event->header.type); | 88 | event->header.type); |
101 | return -1; | 89 | return -1; |
102 | } | 90 | } |
103 | 91 | ||
104 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | ||
105 | |||
106 | if (sample_type & PERF_SAMPLE_RAW) { | 92 | if (sample_type & PERF_SAMPLE_RAW) { |
107 | struct { | ||
108 | u32 size; | ||
109 | char data[0]; | ||
110 | } *raw = more_data; | ||
111 | |||
112 | /* | 93 | /* |
113 | * FIXME: better resolve from pid from the struct trace_entry | 94 | * FIXME: better resolve from pid from the struct trace_entry |
114 | * field, although it should be the same than this perf | 95 | * field, although it should be the same than this perf |
115 | * event pid | 96 | * event pid |
116 | */ | 97 | */ |
117 | scripting_ops->process_event(cpu, raw->data, raw->size, | 98 | scripting_ops->process_event(data.cpu, data.raw_data, |
118 | timestamp, thread->comm); | 99 | data.raw_size, |
100 | data.time, thread->comm); | ||
119 | } | 101 | } |
120 | event__stats.total += period; | 102 | event__stats.total += data.period; |
121 | 103 | ||
122 | return 0; | 104 | return 0; |
123 | } | 105 | } |
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index ca0bedf637c2..59b65d0bd7c1 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c | |||
@@ -100,11 +100,11 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
100 | } | 100 | } |
101 | } | 101 | } |
102 | 102 | ||
103 | int perf_header__read_build_ids(int input, off_t offset, off_t size) | 103 | int perf_header__read_build_ids(int input, u64 offset, u64 size) |
104 | { | 104 | { |
105 | struct build_id_event bev; | 105 | struct build_id_event bev; |
106 | char filename[PATH_MAX]; | 106 | char filename[PATH_MAX]; |
107 | off_t limit = offset + size; | 107 | u64 limit = offset + size; |
108 | int err = -1; | 108 | int err = -1; |
109 | 109 | ||
110 | while (offset < limit) { | 110 | while (offset < limit) { |
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index 3180ff7e3633..258a87bcc4fb 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h | |||
@@ -27,6 +27,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, | |||
27 | int full_paths, | 27 | int full_paths, |
28 | int *cwdlen, | 28 | int *cwdlen, |
29 | char **cwd); | 29 | char **cwd); |
30 | int perf_header__read_build_ids(int input, off_t offset, off_t file_size); | 30 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); |
31 | 31 | ||
32 | #endif | 32 | #endif |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 414b89d1bde9..4dcecafa85dc 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -310,3 +310,70 @@ int event__preprocess_sample(const event_t *self, struct addr_location *al, | |||
310 | al->level == 'H' ? "[hypervisor]" : "<not found>"); | 310 | al->level == 'H' ? "[hypervisor]" : "<not found>"); |
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | |||
314 | int event__parse_sample(event_t *event, u64 type, struct sample_data *data) | ||
315 | { | ||
316 | u64 *array = event->sample.array; | ||
317 | |||
318 | if (type & PERF_SAMPLE_IP) { | ||
319 | data->ip = event->ip.ip; | ||
320 | array++; | ||
321 | } | ||
322 | |||
323 | if (type & PERF_SAMPLE_TID) { | ||
324 | u32 *p = (u32 *)array; | ||
325 | data->pid = p[0]; | ||
326 | data->tid = p[1]; | ||
327 | array++; | ||
328 | } | ||
329 | |||
330 | if (type & PERF_SAMPLE_TIME) { | ||
331 | data->time = *array; | ||
332 | array++; | ||
333 | } | ||
334 | |||
335 | if (type & PERF_SAMPLE_ADDR) { | ||
336 | data->addr = *array; | ||
337 | array++; | ||
338 | } | ||
339 | |||
340 | if (type & PERF_SAMPLE_ID) { | ||
341 | data->id = *array; | ||
342 | array++; | ||
343 | } | ||
344 | |||
345 | if (type & PERF_SAMPLE_STREAM_ID) { | ||
346 | data->stream_id = *array; | ||
347 | array++; | ||
348 | } | ||
349 | |||
350 | if (type & PERF_SAMPLE_CPU) { | ||
351 | u32 *p = (u32 *)array; | ||
352 | data->cpu = *p; | ||
353 | array++; | ||
354 | } | ||
355 | |||
356 | if (type & PERF_SAMPLE_PERIOD) { | ||
357 | data->period = *array; | ||
358 | array++; | ||
359 | } | ||
360 | |||
361 | if (type & PERF_SAMPLE_READ) { | ||
362 | pr_debug("PERF_SAMPLE_READ is unsuported for now\n"); | ||
363 | return -1; | ||
364 | } | ||
365 | |||
366 | if (type & PERF_SAMPLE_CALLCHAIN) { | ||
367 | data->callchain = (struct ip_callchain *)array; | ||
368 | array += 1 + data->callchain->nr; | ||
369 | } | ||
370 | |||
371 | if (type & PERF_SAMPLE_RAW) { | ||
372 | u32 *p = (u32 *)array; | ||
373 | data->raw_size = *p; | ||
374 | p++; | ||
375 | data->raw_data = p; | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | } | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index a4cc8105cf67..c7a78eef8e52 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -56,11 +56,25 @@ struct read_event { | |||
56 | u64 id; | 56 | u64 id; |
57 | }; | 57 | }; |
58 | 58 | ||
59 | struct sample_event{ | 59 | struct sample_event { |
60 | struct perf_event_header header; | 60 | struct perf_event_header header; |
61 | u64 array[]; | 61 | u64 array[]; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | struct sample_data { | ||
65 | u64 ip; | ||
66 | u32 pid, tid; | ||
67 | u64 time; | ||
68 | u64 addr; | ||
69 | u64 id; | ||
70 | u64 stream_id; | ||
71 | u32 cpu; | ||
72 | u64 period; | ||
73 | struct ip_callchain *callchain; | ||
74 | u32 raw_size; | ||
75 | void *raw_data; | ||
76 | }; | ||
77 | |||
64 | #define BUILD_ID_SIZE 20 | 78 | #define BUILD_ID_SIZE 20 |
65 | 79 | ||
66 | struct build_id_event { | 80 | struct build_id_event { |
@@ -155,5 +169,6 @@ int event__process_task(event_t *self); | |||
155 | struct addr_location; | 169 | struct addr_location; |
156 | int event__preprocess_sample(const event_t *self, struct addr_location *al, | 170 | int event__preprocess_sample(const event_t *self, struct addr_location *al, |
157 | symbol_filter_t filter); | 171 | symbol_filter_t filter); |
172 | int event__parse_sample(event_t *event, u64 type, struct sample_data *data); | ||
158 | 173 | ||
159 | #endif /* __PERF_RECORD_H */ | 174 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 4805e6dfd23c..59a9c0b3033e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -187,7 +187,9 @@ static int do_write(int fd, const void *buf, size_t size) | |||
187 | 187 | ||
188 | static int __dsos__write_buildid_table(struct list_head *head, int fd) | 188 | static int __dsos__write_buildid_table(struct list_head *head, int fd) |
189 | { | 189 | { |
190 | #define NAME_ALIGN 64 | ||
190 | struct dso *pos; | 191 | struct dso *pos; |
192 | static const char zero_buf[NAME_ALIGN]; | ||
191 | 193 | ||
192 | list_for_each_entry(pos, head, node) { | 194 | list_for_each_entry(pos, head, node) { |
193 | int err; | 195 | int err; |
@@ -197,14 +199,17 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd) | |||
197 | if (!pos->has_build_id) | 199 | if (!pos->has_build_id) |
198 | continue; | 200 | continue; |
199 | len = pos->long_name_len + 1; | 201 | len = pos->long_name_len + 1; |
200 | len = ALIGN(len, 64); | 202 | len = ALIGN(len, NAME_ALIGN); |
201 | memset(&b, 0, sizeof(b)); | 203 | memset(&b, 0, sizeof(b)); |
202 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); | 204 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); |
203 | b.header.size = sizeof(b) + len; | 205 | b.header.size = sizeof(b) + len; |
204 | err = do_write(fd, &b, sizeof(b)); | 206 | err = do_write(fd, &b, sizeof(b)); |
205 | if (err < 0) | 207 | if (err < 0) |
206 | return err; | 208 | return err; |
207 | err = do_write(fd, pos->long_name, len); | 209 | err = do_write(fd, pos->long_name, pos->long_name_len + 1); |
210 | if (err < 0) | ||
211 | return err; | ||
212 | err = do_write(fd, zero_buf, len - pos->long_name_len - 1); | ||
208 | if (err < 0) | 213 | if (err < 0) |
209 | return err; | 214 | return err; |
210 | } | 215 | } |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 9e5dbd66d34d..e5bc0fb016b2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
197 | if (id == config) { | 197 | if (id == config) { |
198 | closedir(evt_dir); | 198 | closedir(evt_dir); |
199 | closedir(sys_dir); | 199 | closedir(sys_dir); |
200 | path = zalloc(sizeof(path)); | 200 | path = zalloc(sizeof(*path)); |
201 | path->system = malloc(MAX_EVENT_LENGTH); | 201 | path->system = malloc(MAX_EVENT_LENGTH); |
202 | if (!path->system) { | 202 | if (!path->system) { |
203 | free(path); | 203 | free(path); |
@@ -467,7 +467,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags) | |||
467 | while ((evt_ent = readdir(evt_dir))) { | 467 | while ((evt_ent = readdir(evt_dir))) { |
468 | char event_opt[MAX_EVOPT_LEN + 1]; | 468 | char event_opt[MAX_EVOPT_LEN + 1]; |
469 | int len; | 469 | int len; |
470 | unsigned int rem = MAX_EVOPT_LEN; | ||
471 | 470 | ||
472 | if (!strcmp(evt_ent->d_name, ".") | 471 | if (!strcmp(evt_ent->d_name, ".") |
473 | || !strcmp(evt_ent->d_name, "..") | 472 | || !strcmp(evt_ent->d_name, "..") |
@@ -475,20 +474,12 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags) | |||
475 | || !strcmp(evt_ent->d_name, "filter")) | 474 | || !strcmp(evt_ent->d_name, "filter")) |
476 | continue; | 475 | continue; |
477 | 476 | ||
478 | len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, | 477 | len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, |
479 | evt_ent->d_name); | 478 | evt_ent->d_name, flags ? ":" : "", |
479 | flags ?: ""); | ||
480 | if (len < 0) | 480 | if (len < 0) |
481 | return EVT_FAILED; | 481 | return EVT_FAILED; |
482 | 482 | ||
483 | rem -= len; | ||
484 | if (flags) { | ||
485 | if (rem < strlen(flags) + 1) | ||
486 | return EVT_FAILED; | ||
487 | |||
488 | strcat(event_opt, ":"); | ||
489 | strcat(event_opt, flags); | ||
490 | } | ||
491 | |||
492 | if (parse_events(NULL, event_opt, 0)) | 483 | if (parse_events(NULL, event_opt, 0)) |
493 | return EVT_FAILED; | 484 | return EVT_FAILED; |
494 | } | 485 | } |
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 6d8af48c925e..efebd5b476b3 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
@@ -430,6 +430,9 @@ int usage_with_options_internal(const char * const *usagestr, | |||
430 | pos = fprintf(stderr, " "); | 430 | pos = fprintf(stderr, " "); |
431 | if (opts->short_name) | 431 | if (opts->short_name) |
432 | pos += fprintf(stderr, "-%c", opts->short_name); | 432 | pos += fprintf(stderr, "-%c", opts->short_name); |
433 | else | ||
434 | pos += fprintf(stderr, " "); | ||
435 | |||
433 | if (opts->long_name && opts->short_name) | 436 | if (opts->long_name && opts->short_name) |
434 | pos += fprintf(stderr, ", "); | 437 | pos += fprintf(stderr, ", "); |
435 | if (opts->long_name) | 438 | if (opts->long_name) |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index cd7fbda5e2a5..d14a4585bcaf 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -48,6 +48,9 @@ | |||
48 | 48 | ||
49 | /* If there is no space to write, returns -E2BIG. */ | 49 | /* If there is no space to write, returns -E2BIG. */ |
50 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 50 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
51 | __attribute__((format(printf, 3, 4))); | ||
52 | |||
53 | static int e_snprintf(char *str, size_t size, const char *format, ...) | ||
51 | { | 54 | { |
52 | int ret; | 55 | int ret; |
53 | va_list ap; | 56 | va_list ap; |
@@ -258,7 +261,7 @@ int synthesize_perf_probe_event(struct probe_point *pp) | |||
258 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, | 261 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, |
259 | offs, pp->retprobe ? "%return" : "", line); | 262 | offs, pp->retprobe ? "%return" : "", line); |
260 | else | 263 | else |
261 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line); | 264 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); |
262 | if (ret <= 0) | 265 | if (ret <= 0) |
263 | goto error; | 266 | goto error; |
264 | len = ret; | 267 | len = ret; |
@@ -373,14 +376,32 @@ static void clear_probe_point(struct probe_point *pp) | |||
373 | free(pp->args); | 376 | free(pp->args); |
374 | for (i = 0; i < pp->found; i++) | 377 | for (i = 0; i < pp->found; i++) |
375 | free(pp->probes[i]); | 378 | free(pp->probes[i]); |
376 | memset(pp, 0, sizeof(pp)); | 379 | memset(pp, 0, sizeof(*pp)); |
380 | } | ||
381 | |||
382 | /* Show an event */ | ||
383 | static void show_perf_probe_event(const char *group, const char *event, | ||
384 | const char *place, struct probe_point *pp) | ||
385 | { | ||
386 | int i; | ||
387 | char buf[128]; | ||
388 | |||
389 | e_snprintf(buf, 128, "%s:%s", group, event); | ||
390 | printf(" %-40s (on %s", buf, place); | ||
391 | |||
392 | if (pp->nr_args > 0) { | ||
393 | printf(" with"); | ||
394 | for (i = 0; i < pp->nr_args; i++) | ||
395 | printf(" %s", pp->args[i]); | ||
396 | } | ||
397 | printf(")\n"); | ||
377 | } | 398 | } |
378 | 399 | ||
379 | /* List up current perf-probe events */ | 400 | /* List up current perf-probe events */ |
380 | void show_perf_probe_events(void) | 401 | void show_perf_probe_events(void) |
381 | { | 402 | { |
382 | unsigned int i; | 403 | unsigned int i; |
383 | int fd; | 404 | int fd, nr; |
384 | char *group, *event; | 405 | char *group, *event; |
385 | struct probe_point pp; | 406 | struct probe_point pp; |
386 | struct strlist *rawlist; | 407 | struct strlist *rawlist; |
@@ -393,8 +414,13 @@ void show_perf_probe_events(void) | |||
393 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { | 414 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { |
394 | ent = strlist__entry(rawlist, i); | 415 | ent = strlist__entry(rawlist, i); |
395 | parse_trace_kprobe_event(ent->s, &group, &event, &pp); | 416 | parse_trace_kprobe_event(ent->s, &group, &event, &pp); |
417 | /* Synthesize only event probe point */ | ||
418 | nr = pp.nr_args; | ||
419 | pp.nr_args = 0; | ||
396 | synthesize_perf_probe_event(&pp); | 420 | synthesize_perf_probe_event(&pp); |
397 | printf("[%s:%s]\t%s\n", group, event, pp.probes[0]); | 421 | pp.nr_args = nr; |
422 | /* Show an event */ | ||
423 | show_perf_probe_event(group, event, pp.probes[0], &pp); | ||
398 | free(group); | 424 | free(group); |
399 | free(event); | 425 | free(event); |
400 | clear_probe_point(&pp); | 426 | clear_probe_point(&pp); |
@@ -404,21 +430,28 @@ void show_perf_probe_events(void) | |||
404 | } | 430 | } |
405 | 431 | ||
406 | /* Get current perf-probe event names */ | 432 | /* Get current perf-probe event names */ |
407 | static struct strlist *get_perf_event_names(int fd) | 433 | static struct strlist *get_perf_event_names(int fd, bool include_group) |
408 | { | 434 | { |
409 | unsigned int i; | 435 | unsigned int i; |
410 | char *group, *event; | 436 | char *group, *event; |
437 | char buf[128]; | ||
411 | struct strlist *sl, *rawlist; | 438 | struct strlist *sl, *rawlist; |
412 | struct str_node *ent; | 439 | struct str_node *ent; |
413 | 440 | ||
414 | rawlist = get_trace_kprobe_event_rawlist(fd); | 441 | rawlist = get_trace_kprobe_event_rawlist(fd); |
415 | 442 | ||
416 | sl = strlist__new(false, NULL); | 443 | sl = strlist__new(true, NULL); |
417 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { | 444 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { |
418 | ent = strlist__entry(rawlist, i); | 445 | ent = strlist__entry(rawlist, i); |
419 | parse_trace_kprobe_event(ent->s, &group, &event, NULL); | 446 | parse_trace_kprobe_event(ent->s, &group, &event, NULL); |
420 | strlist__add(sl, event); | 447 | if (include_group) { |
448 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | ||
449 | die("Failed to copy group:event name."); | ||
450 | strlist__add(sl, buf); | ||
451 | } else | ||
452 | strlist__add(sl, event); | ||
421 | free(group); | 453 | free(group); |
454 | free(event); | ||
422 | } | 455 | } |
423 | 456 | ||
424 | strlist__delete(rawlist); | 457 | strlist__delete(rawlist); |
@@ -426,24 +459,30 @@ static struct strlist *get_perf_event_names(int fd) | |||
426 | return sl; | 459 | return sl; |
427 | } | 460 | } |
428 | 461 | ||
429 | static int write_trace_kprobe_event(int fd, const char *buf) | 462 | static void write_trace_kprobe_event(int fd, const char *buf) |
430 | { | 463 | { |
431 | int ret; | 464 | int ret; |
432 | 465 | ||
466 | pr_debug("Writing event: %s\n", buf); | ||
433 | ret = write(fd, buf, strlen(buf)); | 467 | ret = write(fd, buf, strlen(buf)); |
434 | if (ret <= 0) | 468 | if (ret <= 0) |
435 | die("Failed to create event."); | 469 | die("Failed to write event: %s", strerror(errno)); |
436 | else | ||
437 | printf("Added new event: %s\n", buf); | ||
438 | |||
439 | return ret; | ||
440 | } | 470 | } |
441 | 471 | ||
442 | static void get_new_event_name(char *buf, size_t len, const char *base, | 472 | static void get_new_event_name(char *buf, size_t len, const char *base, |
443 | struct strlist *namelist) | 473 | struct strlist *namelist) |
444 | { | 474 | { |
445 | int i, ret; | 475 | int i, ret; |
446 | for (i = 0; i < MAX_EVENT_INDEX; i++) { | 476 | |
477 | /* Try no suffix */ | ||
478 | ret = e_snprintf(buf, len, "%s", base); | ||
479 | if (ret < 0) | ||
480 | die("snprintf() failed: %s", strerror(-ret)); | ||
481 | if (!strlist__has_entry(namelist, buf)) | ||
482 | return; | ||
483 | |||
484 | /* Try to add suffix */ | ||
485 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | ||
447 | ret = e_snprintf(buf, len, "%s_%d", base, i); | 486 | ret = e_snprintf(buf, len, "%s_%d", base, i); |
448 | if (ret < 0) | 487 | if (ret < 0) |
449 | die("snprintf() failed: %s", strerror(-ret)); | 488 | die("snprintf() failed: %s", strerror(-ret)); |
@@ -464,7 +503,7 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) | |||
464 | 503 | ||
465 | fd = open_kprobe_events(O_RDWR, O_APPEND); | 504 | fd = open_kprobe_events(O_RDWR, O_APPEND); |
466 | /* Get current event names */ | 505 | /* Get current event names */ |
467 | namelist = get_perf_event_names(fd); | 506 | namelist = get_perf_event_names(fd, false); |
468 | 507 | ||
469 | for (j = 0; j < nr_probes; j++) { | 508 | for (j = 0; j < nr_probes; j++) { |
470 | pp = probes + j; | 509 | pp = probes + j; |
@@ -476,9 +515,73 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) | |||
476 | PERFPROBE_GROUP, event, | 515 | PERFPROBE_GROUP, event, |
477 | pp->probes[i]); | 516 | pp->probes[i]); |
478 | write_trace_kprobe_event(fd, buf); | 517 | write_trace_kprobe_event(fd, buf); |
518 | printf("Added new event:\n"); | ||
519 | /* Get the first parameter (probe-point) */ | ||
520 | sscanf(pp->probes[i], "%s", buf); | ||
521 | show_perf_probe_event(PERFPROBE_GROUP, event, | ||
522 | buf, pp); | ||
479 | /* Add added event name to namelist */ | 523 | /* Add added event name to namelist */ |
480 | strlist__add(namelist, event); | 524 | strlist__add(namelist, event); |
481 | } | 525 | } |
482 | } | 526 | } |
527 | /* Show how to use the event. */ | ||
528 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | ||
529 | printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); | ||
530 | |||
531 | strlist__delete(namelist); | ||
532 | close(fd); | ||
533 | } | ||
534 | |||
535 | static void del_trace_kprobe_event(int fd, const char *group, | ||
536 | const char *event, struct strlist *namelist) | ||
537 | { | ||
538 | char buf[128]; | ||
539 | |||
540 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | ||
541 | die("Failed to copy event."); | ||
542 | if (!strlist__has_entry(namelist, buf)) { | ||
543 | pr_warning("Warning: event \"%s\" is not found.\n", buf); | ||
544 | return; | ||
545 | } | ||
546 | /* Convert from perf-probe event to trace-kprobe event */ | ||
547 | if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0) | ||
548 | die("Failed to copy event."); | ||
549 | |||
550 | write_trace_kprobe_event(fd, buf); | ||
551 | printf("Remove event: %s:%s\n", group, event); | ||
552 | } | ||
553 | |||
554 | void del_trace_kprobe_events(struct strlist *dellist) | ||
555 | { | ||
556 | int fd; | ||
557 | unsigned int i; | ||
558 | const char *group, *event; | ||
559 | char *p, *str; | ||
560 | struct str_node *ent; | ||
561 | struct strlist *namelist; | ||
562 | |||
563 | fd = open_kprobe_events(O_RDWR, O_APPEND); | ||
564 | /* Get current event names */ | ||
565 | namelist = get_perf_event_names(fd, true); | ||
566 | |||
567 | for (i = 0; i < strlist__nr_entries(dellist); i++) { | ||
568 | ent = strlist__entry(dellist, i); | ||
569 | str = strdup(ent->s); | ||
570 | if (!str) | ||
571 | die("Failed to copy event."); | ||
572 | p = strchr(str, ':'); | ||
573 | if (p) { | ||
574 | group = str; | ||
575 | *p = '\0'; | ||
576 | event = p + 1; | ||
577 | } else { | ||
578 | group = PERFPROBE_GROUP; | ||
579 | event = str; | ||
580 | } | ||
581 | del_trace_kprobe_event(fd, group, event, namelist); | ||
582 | free(str); | ||
583 | } | ||
584 | strlist__delete(namelist); | ||
483 | close(fd); | 585 | close(fd); |
484 | } | 586 | } |
587 | |||
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 0c6fe56fe38a..f752159124ae 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -10,6 +10,7 @@ extern void parse_trace_kprobe_event(const char *str, char **group, | |||
10 | char **event, struct probe_point *pp); | 10 | char **event, struct probe_point *pp); |
11 | extern int synthesize_trace_kprobe_event(struct probe_point *pp); | 11 | extern int synthesize_trace_kprobe_event(struct probe_point *pp); |
12 | extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); | 12 | extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); |
13 | extern void del_trace_kprobe_events(struct strlist *dellist); | ||
13 | extern void show_perf_probe_events(void); | 14 | extern void show_perf_probe_events(void); |
14 | 15 | ||
15 | /* Maximum index number of event-name postfix */ | 16 | /* Maximum index number of event-name postfix */ |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 293cdfc1b8ca..4585f1d86792 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -106,7 +106,7 @@ static int strtailcmp(const char *s1, const char *s2) | |||
106 | { | 106 | { |
107 | int i1 = strlen(s1); | 107 | int i1 = strlen(s1); |
108 | int i2 = strlen(s2); | 108 | int i2 = strlen(s2); |
109 | while (--i1 > 0 && --i2 > 0) { | 109 | while (--i1 >= 0 && --i2 >= 0) { |
110 | if (s1[i1] != s2[i2]) | 110 | if (s1[i1] != s2[i2]) |
111 | return s1[i1] - s2[i2]; | 111 | return s1[i1] - s2[i2]; |
112 | } | 112 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index fffcb937cdcb..e7508ad3450f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -938,8 +938,9 @@ static bool __dsos__read_build_ids(struct list_head *head) | |||
938 | 938 | ||
939 | bool dsos__read_build_ids(void) | 939 | bool dsos__read_build_ids(void) |
940 | { | 940 | { |
941 | return __dsos__read_build_ids(&dsos__kernel) || | 941 | bool kbuildids = __dsos__read_build_ids(&dsos__kernel), |
942 | __dsos__read_build_ids(&dsos__user); | 942 | ubuildids = __dsos__read_build_ids(&dsos__user); |
943 | return kbuildids || ubuildids; | ||
943 | } | 944 | } |
944 | 945 | ||
945 | /* | 946 | /* |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0302405aa2ca..c5c32be040bf 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -177,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused) | |||
177 | func_count++; | 177 | func_count++; |
178 | } | 178 | } |
179 | 179 | ||
180 | func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); | 180 | func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1)); |
181 | 181 | ||
182 | i = 0; | 182 | i = 0; |
183 | while (list) { | 183 | while (list) { |
@@ -1477,7 +1477,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok) | |||
1477 | goto out_free; | 1477 | goto out_free; |
1478 | 1478 | ||
1479 | field = malloc_or_die(sizeof(*field)); | 1479 | field = malloc_or_die(sizeof(*field)); |
1480 | memset(field, 0, sizeof(field)); | 1480 | memset(field, 0, sizeof(*field)); |
1481 | 1481 | ||
1482 | value = arg_eval(arg); | 1482 | value = arg_eval(arg); |
1483 | field->value = strdup(value); | 1483 | field->value = strdup(value); |
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c index 51e833fd58c3..a5ffe60db5d6 100644 --- a/tools/perf/util/trace-event-perl.c +++ b/tools/perf/util/trace-event-perl.c | |||
@@ -32,9 +32,6 @@ | |||
32 | 32 | ||
33 | void xs_init(pTHX); | 33 | void xs_init(pTHX); |
34 | 34 | ||
35 | void boot_Perf__Trace__Context(pTHX_ CV *cv); | ||
36 | void boot_DynaLoader(pTHX_ CV *cv); | ||
37 | |||
38 | void xs_init(pTHX) | 35 | void xs_init(pTHX) |
39 | { | 36 | { |
40 | const char *file = __FILE__; | 37 | const char *file = __FILE__; |
@@ -573,26 +570,72 @@ struct scripting_ops perl_scripting_ops = { | |||
573 | .generate_script = perl_generate_script, | 570 | .generate_script = perl_generate_script, |
574 | }; | 571 | }; |
575 | 572 | ||
576 | #ifdef NO_LIBPERL | 573 | static void print_unsupported_msg(void) |
577 | void setup_perl_scripting(void) | ||
578 | { | 574 | { |
579 | fprintf(stderr, "Perl scripting not supported." | 575 | fprintf(stderr, "Perl scripting not supported." |
580 | " Install libperl and rebuild perf to enable it. e.g. " | 576 | " Install libperl and rebuild perf to enable it.\n" |
581 | "apt-get install libperl-dev (ubuntu), yum install " | 577 | "For example:\n # apt-get install libperl-dev (ubuntu)" |
582 | "perl-ExtUtils-Embed (Fedora), etc.\n"); | 578 | "\n # yum install perl-ExtUtils-Embed (Fedora)" |
579 | "\n etc.\n"); | ||
583 | } | 580 | } |
584 | #else | 581 | |
585 | void setup_perl_scripting(void) | 582 | static int perl_start_script_unsupported(const char *script __unused) |
583 | { | ||
584 | print_unsupported_msg(); | ||
585 | |||
586 | return -1; | ||
587 | } | ||
588 | |||
589 | static int perl_stop_script_unsupported(void) | ||
590 | { | ||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | static void perl_process_event_unsupported(int cpu __unused, | ||
595 | void *data __unused, | ||
596 | int size __unused, | ||
597 | unsigned long long nsecs __unused, | ||
598 | char *comm __unused) | ||
599 | { | ||
600 | } | ||
601 | |||
602 | static int perl_generate_script_unsupported(const char *outfile __unused) | ||
603 | { | ||
604 | print_unsupported_msg(); | ||
605 | |||
606 | return -1; | ||
607 | } | ||
608 | |||
609 | struct scripting_ops perl_scripting_unsupported_ops = { | ||
610 | .name = "Perl", | ||
611 | .start_script = perl_start_script_unsupported, | ||
612 | .stop_script = perl_stop_script_unsupported, | ||
613 | .process_event = perl_process_event_unsupported, | ||
614 | .generate_script = perl_generate_script_unsupported, | ||
615 | }; | ||
616 | |||
617 | static void register_perl_scripting(struct scripting_ops *scripting_ops) | ||
586 | { | 618 | { |
587 | int err; | 619 | int err; |
588 | err = script_spec_register("Perl", &perl_scripting_ops); | 620 | err = script_spec_register("Perl", scripting_ops); |
589 | if (err) | 621 | if (err) |
590 | die("error registering Perl script extension"); | 622 | die("error registering Perl script extension"); |
591 | 623 | ||
592 | err = script_spec_register("pl", &perl_scripting_ops); | 624 | err = script_spec_register("pl", scripting_ops); |
593 | if (err) | 625 | if (err) |
594 | die("error registering pl script extension"); | 626 | die("error registering pl script extension"); |
595 | 627 | ||
596 | scripting_context = malloc(sizeof(struct scripting_context)); | 628 | scripting_context = malloc(sizeof(struct scripting_context)); |
597 | } | 629 | } |
630 | |||
631 | #ifdef NO_LIBPERL | ||
632 | void setup_perl_scripting(void) | ||
633 | { | ||
634 | register_perl_scripting(&perl_scripting_unsupported_ops); | ||
635 | } | ||
636 | #else | ||
637 | void setup_perl_scripting(void) | ||
638 | { | ||
639 | register_perl_scripting(&perl_scripting_ops); | ||
640 | } | ||
598 | #endif | 641 | #endif |
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h index 8fe0d866fe1a..e88fb26137bb 100644 --- a/tools/perf/util/trace-event-perl.h +++ b/tools/perf/util/trace-event-perl.h | |||
@@ -34,9 +34,13 @@ typedef int INTERP; | |||
34 | #define dXSUB_SYS | 34 | #define dXSUB_SYS |
35 | #define pTHX_ | 35 | #define pTHX_ |
36 | static inline void newXS(const char *a, void *b, const char *c) {} | 36 | static inline void newXS(const char *a, void *b, const char *c) {} |
37 | static void boot_Perf__Trace__Context(pTHX_ CV *cv) {} | ||
38 | static void boot_DynaLoader(pTHX_ CV *cv) {} | ||
37 | #else | 39 | #else |
38 | #include <EXTERN.h> | 40 | #include <EXTERN.h> |
39 | #include <perl.h> | 41 | #include <perl.h> |
42 | void boot_Perf__Trace__Context(pTHX_ CV *cv); | ||
43 | void boot_DynaLoader(pTHX_ CV *cv); | ||
40 | typedef PerlInterpreter * INTERP; | 44 | typedef PerlInterpreter * INTERP; |
41 | #endif | 45 | #endif |
42 | 46 | ||
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 342dfdd43f87..1744422cafcb 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -145,8 +145,9 @@ static void read_proc_kallsyms(void) | |||
145 | if (!size) | 145 | if (!size) |
146 | return; | 146 | return; |
147 | 147 | ||
148 | buf = malloc_or_die(size); | 148 | buf = malloc_or_die(size + 1); |
149 | read_or_die(buf, size); | 149 | read_or_die(buf, size); |
150 | buf[size] = '\0'; | ||
150 | 151 | ||
151 | parse_proc_kallsyms(buf, size); | 152 | parse_proc_kallsyms(buf, size); |
152 | 153 | ||