Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Pull perf updates from Ingo Molnar:
"Features:

- Add "uretprobes" - an optimization to uprobes, like kretprobes are
an optimization to kprobes. "perf probe -x file sym%return" now
works like kretprobes. By Oleg Nesterov.

- Introduce per core aggregation in 'perf stat', from Stephane
Eranian.

- Add memory profiling via PEBS, from Stephane Eranian.

- Event group view for 'annotate' in --stdio, --tui and --gtk, from
Namhyung Kim.

- Add support for AMD NB and L2I "uncore" counters, by Jacob Shin.

- Add Ivy Bridge-EP uncore support, by Zheng Yan

- IBM zEnterprise EC12 oprofile support patchlet from Robert Richter.

- Add perf test entries for checking breakpoint overflow signal
handler issues, from Jiri Olsa.

- Add perf test entry for for checking number of EXIT events, from
Namhyung Kim.

- Add perf test entries for checking --cpu in record and stat, from
Jiri Olsa.

- Introduce perf stat --repeat forever, from Frederik Deweerdt.

- Add --no-demangle to report/top, from Namhyung Kim.

- PowerPC fixes plus a couple of cleanups/optimizations in uprobes
and trace_uprobes, by Oleg Nesterov.

Various fixes and refactorings:

- Fix dependency of the python binding wrt libtraceevent, from
Naohiro Aota.

- Simplify some perf_evlist methods and to allow 'stat' to share code
with 'record' and 'trace', by Arnaldo Carvalho de Melo.

- Remove dead code in related to libtraceevent integration, from
Namhyung Kim.

- Revert "perf sched: Handle PERF_RECORD_EXIT events" to get 'perf
sched lat' back working, by Arnaldo Carvalho de Melo

- We don't use Newt anymore, just plain libslang, by Arnaldo Carvalho
de Melo.

- Kill a bunch of die() calls, from Namhyung Kim.

- Fix build on non-glibc systems due to libio.h absence, from Cody P
Schafer.

- Remove some perf_session and tracing dead code, from David Ahern.

- Honor parallel jobs, fix from Borislav Petkov

- Introduce tools/lib/lk library, initially just removing duplication
among tools/perf and tools/vm. from Borislav Petkov

... and many more I missed to list, see the shortlog and git log for
more details."

* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (136 commits)
perf/x86/intel/P4: Robistify P4 PMU types
perf/x86/amd: Fix AMD NB and L2I "uncore" support
perf/x86/amd: Remove old-style NB counter support from perf_event_amd.c
perf/x86: Check all MSRs before passing hw check
perf/x86/amd: Add support for AMD NB and L2I "uncore" counters
perf/x86/intel: Add Ivy Bridge-EP uncore support
perf/x86/intel: Fix SNB-EP CBO and PCU uncore PMU filter management
perf/x86: Avoid kfree() in CPU_{STARTING,DYING}
uprobes/perf: Avoid perf_trace_buf_prepare/submit if ->perf_events is empty
uprobes/tracing: Don't pass addr=ip to perf_trace_buf_submit()
uprobes/tracing: Change create_trace_uprobe() to support uretprobes
uprobes/tracing: Make seq_printf() code uretprobe-friendly
uprobes/tracing: Make register_uprobe_event() paths uretprobe-friendly
uprobes/tracing: Make uprobe_{trace,perf}_print() uretprobe-friendly
uprobes/tracing: Introduce is_ret_probe() and uretprobe_dispatcher()
uprobes/tracing: Introduce uprobe_{trace,perf}_print() helpers
uprobes/tracing: Generalize struct uprobe_trace_entry_head
uprobes/tracing: Kill the pointless local_save_flags/preempt_count calls
uprobes/tracing: Kill the pointless seq_print_ip_sym() call
uprobes/tracing: Kill the pointless task_pt_regs() calls
...

+5677 -1715
+66 -46
Documentation/trace/uprobetracer.txt
··· 1 - Uprobe-tracer: Uprobe-based Event Tracing 2 - ========================================= 3 - Documentation written by Srikar Dronamraju 1 + Uprobe-tracer: Uprobe-based Event Tracing 2 + ========================================= 3 + 4 + Documentation written by Srikar Dronamraju 5 + 4 6 5 7 Overview 6 8 -------- ··· 15 13 /sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled. 16 14 17 15 However unlike kprobe-event tracer, the uprobe event interface expects the 18 - user to calculate the offset of the probepoint in the object 16 + user to calculate the offset of the probepoint in the object. 19 17 20 18 Synopsis of uprobe_tracer 21 19 ------------------------- 22 - p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a probe 20 + p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a uprobe 21 + r[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a return uprobe (uretprobe) 22 + -:[GRP/]EVENT : Clear uprobe or uretprobe event 23 23 24 - GRP : Group name. If omitted, use "uprobes" for it. 25 - EVENT : Event name. If omitted, the event name is generated 26 - based on SYMBOL+offs. 27 - PATH : path to an executable or a library. 28 - SYMBOL[+offs] : Symbol+offset where the probe is inserted. 24 + GRP : Group name. If omitted, "uprobes" is the default value. 25 + EVENT : Event name. If omitted, the event name is generated based 26 + on SYMBOL+offs. 27 + PATH : Path to an executable or a library. 28 + SYMBOL[+offs] : Symbol+offset where the probe is inserted. 29 29 30 - FETCHARGS : Arguments. Each probe can have up to 128 args. 31 - %REG : Fetch register REG 30 + FETCHARGS : Arguments. Each probe can have up to 128 args. 31 + %REG : Fetch register REG 32 32 33 33 Event Profiling 34 34 --------------- 35 - You can check the total number of probe hits and probe miss-hits via 35 + You can check the total number of probe hits and probe miss-hits via 36 36 /sys/kernel/debug/tracing/uprobe_profile. 37 - The first column is event name, the second is the number of probe hits, 37 + The first column is event name, the second is the number of probe hits, 38 38 the third is the number of probe miss-hits. 39 39 40 40 Usage examples 41 41 -------------- 42 - To add a probe as a new event, write a new definition to uprobe_events 43 - as below. 42 + * Add a probe as a new uprobe event, write a new definition to uprobe_events 43 + as below: (sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash) 44 44 45 - echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events 45 + echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events 46 46 47 - This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash 47 + * Add a probe as a new uretprobe event: 48 48 49 - echo > /sys/kernel/debug/tracing/uprobe_events 49 + echo 'r: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events 50 50 51 - This clears all probe points. 51 + * Unset registered event: 52 52 53 - The following example shows how to dump the instruction pointer and %ax 54 - a register at the probed text address. Here we are trying to probe 55 - function zfree in /bin/zsh 53 + echo '-:bash_0x4245c0' >> /sys/kernel/debug/tracing/uprobe_events 54 + 55 + * Print out the events that are registered: 56 + 57 + cat /sys/kernel/debug/tracing/uprobe_events 58 + 59 + * Clear all events: 60 + 61 + echo > /sys/kernel/debug/tracing/uprobe_events 62 + 63 + Following example shows how to dump the instruction pointer and %ax register 64 + at the probed text address. Probe zfree function in /bin/zsh: 56 65 57 66 # cd /sys/kernel/debug/tracing/ 58 - # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 67 + # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 59 68 00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh 60 69 # objdump -T /bin/zsh | grep -w zfree 61 70 0000000000446420 g DF .text 0000000000000012 Base zfree 62 71 63 - 0x46420 is the offset of zfree in object /bin/zsh that is loaded at 64 - 0x00400000. Hence the command to probe would be : 72 + 0x46420 is the offset of zfree in object /bin/zsh that is loaded at 73 + 0x00400000. Hence the command to uprobe would be: 65 74 66 - # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events 75 + # echo 'p:zfree_entry /bin/zsh:0x46420 %ip %ax' > uprobe_events 67 76 68 - Please note: User has to explicitly calculate the offset of the probepoint 77 + And the same for the uretprobe would be: 78 + 79 + # echo 'r:zfree_exit /bin/zsh:0x46420 %ip %ax' >> uprobe_events 80 + 81 + Please note: User has to explicitly calculate the offset of the probe-point 69 82 in the object. We can see the events that are registered by looking at the 70 83 uprobe_events file. 71 84 72 85 # cat uprobe_events 73 - p:uprobes/p_zsh_0x46420 /bin/zsh:0x00046420 arg1=%ip arg2=%ax 86 + p:uprobes/zfree_entry /bin/zsh:0x00046420 arg1=%ip arg2=%ax 87 + r:uprobes/zfree_exit /bin/zsh:0x00046420 arg1=%ip arg2=%ax 74 88 75 - The format of events can be seen by viewing the file events/uprobes/p_zsh_0x46420/format 89 + Format of events can be seen by viewing the file events/uprobes/zfree_entry/format 76 90 77 - # cat events/uprobes/p_zsh_0x46420/format 78 - name: p_zsh_0x46420 91 + # cat events/uprobes/zfree_entry/format 92 + name: zfree_entry 79 93 ID: 922 80 94 format: 81 - field:unsigned short common_type; offset:0; size:2; signed:0; 82 - field:unsigned char common_flags; offset:2; size:1; signed:0; 83 - field:unsigned char common_preempt_count; offset:3; size:1; signed:0; 84 - field:int common_pid; offset:4; size:4; signed:1; 85 - field:int common_padding; offset:8; size:4; signed:1; 95 + field:unsigned short common_type; offset:0; size:2; signed:0; 96 + field:unsigned char common_flags; offset:2; size:1; signed:0; 97 + field:unsigned char common_preempt_count; offset:3; size:1; signed:0; 98 + field:int common_pid; offset:4; size:4; signed:1; 99 + field:int common_padding; offset:8; size:4; signed:1; 86 100 87 - field:unsigned long __probe_ip; offset:12; size:4; signed:0; 88 - field:u32 arg1; offset:16; size:4; signed:0; 89 - field:u32 arg2; offset:20; size:4; signed:0; 101 + field:unsigned long __probe_ip; offset:12; size:4; signed:0; 102 + field:u32 arg1; offset:16; size:4; signed:0; 103 + field:u32 arg2; offset:20; size:4; signed:0; 90 104 91 105 print fmt: "(%lx) arg1=%lx arg2=%lx", REC->__probe_ip, REC->arg1, REC->arg2 92 106 ··· 112 94 # echo 1 > events/uprobes/enable 113 95 114 96 Lets disable the event after sleeping for some time. 97 + 115 98 # sleep 20 116 99 # echo 0 > events/uprobes/enable 117 100 ··· 123 104 # 124 105 # TASK-PID CPU# TIMESTAMP FUNCTION 125 106 # | | | | | 126 - zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 127 - zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 128 - zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 129 - zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 107 + zsh-24842 [006] 258544.995456: zfree_entry: (0x446420) arg1=446420 arg2=79 108 + zsh-24842 [007] 258545.000270: zfree_exit: (0x446540 <- 0x446420) arg1=446540 arg2=0 109 + zsh-24842 [002] 258545.043929: zfree_entry: (0x446420) arg1=446420 arg2=79 110 + zsh-24842 [004] 258547.046129: zfree_exit: (0x446540 <- 0x446420) arg1=446540 arg2=0 130 111 131 - Each line shows us probes were triggered for a pid 24842 with ip being 132 - 0x446421 and contents of ax register being 79. 112 + Output shows us uprobe was triggered for a pid 24842 with ip being 0x446420 113 + and contents of ax register being 79. And uretprobe was triggered with ip at 114 + 0x446540 with counterpart function entry at 0x446420.
+2 -2
Makefile
··· 1332 1332 # Clear a bunch of variables before executing the submake 1333 1333 tools/: FORCE 1334 1334 $(Q)mkdir -p $(objtree)/tools 1335 - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ 1335 + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ 1336 1336 1337 1337 tools/%: FORCE 1338 1338 $(Q)mkdir -p $(objtree)/tools 1339 - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ $* 1339 + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ $* 1340 1340 1341 1341 # Single targets 1342 1342 # ---------------------------------------------------------------------------
+1
arch/powerpc/include/asm/uprobes.h
··· 51 51 extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); 52 52 extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); 53 53 extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); 54 + extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs); 54 55 #endif /* _ASM_UPROBES_H */
+23 -6
arch/powerpc/kernel/uprobes.c
··· 31 31 #define UPROBE_TRAP_NR UINT_MAX 32 32 33 33 /** 34 + * is_trap_insn - check if the instruction is a trap variant 35 + * @insn: instruction to be checked. 36 + * Returns true if @insn is a trap variant. 37 + */ 38 + bool is_trap_insn(uprobe_opcode_t *insn) 39 + { 40 + return (is_trap(*insn)); 41 + } 42 + 43 + /** 34 44 * arch_uprobe_analyze_insn 35 45 * @mm: the probed address space. 36 46 * @arch_uprobe: the probepoint information. ··· 53 43 if (addr & 0x03) 54 44 return -EINVAL; 55 45 56 - /* 57 - * We currently don't support a uprobe on an already 58 - * existing breakpoint instruction underneath 59 - */ 60 - if (is_trap(auprobe->ainsn)) 61 - return -ENOTSUPP; 62 46 return 0; 63 47 } 64 48 ··· 191 187 return true; 192 188 193 189 return false; 190 + } 191 + 192 + unsigned long 193 + arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs) 194 + { 195 + unsigned long orig_ret_vaddr; 196 + 197 + orig_ret_vaddr = regs->link; 198 + 199 + /* Replace the return addr with trampoline addr */ 200 + regs->link = trampoline_vaddr; 201 + 202 + return orig_ret_vaddr; 194 203 }
+1
arch/s390/oprofile/init.c
··· 440 440 switch (id.machine) { 441 441 case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break; 442 442 case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break; 443 + case 0x2827: ops->cpu_type = "s390/zEC12"; break; 443 444 default: return -ENODEV; 444 445 } 445 446 }
+2
arch/x86/include/asm/cpufeature.h
··· 168 168 #define X86_FEATURE_TOPOEXT (6*32+22) /* topology extensions CPUID leafs */ 169 169 #define X86_FEATURE_PERFCTR_CORE (6*32+23) /* core performance counter extensions */ 170 170 #define X86_FEATURE_PERFCTR_NB (6*32+24) /* NB performance counter extensions */ 171 + #define X86_FEATURE_PERFCTR_L2 (6*32+28) /* L2 performance counter extensions */ 171 172 172 173 /* 173 174 * Auxiliary flags: Linux defined - For features scattered in various ··· 312 311 #define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ) 313 312 #define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE) 314 313 #define cpu_has_perfctr_nb boot_cpu_has(X86_FEATURE_PERFCTR_NB) 314 + #define cpu_has_perfctr_l2 boot_cpu_has(X86_FEATURE_PERFCTR_L2) 315 315 #define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8) 316 316 #define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) 317 317 #define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
+31 -31
arch/x86/include/asm/perf_event_p4.h
··· 24 24 #define ARCH_P4_CNTRVAL_MASK ((1ULL << ARCH_P4_CNTRVAL_BITS) - 1) 25 25 #define ARCH_P4_UNFLAGGED_BIT ((1ULL) << (ARCH_P4_CNTRVAL_BITS - 1)) 26 26 27 - #define P4_ESCR_EVENT_MASK 0x7e000000U 27 + #define P4_ESCR_EVENT_MASK 0x7e000000ULL 28 28 #define P4_ESCR_EVENT_SHIFT 25 29 - #define P4_ESCR_EVENTMASK_MASK 0x01fffe00U 29 + #define P4_ESCR_EVENTMASK_MASK 0x01fffe00ULL 30 30 #define P4_ESCR_EVENTMASK_SHIFT 9 31 - #define P4_ESCR_TAG_MASK 0x000001e0U 31 + #define P4_ESCR_TAG_MASK 0x000001e0ULL 32 32 #define P4_ESCR_TAG_SHIFT 5 33 - #define P4_ESCR_TAG_ENABLE 0x00000010U 34 - #define P4_ESCR_T0_OS 0x00000008U 35 - #define P4_ESCR_T0_USR 0x00000004U 36 - #define P4_ESCR_T1_OS 0x00000002U 37 - #define P4_ESCR_T1_USR 0x00000001U 33 + #define P4_ESCR_TAG_ENABLE 0x00000010ULL 34 + #define P4_ESCR_T0_OS 0x00000008ULL 35 + #define P4_ESCR_T0_USR 0x00000004ULL 36 + #define P4_ESCR_T1_OS 0x00000002ULL 37 + #define P4_ESCR_T1_USR 0x00000001ULL 38 38 39 39 #define P4_ESCR_EVENT(v) ((v) << P4_ESCR_EVENT_SHIFT) 40 40 #define P4_ESCR_EMASK(v) ((v) << P4_ESCR_EVENTMASK_SHIFT) 41 41 #define P4_ESCR_TAG(v) ((v) << P4_ESCR_TAG_SHIFT) 42 42 43 - #define P4_CCCR_OVF 0x80000000U 44 - #define P4_CCCR_CASCADE 0x40000000U 45 - #define P4_CCCR_OVF_PMI_T0 0x04000000U 46 - #define P4_CCCR_OVF_PMI_T1 0x08000000U 47 - #define P4_CCCR_FORCE_OVF 0x02000000U 48 - #define P4_CCCR_EDGE 0x01000000U 49 - #define P4_CCCR_THRESHOLD_MASK 0x00f00000U 43 + #define P4_CCCR_OVF 0x80000000ULL 44 + #define P4_CCCR_CASCADE 0x40000000ULL 45 + #define P4_CCCR_OVF_PMI_T0 0x04000000ULL 46 + #define P4_CCCR_OVF_PMI_T1 0x08000000ULL 47 + #define P4_CCCR_FORCE_OVF 0x02000000ULL 48 + #define P4_CCCR_EDGE 0x01000000ULL 49 + #define P4_CCCR_THRESHOLD_MASK 0x00f00000ULL 50 50 #define P4_CCCR_THRESHOLD_SHIFT 20 51 - #define P4_CCCR_COMPLEMENT 0x00080000U 52 - #define P4_CCCR_COMPARE 0x00040000U 53 - #define P4_CCCR_ESCR_SELECT_MASK 0x0000e000U 51 + #define P4_CCCR_COMPLEMENT 0x00080000ULL 52 + #define P4_CCCR_COMPARE 0x00040000ULL 53 + #define P4_CCCR_ESCR_SELECT_MASK 0x0000e000ULL 54 54 #define P4_CCCR_ESCR_SELECT_SHIFT 13 55 - #define P4_CCCR_ENABLE 0x00001000U 56 - #define P4_CCCR_THREAD_SINGLE 0x00010000U 57 - #define P4_CCCR_THREAD_BOTH 0x00020000U 58 - #define P4_CCCR_THREAD_ANY 0x00030000U 59 - #define P4_CCCR_RESERVED 0x00000fffU 55 + #define P4_CCCR_ENABLE 0x00001000ULL 56 + #define P4_CCCR_THREAD_SINGLE 0x00010000ULL 57 + #define P4_CCCR_THREAD_BOTH 0x00020000ULL 58 + #define P4_CCCR_THREAD_ANY 0x00030000ULL 59 + #define P4_CCCR_RESERVED 0x00000fffULL 60 60 61 61 #define P4_CCCR_THRESHOLD(v) ((v) << P4_CCCR_THRESHOLD_SHIFT) 62 62 #define P4_CCCR_ESEL(v) ((v) << P4_CCCR_ESCR_SELECT_SHIFT) 63 63 64 64 #define P4_GEN_ESCR_EMASK(class, name, bit) \ 65 - class##__##name = ((1 << bit) << P4_ESCR_EVENTMASK_SHIFT) 65 + class##__##name = ((1ULL << bit) << P4_ESCR_EVENTMASK_SHIFT) 66 66 #define P4_ESCR_EMASK_BIT(class, name) class##__##name 67 67 68 68 /* ··· 107 107 * P4_PEBS_CONFIG_MASK and related bits on 108 108 * modification.) 109 109 */ 110 - #define P4_CONFIG_ALIASABLE (1 << 9) 110 + #define P4_CONFIG_ALIASABLE (1ULL << 9) 111 111 112 112 /* 113 113 * The bits we allow to pass for RAW events ··· 784 784 * Note we have UOP and PEBS bits reserved for now 785 785 * just in case if we will need them once 786 786 */ 787 - #define P4_PEBS_CONFIG_ENABLE (1 << 7) 788 - #define P4_PEBS_CONFIG_UOP_TAG (1 << 8) 789 - #define P4_PEBS_CONFIG_METRIC_MASK 0x3f 790 - #define P4_PEBS_CONFIG_MASK 0xff 787 + #define P4_PEBS_CONFIG_ENABLE (1ULL << 7) 788 + #define P4_PEBS_CONFIG_UOP_TAG (1ULL << 8) 789 + #define P4_PEBS_CONFIG_METRIC_MASK 0x3FLL 790 + #define P4_PEBS_CONFIG_MASK 0xFFLL 791 791 792 792 /* 793 793 * mem: Only counters MSR_IQ_COUNTER4 (16) and 794 794 * MSR_IQ_COUNTER5 (17) are allowed for PEBS sampling 795 795 */ 796 - #define P4_PEBS_ENABLE 0x02000000U 797 - #define P4_PEBS_ENABLE_UOP_TAG 0x01000000U 796 + #define P4_PEBS_ENABLE 0x02000000ULL 797 + #define P4_PEBS_ENABLE_UOP_TAG 0x01000000ULL 798 798 799 799 #define p4_config_unpack_metric(v) (((u64)(v)) & P4_PEBS_CONFIG_METRIC_MASK) 800 800 #define p4_config_unpack_pebs(v) (((u64)(v)) & P4_PEBS_CONFIG_MASK)
+1
arch/x86/include/asm/uprobes.h
··· 55 55 extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); 56 56 extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); 57 57 extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); 58 + extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs); 58 59 #endif /* _ASM_UPROBES_H */
+5
arch/x86/include/uapi/asm/msr-index.h
··· 72 72 #define MSR_IA32_PEBS_ENABLE 0x000003f1 73 73 #define MSR_IA32_DS_AREA 0x00000600 74 74 #define MSR_IA32_PERF_CAPABILITIES 0x00000345 75 + #define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 75 76 76 77 #define MSR_MTRRfix64K_00000 0x00000250 77 78 #define MSR_MTRRfix16K_80000 0x00000258 ··· 195 194 #define MSR_AMD64_IBSCTL 0xc001103a 196 195 #define MSR_AMD64_IBSBRTARGET 0xc001103b 197 196 #define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */ 197 + 198 + /* Fam 16h MSRs */ 199 + #define MSR_F16H_L2I_PERF_CTL 0xc0010230 200 + #define MSR_F16H_L2I_PERF_CTR 0xc0010231 198 201 199 202 /* Fam 15h MSRs */ 200 203 #define MSR_F15H_PERF_CTL 0xc0010200
+1 -1
arch/x86/kernel/cpu/Makefile
··· 31 31 obj-$(CONFIG_PERF_EVENTS) += perf_event.o 32 32 33 33 ifdef CONFIG_PERF_EVENTS 34 - obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o 34 + obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o perf_event_amd_uncore.o 35 35 obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o 36 36 obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o 37 37 obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o
+68 -21
arch/x86/kernel/cpu/perf_event.c
··· 180 180 181 181 static bool check_hw_exists(void) 182 182 { 183 - u64 val, val_new = ~0; 184 - int i, reg, ret = 0; 183 + u64 val, val_fail, val_new= ~0; 184 + int i, reg, reg_fail, ret = 0; 185 + int bios_fail = 0; 185 186 186 187 /* 187 188 * Check to see if the BIOS enabled any of the counters, if so ··· 193 192 ret = rdmsrl_safe(reg, &val); 194 193 if (ret) 195 194 goto msr_fail; 196 - if (val & ARCH_PERFMON_EVENTSEL_ENABLE) 197 - goto bios_fail; 195 + if (val & ARCH_PERFMON_EVENTSEL_ENABLE) { 196 + bios_fail = 1; 197 + val_fail = val; 198 + reg_fail = reg; 199 + } 198 200 } 199 201 200 202 if (x86_pmu.num_counters_fixed) { ··· 206 202 if (ret) 207 203 goto msr_fail; 208 204 for (i = 0; i < x86_pmu.num_counters_fixed; i++) { 209 - if (val & (0x03 << i*4)) 210 - goto bios_fail; 205 + if (val & (0x03 << i*4)) { 206 + bios_fail = 1; 207 + val_fail = val; 208 + reg_fail = reg; 209 + } 211 210 } 212 211 } 213 212 ··· 228 221 if (ret || val != val_new) 229 222 goto msr_fail; 230 223 231 - return true; 232 - 233 - bios_fail: 234 224 /* 235 225 * We still allow the PMU driver to operate: 236 226 */ 237 - printk(KERN_CONT "Broken BIOS detected, complain to your hardware vendor.\n"); 238 - printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg, val); 227 + if (bios_fail) { 228 + printk(KERN_CONT "Broken BIOS detected, complain to your hardware vendor.\n"); 229 + printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg_fail, val_fail); 230 + } 239 231 240 232 return true; 241 233 ··· 1322 1316 */ 1323 1317 static void __init filter_events(struct attribute **attrs) 1324 1318 { 1319 + struct device_attribute *d; 1320 + struct perf_pmu_events_attr *pmu_attr; 1325 1321 int i, j; 1326 1322 1327 1323 for (i = 0; attrs[i]; i++) { 1324 + d = (struct device_attribute *)attrs[i]; 1325 + pmu_attr = container_of(d, struct perf_pmu_events_attr, attr); 1326 + /* str trumps id */ 1327 + if (pmu_attr->event_str) 1328 + continue; 1328 1329 if (x86_pmu.event_map(i)) 1329 1330 continue; 1330 1331 ··· 1343 1330 } 1344 1331 } 1345 1332 1346 - static ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, 1333 + /* Merge two pointer arrays */ 1334 + static __init struct attribute **merge_attr(struct attribute **a, struct attribute **b) 1335 + { 1336 + struct attribute **new; 1337 + int j, i; 1338 + 1339 + for (j = 0; a[j]; j++) 1340 + ; 1341 + for (i = 0; b[i]; i++) 1342 + j++; 1343 + j++; 1344 + 1345 + new = kmalloc(sizeof(struct attribute *) * j, GFP_KERNEL); 1346 + if (!new) 1347 + return NULL; 1348 + 1349 + j = 0; 1350 + for (i = 0; a[i]; i++) 1351 + new[j++] = a[i]; 1352 + for (i = 0; b[i]; i++) 1353 + new[j++] = b[i]; 1354 + new[j] = NULL; 1355 + 1356 + return new; 1357 + } 1358 + 1359 + ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, 1347 1360 char *page) 1348 1361 { 1349 1362 struct perf_pmu_events_attr *pmu_attr = \ 1350 1363 container_of(attr, struct perf_pmu_events_attr, attr); 1351 - 1352 1364 u64 config = x86_pmu.event_map(pmu_attr->id); 1365 + 1366 + /* string trumps id */ 1367 + if (pmu_attr->event_str) 1368 + return sprintf(page, "%s", pmu_attr->event_str); 1369 + 1353 1370 return x86_pmu.events_sysfs_show(page, config); 1354 1371 } 1355 - 1356 - #define EVENT_VAR(_id) event_attr_##_id 1357 - #define EVENT_PTR(_id) &event_attr_##_id.attr.attr 1358 - 1359 - #define EVENT_ATTR(_name, _id) \ 1360 - PMU_EVENT_ATTR(_name, EVENT_VAR(_id), PERF_COUNT_HW_##_id, \ 1361 - events_sysfs_show) 1362 1372 1363 1373 EVENT_ATTR(cpu-cycles, CPU_CYCLES ); 1364 1374 EVENT_ATTR(instructions, INSTRUCTIONS ); ··· 1495 1459 1496 1460 unconstrained = (struct event_constraint) 1497 1461 __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1, 1498 - 0, x86_pmu.num_counters, 0); 1462 + 0, x86_pmu.num_counters, 0, 0); 1499 1463 1500 1464 x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ 1501 1465 x86_pmu_format_group.attrs = x86_pmu.format_attrs; 1466 + 1467 + if (x86_pmu.event_attrs) 1468 + x86_pmu_events_group.attrs = x86_pmu.event_attrs; 1502 1469 1503 1470 if (!x86_pmu.events_sysfs_show) 1504 1471 x86_pmu_events_group.attrs = &empty_attrs; 1505 1472 else 1506 1473 filter_events(x86_pmu_events_group.attrs); 1474 + 1475 + if (x86_pmu.cpu_events) { 1476 + struct attribute **tmp; 1477 + 1478 + tmp = merge_attr(x86_pmu_events_group.attrs, x86_pmu.cpu_events); 1479 + if (!WARN_ON(!tmp)) 1480 + x86_pmu_events_group.attrs = tmp; 1481 + } 1507 1482 1508 1483 pr_info("... version: %d\n", x86_pmu.version); 1509 1484 pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
+52 -4
arch/x86/kernel/cpu/perf_event.h
··· 46 46 EXTRA_REG_RSP_0 = 0, /* offcore_response_0 */ 47 47 EXTRA_REG_RSP_1 = 1, /* offcore_response_1 */ 48 48 EXTRA_REG_LBR = 2, /* lbr_select */ 49 + EXTRA_REG_LDLAT = 3, /* ld_lat_threshold */ 49 50 50 51 EXTRA_REG_MAX /* number of entries needed */ 51 52 }; ··· 60 59 u64 cmask; 61 60 int weight; 62 61 int overlap; 62 + int flags; 63 63 }; 64 + /* 65 + * struct event_constraint flags 66 + */ 67 + #define PERF_X86_EVENT_PEBS_LDLAT 0x1 /* ld+ldlat data address sampling */ 68 + #define PERF_X86_EVENT_PEBS_ST 0x2 /* st data address sampling */ 64 69 65 70 struct amd_nb { 66 71 int nb_id; /* NorthBridge id */ ··· 177 170 void *kfree_on_online; 178 171 }; 179 172 180 - #define __EVENT_CONSTRAINT(c, n, m, w, o) {\ 173 + #define __EVENT_CONSTRAINT(c, n, m, w, o, f) {\ 181 174 { .idxmsk64 = (n) }, \ 182 175 .code = (c), \ 183 176 .cmask = (m), \ 184 177 .weight = (w), \ 185 178 .overlap = (o), \ 179 + .flags = f, \ 186 180 } 187 181 188 182 #define EVENT_CONSTRAINT(c, n, m) \ 189 - __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0) 183 + __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0, 0) 190 184 191 185 /* 192 186 * The overlap flag marks event constraints with overlapping counter ··· 211 203 * and its counter masks must be kept at a minimum. 212 204 */ 213 205 #define EVENT_CONSTRAINT_OVERLAP(c, n, m) \ 214 - __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 1) 206 + __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 1, 0) 215 207 216 208 /* 217 209 * Constraint on the Event code. ··· 238 230 */ 239 231 #define INTEL_UEVENT_CONSTRAINT(c, n) \ 240 232 EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) 233 + 234 + #define INTEL_PLD_CONSTRAINT(c, n) \ 235 + __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ 236 + HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT) 237 + 238 + #define INTEL_PST_CONSTRAINT(c, n) \ 239 + __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ 240 + HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST) 241 241 242 242 #define EVENT_CONSTRAINT_END \ 243 243 EVENT_CONSTRAINT(0, 0, 0) ··· 276 260 .msr = (ms), \ 277 261 .config_mask = (m), \ 278 262 .valid_mask = (vm), \ 279 - .idx = EXTRA_REG_##i \ 263 + .idx = EXTRA_REG_##i, \ 280 264 } 281 265 282 266 #define INTEL_EVENT_EXTRA_REG(event, msr, vm, idx) \ 283 267 EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm, idx) 268 + 269 + #define INTEL_UEVENT_EXTRA_REG(event, msr, vm, idx) \ 270 + EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT | \ 271 + ARCH_PERFMON_EVENTSEL_UMASK, vm, idx) 272 + 273 + #define INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(c) \ 274 + INTEL_UEVENT_EXTRA_REG(c, \ 275 + MSR_PEBS_LD_LAT_THRESHOLD, \ 276 + 0xffff, \ 277 + LDLAT) 284 278 285 279 #define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0, RSP_0) 286 280 ··· 381 355 */ 382 356 int attr_rdpmc; 383 357 struct attribute **format_attrs; 358 + struct attribute **event_attrs; 384 359 385 360 ssize_t (*events_sysfs_show)(char *page, u64 config); 361 + struct attribute **cpu_events; 386 362 387 363 /* 388 364 * CPU Hotplug hooks ··· 448 420 449 421 #define ERF_NO_HT_SHARING 1 450 422 #define ERF_HAS_RSP_1 2 423 + 424 + #define EVENT_VAR(_id) event_attr_##_id 425 + #define EVENT_PTR(_id) &event_attr_##_id.attr.attr 426 + 427 + #define EVENT_ATTR(_name, _id) \ 428 + static struct perf_pmu_events_attr EVENT_VAR(_id) = { \ 429 + .attr = __ATTR(_name, 0444, events_sysfs_show, NULL), \ 430 + .id = PERF_COUNT_HW_##_id, \ 431 + .event_str = NULL, \ 432 + }; 433 + 434 + #define EVENT_ATTR_STR(_name, v, str) \ 435 + static struct perf_pmu_events_attr event_attr_##v = { \ 436 + .attr = __ATTR(_name, 0444, events_sysfs_show, NULL), \ 437 + .id = 0, \ 438 + .event_str = str, \ 439 + }; 451 440 452 441 extern struct x86_pmu x86_pmu __read_mostly; 453 442 ··· 672 627 int p6_pmu_init(void); 673 628 674 629 int knc_pmu_init(void); 630 + 631 + ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, 632 + char *page); 675 633 676 634 #else /* CONFIG_CPU_SUP_INTEL */ 677 635
+5 -133
arch/x86/kernel/cpu/perf_event_amd.c
··· 132 132 return amd_perfmon_event_map[hw_event]; 133 133 } 134 134 135 - static struct event_constraint *amd_nb_event_constraint; 136 - 137 135 /* 138 136 * Previously calculated offsets 139 137 */ 140 138 static unsigned int event_offsets[X86_PMC_IDX_MAX] __read_mostly; 141 139 static unsigned int count_offsets[X86_PMC_IDX_MAX] __read_mostly; 142 - static unsigned int rdpmc_indexes[X86_PMC_IDX_MAX] __read_mostly; 143 140 144 141 /* 145 142 * Legacy CPUs: ··· 144 147 * 145 148 * CPUs with core performance counter extensions: 146 149 * 6 counters starting at 0xc0010200 each offset by 2 147 - * 148 - * CPUs with north bridge performance counter extensions: 149 - * 4 additional counters starting at 0xc0010240 each offset by 2 150 - * (indexed right above either one of the above core counters) 151 150 */ 152 151 static inline int amd_pmu_addr_offset(int index, bool eventsel) 153 152 { 154 - int offset, first, base; 153 + int offset; 155 154 156 155 if (!index) 157 156 return index; ··· 160 167 if (offset) 161 168 return offset; 162 169 163 - if (amd_nb_event_constraint && 164 - test_bit(index, amd_nb_event_constraint->idxmsk)) { 165 - /* 166 - * calculate the offset of NB counters with respect to 167 - * base eventsel or perfctr 168 - */ 169 - 170 - first = find_first_bit(amd_nb_event_constraint->idxmsk, 171 - X86_PMC_IDX_MAX); 172 - 173 - if (eventsel) 174 - base = MSR_F15H_NB_PERF_CTL - x86_pmu.eventsel; 175 - else 176 - base = MSR_F15H_NB_PERF_CTR - x86_pmu.perfctr; 177 - 178 - offset = base + ((index - first) << 1); 179 - } else if (!cpu_has_perfctr_core) 170 + if (!cpu_has_perfctr_core) 180 171 offset = index; 181 172 else 182 173 offset = index << 1; ··· 171 194 count_offsets[index] = offset; 172 195 173 196 return offset; 174 - } 175 - 176 - static inline int amd_pmu_rdpmc_index(int index) 177 - { 178 - int ret, first; 179 - 180 - if (!index) 181 - return index; 182 - 183 - ret = rdpmc_indexes[index]; 184 - 185 - if (ret) 186 - return ret; 187 - 188 - if (amd_nb_event_constraint && 189 - test_bit(index, amd_nb_event_constraint->idxmsk)) { 190 - /* 191 - * according to the mnual, ECX value of the NB counters is 192 - * the index of the NB counter (0, 1, 2 or 3) plus 6 193 - */ 194 - 195 - first = find_first_bit(amd_nb_event_constraint->idxmsk, 196 - X86_PMC_IDX_MAX); 197 - ret = index - first + 6; 198 - } else 199 - ret = index; 200 - 201 - rdpmc_indexes[index] = ret; 202 - 203 - return ret; 204 197 } 205 198 206 199 static int amd_core_hw_config(struct perf_event *event) ··· 192 245 } 193 246 194 247 /* 195 - * NB counters do not support the following event select bits: 196 - * Host/Guest only 197 - * Counter mask 198 - * Invert counter mask 199 - * Edge detect 200 - * OS/User mode 201 - */ 202 - static int amd_nb_hw_config(struct perf_event *event) 203 - { 204 - /* for NB, we only allow system wide counting mode */ 205 - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) 206 - return -EINVAL; 207 - 208 - if (event->attr.exclude_user || event->attr.exclude_kernel || 209 - event->attr.exclude_host || event->attr.exclude_guest) 210 - return -EINVAL; 211 - 212 - event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR | 213 - ARCH_PERFMON_EVENTSEL_OS); 214 - 215 - if (event->hw.config & ~(AMD64_RAW_EVENT_MASK_NB | 216 - ARCH_PERFMON_EVENTSEL_INT)) 217 - return -EINVAL; 218 - 219 - return 0; 220 - } 221 - 222 - /* 223 248 * AMD64 events are detected based on their event codes. 224 249 */ 225 250 static inline unsigned int amd_get_event_code(struct hw_perf_event *hwc) ··· 202 283 static inline int amd_is_nb_event(struct hw_perf_event *hwc) 203 284 { 204 285 return (hwc->config & 0xe0) == 0xe0; 205 - } 206 - 207 - static inline int amd_is_perfctr_nb_event(struct hw_perf_event *hwc) 208 - { 209 - return amd_nb_event_constraint && amd_is_nb_event(hwc); 210 286 } 211 287 212 288 static inline int amd_has_nb(struct cpu_hw_events *cpuc) ··· 229 315 if (event->attr.type == PERF_TYPE_RAW) 230 316 event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK; 231 317 232 - if (amd_is_perfctr_nb_event(&event->hw)) 233 - return amd_nb_hw_config(event); 234 - 235 318 return amd_core_hw_config(event); 236 319 } 237 320 ··· 249 338 for (i = 0; i < x86_pmu.num_counters; i++) { 250 339 if (cmpxchg(nb->owners + i, event, NULL) == event) 251 340 break; 252 - } 253 - } 254 - 255 - static void amd_nb_interrupt_hw_config(struct hw_perf_event *hwc) 256 - { 257 - int core_id = cpu_data(smp_processor_id()).cpu_core_id; 258 - 259 - /* deliver interrupts only to this core */ 260 - if (hwc->config & ARCH_PERFMON_EVENTSEL_INT) { 261 - hwc->config |= AMD64_EVENTSEL_INT_CORE_ENABLE; 262 - hwc->config &= ~AMD64_EVENTSEL_INT_CORE_SEL_MASK; 263 - hwc->config |= (u64)(core_id) << 264 - AMD64_EVENTSEL_INT_CORE_SEL_SHIFT; 265 341 } 266 342 } 267 343 ··· 338 440 339 441 if (new == -1) 340 442 return &emptyconstraint; 341 - 342 - if (amd_is_perfctr_nb_event(hwc)) 343 - amd_nb_interrupt_hw_config(hwc); 344 443 345 444 return &nb->event_constraints[new]; 346 445 } ··· 438 543 if (!(amd_has_nb(cpuc) && amd_is_nb_event(&event->hw))) 439 544 return &unconstrained; 440 545 441 - return __amd_get_nb_event_constraints(cpuc, event, 442 - amd_nb_event_constraint); 546 + return __amd_get_nb_event_constraints(cpuc, event, NULL); 443 547 } 444 548 445 549 static void amd_put_event_constraints(struct cpu_hw_events *cpuc, ··· 537 643 static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0); 538 644 static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0); 539 645 540 - static struct event_constraint amd_NBPMC96 = EVENT_CONSTRAINT(0, 0x3C0, 0); 541 - static struct event_constraint amd_NBPMC74 = EVENT_CONSTRAINT(0, 0xF0, 0); 542 - 543 646 static struct event_constraint * 544 647 amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event) 545 648 { ··· 602 711 return &amd_f15_PMC20; 603 712 } 604 713 case AMD_EVENT_NB: 605 - return __amd_get_nb_event_constraints(cpuc, event, 606 - amd_nb_event_constraint); 714 + /* moved to perf_event_amd_uncore.c */ 715 + return &emptyconstraint; 607 716 default: 608 717 return &emptyconstraint; 609 718 } ··· 629 738 .eventsel = MSR_K7_EVNTSEL0, 630 739 .perfctr = MSR_K7_PERFCTR0, 631 740 .addr_offset = amd_pmu_addr_offset, 632 - .rdpmc_index = amd_pmu_rdpmc_index, 633 741 .event_map = amd_pmu_event_map, 634 742 .max_events = ARRAY_SIZE(amd_perfmon_event_map), 635 743 .num_counters = AMD64_NUM_COUNTERS, ··· 680 790 return 0; 681 791 } 682 792 683 - static int setup_perfctr_nb(void) 684 - { 685 - if (!cpu_has_perfctr_nb) 686 - return -ENODEV; 687 - 688 - x86_pmu.num_counters += AMD64_NUM_COUNTERS_NB; 689 - 690 - if (cpu_has_perfctr_core) 691 - amd_nb_event_constraint = &amd_NBPMC96; 692 - else 693 - amd_nb_event_constraint = &amd_NBPMC74; 694 - 695 - printk(KERN_INFO "perf: AMD northbridge performance counters detected\n"); 696 - 697 - return 0; 698 - } 699 - 700 793 __init int amd_pmu_init(void) 701 794 { 702 795 /* Performance-monitoring supported from K7 and later: */ ··· 690 817 691 818 setup_event_constraints(); 692 819 setup_perfctr_core(); 693 - setup_perfctr_nb(); 694 820 695 821 /* Events are common for all AMDs */ 696 822 memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
+547
arch/x86/kernel/cpu/perf_event_amd_uncore.c
··· 1 + /* 2 + * Copyright (C) 2013 Advanced Micro Devices, Inc. 3 + * 4 + * Author: Jacob Shin <jacob.shin@amd.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/perf_event.h> 12 + #include <linux/percpu.h> 13 + #include <linux/types.h> 14 + #include <linux/slab.h> 15 + #include <linux/init.h> 16 + #include <linux/cpu.h> 17 + #include <linux/cpumask.h> 18 + 19 + #include <asm/cpufeature.h> 20 + #include <asm/perf_event.h> 21 + #include <asm/msr.h> 22 + 23 + #define NUM_COUNTERS_NB 4 24 + #define NUM_COUNTERS_L2 4 25 + #define MAX_COUNTERS NUM_COUNTERS_NB 26 + 27 + #define RDPMC_BASE_NB 6 28 + #define RDPMC_BASE_L2 10 29 + 30 + #define COUNTER_SHIFT 16 31 + 32 + struct amd_uncore { 33 + int id; 34 + int refcnt; 35 + int cpu; 36 + int num_counters; 37 + int rdpmc_base; 38 + u32 msr_base; 39 + cpumask_t *active_mask; 40 + struct pmu *pmu; 41 + struct perf_event *events[MAX_COUNTERS]; 42 + struct amd_uncore *free_when_cpu_online; 43 + }; 44 + 45 + static struct amd_uncore * __percpu *amd_uncore_nb; 46 + static struct amd_uncore * __percpu *amd_uncore_l2; 47 + 48 + static struct pmu amd_nb_pmu; 49 + static struct pmu amd_l2_pmu; 50 + 51 + static cpumask_t amd_nb_active_mask; 52 + static cpumask_t amd_l2_active_mask; 53 + 54 + static bool is_nb_event(struct perf_event *event) 55 + { 56 + return event->pmu->type == amd_nb_pmu.type; 57 + } 58 + 59 + static bool is_l2_event(struct perf_event *event) 60 + { 61 + return event->pmu->type == amd_l2_pmu.type; 62 + } 63 + 64 + static struct amd_uncore *event_to_amd_uncore(struct perf_event *event) 65 + { 66 + if (is_nb_event(event) && amd_uncore_nb) 67 + return *per_cpu_ptr(amd_uncore_nb, event->cpu); 68 + else if (is_l2_event(event) && amd_uncore_l2) 69 + return *per_cpu_ptr(amd_uncore_l2, event->cpu); 70 + 71 + return NULL; 72 + } 73 + 74 + static void amd_uncore_read(struct perf_event *event) 75 + { 76 + struct hw_perf_event *hwc = &event->hw; 77 + u64 prev, new; 78 + s64 delta; 79 + 80 + /* 81 + * since we do not enable counter overflow interrupts, 82 + * we do not have to worry about prev_count changing on us 83 + */ 84 + 85 + prev = local64_read(&hwc->prev_count); 86 + rdpmcl(hwc->event_base_rdpmc, new); 87 + local64_set(&hwc->prev_count, new); 88 + delta = (new << COUNTER_SHIFT) - (prev << COUNTER_SHIFT); 89 + delta >>= COUNTER_SHIFT; 90 + local64_add(delta, &event->count); 91 + } 92 + 93 + static void amd_uncore_start(struct perf_event *event, int flags) 94 + { 95 + struct hw_perf_event *hwc = &event->hw; 96 + 97 + if (flags & PERF_EF_RELOAD) 98 + wrmsrl(hwc->event_base, (u64)local64_read(&hwc->prev_count)); 99 + 100 + hwc->state = 0; 101 + wrmsrl(hwc->config_base, (hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE)); 102 + perf_event_update_userpage(event); 103 + } 104 + 105 + static void amd_uncore_stop(struct perf_event *event, int flags) 106 + { 107 + struct hw_perf_event *hwc = &event->hw; 108 + 109 + wrmsrl(hwc->config_base, hwc->config); 110 + hwc->state |= PERF_HES_STOPPED; 111 + 112 + if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { 113 + amd_uncore_read(event); 114 + hwc->state |= PERF_HES_UPTODATE; 115 + } 116 + } 117 + 118 + static int amd_uncore_add(struct perf_event *event, int flags) 119 + { 120 + int i; 121 + struct amd_uncore *uncore = event_to_amd_uncore(event); 122 + struct hw_perf_event *hwc = &event->hw; 123 + 124 + /* are we already assigned? */ 125 + if (hwc->idx != -1 && uncore->events[hwc->idx] == event) 126 + goto out; 127 + 128 + for (i = 0; i < uncore->num_counters; i++) { 129 + if (uncore->events[i] == event) { 130 + hwc->idx = i; 131 + goto out; 132 + } 133 + } 134 + 135 + /* if not, take the first available counter */ 136 + hwc->idx = -1; 137 + for (i = 0; i < uncore->num_counters; i++) { 138 + if (cmpxchg(&uncore->events[i], NULL, event) == NULL) { 139 + hwc->idx = i; 140 + break; 141 + } 142 + } 143 + 144 + out: 145 + if (hwc->idx == -1) 146 + return -EBUSY; 147 + 148 + hwc->config_base = uncore->msr_base + (2 * hwc->idx); 149 + hwc->event_base = uncore->msr_base + 1 + (2 * hwc->idx); 150 + hwc->event_base_rdpmc = uncore->rdpmc_base + hwc->idx; 151 + hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; 152 + 153 + if (flags & PERF_EF_START) 154 + amd_uncore_start(event, PERF_EF_RELOAD); 155 + 156 + return 0; 157 + } 158 + 159 + static void amd_uncore_del(struct perf_event *event, int flags) 160 + { 161 + int i; 162 + struct amd_uncore *uncore = event_to_amd_uncore(event); 163 + struct hw_perf_event *hwc = &event->hw; 164 + 165 + amd_uncore_stop(event, PERF_EF_UPDATE); 166 + 167 + for (i = 0; i < uncore->num_counters; i++) { 168 + if (cmpxchg(&uncore->events[i], event, NULL) == event) 169 + break; 170 + } 171 + 172 + hwc->idx = -1; 173 + } 174 + 175 + static int amd_uncore_event_init(struct perf_event *event) 176 + { 177 + struct amd_uncore *uncore; 178 + struct hw_perf_event *hwc = &event->hw; 179 + 180 + if (event->attr.type != event->pmu->type) 181 + return -ENOENT; 182 + 183 + /* 184 + * NB and L2 counters (MSRs) are shared across all cores that share the 185 + * same NB / L2 cache. Interrupts can be directed to a single target 186 + * core, however, event counts generated by processes running on other 187 + * cores cannot be masked out. So we do not support sampling and 188 + * per-thread events. 189 + */ 190 + if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) 191 + return -EINVAL; 192 + 193 + /* NB and L2 counters do not have usr/os/guest/host bits */ 194 + if (event->attr.exclude_user || event->attr.exclude_kernel || 195 + event->attr.exclude_host || event->attr.exclude_guest) 196 + return -EINVAL; 197 + 198 + /* and we do not enable counter overflow interrupts */ 199 + hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB; 200 + hwc->idx = -1; 201 + 202 + if (event->cpu < 0) 203 + return -EINVAL; 204 + 205 + uncore = event_to_amd_uncore(event); 206 + if (!uncore) 207 + return -ENODEV; 208 + 209 + /* 210 + * since request can come in to any of the shared cores, we will remap 211 + * to a single common cpu. 212 + */ 213 + event->cpu = uncore->cpu; 214 + 215 + return 0; 216 + } 217 + 218 + static ssize_t amd_uncore_attr_show_cpumask(struct device *dev, 219 + struct device_attribute *attr, 220 + char *buf) 221 + { 222 + int n; 223 + cpumask_t *active_mask; 224 + struct pmu *pmu = dev_get_drvdata(dev); 225 + 226 + if (pmu->type == amd_nb_pmu.type) 227 + active_mask = &amd_nb_active_mask; 228 + else if (pmu->type == amd_l2_pmu.type) 229 + active_mask = &amd_l2_active_mask; 230 + else 231 + return 0; 232 + 233 + n = cpulist_scnprintf(buf, PAGE_SIZE - 2, active_mask); 234 + buf[n++] = '\n'; 235 + buf[n] = '\0'; 236 + return n; 237 + } 238 + static DEVICE_ATTR(cpumask, S_IRUGO, amd_uncore_attr_show_cpumask, NULL); 239 + 240 + static struct attribute *amd_uncore_attrs[] = { 241 + &dev_attr_cpumask.attr, 242 + NULL, 243 + }; 244 + 245 + static struct attribute_group amd_uncore_attr_group = { 246 + .attrs = amd_uncore_attrs, 247 + }; 248 + 249 + PMU_FORMAT_ATTR(event, "config:0-7,32-35"); 250 + PMU_FORMAT_ATTR(umask, "config:8-15"); 251 + 252 + static struct attribute *amd_uncore_format_attr[] = { 253 + &format_attr_event.attr, 254 + &format_attr_umask.attr, 255 + NULL, 256 + }; 257 + 258 + static struct attribute_group amd_uncore_format_group = { 259 + .name = "format", 260 + .attrs = amd_uncore_format_attr, 261 + }; 262 + 263 + static const struct attribute_group *amd_uncore_attr_groups[] = { 264 + &amd_uncore_attr_group, 265 + &amd_uncore_format_group, 266 + NULL, 267 + }; 268 + 269 + static struct pmu amd_nb_pmu = { 270 + .attr_groups = amd_uncore_attr_groups, 271 + .name = "amd_nb", 272 + .event_init = amd_uncore_event_init, 273 + .add = amd_uncore_add, 274 + .del = amd_uncore_del, 275 + .start = amd_uncore_start, 276 + .stop = amd_uncore_stop, 277 + .read = amd_uncore_read, 278 + }; 279 + 280 + static struct pmu amd_l2_pmu = { 281 + .attr_groups = amd_uncore_attr_groups, 282 + .name = "amd_l2", 283 + .event_init = amd_uncore_event_init, 284 + .add = amd_uncore_add, 285 + .del = amd_uncore_del, 286 + .start = amd_uncore_start, 287 + .stop = amd_uncore_stop, 288 + .read = amd_uncore_read, 289 + }; 290 + 291 + static struct amd_uncore * __cpuinit amd_uncore_alloc(unsigned int cpu) 292 + { 293 + return kzalloc_node(sizeof(struct amd_uncore), GFP_KERNEL, 294 + cpu_to_node(cpu)); 295 + } 296 + 297 + static void __cpuinit amd_uncore_cpu_up_prepare(unsigned int cpu) 298 + { 299 + struct amd_uncore *uncore; 300 + 301 + if (amd_uncore_nb) { 302 + uncore = amd_uncore_alloc(cpu); 303 + uncore->cpu = cpu; 304 + uncore->num_counters = NUM_COUNTERS_NB; 305 + uncore->rdpmc_base = RDPMC_BASE_NB; 306 + uncore->msr_base = MSR_F15H_NB_PERF_CTL; 307 + uncore->active_mask = &amd_nb_active_mask; 308 + uncore->pmu = &amd_nb_pmu; 309 + *per_cpu_ptr(amd_uncore_nb, cpu) = uncore; 310 + } 311 + 312 + if (amd_uncore_l2) { 313 + uncore = amd_uncore_alloc(cpu); 314 + uncore->cpu = cpu; 315 + uncore->num_counters = NUM_COUNTERS_L2; 316 + uncore->rdpmc_base = RDPMC_BASE_L2; 317 + uncore->msr_base = MSR_F16H_L2I_PERF_CTL; 318 + uncore->active_mask = &amd_l2_active_mask; 319 + uncore->pmu = &amd_l2_pmu; 320 + *per_cpu_ptr(amd_uncore_l2, cpu) = uncore; 321 + } 322 + } 323 + 324 + static struct amd_uncore * 325 + __cpuinit amd_uncore_find_online_sibling(struct amd_uncore *this, 326 + struct amd_uncore * __percpu *uncores) 327 + { 328 + unsigned int cpu; 329 + struct amd_uncore *that; 330 + 331 + for_each_online_cpu(cpu) { 332 + that = *per_cpu_ptr(uncores, cpu); 333 + 334 + if (!that) 335 + continue; 336 + 337 + if (this == that) 338 + continue; 339 + 340 + if (this->id == that->id) { 341 + that->free_when_cpu_online = this; 342 + this = that; 343 + break; 344 + } 345 + } 346 + 347 + this->refcnt++; 348 + return this; 349 + } 350 + 351 + static void __cpuinit amd_uncore_cpu_starting(unsigned int cpu) 352 + { 353 + unsigned int eax, ebx, ecx, edx; 354 + struct amd_uncore *uncore; 355 + 356 + if (amd_uncore_nb) { 357 + uncore = *per_cpu_ptr(amd_uncore_nb, cpu); 358 + cpuid(0x8000001e, &eax, &ebx, &ecx, &edx); 359 + uncore->id = ecx & 0xff; 360 + 361 + uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_nb); 362 + *per_cpu_ptr(amd_uncore_nb, cpu) = uncore; 363 + } 364 + 365 + if (amd_uncore_l2) { 366 + unsigned int apicid = cpu_data(cpu).apicid; 367 + unsigned int nshared; 368 + 369 + uncore = *per_cpu_ptr(amd_uncore_l2, cpu); 370 + cpuid_count(0x8000001d, 2, &eax, &ebx, &ecx, &edx); 371 + nshared = ((eax >> 14) & 0xfff) + 1; 372 + uncore->id = apicid - (apicid % nshared); 373 + 374 + uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_l2); 375 + *per_cpu_ptr(amd_uncore_l2, cpu) = uncore; 376 + } 377 + } 378 + 379 + static void __cpuinit uncore_online(unsigned int cpu, 380 + struct amd_uncore * __percpu *uncores) 381 + { 382 + struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu); 383 + 384 + kfree(uncore->free_when_cpu_online); 385 + uncore->free_when_cpu_online = NULL; 386 + 387 + if (cpu == uncore->cpu) 388 + cpumask_set_cpu(cpu, uncore->active_mask); 389 + } 390 + 391 + static void __cpuinit amd_uncore_cpu_online(unsigned int cpu) 392 + { 393 + if (amd_uncore_nb) 394 + uncore_online(cpu, amd_uncore_nb); 395 + 396 + if (amd_uncore_l2) 397 + uncore_online(cpu, amd_uncore_l2); 398 + } 399 + 400 + static void __cpuinit uncore_down_prepare(unsigned int cpu, 401 + struct amd_uncore * __percpu *uncores) 402 + { 403 + unsigned int i; 404 + struct amd_uncore *this = *per_cpu_ptr(uncores, cpu); 405 + 406 + if (this->cpu != cpu) 407 + return; 408 + 409 + /* this cpu is going down, migrate to a shared sibling if possible */ 410 + for_each_online_cpu(i) { 411 + struct amd_uncore *that = *per_cpu_ptr(uncores, i); 412 + 413 + if (cpu == i) 414 + continue; 415 + 416 + if (this == that) { 417 + perf_pmu_migrate_context(this->pmu, cpu, i); 418 + cpumask_clear_cpu(cpu, that->active_mask); 419 + cpumask_set_cpu(i, that->active_mask); 420 + that->cpu = i; 421 + break; 422 + } 423 + } 424 + } 425 + 426 + static void __cpuinit amd_uncore_cpu_down_prepare(unsigned int cpu) 427 + { 428 + if (amd_uncore_nb) 429 + uncore_down_prepare(cpu, amd_uncore_nb); 430 + 431 + if (amd_uncore_l2) 432 + uncore_down_prepare(cpu, amd_uncore_l2); 433 + } 434 + 435 + static void __cpuinit uncore_dead(unsigned int cpu, 436 + struct amd_uncore * __percpu *uncores) 437 + { 438 + struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu); 439 + 440 + if (cpu == uncore->cpu) 441 + cpumask_clear_cpu(cpu, uncore->active_mask); 442 + 443 + if (!--uncore->refcnt) 444 + kfree(uncore); 445 + *per_cpu_ptr(amd_uncore_nb, cpu) = NULL; 446 + } 447 + 448 + static void __cpuinit amd_uncore_cpu_dead(unsigned int cpu) 449 + { 450 + if (amd_uncore_nb) 451 + uncore_dead(cpu, amd_uncore_nb); 452 + 453 + if (amd_uncore_l2) 454 + uncore_dead(cpu, amd_uncore_l2); 455 + } 456 + 457 + static int __cpuinit 458 + amd_uncore_cpu_notifier(struct notifier_block *self, unsigned long action, 459 + void *hcpu) 460 + { 461 + unsigned int cpu = (long)hcpu; 462 + 463 + switch (action & ~CPU_TASKS_FROZEN) { 464 + case CPU_UP_PREPARE: 465 + amd_uncore_cpu_up_prepare(cpu); 466 + break; 467 + 468 + case CPU_STARTING: 469 + amd_uncore_cpu_starting(cpu); 470 + break; 471 + 472 + case CPU_ONLINE: 473 + amd_uncore_cpu_online(cpu); 474 + break; 475 + 476 + case CPU_DOWN_PREPARE: 477 + amd_uncore_cpu_down_prepare(cpu); 478 + break; 479 + 480 + case CPU_UP_CANCELED: 481 + case CPU_DEAD: 482 + amd_uncore_cpu_dead(cpu); 483 + break; 484 + 485 + default: 486 + break; 487 + } 488 + 489 + return NOTIFY_OK; 490 + } 491 + 492 + static struct notifier_block amd_uncore_cpu_notifier_block __cpuinitdata = { 493 + .notifier_call = amd_uncore_cpu_notifier, 494 + .priority = CPU_PRI_PERF + 1, 495 + }; 496 + 497 + static void __init init_cpu_already_online(void *dummy) 498 + { 499 + unsigned int cpu = smp_processor_id(); 500 + 501 + amd_uncore_cpu_starting(cpu); 502 + amd_uncore_cpu_online(cpu); 503 + } 504 + 505 + static int __init amd_uncore_init(void) 506 + { 507 + unsigned int cpu; 508 + int ret = -ENODEV; 509 + 510 + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 511 + return -ENODEV; 512 + 513 + if (!cpu_has_topoext) 514 + return -ENODEV; 515 + 516 + if (cpu_has_perfctr_nb) { 517 + amd_uncore_nb = alloc_percpu(struct amd_uncore *); 518 + perf_pmu_register(&amd_nb_pmu, amd_nb_pmu.name, -1); 519 + 520 + printk(KERN_INFO "perf: AMD NB counters detected\n"); 521 + ret = 0; 522 + } 523 + 524 + if (cpu_has_perfctr_l2) { 525 + amd_uncore_l2 = alloc_percpu(struct amd_uncore *); 526 + perf_pmu_register(&amd_l2_pmu, amd_l2_pmu.name, -1); 527 + 528 + printk(KERN_INFO "perf: AMD L2I counters detected\n"); 529 + ret = 0; 530 + } 531 + 532 + if (ret) 533 + return -ENODEV; 534 + 535 + get_online_cpus(); 536 + /* init cpus already online before registering for hotplug notifier */ 537 + for_each_online_cpu(cpu) { 538 + amd_uncore_cpu_up_prepare(cpu); 539 + smp_call_function_single(cpu, init_cpu_already_online, NULL, 1); 540 + } 541 + 542 + register_cpu_notifier(&amd_uncore_cpu_notifier_block); 543 + put_online_cpus(); 544 + 545 + return 0; 546 + } 547 + device_initcall(amd_uncore_init);
+37 -1
arch/x86/kernel/cpu/perf_event_intel.c
··· 81 81 static struct extra_reg intel_nehalem_extra_regs[] __read_mostly = 82 82 { 83 83 INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0), 84 + INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b), 84 85 EVENT_EXTRA_END 85 86 }; 86 87 ··· 109 108 INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.PENDING */ 110 109 INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ 111 110 INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ 111 + INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_DISPATCH */ 112 + INTEL_UEVENT_CONSTRAINT(0x02a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ 112 113 EVENT_CONSTRAINT_END 113 114 }; 114 115 ··· 139 136 { 140 137 INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0), 141 138 INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff, RSP_1), 139 + INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b), 142 140 EVENT_EXTRA_END 143 141 }; 144 142 ··· 159 155 static struct extra_reg intel_snb_extra_regs[] __read_mostly = { 160 156 INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0), 161 157 INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3f807f8fffull, RSP_1), 158 + INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd), 159 + INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd), 162 160 EVENT_EXTRA_END 163 161 }; 164 162 ··· 168 162 INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3fffff8fffull, RSP_0), 169 163 INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3fffff8fffull, RSP_1), 170 164 EVENT_EXTRA_END 165 + }; 166 + 167 + EVENT_ATTR_STR(mem-loads, mem_ld_nhm, "event=0x0b,umask=0x10,ldlat=3"); 168 + EVENT_ATTR_STR(mem-loads, mem_ld_snb, "event=0xcd,umask=0x1,ldlat=3"); 169 + EVENT_ATTR_STR(mem-stores, mem_st_snb, "event=0xcd,umask=0x2"); 170 + 171 + struct attribute *nhm_events_attrs[] = { 172 + EVENT_PTR(mem_ld_nhm), 173 + NULL, 174 + }; 175 + 176 + struct attribute *snb_events_attrs[] = { 177 + EVENT_PTR(mem_ld_snb), 178 + EVENT_PTR(mem_st_snb), 179 + NULL, 171 180 }; 172 181 173 182 static u64 intel_pmu_event_map(int hw_event) ··· 1419 1398 1420 1399 if (x86_pmu.event_constraints) { 1421 1400 for_each_event_constraint(c, x86_pmu.event_constraints) { 1422 - if ((event->hw.config & c->cmask) == c->code) 1401 + if ((event->hw.config & c->cmask) == c->code) { 1402 + /* hw.flags zeroed at initialization */ 1403 + event->hw.flags |= c->flags; 1423 1404 return c; 1405 + } 1424 1406 } 1425 1407 } 1426 1408 ··· 1468 1444 static void intel_put_event_constraints(struct cpu_hw_events *cpuc, 1469 1445 struct perf_event *event) 1470 1446 { 1447 + event->hw.flags = 0; 1471 1448 intel_put_shared_regs_event_constraints(cpuc, event); 1472 1449 } 1473 1450 ··· 1792 1767 1793 1768 PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); 1794 1769 1770 + PMU_FORMAT_ATTR(ldlat, "config1:0-15"); 1771 + 1795 1772 static struct attribute *intel_arch3_formats_attr[] = { 1796 1773 &format_attr_event.attr, 1797 1774 &format_attr_umask.attr, ··· 1804 1777 &format_attr_cmask.attr, 1805 1778 1806 1779 &format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */ 1780 + &format_attr_ldlat.attr, /* PEBS load latency */ 1807 1781 NULL, 1808 1782 }; 1809 1783 ··· 2065 2037 x86_pmu.enable_all = intel_pmu_nhm_enable_all; 2066 2038 x86_pmu.extra_regs = intel_nehalem_extra_regs; 2067 2039 2040 + x86_pmu.cpu_events = nhm_events_attrs; 2041 + 2068 2042 /* UOPS_ISSUED.STALLED_CYCLES */ 2069 2043 intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 2070 2044 X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1); ··· 2110 2080 x86_pmu.extra_regs = intel_westmere_extra_regs; 2111 2081 x86_pmu.er_flags |= ERF_HAS_RSP_1; 2112 2082 2083 + x86_pmu.cpu_events = nhm_events_attrs; 2084 + 2113 2085 /* UOPS_ISSUED.STALLED_CYCLES */ 2114 2086 intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 2115 2087 X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1); ··· 2143 2111 x86_pmu.er_flags |= ERF_HAS_RSP_1; 2144 2112 x86_pmu.er_flags |= ERF_NO_HT_SHARING; 2145 2113 2114 + x86_pmu.cpu_events = snb_events_attrs; 2115 + 2146 2116 /* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */ 2147 2117 intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 2148 2118 X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1); ··· 2173 2139 /* all extra regs are per-cpu when HT is on */ 2174 2140 x86_pmu.er_flags |= ERF_HAS_RSP_1; 2175 2141 x86_pmu.er_flags |= ERF_NO_HT_SHARING; 2142 + 2143 + x86_pmu.cpu_events = snb_events_attrs; 2176 2144 2177 2145 /* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */ 2178 2146 intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
+173 -9
arch/x86/kernel/cpu/perf_event_intel_ds.c
··· 24 24 25 25 */ 26 26 27 + union intel_x86_pebs_dse { 28 + u64 val; 29 + struct { 30 + unsigned int ld_dse:4; 31 + unsigned int ld_stlb_miss:1; 32 + unsigned int ld_locked:1; 33 + unsigned int ld_reserved:26; 34 + }; 35 + struct { 36 + unsigned int st_l1d_hit:1; 37 + unsigned int st_reserved1:3; 38 + unsigned int st_stlb_miss:1; 39 + unsigned int st_locked:1; 40 + unsigned int st_reserved2:26; 41 + }; 42 + }; 43 + 44 + 45 + /* 46 + * Map PEBS Load Latency Data Source encodings to generic 47 + * memory data source information 48 + */ 49 + #define P(a, b) PERF_MEM_S(a, b) 50 + #define OP_LH (P(OP, LOAD) | P(LVL, HIT)) 51 + #define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS)) 52 + 53 + static const u64 pebs_data_source[] = { 54 + P(OP, LOAD) | P(LVL, MISS) | P(LVL, L3) | P(SNOOP, NA),/* 0x00:ukn L3 */ 55 + OP_LH | P(LVL, L1) | P(SNOOP, NONE), /* 0x01: L1 local */ 56 + OP_LH | P(LVL, LFB) | P(SNOOP, NONE), /* 0x02: LFB hit */ 57 + OP_LH | P(LVL, L2) | P(SNOOP, NONE), /* 0x03: L2 hit */ 58 + OP_LH | P(LVL, L3) | P(SNOOP, NONE), /* 0x04: L3 hit */ 59 + OP_LH | P(LVL, L3) | P(SNOOP, MISS), /* 0x05: L3 hit, snoop miss */ 60 + OP_LH | P(LVL, L3) | P(SNOOP, HIT), /* 0x06: L3 hit, snoop hit */ 61 + OP_LH | P(LVL, L3) | P(SNOOP, HITM), /* 0x07: L3 hit, snoop hitm */ 62 + OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HIT), /* 0x08: L3 miss snoop hit */ 63 + OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HITM), /* 0x09: L3 miss snoop hitm*/ 64 + OP_LH | P(LVL, LOC_RAM) | P(SNOOP, HIT), /* 0x0a: L3 miss, shared */ 65 + OP_LH | P(LVL, REM_RAM1) | P(SNOOP, HIT), /* 0x0b: L3 miss, shared */ 66 + OP_LH | P(LVL, LOC_RAM) | SNOOP_NONE_MISS,/* 0x0c: L3 miss, excl */ 67 + OP_LH | P(LVL, REM_RAM1) | SNOOP_NONE_MISS,/* 0x0d: L3 miss, excl */ 68 + OP_LH | P(LVL, IO) | P(SNOOP, NONE), /* 0x0e: I/O */ 69 + OP_LH | P(LVL, UNC) | P(SNOOP, NONE), /* 0x0f: uncached */ 70 + }; 71 + 72 + static u64 precise_store_data(u64 status) 73 + { 74 + union intel_x86_pebs_dse dse; 75 + u64 val = P(OP, STORE) | P(SNOOP, NA) | P(LVL, L1) | P(TLB, L2); 76 + 77 + dse.val = status; 78 + 79 + /* 80 + * bit 4: TLB access 81 + * 1 = stored missed 2nd level TLB 82 + * 83 + * so it either hit the walker or the OS 84 + * otherwise hit 2nd level TLB 85 + */ 86 + if (dse.st_stlb_miss) 87 + val |= P(TLB, MISS); 88 + else 89 + val |= P(TLB, HIT); 90 + 91 + /* 92 + * bit 0: hit L1 data cache 93 + * if not set, then all we know is that 94 + * it missed L1D 95 + */ 96 + if (dse.st_l1d_hit) 97 + val |= P(LVL, HIT); 98 + else 99 + val |= P(LVL, MISS); 100 + 101 + /* 102 + * bit 5: Locked prefix 103 + */ 104 + if (dse.st_locked) 105 + val |= P(LOCK, LOCKED); 106 + 107 + return val; 108 + } 109 + 110 + static u64 load_latency_data(u64 status) 111 + { 112 + union intel_x86_pebs_dse dse; 113 + u64 val; 114 + int model = boot_cpu_data.x86_model; 115 + int fam = boot_cpu_data.x86; 116 + 117 + dse.val = status; 118 + 119 + /* 120 + * use the mapping table for bit 0-3 121 + */ 122 + val = pebs_data_source[dse.ld_dse]; 123 + 124 + /* 125 + * Nehalem models do not support TLB, Lock infos 126 + */ 127 + if (fam == 0x6 && (model == 26 || model == 30 128 + || model == 31 || model == 46)) { 129 + val |= P(TLB, NA) | P(LOCK, NA); 130 + return val; 131 + } 132 + /* 133 + * bit 4: TLB access 134 + * 0 = did not miss 2nd level TLB 135 + * 1 = missed 2nd level TLB 136 + */ 137 + if (dse.ld_stlb_miss) 138 + val |= P(TLB, MISS) | P(TLB, L2); 139 + else 140 + val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2); 141 + 142 + /* 143 + * bit 5: locked prefix 144 + */ 145 + if (dse.ld_locked) 146 + val |= P(LOCK, LOCKED); 147 + 148 + return val; 149 + } 150 + 27 151 struct pebs_record_core { 28 152 u64 flags, ip; 29 153 u64 ax, bx, cx, dx; ··· 489 365 }; 490 366 491 367 struct event_constraint intel_nehalem_pebs_event_constraints[] = { 492 - INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */ 368 + INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ 493 369 INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ 494 370 INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ 495 371 INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */ ··· 504 380 }; 505 381 506 382 struct event_constraint intel_westmere_pebs_event_constraints[] = { 507 - INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */ 383 + INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */ 508 384 INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */ 509 385 INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ 510 386 INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */ ··· 524 400 INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */ 525 401 INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ 526 402 INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */ 527 - INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.* */ 403 + INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ 404 + INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ 528 405 INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */ 529 406 INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ 530 407 INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ ··· 539 414 INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */ 540 415 INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ 541 416 INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */ 542 - INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.* */ 417 + INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ 418 + INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ 543 419 INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */ 544 420 INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ 545 421 INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ ··· 557 431 558 432 if (x86_pmu.pebs_constraints) { 559 433 for_each_event_constraint(c, x86_pmu.pebs_constraints) { 560 - if ((event->hw.config & c->cmask) == c->code) 434 + if ((event->hw.config & c->cmask) == c->code) { 435 + event->hw.flags |= c->flags; 561 436 return c; 437 + } 562 438 } 563 439 } 564 440 ··· 575 447 hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT; 576 448 577 449 cpuc->pebs_enabled |= 1ULL << hwc->idx; 450 + 451 + if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) 452 + cpuc->pebs_enabled |= 1ULL << (hwc->idx + 32); 453 + else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) 454 + cpuc->pebs_enabled |= 1ULL << 63; 578 455 } 579 456 580 457 void intel_pmu_pebs_disable(struct perf_event *event) ··· 692 559 struct pt_regs *iregs, void *__pebs) 693 560 { 694 561 /* 695 - * We cast to pebs_record_core since that is a subset of 696 - * both formats and we don't use the other fields in this 697 - * routine. 562 + * We cast to pebs_record_nhm to get the load latency data 563 + * if extra_reg MSR_PEBS_LD_LAT_THRESHOLD used 698 564 */ 699 565 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); 700 - struct pebs_record_core *pebs = __pebs; 566 + struct pebs_record_nhm *pebs = __pebs; 701 567 struct perf_sample_data data; 702 568 struct pt_regs regs; 569 + u64 sample_type; 570 + int fll, fst; 703 571 704 572 if (!intel_pmu_save_and_restart(event)) 705 573 return; 706 574 575 + fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT; 576 + fst = event->hw.flags & PERF_X86_EVENT_PEBS_ST; 577 + 707 578 perf_sample_data_init(&data, 0, event->hw.last_period); 579 + 580 + data.period = event->hw.last_period; 581 + sample_type = event->attr.sample_type; 582 + 583 + /* 584 + * if PEBS-LL or PreciseStore 585 + */ 586 + if (fll || fst) { 587 + if (sample_type & PERF_SAMPLE_ADDR) 588 + data.addr = pebs->dla; 589 + 590 + /* 591 + * Use latency for weight (only avail with PEBS-LL) 592 + */ 593 + if (fll && (sample_type & PERF_SAMPLE_WEIGHT)) 594 + data.weight = pebs->lat; 595 + 596 + /* 597 + * data.data_src encodes the data source 598 + */ 599 + if (sample_type & PERF_SAMPLE_DATA_SRC) { 600 + if (fll) 601 + data.data_src.val = load_latency_data(pebs->dse); 602 + else 603 + data.data_src.val = precise_store_data(pebs->dse); 604 + } 605 + } 708 606 709 607 /* 710 608 * We use the interrupt regs as a base because the PEBS record
+787 -89
arch/x86/kernel/cpu/perf_event_intel_uncore.c
··· 17 17 static struct event_constraint constraint_empty = 18 18 EVENT_CONSTRAINT(0, 0, 0); 19 19 20 + #define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \ 21 + ((1ULL << (n)) - 1))) 22 + 20 23 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); 21 24 DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21"); 22 25 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); ··· 34 31 DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30"); 35 32 DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51"); 36 33 DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4"); 34 + DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8"); 37 35 DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17"); 36 + DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47"); 38 37 DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22"); 38 + DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22"); 39 39 DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31"); 40 + DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60"); 40 41 DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7"); 41 42 DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15"); 42 43 DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23"); ··· 115 108 er = &box->shared_regs[reg1->idx]; 116 109 atomic_dec(&er->ref); 117 110 reg1->alloc = 0; 111 + } 112 + 113 + static u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx) 114 + { 115 + struct intel_uncore_extra_reg *er; 116 + unsigned long flags; 117 + u64 config; 118 + 119 + er = &box->shared_regs[idx]; 120 + 121 + raw_spin_lock_irqsave(&er->lock, flags); 122 + config = er->config; 123 + raw_spin_unlock_irqrestore(&er->lock, flags); 124 + 125 + return config; 118 126 } 119 127 120 128 /* Sandy Bridge-EP uncore support */ ··· 227 205 struct hw_perf_event_extra *reg1 = &hwc->extra_reg; 228 206 229 207 if (reg1->idx != EXTRA_REG_NONE) 230 - wrmsrl(reg1->reg, reg1->config); 208 + wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0)); 231 209 232 210 wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); 233 211 } ··· 246 224 247 225 if (msr) 248 226 wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT); 249 - } 250 - 251 - static int snbep_uncore_hw_config(struct intel_uncore_box *box, struct perf_event *event) 252 - { 253 - struct hw_perf_event *hwc = &event->hw; 254 - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; 255 - 256 - if (box->pmu->type == &snbep_uncore_cbox) { 257 - reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + 258 - SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; 259 - reg1->config = event->attr.config1 & 260 - SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK; 261 - } else { 262 - if (box->pmu->type == &snbep_uncore_pcu) { 263 - reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER; 264 - reg1->config = event->attr.config1 & SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK; 265 - } else { 266 - return 0; 267 - } 268 - } 269 - reg1->idx = 0; 270 - 271 - return 0; 272 227 } 273 228 274 229 static struct attribute *snbep_uncore_formats_attr[] = { ··· 344 345 .attrs = snbep_uncore_qpi_formats_attr, 345 346 }; 346 347 348 + #define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ 349 + .init_box = snbep_uncore_msr_init_box, \ 350 + .disable_box = snbep_uncore_msr_disable_box, \ 351 + .enable_box = snbep_uncore_msr_enable_box, \ 352 + .disable_event = snbep_uncore_msr_disable_event, \ 353 + .enable_event = snbep_uncore_msr_enable_event, \ 354 + .read_counter = uncore_msr_read_counter 355 + 347 356 static struct intel_uncore_ops snbep_uncore_msr_ops = { 348 - .init_box = snbep_uncore_msr_init_box, 349 - .disable_box = snbep_uncore_msr_disable_box, 350 - .enable_box = snbep_uncore_msr_enable_box, 351 - .disable_event = snbep_uncore_msr_disable_event, 352 - .enable_event = snbep_uncore_msr_enable_event, 353 - .read_counter = uncore_msr_read_counter, 354 - .get_constraint = uncore_get_constraint, 355 - .put_constraint = uncore_put_constraint, 356 - .hw_config = snbep_uncore_hw_config, 357 + SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), 357 358 }; 358 359 359 360 static struct intel_uncore_ops snbep_uncore_pci_ops = { ··· 371 372 UNCORE_EVENT_CONSTRAINT(0x04, 0x3), 372 373 UNCORE_EVENT_CONSTRAINT(0x05, 0x3), 373 374 UNCORE_EVENT_CONSTRAINT(0x07, 0x3), 375 + UNCORE_EVENT_CONSTRAINT(0x09, 0x3), 374 376 UNCORE_EVENT_CONSTRAINT(0x11, 0x1), 375 377 UNCORE_EVENT_CONSTRAINT(0x12, 0x3), 376 378 UNCORE_EVENT_CONSTRAINT(0x13, 0x3), ··· 421 421 UNCORE_EVENT_CONSTRAINT(0x24, 0x3), 422 422 UNCORE_EVENT_CONSTRAINT(0x25, 0x3), 423 423 UNCORE_EVENT_CONSTRAINT(0x26, 0x3), 424 + UNCORE_EVENT_CONSTRAINT(0x28, 0x3), 425 + UNCORE_EVENT_CONSTRAINT(0x29, 0x3), 426 + UNCORE_EVENT_CONSTRAINT(0x2a, 0x3), 427 + UNCORE_EVENT_CONSTRAINT(0x2b, 0x3), 428 + UNCORE_EVENT_CONSTRAINT(0x2c, 0x3), 429 + UNCORE_EVENT_CONSTRAINT(0x2d, 0x3), 430 + UNCORE_EVENT_CONSTRAINT(0x2e, 0x3), 431 + UNCORE_EVENT_CONSTRAINT(0x2f, 0x3), 424 432 UNCORE_EVENT_CONSTRAINT(0x30, 0x3), 425 433 UNCORE_EVENT_CONSTRAINT(0x31, 0x3), 426 434 UNCORE_EVENT_CONSTRAINT(0x32, 0x3), ··· 436 428 UNCORE_EVENT_CONSTRAINT(0x34, 0x3), 437 429 UNCORE_EVENT_CONSTRAINT(0x36, 0x3), 438 430 UNCORE_EVENT_CONSTRAINT(0x37, 0x3), 431 + UNCORE_EVENT_CONSTRAINT(0x38, 0x3), 432 + UNCORE_EVENT_CONSTRAINT(0x39, 0x3), 439 433 EVENT_CONSTRAINT_END 440 434 }; 441 435 ··· 456 446 .format_group = &snbep_uncore_ubox_format_group, 457 447 }; 458 448 449 + static struct extra_reg snbep_uncore_cbox_extra_regs[] = { 450 + SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN, 451 + SNBEP_CBO_PMON_CTL_TID_EN, 0x1), 452 + SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4), 453 + SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4), 454 + SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4), 455 + SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6), 456 + SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8), 457 + SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8), 458 + SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xc), 459 + SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xc), 460 + SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2), 461 + SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2), 462 + SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2), 463 + SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2), 464 + SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8), 465 + SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8), 466 + SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xc), 467 + SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xc), 468 + SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2), 469 + SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2), 470 + SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2), 471 + SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2), 472 + EVENT_EXTRA_END 473 + }; 474 + 475 + static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) 476 + { 477 + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; 478 + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; 479 + int i; 480 + 481 + if (uncore_box_is_fake(box)) 482 + return; 483 + 484 + for (i = 0; i < 5; i++) { 485 + if (reg1->alloc & (0x1 << i)) 486 + atomic_sub(1 << (i * 6), &er->ref); 487 + } 488 + reg1->alloc = 0; 489 + } 490 + 491 + static struct event_constraint * 492 + __snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event, 493 + u64 (*cbox_filter_mask)(int fields)) 494 + { 495 + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; 496 + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; 497 + int i, alloc = 0; 498 + unsigned long flags; 499 + u64 mask; 500 + 501 + if (reg1->idx == EXTRA_REG_NONE) 502 + return NULL; 503 + 504 + raw_spin_lock_irqsave(&er->lock, flags); 505 + for (i = 0; i < 5; i++) { 506 + if (!(reg1->idx & (0x1 << i))) 507 + continue; 508 + if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i))) 509 + continue; 510 + 511 + mask = cbox_filter_mask(0x1 << i); 512 + if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) || 513 + !((reg1->config ^ er->config) & mask)) { 514 + atomic_add(1 << (i * 6), &er->ref); 515 + er->config &= ~mask; 516 + er->config |= reg1->config & mask; 517 + alloc |= (0x1 << i); 518 + } else { 519 + break; 520 + } 521 + } 522 + raw_spin_unlock_irqrestore(&er->lock, flags); 523 + if (i < 5) 524 + goto fail; 525 + 526 + if (!uncore_box_is_fake(box)) 527 + reg1->alloc |= alloc; 528 + 529 + return 0; 530 + fail: 531 + for (; i >= 0; i--) { 532 + if (alloc & (0x1 << i)) 533 + atomic_sub(1 << (i * 6), &er->ref); 534 + } 535 + return &constraint_empty; 536 + } 537 + 538 + static u64 snbep_cbox_filter_mask(int fields) 539 + { 540 + u64 mask = 0; 541 + 542 + if (fields & 0x1) 543 + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID; 544 + if (fields & 0x2) 545 + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID; 546 + if (fields & 0x4) 547 + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE; 548 + if (fields & 0x8) 549 + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC; 550 + 551 + return mask; 552 + } 553 + 554 + static struct event_constraint * 555 + snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) 556 + { 557 + return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask); 558 + } 559 + 560 + static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) 561 + { 562 + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; 563 + struct extra_reg *er; 564 + int idx = 0; 565 + 566 + for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) { 567 + if (er->event != (event->hw.config & er->config_mask)) 568 + continue; 569 + idx |= er->idx; 570 + } 571 + 572 + if (idx) { 573 + reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + 574 + SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; 575 + reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx); 576 + reg1->idx = idx; 577 + } 578 + return 0; 579 + } 580 + 581 + static struct intel_uncore_ops snbep_uncore_cbox_ops = { 582 + SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), 583 + .hw_config = snbep_cbox_hw_config, 584 + .get_constraint = snbep_cbox_get_constraint, 585 + .put_constraint = snbep_cbox_put_constraint, 586 + }; 587 + 459 588 static struct intel_uncore_type snbep_uncore_cbox = { 460 589 .name = "cbox", 461 590 .num_counters = 4, ··· 607 458 .msr_offset = SNBEP_CBO_MSR_OFFSET, 608 459 .num_shared_regs = 1, 609 460 .constraints = snbep_uncore_cbox_constraints, 610 - .ops = &snbep_uncore_msr_ops, 461 + .ops = &snbep_uncore_cbox_ops, 611 462 .format_group = &snbep_uncore_cbox_format_group, 463 + }; 464 + 465 + static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify) 466 + { 467 + struct hw_perf_event *hwc = &event->hw; 468 + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; 469 + u64 config = reg1->config; 470 + 471 + if (new_idx > reg1->idx) 472 + config <<= 8 * (new_idx - reg1->idx); 473 + else 474 + config >>= 8 * (reg1->idx - new_idx); 475 + 476 + if (modify) { 477 + hwc->config += new_idx - reg1->idx; 478 + reg1->config = config; 479 + reg1->idx = new_idx; 480 + } 481 + return config; 482 + } 483 + 484 + static struct event_constraint * 485 + snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event) 486 + { 487 + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; 488 + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; 489 + unsigned long flags; 490 + int idx = reg1->idx; 491 + u64 mask, config1 = reg1->config; 492 + bool ok = false; 493 + 494 + if (reg1->idx == EXTRA_REG_NONE || 495 + (!uncore_box_is_fake(box) && reg1->alloc)) 496 + return NULL; 497 + again: 498 + mask = 0xff << (idx * 8); 499 + raw_spin_lock_irqsave(&er->lock, flags); 500 + if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) || 501 + !((config1 ^ er->config) & mask)) { 502 + atomic_add(1 << (idx * 8), &er->ref); 503 + er->config &= ~mask; 504 + er->config |= config1 & mask; 505 + ok = true; 506 + } 507 + raw_spin_unlock_irqrestore(&er->lock, flags); 508 + 509 + if (!ok) { 510 + idx = (idx + 1) % 4; 511 + if (idx != reg1->idx) { 512 + config1 = snbep_pcu_alter_er(event, idx, false); 513 + goto again; 514 + } 515 + return &constraint_empty; 516 + } 517 + 518 + if (!uncore_box_is_fake(box)) { 519 + if (idx != reg1->idx) 520 + snbep_pcu_alter_er(event, idx, true); 521 + reg1->alloc = 1; 522 + } 523 + return NULL; 524 + } 525 + 526 + static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event) 527 + { 528 + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; 529 + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; 530 + 531 + if (uncore_box_is_fake(box) || !reg1->alloc) 532 + return; 533 + 534 + atomic_sub(1 << (reg1->idx * 8), &er->ref); 535 + reg1->alloc = 0; 536 + } 537 + 538 + static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event) 539 + { 540 + struct hw_perf_event *hwc = &event->hw; 541 + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; 542 + int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK; 543 + 544 + if (ev_sel >= 0xb && ev_sel <= 0xe) { 545 + reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER; 546 + reg1->idx = ev_sel - 0xb; 547 + reg1->config = event->attr.config1 & (0xff << reg1->idx); 548 + } 549 + return 0; 550 + } 551 + 552 + static struct intel_uncore_ops snbep_uncore_pcu_ops = { 553 + SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), 554 + .hw_config = snbep_pcu_hw_config, 555 + .get_constraint = snbep_pcu_get_constraint, 556 + .put_constraint = snbep_pcu_put_constraint, 612 557 }; 613 558 614 559 static struct intel_uncore_type snbep_uncore_pcu = { ··· 715 472 .event_mask = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK, 716 473 .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, 717 474 .num_shared_regs = 1, 718 - .ops = &snbep_uncore_msr_ops, 475 + .ops = &snbep_uncore_pcu_ops, 719 476 .format_group = &snbep_uncore_pcu_format_group, 720 477 }; 721 478 ··· 787 544 SNBEP_UNCORE_PCI_COMMON_INIT(), 788 545 }; 789 546 547 + enum { 548 + SNBEP_PCI_UNCORE_HA, 549 + SNBEP_PCI_UNCORE_IMC, 550 + SNBEP_PCI_UNCORE_QPI, 551 + SNBEP_PCI_UNCORE_R2PCIE, 552 + SNBEP_PCI_UNCORE_R3QPI, 553 + }; 554 + 790 555 static struct intel_uncore_type *snbep_pci_uncores[] = { 791 - &snbep_uncore_ha, 792 - &snbep_uncore_imc, 793 - &snbep_uncore_qpi, 794 - &snbep_uncore_r2pcie, 795 - &snbep_uncore_r3qpi, 556 + [SNBEP_PCI_UNCORE_HA] = &snbep_uncore_ha, 557 + [SNBEP_PCI_UNCORE_IMC] = &snbep_uncore_imc, 558 + [SNBEP_PCI_UNCORE_QPI] = &snbep_uncore_qpi, 559 + [SNBEP_PCI_UNCORE_R2PCIE] = &snbep_uncore_r2pcie, 560 + [SNBEP_PCI_UNCORE_R3QPI] = &snbep_uncore_r3qpi, 796 561 NULL, 797 562 }; 798 563 799 564 static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = { 800 565 { /* Home Agent */ 801 566 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA), 802 - .driver_data = (unsigned long)&snbep_uncore_ha, 567 + .driver_data = SNBEP_PCI_UNCORE_HA, 803 568 }, 804 569 { /* MC Channel 0 */ 805 570 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0), 806 - .driver_data = (unsigned long)&snbep_uncore_imc, 571 + .driver_data = SNBEP_PCI_UNCORE_IMC, 807 572 }, 808 573 { /* MC Channel 1 */ 809 574 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1), 810 - .driver_data = (unsigned long)&snbep_uncore_imc, 575 + .driver_data = SNBEP_PCI_UNCORE_IMC, 811 576 }, 812 577 { /* MC Channel 2 */ 813 578 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2), 814 - .driver_data = (unsigned long)&snbep_uncore_imc, 579 + .driver_data = SNBEP_PCI_UNCORE_IMC, 815 580 }, 816 581 { /* MC Channel 3 */ 817 582 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3), 818 - .driver_data = (unsigned long)&snbep_uncore_imc, 583 + .driver_data = SNBEP_PCI_UNCORE_IMC, 819 584 }, 820 585 { /* QPI Port 0 */ 821 586 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0), 822 - .driver_data = (unsigned long)&snbep_uncore_qpi, 587 + .driver_data = SNBEP_PCI_UNCORE_QPI, 823 588 }, 824 589 { /* QPI Port 1 */ 825 590 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1), 826 - .driver_data = (unsigned long)&snbep_uncore_qpi, 591 + .driver_data = SNBEP_PCI_UNCORE_QPI, 827 592 }, 828 - { /* P2PCIe */ 593 + { /* R2PCIe */ 829 594 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE), 830 - .driver_data = (unsigned long)&snbep_uncore_r2pcie, 595 + .driver_data = SNBEP_PCI_UNCORE_R2PCIE, 831 596 }, 832 597 { /* R3QPI Link 0 */ 833 598 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0), 834 - .driver_data = (unsigned long)&snbep_uncore_r3qpi, 599 + .driver_data = SNBEP_PCI_UNCORE_R3QPI, 835 600 }, 836 601 { /* R3QPI Link 1 */ 837 602 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1), 838 - .driver_data = (unsigned long)&snbep_uncore_r3qpi, 603 + .driver_data = SNBEP_PCI_UNCORE_R3QPI, 839 604 }, 840 605 { /* end: all zeroes */ } 841 606 }; ··· 856 605 /* 857 606 * build pci bus to socket mapping 858 607 */ 859 - static int snbep_pci2phy_map_init(void) 608 + static int snbep_pci2phy_map_init(int devid) 860 609 { 861 610 struct pci_dev *ubox_dev = NULL; 862 611 int i, bus, nodeid; ··· 865 614 866 615 while (1) { 867 616 /* find the UBOX device */ 868 - ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 869 - PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX, 870 - ubox_dev); 617 + ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev); 871 618 if (!ubox_dev) 872 619 break; 873 620 bus = ubox_dev->bus->number; ··· 888 639 break; 889 640 } 890 641 } 891 - }; 642 + } 892 643 893 644 if (ubox_dev) 894 645 pci_dev_put(ubox_dev); ··· 896 647 return err ? pcibios_err_to_errno(err) : 0; 897 648 } 898 649 /* end of Sandy Bridge-EP uncore support */ 650 + 651 + /* IvyTown uncore support */ 652 + static void ivt_uncore_msr_init_box(struct intel_uncore_box *box) 653 + { 654 + unsigned msr = uncore_msr_box_ctl(box); 655 + if (msr) 656 + wrmsrl(msr, IVT_PMON_BOX_CTL_INT); 657 + } 658 + 659 + static void ivt_uncore_pci_init_box(struct intel_uncore_box *box) 660 + { 661 + struct pci_dev *pdev = box->pci_dev; 662 + 663 + pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVT_PMON_BOX_CTL_INT); 664 + } 665 + 666 + #define IVT_UNCORE_MSR_OPS_COMMON_INIT() \ 667 + .init_box = ivt_uncore_msr_init_box, \ 668 + .disable_box = snbep_uncore_msr_disable_box, \ 669 + .enable_box = snbep_uncore_msr_enable_box, \ 670 + .disable_event = snbep_uncore_msr_disable_event, \ 671 + .enable_event = snbep_uncore_msr_enable_event, \ 672 + .read_counter = uncore_msr_read_counter 673 + 674 + static struct intel_uncore_ops ivt_uncore_msr_ops = { 675 + IVT_UNCORE_MSR_OPS_COMMON_INIT(), 676 + }; 677 + 678 + static struct intel_uncore_ops ivt_uncore_pci_ops = { 679 + .init_box = ivt_uncore_pci_init_box, 680 + .disable_box = snbep_uncore_pci_disable_box, 681 + .enable_box = snbep_uncore_pci_enable_box, 682 + .disable_event = snbep_uncore_pci_disable_event, 683 + .enable_event = snbep_uncore_pci_enable_event, 684 + .read_counter = snbep_uncore_pci_read_counter, 685 + }; 686 + 687 + #define IVT_UNCORE_PCI_COMMON_INIT() \ 688 + .perf_ctr = SNBEP_PCI_PMON_CTR0, \ 689 + .event_ctl = SNBEP_PCI_PMON_CTL0, \ 690 + .event_mask = IVT_PMON_RAW_EVENT_MASK, \ 691 + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ 692 + .ops = &ivt_uncore_pci_ops, \ 693 + .format_group = &ivt_uncore_format_group 694 + 695 + static struct attribute *ivt_uncore_formats_attr[] = { 696 + &format_attr_event.attr, 697 + &format_attr_umask.attr, 698 + &format_attr_edge.attr, 699 + &format_attr_inv.attr, 700 + &format_attr_thresh8.attr, 701 + NULL, 702 + }; 703 + 704 + static struct attribute *ivt_uncore_ubox_formats_attr[] = { 705 + &format_attr_event.attr, 706 + &format_attr_umask.attr, 707 + &format_attr_edge.attr, 708 + &format_attr_inv.attr, 709 + &format_attr_thresh5.attr, 710 + NULL, 711 + }; 712 + 713 + static struct attribute *ivt_uncore_cbox_formats_attr[] = { 714 + &format_attr_event.attr, 715 + &format_attr_umask.attr, 716 + &format_attr_edge.attr, 717 + &format_attr_tid_en.attr, 718 + &format_attr_thresh8.attr, 719 + &format_attr_filter_tid.attr, 720 + &format_attr_filter_link.attr, 721 + &format_attr_filter_state2.attr, 722 + &format_attr_filter_nid2.attr, 723 + &format_attr_filter_opc2.attr, 724 + NULL, 725 + }; 726 + 727 + static struct attribute *ivt_uncore_pcu_formats_attr[] = { 728 + &format_attr_event_ext.attr, 729 + &format_attr_occ_sel.attr, 730 + &format_attr_edge.attr, 731 + &format_attr_thresh5.attr, 732 + &format_attr_occ_invert.attr, 733 + &format_attr_occ_edge.attr, 734 + &format_attr_filter_band0.attr, 735 + &format_attr_filter_band1.attr, 736 + &format_attr_filter_band2.attr, 737 + &format_attr_filter_band3.attr, 738 + NULL, 739 + }; 740 + 741 + static struct attribute *ivt_uncore_qpi_formats_attr[] = { 742 + &format_attr_event_ext.attr, 743 + &format_attr_umask.attr, 744 + &format_attr_edge.attr, 745 + &format_attr_thresh8.attr, 746 + NULL, 747 + }; 748 + 749 + static struct attribute_group ivt_uncore_format_group = { 750 + .name = "format", 751 + .attrs = ivt_uncore_formats_attr, 752 + }; 753 + 754 + static struct attribute_group ivt_uncore_ubox_format_group = { 755 + .name = "format", 756 + .attrs = ivt_uncore_ubox_formats_attr, 757 + }; 758 + 759 + static struct attribute_group ivt_uncore_cbox_format_group = { 760 + .name = "format", 761 + .attrs = ivt_uncore_cbox_formats_attr, 762 + }; 763 + 764 + static struct attribute_group ivt_uncore_pcu_format_group = { 765 + .name = "format", 766 + .attrs = ivt_uncore_pcu_formats_attr, 767 + }; 768 + 769 + static struct attribute_group ivt_uncore_qpi_format_group = { 770 + .name = "format", 771 + .attrs = ivt_uncore_qpi_formats_attr, 772 + }; 773 + 774 + static struct intel_uncore_type ivt_uncore_ubox = { 775 + .name = "ubox", 776 + .num_counters = 2, 777 + .num_boxes = 1, 778 + .perf_ctr_bits = 44, 779 + .fixed_ctr_bits = 48, 780 + .perf_ctr = SNBEP_U_MSR_PMON_CTR0, 781 + .event_ctl = SNBEP_U_MSR_PMON_CTL0, 782 + .event_mask = IVT_U_MSR_PMON_RAW_EVENT_MASK, 783 + .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, 784 + .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, 785 + .ops = &ivt_uncore_msr_ops, 786 + .format_group = &ivt_uncore_ubox_format_group, 787 + }; 788 + 789 + static struct extra_reg ivt_uncore_cbox_extra_regs[] = { 790 + SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN, 791 + SNBEP_CBO_PMON_CTL_TID_EN, 0x1), 792 + SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2), 793 + SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4), 794 + SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4), 795 + SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4), 796 + SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc), 797 + SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10), 798 + SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10), 799 + SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10), 800 + SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10), 801 + SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18), 802 + SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18), 803 + SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8), 804 + SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8), 805 + SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8), 806 + SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8), 807 + SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10), 808 + SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10), 809 + SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10), 810 + SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10), 811 + SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10), 812 + SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10), 813 + SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18), 814 + SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18), 815 + SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8), 816 + SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8), 817 + SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8), 818 + SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8), 819 + SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10), 820 + SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10), 821 + SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8), 822 + EVENT_EXTRA_END 823 + }; 824 + 825 + static u64 ivt_cbox_filter_mask(int fields) 826 + { 827 + u64 mask = 0; 828 + 829 + if (fields & 0x1) 830 + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_TID; 831 + if (fields & 0x2) 832 + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_LINK; 833 + if (fields & 0x4) 834 + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_STATE; 835 + if (fields & 0x8) 836 + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_NID; 837 + if (fields & 0x10) 838 + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_OPC; 839 + 840 + return mask; 841 + } 842 + 843 + static struct event_constraint * 844 + ivt_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) 845 + { 846 + return __snbep_cbox_get_constraint(box, event, ivt_cbox_filter_mask); 847 + } 848 + 849 + static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) 850 + { 851 + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; 852 + struct extra_reg *er; 853 + int idx = 0; 854 + 855 + for (er = ivt_uncore_cbox_extra_regs; er->msr; er++) { 856 + if (er->event != (event->hw.config & er->config_mask)) 857 + continue; 858 + idx |= er->idx; 859 + } 860 + 861 + if (idx) { 862 + reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + 863 + SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; 864 + reg1->config = event->attr.config1 & ivt_cbox_filter_mask(idx); 865 + reg1->idx = idx; 866 + } 867 + return 0; 868 + } 869 + 870 + static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event) 871 + { 872 + struct hw_perf_event *hwc = &event->hw; 873 + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; 874 + 875 + if (reg1->idx != EXTRA_REG_NONE) { 876 + u64 filter = uncore_shared_reg_config(box, 0); 877 + wrmsrl(reg1->reg, filter & 0xffffffff); 878 + wrmsrl(reg1->reg + 6, filter >> 32); 879 + } 880 + 881 + wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); 882 + } 883 + 884 + static struct intel_uncore_ops ivt_uncore_cbox_ops = { 885 + .init_box = ivt_uncore_msr_init_box, 886 + .disable_box = snbep_uncore_msr_disable_box, 887 + .enable_box = snbep_uncore_msr_enable_box, 888 + .disable_event = snbep_uncore_msr_disable_event, 889 + .enable_event = ivt_cbox_enable_event, 890 + .read_counter = uncore_msr_read_counter, 891 + .hw_config = ivt_cbox_hw_config, 892 + .get_constraint = ivt_cbox_get_constraint, 893 + .put_constraint = snbep_cbox_put_constraint, 894 + }; 895 + 896 + static struct intel_uncore_type ivt_uncore_cbox = { 897 + .name = "cbox", 898 + .num_counters = 4, 899 + .num_boxes = 15, 900 + .perf_ctr_bits = 44, 901 + .event_ctl = SNBEP_C0_MSR_PMON_CTL0, 902 + .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, 903 + .event_mask = IVT_CBO_MSR_PMON_RAW_EVENT_MASK, 904 + .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, 905 + .msr_offset = SNBEP_CBO_MSR_OFFSET, 906 + .num_shared_regs = 1, 907 + .constraints = snbep_uncore_cbox_constraints, 908 + .ops = &ivt_uncore_cbox_ops, 909 + .format_group = &ivt_uncore_cbox_format_group, 910 + }; 911 + 912 + static struct intel_uncore_ops ivt_uncore_pcu_ops = { 913 + IVT_UNCORE_MSR_OPS_COMMON_INIT(), 914 + .hw_config = snbep_pcu_hw_config, 915 + .get_constraint = snbep_pcu_get_constraint, 916 + .put_constraint = snbep_pcu_put_constraint, 917 + }; 918 + 919 + static struct intel_uncore_type ivt_uncore_pcu = { 920 + .name = "pcu", 921 + .num_counters = 4, 922 + .num_boxes = 1, 923 + .perf_ctr_bits = 48, 924 + .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, 925 + .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, 926 + .event_mask = IVT_PCU_MSR_PMON_RAW_EVENT_MASK, 927 + .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, 928 + .num_shared_regs = 1, 929 + .ops = &ivt_uncore_pcu_ops, 930 + .format_group = &ivt_uncore_pcu_format_group, 931 + }; 932 + 933 + static struct intel_uncore_type *ivt_msr_uncores[] = { 934 + &ivt_uncore_ubox, 935 + &ivt_uncore_cbox, 936 + &ivt_uncore_pcu, 937 + NULL, 938 + }; 939 + 940 + static struct intel_uncore_type ivt_uncore_ha = { 941 + .name = "ha", 942 + .num_counters = 4, 943 + .num_boxes = 2, 944 + .perf_ctr_bits = 48, 945 + IVT_UNCORE_PCI_COMMON_INIT(), 946 + }; 947 + 948 + static struct intel_uncore_type ivt_uncore_imc = { 949 + .name = "imc", 950 + .num_counters = 4, 951 + .num_boxes = 8, 952 + .perf_ctr_bits = 48, 953 + .fixed_ctr_bits = 48, 954 + .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, 955 + .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, 956 + IVT_UNCORE_PCI_COMMON_INIT(), 957 + }; 958 + 959 + static struct intel_uncore_type ivt_uncore_qpi = { 960 + .name = "qpi", 961 + .num_counters = 4, 962 + .num_boxes = 3, 963 + .perf_ctr_bits = 48, 964 + .perf_ctr = SNBEP_PCI_PMON_CTR0, 965 + .event_ctl = SNBEP_PCI_PMON_CTL0, 966 + .event_mask = IVT_QPI_PCI_PMON_RAW_EVENT_MASK, 967 + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, 968 + .ops = &ivt_uncore_pci_ops, 969 + .format_group = &ivt_uncore_qpi_format_group, 970 + }; 971 + 972 + static struct intel_uncore_type ivt_uncore_r2pcie = { 973 + .name = "r2pcie", 974 + .num_counters = 4, 975 + .num_boxes = 1, 976 + .perf_ctr_bits = 44, 977 + .constraints = snbep_uncore_r2pcie_constraints, 978 + IVT_UNCORE_PCI_COMMON_INIT(), 979 + }; 980 + 981 + static struct intel_uncore_type ivt_uncore_r3qpi = { 982 + .name = "r3qpi", 983 + .num_counters = 3, 984 + .num_boxes = 2, 985 + .perf_ctr_bits = 44, 986 + .constraints = snbep_uncore_r3qpi_constraints, 987 + IVT_UNCORE_PCI_COMMON_INIT(), 988 + }; 989 + 990 + enum { 991 + IVT_PCI_UNCORE_HA, 992 + IVT_PCI_UNCORE_IMC, 993 + IVT_PCI_UNCORE_QPI, 994 + IVT_PCI_UNCORE_R2PCIE, 995 + IVT_PCI_UNCORE_R3QPI, 996 + }; 997 + 998 + static struct intel_uncore_type *ivt_pci_uncores[] = { 999 + [IVT_PCI_UNCORE_HA] = &ivt_uncore_ha, 1000 + [IVT_PCI_UNCORE_IMC] = &ivt_uncore_imc, 1001 + [IVT_PCI_UNCORE_QPI] = &ivt_uncore_qpi, 1002 + [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie, 1003 + [IVT_PCI_UNCORE_R3QPI] = &ivt_uncore_r3qpi, 1004 + NULL, 1005 + }; 1006 + 1007 + static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = { 1008 + { /* Home Agent 0 */ 1009 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30), 1010 + .driver_data = IVT_PCI_UNCORE_HA, 1011 + }, 1012 + { /* Home Agent 1 */ 1013 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38), 1014 + .driver_data = IVT_PCI_UNCORE_HA, 1015 + }, 1016 + { /* MC0 Channel 0 */ 1017 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4), 1018 + .driver_data = IVT_PCI_UNCORE_IMC, 1019 + }, 1020 + { /* MC0 Channel 1 */ 1021 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5), 1022 + .driver_data = IVT_PCI_UNCORE_IMC, 1023 + }, 1024 + { /* MC0 Channel 3 */ 1025 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0), 1026 + .driver_data = IVT_PCI_UNCORE_IMC, 1027 + }, 1028 + { /* MC0 Channel 4 */ 1029 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1), 1030 + .driver_data = IVT_PCI_UNCORE_IMC, 1031 + }, 1032 + { /* MC1 Channel 0 */ 1033 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4), 1034 + .driver_data = IVT_PCI_UNCORE_IMC, 1035 + }, 1036 + { /* MC1 Channel 1 */ 1037 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5), 1038 + .driver_data = IVT_PCI_UNCORE_IMC, 1039 + }, 1040 + { /* MC1 Channel 3 */ 1041 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0), 1042 + .driver_data = IVT_PCI_UNCORE_IMC, 1043 + }, 1044 + { /* MC1 Channel 4 */ 1045 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1), 1046 + .driver_data = IVT_PCI_UNCORE_IMC, 1047 + }, 1048 + { /* QPI0 Port 0 */ 1049 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32), 1050 + .driver_data = IVT_PCI_UNCORE_QPI, 1051 + }, 1052 + { /* QPI0 Port 1 */ 1053 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33), 1054 + .driver_data = IVT_PCI_UNCORE_QPI, 1055 + }, 1056 + { /* QPI1 Port 2 */ 1057 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a), 1058 + .driver_data = IVT_PCI_UNCORE_QPI, 1059 + }, 1060 + { /* R2PCIe */ 1061 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34), 1062 + .driver_data = IVT_PCI_UNCORE_R2PCIE, 1063 + }, 1064 + { /* R3QPI0 Link 0 */ 1065 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36), 1066 + .driver_data = IVT_PCI_UNCORE_R3QPI, 1067 + }, 1068 + { /* R3QPI0 Link 1 */ 1069 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37), 1070 + .driver_data = IVT_PCI_UNCORE_R3QPI, 1071 + }, 1072 + { /* R3QPI1 Link 2 */ 1073 + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e), 1074 + .driver_data = IVT_PCI_UNCORE_R3QPI, 1075 + }, 1076 + { /* end: all zeroes */ } 1077 + }; 1078 + 1079 + static struct pci_driver ivt_uncore_pci_driver = { 1080 + .name = "ivt_uncore", 1081 + .id_table = ivt_uncore_pci_ids, 1082 + }; 1083 + /* end of IvyTown uncore support */ 899 1084 900 1085 /* Sandy Bridge uncore support */ 901 1086 static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) ··· 1491 808 /* end of Nehalem uncore support */ 1492 809 1493 810 /* Nehalem-EX uncore support */ 1494 - #define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \ 1495 - ((1ULL << (n)) - 1))) 1496 - 1497 811 DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5"); 1498 812 DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7"); 1499 813 DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63"); ··· 1841 1161 }; 1842 1162 1843 1163 /* Nehalem-EX or Westmere-EX ? */ 1844 - bool uncore_nhmex; 1164 + static bool uncore_nhmex; 1845 1165 1846 1166 static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config) 1847 1167 { ··· 1919 1239 atomic_sub(1 << (idx * 8), &er->ref); 1920 1240 } 1921 1241 1922 - u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify) 1242 + static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify) 1923 1243 { 1924 1244 struct hw_perf_event *hwc = &event->hw; 1925 1245 struct hw_perf_event_extra *reg1 = &hwc->extra_reg; ··· 2234 1554 .format_group = &nhmex_uncore_mbox_format_group, 2235 1555 }; 2236 1556 2237 - void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event) 1557 + static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event) 2238 1558 { 2239 1559 struct hw_perf_event *hwc = &event->hw; 2240 1560 struct hw_perf_event_extra *reg1 = &hwc->extra_reg; ··· 2404 1724 return 0; 2405 1725 } 2406 1726 2407 - static u64 nhmex_rbox_shared_reg_config(struct intel_uncore_box *box, int idx) 2408 - { 2409 - struct intel_uncore_extra_reg *er; 2410 - unsigned long flags; 2411 - u64 config; 2412 - 2413 - er = &box->shared_regs[idx]; 2414 - 2415 - raw_spin_lock_irqsave(&er->lock, flags); 2416 - config = er->config; 2417 - raw_spin_unlock_irqrestore(&er->lock, flags); 2418 - 2419 - return config; 2420 - } 2421 - 2422 1727 static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) 2423 1728 { 2424 1729 struct hw_perf_event *hwc = &event->hw; ··· 2424 1759 case 2: 2425 1760 case 3: 2426 1761 wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port), 2427 - nhmex_rbox_shared_reg_config(box, 2 + (idx / 6) * 5)); 1762 + uncore_shared_reg_config(box, 2 + (idx / 6) * 5)); 2428 1763 break; 2429 1764 case 4: 2430 1765 wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port), ··· 2950 2285 return ret; 2951 2286 } 2952 2287 2953 - int uncore_pmu_event_init(struct perf_event *event) 2288 + static int uncore_pmu_event_init(struct perf_event *event) 2954 2289 { 2955 2290 struct intel_uncore_pmu *pmu; 2956 2291 struct intel_uncore_box *box; ··· 3103 2438 3104 2439 type->unconstrainted = (struct event_constraint) 3105 2440 __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1, 3106 - 0, type->num_counters, 0); 2441 + 0, type->num_counters, 0, 0); 3107 2442 3108 2443 for (i = 0; i < type->num_boxes; i++) { 3109 2444 pmus[i].func_id = -1; ··· 3221 2556 if (WARN_ON_ONCE(phys_id != box->phys_id)) 3222 2557 return; 3223 2558 2559 + pci_set_drvdata(pdev, NULL); 2560 + 3224 2561 raw_spin_lock(&uncore_box_lock); 3225 2562 list_del(&box->list); 3226 2563 raw_spin_unlock(&uncore_box_lock); ··· 3241 2574 static int uncore_pci_probe(struct pci_dev *pdev, 3242 2575 const struct pci_device_id *id) 3243 2576 { 3244 - struct intel_uncore_type *type; 3245 - 3246 - type = (struct intel_uncore_type *)id->driver_data; 3247 - 3248 - return uncore_pci_add(type, pdev); 2577 + return uncore_pci_add(pci_uncores[id->driver_data], pdev); 3249 2578 } 3250 2579 3251 2580 static int __init uncore_pci_init(void) ··· 3250 2587 3251 2588 switch (boot_cpu_data.x86_model) { 3252 2589 case 45: /* Sandy Bridge-EP */ 3253 - ret = snbep_pci2phy_map_init(); 2590 + ret = snbep_pci2phy_map_init(0x3ce0); 3254 2591 if (ret) 3255 2592 return ret; 3256 2593 pci_uncores = snbep_pci_uncores; 3257 2594 uncore_pci_driver = &snbep_uncore_pci_driver; 2595 + break; 2596 + case 62: /* IvyTown */ 2597 + ret = snbep_pci2phy_map_init(0x0e1e); 2598 + if (ret) 2599 + return ret; 2600 + pci_uncores = ivt_pci_uncores; 2601 + uncore_pci_driver = &ivt_uncore_pci_driver; 3258 2602 break; 3259 2603 default: 3260 2604 return 0; ··· 3292 2622 } 3293 2623 } 3294 2624 2625 + /* CPU hot plug/unplug are serialized by cpu_add_remove_lock mutex */ 2626 + static LIST_HEAD(boxes_to_free); 2627 + 2628 + static void __cpuinit uncore_kfree_boxes(void) 2629 + { 2630 + struct intel_uncore_box *box; 2631 + 2632 + while (!list_empty(&boxes_to_free)) { 2633 + box = list_entry(boxes_to_free.next, 2634 + struct intel_uncore_box, list); 2635 + list_del(&box->list); 2636 + kfree(box); 2637 + } 2638 + } 2639 + 3295 2640 static void __cpuinit uncore_cpu_dying(int cpu) 3296 2641 { 3297 2642 struct intel_uncore_type *type; ··· 3321 2636 box = *per_cpu_ptr(pmu->box, cpu); 3322 2637 *per_cpu_ptr(pmu->box, cpu) = NULL; 3323 2638 if (box && atomic_dec_and_test(&box->refcnt)) 3324 - kfree(box); 2639 + list_add(&box->list, &boxes_to_free); 3325 2640 } 3326 2641 } 3327 2642 } ··· 3351 2666 if (exist && exist->phys_id == phys_id) { 3352 2667 atomic_inc(&exist->refcnt); 3353 2668 *per_cpu_ptr(pmu->box, cpu) = exist; 3354 - kfree(box); 3355 - box = NULL; 2669 + if (box) { 2670 + list_add(&box->list, 2671 + &boxes_to_free); 2672 + box = NULL; 2673 + } 3356 2674 break; 3357 2675 } 3358 2676 } ··· 3494 2806 case CPU_DYING: 3495 2807 uncore_cpu_dying(cpu); 3496 2808 break; 2809 + case CPU_ONLINE: 2810 + case CPU_DEAD: 2811 + uncore_kfree_boxes(); 2812 + break; 3497 2813 default: 3498 2814 break; 3499 2815 } ··· 3563 2871 nhmex_uncore_cbox.num_boxes = max_cores; 3564 2872 msr_uncores = nhmex_msr_uncores; 3565 2873 break; 2874 + case 62: /* IvyTown */ 2875 + if (ivt_uncore_cbox.num_boxes > max_cores) 2876 + ivt_uncore_cbox.num_boxes = max_cores; 2877 + msr_uncores = ivt_msr_uncores; 2878 + break; 2879 + 3566 2880 default: 3567 2881 return 0; 3568 2882 }
+62 -2
arch/x86/kernel/cpu/perf_event_intel_uncore.h
··· 76 76 #define SNBEP_PMON_CTL_UMASK_MASK 0x0000ff00 77 77 #define SNBEP_PMON_CTL_RST (1 << 17) 78 78 #define SNBEP_PMON_CTL_EDGE_DET (1 << 18) 79 - #define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21) /* only for QPI */ 79 + #define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21) 80 80 #define SNBEP_PMON_CTL_EN (1 << 22) 81 81 #define SNBEP_PMON_CTL_INVERT (1 << 23) 82 82 #define SNBEP_PMON_CTL_TRESH_MASK 0xff000000 ··· 148 148 #define SNBEP_C0_MSR_PMON_CTL0 0xd10 149 149 #define SNBEP_C0_MSR_PMON_BOX_CTL 0xd04 150 150 #define SNBEP_C0_MSR_PMON_BOX_FILTER 0xd14 151 - #define SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK 0xfffffc1f 152 151 #define SNBEP_CBO_MSR_OFFSET 0x20 152 + 153 + #define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID 0x1f 154 + #define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID 0x3fc00 155 + #define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE 0x7c0000 156 + #define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC 0xff800000 157 + 158 + #define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) { \ 159 + .event = (e), \ 160 + .msr = SNBEP_C0_MSR_PMON_BOX_FILTER, \ 161 + .config_mask = (m), \ 162 + .idx = (i) \ 163 + } 153 164 154 165 /* SNB-EP PCU register */ 155 166 #define SNBEP_PCU_MSR_PMON_CTR0 0xc36 ··· 170 159 #define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK 0xffffffff 171 160 #define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc 172 161 #define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd 162 + 163 + /* IVT event control */ 164 + #define IVT_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ 165 + SNBEP_PMON_BOX_CTL_RST_CTRS) 166 + #define IVT_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ 167 + SNBEP_PMON_CTL_UMASK_MASK | \ 168 + SNBEP_PMON_CTL_EDGE_DET | \ 169 + SNBEP_PMON_CTL_TRESH_MASK) 170 + /* IVT Ubox */ 171 + #define IVT_U_MSR_PMON_GLOBAL_CTL 0xc00 172 + #define IVT_U_PMON_GLOBAL_FRZ_ALL (1 << 31) 173 + #define IVT_U_PMON_GLOBAL_UNFRZ_ALL (1 << 29) 174 + 175 + #define IVT_U_MSR_PMON_RAW_EVENT_MASK \ 176 + (SNBEP_PMON_CTL_EV_SEL_MASK | \ 177 + SNBEP_PMON_CTL_UMASK_MASK | \ 178 + SNBEP_PMON_CTL_EDGE_DET | \ 179 + SNBEP_U_MSR_PMON_CTL_TRESH_MASK) 180 + /* IVT Cbo */ 181 + #define IVT_CBO_MSR_PMON_RAW_EVENT_MASK (IVT_PMON_RAW_EVENT_MASK | \ 182 + SNBEP_CBO_PMON_CTL_TID_EN) 183 + 184 + #define IVT_CB0_MSR_PMON_BOX_FILTER_TID (0x1fULL << 0) 185 + #define IVT_CB0_MSR_PMON_BOX_FILTER_LINK (0xfULL << 5) 186 + #define IVT_CB0_MSR_PMON_BOX_FILTER_STATE (0x3fULL << 17) 187 + #define IVT_CB0_MSR_PMON_BOX_FILTER_NID (0xffffULL << 32) 188 + #define IVT_CB0_MSR_PMON_BOX_FILTER_OPC (0x1ffULL << 52) 189 + #define IVT_CB0_MSR_PMON_BOX_FILTER_C6 (0x1ULL << 61) 190 + #define IVT_CB0_MSR_PMON_BOX_FILTER_NC (0x1ULL << 62) 191 + #define IVT_CB0_MSR_PMON_BOX_FILTER_IOSC (0x1ULL << 63) 192 + 193 + /* IVT home agent */ 194 + #define IVT_HA_PCI_PMON_CTL_Q_OCC_RST (1 << 16) 195 + #define IVT_HA_PCI_PMON_RAW_EVENT_MASK \ 196 + (IVT_PMON_RAW_EVENT_MASK | \ 197 + IVT_HA_PCI_PMON_CTL_Q_OCC_RST) 198 + /* IVT PCU */ 199 + #define IVT_PCU_MSR_PMON_RAW_EVENT_MASK \ 200 + (SNBEP_PMON_CTL_EV_SEL_MASK | \ 201 + SNBEP_PMON_CTL_EV_SEL_EXT | \ 202 + SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ 203 + SNBEP_PMON_CTL_EDGE_DET | \ 204 + SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ 205 + SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ 206 + SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) 207 + /* IVT QPI */ 208 + #define IVT_QPI_PCI_PMON_RAW_EVENT_MASK \ 209 + (IVT_PMON_RAW_EVENT_MASK | \ 210 + SNBEP_PMON_CTL_EV_SEL_EXT) 173 211 174 212 /* NHM-EX event control */ 175 213 #define NHMEX_PMON_CTL_EV_SEL_MASK 0x000000ff
+4 -5
arch/x86/kernel/cpu/perf_event_p4.c
··· 895 895 * So at moment let leave metrics turned on forever -- it's 896 896 * ok for now but need to be revisited! 897 897 * 898 - * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, (u64)0); 899 - * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, (u64)0); 898 + * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, 0); 899 + * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, 0); 900 900 */ 901 901 } 902 902 ··· 910 910 * asserted again and again 911 911 */ 912 912 (void)wrmsrl_safe(hwc->config_base, 913 - (u64)(p4_config_unpack_cccr(hwc->config)) & 914 - ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED); 913 + p4_config_unpack_cccr(hwc->config) & ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED); 915 914 } 916 915 917 916 static void p4_pmu_disable_all(void) ··· 956 957 u64 escr_addr, cccr; 957 958 958 959 bind = &p4_event_bind_map[idx]; 959 - escr_addr = (u64)bind->escr_msr[thread]; 960 + escr_addr = bind->escr_msr[thread]; 960 961 961 962 /* 962 963 * - we dont support cascaded counters yet
+5 -1
arch/x86/kernel/kprobes/core.c
··· 353 353 * have given. 354 354 */ 355 355 newdisp = (u8 *) src + (s64) insn.displacement.value - (u8 *) dest; 356 - BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check. */ 356 + if ((s64) (s32) newdisp != newdisp) { 357 + pr_err("Kprobes error: new displacement does not fit into s32 (%llx)\n", newdisp); 358 + pr_err("\tSrc: %p, Dest: %p, old disp: %x\n", src, dest, insn.displacement.value); 359 + return 0; 360 + } 357 361 disp = (u8 *) dest + insn_offset_displacement(&insn); 358 362 *(s32 *) disp = (s32) newdisp; 359 363 }
+29
arch/x86/kernel/uprobes.c
··· 697 697 send_sig(SIGTRAP, current, 0); 698 698 return ret; 699 699 } 700 + 701 + unsigned long 702 + arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs) 703 + { 704 + int rasize, ncopied; 705 + unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */ 706 + 707 + rasize = is_ia32_task() ? 4 : 8; 708 + ncopied = copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize); 709 + if (unlikely(ncopied)) 710 + return -1; 711 + 712 + /* check whether address has been already hijacked */ 713 + if (orig_ret_vaddr == trampoline_vaddr) 714 + return orig_ret_vaddr; 715 + 716 + ncopied = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize); 717 + if (likely(!ncopied)) 718 + return orig_ret_vaddr; 719 + 720 + if (ncopied != rasize) { 721 + pr_err("uprobe: return address clobbered: pid=%d, %%sp=%#lx, " 722 + "%%ip=%#lx\n", current->pid, regs->sp, regs->ip); 723 + 724 + force_sig_info(SIGSEGV, SEND_SIG_FORCED, current); 725 + } 726 + 727 + return -1; 728 + }
+6
include/linux/compiler.h
··· 351 351 */ 352 352 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) 353 353 354 + /* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */ 355 + #ifdef CONFIG_KPROBES 356 + # define __kprobes __attribute__((__section__(".kprobes.text"))) 357 + #else 358 + # define __kprobes 359 + #endif 354 360 #endif /* __LINUX_COMPILER_H */
+1 -5
include/linux/kprobes.h
··· 29 29 * <jkenisto@us.ibm.com> and Prasanna S Panchamukhi 30 30 * <prasanna@in.ibm.com> added function-return probes. 31 31 */ 32 + #include <linux/compiler.h> /* for __kprobes */ 32 33 #include <linux/linkage.h> 33 34 #include <linux/list.h> 34 35 #include <linux/notifier.h> ··· 50 49 #define KPROBE_REENTER 0x00000004 51 50 #define KPROBE_HIT_SSDONE 0x00000008 52 51 53 - /* Attach to insert probes on any functions which should be ignored*/ 54 - #define __kprobes __attribute__((__section__(".kprobes.text"))) 55 - 56 52 #else /* CONFIG_KPROBES */ 57 53 typedef int kprobe_opcode_t; 58 54 struct arch_specific_insn { 59 55 int dummy; 60 56 }; 61 - #define __kprobes 62 - 63 57 #endif /* CONFIG_KPROBES */ 64 58 65 59 struct kprobe;
+7 -17
include/linux/perf_event.h
··· 21 21 */ 22 22 23 23 #ifdef CONFIG_PERF_EVENTS 24 - # include <linux/cgroup.h> 25 24 # include <asm/perf_event.h> 26 25 # include <asm/local64.h> 27 26 #endif ··· 127 128 int event_base_rdpmc; 128 129 int idx; 129 130 int last_cpu; 131 + int flags; 130 132 131 133 struct hw_perf_event_extra extra_reg; 132 134 struct hw_perf_event_extra branch_reg; ··· 299 299 #define PERF_ATTACH_GROUP 0x02 300 300 #define PERF_ATTACH_TASK 0x04 301 301 302 - #ifdef CONFIG_CGROUP_PERF 303 - /* 304 - * perf_cgroup_info keeps track of time_enabled for a cgroup. 305 - * This is a per-cpu dynamically allocated data structure. 306 - */ 307 - struct perf_cgroup_info { 308 - u64 time; 309 - u64 timestamp; 310 - }; 311 - 312 - struct perf_cgroup { 313 - struct cgroup_subsys_state css; 314 - struct perf_cgroup_info *info; /* timing info, one per cpu */ 315 - }; 316 - #endif 317 - 302 + struct perf_cgroup; 318 303 struct ring_buffer; 319 304 320 305 /** ··· 568 583 u32 reserved; 569 584 } cpu_entry; 570 585 u64 period; 586 + union perf_mem_data_src data_src; 571 587 struct perf_callchain_entry *callchain; 572 588 struct perf_raw_record *raw; 573 589 struct perf_branch_stack *br_stack; 574 590 struct perf_regs_user regs_user; 575 591 u64 stack_user_size; 592 + u64 weight; 576 593 }; 577 594 578 595 static inline void perf_sample_data_init(struct perf_sample_data *data, ··· 588 601 data->regs_user.abi = PERF_SAMPLE_REGS_ABI_NONE; 589 602 data->regs_user.regs = NULL; 590 603 data->stack_user_size = 0; 604 + data->weight = 0; 605 + data->data_src.val = 0; 591 606 } 592 607 593 608 extern void perf_output_sample(struct perf_output_handle *handle, ··· 820 831 struct perf_pmu_events_attr { 821 832 struct device_attribute attr; 822 833 u64 id; 834 + const char *event_str; 823 835 }; 824 836 825 837 #define PMU_EVENT_ATTR(_name, _var, _id, _show) \
+8
include/linux/uprobes.h
··· 38 38 #define UPROBE_HANDLER_REMOVE 1 39 39 #define UPROBE_HANDLER_MASK 1 40 40 41 + #define MAX_URETPROBE_DEPTH 64 42 + 41 43 enum uprobe_filter_ctx { 42 44 UPROBE_FILTER_REGISTER, 43 45 UPROBE_FILTER_UNREGISTER, ··· 48 46 49 47 struct uprobe_consumer { 50 48 int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); 49 + int (*ret_handler)(struct uprobe_consumer *self, 50 + unsigned long func, 51 + struct pt_regs *regs); 51 52 bool (*filter)(struct uprobe_consumer *self, 52 53 enum uprobe_filter_ctx ctx, 53 54 struct mm_struct *mm); ··· 73 68 enum uprobe_task_state state; 74 69 struct arch_uprobe_task autask; 75 70 71 + struct return_instance *return_instances; 72 + unsigned int depth; 76 73 struct uprobe *active_uprobe; 77 74 78 75 unsigned long xol_vaddr; ··· 107 100 extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); 108 101 extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); 109 102 extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); 103 + extern bool __weak is_trap_insn(uprobe_opcode_t *insn); 110 104 extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); 111 105 extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); 112 106 extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
+70 -1
include/uapi/linux/perf_event.h
··· 132 132 PERF_SAMPLE_BRANCH_STACK = 1U << 11, 133 133 PERF_SAMPLE_REGS_USER = 1U << 12, 134 134 PERF_SAMPLE_STACK_USER = 1U << 13, 135 + PERF_SAMPLE_WEIGHT = 1U << 14, 136 + PERF_SAMPLE_DATA_SRC = 1U << 15, 135 137 136 - PERF_SAMPLE_MAX = 1U << 14, /* non-ABI */ 138 + PERF_SAMPLE_MAX = 1U << 16, /* non-ABI */ 137 139 }; 138 140 139 141 /* ··· 445 443 #define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0) 446 444 #define PERF_RECORD_MISC_GUEST_USER (5 << 0) 447 445 446 + #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) 448 447 /* 449 448 * Indicates that the content of PERF_SAMPLE_IP points to 450 449 * the actual instruction that triggered the event. See also ··· 591 588 * { u64 size; 592 589 * char data[size]; 593 590 * u64 dyn_size; } && PERF_SAMPLE_STACK_USER 591 + * 592 + * { u64 weight; } && PERF_SAMPLE_WEIGHT 593 + * { u64 data_src; } && PERF_SAMPLE_DATA_SRC 594 594 * }; 595 595 */ 596 596 PERF_RECORD_SAMPLE = 9, ··· 618 612 #define PERF_FLAG_FD_NO_GROUP (1U << 0) 619 613 #define PERF_FLAG_FD_OUTPUT (1U << 1) 620 614 #define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ 615 + 616 + union perf_mem_data_src { 617 + __u64 val; 618 + struct { 619 + __u64 mem_op:5, /* type of opcode */ 620 + mem_lvl:14, /* memory hierarchy level */ 621 + mem_snoop:5, /* snoop mode */ 622 + mem_lock:2, /* lock instr */ 623 + mem_dtlb:7, /* tlb access */ 624 + mem_rsvd:31; 625 + }; 626 + }; 627 + 628 + /* type of opcode (load/store/prefetch,code) */ 629 + #define PERF_MEM_OP_NA 0x01 /* not available */ 630 + #define PERF_MEM_OP_LOAD 0x02 /* load instruction */ 631 + #define PERF_MEM_OP_STORE 0x04 /* store instruction */ 632 + #define PERF_MEM_OP_PFETCH 0x08 /* prefetch */ 633 + #define PERF_MEM_OP_EXEC 0x10 /* code (execution) */ 634 + #define PERF_MEM_OP_SHIFT 0 635 + 636 + /* memory hierarchy (memory level, hit or miss) */ 637 + #define PERF_MEM_LVL_NA 0x01 /* not available */ 638 + #define PERF_MEM_LVL_HIT 0x02 /* hit level */ 639 + #define PERF_MEM_LVL_MISS 0x04 /* miss level */ 640 + #define PERF_MEM_LVL_L1 0x08 /* L1 */ 641 + #define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */ 642 + #define PERF_MEM_LVL_L2 0x20 /* L2 */ 643 + #define PERF_MEM_LVL_L3 0x40 /* L3 */ 644 + #define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */ 645 + #define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */ 646 + #define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */ 647 + #define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */ 648 + #define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */ 649 + #define PERF_MEM_LVL_IO 0x1000 /* I/O memory */ 650 + #define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */ 651 + #define PERF_MEM_LVL_SHIFT 5 652 + 653 + /* snoop mode */ 654 + #define PERF_MEM_SNOOP_NA 0x01 /* not available */ 655 + #define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */ 656 + #define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */ 657 + #define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */ 658 + #define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */ 659 + #define PERF_MEM_SNOOP_SHIFT 19 660 + 661 + /* locked instruction */ 662 + #define PERF_MEM_LOCK_NA 0x01 /* not available */ 663 + #define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */ 664 + #define PERF_MEM_LOCK_SHIFT 24 665 + 666 + /* TLB access */ 667 + #define PERF_MEM_TLB_NA 0x01 /* not available */ 668 + #define PERF_MEM_TLB_HIT 0x02 /* hit level */ 669 + #define PERF_MEM_TLB_MISS 0x04 /* miss level */ 670 + #define PERF_MEM_TLB_L1 0x08 /* L1 */ 671 + #define PERF_MEM_TLB_L2 0x10 /* L2 */ 672 + #define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/ 673 + #define PERF_MEM_TLB_OS 0x40 /* OS fault handler */ 674 + #define PERF_MEM_TLB_SHIFT 26 675 + 676 + #define PERF_MEM_S(a, s) \ 677 + (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT) 621 678 622 679 #endif /* _UAPI_LINUX_PERF_EVENT_H */
+30
kernel/events/core.c
··· 37 37 #include <linux/ftrace_event.h> 38 38 #include <linux/hw_breakpoint.h> 39 39 #include <linux/mm_types.h> 40 + #include <linux/cgroup.h> 40 41 41 42 #include "internal.h" 42 43 ··· 233 232 } 234 233 235 234 #ifdef CONFIG_CGROUP_PERF 235 + 236 + /* 237 + * perf_cgroup_info keeps track of time_enabled for a cgroup. 238 + * This is a per-cpu dynamically allocated data structure. 239 + */ 240 + struct perf_cgroup_info { 241 + u64 time; 242 + u64 timestamp; 243 + }; 244 + 245 + struct perf_cgroup { 246 + struct cgroup_subsys_state css; 247 + struct perf_cgroup_info __percpu *info; 248 + }; 236 249 237 250 /* 238 251 * Must ensure cgroup is pinned (css_get) before calling ··· 991 976 if (sample_type & PERF_SAMPLE_PERIOD) 992 977 size += sizeof(data->period); 993 978 979 + if (sample_type & PERF_SAMPLE_WEIGHT) 980 + size += sizeof(data->weight); 981 + 994 982 if (sample_type & PERF_SAMPLE_READ) 995 983 size += event->read_size; 984 + 985 + if (sample_type & PERF_SAMPLE_DATA_SRC) 986 + size += sizeof(data->data_src.val); 996 987 997 988 event->header_size = size; 998 989 } ··· 4214 4193 perf_output_sample_ustack(handle, 4215 4194 data->stack_user_size, 4216 4195 data->regs_user.regs); 4196 + 4197 + if (sample_type & PERF_SAMPLE_WEIGHT) 4198 + perf_output_put(handle, data->weight); 4199 + 4200 + if (sample_type & PERF_SAMPLE_DATA_SRC) 4201 + perf_output_put(handle, data->data_src.val); 4217 4202 } 4218 4203 4219 4204 void perf_prepare_sample(struct perf_event_header *header, ··· 4808 4781 4809 4782 mmap_event->file_name = name; 4810 4783 mmap_event->file_size = size; 4784 + 4785 + if (!(vma->vm_flags & VM_EXEC)) 4786 + mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA; 4811 4787 4812 4788 mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size; 4813 4789
+251 -49
kernel/events/uprobes.c
··· 75 75 struct arch_uprobe arch; 76 76 }; 77 77 78 + struct return_instance { 79 + struct uprobe *uprobe; 80 + unsigned long func; 81 + unsigned long orig_ret_vaddr; /* original return address */ 82 + bool chained; /* true, if instance is nested */ 83 + 84 + struct return_instance *next; /* keep as stack */ 85 + }; 86 + 78 87 /* 79 88 * valid_vma: Verify if the specified vma is an executable vma 80 89 * Relax restrictions while unregistering: vm_flags might have ··· 182 173 return *insn == UPROBE_SWBP_INSN; 183 174 } 184 175 185 - static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode) 176 + /** 177 + * is_trap_insn - check if instruction is breakpoint instruction. 178 + * @insn: instruction to be checked. 179 + * Default implementation of is_trap_insn 180 + * Returns true if @insn is a breakpoint instruction. 181 + * 182 + * This function is needed for the case where an architecture has multiple 183 + * trap instructions (like powerpc). 184 + */ 185 + bool __weak is_trap_insn(uprobe_opcode_t *insn) 186 + { 187 + return is_swbp_insn(insn); 188 + } 189 + 190 + static void copy_from_page(struct page *page, unsigned long vaddr, void *dst, int len) 186 191 { 187 192 void *kaddr = kmap_atomic(page); 188 - memcpy(opcode, kaddr + (vaddr & ~PAGE_MASK), UPROBE_SWBP_INSN_SIZE); 193 + memcpy(dst, kaddr + (vaddr & ~PAGE_MASK), len); 194 + kunmap_atomic(kaddr); 195 + } 196 + 197 + static void copy_to_page(struct page *page, unsigned long vaddr, const void *src, int len) 198 + { 199 + void *kaddr = kmap_atomic(page); 200 + memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len); 189 201 kunmap_atomic(kaddr); 190 202 } 191 203 ··· 215 185 uprobe_opcode_t old_opcode; 216 186 bool is_swbp; 217 187 218 - copy_opcode(page, vaddr, &old_opcode); 188 + /* 189 + * Note: We only check if the old_opcode is UPROBE_SWBP_INSN here. 190 + * We do not check if it is any other 'trap variant' which could 191 + * be conditional trap instruction such as the one powerpc supports. 192 + * 193 + * The logic is that we do not care if the underlying instruction 194 + * is a trap variant; uprobes always wins over any other (gdb) 195 + * breakpoint. 196 + */ 197 + copy_from_page(page, vaddr, &old_opcode, UPROBE_SWBP_INSN_SIZE); 219 198 is_swbp = is_swbp_insn(&old_opcode); 220 199 221 200 if (is_swbp_insn(new_opcode)) { ··· 243 204 * Expect the breakpoint instruction to be the smallest size instruction for 244 205 * the architecture. If an arch has variable length instruction and the 245 206 * breakpoint instruction is not of the smallest length instruction 246 - * supported by that architecture then we need to modify is_swbp_at_addr and 207 + * supported by that architecture then we need to modify is_trap_at_addr and 247 208 * write_opcode accordingly. This would never be a problem for archs that 248 209 * have fixed length instructions. 249 210 */ ··· 264 225 uprobe_opcode_t opcode) 265 226 { 266 227 struct page *old_page, *new_page; 267 - void *vaddr_old, *vaddr_new; 268 228 struct vm_area_struct *vma; 269 229 int ret; 270 230 ··· 284 246 285 247 __SetPageUptodate(new_page); 286 248 287 - /* copy the page now that we've got it stable */ 288 - vaddr_old = kmap_atomic(old_page); 289 - vaddr_new = kmap_atomic(new_page); 290 - 291 - memcpy(vaddr_new, vaddr_old, PAGE_SIZE); 292 - memcpy(vaddr_new + (vaddr & ~PAGE_MASK), &opcode, UPROBE_SWBP_INSN_SIZE); 293 - 294 - kunmap_atomic(vaddr_new); 295 - kunmap_atomic(vaddr_old); 249 + copy_highpage(new_page, old_page); 250 + copy_to_page(new_page, vaddr, &opcode, UPROBE_SWBP_INSN_SIZE); 296 251 297 252 ret = anon_vma_prepare(vma); 298 253 if (ret) ··· 508 477 unsigned long nbytes, loff_t offset) 509 478 { 510 479 struct page *page; 511 - void *vaddr; 512 - unsigned long off; 513 - pgoff_t idx; 514 - 515 - if (!filp) 516 - return -EINVAL; 517 480 518 481 if (!mapping->a_ops->readpage) 519 482 return -EIO; 520 - 521 - idx = offset >> PAGE_CACHE_SHIFT; 522 - off = offset & ~PAGE_MASK; 523 - 524 483 /* 525 484 * Ensure that the page that has the original instruction is 526 485 * populated and in page-cache. 527 486 */ 528 - page = read_mapping_page(mapping, idx, filp); 487 + page = read_mapping_page(mapping, offset >> PAGE_CACHE_SHIFT, filp); 529 488 if (IS_ERR(page)) 530 489 return PTR_ERR(page); 531 490 532 - vaddr = kmap_atomic(page); 533 - memcpy(insn, vaddr + off, nbytes); 534 - kunmap_atomic(vaddr); 491 + copy_from_page(page, offset, insn, nbytes); 535 492 page_cache_release(page); 536 493 537 494 return 0; ··· 569 550 goto out; 570 551 571 552 ret = -ENOTSUPP; 572 - if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) 553 + if (is_trap_insn((uprobe_opcode_t *)uprobe->arch.insn)) 573 554 goto out; 574 555 575 556 ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); ··· 777 758 down_write(&mm->mmap_sem); 778 759 vma = find_vma(mm, info->vaddr); 779 760 if (!vma || !valid_vma(vma, is_register) || 780 - vma->vm_file->f_mapping->host != uprobe->inode) 761 + file_inode(vma->vm_file) != uprobe->inode) 781 762 goto unlock; 782 763 783 764 if (vma->vm_start > info->vaddr || ··· 846 827 { 847 828 struct uprobe *uprobe; 848 829 int ret; 830 + 831 + /* Uprobe must have at least one set consumer */ 832 + if (!uc->handler && !uc->ret_handler) 833 + return -EINVAL; 849 834 850 835 /* Racy, just to catch the obvious mistakes */ 851 836 if (offset > i_size_read(inode)) ··· 940 917 loff_t offset; 941 918 942 919 if (!valid_vma(vma, false) || 943 - vma->vm_file->f_mapping->host != uprobe->inode) 920 + file_inode(vma->vm_file) != uprobe->inode) 944 921 continue; 945 922 946 923 offset = (loff_t)vma->vm_pgoff << PAGE_SHIFT; ··· 1033 1010 if (no_uprobe_events() || !valid_vma(vma, true)) 1034 1011 return 0; 1035 1012 1036 - inode = vma->vm_file->f_mapping->host; 1013 + inode = file_inode(vma->vm_file); 1037 1014 if (!inode) 1038 1015 return 0; 1039 1016 ··· 1064 1041 struct inode *inode; 1065 1042 struct rb_node *n; 1066 1043 1067 - inode = vma->vm_file->f_mapping->host; 1044 + inode = file_inode(vma->vm_file); 1068 1045 1069 1046 min = vaddr_to_offset(vma, start); 1070 1047 max = min + (end - start) - 1; ··· 1137 1114 { 1138 1115 struct mm_struct *mm = current->mm; 1139 1116 struct xol_area *area; 1117 + uprobe_opcode_t insn = UPROBE_SWBP_INSN; 1140 1118 1141 1119 area = mm->uprobes_state.xol_area; 1142 1120 if (area) ··· 1155 1131 if (!area->page) 1156 1132 goto free_bitmap; 1157 1133 1134 + /* allocate first slot of task's xol_area for the return probes */ 1135 + set_bit(0, area->bitmap); 1136 + copy_to_page(area->page, 0, &insn, UPROBE_SWBP_INSN_SIZE); 1137 + atomic_set(&area->slot_count, 1); 1158 1138 init_waitqueue_head(&area->wq); 1139 + 1159 1140 if (!xol_add_vma(area)) 1160 1141 return area; 1161 1142 ··· 1245 1216 static unsigned long xol_get_insn_slot(struct uprobe *uprobe) 1246 1217 { 1247 1218 struct xol_area *area; 1248 - unsigned long offset; 1249 1219 unsigned long xol_vaddr; 1250 - void *vaddr; 1251 1220 1252 1221 area = get_xol_area(); 1253 1222 if (!area) ··· 1256 1229 return 0; 1257 1230 1258 1231 /* Initialize the slot */ 1259 - offset = xol_vaddr & ~PAGE_MASK; 1260 - vaddr = kmap_atomic(area->page); 1261 - memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES); 1262 - kunmap_atomic(vaddr); 1232 + copy_to_page(area->page, xol_vaddr, uprobe->arch.insn, MAX_UINSN_BYTES); 1263 1233 /* 1264 1234 * We probably need flush_icache_user_range() but it needs vma. 1265 1235 * This should work on supported architectures too. ··· 1322 1298 void uprobe_free_utask(struct task_struct *t) 1323 1299 { 1324 1300 struct uprobe_task *utask = t->utask; 1301 + struct return_instance *ri, *tmp; 1325 1302 1326 1303 if (!utask) 1327 1304 return; 1328 1305 1329 1306 if (utask->active_uprobe) 1330 1307 put_uprobe(utask->active_uprobe); 1308 + 1309 + ri = utask->return_instances; 1310 + while (ri) { 1311 + tmp = ri; 1312 + ri = ri->next; 1313 + 1314 + put_uprobe(tmp->uprobe); 1315 + kfree(tmp); 1316 + } 1331 1317 1332 1318 xol_free_insn_slot(t); 1333 1319 kfree(utask); ··· 1365 1331 if (!current->utask) 1366 1332 current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL); 1367 1333 return current->utask; 1334 + } 1335 + 1336 + /* 1337 + * Current area->vaddr notion assume the trampoline address is always 1338 + * equal area->vaddr. 1339 + * 1340 + * Returns -1 in case the xol_area is not allocated. 1341 + */ 1342 + static unsigned long get_trampoline_vaddr(void) 1343 + { 1344 + struct xol_area *area; 1345 + unsigned long trampoline_vaddr = -1; 1346 + 1347 + area = current->mm->uprobes_state.xol_area; 1348 + smp_read_barrier_depends(); 1349 + if (area) 1350 + trampoline_vaddr = area->vaddr; 1351 + 1352 + return trampoline_vaddr; 1353 + } 1354 + 1355 + static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs) 1356 + { 1357 + struct return_instance *ri; 1358 + struct uprobe_task *utask; 1359 + unsigned long orig_ret_vaddr, trampoline_vaddr; 1360 + bool chained = false; 1361 + 1362 + if (!get_xol_area()) 1363 + return; 1364 + 1365 + utask = get_utask(); 1366 + if (!utask) 1367 + return; 1368 + 1369 + if (utask->depth >= MAX_URETPROBE_DEPTH) { 1370 + printk_ratelimited(KERN_INFO "uprobe: omit uretprobe due to" 1371 + " nestedness limit pid/tgid=%d/%d\n", 1372 + current->pid, current->tgid); 1373 + return; 1374 + } 1375 + 1376 + ri = kzalloc(sizeof(struct return_instance), GFP_KERNEL); 1377 + if (!ri) 1378 + goto fail; 1379 + 1380 + trampoline_vaddr = get_trampoline_vaddr(); 1381 + orig_ret_vaddr = arch_uretprobe_hijack_return_addr(trampoline_vaddr, regs); 1382 + if (orig_ret_vaddr == -1) 1383 + goto fail; 1384 + 1385 + /* 1386 + * We don't want to keep trampoline address in stack, rather keep the 1387 + * original return address of first caller thru all the consequent 1388 + * instances. This also makes breakpoint unwrapping easier. 1389 + */ 1390 + if (orig_ret_vaddr == trampoline_vaddr) { 1391 + if (!utask->return_instances) { 1392 + /* 1393 + * This situation is not possible. Likely we have an 1394 + * attack from user-space. 1395 + */ 1396 + pr_warn("uprobe: unable to set uretprobe pid/tgid=%d/%d\n", 1397 + current->pid, current->tgid); 1398 + goto fail; 1399 + } 1400 + 1401 + chained = true; 1402 + orig_ret_vaddr = utask->return_instances->orig_ret_vaddr; 1403 + } 1404 + 1405 + atomic_inc(&uprobe->ref); 1406 + ri->uprobe = uprobe; 1407 + ri->func = instruction_pointer(regs); 1408 + ri->orig_ret_vaddr = orig_ret_vaddr; 1409 + ri->chained = chained; 1410 + 1411 + utask->depth++; 1412 + 1413 + /* add instance to the stack */ 1414 + ri->next = utask->return_instances; 1415 + utask->return_instances = ri; 1416 + 1417 + return; 1418 + 1419 + fail: 1420 + kfree(ri); 1368 1421 } 1369 1422 1370 1423 /* Prepare to single-step probed instruction out of line. */ ··· 1552 1431 clear_bit(MMF_HAS_UPROBES, &mm->flags); 1553 1432 } 1554 1433 1555 - static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) 1434 + static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr) 1556 1435 { 1557 1436 struct page *page; 1558 1437 uprobe_opcode_t opcode; ··· 1570 1449 if (result < 0) 1571 1450 return result; 1572 1451 1573 - copy_opcode(page, vaddr, &opcode); 1452 + copy_from_page(page, vaddr, &opcode, UPROBE_SWBP_INSN_SIZE); 1574 1453 put_page(page); 1575 1454 out: 1576 - return is_swbp_insn(&opcode); 1455 + /* This needs to return true for any variant of the trap insn */ 1456 + return is_trap_insn(&opcode); 1577 1457 } 1578 1458 1579 1459 static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) ··· 1587 1465 vma = find_vma(mm, bp_vaddr); 1588 1466 if (vma && vma->vm_start <= bp_vaddr) { 1589 1467 if (valid_vma(vma, false)) { 1590 - struct inode *inode = vma->vm_file->f_mapping->host; 1468 + struct inode *inode = file_inode(vma->vm_file); 1591 1469 loff_t offset = vaddr_to_offset(vma, bp_vaddr); 1592 1470 1593 1471 uprobe = find_uprobe(inode, offset); 1594 1472 } 1595 1473 1596 1474 if (!uprobe) 1597 - *is_swbp = is_swbp_at_addr(mm, bp_vaddr); 1475 + *is_swbp = is_trap_at_addr(mm, bp_vaddr); 1598 1476 } else { 1599 1477 *is_swbp = -EFAULT; 1600 1478 } ··· 1610 1488 { 1611 1489 struct uprobe_consumer *uc; 1612 1490 int remove = UPROBE_HANDLER_REMOVE; 1491 + bool need_prep = false; /* prepare return uprobe, when needed */ 1613 1492 1614 1493 down_read(&uprobe->register_rwsem); 1615 1494 for (uc = uprobe->consumers; uc; uc = uc->next) { 1616 - int rc = uc->handler(uc, regs); 1495 + int rc = 0; 1617 1496 1618 - WARN(rc & ~UPROBE_HANDLER_MASK, 1619 - "bad rc=0x%x from %pf()\n", rc, uc->handler); 1497 + if (uc->handler) { 1498 + rc = uc->handler(uc, regs); 1499 + WARN(rc & ~UPROBE_HANDLER_MASK, 1500 + "bad rc=0x%x from %pf()\n", rc, uc->handler); 1501 + } 1502 + 1503 + if (uc->ret_handler) 1504 + need_prep = true; 1505 + 1620 1506 remove &= rc; 1621 1507 } 1508 + 1509 + if (need_prep && !remove) 1510 + prepare_uretprobe(uprobe, regs); /* put bp at return */ 1622 1511 1623 1512 if (remove && uprobe->consumers) { 1624 1513 WARN_ON(!uprobe_is_active(uprobe)); 1625 1514 unapply_uprobe(uprobe, current->mm); 1626 1515 } 1627 1516 up_read(&uprobe->register_rwsem); 1517 + } 1518 + 1519 + static void 1520 + handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs) 1521 + { 1522 + struct uprobe *uprobe = ri->uprobe; 1523 + struct uprobe_consumer *uc; 1524 + 1525 + down_read(&uprobe->register_rwsem); 1526 + for (uc = uprobe->consumers; uc; uc = uc->next) { 1527 + if (uc->ret_handler) 1528 + uc->ret_handler(uc, ri->func, regs); 1529 + } 1530 + up_read(&uprobe->register_rwsem); 1531 + } 1532 + 1533 + static bool handle_trampoline(struct pt_regs *regs) 1534 + { 1535 + struct uprobe_task *utask; 1536 + struct return_instance *ri, *tmp; 1537 + bool chained; 1538 + 1539 + utask = current->utask; 1540 + if (!utask) 1541 + return false; 1542 + 1543 + ri = utask->return_instances; 1544 + if (!ri) 1545 + return false; 1546 + 1547 + /* 1548 + * TODO: we should throw out return_instance's invalidated by 1549 + * longjmp(), currently we assume that the probed function always 1550 + * returns. 1551 + */ 1552 + instruction_pointer_set(regs, ri->orig_ret_vaddr); 1553 + 1554 + for (;;) { 1555 + handle_uretprobe_chain(ri, regs); 1556 + 1557 + chained = ri->chained; 1558 + put_uprobe(ri->uprobe); 1559 + 1560 + tmp = ri; 1561 + ri = ri->next; 1562 + kfree(tmp); 1563 + 1564 + if (!chained) 1565 + break; 1566 + 1567 + utask->depth--; 1568 + 1569 + BUG_ON(!ri); 1570 + } 1571 + 1572 + utask->return_instances = ri; 1573 + 1574 + return true; 1628 1575 } 1629 1576 1630 1577 /* ··· 1707 1516 int uninitialized_var(is_swbp); 1708 1517 1709 1518 bp_vaddr = uprobe_get_swbp_addr(regs); 1710 - uprobe = find_active_uprobe(bp_vaddr, &is_swbp); 1519 + if (bp_vaddr == get_trampoline_vaddr()) { 1520 + if (handle_trampoline(regs)) 1521 + return; 1711 1522 1523 + pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n", 1524 + current->pid, current->tgid); 1525 + } 1526 + 1527 + uprobe = find_active_uprobe(bp_vaddr, &is_swbp); 1712 1528 if (!uprobe) { 1713 1529 if (is_swbp > 0) { 1714 1530 /* No matching uprobe; signal SIGTRAP. */ ··· 1814 1616 */ 1815 1617 int uprobe_pre_sstep_notifier(struct pt_regs *regs) 1816 1618 { 1817 - if (!current->mm || !test_bit(MMF_HAS_UPROBES, &current->mm->flags)) 1619 + if (!current->mm) 1620 + return 0; 1621 + 1622 + if (!test_bit(MMF_HAS_UPROBES, &current->mm->flags) && 1623 + (!current->utask || !current->utask->return_instances)) 1818 1624 return 0; 1819 1625 1820 1626 set_thread_flag(TIF_UPROBE);
-5
kernel/trace/trace.h
··· 109 109 unsigned long ret_ip; 110 110 }; 111 111 112 - struct uprobe_trace_entry_head { 113 - struct trace_entry ent; 114 - unsigned long ip; 115 - }; 116 - 117 112 /* 118 113 * trace_flag_type is an enumeration that holds different 119 114 * states when a trace occurs. These are:
+146 -57
kernel/trace/trace_uprobe.c
··· 28 28 29 29 #define UPROBE_EVENT_SYSTEM "uprobes" 30 30 31 + struct uprobe_trace_entry_head { 32 + struct trace_entry ent; 33 + unsigned long vaddr[]; 34 + }; 35 + 36 + #define SIZEOF_TRACE_ENTRY(is_return) \ 37 + (sizeof(struct uprobe_trace_entry_head) + \ 38 + sizeof(unsigned long) * (is_return ? 2 : 1)) 39 + 40 + #define DATAOF_TRACE_ENTRY(entry, is_return) \ 41 + ((void*)(entry) + SIZEOF_TRACE_ENTRY(is_return)) 42 + 31 43 struct trace_uprobe_filter { 32 44 rwlock_t rwlock; 33 45 int nr_systemwide; ··· 76 64 static LIST_HEAD(uprobe_list); 77 65 78 66 static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs); 67 + static int uretprobe_dispatcher(struct uprobe_consumer *con, 68 + unsigned long func, struct pt_regs *regs); 79 69 80 70 static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter) 81 71 { ··· 91 77 return !filter->nr_systemwide && list_empty(&filter->perf_events); 92 78 } 93 79 80 + static inline bool is_ret_probe(struct trace_uprobe *tu) 81 + { 82 + return tu->consumer.ret_handler != NULL; 83 + } 84 + 94 85 /* 95 86 * Allocate new trace_uprobe and initialize it (including uprobes). 96 87 */ 97 88 static struct trace_uprobe * 98 - alloc_trace_uprobe(const char *group, const char *event, int nargs) 89 + alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret) 99 90 { 100 91 struct trace_uprobe *tu; 101 92 ··· 125 106 126 107 INIT_LIST_HEAD(&tu->list); 127 108 tu->consumer.handler = uprobe_dispatcher; 109 + if (is_ret) 110 + tu->consumer.ret_handler = uretprobe_dispatcher; 128 111 init_trace_uprobe_filter(&tu->filter); 129 112 return tu; 130 113 ··· 201 180 202 181 /* 203 182 * Argument syntax: 204 - * - Add uprobe: p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] 183 + * - Add uprobe: p|r[:[GRP/]EVENT] PATH:SYMBOL [FETCHARGS] 205 184 * 206 185 * - Remove uprobe: -:[GRP/]EVENT 207 186 */ ··· 213 192 char buf[MAX_EVENT_NAME_LEN]; 214 193 struct path path; 215 194 unsigned long offset; 216 - bool is_delete; 195 + bool is_delete, is_return; 217 196 int i, ret; 218 197 219 198 inode = NULL; 220 199 ret = 0; 221 200 is_delete = false; 201 + is_return = false; 222 202 event = NULL; 223 203 group = NULL; 224 204 225 205 /* argc must be >= 1 */ 226 206 if (argv[0][0] == '-') 227 207 is_delete = true; 208 + else if (argv[0][0] == 'r') 209 + is_return = true; 228 210 else if (argv[0][0] != 'p') { 229 - pr_info("Probe definition must be started with 'p' or '-'.\n"); 211 + pr_info("Probe definition must be started with 'p', 'r' or '-'.\n"); 230 212 return -EINVAL; 231 213 } 232 214 ··· 327 303 kfree(tail); 328 304 } 329 305 330 - tu = alloc_trace_uprobe(group, event, argc); 306 + tu = alloc_trace_uprobe(group, event, argc, is_return); 331 307 if (IS_ERR(tu)) { 332 308 pr_info("Failed to allocate trace_uprobe.(%d)\n", (int)PTR_ERR(tu)); 333 309 ret = PTR_ERR(tu); ··· 438 414 static int probes_seq_show(struct seq_file *m, void *v) 439 415 { 440 416 struct trace_uprobe *tu = v; 417 + char c = is_ret_probe(tu) ? 'r' : 'p'; 441 418 int i; 442 419 443 - seq_printf(m, "p:%s/%s", tu->call.class->system, tu->call.name); 420 + seq_printf(m, "%c:%s/%s", c, tu->call.class->system, tu->call.name); 444 421 seq_printf(m, " %s:0x%p", tu->filename, (void *)tu->offset); 445 422 446 423 for (i = 0; i < tu->nr_args; i++) ··· 510 485 .release = seq_release, 511 486 }; 512 487 513 - /* uprobe handler */ 514 - static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) 488 + static void uprobe_trace_print(struct trace_uprobe *tu, 489 + unsigned long func, struct pt_regs *regs) 515 490 { 516 491 struct uprobe_trace_entry_head *entry; 517 492 struct ring_buffer_event *event; 518 493 struct ring_buffer *buffer; 519 - u8 *data; 520 - int size, i, pc; 521 - unsigned long irq_flags; 494 + void *data; 495 + int size, i; 522 496 struct ftrace_event_call *call = &tu->call; 523 497 524 - local_save_flags(irq_flags); 525 - pc = preempt_count(); 526 - 527 - size = sizeof(*entry) + tu->size; 528 - 498 + size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); 529 499 event = trace_current_buffer_lock_reserve(&buffer, call->event.type, 530 - size, irq_flags, pc); 500 + size + tu->size, 0, 0); 531 501 if (!event) 532 - return 0; 502 + return; 533 503 534 504 entry = ring_buffer_event_data(event); 535 - entry->ip = instruction_pointer(task_pt_regs(current)); 536 - data = (u8 *)&entry[1]; 505 + if (is_ret_probe(tu)) { 506 + entry->vaddr[0] = func; 507 + entry->vaddr[1] = instruction_pointer(regs); 508 + data = DATAOF_TRACE_ENTRY(entry, true); 509 + } else { 510 + entry->vaddr[0] = instruction_pointer(regs); 511 + data = DATAOF_TRACE_ENTRY(entry, false); 512 + } 513 + 537 514 for (i = 0; i < tu->nr_args; i++) 538 515 call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); 539 516 540 517 if (!filter_current_check_discard(buffer, call, entry, event)) 541 - trace_buffer_unlock_commit(buffer, event, irq_flags, pc); 518 + trace_buffer_unlock_commit(buffer, event, 0, 0); 519 + } 542 520 521 + /* uprobe handler */ 522 + static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) 523 + { 524 + if (!is_ret_probe(tu)) 525 + uprobe_trace_print(tu, 0, regs); 543 526 return 0; 527 + } 528 + 529 + static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func, 530 + struct pt_regs *regs) 531 + { 532 + uprobe_trace_print(tu, func, regs); 544 533 } 545 534 546 535 /* Event entry printers */ 547 536 static enum print_line_t 548 537 print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event) 549 538 { 550 - struct uprobe_trace_entry_head *field; 539 + struct uprobe_trace_entry_head *entry; 551 540 struct trace_seq *s = &iter->seq; 552 541 struct trace_uprobe *tu; 553 542 u8 *data; 554 543 int i; 555 544 556 - field = (struct uprobe_trace_entry_head *)iter->ent; 545 + entry = (struct uprobe_trace_entry_head *)iter->ent; 557 546 tu = container_of(event, struct trace_uprobe, call.event); 558 547 559 - if (!trace_seq_printf(s, "%s: (", tu->call.name)) 560 - goto partial; 548 + if (is_ret_probe(tu)) { 549 + if (!trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)", tu->call.name, 550 + entry->vaddr[1], entry->vaddr[0])) 551 + goto partial; 552 + data = DATAOF_TRACE_ENTRY(entry, true); 553 + } else { 554 + if (!trace_seq_printf(s, "%s: (0x%lx)", tu->call.name, 555 + entry->vaddr[0])) 556 + goto partial; 557 + data = DATAOF_TRACE_ENTRY(entry, false); 558 + } 561 559 562 - if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET)) 563 - goto partial; 564 - 565 - if (!trace_seq_puts(s, ")")) 566 - goto partial; 567 - 568 - data = (u8 *)&field[1]; 569 560 for (i = 0; i < tu->nr_args; i++) { 570 561 if (!tu->args[i].type->print(s, tu->args[i].name, 571 - data + tu->args[i].offset, field)) 562 + data + tu->args[i].offset, entry)) 572 563 goto partial; 573 564 } 574 565 ··· 636 595 637 596 static int uprobe_event_define_fields(struct ftrace_event_call *event_call) 638 597 { 639 - int ret, i; 598 + int ret, i, size; 640 599 struct uprobe_trace_entry_head field; 641 - struct trace_uprobe *tu = (struct trace_uprobe *)event_call->data; 600 + struct trace_uprobe *tu = event_call->data; 642 601 643 - DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); 602 + if (is_ret_probe(tu)) { 603 + DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_FUNC, 0); 604 + DEFINE_FIELD(unsigned long, vaddr[1], FIELD_STRING_RETIP, 0); 605 + size = SIZEOF_TRACE_ENTRY(true); 606 + } else { 607 + DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_IP, 0); 608 + size = SIZEOF_TRACE_ENTRY(false); 609 + } 644 610 /* Set argument names as fields */ 645 611 for (i = 0; i < tu->nr_args; i++) { 646 612 ret = trace_define_field(event_call, tu->args[i].type->fmttype, 647 613 tu->args[i].name, 648 - sizeof(field) + tu->args[i].offset, 614 + size + tu->args[i].offset, 649 615 tu->args[i].type->size, 650 616 tu->args[i].type->is_signed, 651 617 FILTER_OTHER); ··· 670 622 int i; 671 623 int pos = 0; 672 624 673 - fmt = "(%lx)"; 674 - arg = "REC->" FIELD_STRING_IP; 625 + if (is_ret_probe(tu)) { 626 + fmt = "(%lx <- %lx)"; 627 + arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; 628 + } else { 629 + fmt = "(%lx)"; 630 + arg = "REC->" FIELD_STRING_IP; 631 + } 675 632 676 633 /* When len=0, we just calculate the needed length */ 677 634 ··· 805 752 return ret; 806 753 } 807 754 808 - /* uprobe profile handler */ 809 - static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) 755 + static void uprobe_perf_print(struct trace_uprobe *tu, 756 + unsigned long func, struct pt_regs *regs) 810 757 { 811 758 struct ftrace_event_call *call = &tu->call; 812 759 struct uprobe_trace_entry_head *entry; 813 760 struct hlist_head *head; 814 - u8 *data; 815 - int size, __size, i; 816 - int rctx; 761 + void *data; 762 + int size, rctx, i; 817 763 818 - if (!uprobe_perf_filter(&tu->consumer, 0, current->mm)) 819 - return UPROBE_HANDLER_REMOVE; 820 - 821 - __size = sizeof(*entry) + tu->size; 822 - size = ALIGN(__size + sizeof(u32), sizeof(u64)); 823 - size -= sizeof(u32); 764 + size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); 765 + size = ALIGN(size + tu->size + sizeof(u32), sizeof(u64)) - sizeof(u32); 824 766 if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) 825 - return 0; 767 + return; 826 768 827 769 preempt_disable(); 770 + head = this_cpu_ptr(call->perf_events); 771 + if (hlist_empty(head)) 772 + goto out; 828 773 829 774 entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx); 830 775 if (!entry) 831 776 goto out; 832 777 833 - entry->ip = instruction_pointer(task_pt_regs(current)); 834 - data = (u8 *)&entry[1]; 778 + if (is_ret_probe(tu)) { 779 + entry->vaddr[0] = func; 780 + entry->vaddr[1] = instruction_pointer(regs); 781 + data = DATAOF_TRACE_ENTRY(entry, true); 782 + } else { 783 + entry->vaddr[0] = instruction_pointer(regs); 784 + data = DATAOF_TRACE_ENTRY(entry, false); 785 + } 786 + 835 787 for (i = 0; i < tu->nr_args; i++) 836 788 call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); 837 789 838 - head = this_cpu_ptr(call->perf_events); 839 - perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head, NULL); 840 - 790 + perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); 841 791 out: 842 792 preempt_enable(); 793 + } 794 + 795 + /* uprobe profile handler */ 796 + static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) 797 + { 798 + if (!uprobe_perf_filter(&tu->consumer, 0, current->mm)) 799 + return UPROBE_HANDLER_REMOVE; 800 + 801 + if (!is_ret_probe(tu)) 802 + uprobe_perf_print(tu, 0, regs); 843 803 return 0; 804 + } 805 + 806 + static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func, 807 + struct pt_regs *regs) 808 + { 809 + uprobe_perf_print(tu, func, regs); 844 810 } 845 811 #endif /* CONFIG_PERF_EVENTS */ 846 812 847 813 static 848 814 int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, void *data) 849 815 { 850 - struct trace_uprobe *tu = (struct trace_uprobe *)event->data; 816 + struct trace_uprobe *tu = event->data; 851 817 852 818 switch (type) { 853 819 case TRACE_REG_REGISTER: ··· 913 841 ret |= uprobe_perf_func(tu, regs); 914 842 #endif 915 843 return ret; 844 + } 845 + 846 + static int uretprobe_dispatcher(struct uprobe_consumer *con, 847 + unsigned long func, struct pt_regs *regs) 848 + { 849 + struct trace_uprobe *tu; 850 + 851 + tu = container_of(con, struct trace_uprobe, consumer); 852 + 853 + if (tu->flags & TP_FLAG_TRACE) 854 + uretprobe_trace_func(tu, func, regs); 855 + 856 + #ifdef CONFIG_PERF_EVENTS 857 + if (tu->flags & TP_FLAG_PROFILE) 858 + uretprobe_perf_func(tu, func, regs); 859 + #endif 860 + return 0; 916 861 } 917 862 918 863 static struct trace_event_functions uprobe_funcs = {
+5
kernel/watchdog.c
··· 517 517 return ret; 518 518 519 519 set_sample_period(); 520 + /* 521 + * Watchdog threads shouldn't be enabled if they are 522 + * disabled. The 'watchdog_disabled' variable check in 523 + * watchdog_*_all_cpus() function takes care of this. 524 + */ 520 525 if (watchdog_enabled && watchdog_thresh) 521 526 watchdog_enable_all_cpus(); 522 527 else
+14 -2
tools/Makefile
··· 34 34 cpupower: FORCE 35 35 $(call descend,power/$@) 36 36 37 - cgroup firewire lguest perf usb virtio vm: FORCE 37 + cgroup firewire guest usb virtio vm: FORCE 38 + $(call descend,$@) 39 + 40 + liblk: FORCE 41 + $(call descend,lib/lk) 42 + 43 + perf: liblk FORCE 38 44 $(call descend,$@) 39 45 40 46 selftests: FORCE ··· 68 62 cpupower_clean: 69 63 $(call descend,power/cpupower,clean) 70 64 71 - cgroup_clean firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean: 65 + cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean: 66 + $(call descend,$(@:_clean=),clean) 67 + 68 + liblk_clean: 69 + $(call descend,lib/lk,clean) 70 + 71 + perf_clean: liblk_clean 72 72 $(call descend,$(@:_clean=),clean) 73 73 74 74 selftests_clean:
+35
tools/lib/lk/Makefile
··· 1 + include ../../scripts/Makefile.include 2 + 3 + # guard against environment variables 4 + LIB_H= 5 + LIB_OBJS= 6 + 7 + LIB_H += debugfs.h 8 + 9 + LIB_OBJS += $(OUTPUT)debugfs.o 10 + 11 + LIBFILE = liblk.a 12 + 13 + CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC 14 + EXTLIBS = -lpthread -lrt -lelf -lm 15 + ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 16 + ALL_LDFLAGS = $(LDFLAGS) 17 + 18 + RM = rm -f 19 + 20 + $(LIBFILE): $(LIB_OBJS) 21 + $(QUIET_AR)$(RM) $@ && $(AR) rcs $(OUTPUT)$@ $(LIB_OBJS) 22 + 23 + $(LIB_OBJS): $(LIB_H) 24 + 25 + $(OUTPUT)%.o: %.c 26 + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 27 + $(OUTPUT)%.s: %.c 28 + $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 29 + $(OUTPUT)%.o: %.S 30 + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 31 + 32 + clean: 33 + $(RM) $(LIB_OBJS) $(LIBFILE) 34 + 35 + .PHONY: clean
+29
tools/lib/lk/debugfs.h
··· 1 + #ifndef __LK_DEBUGFS_H__ 2 + #define __LK_DEBUGFS_H__ 3 + 4 + #define _STR(x) #x 5 + #define STR(x) _STR(x) 6 + 7 + /* 8 + * On most systems <limits.h> would have given us this, but not on some systems 9 + * (e.g. GNU/Hurd). 10 + */ 11 + #ifndef PATH_MAX 12 + #define PATH_MAX 4096 13 + #endif 14 + 15 + #ifndef DEBUGFS_MAGIC 16 + #define DEBUGFS_MAGIC 0x64626720 17 + #endif 18 + 19 + #ifndef PERF_DEBUGFS_ENVIRONMENT 20 + #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" 21 + #endif 22 + 23 + const char *debugfs_find_mountpoint(void); 24 + int debugfs_valid_mountpoint(const char *debugfs); 25 + char *debugfs_mount(const char *mountpoint); 26 + 27 + extern char debugfs_mountpoint[]; 28 + 29 + #endif /* __LK_DEBUGFS_H__ */
+3
tools/perf/Documentation/perf-annotate.txt
··· 93 93 --skip-missing:: 94 94 Skip symbols that cannot be annotated. 95 95 96 + --group:: 97 + Show event group information together 98 + 96 99 SEE ALSO 97 100 -------- 98 101 linkperf:perf-record[1], linkperf:perf-report[1]
+48
tools/perf/Documentation/perf-mem.txt
··· 1 + perf-mem(1) 2 + =========== 3 + 4 + NAME 5 + ---- 6 + perf-mem - Profile memory accesses 7 + 8 + SYNOPSIS 9 + -------- 10 + [verse] 11 + 'perf mem' [<options>] (record [<command>] | report) 12 + 13 + DESCRIPTION 14 + ----------- 15 + "perf mem -t <TYPE> record" runs a command and gathers memory operation data 16 + from it, into perf.data. Perf record options are accepted and are passed through. 17 + 18 + "perf mem -t <TYPE> report" displays the result. It invokes perf report with the 19 + right set of options to display a memory access profile. 20 + 21 + OPTIONS 22 + ------- 23 + <command>...:: 24 + Any command you can specify in a shell. 25 + 26 + -t:: 27 + --type=:: 28 + Select the memory operation type: load or store (default: load) 29 + 30 + -D:: 31 + --dump-raw-samples=:: 32 + Dump the raw decoded samples on the screen in a format that is easy to parse with 33 + one sample per line. 34 + 35 + -x:: 36 + --field-separator:: 37 + Specify the field separator used when dump raw samples (-D option). By default, 38 + The separator is the space character. 39 + 40 + -C:: 41 + --cpu-list:: 42 + Restrict dump of raw samples to those provided via this option. Note that the same 43 + option can be passed in record mode. It will be interpreted the same way as perf 44 + record. 45 + 46 + SEE ALSO 47 + -------- 48 + linkperf:perf-record[1], linkperf:perf-report[1]
+6
tools/perf/Documentation/perf-record.txt
··· 182 182 The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k 183 183 Note that this feature may not be available on all processors. 184 184 185 + -W:: 186 + --weight:: 187 + Enable weightened sampling. An additional weight is recorded per sample and can be 188 + displayed with the weight and local_weight sort keys. This currently works for TSX 189 + abort events and some memory events in precise mode on modern Intel CPUs. 190 + 185 191 SEE ALSO 186 192 -------- 187 193 linkperf:perf-stat[1], linkperf:perf-list[1]
+5 -1
tools/perf/Documentation/perf-report.txt
··· 59 59 --sort=:: 60 60 Sort histogram entries by given key(s) - multiple keys can be specified 61 61 in CSV format. Following sort keys are available: 62 - pid, comm, dso, symbol, parent, cpu, srcline. 62 + pid, comm, dso, symbol, parent, cpu, srcline, weight, local_weight. 63 63 64 64 Each key has following meaning: 65 65 ··· 205 205 206 206 --group:: 207 207 Show event group information together. 208 + 209 + --demangle:: 210 + Demangle symbol names to human readable form. It's enabled by default, 211 + disable with --no-demangle. 208 212 209 213 SEE ALSO 210 214 --------
+9 -3
tools/perf/Documentation/perf-stat.txt
··· 52 52 53 53 -r:: 54 54 --repeat=<n>:: 55 - repeat command and print average + stddev (max: 100) 55 + repeat command and print average + stddev (max: 100). 0 means forever. 56 56 57 57 -B:: 58 58 --big-num:: ··· 119 119 Print count deltas every N milliseconds (minimum: 100ms) 120 120 example: perf stat -I 1000 -e cycles -a sleep 5 121 121 122 - --aggr-socket:: 122 + --per-socket:: 123 123 Aggregate counts per processor socket for system-wide mode measurements. This 124 124 is a useful mode to detect imbalance between sockets. To enable this mode, 125 - use --aggr-socket in addition to -a. (system-wide). The output includes the 125 + use --per-socket in addition to -a. (system-wide). The output includes the 126 126 socket number and the number of online processors on that socket. This is 127 127 useful to gauge the amount of aggregation. 128 + 129 + --per-core:: 130 + Aggregate counts per physical processor for system-wide mode measurements. This 131 + is a useful mode to detect imbalance between physical cores. To enable this mode, 132 + use --per-core in addition to -a. (system-wide). The output includes the 133 + core number and the number of online logical processors on that physical processor. 128 134 129 135 EXAMPLES 130 136 --------
+1 -1
tools/perf/Documentation/perf-top.txt
··· 112 112 113 113 -s:: 114 114 --sort:: 115 - Sort by key(s): pid, comm, dso, symbol, parent, srcline. 115 + Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, local_weight. 116 116 117 117 -n:: 118 118 --show-nr-samples::
+1
tools/perf/MANIFEST
··· 1 1 tools/perf 2 2 tools/scripts 3 3 tools/lib/traceevent 4 + tools/lib/lk 4 5 include/linux/const.h 5 6 include/linux/perf_event.h 6 7 include/linux/rbtree.h
+46 -15
tools/perf/Makefile
··· 35 35 # 36 36 # Define WERROR=0 to disable treating any warnings as errors. 37 37 # 38 - # Define NO_NEWT if you do not want TUI support. 38 + # Define NO_NEWT if you do not want TUI support. (deprecated) 39 + # 40 + # Define NO_SLANG if you do not want TUI support. 39 41 # 40 42 # Define NO_GTK2 if you do not want GTK+ GUI support. 41 43 # ··· 104 102 PARSER_DEBUG_BISON := -t 105 103 PARSER_DEBUG_FLEX := -d 106 104 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG 105 + endif 106 + 107 + ifdef NO_NEWT 108 + NO_SLANG=1 107 109 endif 108 110 109 111 CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS) ··· 221 215 -Iutil \ 222 216 -I. \ 223 217 -I$(TRACE_EVENT_DIR) \ 218 + -I../lib/ \ 224 219 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 225 220 226 221 BASIC_LDFLAGS = ··· 247 240 grep-libs = $(filter -l%,$(1)) 248 241 strip-libs = $(filter-out -l%,$(1)) 249 242 243 + LK_DIR = ../lib/lk/ 250 244 TRACE_EVENT_DIR = ../lib/traceevent/ 245 + 246 + LK_PATH=$(LK_DIR) 251 247 252 248 ifneq ($(OUTPUT),) 253 249 TE_PATH=$(OUTPUT) 250 + ifneq ($(subdir),) 251 + LK_PATH=$(OUTPUT)$(LK_DIR) 252 + else 253 + LK_PATH=$(OUTPUT) 254 + endif 254 255 else 255 256 TE_PATH=$(TRACE_EVENT_DIR) 256 257 endif 257 258 258 259 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 259 - TE_LIB := -L$(TE_PATH) -ltraceevent 260 - 261 260 export LIBTRACEEVENT 261 + 262 + LIBLK = $(LK_PATH)liblk.a 263 + export LIBLK 262 264 263 265 # python extension build directories 264 266 PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ ··· 278 262 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so 279 263 280 264 PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 281 - PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py 265 + PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) 282 266 283 267 $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 284 268 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ ··· 371 355 LIB_H += util/callchain.h 372 356 LIB_H += util/build-id.h 373 357 LIB_H += util/debug.h 374 - LIB_H += util/debugfs.h 375 358 LIB_H += util/sysfs.h 376 359 LIB_H += util/pmu.h 377 360 LIB_H += util/event.h ··· 431 416 LIB_OBJS += $(OUTPUT)util/build-id.o 432 417 LIB_OBJS += $(OUTPUT)util/config.o 433 418 LIB_OBJS += $(OUTPUT)util/ctype.o 434 - LIB_OBJS += $(OUTPUT)util/debugfs.o 435 419 LIB_OBJS += $(OUTPUT)util/sysfs.o 436 420 LIB_OBJS += $(OUTPUT)util/pmu.o 437 421 LIB_OBJS += $(OUTPUT)util/environment.o ··· 517 503 LIB_OBJS += $(OUTPUT)tests/pmu.o 518 504 LIB_OBJS += $(OUTPUT)tests/hists_link.o 519 505 LIB_OBJS += $(OUTPUT)tests/python-use.o 506 + LIB_OBJS += $(OUTPUT)tests/bp_signal.o 507 + LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 508 + LIB_OBJS += $(OUTPUT)tests/task-exit.o 509 + LIB_OBJS += $(OUTPUT)tests/sw-clock.o 520 510 521 511 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 522 512 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o ··· 553 535 BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o 554 536 BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 555 537 BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o 538 + BUILTIN_OBJS += $(OUTPUT)builtin-mem.o 556 539 557 - PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) 540 + PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) 558 541 559 542 # 560 543 # Platform specific tweaks ··· 686 667 endif 687 668 endif 688 669 689 - ifndef NO_NEWT 690 - FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt 691 - ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y) 692 - msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 670 + ifndef NO_SLANG 671 + FLAGS_SLANG=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang 672 + ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y) 673 + msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); 693 674 else 694 675 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 695 676 BASIC_CFLAGS += -I/usr/include/slang 696 - BASIC_CFLAGS += -DNEWT_SUPPORT 697 - EXTLIBS += -lnewt -lslang 677 + BASIC_CFLAGS += -DSLANG_SUPPORT 678 + EXTLIBS += -lslang 698 679 LIB_OBJS += $(OUTPUT)ui/browser.o 699 680 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o 700 681 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o ··· 1070 1051 $(LIBTRACEEVENT)-clean: 1071 1052 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean 1072 1053 1054 + # if subdir is set, we've been called from above so target has been built 1055 + # already 1056 + $(LIBLK): 1057 + ifeq ($(subdir),) 1058 + $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a 1059 + endif 1060 + 1061 + $(LIBLK)-clean: 1062 + ifeq ($(subdir),) 1063 + $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean 1064 + endif 1065 + 1073 1066 help: 1074 1067 @echo 'Perf make targets:' 1075 1068 @echo ' doc - make *all* documentation (see below)' ··· 1202 1171 1203 1172 ### Cleaning rules 1204 1173 1205 - clean: $(LIBTRACEEVENT)-clean 1174 + clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean 1206 1175 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) 1207 1176 $(RM) $(ALL_PROGRAMS) perf 1208 1177 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* ··· 1212 1181 $(RM) $(OUTPUT)util/*-flex* 1213 1182 $(python-clean) 1214 1183 1215 - .PHONY: all install clean strip $(LIBTRACEEVENT) 1184 + .PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK) 1216 1185 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 1217 1186 .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
+1 -4
tools/perf/arch/arm/util/dwarf-regs.c
··· 8 8 * published by the Free Software Foundation. 9 9 */ 10 10 11 - #include <stdlib.h> 12 - #ifndef __UCLIBC__ 13 - #include <libio.h> 14 - #endif 11 + #include <stddef.h> 15 12 #include <dwarf-regs.h> 16 13 17 14 struct pt_regs_dwarfnum {
+1 -4
tools/perf/arch/powerpc/util/dwarf-regs.c
··· 9 9 * 2 of the License, or (at your option) any later version. 10 10 */ 11 11 12 - #include <stdlib.h> 13 - #ifndef __UCLIBC__ 14 - #include <libio.h> 15 - #endif 12 + #include <stddef.h> 16 13 #include <dwarf-regs.h> 17 14 18 15
+1 -1
tools/perf/arch/s390/util/dwarf-regs.c
··· 6 6 * 7 7 */ 8 8 9 - #include <libio.h> 9 + #include <stddef.h> 10 10 #include <dwarf-regs.h> 11 11 12 12 #define NUM_GPRS 16
+1 -1
tools/perf/arch/sh/util/dwarf-regs.c
··· 19 19 * 20 20 */ 21 21 22 - #include <libio.h> 22 + #include <stddef.h> 23 23 #include <dwarf-regs.h> 24 24 25 25 /*
+1 -1
tools/perf/arch/sparc/util/dwarf-regs.c
··· 9 9 * 2 of the License, or (at your option) any later version. 10 10 */ 11 11 12 - #include <libio.h> 12 + #include <stddef.h> 13 13 #include <dwarf-regs.h> 14 14 15 15 #define SPARC_MAX_REGS 96
+1 -1
tools/perf/arch/x86/util/dwarf-regs.c
··· 20 20 * 21 21 */ 22 22 23 - #include <libio.h> 23 + #include <stddef.h> 24 24 #include <dwarf-regs.h> 25 25 26 26 /*
+17 -8
tools/perf/builtin-annotate.c
··· 63 63 return 0; 64 64 } 65 65 66 - he = __hists__add_entry(&evsel->hists, al, NULL, 1); 66 + he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1); 67 67 if (he == NULL) 68 68 return -ENOMEM; 69 69 ··· 109 109 return 0; 110 110 } 111 111 112 - static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, 112 + static int hist_entry__tty_annotate(struct hist_entry *he, 113 + struct perf_evsel *evsel, 113 114 struct perf_annotate *ann) 114 115 { 115 - return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, 116 + return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, 116 117 ann->print_line, ann->full_paths, 0, 0); 117 118 } 118 119 119 - static void hists__find_annotations(struct hists *self, int evidx, 120 + static void hists__find_annotations(struct hists *self, 121 + struct perf_evsel *evsel, 120 122 struct perf_annotate *ann) 121 123 { 122 124 struct rb_node *nd = rb_first(&self->entries), *next; ··· 144 142 if (use_browser == 2) { 145 143 int ret; 146 144 147 - ret = hist_entry__gtk_annotate(he, evidx, NULL); 145 + ret = hist_entry__gtk_annotate(he, evsel, NULL); 148 146 if (!ret || !ann->skip_missing) 149 147 return; 150 148 151 149 /* skip missing symbols */ 152 150 nd = rb_next(nd); 153 151 } else if (use_browser == 1) { 154 - key = hist_entry__tui_annotate(he, evidx, NULL); 152 + key = hist_entry__tui_annotate(he, evsel, NULL); 155 153 switch (key) { 156 154 case -1: 157 155 if (!ann->skip_missing) ··· 170 168 if (next != NULL) 171 169 nd = next; 172 170 } else { 173 - hist_entry__tty_annotate(he, evidx, ann); 171 + hist_entry__tty_annotate(he, evsel, ann); 174 172 nd = rb_next(nd); 175 173 /* 176 174 * Since we have a hist_entry per IP for the same ··· 232 230 total_nr_samples += nr_samples; 233 231 hists__collapse_resort(hists); 234 232 hists__output_resort(hists); 235 - hists__find_annotations(hists, pos->idx, ann); 233 + 234 + if (symbol_conf.event_group && 235 + !perf_evsel__is_group_leader(pos)) 236 + continue; 237 + 238 + hists__find_annotations(hists, pos, ann); 236 239 } 237 240 } 238 241 ··· 319 312 "Specify disassembler style (e.g. -M intel for intel syntax)"), 320 313 OPT_STRING(0, "objdump", &objdump_path, "path", 321 314 "objdump binary to use for disassembly and annotations"), 315 + OPT_BOOLEAN(0, "group", &symbol_conf.event_group, 316 + "Show event group information together"), 322 317 OPT_END() 323 318 }; 324 319
+4 -3
tools/perf/builtin-diff.c
··· 231 231 } 232 232 233 233 static int hists__add_entry(struct hists *self, 234 - struct addr_location *al, u64 period) 234 + struct addr_location *al, u64 period, 235 + u64 weight) 235 236 { 236 - if (__hists__add_entry(self, al, NULL, period) != NULL) 237 + if (__hists__add_entry(self, al, NULL, period, weight) != NULL) 237 238 return 0; 238 239 return -ENOMEM; 239 240 } ··· 256 255 if (al.filtered) 257 256 return 0; 258 257 259 - if (hists__add_entry(&evsel->hists, &al, sample->period)) { 258 + if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) { 260 259 pr_warning("problem incrementing symbol period, skipping event\n"); 261 260 return -1; 262 261 }
+1 -1
tools/perf/builtin-kvm.c
··· 12 12 #include "util/parse-options.h" 13 13 #include "util/trace-event.h" 14 14 #include "util/debug.h" 15 - #include "util/debugfs.h" 15 + #include <lk/debugfs.h> 16 16 #include "util/tool.h" 17 17 #include "util/stat.h" 18 18
+242
tools/perf/builtin-mem.c
··· 1 + #include "builtin.h" 2 + #include "perf.h" 3 + 4 + #include "util/parse-options.h" 5 + #include "util/trace-event.h" 6 + #include "util/tool.h" 7 + #include "util/session.h" 8 + 9 + #define MEM_OPERATION_LOAD "load" 10 + #define MEM_OPERATION_STORE "store" 11 + 12 + static const char *mem_operation = MEM_OPERATION_LOAD; 13 + 14 + struct perf_mem { 15 + struct perf_tool tool; 16 + char const *input_name; 17 + symbol_filter_t annotate_init; 18 + bool hide_unresolved; 19 + bool dump_raw; 20 + const char *cpu_list; 21 + DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 22 + }; 23 + 24 + static const char * const mem_usage[] = { 25 + "perf mem [<options>] {record <command> |report}", 26 + NULL 27 + }; 28 + 29 + static int __cmd_record(int argc, const char **argv) 30 + { 31 + int rec_argc, i = 0, j; 32 + const char **rec_argv; 33 + char event[64]; 34 + int ret; 35 + 36 + rec_argc = argc + 4; 37 + rec_argv = calloc(rec_argc + 1, sizeof(char *)); 38 + if (!rec_argv) 39 + return -1; 40 + 41 + rec_argv[i++] = strdup("record"); 42 + if (!strcmp(mem_operation, MEM_OPERATION_LOAD)) 43 + rec_argv[i++] = strdup("-W"); 44 + rec_argv[i++] = strdup("-d"); 45 + rec_argv[i++] = strdup("-e"); 46 + 47 + if (strcmp(mem_operation, MEM_OPERATION_LOAD)) 48 + sprintf(event, "cpu/mem-stores/pp"); 49 + else 50 + sprintf(event, "cpu/mem-loads/pp"); 51 + 52 + rec_argv[i++] = strdup(event); 53 + for (j = 1; j < argc; j++, i++) 54 + rec_argv[i] = argv[j]; 55 + 56 + ret = cmd_record(i, rec_argv, NULL); 57 + free(rec_argv); 58 + return ret; 59 + } 60 + 61 + static int 62 + dump_raw_samples(struct perf_tool *tool, 63 + union perf_event *event, 64 + struct perf_sample *sample, 65 + struct perf_evsel *evsel __maybe_unused, 66 + struct machine *machine) 67 + { 68 + struct perf_mem *mem = container_of(tool, struct perf_mem, tool); 69 + struct addr_location al; 70 + const char *fmt; 71 + 72 + if (perf_event__preprocess_sample(event, machine, &al, sample, 73 + mem->annotate_init) < 0) { 74 + fprintf(stderr, "problem processing %d event, skipping it.\n", 75 + event->header.type); 76 + return -1; 77 + } 78 + 79 + if (al.filtered || (mem->hide_unresolved && al.sym == NULL)) 80 + return 0; 81 + 82 + if (al.map != NULL) 83 + al.map->dso->hit = 1; 84 + 85 + if (symbol_conf.field_sep) { 86 + fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64 87 + "%s0x%"PRIx64"%s%s:%s\n"; 88 + } else { 89 + fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64 90 + "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n"; 91 + symbol_conf.field_sep = " "; 92 + } 93 + 94 + printf(fmt, 95 + sample->pid, 96 + symbol_conf.field_sep, 97 + sample->tid, 98 + symbol_conf.field_sep, 99 + event->ip.ip, 100 + symbol_conf.field_sep, 101 + sample->addr, 102 + symbol_conf.field_sep, 103 + sample->weight, 104 + symbol_conf.field_sep, 105 + sample->data_src, 106 + symbol_conf.field_sep, 107 + al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???", 108 + al.sym ? al.sym->name : "???"); 109 + 110 + return 0; 111 + } 112 + 113 + static int process_sample_event(struct perf_tool *tool, 114 + union perf_event *event, 115 + struct perf_sample *sample, 116 + struct perf_evsel *evsel, 117 + struct machine *machine) 118 + { 119 + return dump_raw_samples(tool, event, sample, evsel, machine); 120 + } 121 + 122 + static int report_raw_events(struct perf_mem *mem) 123 + { 124 + int err = -EINVAL; 125 + int ret; 126 + struct perf_session *session = perf_session__new(input_name, O_RDONLY, 127 + 0, false, &mem->tool); 128 + 129 + if (session == NULL) 130 + return -ENOMEM; 131 + 132 + if (mem->cpu_list) { 133 + ret = perf_session__cpu_bitmap(session, mem->cpu_list, 134 + mem->cpu_bitmap); 135 + if (ret) 136 + goto out_delete; 137 + } 138 + 139 + if (symbol__init() < 0) 140 + return -1; 141 + 142 + printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); 143 + 144 + err = perf_session__process_events(session, &mem->tool); 145 + if (err) 146 + return err; 147 + 148 + return 0; 149 + 150 + out_delete: 151 + perf_session__delete(session); 152 + return err; 153 + } 154 + 155 + static int report_events(int argc, const char **argv, struct perf_mem *mem) 156 + { 157 + const char **rep_argv; 158 + int ret, i = 0, j, rep_argc; 159 + 160 + if (mem->dump_raw) 161 + return report_raw_events(mem); 162 + 163 + rep_argc = argc + 3; 164 + rep_argv = calloc(rep_argc + 1, sizeof(char *)); 165 + if (!rep_argv) 166 + return -1; 167 + 168 + rep_argv[i++] = strdup("report"); 169 + rep_argv[i++] = strdup("--mem-mode"); 170 + rep_argv[i++] = strdup("-n"); /* display number of samples */ 171 + 172 + /* 173 + * there is no weight (cost) associated with stores, so don't print 174 + * the column 175 + */ 176 + if (strcmp(mem_operation, MEM_OPERATION_LOAD)) 177 + rep_argv[i++] = strdup("--sort=mem,sym,dso,symbol_daddr," 178 + "dso_daddr,tlb,locked"); 179 + 180 + for (j = 1; j < argc; j++, i++) 181 + rep_argv[i] = argv[j]; 182 + 183 + ret = cmd_report(i, rep_argv, NULL); 184 + free(rep_argv); 185 + return ret; 186 + } 187 + 188 + int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) 189 + { 190 + struct stat st; 191 + struct perf_mem mem = { 192 + .tool = { 193 + .sample = process_sample_event, 194 + .mmap = perf_event__process_mmap, 195 + .comm = perf_event__process_comm, 196 + .lost = perf_event__process_lost, 197 + .fork = perf_event__process_fork, 198 + .build_id = perf_event__process_build_id, 199 + .ordered_samples = true, 200 + }, 201 + .input_name = "perf.data", 202 + }; 203 + const struct option mem_options[] = { 204 + OPT_STRING('t', "type", &mem_operation, 205 + "type", "memory operations(load/store)"), 206 + OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw, 207 + "dump raw samples in ASCII"), 208 + OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved, 209 + "Only display entries resolved to a symbol"), 210 + OPT_STRING('i', "input", &input_name, "file", 211 + "input file name"), 212 + OPT_STRING('C', "cpu", &mem.cpu_list, "cpu", 213 + "list of cpus to profile"), 214 + OPT_STRING('x', "field-separator", &symbol_conf.field_sep, 215 + "separator", 216 + "separator for columns, no spaces will be added" 217 + " between columns '.' is reserved."), 218 + OPT_END() 219 + }; 220 + 221 + argc = parse_options(argc, argv, mem_options, mem_usage, 222 + PARSE_OPT_STOP_AT_NON_OPTION); 223 + 224 + if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation)) 225 + usage_with_options(mem_usage, mem_options); 226 + 227 + if (!mem.input_name || !strlen(mem.input_name)) { 228 + if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) 229 + mem.input_name = "-"; 230 + else 231 + mem.input_name = "perf.data"; 232 + } 233 + 234 + if (!strncmp(argv[0], "rec", 3)) 235 + return __cmd_record(argc, argv); 236 + else if (!strncmp(argv[0], "rep", 3)) 237 + return report_events(argc, argv, &mem); 238 + else 239 + usage_with_options(mem_usage, mem_options); 240 + 241 + return 0; 242 + }
+1 -1
tools/perf/builtin-probe.c
··· 37 37 #include "util/strfilter.h" 38 38 #include "util/symbol.h" 39 39 #include "util/debug.h" 40 - #include "util/debugfs.h" 40 + #include <lk/debugfs.h> 41 41 #include "util/parse-options.h" 42 42 #include "util/probe-finder.h" 43 43 #include "util/probe-event.h"
+10 -5
tools/perf/builtin-record.c
··· 5 5 * (or a CPU, or a PID) into the perf.data output file - for 6 6 * later analysis via perf report. 7 7 */ 8 - #define _FILE_OFFSET_BITS 64 9 - 10 8 #include "builtin.h" 11 9 12 10 #include "perf.h" ··· 472 474 } 473 475 474 476 if (forks) { 475 - err = perf_evlist__prepare_workload(evsel_list, opts, argv); 477 + err = perf_evlist__prepare_workload(evsel_list, &opts->target, 478 + argv, opts->pipe_output, 479 + true); 476 480 if (err < 0) { 477 481 pr_err("Couldn't run the workload!\n"); 478 482 goto out_delete_session; ··· 953 953 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack, 954 954 "branch filter mask", "branch stack filter modes", 955 955 parse_branch_stack), 956 + OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, 957 + "sample by weight (on special events only)"), 956 958 OPT_END() 957 959 }; 958 960 ··· 966 964 struct perf_record *rec = &record; 967 965 char errbuf[BUFSIZ]; 968 966 969 - evsel_list = perf_evlist__new(NULL, NULL); 967 + evsel_list = perf_evlist__new(); 970 968 if (evsel_list == NULL) 971 969 return -ENOMEM; 972 970 ··· 1028 1026 ui__error("%s", errbuf); 1029 1027 1030 1028 err = -saved_errno; 1031 - goto out_free_fd; 1029 + goto out_symbol_exit; 1032 1030 } 1033 1031 1034 1032 err = -ENOMEM; ··· 1059 1057 } 1060 1058 1061 1059 err = __cmd_record(&record, argc, argv); 1060 + 1061 + perf_evlist__munmap(evsel_list); 1062 + perf_evlist__close(evsel_list); 1062 1063 out_free_fd: 1063 1064 perf_evlist__delete_maps(evsel_list); 1064 1065 out_symbol_exit:
+140 -10
tools/perf/builtin-report.c
··· 13 13 #include "util/annotate.h" 14 14 #include "util/color.h" 15 15 #include <linux/list.h> 16 - #include "util/cache.h" 17 16 #include <linux/rbtree.h> 18 17 #include "util/symbol.h" 19 18 #include "util/callchain.h" ··· 46 47 bool show_full_info; 47 48 bool show_threads; 48 49 bool inverted_callchain; 50 + bool mem_mode; 49 51 struct perf_read_values show_threads_values; 50 52 const char *pretty_printing_style; 51 53 symbol_filter_t annotate_init; ··· 63 63 } 64 64 65 65 return perf_default_config(var, value, cb); 66 + } 67 + 68 + static int perf_report__add_mem_hist_entry(struct perf_tool *tool, 69 + struct addr_location *al, 70 + struct perf_sample *sample, 71 + struct perf_evsel *evsel, 72 + struct machine *machine, 73 + union perf_event *event) 74 + { 75 + struct perf_report *rep = container_of(tool, struct perf_report, tool); 76 + struct symbol *parent = NULL; 77 + u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 78 + int err = 0; 79 + struct hist_entry *he; 80 + struct mem_info *mi, *mx; 81 + uint64_t cost; 82 + 83 + if ((sort__has_parent || symbol_conf.use_callchain) && 84 + sample->callchain) { 85 + err = machine__resolve_callchain(machine, evsel, al->thread, 86 + sample, &parent); 87 + if (err) 88 + return err; 89 + } 90 + 91 + mi = machine__resolve_mem(machine, al->thread, sample, cpumode); 92 + if (!mi) 93 + return -ENOMEM; 94 + 95 + if (rep->hide_unresolved && !al->sym) 96 + return 0; 97 + 98 + cost = sample->weight; 99 + if (!cost) 100 + cost = 1; 101 + 102 + /* 103 + * must pass period=weight in order to get the correct 104 + * sorting from hists__collapse_resort() which is solely 105 + * based on periods. We want sorting be done on nr_events * weight 106 + * and this is indirectly achieved by passing period=weight here 107 + * and the he_stat__add_period() function. 108 + */ 109 + he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost); 110 + if (!he) 111 + return -ENOMEM; 112 + 113 + /* 114 + * In the TUI browser, we are doing integrated annotation, 115 + * so we don't allocate the extra space needed because the stdio 116 + * code will not use it. 117 + */ 118 + if (sort__has_sym && he->ms.sym && use_browser > 0) { 119 + struct annotation *notes = symbol__annotation(he->ms.sym); 120 + 121 + assert(evsel != NULL); 122 + 123 + if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) 124 + goto out; 125 + 126 + err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 127 + if (err) 128 + goto out; 129 + } 130 + 131 + if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) { 132 + struct annotation *notes; 133 + 134 + mx = he->mem_info; 135 + 136 + notes = symbol__annotation(mx->daddr.sym); 137 + if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0) 138 + goto out; 139 + 140 + err = symbol__inc_addr_samples(mx->daddr.sym, 141 + mx->daddr.map, 142 + evsel->idx, 143 + mx->daddr.al_addr); 144 + if (err) 145 + goto out; 146 + } 147 + 148 + evsel->hists.stats.total_period += cost; 149 + hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 150 + err = 0; 151 + 152 + if (symbol_conf.use_callchain) { 153 + err = callchain_append(he->callchain, 154 + &callchain_cursor, 155 + sample->period); 156 + } 157 + out: 158 + return err; 66 159 } 67 160 68 161 static int perf_report__add_branch_hist_entry(struct perf_tool *tool, ··· 192 99 * and not events sampled. Thus we use a pseudo period of 1. 193 100 */ 194 101 he = __hists__add_branch_entry(&evsel->hists, al, parent, 195 - &bi[i], 1); 102 + &bi[i], 1, 1); 196 103 if (he) { 197 104 struct annotation *notes; 198 105 err = -ENOMEM; ··· 250 157 return err; 251 158 } 252 159 253 - he = __hists__add_entry(&evsel->hists, al, parent, sample->period); 160 + he = __hists__add_entry(&evsel->hists, al, parent, sample->period, 161 + sample->weight); 254 162 if (he == NULL) 255 163 return -ENOMEM; 256 164 ··· 263 169 return err; 264 170 } 265 171 /* 266 - * Only in the newt browser we are doing integrated annotation, 172 + * Only in the TUI browser we are doing integrated annotation, 267 173 * so we don't allocated the extra space needed because the stdio 268 174 * code will not use it. 269 175 */ ··· 312 218 if (perf_report__add_branch_hist_entry(tool, &al, sample, 313 219 evsel, machine)) { 314 220 pr_debug("problem adding lbr entry, skipping event\n"); 221 + return -1; 222 + } 223 + } else if (rep->mem_mode == 1) { 224 + if (perf_report__add_mem_hist_entry(tool, &al, sample, 225 + evsel, machine, event)) { 226 + pr_debug("problem adding mem entry, skipping event\n"); 315 227 return -1; 316 228 } 317 229 } else { ··· 403 303 session_done = 1; 404 304 } 405 305 406 - static size_t hists__fprintf_nr_sample_events(struct hists *self, 306 + static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, 307 + struct hists *self, 407 308 const char *evname, FILE *fp) 408 309 { 409 310 size_t ret; ··· 415 314 char buf[512]; 416 315 size_t size = sizeof(buf); 417 316 418 - if (symbol_conf.event_group && evsel->nr_members > 1) { 317 + if (perf_evsel__is_group_event(evsel)) { 419 318 struct perf_evsel *pos; 420 319 421 320 perf_evsel__group_desc(evsel, buf, size); ··· 432 331 if (evname != NULL) 433 332 ret += fprintf(fp, " of event '%s'", evname); 434 333 435 - ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); 334 + if (rep->mem_mode) { 335 + ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events); 336 + ret += fprintf(fp, "\n# Sort order : %s", sort_order); 337 + } else 338 + ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); 436 339 return ret + fprintf(fp, "\n#\n"); 437 340 } 438 341 ··· 454 349 !perf_evsel__is_group_leader(pos)) 455 350 continue; 456 351 457 - hists__fprintf_nr_sample_events(hists, evname, stdout); 352 + hists__fprintf_nr_sample_events(rep, hists, evname, stdout); 458 353 hists__fprintf(hists, true, 0, 0, stdout); 459 354 fprintf(stdout, "\n\n"); 460 355 } ··· 750 645 "Use the stdio interface"), 751 646 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 752 647 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 753 - " dso_to, dso_from, symbol_to, symbol_from, mispredict"), 648 + " dso_to, dso_from, symbol_to, symbol_from, mispredict," 649 + " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " 650 + "snoop, locked"), 754 651 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 755 652 "Show sample percentage for different cpu modes"), 756 653 OPT_STRING('p', "parent", &parent_pattern, "regex", ··· 800 693 "use branch records for histogram filling", parse_branch_mode), 801 694 OPT_STRING(0, "objdump", &objdump_path, "path", 802 695 "objdump binary to use for disassembly and annotations"), 696 + OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, 697 + "Disable symbol demangling"), 698 + OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), 803 699 OPT_END() 804 700 }; 805 701 ··· 860 750 "dso_to,symbol_to"; 861 751 862 752 } 753 + if (report.mem_mode) { 754 + if (sort__branch_mode == 1) { 755 + fprintf(stderr, "branch and mem mode incompatible\n"); 756 + goto error; 757 + } 758 + /* 759 + * if no sort_order is provided, then specify 760 + * branch-mode specific order 761 + */ 762 + if (sort_order == default_sort_order) 763 + sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 764 + } 863 765 864 766 if (setup_sorting() < 0) 865 767 usage_with_options(report_usage, options); 866 768 867 769 /* 868 - * Only in the newt browser we are doing integrated annotation, 770 + * Only in the TUI browser we are doing integrated annotation, 869 771 * so don't allocate extra space that won't be used in the stdio 870 772 * implementation. 871 773 */ ··· 937 815 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout); 938 816 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout); 939 817 } else { 818 + if (report.mem_mode) { 819 + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout); 820 + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout); 821 + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout); 822 + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout); 823 + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout); 824 + sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout); 825 + } 940 826 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); 941 827 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); 942 828 }
-1
tools/perf/builtin-sched.c
··· 1671 1671 .sample = perf_sched__process_tracepoint_sample, 1672 1672 .comm = perf_event__process_comm, 1673 1673 .lost = perf_event__process_lost, 1674 - .exit = perf_event__process_exit, 1675 1674 .fork = perf_event__process_fork, 1676 1675 .ordered_samples = true, 1677 1676 },
+237 -171
tools/perf/builtin-stat.c
··· 68 68 static void print_stat(int argc, const char **argv); 69 69 static void print_counter_aggr(struct perf_evsel *counter, char *prefix); 70 70 static void print_counter(struct perf_evsel *counter, char *prefix); 71 - static void print_aggr_socket(char *prefix); 71 + static void print_aggr(char *prefix); 72 72 73 73 static struct perf_evlist *evsel_list; 74 74 ··· 76 76 .uid = UINT_MAX, 77 77 }; 78 78 79 + enum aggr_mode { 80 + AGGR_NONE, 81 + AGGR_GLOBAL, 82 + AGGR_SOCKET, 83 + AGGR_CORE, 84 + }; 85 + 79 86 static int run_count = 1; 80 87 static bool no_inherit = false; 81 88 static bool scale = true; 82 - static bool no_aggr = false; 83 - static bool aggr_socket = false; 89 + static enum aggr_mode aggr_mode = AGGR_GLOBAL; 84 90 static pid_t child_pid = -1; 85 91 static bool null_run = false; 86 92 static int detailed_run = 0; ··· 100 94 static const char *post_cmd = NULL; 101 95 static bool sync_run = false; 102 96 static unsigned int interval = 0; 97 + static bool forever = false; 103 98 static struct timespec ref_time; 104 - static struct cpu_map *sock_map; 99 + static struct cpu_map *aggr_map; 100 + static int (*aggr_get_id)(struct cpu_map *m, int cpu); 105 101 106 102 static volatile int done = 0; 107 103 ··· 131 123 static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) 132 124 { 133 125 return perf_evsel__cpus(evsel)->nr; 126 + } 127 + 128 + static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) 129 + { 130 + memset(evsel->priv, 0, sizeof(struct perf_stat)); 134 131 } 135 132 136 133 static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) ··· 173 160 evsel->prev_raw_counts = NULL; 174 161 } 175 162 163 + static void perf_evlist__free_stats(struct perf_evlist *evlist) 164 + { 165 + struct perf_evsel *evsel; 166 + 167 + list_for_each_entry(evsel, &evlist->entries, node) { 168 + perf_evsel__free_stat_priv(evsel); 169 + perf_evsel__free_counts(evsel); 170 + perf_evsel__free_prev_raw_counts(evsel); 171 + } 172 + } 173 + 174 + static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) 175 + { 176 + struct perf_evsel *evsel; 177 + 178 + list_for_each_entry(evsel, &evlist->entries, node) { 179 + if (perf_evsel__alloc_stat_priv(evsel) < 0 || 180 + perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 || 181 + (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0)) 182 + goto out_free; 183 + } 184 + 185 + return 0; 186 + 187 + out_free: 188 + perf_evlist__free_stats(evlist); 189 + return -1; 190 + } 191 + 176 192 static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 177 193 static struct stats runtime_cycles_stats[MAX_NR_CPUS]; 178 194 static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; ··· 214 172 static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; 215 173 static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 216 174 static struct stats walltime_nsecs_stats; 175 + 176 + static void perf_stat__reset_stats(struct perf_evlist *evlist) 177 + { 178 + struct perf_evsel *evsel; 179 + 180 + list_for_each_entry(evsel, &evlist->entries, node) { 181 + perf_evsel__reset_stat_priv(evsel); 182 + perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel)); 183 + } 184 + 185 + memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats)); 186 + memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats)); 187 + memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats)); 188 + memset(runtime_stalled_cycles_back_stats, 0, sizeof(runtime_stalled_cycles_back_stats)); 189 + memset(runtime_branches_stats, 0, sizeof(runtime_branches_stats)); 190 + memset(runtime_cacherefs_stats, 0, sizeof(runtime_cacherefs_stats)); 191 + memset(runtime_l1_dcache_stats, 0, sizeof(runtime_l1_dcache_stats)); 192 + memset(runtime_l1_icache_stats, 0, sizeof(runtime_l1_icache_stats)); 193 + memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats)); 194 + memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats)); 195 + memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats)); 196 + memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); 197 + } 217 198 218 199 static int create_perf_stat_counter(struct perf_evsel *evsel) 219 200 { ··· 314 249 int i; 315 250 316 251 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), 317 - evsel_list->threads->nr, scale) < 0) 252 + thread_map__nr(evsel_list->threads), scale) < 0) 318 253 return -1; 319 254 320 255 for (i = 0; i < 3; i++) ··· 362 297 struct timespec ts, rs; 363 298 char prefix[64]; 364 299 365 - if (no_aggr) { 366 - list_for_each_entry(counter, &evsel_list->entries, node) { 367 - ps = counter->priv; 368 - memset(ps->res_stats, 0, sizeof(ps->res_stats)); 369 - read_counter(counter); 370 - } 371 - } else { 300 + if (aggr_mode == AGGR_GLOBAL) { 372 301 list_for_each_entry(counter, &evsel_list->entries, node) { 373 302 ps = counter->priv; 374 303 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 375 304 read_counter_aggr(counter); 376 305 } 306 + } else { 307 + list_for_each_entry(counter, &evsel_list->entries, node) { 308 + ps = counter->priv; 309 + memset(ps->res_stats, 0, sizeof(ps->res_stats)); 310 + read_counter(counter); 311 + } 377 312 } 313 + 378 314 clock_gettime(CLOCK_MONOTONIC, &ts); 379 315 diff_timespec(&rs, &ts, &ref_time); 380 316 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); 381 317 382 318 if (num_print_interval == 0 && !csv_output) { 383 - if (aggr_socket) 319 + switch (aggr_mode) { 320 + case AGGR_SOCKET: 384 321 fprintf(output, "# time socket cpus counts events\n"); 385 - else if (no_aggr) 322 + break; 323 + case AGGR_CORE: 324 + fprintf(output, "# time core cpus counts events\n"); 325 + break; 326 + case AGGR_NONE: 386 327 fprintf(output, "# time CPU counts events\n"); 387 - else 328 + break; 329 + case AGGR_GLOBAL: 330 + default: 388 331 fprintf(output, "# time counts events\n"); 332 + } 389 333 } 390 334 391 335 if (++num_print_interval == 25) 392 336 num_print_interval = 0; 393 337 394 - if (aggr_socket) 395 - print_aggr_socket(prefix); 396 - else if (no_aggr) { 338 + switch (aggr_mode) { 339 + case AGGR_CORE: 340 + case AGGR_SOCKET: 341 + print_aggr(prefix); 342 + break; 343 + case AGGR_NONE: 397 344 list_for_each_entry(counter, &evsel_list->entries, node) 398 345 print_counter(counter, prefix); 399 - } else { 346 + break; 347 + case AGGR_GLOBAL: 348 + default: 400 349 list_for_each_entry(counter, &evsel_list->entries, node) 401 350 print_counter_aggr(counter, prefix); 402 351 } 403 352 } 404 353 405 - static int __run_perf_stat(int argc __maybe_unused, const char **argv) 354 + static int __run_perf_stat(int argc, const char **argv) 406 355 { 407 356 char msg[512]; 408 357 unsigned long long t0, t1; 409 358 struct perf_evsel *counter; 410 359 struct timespec ts; 411 360 int status = 0; 412 - int child_ready_pipe[2], go_pipe[2]; 413 361 const bool forks = (argc > 0); 414 - char buf; 415 362 416 363 if (interval) { 417 364 ts.tv_sec = interval / 1000; ··· 433 356 ts.tv_nsec = 0; 434 357 } 435 358 436 - if (aggr_socket 437 - && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) { 438 - perror("cannot build socket map"); 439 - return -1; 440 - } 441 - 442 - if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 443 - perror("failed to create pipes"); 444 - return -1; 445 - } 446 - 447 359 if (forks) { 448 - if ((child_pid = fork()) < 0) 449 - perror("failed to fork"); 450 - 451 - if (!child_pid) { 452 - close(child_ready_pipe[0]); 453 - close(go_pipe[1]); 454 - fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 455 - 456 - /* 457 - * Do a dummy execvp to get the PLT entry resolved, 458 - * so we avoid the resolver overhead on the real 459 - * execvp call. 460 - */ 461 - execvp("", (char **)argv); 462 - 463 - /* 464 - * Tell the parent we're ready to go 465 - */ 466 - close(child_ready_pipe[1]); 467 - 468 - /* 469 - * Wait until the parent tells us to go. 470 - */ 471 - if (read(go_pipe[0], &buf, 1) == -1) 472 - perror("unable to read pipe"); 473 - 474 - execvp(argv[0], (char **)argv); 475 - 476 - perror(argv[0]); 477 - exit(-1); 360 + if (perf_evlist__prepare_workload(evsel_list, &target, argv, 361 + false, false) < 0) { 362 + perror("failed to prepare workload"); 363 + return -1; 478 364 } 479 - 480 - if (perf_target__none(&target)) 481 - evsel_list->threads->map[0] = child_pid; 482 - 483 - /* 484 - * Wait for the child to be ready to exec. 485 - */ 486 - close(child_ready_pipe[1]); 487 - close(go_pipe[0]); 488 - if (read(child_ready_pipe[0], &buf, 1) == -1) 489 - perror("unable to read pipe"); 490 - close(child_ready_pipe[0]); 491 365 } 492 366 493 367 if (group) ··· 485 457 clock_gettime(CLOCK_MONOTONIC, &ref_time); 486 458 487 459 if (forks) { 488 - close(go_pipe[1]); 460 + perf_evlist__start_workload(evsel_list); 461 + 489 462 if (interval) { 490 463 while (!waitpid(child_pid, &status, WNOHANG)) { 491 464 nanosleep(&ts, NULL); ··· 508 479 509 480 update_stats(&walltime_nsecs_stats, t1 - t0); 510 481 511 - if (no_aggr) { 512 - list_for_each_entry(counter, &evsel_list->entries, node) { 513 - read_counter(counter); 514 - perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); 515 - } 516 - } else { 482 + if (aggr_mode == AGGR_GLOBAL) { 517 483 list_for_each_entry(counter, &evsel_list->entries, node) { 518 484 read_counter_aggr(counter); 519 485 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 520 - evsel_list->threads->nr); 486 + thread_map__nr(evsel_list->threads)); 487 + } 488 + } else { 489 + list_for_each_entry(counter, &evsel_list->entries, node) { 490 + read_counter(counter); 491 + perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); 521 492 } 522 493 } 523 494 ··· 571 542 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 572 543 } 573 544 574 - static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 545 + static void aggr_printout(struct perf_evsel *evsel, int id, int nr) 575 546 { 576 - double msecs = avg / 1e6; 577 - char cpustr[16] = { '\0', }; 578 - const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; 579 - 580 - if (aggr_socket) 581 - sprintf(cpustr, "S%*d%s%*d%s", 582 - csv_output ? 0 : -5, 583 - cpu, 547 + switch (aggr_mode) { 548 + case AGGR_CORE: 549 + fprintf(output, "S%d-C%*d%s%*d%s", 550 + cpu_map__id_to_socket(id), 551 + csv_output ? 0 : -8, 552 + cpu_map__id_to_cpu(id), 584 553 csv_sep, 585 554 csv_output ? 0 : 4, 586 555 nr, 587 556 csv_sep); 588 - else if (no_aggr) 589 - sprintf(cpustr, "CPU%*d%s", 557 + break; 558 + case AGGR_SOCKET: 559 + fprintf(output, "S%*d%s%*d%s", 560 + csv_output ? 0 : -5, 561 + id, 562 + csv_sep, 563 + csv_output ? 0 : 4, 564 + nr, 565 + csv_sep); 566 + break; 567 + case AGGR_NONE: 568 + fprintf(output, "CPU%*d%s", 590 569 csv_output ? 0 : -4, 591 - perf_evsel__cpus(evsel)->map[cpu], csv_sep); 570 + perf_evsel__cpus(evsel)->map[id], csv_sep); 571 + break; 572 + case AGGR_GLOBAL: 573 + default: 574 + break; 575 + } 576 + } 592 577 593 - fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); 578 + static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 579 + { 580 + double msecs = avg / 1e6; 581 + const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; 582 + 583 + aggr_printout(evsel, cpu, nr); 584 + 585 + fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel)); 594 586 595 587 if (evsel->cgrp) 596 588 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); ··· 808 758 static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 809 759 { 810 760 double total, ratio = 0.0; 811 - char cpustr[16] = { '\0', }; 812 761 const char *fmt; 813 762 814 763 if (csv_output) 815 - fmt = "%s%.0f%s%s"; 764 + fmt = "%.0f%s%s"; 816 765 else if (big_num) 817 - fmt = "%s%'18.0f%s%-25s"; 766 + fmt = "%'18.0f%s%-25s"; 818 767 else 819 - fmt = "%s%18.0f%s%-25s"; 768 + fmt = "%18.0f%s%-25s"; 820 769 821 - if (aggr_socket) 822 - sprintf(cpustr, "S%*d%s%*d%s", 823 - csv_output ? 0 : -5, 824 - cpu, 825 - csv_sep, 826 - csv_output ? 0 : 4, 827 - nr, 828 - csv_sep); 829 - else if (no_aggr) 830 - sprintf(cpustr, "CPU%*d%s", 831 - csv_output ? 0 : -4, 832 - perf_evsel__cpus(evsel)->map[cpu], csv_sep); 833 - else 770 + aggr_printout(evsel, cpu, nr); 771 + 772 + if (aggr_mode == AGGR_GLOBAL) 834 773 cpu = 0; 835 774 836 - fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel)); 775 + fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel)); 837 776 838 777 if (evsel->cgrp) 839 778 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); ··· 921 882 } 922 883 } 923 884 924 - static void print_aggr_socket(char *prefix) 885 + static void print_aggr(char *prefix) 925 886 { 926 887 struct perf_evsel *counter; 888 + int cpu, s, s2, id, nr; 927 889 u64 ena, run, val; 928 - int cpu, s, s2, sock, nr; 929 890 930 - if (!sock_map) 891 + if (!(aggr_map || aggr_get_id)) 931 892 return; 932 893 933 - for (s = 0; s < sock_map->nr; s++) { 934 - sock = cpu_map__socket(sock_map, s); 894 + for (s = 0; s < aggr_map->nr; s++) { 895 + id = aggr_map->map[s]; 935 896 list_for_each_entry(counter, &evsel_list->entries, node) { 936 897 val = ena = run = 0; 937 898 nr = 0; 938 899 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 939 - s2 = cpu_map__get_socket(evsel_list->cpus, cpu); 940 - if (s2 != sock) 900 + s2 = aggr_get_id(evsel_list->cpus, cpu); 901 + if (s2 != id) 941 902 continue; 942 903 val += counter->counts->cpu[cpu].val; 943 904 ena += counter->counts->cpu[cpu].ena; ··· 948 909 fprintf(output, "%s", prefix); 949 910 950 911 if (run == 0 || ena == 0) { 951 - fprintf(output, "S%*d%s%*d%s%*s%s%*s", 952 - csv_output ? 0 : -5, 953 - s, 954 - csv_sep, 955 - csv_output ? 0 : 4, 956 - nr, 957 - csv_sep, 912 + aggr_printout(counter, cpu, nr); 913 + 914 + fprintf(output, "%*s%s%*s", 958 915 csv_output ? 0 : 18, 959 916 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 960 917 csv_sep, 961 918 csv_output ? 0 : -24, 962 919 perf_evsel__name(counter)); 920 + 963 921 if (counter->cgrp) 964 922 fprintf(output, "%s%s", 965 923 csv_sep, counter->cgrp->name); ··· 966 930 } 967 931 968 932 if (nsec_counter(counter)) 969 - nsec_printout(sock, nr, counter, val); 933 + nsec_printout(id, nr, counter, val); 970 934 else 971 - abs_printout(sock, nr, counter, val); 935 + abs_printout(id, nr, counter, val); 972 936 973 937 if (!csv_output) { 974 938 print_noise(counter, 1.0); ··· 1109 1073 fprintf(output, ":\n\n"); 1110 1074 } 1111 1075 1112 - if (aggr_socket) 1113 - print_aggr_socket(NULL); 1114 - else if (no_aggr) { 1115 - list_for_each_entry(counter, &evsel_list->entries, node) 1116 - print_counter(counter, NULL); 1117 - } else { 1076 + switch (aggr_mode) { 1077 + case AGGR_CORE: 1078 + case AGGR_SOCKET: 1079 + print_aggr(NULL); 1080 + break; 1081 + case AGGR_GLOBAL: 1118 1082 list_for_each_entry(counter, &evsel_list->entries, node) 1119 1083 print_counter_aggr(counter, NULL); 1084 + break; 1085 + case AGGR_NONE: 1086 + list_for_each_entry(counter, &evsel_list->entries, node) 1087 + print_counter(counter, NULL); 1088 + break; 1089 + default: 1090 + break; 1120 1091 } 1121 1092 1122 1093 if (!csv_output) { ··· 1168 1125 big_num_opt = unset ? 0 : 1; 1169 1126 return 0; 1170 1127 } 1128 + 1129 + static int perf_stat_init_aggr_mode(void) 1130 + { 1131 + switch (aggr_mode) { 1132 + case AGGR_SOCKET: 1133 + if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { 1134 + perror("cannot build socket map"); 1135 + return -1; 1136 + } 1137 + aggr_get_id = cpu_map__get_socket; 1138 + break; 1139 + case AGGR_CORE: 1140 + if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { 1141 + perror("cannot build core map"); 1142 + return -1; 1143 + } 1144 + aggr_get_id = cpu_map__get_core; 1145 + break; 1146 + case AGGR_NONE: 1147 + case AGGR_GLOBAL: 1148 + default: 1149 + break; 1150 + } 1151 + return 0; 1152 + } 1153 + 1171 1154 1172 1155 /* 1173 1156 * Add default attributes, if there were no attributes specified or ··· 1365 1296 OPT_INCR('v', "verbose", &verbose, 1366 1297 "be more verbose (show counter open errors, etc)"), 1367 1298 OPT_INTEGER('r', "repeat", &run_count, 1368 - "repeat command and print average + stddev (max: 100)"), 1299 + "repeat command and print average + stddev (max: 100, forever: 0)"), 1369 1300 OPT_BOOLEAN('n', "null", &null_run, 1370 1301 "null run - dont start any counters"), 1371 1302 OPT_INCR('d', "detailed", &detailed_run, ··· 1377 1308 stat__set_big_num), 1378 1309 OPT_STRING('C', "cpu", &target.cpu_list, "cpu", 1379 1310 "list of cpus to monitor in system-wide"), 1380 - OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), 1311 + OPT_SET_UINT('A', "no-aggr", &aggr_mode, 1312 + "disable CPU count aggregation", AGGR_NONE), 1381 1313 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1382 1314 "print counts with custom separator"), 1383 1315 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", ··· 1393 1323 "command to run after to the measured command"), 1394 1324 OPT_UINTEGER('I', "interval-print", &interval, 1395 1325 "print counts at regular interval in ms (>= 100)"), 1396 - OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"), 1326 + OPT_SET_UINT(0, "per-socket", &aggr_mode, 1327 + "aggregate counts per processor socket", AGGR_SOCKET), 1328 + OPT_SET_UINT(0, "per-core", &aggr_mode, 1329 + "aggregate counts per physical processor core", AGGR_CORE), 1397 1330 OPT_END() 1398 1331 }; 1399 1332 const char * const stat_usage[] = { 1400 1333 "perf stat [<options>] [<command>]", 1401 1334 NULL 1402 1335 }; 1403 - struct perf_evsel *pos; 1404 1336 int status = -ENOMEM, run_idx; 1405 1337 const char *mode; 1406 1338 1407 1339 setlocale(LC_ALL, ""); 1408 1340 1409 - evsel_list = perf_evlist__new(NULL, NULL); 1341 + evsel_list = perf_evlist__new(); 1410 1342 if (evsel_list == NULL) 1411 1343 return -ENOMEM; 1412 1344 ··· 1471 1399 1472 1400 if (!argc && !perf_target__has_task(&target)) 1473 1401 usage_with_options(stat_usage, options); 1474 - if (run_count <= 0) 1402 + if (run_count < 0) { 1475 1403 usage_with_options(stat_usage, options); 1404 + } else if (run_count == 0) { 1405 + forever = true; 1406 + run_count = 1; 1407 + } 1476 1408 1477 1409 /* no_aggr, cgroup are for system-wide only */ 1478 - if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { 1410 + if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) 1411 + && !perf_target__has_cpu(&target)) { 1479 1412 fprintf(stderr, "both cgroup and no-aggregation " 1480 1413 "modes only available in system-wide mode\n"); 1481 1414 1482 1415 usage_with_options(stat_usage, options); 1483 - } 1484 - 1485 - if (aggr_socket) { 1486 - if (!perf_target__has_cpu(&target)) { 1487 - fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n"); 1488 - usage_with_options(stat_usage, options); 1489 - } 1490 - no_aggr = true; 1416 + return -1; 1491 1417 } 1492 1418 1493 1419 if (add_default_attributes()) ··· 1508 1438 return -1; 1509 1439 } 1510 1440 1511 - list_for_each_entry(pos, &evsel_list->entries, node) { 1512 - if (perf_evsel__alloc_stat_priv(pos) < 0 || 1513 - perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) 1514 - goto out_free_fd; 1515 - } 1516 - if (interval) { 1517 - list_for_each_entry(pos, &evsel_list->entries, node) { 1518 - if (perf_evsel__alloc_prev_raw_counts(pos) < 0) 1519 - goto out_free_fd; 1520 - } 1521 - } 1441 + if (perf_evlist__alloc_stats(evsel_list, interval)) 1442 + goto out_free_maps; 1443 + 1444 + if (perf_stat_init_aggr_mode()) 1445 + goto out; 1522 1446 1523 1447 /* 1524 1448 * We dont want to block the signals - that would cause ··· 1521 1457 * task, but being ignored by perf stat itself: 1522 1458 */ 1523 1459 atexit(sig_atexit); 1524 - signal(SIGINT, skip_signal); 1460 + if (!forever) 1461 + signal(SIGINT, skip_signal); 1525 1462 signal(SIGCHLD, skip_signal); 1526 1463 signal(SIGALRM, skip_signal); 1527 1464 signal(SIGABRT, skip_signal); 1528 1465 1529 1466 status = 0; 1530 - for (run_idx = 0; run_idx < run_count; run_idx++) { 1467 + for (run_idx = 0; forever || run_idx < run_count; run_idx++) { 1531 1468 if (run_count != 1 && verbose) 1532 1469 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1533 1470 run_idx + 1); 1534 1471 1535 1472 status = run_perf_stat(argc, argv); 1473 + if (forever && status != -1) { 1474 + print_stat(argc, argv); 1475 + perf_stat__reset_stats(evsel_list); 1476 + } 1536 1477 } 1537 1478 1538 - if (status != -1 && !interval) 1479 + if (!forever && status != -1 && !interval) 1539 1480 print_stat(argc, argv); 1540 - out_free_fd: 1541 - list_for_each_entry(pos, &evsel_list->entries, node) { 1542 - perf_evsel__free_stat_priv(pos); 1543 - perf_evsel__free_counts(pos); 1544 - perf_evsel__free_prev_raw_counts(pos); 1545 - } 1481 + 1482 + perf_evlist__free_stats(evsel_list); 1483 + out_free_maps: 1546 1484 perf_evlist__delete_maps(evsel_list); 1547 1485 out: 1548 1486 perf_evlist__delete(evsel_list);
+5 -4
tools/perf/builtin-top.c
··· 231 231 printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); 232 232 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); 233 233 234 - more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, 234 + more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, 235 235 0, top->sym_pcnt_filter, top->print_entries, 4); 236 236 if (top->zero) 237 237 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); ··· 251 251 { 252 252 struct hist_entry *he; 253 253 254 - he = __hists__add_entry(&evsel->hists, al, NULL, sample->period); 254 + he = __hists__add_entry(&evsel->hists, al, NULL, sample->period, 255 + sample->weight); 255 256 if (he == NULL) 256 257 return NULL; 257 258 ··· 1089 1088 OPT_INCR('v', "verbose", &verbose, 1090 1089 "be more verbose (show counter open errors, etc)"), 1091 1090 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1092 - "sort by key(s): pid, comm, dso, symbol, parent"), 1091 + "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"), 1093 1092 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1094 1093 "Show a column with the number of samples"), 1095 1094 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, ··· 1117 1116 NULL 1118 1117 }; 1119 1118 1120 - top.evlist = perf_evlist__new(NULL, NULL); 1119 + top.evlist = perf_evlist__new(); 1121 1120 if (top.evlist == NULL) 1122 1121 return -ENOMEM; 1123 1122
+14 -14
tools/perf/builtin-trace.c
··· 419 419 420 420 static int trace__run(struct trace *trace, int argc, const char **argv) 421 421 { 422 - struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 422 + struct perf_evlist *evlist = perf_evlist__new(); 423 423 struct perf_evsel *evsel; 424 424 int err = -1, i; 425 425 unsigned long before; ··· 452 452 err = trace__symbols_init(trace, evlist); 453 453 if (err < 0) { 454 454 printf("Problems initializing symbol libraries!\n"); 455 - goto out_delete_evlist; 455 + goto out_delete_maps; 456 456 } 457 457 458 458 perf_evlist__config(evlist, &trace->opts); ··· 461 461 signal(SIGINT, sig_handler); 462 462 463 463 if (forks) { 464 - err = perf_evlist__prepare_workload(evlist, &trace->opts, argv); 464 + err = perf_evlist__prepare_workload(evlist, &trace->opts.target, 465 + argv, false, false); 465 466 if (err < 0) { 466 467 printf("Couldn't run the workload!\n"); 467 - goto out_delete_evlist; 468 + goto out_delete_maps; 468 469 } 469 470 } 470 471 471 472 err = perf_evlist__open(evlist); 472 473 if (err < 0) { 473 474 printf("Couldn't create the events: %s\n", strerror(errno)); 474 - goto out_delete_evlist; 475 + goto out_delete_maps; 475 476 } 476 477 477 478 err = perf_evlist__mmap(evlist, UINT_MAX, false); 478 479 if (err < 0) { 479 480 printf("Couldn't mmap the events: %s\n", strerror(errno)); 480 - goto out_delete_evlist; 481 + goto out_close_evlist; 481 482 } 482 483 483 484 perf_evlist__enable(evlist); ··· 527 526 continue; 528 527 } 529 528 530 - if (sample.raw_data == NULL) { 531 - printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 532 - perf_evsel__name(evsel), sample.tid, 533 - sample.cpu, sample.raw_size); 534 - continue; 535 - } 536 - 537 529 handler = evsel->handler.func; 538 530 handler(trace, evsel, &sample); 539 531 } ··· 534 540 535 541 if (trace->nr_events == before) { 536 542 if (done) 537 - goto out_delete_evlist; 543 + goto out_unmap_evlist; 538 544 539 545 poll(evlist->pollfd, evlist->nr_fds, -1); 540 546 } ··· 544 550 545 551 goto again; 546 552 553 + out_unmap_evlist: 554 + perf_evlist__munmap(evlist); 555 + out_close_evlist: 556 + perf_evlist__close(evlist); 557 + out_delete_maps: 558 + perf_evlist__delete_maps(evlist); 547 559 out_delete_evlist: 548 560 perf_evlist__delete(evlist); 549 561 out:
+1
tools/perf/builtin.h
··· 36 36 extern int cmd_test(int argc, const char **argv, const char *prefix); 37 37 extern int cmd_trace(int argc, const char **argv, const char *prefix); 38 38 extern int cmd_inject(int argc, const char **argv, const char *prefix); 39 + extern int cmd_mem(int argc, const char **argv, const char *prefix); 39 40 40 41 extern int find_scripts(char **scripts_array, char **scripts_path_array); 41 42 #endif
+8 -7
tools/perf/command-list.txt
··· 10 10 perf-diff mainporcelain common 11 11 perf-evlist mainporcelain common 12 12 perf-inject mainporcelain common 13 + perf-kmem mainporcelain common 14 + perf-kvm mainporcelain common 13 15 perf-list mainporcelain common 14 - perf-sched mainporcelain common 16 + perf-lock mainporcelain common 17 + perf-mem mainporcelain common 18 + perf-probe mainporcelain full 15 19 perf-record mainporcelain common 16 20 perf-report mainporcelain common 21 + perf-sched mainporcelain common 22 + perf-script mainporcelain common 17 23 perf-stat mainporcelain common 24 + perf-test mainporcelain common 18 25 perf-timechart mainporcelain common 19 26 perf-top mainporcelain common 20 27 perf-trace mainporcelain common 21 - perf-script mainporcelain common 22 - perf-probe mainporcelain full 23 - perf-kmem mainporcelain common 24 - perf-lock mainporcelain common 25 - perf-kvm mainporcelain common 26 - perf-test mainporcelain common
+4 -6
tools/perf/config/feature-tests.mak
··· 61 61 } 62 62 endef 63 63 64 - ifndef NO_NEWT 65 - define SOURCE_NEWT 66 - #include <newt.h> 64 + ifndef NO_SLANG 65 + define SOURCE_SLANG 66 + #include <slang.h> 67 67 68 68 int main(void) 69 69 { 70 - newtInit(); 71 - newtCls(); 72 - return newtFinished(); 70 + return SLsmg_init_smg(); 73 71 } 74 72 endef 75 73 endif
+6 -6
tools/perf/perf.c
··· 13 13 #include "util/quote.h" 14 14 #include "util/run-command.h" 15 15 #include "util/parse-events.h" 16 - #include "util/debugfs.h" 16 + #include <lk/debugfs.h> 17 17 #include <pthread.h> 18 18 19 19 const char perf_usage_string[] = ··· 60 60 { "trace", cmd_trace, 0 }, 61 61 #endif 62 62 { "inject", cmd_inject, 0 }, 63 + { "mem", cmd_mem, 0 }, 63 64 }; 64 65 65 66 struct pager_config { ··· 194 193 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 195 194 usage(perf_usage_string); 196 195 } 197 - debugfs_set_path((*argv)[1]); 196 + perf_debugfs_set_path((*argv)[1]); 198 197 if (envchanged) 199 198 *envchanged = 1; 200 199 (*argv)++; 201 200 (*argc)--; 202 201 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { 203 - debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); 202 + perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); 204 203 fprintf(stderr, "dir: %s\n", debugfs_mountpoint); 205 204 if (envchanged) 206 205 *envchanged = 1; ··· 462 461 if (!cmd) 463 462 cmd = "perf-help"; 464 463 /* get debugfs mount point from /proc/mounts */ 465 - debugfs_mount(NULL); 464 + perf_debugfs_mount(NULL); 466 465 /* 467 466 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 468 467 * ··· 518 517 519 518 while (1) { 520 519 static int done_help; 521 - static int was_alias; 520 + int was_alias = run_argv(&argc, &argv); 522 521 523 - was_alias = run_argv(&argc, &argv); 524 522 if (errno != ENOENT) 525 523 break; 526 524
+1
tools/perf/perf.h
··· 218 218 bool pipe_output; 219 219 bool raw_samples; 220 220 bool sample_address; 221 + bool sample_weight; 221 222 bool sample_time; 222 223 bool period; 223 224 unsigned int freq;
+7 -2
tools/perf/tests/attr.c
··· 147 147 148 148 static int run_dir(const char *d, const char *perf) 149 149 { 150 + char v[] = "-vvvvv"; 151 + int vcnt = min(verbose, (int) sizeof(v) - 1); 150 152 char cmd[3*PATH_MAX]; 151 153 152 - snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s", 153 - d, d, perf, verbose ? "-v" : ""); 154 + if (verbose) 155 + vcnt++; 156 + 157 + snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s", 158 + d, d, perf, vcnt, v); 154 159 155 160 return system(cmd); 156 161 }
+3 -2
tools/perf/tests/attr.py
··· 24 24 25 25 class Event(dict): 26 26 terms = [ 27 + 'cpu', 27 28 'flags', 28 29 'type', 29 30 'size', ··· 122 121 parser = ConfigParser.SafeConfigParser() 123 122 parser.read(path) 124 123 125 - log.debug("running '%s'" % path) 124 + log.warning("running '%s'" % path) 126 125 127 126 self.path = path 128 127 self.test_dir = options.test_dir ··· 173 172 self.perf, self.command, tempdir, self.args) 174 173 ret = os.WEXITSTATUS(os.system(cmd)) 175 174 176 - log.warning(" running '%s' ret %d " % (cmd, ret)) 175 + log.info(" '%s' ret %d " % (cmd, ret)) 177 176 178 177 if ret != int(self.ret): 179 178 raise Unsup(self)
+1
tools/perf/tests/attr/base-record
··· 2 2 fd=1 3 3 group_fd=-1 4 4 flags=0 5 + cpu=* 5 6 type=0|1 6 7 size=96 7 8 config=0
+1
tools/perf/tests/attr/base-stat
··· 2 2 fd=1 3 3 group_fd=-1 4 4 flags=0 5 + cpu=* 5 6 type=0 6 7 size=96 7 8 config=0
+13
tools/perf/tests/attr/test-record-C0
··· 1 + [config] 2 + command = record 3 + args = -C 0 kill >/dev/null 2>&1 4 + 5 + [event:base-record] 6 + cpu=0 7 + 8 + # no enable on exec for CPU attached 9 + enable_on_exec=0 10 + 11 + # PERF_SAMPLE_IP | PERF_SAMPLE_TID PERF_SAMPLE_TIME | # PERF_SAMPLE_PERIOD 12 + # + PERF_SAMPLE_CPU added by -C 0 13 + sample_type=391
+9
tools/perf/tests/attr/test-stat-C0
··· 1 + [config] 2 + command = stat 3 + args = -e cycles -C 0 kill >/dev/null 2>&1 4 + ret = 1 5 + 6 + [event:base-stat] 7 + # events are enabled by default when attached to cpu 8 + disabled=0 9 + enable_on_exec=0
+186
tools/perf/tests/bp_signal.c
··· 1 + /* 2 + * Inspired by breakpoint overflow test done by 3 + * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests 4 + * (git://github.com/deater/perf_event_tests) 5 + */ 6 + 7 + #include <stdlib.h> 8 + #include <stdio.h> 9 + #include <unistd.h> 10 + #include <string.h> 11 + #include <sys/ioctl.h> 12 + #include <time.h> 13 + #include <fcntl.h> 14 + #include <signal.h> 15 + #include <sys/mman.h> 16 + #include <linux/compiler.h> 17 + #include <linux/hw_breakpoint.h> 18 + 19 + #include "tests.h" 20 + #include "debug.h" 21 + #include "perf.h" 22 + 23 + static int fd1; 24 + static int fd2; 25 + static int overflows; 26 + 27 + __attribute__ ((noinline)) 28 + static int test_function(void) 29 + { 30 + return time(NULL); 31 + } 32 + 33 + static void sig_handler(int signum __maybe_unused, 34 + siginfo_t *oh __maybe_unused, 35 + void *uc __maybe_unused) 36 + { 37 + overflows++; 38 + 39 + if (overflows > 10) { 40 + /* 41 + * This should be executed only once during 42 + * this test, if we are here for the 10th 43 + * time, consider this the recursive issue. 44 + * 45 + * We can get out of here by disable events, 46 + * so no new SIGIO is delivered. 47 + */ 48 + ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 49 + ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 50 + } 51 + } 52 + 53 + static int bp_event(void *fn, int setup_signal) 54 + { 55 + struct perf_event_attr pe; 56 + int fd; 57 + 58 + memset(&pe, 0, sizeof(struct perf_event_attr)); 59 + pe.type = PERF_TYPE_BREAKPOINT; 60 + pe.size = sizeof(struct perf_event_attr); 61 + 62 + pe.config = 0; 63 + pe.bp_type = HW_BREAKPOINT_X; 64 + pe.bp_addr = (unsigned long) fn; 65 + pe.bp_len = sizeof(long); 66 + 67 + pe.sample_period = 1; 68 + pe.sample_type = PERF_SAMPLE_IP; 69 + pe.wakeup_events = 1; 70 + 71 + pe.disabled = 1; 72 + pe.exclude_kernel = 1; 73 + pe.exclude_hv = 1; 74 + 75 + fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 76 + if (fd < 0) { 77 + pr_debug("failed opening event %llx\n", pe.config); 78 + return TEST_FAIL; 79 + } 80 + 81 + if (setup_signal) { 82 + fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); 83 + fcntl(fd, F_SETSIG, SIGIO); 84 + fcntl(fd, F_SETOWN, getpid()); 85 + } 86 + 87 + ioctl(fd, PERF_EVENT_IOC_RESET, 0); 88 + 89 + return fd; 90 + } 91 + 92 + static long long bp_count(int fd) 93 + { 94 + long long count; 95 + int ret; 96 + 97 + ret = read(fd, &count, sizeof(long long)); 98 + if (ret != sizeof(long long)) { 99 + pr_debug("failed to read: %d\n", ret); 100 + return TEST_FAIL; 101 + } 102 + 103 + return count; 104 + } 105 + 106 + int test__bp_signal(void) 107 + { 108 + struct sigaction sa; 109 + long long count1, count2; 110 + 111 + /* setup SIGIO signal handler */ 112 + memset(&sa, 0, sizeof(struct sigaction)); 113 + sa.sa_sigaction = (void *) sig_handler; 114 + sa.sa_flags = SA_SIGINFO; 115 + 116 + if (sigaction(SIGIO, &sa, NULL) < 0) { 117 + pr_debug("failed setting up signal handler\n"); 118 + return TEST_FAIL; 119 + } 120 + 121 + /* 122 + * We create following events: 123 + * 124 + * fd1 - breakpoint event on test_function with SIGIO 125 + * signal configured. We should get signal 126 + * notification each time the breakpoint is hit 127 + * 128 + * fd2 - breakpoint event on sig_handler without SIGIO 129 + * configured. 130 + * 131 + * Following processing should happen: 132 + * - execute test_function 133 + * - fd1 event breakpoint hit -> count1 == 1 134 + * - SIGIO is delivered -> overflows == 1 135 + * - fd2 event breakpoint hit -> count2 == 1 136 + * 137 + * The test case check following error conditions: 138 + * - we get stuck in signal handler because of debug 139 + * exception being triggered receursively due to 140 + * the wrong RF EFLAG management 141 + * 142 + * - we never trigger the sig_handler breakpoint due 143 + * to the rong RF EFLAG management 144 + * 145 + */ 146 + 147 + fd1 = bp_event(test_function, 1); 148 + fd2 = bp_event(sig_handler, 0); 149 + 150 + ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); 151 + ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); 152 + 153 + /* 154 + * Kick off the test by trigering 'fd1' 155 + * breakpoint. 156 + */ 157 + test_function(); 158 + 159 + ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 160 + ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 161 + 162 + count1 = bp_count(fd1); 163 + count2 = bp_count(fd2); 164 + 165 + close(fd1); 166 + close(fd2); 167 + 168 + pr_debug("count1 %lld, count2 %lld, overflow %d\n", 169 + count1, count2, overflows); 170 + 171 + if (count1 != 1) { 172 + if (count1 == 11) 173 + pr_debug("failed: RF EFLAG recursion issue detected\n"); 174 + else 175 + pr_debug("failed: wrong count for bp1%lld\n", count1); 176 + } 177 + 178 + if (overflows != 1) 179 + pr_debug("failed: wrong overflow hit\n"); 180 + 181 + if (count2 != 1) 182 + pr_debug("failed: wrong count for bp2\n"); 183 + 184 + return count1 == 1 && overflows == 1 && count2 == 1 ? 185 + TEST_OK : TEST_FAIL; 186 + }
+126
tools/perf/tests/bp_signal_overflow.c
··· 1 + /* 2 + * Originally done by Vince Weaver <vincent.weaver@maine.edu> for 3 + * perf_event_tests (git://github.com/deater/perf_event_tests) 4 + */ 5 + 6 + #include <stdlib.h> 7 + #include <stdio.h> 8 + #include <unistd.h> 9 + #include <string.h> 10 + #include <sys/ioctl.h> 11 + #include <time.h> 12 + #include <fcntl.h> 13 + #include <signal.h> 14 + #include <sys/mman.h> 15 + #include <linux/compiler.h> 16 + #include <linux/hw_breakpoint.h> 17 + 18 + #include "tests.h" 19 + #include "debug.h" 20 + #include "perf.h" 21 + 22 + static int overflows; 23 + 24 + __attribute__ ((noinline)) 25 + static int test_function(void) 26 + { 27 + return time(NULL); 28 + } 29 + 30 + static void sig_handler(int signum __maybe_unused, 31 + siginfo_t *oh __maybe_unused, 32 + void *uc __maybe_unused) 33 + { 34 + overflows++; 35 + } 36 + 37 + static long long bp_count(int fd) 38 + { 39 + long long count; 40 + int ret; 41 + 42 + ret = read(fd, &count, sizeof(long long)); 43 + if (ret != sizeof(long long)) { 44 + pr_debug("failed to read: %d\n", ret); 45 + return TEST_FAIL; 46 + } 47 + 48 + return count; 49 + } 50 + 51 + #define EXECUTIONS 10000 52 + #define THRESHOLD 100 53 + 54 + int test__bp_signal_overflow(void) 55 + { 56 + struct perf_event_attr pe; 57 + struct sigaction sa; 58 + long long count; 59 + int fd, i, fails = 0; 60 + 61 + /* setup SIGIO signal handler */ 62 + memset(&sa, 0, sizeof(struct sigaction)); 63 + sa.sa_sigaction = (void *) sig_handler; 64 + sa.sa_flags = SA_SIGINFO; 65 + 66 + if (sigaction(SIGIO, &sa, NULL) < 0) { 67 + pr_debug("failed setting up signal handler\n"); 68 + return TEST_FAIL; 69 + } 70 + 71 + memset(&pe, 0, sizeof(struct perf_event_attr)); 72 + pe.type = PERF_TYPE_BREAKPOINT; 73 + pe.size = sizeof(struct perf_event_attr); 74 + 75 + pe.config = 0; 76 + pe.bp_type = HW_BREAKPOINT_X; 77 + pe.bp_addr = (unsigned long) test_function; 78 + pe.bp_len = sizeof(long); 79 + 80 + pe.sample_period = THRESHOLD; 81 + pe.sample_type = PERF_SAMPLE_IP; 82 + pe.wakeup_events = 1; 83 + 84 + pe.disabled = 1; 85 + pe.exclude_kernel = 1; 86 + pe.exclude_hv = 1; 87 + 88 + fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 89 + if (fd < 0) { 90 + pr_debug("failed opening event %llx\n", pe.config); 91 + return TEST_FAIL; 92 + } 93 + 94 + fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); 95 + fcntl(fd, F_SETSIG, SIGIO); 96 + fcntl(fd, F_SETOWN, getpid()); 97 + 98 + ioctl(fd, PERF_EVENT_IOC_RESET, 0); 99 + ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); 100 + 101 + for (i = 0; i < EXECUTIONS; i++) 102 + test_function(); 103 + 104 + ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); 105 + 106 + count = bp_count(fd); 107 + 108 + close(fd); 109 + 110 + pr_debug("count %lld, overflow %d\n", 111 + count, overflows); 112 + 113 + if (count != EXECUTIONS) { 114 + pr_debug("\tWrong number of executions %lld != %d\n", 115 + count, EXECUTIONS); 116 + fails++; 117 + } 118 + 119 + if (overflows != EXECUTIONS / THRESHOLD) { 120 + pr_debug("\tWrong number of overflows %d != %d\n", 121 + overflows, EXECUTIONS / THRESHOLD); 122 + fails++; 123 + } 124 + 125 + return fails ? TEST_FAIL : TEST_OK; 126 + }
+16
tools/perf/tests/builtin-test.c
··· 78 78 .func = test__python_use, 79 79 }, 80 80 { 81 + .desc = "Test breakpoint overflow signal handler", 82 + .func = test__bp_signal, 83 + }, 84 + { 85 + .desc = "Test breakpoint overflow sampling", 86 + .func = test__bp_signal_overflow, 87 + }, 88 + { 89 + .desc = "Test number of exit event of a simple workload", 90 + .func = test__task_exit, 91 + }, 92 + { 93 + .desc = "Test software clock events have valid period values", 94 + .func = test__sw_clock_freq, 95 + }, 96 + { 81 97 .func = NULL, 82 98 }, 83 99 };
+2 -2
tools/perf/tests/evsel-roundtrip-name.c
··· 8 8 char name[128]; 9 9 int type, op, err = 0, ret = 0, i, idx; 10 10 struct perf_evsel *evsel; 11 - struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 11 + struct perf_evlist *evlist = perf_evlist__new(); 12 12 13 13 if (evlist == NULL) 14 14 return -ENOMEM; ··· 64 64 { 65 65 int i, err; 66 66 struct perf_evsel *evsel; 67 - struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 67 + struct perf_evlist *evlist = perf_evlist__new(); 68 68 69 69 if (evlist == NULL) 70 70 return -ENOMEM;
+3 -3
tools/perf/tests/hists_link.c
··· 223 223 &sample, 0) < 0) 224 224 goto out; 225 225 226 - he = __hists__add_entry(&evsel->hists, &al, NULL, 1); 226 + he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 227 227 if (he == NULL) 228 228 goto out; 229 229 ··· 247 247 &sample, 0) < 0) 248 248 goto out; 249 249 250 - he = __hists__add_entry(&evsel->hists, &al, NULL, 1); 250 + he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 251 251 if (he == NULL) 252 252 goto out; 253 253 ··· 436 436 struct machines machines; 437 437 struct machine *machine = NULL; 438 438 struct perf_evsel *evsel, *first; 439 - struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 439 + struct perf_evlist *evlist = perf_evlist__new(); 440 440 441 441 if (evlist == NULL) 442 442 return -ENOMEM;
+3 -1
tools/perf/tests/mmap-basic.c
··· 53 53 goto out_free_cpus; 54 54 } 55 55 56 - evlist = perf_evlist__new(cpus, threads); 56 + evlist = perf_evlist__new(); 57 57 if (evlist == NULL) { 58 58 pr_debug("perf_evlist__new\n"); 59 59 goto out_free_cpus; 60 60 } 61 + 62 + perf_evlist__set_maps(evlist, cpus, threads); 61 63 62 64 for (i = 0; i < nsyscalls; ++i) { 63 65 char name[64];
+7 -3
tools/perf/tests/open-syscall-tp-fields.c
··· 18 18 }; 19 19 const char *filename = "/etc/passwd"; 20 20 int flags = O_RDONLY | O_DIRECTORY; 21 - struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 21 + struct perf_evlist *evlist = perf_evlist__new(); 22 22 struct perf_evsel *evsel; 23 23 int err = -1, i, nr_events = 0, nr_polls = 0; 24 24 ··· 48 48 err = perf_evlist__open(evlist); 49 49 if (err < 0) { 50 50 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 51 - goto out_delete_evlist; 51 + goto out_delete_maps; 52 52 } 53 53 54 54 err = perf_evlist__mmap(evlist, UINT_MAX, false); 55 55 if (err < 0) { 56 56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 57 - goto out_delete_evlist; 57 + goto out_close_evlist; 58 58 } 59 59 60 60 perf_evlist__enable(evlist); ··· 110 110 err = 0; 111 111 out_munmap: 112 112 perf_evlist__munmap(evlist); 113 + out_close_evlist: 114 + perf_evlist__close(evlist); 115 + out_delete_maps: 116 + perf_evlist__delete_maps(evlist); 113 117 out_delete_evlist: 114 118 perf_evlist__delete(evlist); 115 119 out:
+2 -2
tools/perf/tests/parse-events.c
··· 3 3 #include "evsel.h" 4 4 #include "evlist.h" 5 5 #include "sysfs.h" 6 - #include "debugfs.h" 6 + #include <lk/debugfs.h> 7 7 #include "tests.h" 8 8 #include <linux/hw_breakpoint.h> 9 9 ··· 1218 1218 struct perf_evlist *evlist; 1219 1219 int ret; 1220 1220 1221 - evlist = perf_evlist__new(NULL, NULL); 1221 + evlist = perf_evlist__new(); 1222 1222 if (evlist == NULL) 1223 1223 return -ENOMEM; 1224 1224
+6 -3
tools/perf/tests/perf-record.c
··· 45 45 }; 46 46 cpu_set_t cpu_mask; 47 47 size_t cpu_mask_size = sizeof(cpu_mask); 48 - struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 48 + struct perf_evlist *evlist = perf_evlist__new(); 49 49 struct perf_evsel *evsel; 50 50 struct perf_sample sample; 51 51 const char *cmd = "sleep"; ··· 93 93 * so that we have time to open the evlist (calling sys_perf_event_open 94 94 * on all the fds) and then mmap them. 95 95 */ 96 - err = perf_evlist__prepare_workload(evlist, &opts, argv); 96 + err = perf_evlist__prepare_workload(evlist, &opts.target, argv, 97 + false, false); 97 98 if (err < 0) { 98 99 pr_debug("Couldn't run the workload!\n"); 99 100 goto out_delete_maps; ··· 143 142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 144 143 if (err < 0) { 145 144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 146 - goto out_delete_maps; 145 + goto out_close_evlist; 147 146 } 148 147 149 148 /* ··· 306 305 } 307 306 out_err: 308 307 perf_evlist__munmap(evlist); 308 + out_close_evlist: 309 + perf_evlist__close(evlist); 309 310 out_delete_maps: 310 311 perf_evlist__delete_maps(evlist); 311 312 out_delete_evlist:
+119
tools/perf/tests/sw-clock.c
··· 1 + #include <unistd.h> 2 + #include <stdlib.h> 3 + #include <signal.h> 4 + #include <sys/mman.h> 5 + 6 + #include "tests.h" 7 + #include "util/evsel.h" 8 + #include "util/evlist.h" 9 + #include "util/cpumap.h" 10 + #include "util/thread_map.h" 11 + 12 + #define NR_LOOPS 1000000 13 + 14 + /* 15 + * This test will open software clock events (cpu-clock, task-clock) 16 + * then check their frequency -> period conversion has no artifact of 17 + * setting period to 1 forcefully. 18 + */ 19 + static int __test__sw_clock_freq(enum perf_sw_ids clock_id) 20 + { 21 + int i, err = -1; 22 + volatile int tmp = 0; 23 + u64 total_periods = 0; 24 + int nr_samples = 0; 25 + union perf_event *event; 26 + struct perf_evsel *evsel; 27 + struct perf_evlist *evlist; 28 + struct perf_event_attr attr = { 29 + .type = PERF_TYPE_SOFTWARE, 30 + .config = clock_id, 31 + .sample_type = PERF_SAMPLE_PERIOD, 32 + .exclude_kernel = 1, 33 + .disabled = 1, 34 + .freq = 1, 35 + }; 36 + 37 + attr.sample_freq = 10000; 38 + 39 + evlist = perf_evlist__new(); 40 + if (evlist == NULL) { 41 + pr_debug("perf_evlist__new\n"); 42 + return -1; 43 + } 44 + 45 + evsel = perf_evsel__new(&attr, 0); 46 + if (evsel == NULL) { 47 + pr_debug("perf_evsel__new\n"); 48 + goto out_free_evlist; 49 + } 50 + perf_evlist__add(evlist, evsel); 51 + 52 + evlist->cpus = cpu_map__dummy_new(); 53 + evlist->threads = thread_map__new_by_tid(getpid()); 54 + if (!evlist->cpus || !evlist->threads) { 55 + err = -ENOMEM; 56 + pr_debug("Not enough memory to create thread/cpu maps\n"); 57 + goto out_delete_maps; 58 + } 59 + 60 + perf_evlist__open(evlist); 61 + 62 + err = perf_evlist__mmap(evlist, 128, true); 63 + if (err < 0) { 64 + pr_debug("failed to mmap event: %d (%s)\n", errno, 65 + strerror(errno)); 66 + goto out_close_evlist; 67 + } 68 + 69 + perf_evlist__enable(evlist); 70 + 71 + /* collect samples */ 72 + for (i = 0; i < NR_LOOPS; i++) 73 + tmp++; 74 + 75 + perf_evlist__disable(evlist); 76 + 77 + while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { 78 + struct perf_sample sample; 79 + 80 + if (event->header.type != PERF_RECORD_SAMPLE) 81 + continue; 82 + 83 + err = perf_evlist__parse_sample(evlist, event, &sample); 84 + if (err < 0) { 85 + pr_debug("Error during parse sample\n"); 86 + goto out_unmap_evlist; 87 + } 88 + 89 + total_periods += sample.period; 90 + nr_samples++; 91 + } 92 + 93 + if ((u64) nr_samples == total_periods) { 94 + pr_debug("All (%d) samples have period value of 1!\n", 95 + nr_samples); 96 + err = -1; 97 + } 98 + 99 + out_unmap_evlist: 100 + perf_evlist__munmap(evlist); 101 + out_close_evlist: 102 + perf_evlist__close(evlist); 103 + out_delete_maps: 104 + perf_evlist__delete_maps(evlist); 105 + out_free_evlist: 106 + perf_evlist__delete(evlist); 107 + return err; 108 + } 109 + 110 + int test__sw_clock_freq(void) 111 + { 112 + int ret; 113 + 114 + ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK); 115 + if (!ret) 116 + ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK); 117 + 118 + return ret; 119 + }
+123
tools/perf/tests/task-exit.c
··· 1 + #include "evlist.h" 2 + #include "evsel.h" 3 + #include "thread_map.h" 4 + #include "cpumap.h" 5 + #include "tests.h" 6 + 7 + #include <signal.h> 8 + 9 + static int exited; 10 + static int nr_exit; 11 + 12 + static void sig_handler(int sig) 13 + { 14 + exited = 1; 15 + 16 + if (sig == SIGUSR1) 17 + nr_exit = -1; 18 + } 19 + 20 + /* 21 + * This test will start a workload that does nothing then it checks 22 + * if the number of exit event reported by the kernel is 1 or not 23 + * in order to check the kernel returns correct number of event. 24 + */ 25 + int test__task_exit(void) 26 + { 27 + int err = -1; 28 + union perf_event *event; 29 + struct perf_evsel *evsel; 30 + struct perf_evlist *evlist; 31 + struct perf_target target = { 32 + .uid = UINT_MAX, 33 + .uses_mmap = true, 34 + }; 35 + const char *argv[] = { "true", NULL }; 36 + 37 + signal(SIGCHLD, sig_handler); 38 + signal(SIGUSR1, sig_handler); 39 + 40 + evlist = perf_evlist__new(); 41 + if (evlist == NULL) { 42 + pr_debug("perf_evlist__new\n"); 43 + return -1; 44 + } 45 + /* 46 + * We need at least one evsel in the evlist, use the default 47 + * one: "cycles". 48 + */ 49 + err = perf_evlist__add_default(evlist); 50 + if (err < 0) { 51 + pr_debug("Not enough memory to create evsel\n"); 52 + goto out_free_evlist; 53 + } 54 + 55 + /* 56 + * Create maps of threads and cpus to monitor. In this case 57 + * we start with all threads and cpus (-1, -1) but then in 58 + * perf_evlist__prepare_workload we'll fill in the only thread 59 + * we're monitoring, the one forked there. 60 + */ 61 + evlist->cpus = cpu_map__dummy_new(); 62 + evlist->threads = thread_map__new_by_tid(-1); 63 + if (!evlist->cpus || !evlist->threads) { 64 + err = -ENOMEM; 65 + pr_debug("Not enough memory to create thread/cpu maps\n"); 66 + goto out_delete_maps; 67 + } 68 + 69 + err = perf_evlist__prepare_workload(evlist, &target, argv, false, true); 70 + if (err < 0) { 71 + pr_debug("Couldn't run the workload!\n"); 72 + goto out_delete_maps; 73 + } 74 + 75 + evsel = perf_evlist__first(evlist); 76 + evsel->attr.task = 1; 77 + evsel->attr.sample_freq = 0; 78 + evsel->attr.inherit = 0; 79 + evsel->attr.watermark = 0; 80 + evsel->attr.wakeup_events = 1; 81 + evsel->attr.exclude_kernel = 1; 82 + 83 + err = perf_evlist__open(evlist); 84 + if (err < 0) { 85 + pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); 86 + goto out_delete_maps; 87 + } 88 + 89 + if (perf_evlist__mmap(evlist, 128, true) < 0) { 90 + pr_debug("failed to mmap events: %d (%s)\n", errno, 91 + strerror(errno)); 92 + goto out_close_evlist; 93 + } 94 + 95 + perf_evlist__start_workload(evlist); 96 + 97 + retry: 98 + while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { 99 + if (event->header.type != PERF_RECORD_EXIT) 100 + continue; 101 + 102 + nr_exit++; 103 + } 104 + 105 + if (!exited || !nr_exit) { 106 + poll(evlist->pollfd, evlist->nr_fds, -1); 107 + goto retry; 108 + } 109 + 110 + if (nr_exit != 1) { 111 + pr_debug("received %d EXIT records\n", nr_exit); 112 + err = -1; 113 + } 114 + 115 + perf_evlist__munmap(evlist); 116 + out_close_evlist: 117 + perf_evlist__close(evlist); 118 + out_delete_maps: 119 + perf_evlist__delete_maps(evlist); 120 + out_free_evlist: 121 + perf_evlist__delete(evlist); 122 + return err; 123 + }
+4
tools/perf/tests/tests.h
··· 23 23 int test__parse_events(void); 24 24 int test__hists_link(void); 25 25 int test__python_use(void); 26 + int test__bp_signal(void); 27 + int test__bp_signal_overflow(void); 28 + int test__task_exit(void); 29 + int test__sw_clock_freq(void); 26 30 27 31 #endif /* TESTS_H */
+7 -2
tools/perf/ui/browser.c
··· 2 2 #include "../cache.h" 3 3 #include "../../perf.h" 4 4 #include "libslang.h" 5 - #include <newt.h> 6 5 #include "ui.h" 7 6 #include "util.h" 8 7 #include <linux/compiler.h> ··· 233 234 void __ui_browser__show_title(struct ui_browser *browser, const char *title) 234 235 { 235 236 SLsmg_gotorc(0, 0); 236 - ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 237 + ui_browser__set_color(browser, HE_COLORSET_ROOT); 237 238 slsmg_write_nstring(title, browser->width + 1); 238 239 } 239 240 ··· 511 512 .name = "addr", 512 513 .fg = "magenta", 513 514 .bg = "default", 515 + }, 516 + { 517 + .colorset = HE_COLORSET_ROOT, 518 + .name = "root", 519 + .fg = "white", 520 + .bg = "blue", 514 521 }, 515 522 { 516 523 .name = NULL,
+1
tools/perf/ui/browser.h
··· 11 11 #define HE_COLORSET_SELECTED 53 12 12 #define HE_COLORSET_CODE 54 13 13 #define HE_COLORSET_ADDR 55 14 + #define HE_COLORSET_ROOT 56 14 15 15 16 struct ui_browser { 16 17 u64 index, top_idx;
+98 -60
tools/perf/ui/browsers/annotate.c
··· 8 8 #include "../../util/hist.h" 9 9 #include "../../util/sort.h" 10 10 #include "../../util/symbol.h" 11 + #include "../../util/evsel.h" 11 12 #include <pthread.h> 12 - #include <newt.h> 13 13 14 14 struct browser_disasm_line { 15 15 struct rb_node rb_node; 16 - double percent; 17 16 u32 idx; 18 17 int idx_asm; 19 18 int jump_sources; 19 + /* 20 + * actual length of this array is saved on the nr_events field 21 + * of the struct annotate_browser 22 + */ 23 + double percent[1]; 20 24 }; 21 25 22 26 static struct annotate_browser_opt { ··· 37 33 struct ui_browser b; 38 34 struct rb_root entries; 39 35 struct rb_node *curr_hot; 40 - struct disasm_line *selection; 36 + struct disasm_line *selection; 41 37 struct disasm_line **offsets; 38 + int nr_events; 42 39 u64 start; 43 40 int nr_asm_entries; 44 41 int nr_entries; ··· 99 94 (!current_entry || (browser->use_navkeypressed && 100 95 !browser->navkeypressed))); 101 96 int width = browser->width, printed; 97 + int i, pcnt_width = 7 * ab->nr_events; 98 + double percent_max = 0.0; 102 99 char bf[256]; 103 100 104 - if (dl->offset != -1 && bdl->percent != 0.0) { 105 - ui_browser__set_percent_color(browser, bdl->percent, current_entry); 106 - slsmg_printf("%6.2f ", bdl->percent); 101 + for (i = 0; i < ab->nr_events; i++) { 102 + if (bdl->percent[i] > percent_max) 103 + percent_max = bdl->percent[i]; 104 + } 105 + 106 + if (dl->offset != -1 && percent_max != 0.0) { 107 + for (i = 0; i < ab->nr_events; i++) { 108 + ui_browser__set_percent_color(browser, bdl->percent[i], 109 + current_entry); 110 + slsmg_printf("%6.2f ", bdl->percent[i]); 111 + } 107 112 } else { 108 113 ui_browser__set_percent_color(browser, 0, current_entry); 109 - slsmg_write_nstring(" ", 7); 114 + slsmg_write_nstring(" ", pcnt_width); 110 115 } 111 116 112 117 SLsmg_write_char(' '); ··· 126 111 width += 1; 127 112 128 113 if (!*dl->line) 129 - slsmg_write_nstring(" ", width - 7); 114 + slsmg_write_nstring(" ", width - pcnt_width); 130 115 else if (dl->offset == -1) { 131 116 printed = scnprintf(bf, sizeof(bf), "%*s ", 132 117 ab->addr_width, " "); 133 118 slsmg_write_nstring(bf, printed); 134 - slsmg_write_nstring(dl->line, width - printed - 6); 119 + slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1); 135 120 } else { 136 121 u64 addr = dl->offset; 137 122 int color = -1; ··· 190 175 } 191 176 192 177 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 193 - slsmg_write_nstring(bf, width - 10 - printed); 178 + slsmg_write_nstring(bf, width - pcnt_width - 3 - printed); 194 179 } 195 180 196 181 if (current_entry) ··· 215 200 unsigned int from, to; 216 201 struct map_symbol *ms = ab->b.priv; 217 202 struct symbol *sym = ms->sym; 203 + u8 pcnt_width = 7; 218 204 219 205 /* PLT symbols contain external offsets */ 220 206 if (strstr(sym->name, "@plt")) ··· 239 223 to = (u64)btarget->idx; 240 224 } 241 225 226 + pcnt_width *= ab->nr_events; 227 + 242 228 ui_browser__set_color(browser, HE_COLORSET_CODE); 243 - __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to); 229 + __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 230 + from, to); 244 231 } 245 232 246 233 static unsigned int annotate_browser__refresh(struct ui_browser *browser) 247 234 { 235 + struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 248 236 int ret = ui_browser__list_head_refresh(browser); 237 + int pcnt_width; 238 + 239 + pcnt_width = 7 * ab->nr_events; 249 240 250 241 if (annotate_browser__opts.jump_arrows) 251 242 annotate_browser__draw_current_jump(browser); 252 243 253 244 ui_browser__set_color(browser, HE_COLORSET_NORMAL); 254 - __ui_browser__vline(browser, 7, 0, browser->height - 1); 245 + __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); 255 246 return ret; 256 247 } 257 248 258 - static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) 249 + static int disasm__cmp(struct browser_disasm_line *a, 250 + struct browser_disasm_line *b, int nr_pcnt) 259 251 { 260 - double percent = 0.0; 252 + int i; 261 253 262 - if (dl->offset != -1) { 263 - int len = sym->end - sym->start; 264 - unsigned int hits = 0; 265 - struct annotation *notes = symbol__annotation(sym); 266 - struct source_line *src_line = notes->src->lines; 267 - struct sym_hist *h = annotation__histogram(notes, evidx); 268 - s64 offset = dl->offset; 269 - struct disasm_line *next; 270 - 271 - next = disasm__get_next_ip_line(&notes->src->source, dl); 272 - while (offset < (s64)len && 273 - (next == NULL || offset < next->offset)) { 274 - if (src_line) { 275 - percent += src_line[offset].percent; 276 - } else 277 - hits += h->addr[offset]; 278 - 279 - ++offset; 280 - } 281 - /* 282 - * If the percentage wasn't already calculated in 283 - * symbol__get_source_line, do it now: 284 - */ 285 - if (src_line == NULL && h->sum) 286 - percent = 100.0 * hits / h->sum; 254 + for (i = 0; i < nr_pcnt; i++) { 255 + if (a->percent[i] == b->percent[i]) 256 + continue; 257 + return a->percent[i] < b->percent[i]; 287 258 } 288 - 289 - return percent; 259 + return 0; 290 260 } 291 261 292 - static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) 262 + static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl, 263 + int nr_events) 293 264 { 294 265 struct rb_node **p = &root->rb_node; 295 266 struct rb_node *parent = NULL; ··· 285 282 while (*p != NULL) { 286 283 parent = *p; 287 284 l = rb_entry(parent, struct browser_disasm_line, rb_node); 288 - if (bdl->percent < l->percent) 285 + 286 + if (disasm__cmp(bdl, l, nr_events)) 289 287 p = &(*p)->rb_left; 290 288 else 291 289 p = &(*p)->rb_right; ··· 335 331 } 336 332 337 333 static void annotate_browser__calc_percent(struct annotate_browser *browser, 338 - int evidx) 334 + struct perf_evsel *evsel) 339 335 { 340 336 struct map_symbol *ms = browser->b.priv; 341 337 struct symbol *sym = ms->sym; 342 338 struct annotation *notes = symbol__annotation(sym); 343 - struct disasm_line *pos; 339 + struct disasm_line *pos, *next; 340 + s64 len = symbol__size(sym); 344 341 345 342 browser->entries = RB_ROOT; 346 343 ··· 349 344 350 345 list_for_each_entry(pos, &notes->src->source, node) { 351 346 struct browser_disasm_line *bpos = disasm_line__browser(pos); 352 - bpos->percent = disasm_line__calc_percent(pos, sym, evidx); 353 - if (bpos->percent < 0.01) { 347 + const char *path = NULL; 348 + double max_percent = 0.0; 349 + int i; 350 + 351 + if (pos->offset == -1) { 354 352 RB_CLEAR_NODE(&bpos->rb_node); 355 353 continue; 356 354 } 357 - disasm_rb_tree__insert(&browser->entries, bpos); 355 + 356 + next = disasm__get_next_ip_line(&notes->src->source, pos); 357 + 358 + for (i = 0; i < browser->nr_events; i++) { 359 + bpos->percent[i] = disasm__calc_percent(notes, 360 + evsel->idx + i, 361 + pos->offset, 362 + next ? next->offset : len, 363 + &path); 364 + 365 + if (max_percent < bpos->percent[i]) 366 + max_percent = bpos->percent[i]; 367 + } 368 + 369 + if (max_percent < 0.01) { 370 + RB_CLEAR_NODE(&bpos->rb_node); 371 + continue; 372 + } 373 + disasm_rb_tree__insert(&browser->entries, bpos, 374 + browser->nr_events); 358 375 } 359 376 pthread_mutex_unlock(&notes->lock); 360 377 ··· 428 401 browser->b.nr_entries = browser->nr_asm_entries; 429 402 } 430 403 431 - static bool annotate_browser__callq(struct annotate_browser *browser, int evidx, 404 + static bool annotate_browser__callq(struct annotate_browser *browser, 405 + struct perf_evsel *evsel, 432 406 struct hist_browser_timer *hbt) 433 407 { 434 408 struct map_symbol *ms = browser->b.priv; ··· 460 432 } 461 433 462 434 pthread_mutex_unlock(&notes->lock); 463 - symbol__tui_annotate(target, ms->map, evidx, hbt); 435 + symbol__tui_annotate(target, ms->map, evsel, hbt); 464 436 ui_browser__show_title(&browser->b, sym->name); 465 437 return true; 466 438 } ··· 643 615 browser->addr_width += browser->jumps_width + 1; 644 616 } 645 617 646 - static int annotate_browser__run(struct annotate_browser *browser, int evidx, 618 + static int annotate_browser__run(struct annotate_browser *browser, 619 + struct perf_evsel *evsel, 647 620 struct hist_browser_timer *hbt) 648 621 { 649 622 struct rb_node *nd = NULL; ··· 657 628 if (ui_browser__show(&browser->b, sym->name, help) < 0) 658 629 return -1; 659 630 660 - annotate_browser__calc_percent(browser, evidx); 631 + annotate_browser__calc_percent(browser, evsel); 661 632 662 633 if (browser->curr_hot) { 663 634 annotate_browser__set_rb_top(browser, browser->curr_hot); ··· 670 641 key = ui_browser__run(&browser->b, delay_secs); 671 642 672 643 if (delay_secs != 0) { 673 - annotate_browser__calc_percent(browser, evidx); 644 + annotate_browser__calc_percent(browser, evsel); 674 645 /* 675 646 * Current line focus got out of the list of most active 676 647 * lines, NULL it so that if TAB|UNTAB is pressed, we ··· 686 657 hbt->timer(hbt->arg); 687 658 688 659 if (delay_secs != 0) 689 - symbol__annotate_decay_histogram(sym, evidx); 660 + symbol__annotate_decay_histogram(sym, evsel->idx); 690 661 continue; 691 662 case K_TAB: 692 663 if (nd != NULL) { ··· 783 754 goto show_sup_ins; 784 755 goto out; 785 756 } else if (!(annotate_browser__jump(browser) || 786 - annotate_browser__callq(browser, evidx, hbt))) { 757 + annotate_browser__callq(browser, evsel, hbt))) { 787 758 show_sup_ins: 788 759 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 789 760 } ··· 805 776 return key; 806 777 } 807 778 808 - int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 779 + int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 809 780 struct hist_browser_timer *hbt) 810 781 { 811 - return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt); 782 + return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt); 812 783 } 813 784 814 785 static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, ··· 855 826 return 1; 856 827 } 857 828 858 - int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 829 + int symbol__tui_annotate(struct symbol *sym, struct map *map, 830 + struct perf_evsel *evsel, 859 831 struct hist_browser_timer *hbt) 860 832 { 861 833 struct disasm_line *pos, *n; ··· 877 847 }, 878 848 }; 879 849 int ret = -1; 850 + int nr_pcnt = 1; 851 + size_t sizeof_bdl = sizeof(struct browser_disasm_line); 880 852 881 853 if (sym == NULL) 882 854 return -1; ··· 894 862 return -1; 895 863 } 896 864 897 - if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { 865 + if (perf_evsel__is_group_event(evsel)) { 866 + nr_pcnt = evsel->nr_members; 867 + sizeof_bdl += sizeof(double) * (nr_pcnt - 1); 868 + } 869 + 870 + if (symbol__annotate(sym, map, sizeof_bdl) < 0) { 898 871 ui__error("%s", ui_helpline__last_msg); 899 872 goto out_free_offsets; 900 873 } ··· 937 900 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); 938 901 browser.max_addr_width = hex_width(sym->end); 939 902 browser.jumps_width = width_jumps(browser.max_jump_sources); 903 + browser.nr_events = nr_pcnt; 940 904 browser.b.nr_entries = browser.nr_entries; 941 905 browser.b.entries = &notes->src->source, 942 906 browser.b.width += 18; /* Percentage */ ··· 947 909 948 910 annotate_browser__update_addr_width(&browser); 949 911 950 - ret = annotate_browser__run(&browser, evidx, hbt); 912 + ret = annotate_browser__run(&browser, evsel, hbt); 951 913 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 952 914 list_del(&pos->node); 953 915 disasm_line__free(pos);
+3 -4
tools/perf/ui/browsers/hists.c
··· 2 2 #include "../libslang.h" 3 3 #include <stdlib.h> 4 4 #include <string.h> 5 - #include <newt.h> 6 5 #include <linux/rbtree.h> 7 6 8 7 #include "../../util/evsel.h" ··· 1192 1193 char buf[512]; 1193 1194 size_t buflen = sizeof(buf); 1194 1195 1195 - if (symbol_conf.event_group && evsel->nr_members > 1) { 1196 + if (perf_evsel__is_group_event(evsel)) { 1196 1197 struct perf_evsel *pos; 1197 1198 1198 1199 perf_evsel__group_desc(evsel, buf, buflen); ··· 1598 1599 * Don't let this be freed, say, by hists__decay_entry. 1599 1600 */ 1600 1601 he->used = true; 1601 - err = hist_entry__tui_annotate(he, evsel->idx, hbt); 1602 + err = hist_entry__tui_annotate(he, evsel, hbt); 1602 1603 he->used = false; 1603 1604 /* 1604 1605 * offer option to annotate the other branch source or target ··· 1708 1709 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1709 1710 HE_COLORSET_NORMAL); 1710 1711 1711 - if (symbol_conf.event_group && evsel->nr_members > 1) { 1712 + if (perf_evsel__is_group_event(evsel)) { 1712 1713 struct perf_evsel *pos; 1713 1714 1714 1715 ev_name = perf_evsel__group_name(evsel);
+18 -42
tools/perf/ui/browsers/map.c
··· 1 1 #include "../libslang.h" 2 2 #include <elf.h> 3 - #include <newt.h> 4 3 #include <inttypes.h> 5 4 #include <sys/ttydefaults.h> 6 5 #include <string.h> ··· 9 10 #include "../../util/symbol.h" 10 11 #include "../browser.h" 11 12 #include "../helpline.h" 13 + #include "../keysyms.h" 12 14 #include "map.h" 13 - 14 - static int ui_entry__read(const char *title, char *bf, size_t size, int width) 15 - { 16 - struct newtExitStruct es; 17 - newtComponent form, entry; 18 - const char *result; 19 - int err = -1; 20 - 21 - newtCenteredWindow(width, 1, title); 22 - form = newtForm(NULL, NULL, 0); 23 - if (form == NULL) 24 - return -1; 25 - 26 - entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL); 27 - if (entry == NULL) 28 - goto out_free_form; 29 - 30 - newtFormAddComponent(form, entry); 31 - newtFormAddHotKey(form, NEWT_KEY_ENTER); 32 - newtFormAddHotKey(form, NEWT_KEY_ESCAPE); 33 - newtFormAddHotKey(form, NEWT_KEY_LEFT); 34 - newtFormAddHotKey(form, CTRL('c')); 35 - newtFormRun(form, &es); 36 - 37 - if (result != NULL) { 38 - strncpy(bf, result, size); 39 - err = 0; 40 - } 41 - out_free_form: 42 - newtPopWindow(); 43 - newtFormDestroy(form); 44 - return err; 45 - } 46 15 47 16 struct map_browser { 48 17 struct ui_browser b; ··· 45 78 { 46 79 char target[512]; 47 80 struct symbol *sym; 48 - int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40); 49 - 50 - if (err) 51 - return err; 81 + int err = ui_browser__input_window("Search by name/addr", 82 + "Prefix with 0x to search by address", 83 + target, "ENTER: OK, ESC: Cancel", 0); 84 + if (err != K_ENTER) 85 + return -1; 52 86 53 87 if (target[0] == '0' && tolower(target[1]) == 'x') { 54 88 u64 addr = strtoull(target, NULL, 16); ··· 80 112 while (1) { 81 113 key = ui_browser__run(&self->b, 0); 82 114 83 - if (verbose && key == '/') 84 - map_browser__search(self); 85 - else 115 + switch (key) { 116 + case '/': 117 + if (verbose) 118 + map_browser__search(self); 119 + default: 86 120 break; 121 + case K_LEFT: 122 + case K_ESC: 123 + case 'q': 124 + case CTRL('c'): 125 + goto out; 126 + } 87 127 } 88 - 128 + out: 89 129 ui_browser__hide(&self->b); 90 130 return key; 91 131 }
-1
tools/perf/ui/browsers/scripts.c
··· 1 1 #include <elf.h> 2 - #include <newt.h> 3 2 #include <inttypes.h> 4 3 #include <sys/ttydefaults.h> 5 4 #include <string.h>
+21 -5
tools/perf/ui/gtk/annotate.c
··· 1 1 #include "gtk.h" 2 2 #include "util/debug.h" 3 3 #include "util/annotate.h" 4 + #include "util/evsel.h" 4 5 #include "ui/helpline.h" 5 6 6 7 ··· 33 32 return 0; 34 33 35 34 symhist = annotation__histogram(symbol__annotation(sym), evidx); 36 - if (!symhist->addr[dl->offset]) 35 + if (!symbol_conf.event_group && !symhist->addr[dl->offset]) 37 36 return 0; 38 37 39 38 percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; ··· 86 85 } 87 86 88 87 static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, 89 - struct map *map, int evidx, 88 + struct map *map, struct perf_evsel *evsel, 90 89 struct hist_browser_timer *hbt __maybe_unused) 91 90 { 92 91 struct disasm_line *pos, *n; ··· 119 118 120 119 list_for_each_entry(pos, &notes->src->source, node) { 121 120 GtkTreeIter iter; 121 + int ret = 0; 122 122 123 123 gtk_list_store_append(store, &iter); 124 124 125 - if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx)) 125 + if (perf_evsel__is_group_event(evsel)) { 126 + for (i = 0; i < evsel->nr_members; i++) { 127 + ret += perf_gtk__get_percent(s + ret, 128 + sizeof(s) - ret, 129 + sym, pos, 130 + evsel->idx + i); 131 + ret += scnprintf(s + ret, sizeof(s) - ret, " "); 132 + } 133 + } else { 134 + ret = perf_gtk__get_percent(s, sizeof(s), sym, pos, 135 + evsel->idx); 136 + } 137 + 138 + if (ret) 126 139 gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); 127 140 if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) 128 141 gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); ··· 154 139 return 0; 155 140 } 156 141 157 - int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, 142 + int symbol__gtk_annotate(struct symbol *sym, struct map *map, 143 + struct perf_evsel *evsel, 158 144 struct hist_browser_timer *hbt) 159 145 { 160 146 GtkWidget *window; ··· 222 206 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, 223 207 tab_label); 224 208 225 - perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); 209 + perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt); 226 210 return 0; 227 211 } 228 212
+2 -5
tools/perf/ui/gtk/hists.c
··· 32 32 int ret; 33 33 double percent = 0.0; 34 34 struct hists *hists = he->hists; 35 + struct perf_evsel *evsel = hists_to_evsel(hists); 35 36 36 37 if (hists->stats.total_period) 37 38 percent = 100.0 * get_field(he) / hists->stats.total_period; 38 39 39 40 ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); 40 41 41 - if (symbol_conf.event_group) { 42 + if (perf_evsel__is_group_event(evsel)) { 42 43 int prev_idx, idx_delta; 43 - struct perf_evsel *evsel = hists_to_evsel(hists); 44 44 struct hist_entry *pair; 45 45 int nr_members = evsel->nr_members; 46 - 47 - if (nr_members <= 1) 48 - return ret; 49 46 50 47 prev_idx = perf_evsel__group_idx(evsel); 51 48
+2 -5
tools/perf/ui/hist.c
··· 16 16 { 17 17 int ret; 18 18 struct hists *hists = he->hists; 19 + struct perf_evsel *evsel = hists_to_evsel(hists); 19 20 20 21 if (fmt_percent) { 21 22 double percent = 0.0; ··· 29 28 } else 30 29 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); 31 30 32 - if (symbol_conf.event_group) { 31 + if (perf_evsel__is_group_event(evsel)) { 33 32 int prev_idx, idx_delta; 34 - struct perf_evsel *evsel = hists_to_evsel(hists); 35 33 struct hist_entry *pair; 36 34 int nr_members = evsel->nr_members; 37 - 38 - if (nr_members <= 1) 39 - return ret; 40 35 41 36 prev_idx = perf_evsel__group_idx(evsel); 42 37
+11 -10
tools/perf/ui/tui/setup.c
··· 1 - #include <newt.h> 2 1 #include <signal.h> 3 2 #include <stdbool.h> 4 3 ··· 87 88 return SLkp_getkey(); 88 89 } 89 90 90 - static void newt_suspend(void *d __maybe_unused) 91 - { 92 - newtSuspend(); 93 - raise(SIGTSTP); 94 - newtResume(); 95 - } 96 - 97 91 static void ui__signal(int sig) 98 92 { 99 93 ui__exit(false); ··· 98 106 { 99 107 int err; 100 108 101 - newtInit(); 109 + SLutf8_enable(-1); 110 + SLtt_get_terminfo(); 111 + SLtt_get_screen_size(); 112 + 113 + err = SLsmg_init_smg(); 114 + if (err < 0) 115 + goto out; 116 + err = SLang_init_tty(0, 0, 0); 117 + if (err < 0) 118 + goto out; 119 + 102 120 err = SLkp_init(); 103 121 if (err < 0) { 104 122 pr_err("TUI initialization failed.\n"); ··· 117 115 118 116 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); 119 117 120 - newtSetSuspendCallback(newt_suspend, NULL); 121 118 ui_helpline__init(); 122 119 ui_browser__init(); 123 120 ui_progress__init();
+1 -1
tools/perf/ui/ui.h
··· 12 12 void setup_browser(bool fallback_to_pager); 13 13 void exit_browser(bool wait_for_ok); 14 14 15 - #ifdef NEWT_SUPPORT 15 + #ifdef SLANG_SUPPORT 16 16 int ui__init(void); 17 17 void ui__exit(bool wait_for_ok); 18 18 #else
+200 -64
tools/perf/util/annotate.c
··· 14 14 #include "symbol.h" 15 15 #include "debug.h" 16 16 #include "annotate.h" 17 + #include "evsel.h" 17 18 #include <pthread.h> 18 19 #include <linux/bitops.h> 19 20 ··· 603 602 return NULL; 604 603 } 605 604 605 + double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, 606 + s64 end, const char **path) 607 + { 608 + struct source_line *src_line = notes->src->lines; 609 + double percent = 0.0; 610 + 611 + if (src_line) { 612 + size_t sizeof_src_line = sizeof(*src_line) + 613 + sizeof(src_line->p) * (src_line->nr_pcnt - 1); 614 + 615 + while (offset < end) { 616 + src_line = (void *)notes->src->lines + 617 + (sizeof_src_line * offset); 618 + 619 + if (*path == NULL) 620 + *path = src_line->path; 621 + 622 + percent += src_line->p[evidx].percent; 623 + offset++; 624 + } 625 + } else { 626 + struct sym_hist *h = annotation__histogram(notes, evidx); 627 + unsigned int hits = 0; 628 + 629 + while (offset < end) 630 + hits += h->addr[offset++]; 631 + 632 + if (h->sum) 633 + percent = 100.0 * hits / h->sum; 634 + } 635 + 636 + return percent; 637 + } 638 + 606 639 static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 607 - int evidx, u64 len, int min_pcnt, int printed, 640 + struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, 608 641 int max_lines, struct disasm_line *queue) 609 642 { 610 643 static const char *prev_line; ··· 646 611 647 612 if (dl->offset != -1) { 648 613 const char *path = NULL; 649 - unsigned int hits = 0; 650 - double percent = 0.0; 614 + double percent, max_percent = 0.0; 615 + double *ppercents = &percent; 616 + int i, nr_percent = 1; 651 617 const char *color; 652 618 struct annotation *notes = symbol__annotation(sym); 653 - struct source_line *src_line = notes->src->lines; 654 - struct sym_hist *h = annotation__histogram(notes, evidx); 655 619 s64 offset = dl->offset; 656 620 const u64 addr = start + offset; 657 621 struct disasm_line *next; 658 622 659 623 next = disasm__get_next_ip_line(&notes->src->source, dl); 660 624 661 - while (offset < (s64)len && 662 - (next == NULL || offset < next->offset)) { 663 - if (src_line) { 664 - if (path == NULL) 665 - path = src_line[offset].path; 666 - percent += src_line[offset].percent; 667 - } else 668 - hits += h->addr[offset]; 669 - 670 - ++offset; 625 + if (perf_evsel__is_group_event(evsel)) { 626 + nr_percent = evsel->nr_members; 627 + ppercents = calloc(nr_percent, sizeof(double)); 628 + if (ppercents == NULL) 629 + return -1; 671 630 } 672 631 673 - if (src_line == NULL && h->sum) 674 - percent = 100.0 * hits / h->sum; 632 + for (i = 0; i < nr_percent; i++) { 633 + percent = disasm__calc_percent(notes, 634 + notes->src->lines ? i : evsel->idx + i, 635 + offset, 636 + next ? next->offset : (s64) len, 637 + &path); 675 638 676 - if (percent < min_pcnt) 639 + ppercents[i] = percent; 640 + if (percent > max_percent) 641 + max_percent = percent; 642 + } 643 + 644 + if (max_percent < min_pcnt) 677 645 return -1; 678 646 679 647 if (max_lines && printed >= max_lines) ··· 686 648 list_for_each_entry_from(queue, &notes->src->source, node) { 687 649 if (queue == dl) 688 650 break; 689 - disasm_line__print(queue, sym, start, evidx, len, 651 + disasm_line__print(queue, sym, start, evsel, len, 690 652 0, 0, 1, NULL); 691 653 } 692 654 } 693 655 694 - color = get_percent_color(percent); 656 + color = get_percent_color(max_percent); 695 657 696 658 /* 697 659 * Also color the filename and line if needed, with ··· 707 669 } 708 670 } 709 671 710 - color_fprintf(stdout, color, " %7.2f", percent); 672 + for (i = 0; i < nr_percent; i++) { 673 + percent = ppercents[i]; 674 + color = get_percent_color(percent); 675 + color_fprintf(stdout, color, " %7.2f", percent); 676 + } 677 + 711 678 printf(" : "); 712 679 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 713 680 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); 681 + 682 + if (ppercents != &percent) 683 + free(ppercents); 684 + 714 685 } else if (max_lines && printed >= max_lines) 715 686 return 1; 716 687 else { 688 + int width = 8; 689 + 717 690 if (queue) 718 691 return -1; 719 692 693 + if (perf_evsel__is_group_event(evsel)) 694 + width *= evsel->nr_members; 695 + 720 696 if (!*dl->line) 721 - printf(" :\n"); 697 + printf(" %*s:\n", width, " "); 722 698 else 723 - printf(" : %s\n", dl->line); 699 + printf(" %*s: %s\n", width, " ", dl->line); 724 700 } 725 701 726 702 return 0; 727 703 } 728 704 705 + /* 706 + * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) 707 + * which looks like following 708 + * 709 + * 0000000000415500 <_init>: 710 + * 415500: sub $0x8,%rsp 711 + * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> 712 + * 41550b: test %rax,%rax 713 + * 41550e: je 415515 <_init+0x15> 714 + * 415510: callq 416e70 <__gmon_start__@plt> 715 + * 415515: add $0x8,%rsp 716 + * 415519: retq 717 + * 718 + * it will be parsed and saved into struct disasm_line as 719 + * <offset> <name> <ops.raw> 720 + * 721 + * The offset will be a relative offset from the start of the symbol and -1 722 + * means that it's not a disassembly line so should be treated differently. 723 + * The ops.raw part will be parsed further according to type of the instruction. 724 + */ 729 725 static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 730 726 FILE *file, size_t privsize) 731 727 { ··· 930 858 struct source_line *iter; 931 859 struct rb_node **p = &root->rb_node; 932 860 struct rb_node *parent = NULL; 933 - int ret; 861 + int i, ret; 934 862 935 863 while (*p != NULL) { 936 864 parent = *p; ··· 938 866 939 867 ret = strcmp(iter->path, src_line->path); 940 868 if (ret == 0) { 941 - iter->percent_sum += src_line->percent; 869 + for (i = 0; i < src_line->nr_pcnt; i++) 870 + iter->p[i].percent_sum += src_line->p[i].percent; 942 871 return; 943 872 } 944 873 ··· 949 876 p = &(*p)->rb_right; 950 877 } 951 878 952 - src_line->percent_sum = src_line->percent; 879 + for (i = 0; i < src_line->nr_pcnt; i++) 880 + src_line->p[i].percent_sum = src_line->p[i].percent; 953 881 954 882 rb_link_node(&src_line->node, parent, p); 955 883 rb_insert_color(&src_line->node, root); 884 + } 885 + 886 + static int cmp_source_line(struct source_line *a, struct source_line *b) 887 + { 888 + int i; 889 + 890 + for (i = 0; i < a->nr_pcnt; i++) { 891 + if (a->p[i].percent_sum == b->p[i].percent_sum) 892 + continue; 893 + return a->p[i].percent_sum > b->p[i].percent_sum; 894 + } 895 + 896 + return 0; 956 897 } 957 898 958 899 static void __resort_source_line(struct rb_root *root, struct source_line *src_line) ··· 979 892 parent = *p; 980 893 iter = rb_entry(parent, struct source_line, node); 981 894 982 - if (src_line->percent_sum > iter->percent_sum) 895 + if (cmp_source_line(src_line, iter)) 983 896 p = &(*p)->rb_left; 984 897 else 985 898 p = &(*p)->rb_right; ··· 1011 924 { 1012 925 struct annotation *notes = symbol__annotation(sym); 1013 926 struct source_line *src_line = notes->src->lines; 927 + size_t sizeof_src_line; 1014 928 int i; 1015 929 1016 - for (i = 0; i < len; i++) 1017 - free(src_line[i].path); 930 + sizeof_src_line = sizeof(*src_line) + 931 + (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); 1018 932 1019 - free(src_line); 933 + for (i = 0; i < len; i++) { 934 + free(src_line->path); 935 + src_line = (void *)src_line + sizeof_src_line; 936 + } 937 + 938 + free(notes->src->lines); 1020 939 notes->src->lines = NULL; 1021 940 } 1022 941 1023 942 /* Get the filename:line for the colored entries */ 1024 943 static int symbol__get_source_line(struct symbol *sym, struct map *map, 1025 - int evidx, struct rb_root *root, int len, 944 + struct perf_evsel *evsel, 945 + struct rb_root *root, int len, 1026 946 const char *filename) 1027 947 { 1028 948 u64 start; 1029 - int i; 949 + int i, k; 950 + int evidx = evsel->idx; 1030 951 char cmd[PATH_MAX * 2]; 1031 952 struct source_line *src_line; 1032 953 struct annotation *notes = symbol__annotation(sym); 1033 954 struct sym_hist *h = annotation__histogram(notes, evidx); 1034 955 struct rb_root tmp_root = RB_ROOT; 956 + int nr_pcnt = 1; 957 + u64 h_sum = h->sum; 958 + size_t sizeof_src_line = sizeof(struct source_line); 1035 959 1036 - if (!h->sum) 960 + if (perf_evsel__is_group_event(evsel)) { 961 + for (i = 1; i < evsel->nr_members; i++) { 962 + h = annotation__histogram(notes, evidx + i); 963 + h_sum += h->sum; 964 + } 965 + nr_pcnt = evsel->nr_members; 966 + sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p); 967 + } 968 + 969 + if (!h_sum) 1037 970 return 0; 1038 971 1039 - src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); 972 + src_line = notes->src->lines = calloc(len, sizeof_src_line); 1040 973 if (!notes->src->lines) 1041 974 return -1; 1042 975 ··· 1067 960 size_t line_len; 1068 961 u64 offset; 1069 962 FILE *fp; 963 + double percent_max = 0.0; 1070 964 1071 - src_line[i].percent = 100.0 * h->addr[i] / h->sum; 1072 - if (src_line[i].percent <= 0.5) 1073 - continue; 965 + src_line->nr_pcnt = nr_pcnt; 966 + 967 + for (k = 0; k < nr_pcnt; k++) { 968 + h = annotation__histogram(notes, evidx + k); 969 + src_line->p[k].percent = 100.0 * h->addr[i] / h->sum; 970 + 971 + if (src_line->p[k].percent > percent_max) 972 + percent_max = src_line->p[k].percent; 973 + } 974 + 975 + if (percent_max <= 0.5) 976 + goto next; 1074 977 1075 978 offset = start + i; 1076 979 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 1077 980 fp = popen(cmd, "r"); 1078 981 if (!fp) 1079 - continue; 982 + goto next; 1080 983 1081 984 if (getline(&path, &line_len, fp) < 0 || !line_len) 1082 - goto next; 985 + goto next_close; 1083 986 1084 - src_line[i].path = malloc(sizeof(char) * line_len + 1); 1085 - if (!src_line[i].path) 1086 - goto next; 987 + src_line->path = malloc(sizeof(char) * line_len + 1); 988 + if (!src_line->path) 989 + goto next_close; 1087 990 1088 - strcpy(src_line[i].path, path); 1089 - insert_source_line(&tmp_root, &src_line[i]); 991 + strcpy(src_line->path, path); 992 + insert_source_line(&tmp_root, src_line); 1090 993 1091 - next: 994 + next_close: 1092 995 pclose(fp); 996 + next: 997 + src_line = (void *)src_line + sizeof_src_line; 1093 998 } 1094 999 1095 1000 resort_source_line(root, &tmp_root); ··· 1123 1004 1124 1005 node = rb_first(root); 1125 1006 while (node) { 1126 - double percent; 1007 + double percent, percent_max = 0.0; 1127 1008 const char *color; 1128 1009 char *path; 1010 + int i; 1129 1011 1130 1012 src_line = rb_entry(node, struct source_line, node); 1131 - percent = src_line->percent_sum; 1132 - color = get_percent_color(percent); 1133 - path = src_line->path; 1013 + for (i = 0; i < src_line->nr_pcnt; i++) { 1014 + percent = src_line->p[i].percent_sum; 1015 + color = get_percent_color(percent); 1016 + color_fprintf(stdout, color, " %7.2f", percent); 1134 1017 1135 - color_fprintf(stdout, color, " %7.2f %s", percent, path); 1018 + if (percent > percent_max) 1019 + percent_max = percent; 1020 + } 1021 + 1022 + path = src_line->path; 1023 + color = get_percent_color(percent_max); 1024 + color_fprintf(stdout, color, " %s", path); 1025 + 1136 1026 node = rb_next(node); 1137 1027 } 1138 1028 } 1139 1029 1140 - static void symbol__annotate_hits(struct symbol *sym, int evidx) 1030 + static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) 1141 1031 { 1142 1032 struct annotation *notes = symbol__annotation(sym); 1143 - struct sym_hist *h = annotation__histogram(notes, evidx); 1033 + struct sym_hist *h = annotation__histogram(notes, evsel->idx); 1144 1034 u64 len = symbol__size(sym), offset; 1145 1035 1146 1036 for (offset = 0; offset < len; ++offset) ··· 1159 1031 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); 1160 1032 } 1161 1033 1162 - int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 1163 - bool full_paths, int min_pcnt, int max_lines, 1164 - int context) 1034 + int symbol__annotate_printf(struct symbol *sym, struct map *map, 1035 + struct perf_evsel *evsel, bool full_paths, 1036 + int min_pcnt, int max_lines, int context) 1165 1037 { 1166 1038 struct dso *dso = map->dso; 1167 1039 char *filename; ··· 1172 1044 int printed = 2, queue_len = 0; 1173 1045 int more = 0; 1174 1046 u64 len; 1047 + int width = 8; 1048 + int namelen; 1175 1049 1176 1050 filename = strdup(dso->long_name); 1177 1051 if (!filename) ··· 1185 1055 d_filename = basename(filename); 1186 1056 1187 1057 len = symbol__size(sym); 1058 + namelen = strlen(d_filename); 1188 1059 1189 - printf(" Percent | Source code & Disassembly of %s\n", d_filename); 1190 - printf("------------------------------------------------\n"); 1060 + if (perf_evsel__is_group_event(evsel)) 1061 + width *= evsel->nr_members; 1062 + 1063 + printf(" %-*.*s| Source code & Disassembly of %s\n", 1064 + width, width, "Percent", d_filename); 1065 + printf("-%-*.*s-------------------------------------\n", 1066 + width+namelen, width+namelen, graph_dotted_line); 1191 1067 1192 1068 if (verbose) 1193 - symbol__annotate_hits(sym, evidx); 1069 + symbol__annotate_hits(sym, evsel); 1194 1070 1195 1071 list_for_each_entry(pos, &notes->src->source, node) { 1196 1072 if (context && queue == NULL) { ··· 1204 1068 queue_len = 0; 1205 1069 } 1206 1070 1207 - switch (disasm_line__print(pos, sym, start, evidx, len, 1071 + switch (disasm_line__print(pos, sym, start, evsel, len, 1208 1072 min_pcnt, printed, max_lines, 1209 1073 queue)) { 1210 1074 case 0: ··· 1299 1163 return printed; 1300 1164 } 1301 1165 1302 - int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1303 - bool print_lines, bool full_paths, int min_pcnt, 1304 - int max_lines) 1166 + int symbol__tty_annotate(struct symbol *sym, struct map *map, 1167 + struct perf_evsel *evsel, bool print_lines, 1168 + bool full_paths, int min_pcnt, int max_lines) 1305 1169 { 1306 1170 struct dso *dso = map->dso; 1307 1171 const char *filename = dso->long_name; ··· 1314 1178 len = symbol__size(sym); 1315 1179 1316 1180 if (print_lines) { 1317 - symbol__get_source_line(sym, map, evidx, &source_line, 1181 + symbol__get_source_line(sym, map, evsel, &source_line, 1318 1182 len, filename); 1319 1183 print_summary(&source_line, filename); 1320 1184 } 1321 1185 1322 - symbol__annotate_printf(sym, map, evidx, full_paths, 1186 + symbol__annotate_printf(sym, map, evsel, full_paths, 1323 1187 min_pcnt, max_lines, 0); 1324 1188 if (print_lines) 1325 1189 symbol__free_source_line(sym, len);
+31 -20
tools/perf/util/annotate.h
··· 50 50 bool ins__is_call(const struct ins *ins); 51 51 int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); 52 52 53 + struct annotation; 54 + 53 55 struct disasm_line { 54 56 struct list_head node; 55 57 s64 offset; ··· 70 68 struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); 71 69 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 72 70 size_t disasm__fprintf(struct list_head *head, FILE *fp); 71 + double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, 72 + s64 end, const char **path); 73 73 74 74 struct sym_hist { 75 75 u64 sum; 76 76 u64 addr[0]; 77 77 }; 78 78 79 - struct source_line { 80 - struct rb_node node; 79 + struct source_line_percent { 81 80 double percent; 82 81 double percent_sum; 82 + }; 83 + 84 + struct source_line { 85 + struct rb_node node; 83 86 char *path; 87 + int nr_pcnt; 88 + struct source_line_percent p[1]; 84 89 }; 85 90 86 91 /** struct annotated_source - symbols with hits have this attached as in sannotation ··· 139 130 140 131 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 141 132 int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 142 - int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 143 - bool full_paths, int min_pcnt, int max_lines, 144 - int context); 133 + int symbol__annotate_printf(struct symbol *sym, struct map *map, 134 + struct perf_evsel *evsel, bool full_paths, 135 + int min_pcnt, int max_lines, int context); 145 136 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 146 137 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 147 138 void disasm__purge(struct list_head *head); 148 139 149 - int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 150 - bool print_lines, bool full_paths, int min_pcnt, 151 - int max_lines); 140 + int symbol__tty_annotate(struct symbol *sym, struct map *map, 141 + struct perf_evsel *evsel, bool print_lines, 142 + bool full_paths, int min_pcnt, int max_lines); 152 143 153 - #ifdef NEWT_SUPPORT 154 - int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 144 + #ifdef SLANG_SUPPORT 145 + int symbol__tui_annotate(struct symbol *sym, struct map *map, 146 + struct perf_evsel *evsel, 155 147 struct hist_browser_timer *hbt); 156 148 #else 157 149 static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, 158 - struct map *map __maybe_unused, 159 - int evidx __maybe_unused, 160 - struct hist_browser_timer *hbt 161 - __maybe_unused) 150 + struct map *map __maybe_unused, 151 + struct perf_evsel *evsel __maybe_unused, 152 + struct hist_browser_timer *hbt 153 + __maybe_unused) 162 154 { 163 155 return 0; 164 156 } 165 157 #endif 166 158 167 159 #ifdef GTK2_SUPPORT 168 - int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, 160 + int symbol__gtk_annotate(struct symbol *sym, struct map *map, 161 + struct perf_evsel *evsel, 169 162 struct hist_browser_timer *hbt); 170 163 171 - static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, 164 + static inline int hist_entry__gtk_annotate(struct hist_entry *he, 165 + struct perf_evsel *evsel, 172 166 struct hist_browser_timer *hbt) 173 167 { 174 - return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt); 168 + return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt); 175 169 } 176 170 177 171 void perf_gtk__show_annotations(void); 178 172 #else 179 173 static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, 180 - int evidx __maybe_unused, 181 - struct hist_browser_timer *hbt 182 - __maybe_unused) 174 + struct perf_evsel *evsel __maybe_unused, 175 + struct hist_browser_timer *hbt __maybe_unused) 183 176 { 184 177 return 0; 185 178 }
+74 -12
tools/perf/util/cpumap.c
··· 4 4 #include "cpumap.h" 5 5 #include <assert.h> 6 6 #include <stdio.h> 7 + #include <stdlib.h> 7 8 8 9 static struct cpu_map *cpu_map__default_new(void) 9 10 { ··· 220 219 if (!mnt) 221 220 return -1; 222 221 223 - sprintf(path, 222 + snprintf(path, PATH_MAX, 224 223 "%s/devices/system/cpu/cpu%d/topology/physical_package_id", 225 224 mnt, cpu); 226 225 ··· 232 231 return ret == 1 ? cpu : -1; 233 232 } 234 233 235 - int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) 234 + static int cmp_ids(const void *a, const void *b) 236 235 { 237 - struct cpu_map *sock; 236 + return *(int *)a - *(int *)b; 237 + } 238 + 239 + static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, 240 + int (*f)(struct cpu_map *map, int cpu)) 241 + { 242 + struct cpu_map *c; 238 243 int nr = cpus->nr; 239 244 int cpu, s1, s2; 240 245 241 - sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); 242 - if (!sock) 246 + /* allocate as much as possible */ 247 + c = calloc(1, sizeof(*c) + nr * sizeof(int)); 248 + if (!c) 243 249 return -1; 244 250 245 251 for (cpu = 0; cpu < nr; cpu++) { 246 - s1 = cpu_map__get_socket(cpus, cpu); 247 - for (s2 = 0; s2 < sock->nr; s2++) { 248 - if (s1 == sock->map[s2]) 252 + s1 = f(cpus, cpu); 253 + for (s2 = 0; s2 < c->nr; s2++) { 254 + if (s1 == c->map[s2]) 249 255 break; 250 256 } 251 - if (s2 == sock->nr) { 252 - sock->map[sock->nr] = s1; 253 - sock->nr++; 257 + if (s2 == c->nr) { 258 + c->map[c->nr] = s1; 259 + c->nr++; 254 260 } 255 261 } 256 - *sockp = sock; 262 + /* ensure we process id in increasing order */ 263 + qsort(c->map, c->nr, sizeof(int), cmp_ids); 264 + 265 + *res = c; 257 266 return 0; 267 + } 268 + 269 + int cpu_map__get_core(struct cpu_map *map, int idx) 270 + { 271 + FILE *fp; 272 + const char *mnt; 273 + char path[PATH_MAX]; 274 + int cpu, ret, s; 275 + 276 + if (idx > map->nr) 277 + return -1; 278 + 279 + cpu = map->map[idx]; 280 + 281 + mnt = sysfs_find_mountpoint(); 282 + if (!mnt) 283 + return -1; 284 + 285 + snprintf(path, PATH_MAX, 286 + "%s/devices/system/cpu/cpu%d/topology/core_id", 287 + mnt, cpu); 288 + 289 + fp = fopen(path, "r"); 290 + if (!fp) 291 + return -1; 292 + ret = fscanf(fp, "%d", &cpu); 293 + fclose(fp); 294 + if (ret != 1) 295 + return -1; 296 + 297 + s = cpu_map__get_socket(map, idx); 298 + if (s == -1) 299 + return -1; 300 + 301 + /* 302 + * encode socket in upper 16 bits 303 + * core_id is relative to socket, and 304 + * we need a global id. So we combine 305 + * socket+ core id 306 + */ 307 + return (s << 16) | (cpu & 0xffff); 308 + } 309 + 310 + int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) 311 + { 312 + return cpu_map__build_map(cpus, sockp, cpu_map__get_socket); 313 + } 314 + 315 + int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep) 316 + { 317 + return cpu_map__build_map(cpus, corep, cpu_map__get_core); 258 318 }
+12
tools/perf/util/cpumap.h
··· 15 15 struct cpu_map *cpu_map__read(FILE *file); 16 16 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 17 17 int cpu_map__get_socket(struct cpu_map *map, int idx); 18 + int cpu_map__get_core(struct cpu_map *map, int idx); 18 19 int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); 20 + int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); 19 21 20 22 static inline int cpu_map__socket(struct cpu_map *sock, int s) 21 23 { 22 24 if (!sock || s > sock->nr || s < 0) 23 25 return 0; 24 26 return sock->map[s]; 27 + } 28 + 29 + static inline int cpu_map__id_to_socket(int id) 30 + { 31 + return id >> 16; 32 + } 33 + 34 + static inline int cpu_map__id_to_cpu(int id) 35 + { 36 + return id & 0xffff; 25 37 } 26 38 27 39 static inline int cpu_map__nr(const struct cpu_map *map)
+18 -31
tools/perf/util/debugfs.c tools/lib/lk/debugfs.c
··· 1 - #include "util.h" 2 - #include "debugfs.h" 3 - #include "cache.h" 4 - 5 - #include <linux/kernel.h> 1 + #include <errno.h> 2 + #include <stdio.h> 3 + #include <stdlib.h> 4 + #include <string.h> 5 + #include <stdbool.h> 6 + #include <sys/vfs.h> 6 7 #include <sys/mount.h> 8 + #include <linux/magic.h> 9 + #include <linux/kernel.h> 7 10 8 - static int debugfs_premounted; 11 + #include "debugfs.h" 12 + 9 13 char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; 10 - char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; 11 14 12 - static const char *debugfs_known_mountpoints[] = { 15 + static const char * const debugfs_known_mountpoints[] = { 13 16 "/sys/kernel/debug/", 14 17 "/debug/", 15 18 0, 16 19 }; 17 20 18 - static int debugfs_found; 21 + static bool debugfs_found; 19 22 20 23 /* find the path to the mounted debugfs */ 21 24 const char *debugfs_find_mountpoint(void) 22 25 { 23 - const char **ptr; 26 + const char * const *ptr; 24 27 char type[100]; 25 28 FILE *fp; 26 29 27 30 if (debugfs_found) 28 - return (const char *) debugfs_mountpoint; 31 + return (const char *)debugfs_mountpoint; 29 32 30 33 ptr = debugfs_known_mountpoints; 31 34 while (*ptr) { 32 35 if (debugfs_valid_mountpoint(*ptr) == 0) { 33 - debugfs_found = 1; 36 + debugfs_found = true; 34 37 strcpy(debugfs_mountpoint, *ptr); 35 38 return debugfs_mountpoint; 36 39 } ··· 55 52 if (strcmp(type, "debugfs") != 0) 56 53 return NULL; 57 54 58 - debugfs_found = 1; 55 + debugfs_found = true; 59 56 60 57 return debugfs_mountpoint; 61 58 } ··· 74 71 return 0; 75 72 } 76 73 77 - static void debugfs_set_tracing_events_path(const char *mountpoint) 78 - { 79 - snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", 80 - mountpoint, "tracing/events"); 81 - } 82 - 83 74 /* mount the debugfs somewhere if it's not mounted */ 84 - 85 75 char *debugfs_mount(const char *mountpoint) 86 76 { 87 77 /* see if it's already mounted */ 88 - if (debugfs_find_mountpoint()) { 89 - debugfs_premounted = 1; 78 + if (debugfs_find_mountpoint()) 90 79 goto out; 91 - } 92 80 93 81 /* if not mounted and no argument */ 94 82 if (mountpoint == NULL) { ··· 94 100 return NULL; 95 101 96 102 /* save the mountpoint */ 97 - debugfs_found = 1; 103 + debugfs_found = true; 98 104 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 99 105 out: 100 - debugfs_set_tracing_events_path(debugfs_mountpoint); 101 106 return debugfs_mountpoint; 102 - } 103 - 104 - void debugfs_set_path(const char *mountpoint) 105 - { 106 - snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); 107 - debugfs_set_tracing_events_path(mountpoint); 108 107 }
-12
tools/perf/util/debugfs.h
··· 1 - #ifndef __DEBUGFS_H__ 2 - #define __DEBUGFS_H__ 3 - 4 - const char *debugfs_find_mountpoint(void); 5 - int debugfs_valid_mountpoint(const char *debugfs); 6 - char *debugfs_mount(const char *mountpoint); 7 - void debugfs_set_path(const char *mountpoint); 8 - 9 - extern char debugfs_mountpoint[]; 10 - extern char tracing_events_path[]; 11 - 12 - #endif /* __DEBUGFS_H__ */
+9
tools/perf/util/event.h
··· 88 88 u64 id; 89 89 u64 stream_id; 90 90 u64 period; 91 + u64 weight; 91 92 u32 cpu; 92 93 u32 raw_size; 94 + u64 data_src; 93 95 void *raw_data; 94 96 struct ip_callchain *callchain; 95 97 struct branch_stack *branch_stack; 96 98 struct regs_dump user_regs; 97 99 struct stack_dump user_stack; 98 100 }; 101 + 102 + #define PERF_MEM_DATA_SRC_NONE \ 103 + (PERF_MEM_S(OP, NA) |\ 104 + PERF_MEM_S(LVL, NA) |\ 105 + PERF_MEM_S(SNOOP, NA) |\ 106 + PERF_MEM_S(LOCK, NA) |\ 107 + PERF_MEM_S(TLB, NA)) 99 108 100 109 struct build_id_event { 101 110 struct perf_event_header header;
+44 -29
tools/perf/util/evlist.c
··· 7 7 * Released under the GPL v2. (and only v2, not any later version) 8 8 */ 9 9 #include "util.h" 10 - #include "debugfs.h" 10 + #include <lk/debugfs.h> 11 11 #include <poll.h> 12 12 #include "cpumap.h" 13 13 #include "thread_map.h" ··· 38 38 evlist->workload.pid = -1; 39 39 } 40 40 41 - struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 42 - struct thread_map *threads) 41 + struct perf_evlist *perf_evlist__new(void) 43 42 { 44 43 struct perf_evlist *evlist = zalloc(sizeof(*evlist)); 45 44 46 45 if (evlist != NULL) 47 - perf_evlist__init(evlist, cpus, threads); 46 + perf_evlist__init(evlist, NULL, NULL); 48 47 49 48 return evlist; 50 49 } ··· 227 228 { 228 229 int cpu, thread; 229 230 struct perf_evsel *pos; 231 + int nr_cpus = cpu_map__nr(evlist->cpus); 232 + int nr_threads = thread_map__nr(evlist->threads); 230 233 231 - for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 234 + for (cpu = 0; cpu < nr_cpus; cpu++) { 232 235 list_for_each_entry(pos, &evlist->entries, node) { 233 236 if (!perf_evsel__is_group_leader(pos)) 234 237 continue; 235 - for (thread = 0; thread < evlist->threads->nr; thread++) 238 + for (thread = 0; thread < nr_threads; thread++) 236 239 ioctl(FD(pos, cpu, thread), 237 240 PERF_EVENT_IOC_DISABLE, 0); 238 241 } ··· 245 244 { 246 245 int cpu, thread; 247 246 struct perf_evsel *pos; 247 + int nr_cpus = cpu_map__nr(evlist->cpus); 248 + int nr_threads = thread_map__nr(evlist->threads); 248 249 249 - for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 250 + for (cpu = 0; cpu < nr_cpus; cpu++) { 250 251 list_for_each_entry(pos, &evlist->entries, node) { 251 252 if (!perf_evsel__is_group_leader(pos)) 252 253 continue; 253 - for (thread = 0; thread < evlist->threads->nr; thread++) 254 + for (thread = 0; thread < nr_threads; thread++) 254 255 ioctl(FD(pos, cpu, thread), 255 256 PERF_EVENT_IOC_ENABLE, 0); 256 257 } ··· 261 258 262 259 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 263 260 { 264 - int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries; 261 + int nr_cpus = cpu_map__nr(evlist->cpus); 262 + int nr_threads = thread_map__nr(evlist->threads); 263 + int nfds = nr_cpus * nr_threads * evlist->nr_entries; 265 264 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 266 265 return evlist->pollfd != NULL ? 0 : -ENOMEM; 267 266 } ··· 422 417 { 423 418 evlist->nr_mmaps = cpu_map__nr(evlist->cpus); 424 419 if (cpu_map__all(evlist->cpus)) 425 - evlist->nr_mmaps = evlist->threads->nr; 420 + evlist->nr_mmaps = thread_map__nr(evlist->threads); 426 421 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 427 422 return evlist->mmap != NULL ? 0 : -ENOMEM; 428 423 } ··· 447 442 { 448 443 struct perf_evsel *evsel; 449 444 int cpu, thread; 445 + int nr_cpus = cpu_map__nr(evlist->cpus); 446 + int nr_threads = thread_map__nr(evlist->threads); 450 447 451 - for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 448 + for (cpu = 0; cpu < nr_cpus; cpu++) { 452 449 int output = -1; 453 450 454 - for (thread = 0; thread < evlist->threads->nr; thread++) { 451 + for (thread = 0; thread < nr_threads; thread++) { 455 452 list_for_each_entry(evsel, &evlist->entries, node) { 456 453 int fd = FD(evsel, cpu, thread); 457 454 ··· 477 470 return 0; 478 471 479 472 out_unmap: 480 - for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 473 + for (cpu = 0; cpu < nr_cpus; cpu++) { 481 474 if (evlist->mmap[cpu].base != NULL) { 482 475 munmap(evlist->mmap[cpu].base, evlist->mmap_len); 483 476 evlist->mmap[cpu].base = NULL; ··· 490 483 { 491 484 struct perf_evsel *evsel; 492 485 int thread; 486 + int nr_threads = thread_map__nr(evlist->threads); 493 487 494 - for (thread = 0; thread < evlist->threads->nr; thread++) { 488 + for (thread = 0; thread < nr_threads; thread++) { 495 489 int output = -1; 496 490 497 491 list_for_each_entry(evsel, &evlist->entries, node) { ··· 517 509 return 0; 518 510 519 511 out_unmap: 520 - for (thread = 0; thread < evlist->threads->nr; thread++) { 512 + for (thread = 0; thread < nr_threads; thread++) { 521 513 if (evlist->mmap[thread].base != NULL) { 522 514 munmap(evlist->mmap[thread].base, evlist->mmap_len); 523 515 evlist->mmap[thread].base = NULL; ··· 618 610 struct perf_evsel *evsel; 619 611 int err = 0; 620 612 const int ncpus = cpu_map__nr(evlist->cpus), 621 - nthreads = evlist->threads->nr; 613 + nthreads = thread_map__nr(evlist->threads); 622 614 623 615 list_for_each_entry(evsel, &evlist->entries, node) { 624 616 if (evsel->filter == NULL) ··· 637 629 struct perf_evsel *evsel; 638 630 int err = 0; 639 631 const int ncpus = cpu_map__nr(evlist->cpus), 640 - nthreads = evlist->threads->nr; 632 + nthreads = thread_map__nr(evlist->threads); 641 633 642 634 list_for_each_entry(evsel, &evlist->entries, node) { 643 635 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); ··· 720 712 evlist->selected = evsel; 721 713 } 722 714 715 + void perf_evlist__close(struct perf_evlist *evlist) 716 + { 717 + struct perf_evsel *evsel; 718 + int ncpus = cpu_map__nr(evlist->cpus); 719 + int nthreads = thread_map__nr(evlist->threads); 720 + 721 + list_for_each_entry_reverse(evsel, &evlist->entries, node) 722 + perf_evsel__close(evsel, ncpus, nthreads); 723 + } 724 + 723 725 int perf_evlist__open(struct perf_evlist *evlist) 724 726 { 725 727 struct perf_evsel *evsel; 726 - int err, ncpus, nthreads; 728 + int err; 727 729 728 730 list_for_each_entry(evsel, &evlist->entries, node) { 729 731 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); ··· 743 725 744 726 return 0; 745 727 out_err: 746 - ncpus = evlist->cpus ? evlist->cpus->nr : 1; 747 - nthreads = evlist->threads ? evlist->threads->nr : 1; 748 - 749 - list_for_each_entry_reverse(evsel, &evlist->entries, node) 750 - perf_evsel__close(evsel, ncpus, nthreads); 751 - 728 + perf_evlist__close(evlist); 752 729 errno = -err; 753 730 return err; 754 731 } 755 732 756 733 int perf_evlist__prepare_workload(struct perf_evlist *evlist, 757 - struct perf_record_opts *opts, 758 - const char *argv[]) 734 + struct perf_target *target, 735 + const char *argv[], bool pipe_output, 736 + bool want_signal) 759 737 { 760 738 int child_ready_pipe[2], go_pipe[2]; 761 739 char bf; ··· 773 759 } 774 760 775 761 if (!evlist->workload.pid) { 776 - if (opts->pipe_output) 762 + if (pipe_output) 777 763 dup2(2, 1); 778 764 779 765 close(child_ready_pipe[0]); ··· 801 787 execvp(argv[0], (char **)argv); 802 788 803 789 perror(argv[0]); 804 - kill(getppid(), SIGUSR1); 790 + if (want_signal) 791 + kill(getppid(), SIGUSR1); 805 792 exit(-1); 806 793 } 807 794 808 - if (perf_target__none(&opts->target)) 795 + if (perf_target__none(target)) 809 796 evlist->threads->map[0] = evlist->workload.pid; 810 797 811 798 close(child_ready_pipe[1]);
+5 -4
tools/perf/util/evlist.h
··· 49 49 void *handler; 50 50 }; 51 51 52 - struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 53 - struct thread_map *threads); 52 + struct perf_evlist *perf_evlist__new(void); 54 53 void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 55 54 struct thread_map *threads); 56 55 void perf_evlist__exit(struct perf_evlist *evlist); ··· 81 82 union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 82 83 83 84 int perf_evlist__open(struct perf_evlist *evlist); 85 + void perf_evlist__close(struct perf_evlist *evlist); 84 86 85 87 void perf_evlist__config(struct perf_evlist *evlist, 86 88 struct perf_record_opts *opts); 87 89 88 90 int perf_evlist__prepare_workload(struct perf_evlist *evlist, 89 - struct perf_record_opts *opts, 90 - const char *argv[]); 91 + struct perf_target *target, 92 + const char *argv[], bool pipe_output, 93 + bool want_signal); 91 94 int perf_evlist__start_workload(struct perf_evlist *evlist); 92 95 93 96 int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
+28 -4
tools/perf/util/evsel.c
··· 10 10 #include <byteswap.h> 11 11 #include <linux/bitops.h> 12 12 #include "asm/bug.h" 13 - #include "debugfs.h" 13 + #include <lk/debugfs.h> 14 14 #include "event-parse.h" 15 15 #include "evsel.h" 16 16 #include "evlist.h" ··· 554 554 perf_evsel__set_sample_bit(evsel, CPU); 555 555 } 556 556 557 + if (opts->sample_address) 558 + attr->sample_type |= PERF_SAMPLE_DATA_SRC; 559 + 557 560 if (opts->no_delay) { 558 561 attr->watermark = 0; 559 562 attr->wakeup_events = 1; ··· 565 562 perf_evsel__set_sample_bit(evsel, BRANCH_STACK); 566 563 attr->branch_sample_type = opts->branch_stack; 567 564 } 565 + 566 + if (opts->sample_weight) 567 + attr->sample_type |= PERF_SAMPLE_WEIGHT; 568 568 569 569 attr->mmap = track; 570 570 attr->comm = track; ··· 639 633 return 0; 640 634 } 641 635 636 + void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) 637 + { 638 + memset(evsel->counts, 0, (sizeof(*evsel->counts) + 639 + (ncpus * sizeof(struct perf_counts_values)))); 640 + } 641 + 642 642 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 643 643 { 644 644 evsel->counts = zalloc((sizeof(*evsel->counts) + ··· 685 673 void perf_evsel__exit(struct perf_evsel *evsel) 686 674 { 687 675 assert(list_empty(&evsel->node)); 688 - xyarray__delete(evsel->fd); 689 - xyarray__delete(evsel->sample_id); 690 - free(evsel->id); 676 + perf_evsel__free_fd(evsel); 677 + perf_evsel__free_id(evsel); 691 678 } 692 679 693 680 void perf_evsel__delete(struct perf_evsel *evsel) ··· 1023 1012 data->cpu = data->pid = data->tid = -1; 1024 1013 data->stream_id = data->id = data->time = -1ULL; 1025 1014 data->period = 1; 1015 + data->weight = 0; 1026 1016 1027 1017 if (event->header.type != PERF_RECORD_SAMPLE) { 1028 1018 if (!evsel->attr.sample_id_all) ··· 1172 1160 array += size / sizeof(*array); 1173 1161 data->user_stack.size = *array; 1174 1162 } 1163 + } 1164 + 1165 + data->weight = 0; 1166 + if (type & PERF_SAMPLE_WEIGHT) { 1167 + data->weight = *array; 1168 + array++; 1169 + } 1170 + 1171 + data->data_src = PERF_MEM_DATA_SRC_NONE; 1172 + if (type & PERF_SAMPLE_DATA_SRC) { 1173 + data->data_src = *array; 1174 + array++; 1175 1175 } 1176 1176 1177 1177 return 0;
+25
tools/perf/util/evsel.h
··· 9 9 #include "xyarray.h" 10 10 #include "cgroup.h" 11 11 #include "hist.h" 12 + #include "symbol.h" 12 13 13 14 struct perf_counts_values { 14 15 union { ··· 121 120 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 122 121 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 123 122 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 123 + void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); 124 124 void perf_evsel__free_fd(struct perf_evsel *evsel); 125 125 void perf_evsel__free_id(struct perf_evsel *evsel); 126 126 void perf_evsel__free_counts(struct perf_evsel *evsel); ··· 248 246 return list_entry(evsel->node.next, struct perf_evsel, node); 249 247 } 250 248 249 + /** 250 + * perf_evsel__is_group_leader - Return whether given evsel is a leader event 251 + * 252 + * @evsel - evsel selector to be tested 253 + * 254 + * Return %true if @evsel is a group leader or a stand-alone event 255 + */ 251 256 static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) 252 257 { 253 258 return evsel->leader == evsel; 259 + } 260 + 261 + /** 262 + * perf_evsel__is_group_event - Return whether given evsel is a group event 263 + * 264 + * @evsel - evsel selector to be tested 265 + * 266 + * Return %true iff event group view is enabled and @evsel is a actual group 267 + * leader which has other members in the group 268 + */ 269 + static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel) 270 + { 271 + if (!symbol_conf.event_group) 272 + return false; 273 + 274 + return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1; 254 275 } 255 276 256 277 struct perf_attr_details {
+9 -6
tools/perf/util/header.c
··· 1 - #define _FILE_OFFSET_BITS 64 2 - 3 1 #include "util.h" 4 2 #include <sys/types.h> 5 3 #include <byteswap.h> ··· 1670 1672 struct perf_header *ph __maybe_unused, 1671 1673 int fd, void *data) 1672 1674 { 1673 - trace_report(fd, data, false); 1674 - return 0; 1675 + ssize_t ret = trace_report(fd, data, false); 1676 + return ret < 0 ? -1 : 0; 1675 1677 } 1676 1678 1677 1679 static int process_build_id(struct perf_file_section *section, ··· 2750 2752 if (evsel->tp_format) 2751 2753 return 0; 2752 2754 2755 + if (pevent == NULL) { 2756 + pr_debug("broken or missing trace data\n"); 2757 + return -1; 2758 + } 2759 + 2753 2760 event = pevent_find_event(pevent, evsel->attr.config); 2754 2761 if (event == NULL) 2755 2762 return -1; ··· 2792 2789 u64 f_id; 2793 2790 int nr_attrs, nr_ids, i, j; 2794 2791 2795 - session->evlist = perf_evlist__new(NULL, NULL); 2792 + session->evlist = perf_evlist__new(); 2796 2793 if (session->evlist == NULL) 2797 2794 return -ENOMEM; 2798 2795 ··· 2943 2940 struct perf_evlist *evlist = *pevlist; 2944 2941 2945 2942 if (evlist == NULL) { 2946 - *pevlist = evlist = perf_evlist__new(NULL, NULL); 2943 + *pevlist = evlist = perf_evlist__new(); 2947 2944 if (evlist == NULL) 2948 2945 return -ENOMEM; 2949 2946 }
+100 -10
tools/perf/util/hist.c
··· 67 67 void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 68 68 { 69 69 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 70 + int symlen; 70 71 u16 len; 71 72 72 73 if (h->ms.sym) 73 74 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); 74 - else 75 + else { 76 + symlen = unresolved_col_width + 4 + 2; 77 + hists__new_col_len(hists, HISTC_SYMBOL, symlen); 75 78 hists__set_unres_dso_col_len(hists, HISTC_DSO); 79 + } 76 80 77 81 len = thread__comm_len(h->thread); 78 82 if (hists__new_col_len(hists, HISTC_COMM, len)) ··· 91 87 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); 92 88 93 89 if (h->branch_info) { 94 - int symlen; 95 90 /* 96 91 * +4 accounts for '[x] ' priv level info 97 92 * +2 account of 0x prefix on raw addresses ··· 119 116 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); 120 117 } 121 118 } 119 + 120 + if (h->mem_info) { 121 + /* 122 + * +4 accounts for '[x] ' priv level info 123 + * +2 account of 0x prefix on raw addresses 124 + */ 125 + if (h->mem_info->daddr.sym) { 126 + symlen = (int)h->mem_info->daddr.sym->namelen + 4 127 + + unresolved_col_width + 2; 128 + hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 129 + symlen); 130 + } else { 131 + symlen = unresolved_col_width + 4 + 2; 132 + hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 133 + symlen); 134 + } 135 + if (h->mem_info->daddr.map) { 136 + symlen = dso__name_len(h->mem_info->daddr.map->dso); 137 + hists__new_col_len(hists, HISTC_MEM_DADDR_DSO, 138 + symlen); 139 + } else { 140 + symlen = unresolved_col_width + 4 + 2; 141 + hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); 142 + } 143 + } else { 144 + symlen = unresolved_col_width + 4 + 2; 145 + hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen); 146 + hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); 147 + } 148 + 149 + hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); 150 + hists__new_col_len(hists, HISTC_MEM_TLB, 22); 151 + hists__new_col_len(hists, HISTC_MEM_SNOOP, 12); 152 + hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); 153 + hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); 154 + hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); 122 155 } 123 156 124 157 void hists__output_recalc_col_len(struct hists *hists, int max_rows) ··· 194 155 } 195 156 } 196 157 197 - static void he_stat__add_period(struct he_stat *he_stat, u64 period) 158 + static void he_stat__add_period(struct he_stat *he_stat, u64 period, 159 + u64 weight) 198 160 { 161 + 199 162 he_stat->period += period; 163 + he_stat->weight += weight; 200 164 he_stat->nr_events += 1; 201 165 } 202 166 ··· 211 169 dest->period_guest_sys += src->period_guest_sys; 212 170 dest->period_guest_us += src->period_guest_us; 213 171 dest->nr_events += src->nr_events; 172 + dest->weight += src->weight; 214 173 } 215 174 216 175 static void hist_entry__decay(struct hist_entry *he) 217 176 { 218 177 he->stat.period = (he->stat.period * 7) / 8; 219 178 he->stat.nr_events = (he->stat.nr_events * 7) / 8; 179 + /* XXX need decay for weight too? */ 220 180 } 221 181 222 182 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) ··· 283 239 static struct hist_entry *hist_entry__new(struct hist_entry *template) 284 240 { 285 241 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 286 - struct hist_entry *he = malloc(sizeof(*he) + callchain_size); 242 + struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); 287 243 288 244 if (he != NULL) { 289 245 *he = *template; ··· 296 252 he->branch_info->from.map->referenced = true; 297 253 if (he->branch_info->to.map) 298 254 he->branch_info->to.map->referenced = true; 255 + } 256 + 257 + if (he->mem_info) { 258 + if (he->mem_info->iaddr.map) 259 + he->mem_info->iaddr.map->referenced = true; 260 + if (he->mem_info->daddr.map) 261 + he->mem_info->daddr.map->referenced = true; 299 262 } 300 263 301 264 if (symbol_conf.use_callchain) ··· 333 282 static struct hist_entry *add_hist_entry(struct hists *hists, 334 283 struct hist_entry *entry, 335 284 struct addr_location *al, 336 - u64 period) 285 + u64 period, 286 + u64 weight) 337 287 { 338 288 struct rb_node **p; 339 289 struct rb_node *parent = NULL; ··· 358 306 cmp = hist_entry__cmp(he, entry); 359 307 360 308 if (!cmp) { 361 - he_stat__add_period(&he->stat, period); 309 + he_stat__add_period(&he->stat, period, weight); 362 310 363 311 /* If the map of an existing hist_entry has 364 312 * become out-of-date due to an exec() or ··· 393 341 return he; 394 342 } 395 343 344 + struct hist_entry *__hists__add_mem_entry(struct hists *self, 345 + struct addr_location *al, 346 + struct symbol *sym_parent, 347 + struct mem_info *mi, 348 + u64 period, 349 + u64 weight) 350 + { 351 + struct hist_entry entry = { 352 + .thread = al->thread, 353 + .ms = { 354 + .map = al->map, 355 + .sym = al->sym, 356 + }, 357 + .stat = { 358 + .period = period, 359 + .weight = weight, 360 + .nr_events = 1, 361 + }, 362 + .cpu = al->cpu, 363 + .ip = al->addr, 364 + .level = al->level, 365 + .parent = sym_parent, 366 + .filtered = symbol__parent_filter(sym_parent), 367 + .hists = self, 368 + .mem_info = mi, 369 + .branch_info = NULL, 370 + }; 371 + return add_hist_entry(self, &entry, al, period, weight); 372 + } 373 + 396 374 struct hist_entry *__hists__add_branch_entry(struct hists *self, 397 375 struct addr_location *al, 398 376 struct symbol *sym_parent, 399 377 struct branch_info *bi, 400 - u64 period) 378 + u64 period, 379 + u64 weight) 401 380 { 402 381 struct hist_entry entry = { 403 382 .thread = al->thread, ··· 442 359 .stat = { 443 360 .period = period, 444 361 .nr_events = 1, 362 + .weight = weight, 445 363 }, 446 364 .parent = sym_parent, 447 365 .filtered = symbol__parent_filter(sym_parent), 448 366 .branch_info = bi, 449 367 .hists = self, 368 + .mem_info = NULL, 450 369 }; 451 370 452 - return add_hist_entry(self, &entry, al, period); 371 + return add_hist_entry(self, &entry, al, period, weight); 453 372 } 454 373 455 374 struct hist_entry *__hists__add_entry(struct hists *self, 456 375 struct addr_location *al, 457 - struct symbol *sym_parent, u64 period) 376 + struct symbol *sym_parent, u64 period, 377 + u64 weight) 458 378 { 459 379 struct hist_entry entry = { 460 380 .thread = al->thread, ··· 471 385 .stat = { 472 386 .period = period, 473 387 .nr_events = 1, 388 + .weight = weight, 474 389 }, 475 390 .parent = sym_parent, 476 391 .filtered = symbol__parent_filter(sym_parent), 477 392 .hists = self, 393 + .branch_info = NULL, 394 + .mem_info = NULL, 478 395 }; 479 396 480 - return add_hist_entry(self, &entry, al, period); 397 + return add_hist_entry(self, &entry, al, period, weight); 481 398 } 482 399 483 400 int64_t ··· 520 431 void hist_entry__free(struct hist_entry *he) 521 432 { 522 433 free(he->branch_info); 434 + free(he->mem_info); 523 435 free(he); 524 436 } 525 437
+23 -5
tools/perf/util/hist.h
··· 49 49 HISTC_DSO_FROM, 50 50 HISTC_DSO_TO, 51 51 HISTC_SRCLINE, 52 + HISTC_LOCAL_WEIGHT, 53 + HISTC_GLOBAL_WEIGHT, 54 + HISTC_MEM_DADDR_SYMBOL, 55 + HISTC_MEM_DADDR_DSO, 56 + HISTC_MEM_LOCKED, 57 + HISTC_MEM_TLB, 58 + HISTC_MEM_LVL, 59 + HISTC_MEM_SNOOP, 52 60 HISTC_NR_COLS, /* Last entry */ 53 61 }; 54 62 ··· 81 73 82 74 struct hist_entry *__hists__add_entry(struct hists *self, 83 75 struct addr_location *al, 84 - struct symbol *parent, u64 period); 76 + struct symbol *parent, u64 period, 77 + u64 weight); 85 78 int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 86 79 int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 87 80 int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, ··· 93 84 struct addr_location *al, 94 85 struct symbol *sym_parent, 95 86 struct branch_info *bi, 96 - u64 period); 87 + u64 period, 88 + u64 weight); 89 + 90 + struct hist_entry *__hists__add_mem_entry(struct hists *self, 91 + struct addr_location *al, 92 + struct symbol *sym_parent, 93 + struct mem_info *mi, 94 + u64 period, 95 + u64 weight); 97 96 98 97 void hists__output_resort(struct hists *self); 99 98 void hists__output_resort_threaded(struct hists *hists); ··· 192 175 int refresh; 193 176 }; 194 177 195 - #ifdef NEWT_SUPPORT 178 + #ifdef SLANG_SUPPORT 196 179 #include "../ui/keysyms.h" 197 - int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 180 + int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 198 181 struct hist_browser_timer *hbt); 199 182 200 183 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, ··· 213 196 214 197 static inline int hist_entry__tui_annotate(struct hist_entry *self 215 198 __maybe_unused, 216 - int evidx __maybe_unused, 199 + struct perf_evsel *evsel 200 + __maybe_unused, 217 201 struct hist_browser_timer *hbt 218 202 __maybe_unused) 219 203 {
+52 -12
tools/perf/util/machine.c
··· 955 955 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 956 956 struct thread *thread; 957 957 struct map *map; 958 + enum map_type type; 958 959 int ret = 0; 959 960 960 961 if (dump_trace) ··· 972 971 thread = machine__findnew_thread(machine, event->mmap.pid); 973 972 if (thread == NULL) 974 973 goto out_problem; 974 + 975 + if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) 976 + type = MAP__VARIABLE; 977 + else 978 + type = MAP__FUNCTION; 979 + 975 980 map = map__new(&machine->user_dsos, event->mmap.start, 976 981 event->mmap.len, event->mmap.pgoff, 977 982 event->mmap.pid, event->mmap.filename, 978 - MAP__FUNCTION); 983 + type); 984 + 979 985 if (map == NULL) 980 986 goto out_problem; 981 987 ··· 1009 1001 } 1010 1002 1011 1003 return 0; 1004 + } 1005 + 1006 + static void machine__remove_thread(struct machine *machine, struct thread *th) 1007 + { 1008 + machine->last_match = NULL; 1009 + rb_erase(&th->rb_node, &machine->threads); 1010 + /* 1011 + * We may have references to this thread, for instance in some hist_entry 1012 + * instances, so just move them to a separate list. 1013 + */ 1014 + list_add_tail(&th->node, &machine->dead_threads); 1012 1015 } 1013 1016 1014 1017 int machine__process_exit_event(struct machine *machine, union perf_event *event) ··· 1056 1037 } 1057 1038 1058 1039 return ret; 1059 - } 1060 - 1061 - void machine__remove_thread(struct machine *machine, struct thread *th) 1062 - { 1063 - machine->last_match = NULL; 1064 - rb_erase(&th->rb_node, &machine->threads); 1065 - /* 1066 - * We may have references to this thread, for instance in some hist_entry 1067 - * instances, so just move them to a separate list. 1068 - */ 1069 - list_add_tail(&th->node, &machine->dead_threads); 1070 1040 } 1071 1041 1072 1042 static bool symbol__match_parent_regex(struct symbol *sym) ··· 1103 1095 ams->al_addr = al.addr; 1104 1096 ams->sym = al.sym; 1105 1097 ams->map = al.map; 1098 + } 1099 + 1100 + static void ip__resolve_data(struct machine *machine, struct thread *thread, 1101 + u8 m, struct addr_map_symbol *ams, u64 addr) 1102 + { 1103 + struct addr_location al; 1104 + 1105 + memset(&al, 0, sizeof(al)); 1106 + 1107 + thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, 1108 + NULL); 1109 + ams->addr = addr; 1110 + ams->al_addr = al.addr; 1111 + ams->sym = al.sym; 1112 + ams->map = al.map; 1113 + } 1114 + 1115 + struct mem_info *machine__resolve_mem(struct machine *machine, 1116 + struct thread *thr, 1117 + struct perf_sample *sample, 1118 + u8 cpumode) 1119 + { 1120 + struct mem_info *mi = zalloc(sizeof(*mi)); 1121 + 1122 + if (!mi) 1123 + return NULL; 1124 + 1125 + ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip); 1126 + ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr); 1127 + mi->data_src.val = sample->data_src; 1128 + 1129 + return mi; 1106 1130 } 1107 1131 1108 1132 struct branch_info *machine__resolve_bstack(struct machine *machine,
+3 -1
tools/perf/util/machine.h
··· 76 76 struct branch_info *machine__resolve_bstack(struct machine *machine, 77 77 struct thread *thread, 78 78 struct branch_stack *bs); 79 + struct mem_info *machine__resolve_mem(struct machine *machine, 80 + struct thread *thread, 81 + struct perf_sample *sample, u8 cpumode); 79 82 int machine__resolve_callchain(struct machine *machine, 80 83 struct perf_evsel *evsel, 81 84 struct thread *thread, ··· 100 97 } 101 98 102 99 struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 103 - void machine__remove_thread(struct machine *machine, struct thread *th); 104 100 105 101 size_t machine__fprintf(struct machine *machine, FILE *fp); 106 102
+1 -1
tools/perf/util/parse-events.c
··· 10 10 #include "symbol.h" 11 11 #include "cache.h" 12 12 #include "header.h" 13 - #include "debugfs.h" 13 + #include <lk/debugfs.h> 14 14 #include "parse-events-bison.h" 15 15 #define YY_EXTRA_TYPE int 16 16 #include "parse-events-flex.h"
+1 -1
tools/perf/util/probe-event.c
··· 40 40 #include "color.h" 41 41 #include "symbol.h" 42 42 #include "thread.h" 43 - #include "debugfs.h" 43 + #include <lk/debugfs.h> 44 44 #include "trace-event.h" /* For __maybe_unused */ 45 45 #include "probe-event.h" 46 46 #include "probe-finder.h"
-1
tools/perf/util/python-ext-sources
··· 15 15 util/util.c 16 16 util/xyarray.c 17 17 util/cgroup.c 18 - util/debugfs.c 19 18 util/rblist.c 20 19 util/strlist.c 21 20 util/sysfs.c
+6 -14
tools/perf/util/session.c
··· 1 - #define _FILE_OFFSET_BITS 64 2 - 3 1 #include <linux/kernel.h> 4 2 5 3 #include <byteswap.h> ··· 798 800 799 801 if (sample_type & PERF_SAMPLE_STACK_USER) 800 802 stack_user__printf(&sample->user_stack); 803 + 804 + if (sample_type & PERF_SAMPLE_WEIGHT) 805 + printf("... weight: %" PRIu64 "\n", sample->weight); 806 + 807 + if (sample_type & PERF_SAMPLE_DATA_SRC) 808 + printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); 801 809 } 802 810 803 811 static struct machine * ··· 1367 1363 * session, not just the host... 1368 1364 */ 1369 1365 return machine__fprintf(&session->machines.host, fp); 1370 - } 1371 - 1372 - void perf_session__remove_thread(struct perf_session *session, 1373 - struct thread *th) 1374 - { 1375 - /* 1376 - * FIXME: This one makes no sense, we need to remove the thread from 1377 - * the machine it belongs to, perf_session can have many machines, so 1378 - * doing it always on ->machines.host is wrong. Fix when auditing all 1379 - * the 'perf kvm' code. 1380 - */ 1381 - machine__remove_thread(&session->machines.host, th); 1382 1366 } 1383 1367 1384 1368 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
-1
tools/perf/util/session.h
··· 72 72 int perf_session__create_kernel_maps(struct perf_session *self); 73 73 74 74 void perf_session__set_id_hdr_size(struct perf_session *session); 75 - void perf_session__remove_thread(struct perf_session *self, struct thread *th); 76 75 77 76 static inline 78 77 struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
+2 -1
tools/perf/util/setup.py
··· 24 24 build_lib = getenv('PYTHON_EXTBUILD_LIB') 25 25 build_tmp = getenv('PYTHON_EXTBUILD_TMP') 26 26 libtraceevent = getenv('LIBTRACEEVENT') 27 + liblk = getenv('LIBLK') 27 28 28 29 ext_sources = [f.strip() for f in file('util/python-ext-sources') 29 30 if len(f.strip()) > 0 and f[0] != '#'] ··· 33 32 sources = ext_sources, 34 33 include_dirs = ['util/include'], 35 34 extra_compile_args = cflags, 36 - extra_objects = [libtraceevent], 35 + extra_objects = [libtraceevent, liblk], 37 36 ) 38 37 39 38 setup(name='perf',
+408 -6
tools/perf/util/sort.c
··· 198 198 } 199 199 200 200 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 201 - if (sym) 202 - ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 203 - width - ret, 204 - sym->name); 205 - else { 201 + if (sym && map) { 202 + if (map->type == MAP__VARIABLE) { 203 + ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 204 + ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 205 + ip - map->unmap_ip(map, sym->start)); 206 + ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 207 + width - ret, ""); 208 + } else { 209 + ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 210 + width - ret, 211 + sym->name); 212 + } 213 + } else { 206 214 size_t len = BITS_PER_LONG / 4; 207 215 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 208 216 len, ip); ··· 465 457 return repsep_snprintf(bf, size, "%-*s", width, out); 466 458 } 467 459 460 + /* --sort daddr_sym */ 461 + static int64_t 462 + sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) 463 + { 464 + uint64_t l = 0, r = 0; 465 + 466 + if (left->mem_info) 467 + l = left->mem_info->daddr.addr; 468 + if (right->mem_info) 469 + r = right->mem_info->daddr.addr; 470 + 471 + return (int64_t)(r - l); 472 + } 473 + 474 + static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf, 475 + size_t size, unsigned int width) 476 + { 477 + uint64_t addr = 0; 478 + struct map *map = NULL; 479 + struct symbol *sym = NULL; 480 + 481 + if (self->mem_info) { 482 + addr = self->mem_info->daddr.addr; 483 + map = self->mem_info->daddr.map; 484 + sym = self->mem_info->daddr.sym; 485 + } 486 + return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size, 487 + width); 488 + } 489 + 490 + static int64_t 491 + sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) 492 + { 493 + struct map *map_l = NULL; 494 + struct map *map_r = NULL; 495 + 496 + if (left->mem_info) 497 + map_l = left->mem_info->daddr.map; 498 + if (right->mem_info) 499 + map_r = right->mem_info->daddr.map; 500 + 501 + return _sort__dso_cmp(map_l, map_r); 502 + } 503 + 504 + static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf, 505 + size_t size, unsigned int width) 506 + { 507 + struct map *map = NULL; 508 + 509 + if (self->mem_info) 510 + map = self->mem_info->daddr.map; 511 + 512 + return _hist_entry__dso_snprintf(map, bf, size, width); 513 + } 514 + 515 + static int64_t 516 + sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) 517 + { 518 + union perf_mem_data_src data_src_l; 519 + union perf_mem_data_src data_src_r; 520 + 521 + if (left->mem_info) 522 + data_src_l = left->mem_info->data_src; 523 + else 524 + data_src_l.mem_lock = PERF_MEM_LOCK_NA; 525 + 526 + if (right->mem_info) 527 + data_src_r = right->mem_info->data_src; 528 + else 529 + data_src_r.mem_lock = PERF_MEM_LOCK_NA; 530 + 531 + return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); 532 + } 533 + 534 + static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf, 535 + size_t size, unsigned int width) 536 + { 537 + const char *out; 538 + u64 mask = PERF_MEM_LOCK_NA; 539 + 540 + if (self->mem_info) 541 + mask = self->mem_info->data_src.mem_lock; 542 + 543 + if (mask & PERF_MEM_LOCK_NA) 544 + out = "N/A"; 545 + else if (mask & PERF_MEM_LOCK_LOCKED) 546 + out = "Yes"; 547 + else 548 + out = "No"; 549 + 550 + return repsep_snprintf(bf, size, "%-*s", width, out); 551 + } 552 + 553 + static int64_t 554 + sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right) 555 + { 556 + union perf_mem_data_src data_src_l; 557 + union perf_mem_data_src data_src_r; 558 + 559 + if (left->mem_info) 560 + data_src_l = left->mem_info->data_src; 561 + else 562 + data_src_l.mem_dtlb = PERF_MEM_TLB_NA; 563 + 564 + if (right->mem_info) 565 + data_src_r = right->mem_info->data_src; 566 + else 567 + data_src_r.mem_dtlb = PERF_MEM_TLB_NA; 568 + 569 + return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); 570 + } 571 + 572 + static const char * const tlb_access[] = { 573 + "N/A", 574 + "HIT", 575 + "MISS", 576 + "L1", 577 + "L2", 578 + "Walker", 579 + "Fault", 580 + }; 581 + #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) 582 + 583 + static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf, 584 + size_t size, unsigned int width) 585 + { 586 + char out[64]; 587 + size_t sz = sizeof(out) - 1; /* -1 for null termination */ 588 + size_t l = 0, i; 589 + u64 m = PERF_MEM_TLB_NA; 590 + u64 hit, miss; 591 + 592 + out[0] = '\0'; 593 + 594 + if (self->mem_info) 595 + m = self->mem_info->data_src.mem_dtlb; 596 + 597 + hit = m & PERF_MEM_TLB_HIT; 598 + miss = m & PERF_MEM_TLB_MISS; 599 + 600 + /* already taken care of */ 601 + m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); 602 + 603 + for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) { 604 + if (!(m & 0x1)) 605 + continue; 606 + if (l) { 607 + strcat(out, " or "); 608 + l += 4; 609 + } 610 + strncat(out, tlb_access[i], sz - l); 611 + l += strlen(tlb_access[i]); 612 + } 613 + if (*out == '\0') 614 + strcpy(out, "N/A"); 615 + if (hit) 616 + strncat(out, " hit", sz - l); 617 + if (miss) 618 + strncat(out, " miss", sz - l); 619 + 620 + return repsep_snprintf(bf, size, "%-*s", width, out); 621 + } 622 + 623 + static int64_t 624 + sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right) 625 + { 626 + union perf_mem_data_src data_src_l; 627 + union perf_mem_data_src data_src_r; 628 + 629 + if (left->mem_info) 630 + data_src_l = left->mem_info->data_src; 631 + else 632 + data_src_l.mem_lvl = PERF_MEM_LVL_NA; 633 + 634 + if (right->mem_info) 635 + data_src_r = right->mem_info->data_src; 636 + else 637 + data_src_r.mem_lvl = PERF_MEM_LVL_NA; 638 + 639 + return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); 640 + } 641 + 642 + static const char * const mem_lvl[] = { 643 + "N/A", 644 + "HIT", 645 + "MISS", 646 + "L1", 647 + "LFB", 648 + "L2", 649 + "L3", 650 + "Local RAM", 651 + "Remote RAM (1 hop)", 652 + "Remote RAM (2 hops)", 653 + "Remote Cache (1 hop)", 654 + "Remote Cache (2 hops)", 655 + "I/O", 656 + "Uncached", 657 + }; 658 + #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) 659 + 660 + static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf, 661 + size_t size, unsigned int width) 662 + { 663 + char out[64]; 664 + size_t sz = sizeof(out) - 1; /* -1 for null termination */ 665 + size_t i, l = 0; 666 + u64 m = PERF_MEM_LVL_NA; 667 + u64 hit, miss; 668 + 669 + if (self->mem_info) 670 + m = self->mem_info->data_src.mem_lvl; 671 + 672 + out[0] = '\0'; 673 + 674 + hit = m & PERF_MEM_LVL_HIT; 675 + miss = m & PERF_MEM_LVL_MISS; 676 + 677 + /* already taken care of */ 678 + m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); 679 + 680 + for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) { 681 + if (!(m & 0x1)) 682 + continue; 683 + if (l) { 684 + strcat(out, " or "); 685 + l += 4; 686 + } 687 + strncat(out, mem_lvl[i], sz - l); 688 + l += strlen(mem_lvl[i]); 689 + } 690 + if (*out == '\0') 691 + strcpy(out, "N/A"); 692 + if (hit) 693 + strncat(out, " hit", sz - l); 694 + if (miss) 695 + strncat(out, " miss", sz - l); 696 + 697 + return repsep_snprintf(bf, size, "%-*s", width, out); 698 + } 699 + 700 + static int64_t 701 + sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right) 702 + { 703 + union perf_mem_data_src data_src_l; 704 + union perf_mem_data_src data_src_r; 705 + 706 + if (left->mem_info) 707 + data_src_l = left->mem_info->data_src; 708 + else 709 + data_src_l.mem_snoop = PERF_MEM_SNOOP_NA; 710 + 711 + if (right->mem_info) 712 + data_src_r = right->mem_info->data_src; 713 + else 714 + data_src_r.mem_snoop = PERF_MEM_SNOOP_NA; 715 + 716 + return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); 717 + } 718 + 719 + static const char * const snoop_access[] = { 720 + "N/A", 721 + "None", 722 + "Miss", 723 + "Hit", 724 + "HitM", 725 + }; 726 + #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) 727 + 728 + static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf, 729 + size_t size, unsigned int width) 730 + { 731 + char out[64]; 732 + size_t sz = sizeof(out) - 1; /* -1 for null termination */ 733 + size_t i, l = 0; 734 + u64 m = PERF_MEM_SNOOP_NA; 735 + 736 + out[0] = '\0'; 737 + 738 + if (self->mem_info) 739 + m = self->mem_info->data_src.mem_snoop; 740 + 741 + for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { 742 + if (!(m & 0x1)) 743 + continue; 744 + if (l) { 745 + strcat(out, " or "); 746 + l += 4; 747 + } 748 + strncat(out, snoop_access[i], sz - l); 749 + l += strlen(snoop_access[i]); 750 + } 751 + 752 + if (*out == '\0') 753 + strcpy(out, "N/A"); 754 + 755 + return repsep_snprintf(bf, size, "%-*s", width, out); 756 + } 757 + 468 758 struct sort_entry sort_mispredict = { 469 759 .se_header = "Branch Mispredicted", 470 760 .se_cmp = sort__mispredict_cmp, 471 761 .se_snprintf = hist_entry__mispredict_snprintf, 472 762 .se_width_idx = HISTC_MISPREDICT, 763 + }; 764 + 765 + static u64 he_weight(struct hist_entry *he) 766 + { 767 + return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0; 768 + } 769 + 770 + static int64_t 771 + sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right) 772 + { 773 + return he_weight(left) - he_weight(right); 774 + } 775 + 776 + static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf, 777 + size_t size, unsigned int width) 778 + { 779 + return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self)); 780 + } 781 + 782 + struct sort_entry sort_local_weight = { 783 + .se_header = "Local Weight", 784 + .se_cmp = sort__local_weight_cmp, 785 + .se_snprintf = hist_entry__local_weight_snprintf, 786 + .se_width_idx = HISTC_LOCAL_WEIGHT, 787 + }; 788 + 789 + static int64_t 790 + sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right) 791 + { 792 + return left->stat.weight - right->stat.weight; 793 + } 794 + 795 + static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf, 796 + size_t size, unsigned int width) 797 + { 798 + return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight); 799 + } 800 + 801 + struct sort_entry sort_global_weight = { 802 + .se_header = "Weight", 803 + .se_cmp = sort__global_weight_cmp, 804 + .se_snprintf = hist_entry__global_weight_snprintf, 805 + .se_width_idx = HISTC_GLOBAL_WEIGHT, 806 + }; 807 + 808 + struct sort_entry sort_mem_daddr_sym = { 809 + .se_header = "Data Symbol", 810 + .se_cmp = sort__daddr_cmp, 811 + .se_snprintf = hist_entry__daddr_snprintf, 812 + .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 813 + }; 814 + 815 + struct sort_entry sort_mem_daddr_dso = { 816 + .se_header = "Data Object", 817 + .se_cmp = sort__dso_daddr_cmp, 818 + .se_snprintf = hist_entry__dso_daddr_snprintf, 819 + .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 820 + }; 821 + 822 + struct sort_entry sort_mem_locked = { 823 + .se_header = "Locked", 824 + .se_cmp = sort__locked_cmp, 825 + .se_snprintf = hist_entry__locked_snprintf, 826 + .se_width_idx = HISTC_MEM_LOCKED, 827 + }; 828 + 829 + struct sort_entry sort_mem_tlb = { 830 + .se_header = "TLB access", 831 + .se_cmp = sort__tlb_cmp, 832 + .se_snprintf = hist_entry__tlb_snprintf, 833 + .se_width_idx = HISTC_MEM_TLB, 834 + }; 835 + 836 + struct sort_entry sort_mem_lvl = { 837 + .se_header = "Memory access", 838 + .se_cmp = sort__lvl_cmp, 839 + .se_snprintf = hist_entry__lvl_snprintf, 840 + .se_width_idx = HISTC_MEM_LVL, 841 + }; 842 + 843 + struct sort_entry sort_mem_snoop = { 844 + .se_header = "Snoop", 845 + .se_cmp = sort__snoop_cmp, 846 + .se_snprintf = hist_entry__snoop_snprintf, 847 + .se_width_idx = HISTC_MEM_SNOOP, 473 848 }; 474 849 475 850 struct sort_dimension { ··· 871 480 DIM(SORT_PARENT, "parent", sort_parent), 872 481 DIM(SORT_CPU, "cpu", sort_cpu), 873 482 DIM(SORT_SRCLINE, "srcline", sort_srcline), 483 + DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 484 + DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 485 + DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), 486 + DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), 487 + DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), 488 + DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 489 + DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 490 + DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 874 491 }; 875 492 876 493 #undef DIM ··· 915 516 return -EINVAL; 916 517 } 917 518 sort__has_parent = 1; 918 - } else if (sd->entry == &sort_sym) { 519 + } else if (sd->entry == &sort_sym || 520 + sd->entry == &sort_sym_from || 521 + sd->entry == &sort_sym_to || 522 + sd->entry == &sort_mem_daddr_sym) { 919 523 sort__has_sym = 1; 920 524 } 921 525
+11 -1
tools/perf/util/sort.h
··· 49 49 u64 period_us; 50 50 u64 period_guest_sys; 51 51 u64 period_guest_us; 52 + u64 weight; 52 53 u32 nr_events; 53 54 }; 54 55 ··· 101 100 struct rb_root sorted_chain; 102 101 struct branch_info *branch_info; 103 102 struct hists *hists; 104 - struct callchain_root callchain[0]; 103 + struct mem_info *mem_info; 104 + struct callchain_root callchain[0]; /* must be last member */ 105 105 }; 106 106 107 107 static inline bool hist_entry__has_pairs(struct hist_entry *he) ··· 132 130 SORT_PARENT, 133 131 SORT_CPU, 134 132 SORT_SRCLINE, 133 + SORT_LOCAL_WEIGHT, 134 + SORT_GLOBAL_WEIGHT, 135 + SORT_MEM_DADDR_SYMBOL, 136 + SORT_MEM_DADDR_DSO, 137 + SORT_MEM_LOCKED, 138 + SORT_MEM_TLB, 139 + SORT_MEM_LVL, 140 + SORT_MEM_SNOOP, 135 141 136 142 /* branch stack specific sort keys */ 137 143 __SORT_BRANCH_STACK,
+6 -3
tools/perf/util/symbol-elf.c
··· 806 806 * DWARF DW_compile_unit has this, but we don't always have access 807 807 * to it... 808 808 */ 809 - demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 810 - if (demangled != NULL) 811 - elf_name = demangled; 809 + if (symbol_conf.demangle) { 810 + demangled = bfd_demangle(NULL, elf_name, 811 + DMGL_PARAMS | DMGL_ANSI); 812 + if (demangled != NULL) 813 + elf_name = demangled; 814 + } 812 815 new_symbol: 813 816 f = symbol__new(sym.st_value, sym.st_size, 814 817 GELF_ST_BIND(sym.st_info), elf_name);
+1
tools/perf/util/symbol.c
··· 36 36 .use_modules = true, 37 37 .try_vmlinux_path = true, 38 38 .annotate_src = true, 39 + .demangle = true, 39 40 .symfs = "", 40 41 }; 41 42
+8 -1
tools/perf/util/symbol.h
··· 97 97 kptr_restrict, 98 98 annotate_asm_raw, 99 99 annotate_src, 100 - event_group; 100 + event_group, 101 + demangle; 101 102 const char *vmlinux_name, 102 103 *kallsyms_name, 103 104 *source_prefix, ··· 154 153 struct addr_map_symbol from; 155 154 struct addr_map_symbol to; 156 155 struct branch_flags flags; 156 + }; 157 + 158 + struct mem_info { 159 + struct addr_map_symbol iaddr; 160 + struct addr_map_symbol daddr; 161 + union perf_mem_data_src data_src; 157 162 }; 158 163 159 164 struct addr_location {
+5
tools/perf/util/thread_map.h
··· 21 21 22 22 size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); 23 23 24 + static inline int thread_map__nr(struct thread_map *threads) 25 + { 26 + return threads ? threads->nr : 1; 27 + } 28 + 24 29 #endif /* __PERF_THREAD_MAP_H */
+247 -143
tools/perf/util/trace-event-info.c
··· 38 38 39 39 #include "../perf.h" 40 40 #include "trace-event.h" 41 - #include "debugfs.h" 41 + #include <lk/debugfs.h> 42 42 #include "evsel.h" 43 43 44 44 #define VERSION "0.5" 45 45 46 - #define TRACE_CTRL "tracing_on" 47 - #define TRACE "trace" 48 - #define AVAILABLE "available_tracers" 49 - #define CURRENT "current_tracer" 50 - #define ITER_CTRL "trace_options" 51 - #define MAX_LATENCY "tracing_max_latency" 52 - 53 - unsigned int page_size; 54 - 55 - static const char *output_file = "trace.info"; 56 46 static int output_fd; 57 47 58 - struct event_list { 59 - struct event_list *next; 60 - const char *event; 61 - }; 62 - 63 - struct events { 64 - struct events *sibling; 65 - struct events *children; 66 - struct events *next; 67 - char *name; 68 - }; 69 - 70 - 71 - static void *malloc_or_die(unsigned int size) 72 - { 73 - void *data; 74 - 75 - data = malloc(size); 76 - if (!data) 77 - die("malloc"); 78 - return data; 79 - } 80 48 81 49 static const char *find_debugfs(void) 82 50 { 83 - const char *path = debugfs_mount(NULL); 51 + const char *path = perf_debugfs_mount(NULL); 84 52 85 53 if (!path) 86 - die("Your kernel not support debugfs filesystem"); 54 + pr_debug("Your kernel does not support the debugfs filesystem"); 87 55 88 56 return path; 89 57 } ··· 70 102 return tracing; 71 103 72 104 debugfs = find_debugfs(); 105 + if (!debugfs) 106 + return NULL; 73 107 74 - tracing = malloc_or_die(strlen(debugfs) + 9); 108 + tracing = malloc(strlen(debugfs) + 9); 109 + if (!tracing) 110 + return NULL; 75 111 76 112 sprintf(tracing, "%s/tracing", debugfs); 77 113 ··· 92 120 if (!tracing) 93 121 return NULL; 94 122 95 - file = malloc_or_die(strlen(tracing) + strlen(name) + 2); 123 + file = malloc(strlen(tracing) + strlen(name) + 2); 124 + if (!file) 125 + return NULL; 96 126 97 127 sprintf(file, "%s/%s", tracing, name); 98 128 return file; ··· 103 129 static void put_tracing_file(char *file) 104 130 { 105 131 free(file); 106 - } 107 - 108 - static ssize_t calc_data_size; 109 - 110 - static ssize_t write_or_die(const void *buf, size_t len) 111 - { 112 - int ret; 113 - 114 - if (calc_data_size) { 115 - calc_data_size += len; 116 - return len; 117 - } 118 - 119 - ret = write(output_fd, buf, len); 120 - if (ret < 0) 121 - die("writing to '%s'", output_file); 122 - 123 - return ret; 124 132 } 125 133 126 134 int bigendian(void) ··· 115 159 } 116 160 117 161 /* unfortunately, you can not stat debugfs or proc files for size */ 118 - static void record_file(const char *file, size_t hdr_sz) 162 + static int record_file(const char *file, ssize_t hdr_sz) 119 163 { 120 164 unsigned long long size = 0; 121 165 char buf[BUFSIZ], *sizep; 122 166 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); 123 167 int r, fd; 168 + int err = -EIO; 124 169 125 170 fd = open(file, O_RDONLY); 126 - if (fd < 0) 127 - die("Can't read '%s'", file); 171 + if (fd < 0) { 172 + pr_debug("Can't read '%s'", file); 173 + return -errno; 174 + } 128 175 129 176 /* put in zeros for file size, then fill true size later */ 130 - if (hdr_sz) 131 - write_or_die(&size, hdr_sz); 177 + if (hdr_sz) { 178 + if (write(output_fd, &size, hdr_sz) != hdr_sz) 179 + goto out; 180 + } 132 181 133 182 do { 134 183 r = read(fd, buf, BUFSIZ); 135 184 if (r > 0) { 136 185 size += r; 137 - write_or_die(buf, r); 186 + if (write(output_fd, buf, r) != r) 187 + goto out; 138 188 } 139 189 } while (r > 0); 140 - close(fd); 141 190 142 191 /* ugh, handle big-endian hdr_size == 4 */ 143 192 sizep = (char*)&size; 144 193 if (bigendian()) 145 194 sizep += sizeof(u64) - hdr_sz; 146 195 147 - if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) 148 - die("writing to %s", output_file); 196 + if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) { 197 + pr_debug("writing file size failed\n"); 198 + goto out; 199 + } 200 + 201 + err = 0; 202 + out: 203 + close(fd); 204 + return err; 149 205 } 150 206 151 - static void read_header_files(void) 207 + static int read_header_files(void) 152 208 { 153 209 char *path; 154 210 struct stat st; 211 + int err = -EIO; 155 212 156 213 path = get_tracing_file("events/header_page"); 157 - if (stat(path, &st) < 0) 158 - die("can't read '%s'", path); 214 + if (!path) { 215 + pr_debug("can't get tracing/events/header_page"); 216 + return -ENOMEM; 217 + } 159 218 160 - write_or_die("header_page", 12); 161 - record_file(path, 8); 219 + if (stat(path, &st) < 0) { 220 + pr_debug("can't read '%s'", path); 221 + goto out; 222 + } 223 + 224 + if (write(output_fd, "header_page", 12) != 12) { 225 + pr_debug("can't write header_page\n"); 226 + goto out; 227 + } 228 + 229 + if (record_file(path, 8) < 0) { 230 + pr_debug("can't record header_page file\n"); 231 + goto out; 232 + } 233 + 162 234 put_tracing_file(path); 163 235 164 236 path = get_tracing_file("events/header_event"); 165 - if (stat(path, &st) < 0) 166 - die("can't read '%s'", path); 237 + if (!path) { 238 + pr_debug("can't get tracing/events/header_event"); 239 + err = -ENOMEM; 240 + goto out; 241 + } 167 242 168 - write_or_die("header_event", 13); 169 - record_file(path, 8); 243 + if (stat(path, &st) < 0) { 244 + pr_debug("can't read '%s'", path); 245 + goto out; 246 + } 247 + 248 + if (write(output_fd, "header_event", 13) != 13) { 249 + pr_debug("can't write header_event\n"); 250 + goto out; 251 + } 252 + 253 + if (record_file(path, 8) < 0) { 254 + pr_debug("can't record header_event file\n"); 255 + goto out; 256 + } 257 + 258 + err = 0; 259 + out: 170 260 put_tracing_file(path); 261 + return err; 171 262 } 172 263 173 264 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) ··· 228 225 return false; 229 226 } 230 227 231 - static void copy_event_system(const char *sys, struct tracepoint_path *tps) 228 + static int copy_event_system(const char *sys, struct tracepoint_path *tps) 232 229 { 233 230 struct dirent *dent; 234 231 struct stat st; ··· 236 233 DIR *dir; 237 234 int count = 0; 238 235 int ret; 236 + int err; 239 237 240 238 dir = opendir(sys); 241 - if (!dir) 242 - die("can't read directory '%s'", sys); 239 + if (!dir) { 240 + pr_debug("can't read directory '%s'", sys); 241 + return -errno; 242 + } 243 243 244 244 while ((dent = readdir(dir))) { 245 245 if (dent->d_type != DT_DIR || ··· 250 244 strcmp(dent->d_name, "..") == 0 || 251 245 !name_in_tp_list(dent->d_name, tps)) 252 246 continue; 253 - format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 247 + format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 248 + if (!format) { 249 + err = -ENOMEM; 250 + goto out; 251 + } 254 252 sprintf(format, "%s/%s/format", sys, dent->d_name); 255 253 ret = stat(format, &st); 256 254 free(format); ··· 263 253 count++; 264 254 } 265 255 266 - write_or_die(&count, 4); 256 + if (write(output_fd, &count, 4) != 4) { 257 + err = -EIO; 258 + pr_debug("can't write count\n"); 259 + goto out; 260 + } 267 261 268 262 rewinddir(dir); 269 263 while ((dent = readdir(dir))) { ··· 276 262 strcmp(dent->d_name, "..") == 0 || 277 263 !name_in_tp_list(dent->d_name, tps)) 278 264 continue; 279 - format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 265 + format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 266 + if (!format) { 267 + err = -ENOMEM; 268 + goto out; 269 + } 280 270 sprintf(format, "%s/%s/format", sys, dent->d_name); 281 271 ret = stat(format, &st); 282 272 283 - if (ret >= 0) 284 - record_file(format, 8); 285 - 273 + if (ret >= 0) { 274 + err = record_file(format, 8); 275 + if (err) { 276 + free(format); 277 + goto out; 278 + } 279 + } 286 280 free(format); 287 281 } 282 + err = 0; 283 + out: 288 284 closedir(dir); 285 + return err; 289 286 } 290 287 291 - static void read_ftrace_files(struct tracepoint_path *tps) 288 + static int read_ftrace_files(struct tracepoint_path *tps) 292 289 { 293 290 char *path; 291 + int ret; 294 292 295 293 path = get_tracing_file("events/ftrace"); 294 + if (!path) { 295 + pr_debug("can't get tracing/events/ftrace"); 296 + return -ENOMEM; 297 + } 296 298 297 - copy_event_system(path, tps); 299 + ret = copy_event_system(path, tps); 298 300 299 301 put_tracing_file(path); 302 + 303 + return ret; 300 304 } 301 305 302 306 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) ··· 328 296 return false; 329 297 } 330 298 331 - static void read_event_files(struct tracepoint_path *tps) 299 + static int read_event_files(struct tracepoint_path *tps) 332 300 { 333 301 struct dirent *dent; 334 302 struct stat st; ··· 337 305 DIR *dir; 338 306 int count = 0; 339 307 int ret; 308 + int err; 340 309 341 310 path = get_tracing_file("events"); 311 + if (!path) { 312 + pr_debug("can't get tracing/events"); 313 + return -ENOMEM; 314 + } 342 315 343 316 dir = opendir(path); 344 - if (!dir) 345 - die("can't read directory '%s'", path); 317 + if (!dir) { 318 + err = -errno; 319 + pr_debug("can't read directory '%s'", path); 320 + goto out; 321 + } 346 322 347 323 while ((dent = readdir(dir))) { 348 324 if (dent->d_type != DT_DIR || ··· 362 322 count++; 363 323 } 364 324 365 - write_or_die(&count, 4); 325 + if (write(output_fd, &count, 4) != 4) { 326 + err = -EIO; 327 + pr_debug("can't write count\n"); 328 + goto out; 329 + } 366 330 367 331 rewinddir(dir); 368 332 while ((dent = readdir(dir))) { ··· 376 332 strcmp(dent->d_name, "ftrace") == 0 || 377 333 !system_in_tp_list(dent->d_name, tps)) 378 334 continue; 379 - sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 335 + sys = malloc(strlen(path) + strlen(dent->d_name) + 2); 336 + if (!sys) { 337 + err = -ENOMEM; 338 + goto out; 339 + } 380 340 sprintf(sys, "%s/%s", path, dent->d_name); 381 341 ret = stat(sys, &st); 382 342 if (ret >= 0) { 383 - write_or_die(dent->d_name, strlen(dent->d_name) + 1); 384 - copy_event_system(sys, tps); 343 + ssize_t size = strlen(dent->d_name) + 1; 344 + 345 + if (write(output_fd, dent->d_name, size) != size || 346 + copy_event_system(sys, tps) < 0) { 347 + err = -EIO; 348 + free(sys); 349 + goto out; 350 + } 385 351 } 386 352 free(sys); 387 353 } 388 - 354 + err = 0; 355 + out: 389 356 closedir(dir); 390 357 put_tracing_file(path); 358 + 359 + return err; 391 360 } 392 361 393 - static void read_proc_kallsyms(void) 362 + static int read_proc_kallsyms(void) 394 363 { 395 364 unsigned int size; 396 365 const char *path = "/proc/kallsyms"; 397 366 struct stat st; 398 - int ret; 367 + int ret, err = 0; 399 368 400 369 ret = stat(path, &st); 401 370 if (ret < 0) { 402 371 /* not found */ 403 372 size = 0; 404 - write_or_die(&size, 4); 405 - return; 373 + if (write(output_fd, &size, 4) != 4) 374 + err = -EIO; 375 + return err; 406 376 } 407 - record_file(path, 4); 377 + return record_file(path, 4); 408 378 } 409 379 410 - static void read_ftrace_printk(void) 380 + static int read_ftrace_printk(void) 411 381 { 412 382 unsigned int size; 413 383 char *path; 414 384 struct stat st; 415 - int ret; 385 + int ret, err = 0; 416 386 417 387 path = get_tracing_file("printk_formats"); 388 + if (!path) { 389 + pr_debug("can't get tracing/printk_formats"); 390 + return -ENOMEM; 391 + } 392 + 418 393 ret = stat(path, &st); 419 394 if (ret < 0) { 420 395 /* not found */ 421 396 size = 0; 422 - write_or_die(&size, 4); 397 + if (write(output_fd, &size, 4) != 4) 398 + err = -EIO; 423 399 goto out; 424 400 } 425 - record_file(path, 4); 401 + err = record_file(path, 4); 426 402 427 403 out: 428 404 put_tracing_file(path); 429 - } 430 - 431 - static struct tracepoint_path * 432 - get_tracepoints_path(struct list_head *pattrs) 433 - { 434 - struct tracepoint_path path, *ppath = &path; 435 - struct perf_evsel *pos; 436 - int nr_tracepoints = 0; 437 - 438 - list_for_each_entry(pos, pattrs, node) { 439 - if (pos->attr.type != PERF_TYPE_TRACEPOINT) 440 - continue; 441 - ++nr_tracepoints; 442 - ppath->next = tracepoint_id_to_path(pos->attr.config); 443 - if (!ppath->next) 444 - die("%s\n", "No memory to alloc tracepoints list"); 445 - ppath = ppath->next; 446 - } 447 - 448 - return nr_tracepoints > 0 ? path.next : NULL; 405 + return err; 449 406 } 450 407 451 408 static void ··· 462 417 } 463 418 } 464 419 420 + static struct tracepoint_path * 421 + get_tracepoints_path(struct list_head *pattrs) 422 + { 423 + struct tracepoint_path path, *ppath = &path; 424 + struct perf_evsel *pos; 425 + int nr_tracepoints = 0; 426 + 427 + list_for_each_entry(pos, pattrs, node) { 428 + if (pos->attr.type != PERF_TYPE_TRACEPOINT) 429 + continue; 430 + ++nr_tracepoints; 431 + ppath->next = tracepoint_id_to_path(pos->attr.config); 432 + if (!ppath->next) { 433 + pr_debug("No memory to alloc tracepoints list\n"); 434 + put_tracepoints_path(&path); 435 + return NULL; 436 + } 437 + ppath = ppath->next; 438 + } 439 + 440 + return nr_tracepoints > 0 ? path.next : NULL; 441 + } 442 + 465 443 bool have_tracepoints(struct list_head *pattrs) 466 444 { 467 445 struct perf_evsel *pos; ··· 496 428 return false; 497 429 } 498 430 499 - static void tracing_data_header(void) 431 + static int tracing_data_header(void) 500 432 { 501 433 char buf[20]; 434 + ssize_t size; 502 435 503 436 /* just guessing this is someone's birthday.. ;) */ 504 437 buf[0] = 23; ··· 507 438 buf[2] = 68; 508 439 memcpy(buf + 3, "tracing", 7); 509 440 510 - write_or_die(buf, 10); 441 + if (write(output_fd, buf, 10) != 10) 442 + return -1; 511 443 512 - write_or_die(VERSION, strlen(VERSION) + 1); 444 + size = strlen(VERSION) + 1; 445 + if (write(output_fd, VERSION, size) != size) 446 + return -1; 513 447 514 448 /* save endian */ 515 449 if (bigendian()) ··· 522 450 523 451 read_trace_init(buf[0], buf[0]); 524 452 525 - write_or_die(buf, 1); 453 + if (write(output_fd, buf, 1) != 1) 454 + return -1; 526 455 527 456 /* save size of long */ 528 457 buf[0] = sizeof(long); 529 - write_or_die(buf, 1); 458 + if (write(output_fd, buf, 1) != 1) 459 + return -1; 530 460 531 461 /* save page_size */ 532 - page_size = sysconf(_SC_PAGESIZE); 533 - write_or_die(&page_size, 4); 462 + if (write(output_fd, &page_size, 4) != 4) 463 + return -1; 464 + 465 + return 0; 534 466 } 535 467 536 468 struct tracing_data *tracing_data_get(struct list_head *pattrs, ··· 542 466 { 543 467 struct tracepoint_path *tps; 544 468 struct tracing_data *tdata; 469 + int err; 545 470 546 471 output_fd = fd; 547 472 ··· 550 473 if (!tps) 551 474 return NULL; 552 475 553 - tdata = malloc_or_die(sizeof(*tdata)); 476 + tdata = malloc(sizeof(*tdata)); 477 + if (!tdata) 478 + return NULL; 479 + 554 480 tdata->temp = temp; 555 481 tdata->size = 0; 556 482 ··· 562 482 563 483 snprintf(tdata->temp_file, sizeof(tdata->temp_file), 564 484 "/tmp/perf-XXXXXX"); 565 - if (!mkstemp(tdata->temp_file)) 566 - die("Can't make temp file"); 485 + if (!mkstemp(tdata->temp_file)) { 486 + pr_debug("Can't make temp file"); 487 + return NULL; 488 + } 567 489 568 490 temp_fd = open(tdata->temp_file, O_RDWR); 569 - if (temp_fd < 0) 570 - die("Can't read '%s'", tdata->temp_file); 491 + if (temp_fd < 0) { 492 + pr_debug("Can't read '%s'", tdata->temp_file); 493 + return NULL; 494 + } 571 495 572 496 /* 573 497 * Set the temp file the default output, so all the ··· 580 496 output_fd = temp_fd; 581 497 } 582 498 583 - tracing_data_header(); 584 - read_header_files(); 585 - read_ftrace_files(tps); 586 - read_event_files(tps); 587 - read_proc_kallsyms(); 588 - read_ftrace_printk(); 499 + err = tracing_data_header(); 500 + if (err) 501 + goto out; 502 + err = read_header_files(); 503 + if (err) 504 + goto out; 505 + err = read_ftrace_files(tps); 506 + if (err) 507 + goto out; 508 + err = read_event_files(tps); 509 + if (err) 510 + goto out; 511 + err = read_proc_kallsyms(); 512 + if (err) 513 + goto out; 514 + err = read_ftrace_printk(); 589 515 516 + out: 590 517 /* 591 518 * All tracing data are stored by now, we can restore 592 519 * the default output file in case we used temp file. ··· 608 513 output_fd = fd; 609 514 } 610 515 516 + if (err) { 517 + free(tdata); 518 + tdata = NULL; 519 + } 520 + 611 521 put_tracepoints_path(tps); 612 522 return tdata; 613 523 } 614 524 615 - void tracing_data_put(struct tracing_data *tdata) 525 + int tracing_data_put(struct tracing_data *tdata) 616 526 { 527 + int err = 0; 528 + 617 529 if (tdata->temp) { 618 - record_file(tdata->temp_file, 0); 530 + err = record_file(tdata->temp_file, 0); 619 531 unlink(tdata->temp_file); 620 532 } 621 533 622 534 free(tdata); 535 + return err; 623 536 } 624 537 625 538 int read_tracing_data(int fd, struct list_head *pattrs) 626 539 { 540 + int err; 627 541 struct tracing_data *tdata; 628 542 629 543 /* ··· 643 539 if (!tdata) 644 540 return -ENOMEM; 645 541 646 - tracing_data_put(tdata); 647 - return 0; 542 + err = tracing_data_put(tdata); 543 + return err; 648 544 }
-37
tools/perf/util/trace-event-parse.c
··· 183 183 trace_seq_do_printf(&s); 184 184 } 185 185 186 - void print_trace_event(struct pevent *pevent, int cpu, void *data, int size) 187 - { 188 - int type = trace_parse_common_type(pevent, data); 189 - struct event_format *event = pevent_find_event(pevent, type); 190 - 191 - if (!event) { 192 - warning("ug! no event found for type %d", type); 193 - return; 194 - } 195 - 196 - event_format__print(event, cpu, data, size); 197 - } 198 - 199 - void print_event(struct pevent *pevent, int cpu, void *data, int size, 200 - unsigned long long nsecs, char *comm) 201 - { 202 - struct pevent_record record; 203 - struct trace_seq s; 204 - int pid; 205 - 206 - pevent->latency_format = latency_format; 207 - 208 - record.ts = nsecs; 209 - record.cpu = cpu; 210 - record.size = size; 211 - record.data = data; 212 - pid = pevent_data_pid(pevent, &record); 213 - 214 - if (!pevent_pid_is_registered(pevent, pid)) 215 - pevent_register_comm(pevent, comm, pid); 216 - 217 - trace_seq_init(&s); 218 - pevent_print_event(pevent, &s, &record); 219 - trace_seq_do_printf(&s); 220 - printf("\n"); 221 - } 222 - 223 186 void parse_proc_kallsyms(struct pevent *pevent, 224 187 char *file, unsigned int size __maybe_unused) 225 188 {
+175 -294
tools/perf/util/trace-event-read.c
··· 18 18 * 19 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 20 */ 21 - #define _FILE_OFFSET_BITS 64 22 - 23 21 #include <dirent.h> 24 22 #include <stdio.h> 25 23 #include <stdlib.h> ··· 39 41 40 42 static int input_fd; 41 43 42 - static int read_page; 43 - 44 44 int file_bigendian; 45 45 int host_bigendian; 46 46 static int long_size; 47 47 48 - static ssize_t calc_data_size; 48 + static ssize_t trace_data_size; 49 49 static bool repipe; 50 50 51 - static void *malloc_or_die(int size) 52 - { 53 - void *ret; 54 - 55 - ret = malloc(size); 56 - if (!ret) 57 - die("malloc"); 58 - return ret; 59 - } 60 - 61 - static int do_read(int fd, void *buf, int size) 51 + static int __do_read(int fd, void *buf, int size) 62 52 { 63 53 int rsize = size; 64 54 ··· 59 73 if (repipe) { 60 74 int retw = write(STDOUT_FILENO, buf, ret); 61 75 62 - if (retw <= 0 || retw != ret) 63 - die("repiping input file"); 76 + if (retw <= 0 || retw != ret) { 77 + pr_debug("repiping input file"); 78 + return -1; 79 + } 64 80 } 65 81 66 82 size -= ret; ··· 72 84 return rsize; 73 85 } 74 86 75 - static int read_or_die(void *data, int size) 87 + static int do_read(void *data, int size) 76 88 { 77 89 int r; 78 90 79 - r = do_read(input_fd, data, size); 80 - if (r <= 0) 81 - die("reading input file (size expected=%d received=%d)", 82 - size, r); 91 + r = __do_read(input_fd, data, size); 92 + if (r <= 0) { 93 + pr_debug("reading input file (size expected=%d received=%d)", 94 + size, r); 95 + return -1; 96 + } 83 97 84 - if (calc_data_size) 85 - calc_data_size += r; 98 + trace_data_size += r; 86 99 87 100 return r; 88 101 } ··· 96 107 97 108 while (size) { 98 109 r = size > BUFSIZ ? BUFSIZ : size; 99 - read_or_die(buf, r); 110 + do_read(buf, r); 100 111 size -= r; 101 112 }; 102 113 } ··· 105 116 { 106 117 unsigned int data; 107 118 108 - read_or_die(&data, 4); 119 + if (do_read(&data, 4) < 0) 120 + return 0; 109 121 return __data2host4(pevent, data); 110 122 } 111 123 ··· 114 124 { 115 125 unsigned long long data; 116 126 117 - read_or_die(&data, 8); 127 + if (do_read(&data, 8) < 0) 128 + return 0; 118 129 return __data2host8(pevent, data); 119 130 } 120 131 ··· 129 138 130 139 for (;;) { 131 140 r = read(input_fd, &c, 1); 132 - if (r < 0) 133 - die("reading input file"); 141 + if (r < 0) { 142 + pr_debug("reading input file"); 143 + goto out; 144 + } 134 145 135 - if (!r) 136 - die("no data"); 146 + if (!r) { 147 + pr_debug("no data"); 148 + goto out; 149 + } 137 150 138 151 if (repipe) { 139 152 int retw = write(STDOUT_FILENO, &c, 1); 140 153 141 - if (retw <= 0 || retw != r) 142 - die("repiping input file string"); 154 + if (retw <= 0 || retw != r) { 155 + pr_debug("repiping input file string"); 156 + goto out; 157 + } 143 158 } 144 159 145 160 buf[size++] = c; ··· 154 157 break; 155 158 } 156 159 157 - if (calc_data_size) 158 - calc_data_size += size; 160 + trace_data_size += size; 159 161 160 - str = malloc_or_die(size); 161 - memcpy(str, buf, size); 162 - 162 + str = malloc(size); 163 + if (str) 164 + memcpy(str, buf, size); 165 + out: 163 166 return str; 164 167 } 165 168 166 - static void read_proc_kallsyms(struct pevent *pevent) 169 + static int read_proc_kallsyms(struct pevent *pevent) 167 170 { 168 171 unsigned int size; 169 172 char *buf; 170 173 171 174 size = read4(pevent); 172 175 if (!size) 173 - return; 176 + return 0; 174 177 175 - buf = malloc_or_die(size + 1); 176 - read_or_die(buf, size); 178 + buf = malloc(size + 1); 179 + if (buf == NULL) 180 + return -1; 181 + 182 + if (do_read(buf, size) < 0) { 183 + free(buf); 184 + return -1; 185 + } 177 186 buf[size] = '\0'; 178 187 179 188 parse_proc_kallsyms(pevent, buf, size); 180 189 181 190 free(buf); 191 + return 0; 182 192 } 183 193 184 - static void read_ftrace_printk(struct pevent *pevent) 194 + static int read_ftrace_printk(struct pevent *pevent) 185 195 { 186 196 unsigned int size; 187 197 char *buf; 188 198 199 + /* it can have 0 size */ 189 200 size = read4(pevent); 190 201 if (!size) 191 - return; 202 + return 0; 192 203 193 - buf = malloc_or_die(size); 194 - read_or_die(buf, size); 204 + buf = malloc(size); 205 + if (buf == NULL) 206 + return -1; 207 + 208 + if (do_read(buf, size) < 0) { 209 + free(buf); 210 + return -1; 211 + } 195 212 196 213 parse_ftrace_printk(pevent, buf, size); 197 214 198 215 free(buf); 216 + return 0; 199 217 } 200 218 201 - static void read_header_files(struct pevent *pevent) 219 + static int read_header_files(struct pevent *pevent) 202 220 { 203 221 unsigned long long size; 204 222 char *header_event; 205 223 char buf[BUFSIZ]; 224 + int ret = 0; 206 225 207 - read_or_die(buf, 12); 226 + if (do_read(buf, 12) < 0) 227 + return -1; 208 228 209 - if (memcmp(buf, "header_page", 12) != 0) 210 - die("did not read header page"); 229 + if (memcmp(buf, "header_page", 12) != 0) { 230 + pr_debug("did not read header page"); 231 + return -1; 232 + } 211 233 212 234 size = read8(pevent); 213 235 skip(size); ··· 237 221 */ 238 222 long_size = header_page_size_size; 239 223 240 - read_or_die(buf, 13); 241 - if (memcmp(buf, "header_event", 13) != 0) 242 - die("did not read header event"); 224 + if (do_read(buf, 13) < 0) 225 + return -1; 226 + 227 + if (memcmp(buf, "header_event", 13) != 0) { 228 + pr_debug("did not read header event"); 229 + return -1; 230 + } 243 231 244 232 size = read8(pevent); 245 - header_event = malloc_or_die(size); 246 - read_or_die(header_event, size); 233 + header_event = malloc(size); 234 + if (header_event == NULL) 235 + return -1; 236 + 237 + if (do_read(header_event, size) < 0) 238 + ret = -1; 239 + 247 240 free(header_event); 241 + return ret; 248 242 } 249 243 250 - static void read_ftrace_file(struct pevent *pevent, unsigned long long size) 244 + static int read_ftrace_file(struct pevent *pevent, unsigned long long size) 251 245 { 252 246 char *buf; 253 247 254 - buf = malloc_or_die(size); 255 - read_or_die(buf, size); 248 + buf = malloc(size); 249 + if (buf == NULL) 250 + return -1; 251 + 252 + if (do_read(buf, size) < 0) { 253 + free(buf); 254 + return -1; 255 + } 256 + 256 257 parse_ftrace_file(pevent, buf, size); 257 258 free(buf); 259 + return 0; 258 260 } 259 261 260 - static void read_event_file(struct pevent *pevent, char *sys, 262 + static int read_event_file(struct pevent *pevent, char *sys, 261 263 unsigned long long size) 262 264 { 263 265 char *buf; 264 266 265 - buf = malloc_or_die(size); 266 - read_or_die(buf, size); 267 + buf = malloc(size); 268 + if (buf == NULL) 269 + return -1; 270 + 271 + if (do_read(buf, size) < 0) { 272 + free(buf); 273 + return -1; 274 + } 275 + 267 276 parse_event_file(pevent, buf, size, sys); 268 277 free(buf); 278 + return 0; 269 279 } 270 280 271 - static void read_ftrace_files(struct pevent *pevent) 281 + static int read_ftrace_files(struct pevent *pevent) 272 282 { 273 283 unsigned long long size; 274 284 int count; 275 285 int i; 286 + int ret; 276 287 277 288 count = read4(pevent); 278 289 279 290 for (i = 0; i < count; i++) { 280 291 size = read8(pevent); 281 - read_ftrace_file(pevent, size); 292 + ret = read_ftrace_file(pevent, size); 293 + if (ret) 294 + return ret; 282 295 } 296 + return 0; 283 297 } 284 298 285 - static void read_event_files(struct pevent *pevent) 299 + static int read_event_files(struct pevent *pevent) 286 300 { 287 301 unsigned long long size; 288 302 char *sys; 289 303 int systems; 290 304 int count; 291 305 int i,x; 306 + int ret; 292 307 293 308 systems = read4(pevent); 294 309 295 310 for (i = 0; i < systems; i++) { 296 311 sys = read_string(); 312 + if (sys == NULL) 313 + return -1; 297 314 298 315 count = read4(pevent); 316 + 299 317 for (x=0; x < count; x++) { 300 318 size = read8(pevent); 301 - read_event_file(pevent, sys, size); 319 + ret = read_event_file(pevent, sys, size); 320 + if (ret) 321 + return ret; 302 322 } 303 323 } 304 - } 305 - 306 - struct cpu_data { 307 - unsigned long long offset; 308 - unsigned long long size; 309 - unsigned long long timestamp; 310 - struct pevent_record *next; 311 - char *page; 312 - int cpu; 313 - int index; 314 - int page_size; 315 - }; 316 - 317 - static struct cpu_data *cpu_data; 318 - 319 - static void update_cpu_data_index(int cpu) 320 - { 321 - cpu_data[cpu].offset += page_size; 322 - cpu_data[cpu].size -= page_size; 323 - cpu_data[cpu].index = 0; 324 - } 325 - 326 - static void get_next_page(int cpu) 327 - { 328 - off_t save_seek; 329 - off_t ret; 330 - 331 - if (!cpu_data[cpu].page) 332 - return; 333 - 334 - if (read_page) { 335 - if (cpu_data[cpu].size <= page_size) { 336 - free(cpu_data[cpu].page); 337 - cpu_data[cpu].page = NULL; 338 - return; 339 - } 340 - 341 - update_cpu_data_index(cpu); 342 - 343 - /* other parts of the code may expect the pointer to not move */ 344 - save_seek = lseek(input_fd, 0, SEEK_CUR); 345 - 346 - ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET); 347 - if (ret == (off_t)-1) 348 - die("failed to lseek"); 349 - ret = read(input_fd, cpu_data[cpu].page, page_size); 350 - if (ret < 0) 351 - die("failed to read page"); 352 - 353 - /* reset the file pointer back */ 354 - lseek(input_fd, save_seek, SEEK_SET); 355 - 356 - return; 357 - } 358 - 359 - munmap(cpu_data[cpu].page, page_size); 360 - cpu_data[cpu].page = NULL; 361 - 362 - if (cpu_data[cpu].size <= page_size) 363 - return; 364 - 365 - update_cpu_data_index(cpu); 366 - 367 - cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, 368 - input_fd, cpu_data[cpu].offset); 369 - if (cpu_data[cpu].page == MAP_FAILED) 370 - die("failed to mmap cpu %d at offset 0x%llx", 371 - cpu, cpu_data[cpu].offset); 372 - } 373 - 374 - static unsigned int type_len4host(unsigned int type_len_ts) 375 - { 376 - if (file_bigendian) 377 - return (type_len_ts >> 27) & ((1 << 5) - 1); 378 - else 379 - return type_len_ts & ((1 << 5) - 1); 380 - } 381 - 382 - static unsigned int ts4host(unsigned int type_len_ts) 383 - { 384 - if (file_bigendian) 385 - return type_len_ts & ((1 << 27) - 1); 386 - else 387 - return type_len_ts >> 5; 388 - } 389 - 390 - static int calc_index(void *ptr, int cpu) 391 - { 392 - return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 393 - } 394 - 395 - struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu) 396 - { 397 - struct pevent_record *data; 398 - void *page = cpu_data[cpu].page; 399 - int idx = cpu_data[cpu].index; 400 - void *ptr = page + idx; 401 - unsigned long long extend; 402 - unsigned int type_len_ts; 403 - unsigned int type_len; 404 - unsigned int delta; 405 - unsigned int length = 0; 406 - 407 - if (cpu_data[cpu].next) 408 - return cpu_data[cpu].next; 409 - 410 - if (!page) 411 - return NULL; 412 - 413 - if (!idx) { 414 - /* FIXME: handle header page */ 415 - if (header_page_ts_size != 8) 416 - die("expected a long long type for timestamp"); 417 - cpu_data[cpu].timestamp = data2host8(pevent, ptr); 418 - ptr += 8; 419 - switch (header_page_size_size) { 420 - case 4: 421 - cpu_data[cpu].page_size = data2host4(pevent, ptr); 422 - ptr += 4; 423 - break; 424 - case 8: 425 - cpu_data[cpu].page_size = data2host8(pevent, ptr); 426 - ptr += 8; 427 - break; 428 - default: 429 - die("bad long size"); 430 - } 431 - ptr = cpu_data[cpu].page + header_page_data_offset; 432 - } 433 - 434 - read_again: 435 - idx = calc_index(ptr, cpu); 436 - 437 - if (idx >= cpu_data[cpu].page_size) { 438 - get_next_page(cpu); 439 - return trace_peek_data(pevent, cpu); 440 - } 441 - 442 - type_len_ts = data2host4(pevent, ptr); 443 - ptr += 4; 444 - 445 - type_len = type_len4host(type_len_ts); 446 - delta = ts4host(type_len_ts); 447 - 448 - switch (type_len) { 449 - case RINGBUF_TYPE_PADDING: 450 - if (!delta) 451 - die("error, hit unexpected end of page"); 452 - length = data2host4(pevent, ptr); 453 - ptr += 4; 454 - length *= 4; 455 - ptr += length; 456 - goto read_again; 457 - 458 - case RINGBUF_TYPE_TIME_EXTEND: 459 - extend = data2host4(pevent, ptr); 460 - ptr += 4; 461 - extend <<= TS_SHIFT; 462 - extend += delta; 463 - cpu_data[cpu].timestamp += extend; 464 - goto read_again; 465 - 466 - case RINGBUF_TYPE_TIME_STAMP: 467 - ptr += 12; 468 - break; 469 - case 0: 470 - length = data2host4(pevent, ptr); 471 - ptr += 4; 472 - die("here! length=%d", length); 473 - break; 474 - default: 475 - length = type_len * 4; 476 - break; 477 - } 478 - 479 - cpu_data[cpu].timestamp += delta; 480 - 481 - data = malloc_or_die(sizeof(*data)); 482 - memset(data, 0, sizeof(*data)); 483 - 484 - data->ts = cpu_data[cpu].timestamp; 485 - data->size = length; 486 - data->data = ptr; 487 - ptr += length; 488 - 489 - cpu_data[cpu].index = calc_index(ptr, cpu); 490 - cpu_data[cpu].next = data; 491 - 492 - return data; 493 - } 494 - 495 - struct pevent_record *trace_read_data(struct pevent *pevent, int cpu) 496 - { 497 - struct pevent_record *data; 498 - 499 - data = trace_peek_data(pevent, cpu); 500 - cpu_data[cpu].next = NULL; 501 - 502 - return data; 324 + return 0; 503 325 } 504 326 505 327 ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) ··· 348 494 int show_version = 0; 349 495 int show_funcs = 0; 350 496 int show_printk = 0; 351 - ssize_t size; 497 + ssize_t size = -1; 498 + struct pevent *pevent; 499 + int err; 352 500 353 - calc_data_size = 1; 501 + *ppevent = NULL; 502 + 354 503 repipe = __repipe; 355 - 356 504 input_fd = fd; 357 505 358 - read_or_die(buf, 3); 359 - if (memcmp(buf, test, 3) != 0) 360 - die("no trace data in the file"); 506 + if (do_read(buf, 3) < 0) 507 + return -1; 508 + if (memcmp(buf, test, 3) != 0) { 509 + pr_debug("no trace data in the file"); 510 + return -1; 511 + } 361 512 362 - read_or_die(buf, 7); 363 - if (memcmp(buf, "tracing", 7) != 0) 364 - die("not a trace file (missing 'tracing' tag)"); 513 + if (do_read(buf, 7) < 0) 514 + return -1; 515 + if (memcmp(buf, "tracing", 7) != 0) { 516 + pr_debug("not a trace file (missing 'tracing' tag)"); 517 + return -1; 518 + } 365 519 366 520 version = read_string(); 521 + if (version == NULL) 522 + return -1; 367 523 if (show_version) 368 524 printf("version = %s\n", version); 369 525 free(version); 370 526 371 - read_or_die(buf, 1); 527 + if (do_read(buf, 1) < 0) 528 + return -1; 372 529 file_bigendian = buf[0]; 373 530 host_bigendian = bigendian(); 374 531 375 - *ppevent = read_trace_init(file_bigendian, host_bigendian); 376 - if (*ppevent == NULL) 377 - die("read_trace_init failed"); 532 + pevent = read_trace_init(file_bigendian, host_bigendian); 533 + if (pevent == NULL) { 534 + pr_debug("read_trace_init failed"); 535 + goto out; 536 + } 378 537 379 - read_or_die(buf, 1); 538 + if (do_read(buf, 1) < 0) 539 + goto out; 380 540 long_size = buf[0]; 381 541 382 - page_size = read4(*ppevent); 542 + page_size = read4(pevent); 543 + if (!page_size) 544 + goto out; 383 545 384 - read_header_files(*ppevent); 546 + err = read_header_files(pevent); 547 + if (err) 548 + goto out; 549 + err = read_ftrace_files(pevent); 550 + if (err) 551 + goto out; 552 + err = read_event_files(pevent); 553 + if (err) 554 + goto out; 555 + err = read_proc_kallsyms(pevent); 556 + if (err) 557 + goto out; 558 + err = read_ftrace_printk(pevent); 559 + if (err) 560 + goto out; 385 561 386 - read_ftrace_files(*ppevent); 387 - read_event_files(*ppevent); 388 - read_proc_kallsyms(*ppevent); 389 - read_ftrace_printk(*ppevent); 390 - 391 - size = calc_data_size - 1; 392 - calc_data_size = 0; 562 + size = trace_data_size; 393 563 repipe = false; 394 564 395 565 if (show_funcs) { 396 - pevent_print_funcs(*ppevent); 397 - return size; 398 - } 399 - if (show_printk) { 400 - pevent_print_printk(*ppevent); 401 - return size; 566 + pevent_print_funcs(pevent); 567 + } else if (show_printk) { 568 + pevent_print_printk(pevent); 402 569 } 403 570 571 + *ppevent = pevent; 572 + pevent = NULL; 573 + 574 + out: 575 + if (pevent) 576 + pevent_free(pevent); 404 577 return size; 405 578 }
+1 -5
tools/perf/util/trace-event.h
··· 30 30 int bigendian(void); 31 31 32 32 struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 33 - void print_trace_event(struct pevent *pevent, int cpu, void *data, int size); 34 33 void event_format__print(struct event_format *event, 35 34 int cpu, void *data, int size); 36 - 37 - void print_event(struct pevent *pevent, int cpu, void *data, int size, 38 - unsigned long long nsecs, char *comm); 39 35 40 36 int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); 41 37 int parse_event_file(struct pevent *pevent, ··· 68 72 69 73 struct tracing_data *tracing_data_get(struct list_head *pattrs, 70 74 int fd, bool temp); 71 - void tracing_data_put(struct tracing_data *tdata); 75 + int tracing_data_put(struct tracing_data *tdata); 72 76 73 77 74 78 struct addr_location;
+27
tools/perf/util/util.c
··· 17 17 bool perf_host = true; 18 18 bool perf_guest = false; 19 19 20 + char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; 21 + 20 22 void event_attr_init(struct perf_event_attr *attr) 21 23 { 22 24 if (!perf_host) ··· 243 241 #endif 244 242 ws->ws_row = 25; 245 243 ws->ws_col = 80; 244 + } 245 + 246 + static void set_tracing_events_path(const char *mountpoint) 247 + { 248 + snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", 249 + mountpoint, "tracing/events"); 250 + } 251 + 252 + const char *perf_debugfs_mount(const char *mountpoint) 253 + { 254 + const char *mnt; 255 + 256 + mnt = debugfs_mount(mountpoint); 257 + if (!mnt) 258 + return NULL; 259 + 260 + set_tracing_events_path(mnt); 261 + 262 + return mnt; 263 + } 264 + 265 + void perf_debugfs_set_path(const char *mntpt) 266 + { 267 + snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); 268 + set_tracing_events_path(mntpt); 246 269 }
+5 -4
tools/perf/util/util.h
··· 1 1 #ifndef GIT_COMPAT_UTIL_H 2 2 #define GIT_COMPAT_UTIL_H 3 3 4 - #define _FILE_OFFSET_BITS 64 5 - 6 4 #ifndef FLEX_ARRAY 7 5 /* 8 6 * See if our compiler is known to support flexible array members. ··· 71 73 #include <linux/magic.h> 72 74 #include "types.h" 73 75 #include <sys/ttydefaults.h> 76 + #include <lk/debugfs.h> 74 77 75 78 extern const char *graph_line; 76 79 extern const char *graph_dotted_line; 77 80 extern char buildid_dir[]; 81 + extern char tracing_events_path[]; 82 + extern void perf_debugfs_set_path(const char *mountpoint); 83 + const char *perf_debugfs_mount(const char *mountpoint); 78 84 79 85 /* On most systems <limits.h> would have given us this, but 80 86 * not on some systems (e.g. GNU/Hurd). ··· 276 274 277 275 struct winsize; 278 276 void get_term_dimensions(struct winsize *ws); 279 - 280 - #endif 277 + #endif /* GIT_COMPAT_UTIL_H */
+4 -2
tools/scripts/Makefile.include
··· 1 + ifneq ($(O),) 1 2 ifeq ($(origin O), command line) 2 3 dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) 3 4 ABSOLUTE_O := $(shell cd $(O) ; pwd) ··· 8 7 objtree := $(O) 9 8 endif 10 9 endif 10 + endif 11 11 12 - ifneq ($(OUTPUT),) 13 12 # check that the output directory actually exists 13 + ifneq ($(OUTPUT),) 14 14 OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) 15 15 $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 16 16 endif ··· 72 70 QUIET_BISON = @echo ' ' BISON $@; 73 71 74 72 descend = \ 75 - @echo ' ' DESCEND $(1); \ 73 + +@echo ' ' DESCEND $(1); \ 76 74 mkdir -p $(OUTPUT)$(1) && \ 77 75 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) 78 76 endif
+14 -3
tools/vm/Makefile
··· 1 1 # Makefile for vm tools 2 + # 3 + TARGETS=page-types slabinfo 4 + 5 + LK_DIR = ../lib/lk 6 + LIBLK = $(LK_DIR)/liblk.a 2 7 3 8 CC = $(CROSS_COMPILE)gcc 4 - CFLAGS = -Wall -Wextra 9 + CFLAGS = -Wall -Wextra -I../lib/ 10 + LDFLAGS = $(LIBLK) 5 11 6 - all: page-types slabinfo 12 + $(TARGETS): liblk 13 + 14 + liblk: 15 + make -C $(LK_DIR) 16 + 7 17 %: %.c 8 - $(CC) $(CFLAGS) -o $@ $^ 18 + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 9 19 10 20 clean: 11 21 $(RM) page-types slabinfo 22 + make -C ../lib/lk clean
+7 -78
tools/vm/page-types.c
··· 36 36 #include <sys/statfs.h> 37 37 #include "../../include/uapi/linux/magic.h" 38 38 #include "../../include/uapi/linux/kernel-page-flags.h" 39 - 39 + #include <lk/debugfs.h> 40 40 41 41 #ifndef MAX_PATH 42 42 # define MAX_PATH 256 ··· 178 178 static int opt_hwpoison; 179 179 static int opt_unpoison; 180 180 181 - static char hwpoison_debug_fs[MAX_PATH+1]; 181 + static char *hwpoison_debug_fs; 182 182 static int hwpoison_inject_fd; 183 183 static int hwpoison_forget_fd; 184 184 ··· 458 458 return flags; 459 459 } 460 460 461 - /* verify that a mountpoint is actually a debugfs instance */ 462 - static int debugfs_valid_mountpoint(const char *debugfs) 463 - { 464 - struct statfs st_fs; 465 - 466 - if (statfs(debugfs, &st_fs) < 0) 467 - return -ENOENT; 468 - else if (st_fs.f_type != (long) DEBUGFS_MAGIC) 469 - return -ENOENT; 470 - 471 - return 0; 472 - } 473 - 474 - /* find the path to the mounted debugfs */ 475 - static const char *debugfs_find_mountpoint(void) 476 - { 477 - const char *const *ptr; 478 - char type[100]; 479 - FILE *fp; 480 - 481 - ptr = debugfs_known_mountpoints; 482 - while (*ptr) { 483 - if (debugfs_valid_mountpoint(*ptr) == 0) { 484 - strcpy(hwpoison_debug_fs, *ptr); 485 - return hwpoison_debug_fs; 486 - } 487 - ptr++; 488 - } 489 - 490 - /* give up and parse /proc/mounts */ 491 - fp = fopen("/proc/mounts", "r"); 492 - if (fp == NULL) 493 - perror("Can't open /proc/mounts for read"); 494 - 495 - while (fscanf(fp, "%*s %" 496 - STR(MAX_PATH) 497 - "s %99s %*s %*d %*d\n", 498 - hwpoison_debug_fs, type) == 2) { 499 - if (strcmp(type, "debugfs") == 0) 500 - break; 501 - } 502 - fclose(fp); 503 - 504 - if (strcmp(type, "debugfs") != 0) 505 - return NULL; 506 - 507 - return hwpoison_debug_fs; 508 - } 509 - 510 - /* mount the debugfs somewhere if it's not mounted */ 511 - 512 - static void debugfs_mount(void) 513 - { 514 - const char *const *ptr; 515 - 516 - /* see if it's already mounted */ 517 - if (debugfs_find_mountpoint()) 518 - return; 519 - 520 - ptr = debugfs_known_mountpoints; 521 - while (*ptr) { 522 - if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) { 523 - /* save the mountpoint */ 524 - strcpy(hwpoison_debug_fs, *ptr); 525 - break; 526 - } 527 - ptr++; 528 - } 529 - 530 - if (*ptr == NULL) { 531 - perror("mount debugfs"); 532 - exit(EXIT_FAILURE); 533 - } 534 - } 535 - 536 461 /* 537 462 * page actions 538 463 */ ··· 466 541 { 467 542 char buf[MAX_PATH + 1]; 468 543 469 - debugfs_mount(); 544 + hwpoison_debug_fs = debugfs_mount(NULL); 545 + if (!hwpoison_debug_fs) { 546 + perror("mount debugfs"); 547 + exit(EXIT_FAILURE); 548 + } 470 549 471 550 if (opt_hwpoison && !hwpoison_inject_fd) { 472 551 snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",