mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-18 10:34:24 +08:00
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "As a first remark I'd like to note that the way to build perf tooling has been simplified and sped up, in the future it should be enough for you to build perf via: cd tools/perf/ make install (ie without the -j option.) The build system will figure out the number of CPUs and will do a parallel build+install. The various build system inefficiencies and breakages Linus reported against the v3.12 pull request should now be resolved - please (re-)report any remaining annoyances or bugs. Main changes on the perf kernel side: * Performance optimizations: . perf ring-buffer code optimizations, by Peter Zijlstra . perf ring-buffer code optimizations, by Oleg Nesterov . x86 NMI call-stack processing optimizations, by Peter Zijlstra . perf context-switch optimizations, by Peter Zijlstra . perf sampling speedups, by Peter Zijlstra . x86 Intel PEBS processing speedups, by Peter Zijlstra * Enhanced hardware support: . for Intel Ivy Bridge-EP uncore PMUs, by Zheng Yan . for Haswell transactions, by Andi Kleen, Peter Zijlstra * Core perf events code enhancements and fixes by Oleg Nesterov: . for uprobes, if fork() is called with pending ret-probes . for uprobes platform support code * New ABI details by Andi Kleen: . Report x86 Haswell TSX transaction abort cost as weight Main changes on the perf tooling side (some of these tooling changes utilize the above kernel side changes): * 'perf report/top' enhancements: . Convert callchain children list to rbtree, greatly reducing the time taken for callchain processing, from Namhyung Kim. . Add new COMM infrastructure, further improving histogram processing, from Frédéric Weisbecker, one fix from Namhyung Kim. . Add /proc/kcore based live-annotation improvements, including build-id cache support, multi map 'call' instruction navigation fixes, kcore address validation, objdump workarounds. From Adrian Hunter. . Show progress on histogram collapsing, that can take a long time, from Namhyung Kim. . Add --max-stack option to limit callchain stack scan in 'top' and 'report', improving callchain processing when reducing the stack depth is an option, from Waiman Long. . Add new option --ignore-vmlinux for perf top, from Willy Tarreau. * 'perf trace' enhancements: . 'perf trace' now can can use a 'perf probe' dynamic tracepoints to hook into the userspace -> kernel pathname copy so that it can map fds to pathnames without reading /proc/pid/fd/ symlinks. From Arnaldo Carvalho de Melo. . Show VFS path associated with fd in live sessions, using a 'vfs_getname' 'perf probe' created dynamic tracepoint or by looking at /proc/pid/fd, from Arnaldo Carvalho de Melo. . Add 'trace' beautifiers for lots of syscall arguments, from Arnaldo Carvalho de Melo. . Implement more compact 'trace' output by suppressing zeroed args, from Arnaldo Carvalho de Melo. . Show thread COMM by default in 'trace', from Arnaldo Carvalho de Melo. . Add option to show full timestamp in 'trace', from David Ahern. . Add 'record' command in 'trace', to record raw_syscalls:*, from David Ahern. . Add summary option to dump syscall statistics in 'trace', from David Ahern. . Improve error messages in 'trace', providing hints about system configuration steps needed for using it, from Ramkumar Ramachandra. . 'perf trace' now emits hints as to why tracing is not possible, helping the user to setup the system to allow tracing in the desired permission granularity, telling if the problem is due to debugfs not being mounted or with not enough permission for !root, /proc/sys/kernel/perf_event_paranoit value, etc. From Arnaldo Carvalho de Melo. * 'perf record' enhancements: . Check maximum frequency rate for record/top, emitting better error messages, from Jiri Olsa. . 'perf record' code cleanups, from David Ahern. . Improve write_output error message in 'perf record', from Adrian Hunter. . Allow specifying B/K/M/G unit to the --mmap-pages arguments, from Jiri Olsa. . Fix command line callchain attribute tests to handle the new -g/--call-chain semantics, from Arnaldo Carvalho de Melo. * 'perf kvm' enhancements: . Disable live kvm command if timerfd is not supported, from David Ahern. . Fix detection of non-core features, from David Ahern. * 'perf list' enhancements: . Add usage to 'perf list', from David Ahern. . Show error in 'perf list' if tracepoints not available, from Pekka Enberg. * 'perf probe' enhancements: . Support "$vars" meta argument syntax for local variables, allowing asking for all possible variables at a given probe point to be collected when it hits, from Masami Hiramatsu. * 'perf sched' enhancements: . Address the root cause of that 'perf sched' stack initialization build slowdown, by programmatically setting a big array after moving the global variable back to the stack. Fix from Adrian Hunter. * 'perf script' enhancements: . Set up output options for in-stream attributes, from Adrian Hunter. . Print addr by default for BTS in 'perf script', from Adrian Juntmer * 'perf stat' enhancements: . Improved messages when doing profiling in all or a subset of CPUs using a workload as the session delimitator, as in: 'perf stat --cpu 0,2 sleep 10s' from Arnaldo Carvalho de Melo. . Add units to nanosec-based counters in 'perf stat', from David Ahern. . Remove bogus info when using 'perf stat' -e cycles/instructions, from Ramkumar Ramachandra. * 'perf lock' enhancements: . 'perf lock' fixes and cleanups, from Davidlohr Bueso. * 'perf test' enhancements: . Fixup PERF_SAMPLE_TRANSACTION handling in sample synthesizing and 'perf test', from Adrian Hunter. . Clarify the "sample parsing" test entry, from Arnaldo Carvalho de Melo. . Consider PERF_SAMPLE_TRANSACTION in the "sample parsing" test, from Arnaldo Carvalho de Melo. . Memory leak fixes in 'perf test', from Felipe Pena. * 'perf bench' enhancements: . Change the procps visible command-name of invididual benchmark tests plus cleanups, from Ingo Molnar. * Generic perf tooling infrastructure/plumbing changes: . Separating data file properties from session, code reorganization from Jiri Olsa. . Fix version when building out of tree, as when using one of these: $ make help | grep perf perf-tar-src-pkg - Build perf-3.12.0.tar source tarball perf-targz-src-pkg - Build perf-3.12.0.tar.gz source tarball perf-tarbz2-src-pkg - Build perf-3.12.0.tar.bz2 source tarball perf-tarxz-src-pkg - Build perf-3.12.0.tar.xz source tarball $ from David Ahern. . Enhance option parse error message, showing just the help lines of the options affected, from Namhyung Kim. . libtraceevent updates from upstream trace-cmd repo, from Steven Rostedt. . Always use perf_evsel__set_sample_bit to set sample_type, from Adrian Hunter. . Memory and mmap leak fixes from Chenggang Qin. . Assorted build fixes for from David Ahern and Jiri Olsa. . Speed up and prettify the build system, from Ingo Molnar. . Implement addr2line directly using libbfd, from Roberto Vitillo. . Separate the GTK support in a separate libperf-gtk.so DSO, that is only loaded when --gtk is specified, from Namhyung Kim. . perf bash completion fixes and improvements from Ramkumar Ramachandra. . Support for Openembedded/Yocto -dbg packages, from Ricardo Ribalda Delgado. And lots and lots of other fixes and code reorganizations that did not make it into the list, see the shortlog, diffstat and the Git log for details!" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (300 commits) uprobes: Fix the memory out of bound overwrite in copy_insn() uprobes: Fix the wrong usage of current->utask in uprobe_copy_process() perf tools: Remove unneeded include perf record: Remove post_processing_offset variable perf record: Remove advance_output function perf record: Refactor feature handling into a separate function perf trace: Don't relookup fields by name in each sample perf tools: Fix version when building out of tree perf evsel: Ditch evsel->handler.data field uprobes: Export write_opcode() as uprobe_write_opcode() uprobes: Introduce arch_uprobe->ixol uprobes: Kill module_init() and module_exit() uprobes: Move function declarations out of arch perf/x86/intel: Add Ivy Bridge-EP uncore IRP box support perf/x86/intel/uncore: Add filter support for IvyBridge-EP QPI boxes perf: Factor out strncpy() in perf_event_mmap_event() tools/perf: Add required memory barriers perf: Fix arch_perf_out_copy_user default perf: Update a stale comment perf: Optimize perf_output_begin() -- address calculation ...
This commit is contained in:
commit
ad5d69899e
@ -37,6 +37,7 @@ typedef ppc_opcode_t uprobe_opcode_t;
|
||||
struct arch_uprobe {
|
||||
union {
|
||||
u8 insn[MAX_UINSN_BYTES];
|
||||
u8 ixol[MAX_UINSN_BYTES];
|
||||
u32 ainsn;
|
||||
};
|
||||
};
|
||||
@ -45,11 +46,4 @@ struct arch_uprobe_task {
|
||||
unsigned long saved_trap_nr;
|
||||
};
|
||||
|
||||
extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
|
||||
extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
|
||||
extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
|
||||
extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs);
|
||||
#endif /* _ASM_UPROBES_H */
|
||||
|
@ -35,7 +35,10 @@ typedef u8 uprobe_opcode_t;
|
||||
|
||||
struct arch_uprobe {
|
||||
u16 fixups;
|
||||
u8 insn[MAX_UINSN_BYTES];
|
||||
union {
|
||||
u8 insn[MAX_UINSN_BYTES];
|
||||
u8 ixol[MAX_UINSN_BYTES];
|
||||
};
|
||||
#ifdef CONFIG_X86_64
|
||||
unsigned long rip_rela_target_address;
|
||||
#endif
|
||||
@ -49,11 +52,4 @@ struct arch_uprobe_task {
|
||||
unsigned int saved_tf;
|
||||
};
|
||||
|
||||
extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
|
||||
extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
|
||||
extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
|
||||
extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs);
|
||||
#endif /* _ASM_UPROBES_H */
|
||||
|
@ -1989,7 +1989,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
||||
frame.return_address = 0;
|
||||
|
||||
bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
|
||||
if (bytes != sizeof(frame))
|
||||
if (bytes != 0)
|
||||
break;
|
||||
|
||||
if (!valid_user_frame(fp, sizeof(frame)))
|
||||
@ -2041,7 +2041,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
|
||||
frame.return_address = 0;
|
||||
|
||||
bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
|
||||
if (bytes != sizeof(frame))
|
||||
if (bytes != 0)
|
||||
break;
|
||||
|
||||
if (!valid_user_frame(fp, sizeof(frame)))
|
||||
|
@ -163,6 +163,11 @@ struct cpu_hw_events {
|
||||
u64 intel_ctrl_host_mask;
|
||||
struct perf_guest_switch_msr guest_switch_msrs[X86_PMC_IDX_MAX];
|
||||
|
||||
/*
|
||||
* Intel checkpoint mask
|
||||
*/
|
||||
u64 intel_cp_status;
|
||||
|
||||
/*
|
||||
* manage shared (per-core, per-cpu) registers
|
||||
* used on Intel NHM/WSM/SNB
|
||||
@ -440,6 +445,7 @@ struct x86_pmu {
|
||||
int lbr_nr; /* hardware stack size */
|
||||
u64 lbr_sel_mask; /* LBR_SELECT valid bits */
|
||||
const int *lbr_sel_map; /* lbr_select mappings */
|
||||
bool lbr_double_abort; /* duplicated lbr aborts */
|
||||
|
||||
/*
|
||||
* Extra registers for events
|
||||
|
@ -190,9 +190,9 @@ static struct extra_reg intel_snbep_extra_regs[] __read_mostly = {
|
||||
EVENT_EXTRA_END
|
||||
};
|
||||
|
||||
EVENT_ATTR_STR(mem-loads, mem_ld_nhm, "event=0x0b,umask=0x10,ldlat=3");
|
||||
EVENT_ATTR_STR(mem-loads, mem_ld_snb, "event=0xcd,umask=0x1,ldlat=3");
|
||||
EVENT_ATTR_STR(mem-stores, mem_st_snb, "event=0xcd,umask=0x2");
|
||||
EVENT_ATTR_STR(mem-loads, mem_ld_nhm, "event=0x0b,umask=0x10,ldlat=3");
|
||||
EVENT_ATTR_STR(mem-loads, mem_ld_snb, "event=0xcd,umask=0x1,ldlat=3");
|
||||
EVENT_ATTR_STR(mem-stores, mem_st_snb, "event=0xcd,umask=0x2");
|
||||
|
||||
struct attribute *nhm_events_attrs[] = {
|
||||
EVENT_PTR(mem_ld_nhm),
|
||||
@ -1184,6 +1184,11 @@ static void intel_pmu_disable_fixed(struct hw_perf_event *hwc)
|
||||
wrmsrl(hwc->config_base, ctrl_val);
|
||||
}
|
||||
|
||||
static inline bool event_is_checkpointed(struct perf_event *event)
|
||||
{
|
||||
return (event->hw.config & HSW_IN_TX_CHECKPOINTED) != 0;
|
||||
}
|
||||
|
||||
static void intel_pmu_disable_event(struct perf_event *event)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
@ -1197,6 +1202,7 @@ static void intel_pmu_disable_event(struct perf_event *event)
|
||||
|
||||
cpuc->intel_ctrl_guest_mask &= ~(1ull << hwc->idx);
|
||||
cpuc->intel_ctrl_host_mask &= ~(1ull << hwc->idx);
|
||||
cpuc->intel_cp_status &= ~(1ull << hwc->idx);
|
||||
|
||||
/*
|
||||
* must disable before any actual event
|
||||
@ -1271,6 +1277,9 @@ static void intel_pmu_enable_event(struct perf_event *event)
|
||||
if (event->attr.exclude_guest)
|
||||
cpuc->intel_ctrl_host_mask |= (1ull << hwc->idx);
|
||||
|
||||
if (unlikely(event_is_checkpointed(event)))
|
||||
cpuc->intel_cp_status |= (1ull << hwc->idx);
|
||||
|
||||
if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
|
||||
intel_pmu_enable_fixed(hwc);
|
||||
return;
|
||||
@ -1289,6 +1298,17 @@ static void intel_pmu_enable_event(struct perf_event *event)
|
||||
int intel_pmu_save_and_restart(struct perf_event *event)
|
||||
{
|
||||
x86_perf_event_update(event);
|
||||
/*
|
||||
* For a checkpointed counter always reset back to 0. This
|
||||
* avoids a situation where the counter overflows, aborts the
|
||||
* transaction and is then set back to shortly before the
|
||||
* overflow, and overflows and aborts again.
|
||||
*/
|
||||
if (unlikely(event_is_checkpointed(event))) {
|
||||
/* No race with NMIs because the counter should not be armed */
|
||||
wrmsrl(event->hw.event_base, 0);
|
||||
local64_set(&event->hw.prev_count, 0);
|
||||
}
|
||||
return x86_perf_event_set_period(event);
|
||||
}
|
||||
|
||||
@ -1372,6 +1392,13 @@ again:
|
||||
x86_pmu.drain_pebs(regs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checkpointed counters can lead to 'spurious' PMIs because the
|
||||
* rollback caused by the PMI will have cleared the overflow status
|
||||
* bit. Therefore always force probe these counters.
|
||||
*/
|
||||
status |= cpuc->intel_cp_status;
|
||||
|
||||
for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
|
||||
struct perf_event *event = cpuc->events[bit];
|
||||
|
||||
@ -1837,6 +1864,20 @@ static int hsw_hw_config(struct perf_event *event)
|
||||
event->attr.precise_ip > 0))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (event_is_checkpointed(event)) {
|
||||
/*
|
||||
* Sampling of checkpointed events can cause situations where
|
||||
* the CPU constantly aborts because of a overflow, which is
|
||||
* then checkpointed back and ignored. Forbid checkpointing
|
||||
* for sampling.
|
||||
*
|
||||
* But still allow a long sampling period, so that perf stat
|
||||
* from KVM works.
|
||||
*/
|
||||
if (event->attr.sample_period > 0 &&
|
||||
event->attr.sample_period < 0x7fffffff)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2182,10 +2223,36 @@ static __init void intel_nehalem_quirk(void)
|
||||
}
|
||||
}
|
||||
|
||||
EVENT_ATTR_STR(mem-loads, mem_ld_hsw, "event=0xcd,umask=0x1,ldlat=3");
|
||||
EVENT_ATTR_STR(mem-stores, mem_st_hsw, "event=0xd0,umask=0x82")
|
||||
EVENT_ATTR_STR(mem-loads, mem_ld_hsw, "event=0xcd,umask=0x1,ldlat=3");
|
||||
EVENT_ATTR_STR(mem-stores, mem_st_hsw, "event=0xd0,umask=0x82")
|
||||
|
||||
/* Haswell special events */
|
||||
EVENT_ATTR_STR(tx-start, tx_start, "event=0xc9,umask=0x1");
|
||||
EVENT_ATTR_STR(tx-commit, tx_commit, "event=0xc9,umask=0x2");
|
||||
EVENT_ATTR_STR(tx-abort, tx_abort, "event=0xc9,umask=0x4");
|
||||
EVENT_ATTR_STR(tx-capacity, tx_capacity, "event=0x54,umask=0x2");
|
||||
EVENT_ATTR_STR(tx-conflict, tx_conflict, "event=0x54,umask=0x1");
|
||||
EVENT_ATTR_STR(el-start, el_start, "event=0xc8,umask=0x1");
|
||||
EVENT_ATTR_STR(el-commit, el_commit, "event=0xc8,umask=0x2");
|
||||
EVENT_ATTR_STR(el-abort, el_abort, "event=0xc8,umask=0x4");
|
||||
EVENT_ATTR_STR(el-capacity, el_capacity, "event=0x54,umask=0x2");
|
||||
EVENT_ATTR_STR(el-conflict, el_conflict, "event=0x54,umask=0x1");
|
||||
EVENT_ATTR_STR(cycles-t, cycles_t, "event=0x3c,in_tx=1");
|
||||
EVENT_ATTR_STR(cycles-ct, cycles_ct, "event=0x3c,in_tx=1,in_tx_cp=1");
|
||||
|
||||
static struct attribute *hsw_events_attrs[] = {
|
||||
EVENT_PTR(tx_start),
|
||||
EVENT_PTR(tx_commit),
|
||||
EVENT_PTR(tx_abort),
|
||||
EVENT_PTR(tx_capacity),
|
||||
EVENT_PTR(tx_conflict),
|
||||
EVENT_PTR(el_start),
|
||||
EVENT_PTR(el_commit),
|
||||
EVENT_PTR(el_abort),
|
||||
EVENT_PTR(el_capacity),
|
||||
EVENT_PTR(el_conflict),
|
||||
EVENT_PTR(cycles_t),
|
||||
EVENT_PTR(cycles_ct),
|
||||
EVENT_PTR(mem_ld_hsw),
|
||||
EVENT_PTR(mem_st_hsw),
|
||||
NULL
|
||||
@ -2452,6 +2519,7 @@ __init int intel_pmu_init(void)
|
||||
x86_pmu.hw_config = hsw_hw_config;
|
||||
x86_pmu.get_event_constraints = hsw_get_event_constraints;
|
||||
x86_pmu.cpu_events = hsw_events_attrs;
|
||||
x86_pmu.lbr_double_abort = true;
|
||||
pr_cont("Haswell events, ");
|
||||
break;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#define BTS_BUFFER_SIZE (PAGE_SIZE << 4)
|
||||
#define PEBS_BUFFER_SIZE PAGE_SIZE
|
||||
#define PEBS_FIXUP_SIZE PAGE_SIZE
|
||||
|
||||
/*
|
||||
* pebs_record_32 for p4 and core not supported
|
||||
@ -182,18 +183,32 @@ struct pebs_record_nhm {
|
||||
* Same as pebs_record_nhm, with two additional fields.
|
||||
*/
|
||||
struct pebs_record_hsw {
|
||||
struct pebs_record_nhm nhm;
|
||||
/*
|
||||
* Real IP of the event. In the Intel documentation this
|
||||
* is called eventingrip.
|
||||
*/
|
||||
u64 real_ip;
|
||||
/*
|
||||
* TSX tuning information field: abort cycles and abort flags.
|
||||
*/
|
||||
u64 tsx_tuning;
|
||||
u64 flags, ip;
|
||||
u64 ax, bx, cx, dx;
|
||||
u64 si, di, bp, sp;
|
||||
u64 r8, r9, r10, r11;
|
||||
u64 r12, r13, r14, r15;
|
||||
u64 status, dla, dse, lat;
|
||||
u64 real_ip, tsx_tuning;
|
||||
};
|
||||
|
||||
union hsw_tsx_tuning {
|
||||
struct {
|
||||
u32 cycles_last_block : 32,
|
||||
hle_abort : 1,
|
||||
rtm_abort : 1,
|
||||
instruction_abort : 1,
|
||||
non_instruction_abort : 1,
|
||||
retry : 1,
|
||||
data_conflict : 1,
|
||||
capacity_writes : 1,
|
||||
capacity_reads : 1;
|
||||
};
|
||||
u64 value;
|
||||
};
|
||||
|
||||
#define PEBS_HSW_TSX_FLAGS 0xff00000000ULL
|
||||
|
||||
void init_debug_store_on_cpu(int cpu)
|
||||
{
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
@ -214,12 +229,14 @@ void fini_debug_store_on_cpu(int cpu)
|
||||
wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(void *, insn_buffer);
|
||||
|
||||
static int alloc_pebs_buffer(int cpu)
|
||||
{
|
||||
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
|
||||
int node = cpu_to_node(cpu);
|
||||
int max, thresh = 1; /* always use a single PEBS record */
|
||||
void *buffer;
|
||||
void *buffer, *ibuffer;
|
||||
|
||||
if (!x86_pmu.pebs)
|
||||
return 0;
|
||||
@ -228,6 +245,19 @@ static int alloc_pebs_buffer(int cpu)
|
||||
if (unlikely(!buffer))
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* HSW+ already provides us the eventing ip; no need to allocate this
|
||||
* buffer then.
|
||||
*/
|
||||
if (x86_pmu.intel_cap.pebs_format < 2) {
|
||||
ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node);
|
||||
if (!ibuffer) {
|
||||
kfree(buffer);
|
||||
return -ENOMEM;
|
||||
}
|
||||
per_cpu(insn_buffer, cpu) = ibuffer;
|
||||
}
|
||||
|
||||
max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
|
||||
|
||||
ds->pebs_buffer_base = (u64)(unsigned long)buffer;
|
||||
@ -248,6 +278,9 @@ static void release_pebs_buffer(int cpu)
|
||||
if (!ds || !x86_pmu.pebs)
|
||||
return;
|
||||
|
||||
kfree(per_cpu(insn_buffer, cpu));
|
||||
per_cpu(insn_buffer, cpu) = NULL;
|
||||
|
||||
kfree((void *)(unsigned long)ds->pebs_buffer_base);
|
||||
ds->pebs_buffer_base = 0;
|
||||
}
|
||||
@ -715,6 +748,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
unsigned long old_to, to = cpuc->lbr_entries[0].to;
|
||||
unsigned long ip = regs->ip;
|
||||
int is_64bit = 0;
|
||||
void *kaddr;
|
||||
|
||||
/*
|
||||
* We don't need to fixup if the PEBS assist is fault like
|
||||
@ -738,7 +772,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
* unsigned math, either ip is before the start (impossible) or
|
||||
* the basic block is larger than 1 page (sanity)
|
||||
*/
|
||||
if ((ip - to) > PAGE_SIZE)
|
||||
if ((ip - to) > PEBS_FIXUP_SIZE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -749,29 +783,33 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!kernel_ip(ip)) {
|
||||
int size, bytes;
|
||||
u8 *buf = this_cpu_read(insn_buffer);
|
||||
|
||||
size = ip - to; /* Must fit our buffer, see above */
|
||||
bytes = copy_from_user_nmi(buf, (void __user *)to, size);
|
||||
if (bytes != 0)
|
||||
return 0;
|
||||
|
||||
kaddr = buf;
|
||||
} else {
|
||||
kaddr = (void *)to;
|
||||
}
|
||||
|
||||
do {
|
||||
struct insn insn;
|
||||
u8 buf[MAX_INSN_SIZE];
|
||||
void *kaddr;
|
||||
|
||||
old_to = to;
|
||||
if (!kernel_ip(ip)) {
|
||||
int bytes, size = MAX_INSN_SIZE;
|
||||
|
||||
bytes = copy_from_user_nmi(buf, (void __user *)to, size);
|
||||
if (bytes != size)
|
||||
return 0;
|
||||
|
||||
kaddr = buf;
|
||||
} else
|
||||
kaddr = (void *)to;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32);
|
||||
#endif
|
||||
insn_init(&insn, kaddr, is_64bit);
|
||||
insn_get_length(&insn);
|
||||
|
||||
to += insn.length;
|
||||
kaddr += insn.length;
|
||||
} while (to < ip);
|
||||
|
||||
if (to == ip) {
|
||||
@ -786,16 +824,34 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u64 intel_hsw_weight(struct pebs_record_hsw *pebs)
|
||||
{
|
||||
if (pebs->tsx_tuning) {
|
||||
union hsw_tsx_tuning tsx = { .value = pebs->tsx_tuning };
|
||||
return tsx.cycles_last_block;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u64 intel_hsw_transaction(struct pebs_record_hsw *pebs)
|
||||
{
|
||||
u64 txn = (pebs->tsx_tuning & PEBS_HSW_TSX_FLAGS) >> 32;
|
||||
|
||||
/* For RTM XABORTs also log the abort code from AX */
|
||||
if ((txn & PERF_TXN_TRANSACTION) && (pebs->ax & 1))
|
||||
txn |= ((pebs->ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT;
|
||||
return txn;
|
||||
}
|
||||
|
||||
static void __intel_pmu_pebs_event(struct perf_event *event,
|
||||
struct pt_regs *iregs, void *__pebs)
|
||||
{
|
||||
/*
|
||||
* We cast to pebs_record_nhm to get the load latency data
|
||||
* if extra_reg MSR_PEBS_LD_LAT_THRESHOLD used
|
||||
* We cast to the biggest pebs_record but are careful not to
|
||||
* unconditionally access the 'extra' entries.
|
||||
*/
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
struct pebs_record_nhm *pebs = __pebs;
|
||||
struct pebs_record_hsw *pebs_hsw = __pebs;
|
||||
struct pebs_record_hsw *pebs = __pebs;
|
||||
struct perf_sample_data data;
|
||||
struct pt_regs regs;
|
||||
u64 sample_type;
|
||||
@ -854,7 +910,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
|
||||
regs.sp = pebs->sp;
|
||||
|
||||
if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) {
|
||||
regs.ip = pebs_hsw->real_ip;
|
||||
regs.ip = pebs->real_ip;
|
||||
regs.flags |= PERF_EFLAGS_EXACT;
|
||||
} else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(®s))
|
||||
regs.flags |= PERF_EFLAGS_EXACT;
|
||||
@ -862,9 +918,18 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
|
||||
regs.flags &= ~PERF_EFLAGS_EXACT;
|
||||
|
||||
if ((event->attr.sample_type & PERF_SAMPLE_ADDR) &&
|
||||
x86_pmu.intel_cap.pebs_format >= 1)
|
||||
x86_pmu.intel_cap.pebs_format >= 1)
|
||||
data.addr = pebs->dla;
|
||||
|
||||
if (x86_pmu.intel_cap.pebs_format >= 2) {
|
||||
/* Only set the TSX weight when no memory weight. */
|
||||
if ((event->attr.sample_type & PERF_SAMPLE_WEIGHT) && !fll)
|
||||
data.weight = intel_hsw_weight(pebs);
|
||||
|
||||
if (event->attr.sample_type & PERF_SAMPLE_TRANSACTION)
|
||||
data.txn = intel_hsw_transaction(pebs);
|
||||
}
|
||||
|
||||
if (has_branch_stack(event))
|
||||
data.br_stack = &cpuc->lbr_stack;
|
||||
|
||||
@ -913,17 +978,34 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
|
||||
__intel_pmu_pebs_event(event, iregs, at);
|
||||
}
|
||||
|
||||
static void __intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, void *at,
|
||||
void *top)
|
||||
static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
struct debug_store *ds = cpuc->ds;
|
||||
struct perf_event *event = NULL;
|
||||
void *at, *top;
|
||||
u64 status = 0;
|
||||
int bit;
|
||||
|
||||
if (!x86_pmu.pebs_active)
|
||||
return;
|
||||
|
||||
at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
|
||||
top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index;
|
||||
|
||||
ds->pebs_index = ds->pebs_buffer_base;
|
||||
|
||||
if (unlikely(at > top))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Should not happen, we program the threshold at 1 and do not
|
||||
* set a reset value.
|
||||
*/
|
||||
WARN_ONCE(top - at > x86_pmu.max_pebs_events * x86_pmu.pebs_record_size,
|
||||
"Unexpected number of pebs records %ld\n",
|
||||
(long)(top - at) / x86_pmu.pebs_record_size);
|
||||
|
||||
for (; at < top; at += x86_pmu.pebs_record_size) {
|
||||
struct pebs_record_nhm *p = at;
|
||||
|
||||
@ -951,61 +1033,6 @@ static void __intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, void *at,
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
struct debug_store *ds = cpuc->ds;
|
||||
struct pebs_record_nhm *at, *top;
|
||||
int n;
|
||||
|
||||
if (!x86_pmu.pebs_active)
|
||||
return;
|
||||
|
||||
at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
|
||||
top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index;
|
||||
|
||||
ds->pebs_index = ds->pebs_buffer_base;
|
||||
|
||||
n = top - at;
|
||||
if (n <= 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Should not happen, we program the threshold at 1 and do not
|
||||
* set a reset value.
|
||||
*/
|
||||
WARN_ONCE(n > x86_pmu.max_pebs_events,
|
||||
"Unexpected number of pebs records %d\n", n);
|
||||
|
||||
return __intel_pmu_drain_pebs_nhm(iregs, at, top);
|
||||
}
|
||||
|
||||
static void intel_pmu_drain_pebs_hsw(struct pt_regs *iregs)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
struct debug_store *ds = cpuc->ds;
|
||||
struct pebs_record_hsw *at, *top;
|
||||
int n;
|
||||
|
||||
if (!x86_pmu.pebs_active)
|
||||
return;
|
||||
|
||||
at = (struct pebs_record_hsw *)(unsigned long)ds->pebs_buffer_base;
|
||||
top = (struct pebs_record_hsw *)(unsigned long)ds->pebs_index;
|
||||
|
||||
n = top - at;
|
||||
if (n <= 0)
|
||||
return;
|
||||
/*
|
||||
* Should not happen, we program the threshold at 1 and do not
|
||||
* set a reset value.
|
||||
*/
|
||||
WARN_ONCE(n > x86_pmu.max_pebs_events,
|
||||
"Unexpected number of pebs records %d\n", n);
|
||||
|
||||
return __intel_pmu_drain_pebs_nhm(iregs, at, top);
|
||||
}
|
||||
|
||||
/*
|
||||
* BTS, PEBS probe and setup
|
||||
*/
|
||||
@ -1040,7 +1067,7 @@ void intel_ds_init(void)
|
||||
case 2:
|
||||
pr_cont("PEBS fmt2%c, ", pebs_type);
|
||||
x86_pmu.pebs_record_size = sizeof(struct pebs_record_hsw);
|
||||
x86_pmu.drain_pebs = intel_pmu_drain_pebs_hsw;
|
||||
x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -284,6 +284,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
|
||||
int lbr_format = x86_pmu.intel_cap.lbr_format;
|
||||
u64 tos = intel_pmu_lbr_tos();
|
||||
int i;
|
||||
int out = 0;
|
||||
|
||||
for (i = 0; i < x86_pmu.lbr_nr; i++) {
|
||||
unsigned long lbr_idx = (tos - i) & mask;
|
||||
@ -306,15 +307,27 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
|
||||
}
|
||||
from = (u64)((((s64)from) << skip) >> skip);
|
||||
|
||||
cpuc->lbr_entries[i].from = from;
|
||||
cpuc->lbr_entries[i].to = to;
|
||||
cpuc->lbr_entries[i].mispred = mis;
|
||||
cpuc->lbr_entries[i].predicted = pred;
|
||||
cpuc->lbr_entries[i].in_tx = in_tx;
|
||||
cpuc->lbr_entries[i].abort = abort;
|
||||
cpuc->lbr_entries[i].reserved = 0;
|
||||
/*
|
||||
* Some CPUs report duplicated abort records,
|
||||
* with the second entry not having an abort bit set.
|
||||
* Skip them here. This loop runs backwards,
|
||||
* so we need to undo the previous record.
|
||||
* If the abort just happened outside the window
|
||||
* the extra entry cannot be removed.
|
||||
*/
|
||||
if (abort && x86_pmu.lbr_double_abort && out > 0)
|
||||
out--;
|
||||
|
||||
cpuc->lbr_entries[out].from = from;
|
||||
cpuc->lbr_entries[out].to = to;
|
||||
cpuc->lbr_entries[out].mispred = mis;
|
||||
cpuc->lbr_entries[out].predicted = pred;
|
||||
cpuc->lbr_entries[out].in_tx = in_tx;
|
||||
cpuc->lbr_entries[out].abort = abort;
|
||||
cpuc->lbr_entries[out].reserved = 0;
|
||||
out++;
|
||||
}
|
||||
cpuc->lbr_stack.nr = i;
|
||||
cpuc->lbr_stack.nr = out;
|
||||
}
|
||||
|
||||
void intel_pmu_lbr_read(void)
|
||||
@ -478,7 +491,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
|
||||
|
||||
/* may fail if text not present */
|
||||
bytes = copy_from_user_nmi(buf, (void __user *)from, size);
|
||||
if (bytes != size)
|
||||
if (bytes != 0)
|
||||
return X86_BR_NONE;
|
||||
|
||||
addr = buf;
|
||||
|
@ -997,6 +997,20 @@ static int snbep_pci2phy_map_init(int devid)
|
||||
}
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
/*
|
||||
* For PCI bus with no UBOX device, find the next bus
|
||||
* that has UBOX device and use its mapping.
|
||||
*/
|
||||
i = -1;
|
||||
for (bus = 255; bus >= 0; bus--) {
|
||||
if (pcibus_to_physid[bus] >= 0)
|
||||
i = pcibus_to_physid[bus];
|
||||
else
|
||||
pcibus_to_physid[bus] = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (ubox_dev)
|
||||
pci_dev_put(ubox_dev);
|
||||
|
||||
@ -1099,6 +1113,24 @@ static struct attribute *ivt_uncore_qpi_formats_attr[] = {
|
||||
&format_attr_umask.attr,
|
||||
&format_attr_edge.attr,
|
||||
&format_attr_thresh8.attr,
|
||||
&format_attr_match_rds.attr,
|
||||
&format_attr_match_rnid30.attr,
|
||||
&format_attr_match_rnid4.attr,
|
||||
&format_attr_match_dnid.attr,
|
||||
&format_attr_match_mc.attr,
|
||||
&format_attr_match_opc.attr,
|
||||
&format_attr_match_vnw.attr,
|
||||
&format_attr_match0.attr,
|
||||
&format_attr_match1.attr,
|
||||
&format_attr_mask_rds.attr,
|
||||
&format_attr_mask_rnid30.attr,
|
||||
&format_attr_mask_rnid4.attr,
|
||||
&format_attr_mask_dnid.attr,
|
||||
&format_attr_mask_mc.attr,
|
||||
&format_attr_mask_opc.attr,
|
||||
&format_attr_mask_vnw.attr,
|
||||
&format_attr_mask0.attr,
|
||||
&format_attr_mask1.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -1312,17 +1344,83 @@ static struct intel_uncore_type ivt_uncore_imc = {
|
||||
IVT_UNCORE_PCI_COMMON_INIT(),
|
||||
};
|
||||
|
||||
/* registers in IRP boxes are not properly aligned */
|
||||
static unsigned ivt_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4};
|
||||
static unsigned ivt_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0};
|
||||
|
||||
static void ivt_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event)
|
||||
{
|
||||
struct pci_dev *pdev = box->pci_dev;
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
|
||||
pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx],
|
||||
hwc->config | SNBEP_PMON_CTL_EN);
|
||||
}
|
||||
|
||||
static void ivt_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event)
|
||||
{
|
||||
struct pci_dev *pdev = box->pci_dev;
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
|
||||
pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], hwc->config);
|
||||
}
|
||||
|
||||
static u64 ivt_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
|
||||
{
|
||||
struct pci_dev *pdev = box->pci_dev;
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
u64 count = 0;
|
||||
|
||||
pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
|
||||
pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct intel_uncore_ops ivt_uncore_irp_ops = {
|
||||
.init_box = ivt_uncore_pci_init_box,
|
||||
.disable_box = snbep_uncore_pci_disable_box,
|
||||
.enable_box = snbep_uncore_pci_enable_box,
|
||||
.disable_event = ivt_uncore_irp_disable_event,
|
||||
.enable_event = ivt_uncore_irp_enable_event,
|
||||
.read_counter = ivt_uncore_irp_read_counter,
|
||||
};
|
||||
|
||||
static struct intel_uncore_type ivt_uncore_irp = {
|
||||
.name = "irp",
|
||||
.num_counters = 4,
|
||||
.num_boxes = 1,
|
||||
.perf_ctr_bits = 48,
|
||||
.event_mask = IVT_PMON_RAW_EVENT_MASK,
|
||||
.box_ctl = SNBEP_PCI_PMON_BOX_CTL,
|
||||
.ops = &ivt_uncore_irp_ops,
|
||||
.format_group = &ivt_uncore_format_group,
|
||||
};
|
||||
|
||||
static struct intel_uncore_ops ivt_uncore_qpi_ops = {
|
||||
.init_box = ivt_uncore_pci_init_box,
|
||||
.disable_box = snbep_uncore_pci_disable_box,
|
||||
.enable_box = snbep_uncore_pci_enable_box,
|
||||
.disable_event = snbep_uncore_pci_disable_event,
|
||||
.enable_event = snbep_qpi_enable_event,
|
||||
.read_counter = snbep_uncore_pci_read_counter,
|
||||
.hw_config = snbep_qpi_hw_config,
|
||||
.get_constraint = uncore_get_constraint,
|
||||
.put_constraint = uncore_put_constraint,
|
||||
};
|
||||
|
||||
static struct intel_uncore_type ivt_uncore_qpi = {
|
||||
.name = "qpi",
|
||||
.num_counters = 4,
|
||||
.num_boxes = 3,
|
||||
.perf_ctr_bits = 48,
|
||||
.perf_ctr = SNBEP_PCI_PMON_CTR0,
|
||||
.event_ctl = SNBEP_PCI_PMON_CTL0,
|
||||
.event_mask = IVT_QPI_PCI_PMON_RAW_EVENT_MASK,
|
||||
.box_ctl = SNBEP_PCI_PMON_BOX_CTL,
|
||||
.ops = &ivt_uncore_pci_ops,
|
||||
.format_group = &ivt_uncore_qpi_format_group,
|
||||
.name = "qpi",
|
||||
.num_counters = 4,
|
||||
.num_boxes = 3,
|
||||
.perf_ctr_bits = 48,
|
||||
.perf_ctr = SNBEP_PCI_PMON_CTR0,
|
||||
.event_ctl = SNBEP_PCI_PMON_CTL0,
|
||||
.event_mask = IVT_QPI_PCI_PMON_RAW_EVENT_MASK,
|
||||
.box_ctl = SNBEP_PCI_PMON_BOX_CTL,
|
||||
.num_shared_regs = 1,
|
||||
.ops = &ivt_uncore_qpi_ops,
|
||||
.format_group = &ivt_uncore_qpi_format_group,
|
||||
};
|
||||
|
||||
static struct intel_uncore_type ivt_uncore_r2pcie = {
|
||||
@ -1346,6 +1444,7 @@ static struct intel_uncore_type ivt_uncore_r3qpi = {
|
||||
enum {
|
||||
IVT_PCI_UNCORE_HA,
|
||||
IVT_PCI_UNCORE_IMC,
|
||||
IVT_PCI_UNCORE_IRP,
|
||||
IVT_PCI_UNCORE_QPI,
|
||||
IVT_PCI_UNCORE_R2PCIE,
|
||||
IVT_PCI_UNCORE_R3QPI,
|
||||
@ -1354,6 +1453,7 @@ enum {
|
||||
static struct intel_uncore_type *ivt_pci_uncores[] = {
|
||||
[IVT_PCI_UNCORE_HA] = &ivt_uncore_ha,
|
||||
[IVT_PCI_UNCORE_IMC] = &ivt_uncore_imc,
|
||||
[IVT_PCI_UNCORE_IRP] = &ivt_uncore_irp,
|
||||
[IVT_PCI_UNCORE_QPI] = &ivt_uncore_qpi,
|
||||
[IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie,
|
||||
[IVT_PCI_UNCORE_R3QPI] = &ivt_uncore_r3qpi,
|
||||
@ -1401,6 +1501,10 @@ static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = {
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7),
|
||||
},
|
||||
{ /* IRP */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IRP, 0),
|
||||
},
|
||||
{ /* QPI0 Port 0 */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0),
|
||||
@ -1429,6 +1533,16 @@ static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = {
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 2),
|
||||
},
|
||||
{ /* QPI Port 0 filter */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
||||
SNBEP_PCI_QPI_PORT0_FILTER),
|
||||
},
|
||||
{ /* QPI Port 0 filter */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96),
|
||||
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
||||
SNBEP_PCI_QPI_PORT1_FILTER),
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
|
||||
|
@ -11,39 +11,26 @@
|
||||
#include <linux/sched.h>
|
||||
|
||||
/*
|
||||
* best effort, GUP based copy_from_user() that is NMI-safe
|
||||
* We rely on the nested NMI work to allow atomic faults from the NMI path; the
|
||||
* nested NMI paths are careful to preserve CR2.
|
||||
*/
|
||||
unsigned long
|
||||
copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
unsigned long offset, addr = (unsigned long)from;
|
||||
unsigned long size, len = 0;
|
||||
struct page *page;
|
||||
void *map;
|
||||
int ret;
|
||||
unsigned long ret;
|
||||
|
||||
if (__range_not_ok(from, n, TASK_SIZE))
|
||||
return len;
|
||||
return 0;
|
||||
|
||||
do {
|
||||
ret = __get_user_pages_fast(addr, 1, 0, &page);
|
||||
if (!ret)
|
||||
break;
|
||||
/*
|
||||
* Even though this function is typically called from NMI/IRQ context
|
||||
* disable pagefaults so that its behaviour is consistent even when
|
||||
* called form other contexts.
|
||||
*/
|
||||
pagefault_disable();
|
||||
ret = __copy_from_user_inatomic(to, from, n);
|
||||
pagefault_enable();
|
||||
|
||||
offset = addr & (PAGE_SIZE - 1);
|
||||
size = min(PAGE_SIZE - offset, n - len);
|
||||
|
||||
map = kmap_atomic(page);
|
||||
memcpy(to, map+offset, size);
|
||||
kunmap_atomic(map);
|
||||
put_page(page);
|
||||
|
||||
len += size;
|
||||
to += size;
|
||||
addr += size;
|
||||
|
||||
} while (len < n);
|
||||
|
||||
return len;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(copy_from_user_nmi);
|
||||
|
@ -51,7 +51,7 @@ kmmio_fault(struct pt_regs *regs, unsigned long addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int __kprobes notify_page_fault(struct pt_regs *regs)
|
||||
static inline int __kprobes kprobes_fault(struct pt_regs *regs)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -1048,7 +1048,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
||||
return;
|
||||
|
||||
/* kprobes don't want to hook the spurious faults: */
|
||||
if (notify_page_fault(regs))
|
||||
if (kprobes_fault(regs))
|
||||
return;
|
||||
/*
|
||||
* Don't take the mm semaphore here. If we fixup a prefetch
|
||||
@ -1060,8 +1060,28 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
||||
}
|
||||
|
||||
/* kprobes don't want to hook the spurious faults: */
|
||||
if (unlikely(notify_page_fault(regs)))
|
||||
if (unlikely(kprobes_fault(regs)))
|
||||
return;
|
||||
|
||||
if (unlikely(error_code & PF_RSVD))
|
||||
pgtable_bad(regs, error_code, address);
|
||||
|
||||
if (static_cpu_has(X86_FEATURE_SMAP)) {
|
||||
if (unlikely(smap_violation(error_code, regs))) {
|
||||
bad_area_nosemaphore(regs, error_code, address);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're in an interrupt, have no user context or are running
|
||||
* in an atomic region then we must not take the fault:
|
||||
*/
|
||||
if (unlikely(in_atomic() || !mm)) {
|
||||
bad_area_nosemaphore(regs, error_code, address);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's safe to allow irq's after cr2 has been saved and the
|
||||
* vmalloc fault has been handled.
|
||||
@ -1078,27 +1098,8 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
if (unlikely(error_code & PF_RSVD))
|
||||
pgtable_bad(regs, error_code, address);
|
||||
|
||||
if (static_cpu_has(X86_FEATURE_SMAP)) {
|
||||
if (unlikely(smap_violation(error_code, regs))) {
|
||||
bad_area_nosemaphore(regs, error_code, address);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
|
||||
/*
|
||||
* If we're in an interrupt, have no user context or are running
|
||||
* in an atomic region then we must not take the fault:
|
||||
*/
|
||||
if (unlikely(in_atomic() || !mm)) {
|
||||
bad_area_nosemaphore(regs, error_code, address);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error_code & PF_WRITE)
|
||||
flags |= FAULT_FLAG_WRITE;
|
||||
|
||||
|
@ -47,7 +47,7 @@ dump_user_backtrace_32(struct stack_frame_ia32 *head)
|
||||
unsigned long bytes;
|
||||
|
||||
bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
|
||||
if (bytes != sizeof(bufhead))
|
||||
if (bytes != 0)
|
||||
return NULL;
|
||||
|
||||
fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
|
||||
@ -93,7 +93,7 @@ static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
|
||||
unsigned long bytes;
|
||||
|
||||
bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
|
||||
if (bytes != sizeof(bufhead))
|
||||
if (bytes != 0)
|
||||
return NULL;
|
||||
|
||||
oprofile_add_trace(bufhead[0].return_address);
|
||||
|
@ -584,6 +584,10 @@ struct perf_sample_data {
|
||||
struct perf_regs_user regs_user;
|
||||
u64 stack_user_size;
|
||||
u64 weight;
|
||||
/*
|
||||
* Transaction flags for abort events:
|
||||
*/
|
||||
u64 txn;
|
||||
};
|
||||
|
||||
static inline void perf_sample_data_init(struct perf_sample_data *data,
|
||||
@ -599,6 +603,7 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
|
||||
data->stack_user_size = 0;
|
||||
data->weight = 0;
|
||||
data->data_src.val = 0;
|
||||
data->txn = 0;
|
||||
}
|
||||
|
||||
extern void perf_output_sample(struct perf_output_handle *handle,
|
||||
|
@ -30,6 +30,7 @@
|
||||
struct vm_area_struct;
|
||||
struct mm_struct;
|
||||
struct inode;
|
||||
struct notifier_block;
|
||||
|
||||
#ifdef CONFIG_ARCH_SUPPORTS_UPROBES
|
||||
# include <asm/uprobes.h>
|
||||
@ -108,6 +109,7 @@ extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsign
|
||||
extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
|
||||
extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
|
||||
extern bool __weak is_trap_insn(uprobe_opcode_t *insn);
|
||||
extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t);
|
||||
extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
|
||||
extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool);
|
||||
extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
|
||||
@ -117,14 +119,21 @@ extern void uprobe_start_dup_mmap(void);
|
||||
extern void uprobe_end_dup_mmap(void);
|
||||
extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm);
|
||||
extern void uprobe_free_utask(struct task_struct *t);
|
||||
extern void uprobe_copy_process(struct task_struct *t);
|
||||
extern void uprobe_copy_process(struct task_struct *t, unsigned long flags);
|
||||
extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
|
||||
extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
|
||||
extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
|
||||
extern void uprobe_notify_resume(struct pt_regs *regs);
|
||||
extern bool uprobe_deny_signal(void);
|
||||
extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern bool arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern void uprobe_clear_state(struct mm_struct *mm);
|
||||
extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
|
||||
extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
|
||||
extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
|
||||
extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
|
||||
extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs);
|
||||
#else /* !CONFIG_UPROBES */
|
||||
struct uprobes_state {
|
||||
};
|
||||
@ -174,7 +183,7 @@ static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
|
||||
static inline void uprobe_free_utask(struct task_struct *t)
|
||||
{
|
||||
}
|
||||
static inline void uprobe_copy_process(struct task_struct *t)
|
||||
static inline void uprobe_copy_process(struct task_struct *t, unsigned long flags)
|
||||
{
|
||||
}
|
||||
static inline void uprobe_clear_state(struct mm_struct *mm)
|
||||
|
@ -136,8 +136,9 @@ enum perf_event_sample_format {
|
||||
PERF_SAMPLE_WEIGHT = 1U << 14,
|
||||
PERF_SAMPLE_DATA_SRC = 1U << 15,
|
||||
PERF_SAMPLE_IDENTIFIER = 1U << 16,
|
||||
PERF_SAMPLE_TRANSACTION = 1U << 17,
|
||||
|
||||
PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
|
||||
PERF_SAMPLE_MAX = 1U << 18, /* non-ABI */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -180,6 +181,28 @@ enum perf_sample_regs_abi {
|
||||
PERF_SAMPLE_REGS_ABI_64 = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* Values for the memory transaction event qualifier, mostly for
|
||||
* abort events. Multiple bits can be set.
|
||||
*/
|
||||
enum {
|
||||
PERF_TXN_ELISION = (1 << 0), /* From elision */
|
||||
PERF_TXN_TRANSACTION = (1 << 1), /* From transaction */
|
||||
PERF_TXN_SYNC = (1 << 2), /* Instruction is related */
|
||||
PERF_TXN_ASYNC = (1 << 3), /* Instruction not related */
|
||||
PERF_TXN_RETRY = (1 << 4), /* Retry possible */
|
||||
PERF_TXN_CONFLICT = (1 << 5), /* Conflict abort */
|
||||
PERF_TXN_CAPACITY_WRITE = (1 << 6), /* Capacity write abort */
|
||||
PERF_TXN_CAPACITY_READ = (1 << 7), /* Capacity read abort */
|
||||
|
||||
PERF_TXN_MAX = (1 << 8), /* non-ABI */
|
||||
|
||||
/* bits 32..63 are reserved for the abort code */
|
||||
|
||||
PERF_TXN_ABORT_MASK = (0xffffffffULL << 32),
|
||||
PERF_TXN_ABORT_SHIFT = 32,
|
||||
};
|
||||
|
||||
/*
|
||||
* The format of the data returned by read() on a perf event fd,
|
||||
* as specified by attr.read_format:
|
||||
|
@ -175,8 +175,8 @@ int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE;
|
||||
static int max_samples_per_tick __read_mostly = DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ);
|
||||
static int perf_sample_period_ns __read_mostly = DEFAULT_SAMPLE_PERIOD_NS;
|
||||
|
||||
static atomic_t perf_sample_allowed_ns __read_mostly =
|
||||
ATOMIC_INIT( DEFAULT_SAMPLE_PERIOD_NS * DEFAULT_CPU_TIME_MAX_PERCENT / 100);
|
||||
static int perf_sample_allowed_ns __read_mostly =
|
||||
DEFAULT_SAMPLE_PERIOD_NS * DEFAULT_CPU_TIME_MAX_PERCENT / 100;
|
||||
|
||||
void update_perf_cpu_limits(void)
|
||||
{
|
||||
@ -184,7 +184,7 @@ void update_perf_cpu_limits(void)
|
||||
|
||||
tmp *= sysctl_perf_cpu_time_max_percent;
|
||||
do_div(tmp, 100);
|
||||
atomic_set(&perf_sample_allowed_ns, tmp);
|
||||
ACCESS_ONCE(perf_sample_allowed_ns) = tmp;
|
||||
}
|
||||
|
||||
static int perf_rotate_context(struct perf_cpu_context *cpuctx);
|
||||
@ -193,7 +193,7 @@ int perf_proc_update_handler(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp,
|
||||
loff_t *ppos)
|
||||
{
|
||||
int ret = proc_dointvec(table, write, buffer, lenp, ppos);
|
||||
int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
||||
|
||||
if (ret || !write)
|
||||
return ret;
|
||||
@ -228,14 +228,15 @@ int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write,
|
||||
* we detect that events are taking too long.
|
||||
*/
|
||||
#define NR_ACCUMULATED_SAMPLES 128
|
||||
DEFINE_PER_CPU(u64, running_sample_length);
|
||||
static DEFINE_PER_CPU(u64, running_sample_length);
|
||||
|
||||
void perf_sample_event_took(u64 sample_len_ns)
|
||||
{
|
||||
u64 avg_local_sample_len;
|
||||
u64 local_samples_len;
|
||||
u64 allowed_ns = ACCESS_ONCE(perf_sample_allowed_ns);
|
||||
|
||||
if (atomic_read(&perf_sample_allowed_ns) == 0)
|
||||
if (allowed_ns == 0)
|
||||
return;
|
||||
|
||||
/* decay the counter by 1 average sample */
|
||||
@ -251,7 +252,7 @@ void perf_sample_event_took(u64 sample_len_ns)
|
||||
*/
|
||||
avg_local_sample_len = local_samples_len/NR_ACCUMULATED_SAMPLES;
|
||||
|
||||
if (avg_local_sample_len <= atomic_read(&perf_sample_allowed_ns))
|
||||
if (avg_local_sample_len <= allowed_ns)
|
||||
return;
|
||||
|
||||
if (max_samples_per_tick <= 1)
|
||||
@ -262,10 +263,9 @@ void perf_sample_event_took(u64 sample_len_ns)
|
||||
perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate;
|
||||
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"perf samples too long (%lld > %d), lowering "
|
||||
"perf samples too long (%lld > %lld), lowering "
|
||||
"kernel.perf_event_max_sample_rate to %d\n",
|
||||
avg_local_sample_len,
|
||||
atomic_read(&perf_sample_allowed_ns),
|
||||
avg_local_sample_len, allowed_ns,
|
||||
sysctl_perf_event_sample_rate);
|
||||
|
||||
update_perf_cpu_limits();
|
||||
@ -899,6 +899,7 @@ static void unclone_ctx(struct perf_event_context *ctx)
|
||||
put_ctx(ctx->parent_ctx);
|
||||
ctx->parent_ctx = NULL;
|
||||
}
|
||||
ctx->generation++;
|
||||
}
|
||||
|
||||
static u32 perf_event_pid(struct perf_event *event, struct task_struct *p)
|
||||
@ -1136,6 +1137,8 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
|
||||
ctx->nr_events++;
|
||||
if (event->attr.inherit_stat)
|
||||
ctx->nr_stat++;
|
||||
|
||||
ctx->generation++;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1201,6 +1204,9 @@ static void perf_event__header_size(struct perf_event *event)
|
||||
if (sample_type & PERF_SAMPLE_DATA_SRC)
|
||||
size += sizeof(data->data_src.val);
|
||||
|
||||
if (sample_type & PERF_SAMPLE_TRANSACTION)
|
||||
size += sizeof(data->txn);
|
||||
|
||||
event->header_size = size;
|
||||
}
|
||||
|
||||
@ -1310,6 +1316,8 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
|
||||
*/
|
||||
if (event->state > PERF_EVENT_STATE_OFF)
|
||||
event->state = PERF_EVENT_STATE_OFF;
|
||||
|
||||
ctx->generation++;
|
||||
}
|
||||
|
||||
static void perf_group_detach(struct perf_event *event)
|
||||
@ -2146,22 +2154,38 @@ static void ctx_sched_out(struct perf_event_context *ctx,
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether two contexts are equivalent, i.e. whether they
|
||||
* have both been cloned from the same version of the same context
|
||||
* and they both have the same number of enabled events.
|
||||
* If the number of enabled events is the same, then the set
|
||||
* of enabled events should be the same, because these are both
|
||||
* inherited contexts, therefore we can't access individual events
|
||||
* in them directly with an fd; we can only enable/disable all
|
||||
* events via prctl, or enable/disable all events in a family
|
||||
* via ioctl, which will have the same effect on both contexts.
|
||||
* Test whether two contexts are equivalent, i.e. whether they have both been
|
||||
* cloned from the same version of the same context.
|
||||
*
|
||||
* Equivalence is measured using a generation number in the context that is
|
||||
* incremented on each modification to it; see unclone_ctx(), list_add_event()
|
||||
* and list_del_event().
|
||||
*/
|
||||
static int context_equiv(struct perf_event_context *ctx1,
|
||||
struct perf_event_context *ctx2)
|
||||
{
|
||||
return ctx1->parent_ctx && ctx1->parent_ctx == ctx2->parent_ctx
|
||||
&& ctx1->parent_gen == ctx2->parent_gen
|
||||
&& !ctx1->pin_count && !ctx2->pin_count;
|
||||
/* Pinning disables the swap optimization */
|
||||
if (ctx1->pin_count || ctx2->pin_count)
|
||||
return 0;
|
||||
|
||||
/* If ctx1 is the parent of ctx2 */
|
||||
if (ctx1 == ctx2->parent_ctx && ctx1->generation == ctx2->parent_gen)
|
||||
return 1;
|
||||
|
||||
/* If ctx2 is the parent of ctx1 */
|
||||
if (ctx1->parent_ctx == ctx2 && ctx1->parent_gen == ctx2->generation)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If ctx1 and ctx2 have the same parent; we flatten the parent
|
||||
* hierarchy, see perf_event_init_context().
|
||||
*/
|
||||
if (ctx1->parent_ctx && ctx1->parent_ctx == ctx2->parent_ctx &&
|
||||
ctx1->parent_gen == ctx2->parent_gen)
|
||||
return 1;
|
||||
|
||||
/* Unmatched */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __perf_event_sync_stat(struct perf_event *event,
|
||||
@ -2244,7 +2268,7 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
|
||||
{
|
||||
struct perf_event_context *ctx = task->perf_event_ctxp[ctxn];
|
||||
struct perf_event_context *next_ctx;
|
||||
struct perf_event_context *parent;
|
||||
struct perf_event_context *parent, *next_parent;
|
||||
struct perf_cpu_context *cpuctx;
|
||||
int do_switch = 1;
|
||||
|
||||
@ -2256,10 +2280,18 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
parent = rcu_dereference(ctx->parent_ctx);
|
||||
next_ctx = next->perf_event_ctxp[ctxn];
|
||||
if (parent && next_ctx &&
|
||||
rcu_dereference(next_ctx->parent_ctx) == parent) {
|
||||
if (!next_ctx)
|
||||
goto unlock;
|
||||
|
||||
parent = rcu_dereference(ctx->parent_ctx);
|
||||
next_parent = rcu_dereference(next_ctx->parent_ctx);
|
||||
|
||||
/* If neither context have a parent context; they cannot be clones. */
|
||||
if (!parent && !next_parent)
|
||||
goto unlock;
|
||||
|
||||
if (next_parent == ctx || next_ctx == parent || next_parent == parent) {
|
||||
/*
|
||||
* Looks like the two contexts are clones, so we might be
|
||||
* able to optimize the context switch. We lock both
|
||||
@ -2287,6 +2319,7 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
|
||||
raw_spin_unlock(&next_ctx->lock);
|
||||
raw_spin_unlock(&ctx->lock);
|
||||
}
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
if (do_switch) {
|
||||
@ -4572,6 +4605,9 @@ void perf_output_sample(struct perf_output_handle *handle,
|
||||
if (sample_type & PERF_SAMPLE_DATA_SRC)
|
||||
perf_output_put(handle, data->data_src.val);
|
||||
|
||||
if (sample_type & PERF_SAMPLE_TRANSACTION)
|
||||
perf_output_put(handle, data->txn);
|
||||
|
||||
if (!event->attr.watermark) {
|
||||
int wakeup_events = event->attr.wakeup_events;
|
||||
|
||||
@ -5100,27 +5136,26 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
|
||||
unsigned int size;
|
||||
char tmp[16];
|
||||
char *buf = NULL;
|
||||
const char *name;
|
||||
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
char *name;
|
||||
|
||||
if (file) {
|
||||
struct inode *inode;
|
||||
dev_t dev;
|
||||
|
||||
buf = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
name = "//enomem";
|
||||
goto cpy_name;
|
||||
}
|
||||
/*
|
||||
* d_path works from the end of the rb backwards, so we
|
||||
* d_path() works from the end of the rb backwards, so we
|
||||
* need to add enough zero bytes after the string to handle
|
||||
* the 64bit alignment we do later.
|
||||
*/
|
||||
buf = kzalloc(PATH_MAX + sizeof(u64), GFP_KERNEL);
|
||||
if (!buf) {
|
||||
name = strncpy(tmp, "//enomem", sizeof(tmp));
|
||||
goto got_name;
|
||||
}
|
||||
name = d_path(&file->f_path, buf, PATH_MAX);
|
||||
name = d_path(&file->f_path, buf, PATH_MAX - sizeof(u64));
|
||||
if (IS_ERR(name)) {
|
||||
name = strncpy(tmp, "//toolong", sizeof(tmp));
|
||||
goto got_name;
|
||||
name = "//toolong";
|
||||
goto cpy_name;
|
||||
}
|
||||
inode = file_inode(vma->vm_file);
|
||||
dev = inode->i_sb->s_dev;
|
||||
@ -5128,34 +5163,39 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
|
||||
gen = inode->i_generation;
|
||||
maj = MAJOR(dev);
|
||||
min = MINOR(dev);
|
||||
|
||||
} else {
|
||||
if (arch_vma_name(mmap_event->vma)) {
|
||||
name = strncpy(tmp, arch_vma_name(mmap_event->vma),
|
||||
sizeof(tmp) - 1);
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
goto got_name;
|
||||
}
|
||||
|
||||
if (!vma->vm_mm) {
|
||||
name = strncpy(tmp, "[vdso]", sizeof(tmp));
|
||||
goto got_name;
|
||||
} else if (vma->vm_start <= vma->vm_mm->start_brk &&
|
||||
vma->vm_end >= vma->vm_mm->brk) {
|
||||
name = strncpy(tmp, "[heap]", sizeof(tmp));
|
||||
goto got_name;
|
||||
} else if (vma->vm_start <= vma->vm_mm->start_stack &&
|
||||
vma->vm_end >= vma->vm_mm->start_stack) {
|
||||
name = strncpy(tmp, "[stack]", sizeof(tmp));
|
||||
goto got_name;
|
||||
}
|
||||
|
||||
name = strncpy(tmp, "//anon", sizeof(tmp));
|
||||
goto got_name;
|
||||
} else {
|
||||
name = (char *)arch_vma_name(vma);
|
||||
if (name)
|
||||
goto cpy_name;
|
||||
|
||||
if (vma->vm_start <= vma->vm_mm->start_brk &&
|
||||
vma->vm_end >= vma->vm_mm->brk) {
|
||||
name = "[heap]";
|
||||
goto cpy_name;
|
||||
}
|
||||
if (vma->vm_start <= vma->vm_mm->start_stack &&
|
||||
vma->vm_end >= vma->vm_mm->start_stack) {
|
||||
name = "[stack]";
|
||||
goto cpy_name;
|
||||
}
|
||||
|
||||
name = "//anon";
|
||||
goto cpy_name;
|
||||
}
|
||||
|
||||
cpy_name:
|
||||
strlcpy(tmp, name, sizeof(tmp));
|
||||
name = tmp;
|
||||
got_name:
|
||||
size = ALIGN(strlen(name)+1, sizeof(u64));
|
||||
/*
|
||||
* Since our buffer works in 8 byte units we need to align our string
|
||||
* size to a multiple of 8. However, we must guarantee the tail end is
|
||||
* zero'd out to avoid leaking random bits to userspace.
|
||||
*/
|
||||
size = strlen(name)+1;
|
||||
while (!IS_ALIGNED(size, sizeof(u64)))
|
||||
name[size++] = '\0';
|
||||
|
||||
mmap_event->file_name = name;
|
||||
mmap_event->file_size = size;
|
||||
@ -7129,7 +7169,6 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||
}
|
||||
|
||||
perf_install_in_context(ctx, event, event->cpu);
|
||||
++ctx->generation;
|
||||
perf_unpin_context(ctx);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
|
||||
@ -7212,7 +7251,6 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
|
||||
WARN_ON_ONCE(ctx->parent_ctx);
|
||||
mutex_lock(&ctx->mutex);
|
||||
perf_install_in_context(ctx, event, cpu);
|
||||
++ctx->generation;
|
||||
perf_unpin_context(ctx);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
|
||||
|
@ -82,16 +82,16 @@ static inline unsigned long perf_data_size(struct ring_buffer *rb)
|
||||
}
|
||||
|
||||
#define DEFINE_OUTPUT_COPY(func_name, memcpy_func) \
|
||||
static inline unsigned int \
|
||||
static inline unsigned long \
|
||||
func_name(struct perf_output_handle *handle, \
|
||||
const void *buf, unsigned int len) \
|
||||
const void *buf, unsigned long len) \
|
||||
{ \
|
||||
unsigned long size, written; \
|
||||
\
|
||||
do { \
|
||||
size = min_t(unsigned long, handle->size, len); \
|
||||
\
|
||||
size = min(handle->size, len); \
|
||||
written = memcpy_func(handle->addr, buf, size); \
|
||||
written = size - written; \
|
||||
\
|
||||
len -= written; \
|
||||
handle->addr += written; \
|
||||
@ -110,20 +110,37 @@ func_name(struct perf_output_handle *handle, \
|
||||
return len; \
|
||||
}
|
||||
|
||||
static inline int memcpy_common(void *dst, const void *src, size_t n)
|
||||
static inline unsigned long
|
||||
memcpy_common(void *dst, const void *src, unsigned long n)
|
||||
{
|
||||
memcpy(dst, src, n);
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_OUTPUT_COPY(__output_copy, memcpy_common)
|
||||
|
||||
#define MEMCPY_SKIP(dst, src, n) (n)
|
||||
static inline unsigned long
|
||||
memcpy_skip(void *dst, const void *src, unsigned long n)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_OUTPUT_COPY(__output_skip, MEMCPY_SKIP)
|
||||
DEFINE_OUTPUT_COPY(__output_skip, memcpy_skip)
|
||||
|
||||
#ifndef arch_perf_out_copy_user
|
||||
#define arch_perf_out_copy_user __copy_from_user_inatomic
|
||||
#define arch_perf_out_copy_user arch_perf_out_copy_user
|
||||
|
||||
static inline unsigned long
|
||||
arch_perf_out_copy_user(void *dst, const void *src, unsigned long n)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
pagefault_disable();
|
||||
ret = __copy_from_user_inatomic(dst, src, n);
|
||||
pagefault_enable();
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEFINE_OUTPUT_COPY(__output_copy_user, arch_perf_out_copy_user)
|
||||
|
@ -12,40 +12,10 @@
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/circ_buf.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
static bool perf_output_space(struct ring_buffer *rb, unsigned long tail,
|
||||
unsigned long offset, unsigned long head)
|
||||
{
|
||||
unsigned long sz = perf_data_size(rb);
|
||||
unsigned long mask = sz - 1;
|
||||
|
||||
/*
|
||||
* check if user-writable
|
||||
* overwrite : over-write its own tail
|
||||
* !overwrite: buffer possibly drops events.
|
||||
*/
|
||||
if (rb->overwrite)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* verify that payload is not bigger than buffer
|
||||
* otherwise masking logic may fail to detect
|
||||
* the "not enough space" condition
|
||||
*/
|
||||
if ((head - offset) > sz)
|
||||
return false;
|
||||
|
||||
offset = (offset - tail) & mask;
|
||||
head = (head - tail) & mask;
|
||||
|
||||
if ((int)(head - offset) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void perf_output_wakeup(struct perf_output_handle *handle)
|
||||
{
|
||||
atomic_set(&handle->rb->poll, POLL_IN);
|
||||
@ -115,8 +85,8 @@ again:
|
||||
rb->user_page->data_head = head;
|
||||
|
||||
/*
|
||||
* Now check if we missed an update, rely on the (compiler)
|
||||
* barrier in atomic_dec_and_test() to re-read rb->head.
|
||||
* Now check if we missed an update -- rely on previous implied
|
||||
* compiler barriers to force a re-read.
|
||||
*/
|
||||
if (unlikely(head != local_read(&rb->head))) {
|
||||
local_inc(&rb->nest);
|
||||
@ -135,8 +105,7 @@ int perf_output_begin(struct perf_output_handle *handle,
|
||||
{
|
||||
struct ring_buffer *rb;
|
||||
unsigned long tail, offset, head;
|
||||
int have_lost;
|
||||
struct perf_sample_data sample_data;
|
||||
int have_lost, page_shift;
|
||||
struct {
|
||||
struct perf_event_header header;
|
||||
u64 id;
|
||||
@ -151,57 +120,63 @@ int perf_output_begin(struct perf_output_handle *handle,
|
||||
event = event->parent;
|
||||
|
||||
rb = rcu_dereference(event->rb);
|
||||
if (!rb)
|
||||
if (unlikely(!rb))
|
||||
goto out;
|
||||
|
||||
handle->rb = rb;
|
||||
handle->event = event;
|
||||
|
||||
if (!rb->nr_pages)
|
||||
if (unlikely(!rb->nr_pages))
|
||||
goto out;
|
||||
|
||||
handle->rb = rb;
|
||||
handle->event = event;
|
||||
|
||||
have_lost = local_read(&rb->lost);
|
||||
if (have_lost) {
|
||||
lost_event.header.size = sizeof(lost_event);
|
||||
perf_event_header__init_id(&lost_event.header, &sample_data,
|
||||
event);
|
||||
size += lost_event.header.size;
|
||||
if (unlikely(have_lost)) {
|
||||
size += sizeof(lost_event);
|
||||
if (event->attr.sample_id_all)
|
||||
size += event->id_header_size;
|
||||
}
|
||||
|
||||
perf_output_get_handle(handle);
|
||||
|
||||
do {
|
||||
/*
|
||||
* Userspace could choose to issue a mb() before updating the
|
||||
* tail pointer. So that all reads will be completed before the
|
||||
* write is issued.
|
||||
*
|
||||
* See perf_output_put_handle().
|
||||
*/
|
||||
tail = ACCESS_ONCE(rb->user_page->data_tail);
|
||||
smp_mb();
|
||||
offset = head = local_read(&rb->head);
|
||||
head += size;
|
||||
if (unlikely(!perf_output_space(rb, tail, offset, head)))
|
||||
if (!rb->overwrite &&
|
||||
unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size))
|
||||
goto fail;
|
||||
head += size;
|
||||
} while (local_cmpxchg(&rb->head, offset, head) != offset);
|
||||
|
||||
if (head - local_read(&rb->wakeup) > rb->watermark)
|
||||
/*
|
||||
* Separate the userpage->tail read from the data stores below.
|
||||
* Matches the MB userspace SHOULD issue after reading the data
|
||||
* and before storing the new tail position.
|
||||
*
|
||||
* See perf_output_put_handle().
|
||||
*/
|
||||
smp_mb();
|
||||
|
||||
if (unlikely(head - local_read(&rb->wakeup) > rb->watermark))
|
||||
local_add(rb->watermark, &rb->wakeup);
|
||||
|
||||
handle->page = offset >> (PAGE_SHIFT + page_order(rb));
|
||||
handle->page &= rb->nr_pages - 1;
|
||||
handle->size = offset & ((PAGE_SIZE << page_order(rb)) - 1);
|
||||
handle->addr = rb->data_pages[handle->page];
|
||||
handle->addr += handle->size;
|
||||
handle->size = (PAGE_SIZE << page_order(rb)) - handle->size;
|
||||
page_shift = PAGE_SHIFT + page_order(rb);
|
||||
|
||||
if (have_lost) {
|
||||
handle->page = (offset >> page_shift) & (rb->nr_pages - 1);
|
||||
offset &= (1UL << page_shift) - 1;
|
||||
handle->addr = rb->data_pages[handle->page] + offset;
|
||||
handle->size = (1UL << page_shift) - offset;
|
||||
|
||||
if (unlikely(have_lost)) {
|
||||
struct perf_sample_data sample_data;
|
||||
|
||||
lost_event.header.size = sizeof(lost_event);
|
||||
lost_event.header.type = PERF_RECORD_LOST;
|
||||
lost_event.header.misc = 0;
|
||||
lost_event.id = event->id;
|
||||
lost_event.lost = local_xchg(&rb->lost, 0);
|
||||
|
||||
perf_event_header__init_id(&lost_event.header,
|
||||
&sample_data, event);
|
||||
perf_output_put(handle, lost_event);
|
||||
perf_event__output_id_sample(event, handle, &sample_data);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/kdebug.h> /* notifier mechanism */
|
||||
#include "../../mm/internal.h" /* munlock_vma_page */
|
||||
#include <linux/percpu-rwsem.h>
|
||||
#include <linux/task_work.h>
|
||||
|
||||
#include <linux/uprobes.h>
|
||||
|
||||
@ -244,12 +245,12 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
|
||||
* the architecture. If an arch has variable length instruction and the
|
||||
* breakpoint instruction is not of the smallest length instruction
|
||||
* supported by that architecture then we need to modify is_trap_at_addr and
|
||||
* write_opcode accordingly. This would never be a problem for archs that
|
||||
* have fixed length instructions.
|
||||
* uprobe_write_opcode accordingly. This would never be a problem for archs
|
||||
* that have fixed length instructions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* write_opcode - write the opcode at a given virtual address.
|
||||
* uprobe_write_opcode - write the opcode at a given virtual address.
|
||||
* @mm: the probed process address space.
|
||||
* @vaddr: the virtual address to store the opcode.
|
||||
* @opcode: opcode to be written at @vaddr.
|
||||
@ -260,7 +261,7 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
|
||||
* For mm @mm, write the opcode at @vaddr.
|
||||
* Return 0 (success) or a negative errno.
|
||||
*/
|
||||
static int write_opcode(struct mm_struct *mm, unsigned long vaddr,
|
||||
int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
|
||||
uprobe_opcode_t opcode)
|
||||
{
|
||||
struct page *old_page, *new_page;
|
||||
@ -314,7 +315,7 @@ put_old:
|
||||
*/
|
||||
int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
|
||||
{
|
||||
return write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
|
||||
return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,7 +330,7 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned
|
||||
int __weak
|
||||
set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
|
||||
{
|
||||
return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
|
||||
return uprobe_write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
|
||||
}
|
||||
|
||||
static int match_uprobe(struct uprobe *l, struct uprobe *r)
|
||||
@ -503,9 +504,8 @@ static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
__copy_insn(struct address_space *mapping, struct file *filp, char *insn,
|
||||
unsigned long nbytes, loff_t offset)
|
||||
static int __copy_insn(struct address_space *mapping, struct file *filp,
|
||||
void *insn, int nbytes, loff_t offset)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
@ -527,28 +527,28 @@ __copy_insn(struct address_space *mapping, struct file *filp, char *insn,
|
||||
|
||||
static int copy_insn(struct uprobe *uprobe, struct file *filp)
|
||||
{
|
||||
struct address_space *mapping;
|
||||
unsigned long nbytes;
|
||||
int bytes;
|
||||
struct address_space *mapping = uprobe->inode->i_mapping;
|
||||
loff_t offs = uprobe->offset;
|
||||
void *insn = uprobe->arch.insn;
|
||||
int size = MAX_UINSN_BYTES;
|
||||
int len, err = -EIO;
|
||||
|
||||
nbytes = PAGE_SIZE - (uprobe->offset & ~PAGE_MASK);
|
||||
mapping = uprobe->inode->i_mapping;
|
||||
/* Copy only available bytes, -EIO if nothing was read */
|
||||
do {
|
||||
if (offs >= i_size_read(uprobe->inode))
|
||||
break;
|
||||
|
||||
/* Instruction at end of binary; copy only available bytes */
|
||||
if (uprobe->offset + MAX_UINSN_BYTES > uprobe->inode->i_size)
|
||||
bytes = uprobe->inode->i_size - uprobe->offset;
|
||||
else
|
||||
bytes = MAX_UINSN_BYTES;
|
||||
|
||||
/* Instruction at the page-boundary; copy bytes in second page */
|
||||
if (nbytes < bytes) {
|
||||
int err = __copy_insn(mapping, filp, uprobe->arch.insn + nbytes,
|
||||
bytes - nbytes, uprobe->offset + nbytes);
|
||||
len = min_t(int, size, PAGE_SIZE - (offs & ~PAGE_MASK));
|
||||
err = __copy_insn(mapping, filp, insn, len, offs);
|
||||
if (err)
|
||||
return err;
|
||||
bytes = nbytes;
|
||||
}
|
||||
return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset);
|
||||
break;
|
||||
|
||||
insn += len;
|
||||
offs += len;
|
||||
size -= len;
|
||||
} while (size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
|
||||
@ -576,7 +576,7 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* write_opcode() assumes we don't cross page boundary */
|
||||
/* uprobe_write_opcode() assumes we don't cross page boundary */
|
||||
BUG_ON((uprobe->offset & ~PAGE_MASK) +
|
||||
UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
|
||||
|
||||
@ -1096,21 +1096,22 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
|
||||
}
|
||||
|
||||
/* Slot allocation for XOL */
|
||||
static int xol_add_vma(struct xol_area *area)
|
||||
static int xol_add_vma(struct mm_struct *mm, struct xol_area *area)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
int ret = -EALREADY;
|
||||
|
||||
down_write(&mm->mmap_sem);
|
||||
if (mm->uprobes_state.xol_area)
|
||||
goto fail;
|
||||
|
||||
ret = -ENOMEM;
|
||||
/* Try to map as high as possible, this is only a hint. */
|
||||
area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0);
|
||||
if (area->vaddr & ~PAGE_MASK) {
|
||||
ret = area->vaddr;
|
||||
goto fail;
|
||||
if (!area->vaddr) {
|
||||
/* Try to map as high as possible, this is only a hint. */
|
||||
area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE,
|
||||
PAGE_SIZE, 0, 0);
|
||||
if (area->vaddr & ~PAGE_MASK) {
|
||||
ret = area->vaddr;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = install_special_mapping(mm, area->vaddr, PAGE_SIZE,
|
||||
@ -1120,13 +1121,49 @@ static int xol_add_vma(struct xol_area *area)
|
||||
|
||||
smp_wmb(); /* pairs with get_xol_area() */
|
||||
mm->uprobes_state.xol_area = area;
|
||||
ret = 0;
|
||||
fail:
|
||||
up_write(&mm->mmap_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct xol_area *__create_xol_area(unsigned long vaddr)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
uprobe_opcode_t insn = UPROBE_SWBP_INSN;
|
||||
struct xol_area *area;
|
||||
|
||||
area = kmalloc(sizeof(*area), GFP_KERNEL);
|
||||
if (unlikely(!area))
|
||||
goto out;
|
||||
|
||||
area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL);
|
||||
if (!area->bitmap)
|
||||
goto free_area;
|
||||
|
||||
area->page = alloc_page(GFP_HIGHUSER);
|
||||
if (!area->page)
|
||||
goto free_bitmap;
|
||||
|
||||
area->vaddr = vaddr;
|
||||
init_waitqueue_head(&area->wq);
|
||||
/* Reserve the 1st slot for get_trampoline_vaddr() */
|
||||
set_bit(0, area->bitmap);
|
||||
atomic_set(&area->slot_count, 1);
|
||||
copy_to_page(area->page, 0, &insn, UPROBE_SWBP_INSN_SIZE);
|
||||
|
||||
if (!xol_add_vma(mm, area))
|
||||
return area;
|
||||
|
||||
__free_page(area->page);
|
||||
free_bitmap:
|
||||
kfree(area->bitmap);
|
||||
free_area:
|
||||
kfree(area);
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_xol_area - Allocate process's xol_area if necessary.
|
||||
* This area will be used for storing instructions for execution out of line.
|
||||
@ -1137,42 +1174,12 @@ static struct xol_area *get_xol_area(void)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct xol_area *area;
|
||||
uprobe_opcode_t insn = UPROBE_SWBP_INSN;
|
||||
|
||||
if (!mm->uprobes_state.xol_area)
|
||||
__create_xol_area(0);
|
||||
|
||||
area = mm->uprobes_state.xol_area;
|
||||
if (area)
|
||||
goto ret;
|
||||
|
||||
area = kzalloc(sizeof(*area), GFP_KERNEL);
|
||||
if (unlikely(!area))
|
||||
goto out;
|
||||
|
||||
area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL);
|
||||
if (!area->bitmap)
|
||||
goto free_area;
|
||||
|
||||
area->page = alloc_page(GFP_HIGHUSER);
|
||||
if (!area->page)
|
||||
goto free_bitmap;
|
||||
|
||||
/* allocate first slot of task's xol_area for the return probes */
|
||||
set_bit(0, area->bitmap);
|
||||
copy_to_page(area->page, 0, &insn, UPROBE_SWBP_INSN_SIZE);
|
||||
atomic_set(&area->slot_count, 1);
|
||||
init_waitqueue_head(&area->wq);
|
||||
|
||||
if (!xol_add_vma(area))
|
||||
return area;
|
||||
|
||||
__free_page(area->page);
|
||||
free_bitmap:
|
||||
kfree(area->bitmap);
|
||||
free_area:
|
||||
kfree(area);
|
||||
out:
|
||||
area = mm->uprobes_state.xol_area;
|
||||
ret:
|
||||
smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */
|
||||
smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */
|
||||
return area;
|
||||
}
|
||||
|
||||
@ -1256,7 +1263,8 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
|
||||
return 0;
|
||||
|
||||
/* Initialize the slot */
|
||||
copy_to_page(area->page, xol_vaddr, uprobe->arch.insn, MAX_UINSN_BYTES);
|
||||
copy_to_page(area->page, xol_vaddr,
|
||||
uprobe->arch.ixol, sizeof(uprobe->arch.ixol));
|
||||
/*
|
||||
* We probably need flush_icache_user_range() but it needs vma.
|
||||
* This should work on supported architectures too.
|
||||
@ -1344,14 +1352,6 @@ void uprobe_free_utask(struct task_struct *t)
|
||||
t->utask = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called in context of a new clone/fork from copy_process.
|
||||
*/
|
||||
void uprobe_copy_process(struct task_struct *t)
|
||||
{
|
||||
t->utask = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a uprobe_task object for the task if if necessary.
|
||||
* Called when the thread hits a breakpoint.
|
||||
@ -1367,6 +1367,90 @@ static struct uprobe_task *get_utask(void)
|
||||
return current->utask;
|
||||
}
|
||||
|
||||
static int dup_utask(struct task_struct *t, struct uprobe_task *o_utask)
|
||||
{
|
||||
struct uprobe_task *n_utask;
|
||||
struct return_instance **p, *o, *n;
|
||||
|
||||
n_utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL);
|
||||
if (!n_utask)
|
||||
return -ENOMEM;
|
||||
t->utask = n_utask;
|
||||
|
||||
p = &n_utask->return_instances;
|
||||
for (o = o_utask->return_instances; o; o = o->next) {
|
||||
n = kmalloc(sizeof(struct return_instance), GFP_KERNEL);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
*n = *o;
|
||||
atomic_inc(&n->uprobe->ref);
|
||||
n->next = NULL;
|
||||
|
||||
*p = n;
|
||||
p = &n->next;
|
||||
n_utask->depth++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uprobe_warn(struct task_struct *t, const char *msg)
|
||||
{
|
||||
pr_warn("uprobe: %s:%d failed to %s\n",
|
||||
current->comm, current->pid, msg);
|
||||
}
|
||||
|
||||
static void dup_xol_work(struct callback_head *work)
|
||||
{
|
||||
kfree(work);
|
||||
|
||||
if (current->flags & PF_EXITING)
|
||||
return;
|
||||
|
||||
if (!__create_xol_area(current->utask->vaddr))
|
||||
uprobe_warn(current, "dup xol area");
|
||||
}
|
||||
|
||||
/*
|
||||
* Called in context of a new clone/fork from copy_process.
|
||||
*/
|
||||
void uprobe_copy_process(struct task_struct *t, unsigned long flags)
|
||||
{
|
||||
struct uprobe_task *utask = current->utask;
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct callback_head *work;
|
||||
struct xol_area *area;
|
||||
|
||||
t->utask = NULL;
|
||||
|
||||
if (!utask || !utask->return_instances)
|
||||
return;
|
||||
|
||||
if (mm == t->mm && !(flags & CLONE_VFORK))
|
||||
return;
|
||||
|
||||
if (dup_utask(t, utask))
|
||||
return uprobe_warn(t, "dup ret instances");
|
||||
|
||||
/* The task can fork() after dup_xol_work() fails */
|
||||
area = mm->uprobes_state.xol_area;
|
||||
if (!area)
|
||||
return uprobe_warn(t, "dup xol area");
|
||||
|
||||
if (mm == t->mm)
|
||||
return;
|
||||
|
||||
/* TODO: move it into the union in uprobe_task */
|
||||
work = kmalloc(sizeof(*work), GFP_KERNEL);
|
||||
if (!work)
|
||||
return uprobe_warn(t, "dup xol area");
|
||||
|
||||
t->utask->vaddr = area->vaddr;
|
||||
init_task_work(work, dup_xol_work);
|
||||
task_work_add(t, work, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Current area->vaddr notion assume the trampoline address is always
|
||||
* equal area->vaddr.
|
||||
@ -1857,9 +1941,4 @@ static int __init init_uprobes(void)
|
||||
|
||||
return register_die_notifier(&uprobe_exception_nb);
|
||||
}
|
||||
module_init(init_uprobes);
|
||||
|
||||
static void __exit exit_uprobes(void)
|
||||
{
|
||||
}
|
||||
module_exit(exit_uprobes);
|
||||
__initcall(init_uprobes);
|
||||
|
@ -1373,7 +1373,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||||
INIT_LIST_HEAD(&p->pi_state_list);
|
||||
p->pi_state_cache = NULL;
|
||||
#endif
|
||||
uprobe_copy_process(p);
|
||||
/*
|
||||
* sigaltstack should be cleared when sharing the same VM
|
||||
*/
|
||||
@ -1490,6 +1489,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||||
perf_event_fork(p);
|
||||
|
||||
trace_task_newtask(p, clone_flags);
|
||||
uprobe_copy_process(p, clone_flags);
|
||||
|
||||
return p;
|
||||
|
||||
|
@ -1049,6 +1049,7 @@ static struct ctl_table kern_table[] = {
|
||||
.maxlen = sizeof(sysctl_perf_event_sample_rate),
|
||||
.mode = 0644,
|
||||
.proc_handler = perf_proc_update_handler,
|
||||
.extra1 = &one,
|
||||
},
|
||||
{
|
||||
.procname = "perf_cpu_time_max_percent",
|
||||
|
@ -115,7 +115,9 @@ git --git-dir=$(srctree)/.git archive --prefix=$(perf-tar)/ \
|
||||
-o $(perf-tar).tar; \
|
||||
mkdir -p $(perf-tar); \
|
||||
git --git-dir=$(srctree)/.git rev-parse HEAD > $(perf-tar)/HEAD; \
|
||||
tar rf $(perf-tar).tar $(perf-tar)/HEAD; \
|
||||
(cd $(srctree)/tools/perf; \
|
||||
util/PERF-VERSION-GEN ../../$(perf-tar)/ 2>/dev/null); \
|
||||
tar rf $(perf-tar).tar $(perf-tar)/HEAD $(perf-tar)/PERF-VERSION-FILE; \
|
||||
rm -r $(perf-tar); \
|
||||
$(if $(findstring tar-src,$@),, \
|
||||
$(if $(findstring bz2,$@),bzip2, \
|
||||
|
@ -134,14 +134,14 @@ ifeq ($(VERBOSE),1)
|
||||
print_install =
|
||||
else
|
||||
Q = @
|
||||
print_compile = echo ' CC '$(OBJ);
|
||||
print_app_build = echo ' BUILD '$(OBJ);
|
||||
print_fpic_compile = echo ' CC FPIC '$(OBJ);
|
||||
print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
|
||||
print_plugin_obj_compile = echo ' CC PLUGIN OBJ '$(OBJ);
|
||||
print_plugin_build = echo ' CC PLUGI '$(OBJ);
|
||||
print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
|
||||
print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
|
||||
print_compile = echo ' CC '$(OBJ);
|
||||
print_app_build = echo ' BUILD '$(OBJ);
|
||||
print_fpic_compile = echo ' CC FPIC '$(OBJ);
|
||||
print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
|
||||
print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ);
|
||||
print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
|
||||
print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
|
||||
print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
|
||||
endif
|
||||
|
||||
do_fpic_compile = \
|
||||
@ -268,7 +268,7 @@ TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
|
||||
TRACEEVENT-CFLAGS: force
|
||||
@FLAGS='$(TRACK_CFLAGS)'; \
|
||||
if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
|
||||
echo 1>&2 " * new build flags or cross compiler"; \
|
||||
echo 1>&2 " FLAGS: * new build flags or cross compiler"; \
|
||||
echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
|
||||
fi
|
||||
|
||||
|
@ -305,6 +305,11 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock)
|
||||
{
|
||||
pevent->trace_clock = trace_clock;
|
||||
}
|
||||
|
||||
struct func_map {
|
||||
unsigned long long addr;
|
||||
char *func;
|
||||
@ -599,10 +604,11 @@ find_printk(struct pevent *pevent, unsigned long long addr)
|
||||
* This registers a string by the address it was stored in the kernel.
|
||||
* The @fmt passed in is duplicated.
|
||||
*/
|
||||
int pevent_register_print_string(struct pevent *pevent, char *fmt,
|
||||
int pevent_register_print_string(struct pevent *pevent, const char *fmt,
|
||||
unsigned long long addr)
|
||||
{
|
||||
struct printk_list *item = malloc(sizeof(*item));
|
||||
char *p;
|
||||
|
||||
if (!item)
|
||||
return -1;
|
||||
@ -610,10 +616,21 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
|
||||
item->next = pevent->printklist;
|
||||
item->addr = addr;
|
||||
|
||||
/* Strip off quotes and '\n' from the end */
|
||||
if (fmt[0] == '"')
|
||||
fmt++;
|
||||
item->printk = strdup(fmt);
|
||||
if (!item->printk)
|
||||
goto out_free;
|
||||
|
||||
p = item->printk + strlen(item->printk) - 1;
|
||||
if (*p == '"')
|
||||
*p = 0;
|
||||
|
||||
p -= 2;
|
||||
if (strcmp(p, "\\n") == 0)
|
||||
*p = 0;
|
||||
|
||||
pevent->printklist = item;
|
||||
pevent->printk_count++;
|
||||
|
||||
@ -3488,6 +3505,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||
struct pevent *pevent = event->pevent;
|
||||
struct print_flag_sym *flag;
|
||||
struct format_field *field;
|
||||
struct printk_map *printk;
|
||||
unsigned long long val, fval;
|
||||
unsigned long addr;
|
||||
char *str;
|
||||
@ -3523,7 +3541,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||
if (!(field->flags & FIELD_IS_ARRAY) &&
|
||||
field->size == pevent->long_size) {
|
||||
addr = *(unsigned long *)(data + field->offset);
|
||||
trace_seq_printf(s, "%lx", addr);
|
||||
/* Check if it matches a print format */
|
||||
printk = find_printk(pevent, addr);
|
||||
if (printk)
|
||||
trace_seq_puts(s, printk->printk);
|
||||
else
|
||||
trace_seq_printf(s, "%lx", addr);
|
||||
break;
|
||||
}
|
||||
str = malloc(len + 1);
|
||||
@ -3565,15 +3588,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||
}
|
||||
break;
|
||||
case PRINT_HEX:
|
||||
field = arg->hex.field->field.field;
|
||||
if (!field) {
|
||||
str = arg->hex.field->field.name;
|
||||
field = pevent_find_any_field(event, str);
|
||||
if (!field)
|
||||
goto out_warning_field;
|
||||
arg->hex.field->field.field = field;
|
||||
if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) {
|
||||
unsigned long offset;
|
||||
offset = pevent_read_number(pevent,
|
||||
data + arg->hex.field->dynarray.field->offset,
|
||||
arg->hex.field->dynarray.field->size);
|
||||
hex = data + (offset & 0xffff);
|
||||
} else {
|
||||
field = arg->hex.field->field.field;
|
||||
if (!field) {
|
||||
str = arg->hex.field->field.name;
|
||||
field = pevent_find_any_field(event, str);
|
||||
if (!field)
|
||||
goto out_warning_field;
|
||||
arg->hex.field->field.field = field;
|
||||
}
|
||||
hex = data + field->offset;
|
||||
}
|
||||
hex = data + field->offset;
|
||||
len = eval_num_arg(data, size, event, arg->hex.size);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i)
|
||||
@ -3771,8 +3802,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||
if (asprintf(&arg->atom.atom, "%lld", ip) < 0)
|
||||
goto out_free;
|
||||
|
||||
/* skip the first "%pf : " */
|
||||
for (ptr = fmt + 6, bptr = data + field->offset;
|
||||
/* skip the first "%pf: " */
|
||||
for (ptr = fmt + 5, bptr = data + field->offset;
|
||||
bptr < data + size && *ptr; ptr++) {
|
||||
int ls = 0;
|
||||
|
||||
@ -3882,7 +3913,6 @@ get_bprint_format(void *data, int size __maybe_unused,
|
||||
struct format_field *field;
|
||||
struct printk_map *printk;
|
||||
char *format;
|
||||
char *p;
|
||||
|
||||
field = pevent->bprint_fmt_field;
|
||||
|
||||
@ -3899,25 +3929,13 @@ get_bprint_format(void *data, int size __maybe_unused,
|
||||
|
||||
printk = find_printk(pevent, addr);
|
||||
if (!printk) {
|
||||
if (asprintf(&format, "%%pf : (NO FORMAT FOUND at %llx)\n", addr) < 0)
|
||||
if (asprintf(&format, "%%pf: (NO FORMAT FOUND at %llx)\n", addr) < 0)
|
||||
return NULL;
|
||||
return format;
|
||||
}
|
||||
|
||||
p = printk->printk;
|
||||
/* Remove any quotes. */
|
||||
if (*p == '"')
|
||||
p++;
|
||||
if (asprintf(&format, "%s : %s", "%pf", p) < 0)
|
||||
if (asprintf(&format, "%s: %s", "%pf", printk->printk) < 0)
|
||||
return NULL;
|
||||
/* remove ending quotes and new line since we will add one too */
|
||||
p = format + strlen(format) - 1;
|
||||
if (*p == '"')
|
||||
*p = 0;
|
||||
|
||||
p -= 2;
|
||||
if (strcmp(p, "\\n") == 0)
|
||||
*p = 0;
|
||||
|
||||
return format;
|
||||
}
|
||||
@ -3963,7 +3981,7 @@ static int is_printable_array(char *p, unsigned int len)
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len && p[i]; i++)
|
||||
if (!isprint(p[i]))
|
||||
if (!isprint(p[i]) && !isspace(p[i]))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -4428,11 +4446,11 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
|
||||
{
|
||||
int print_pretty = 1;
|
||||
|
||||
if (event->pevent->print_raw)
|
||||
if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW))
|
||||
print_event_fields(s, record->data, record->size, event);
|
||||
else {
|
||||
|
||||
if (event->handler)
|
||||
if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
|
||||
print_pretty = event->handler(s, record, event,
|
||||
event->context);
|
||||
|
||||
@ -4443,8 +4461,21 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
|
||||
trace_seq_terminate(s);
|
||||
}
|
||||
|
||||
static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock)
|
||||
{
|
||||
if (!use_trace_clock)
|
||||
return true;
|
||||
|
||||
if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global")
|
||||
|| !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf"))
|
||||
return true;
|
||||
|
||||
/* trace_clock is setting in tsc or counter mode */
|
||||
return false;
|
||||
}
|
||||
|
||||
void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
|
||||
struct pevent_record *record)
|
||||
struct pevent_record *record, bool use_trace_clock)
|
||||
{
|
||||
static const char *spaces = " "; /* 20 spaces */
|
||||
struct event_format *event;
|
||||
@ -4457,9 +4488,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
|
||||
int pid;
|
||||
int len;
|
||||
int p;
|
||||
bool use_usec_format;
|
||||
|
||||
secs = record->ts / NSECS_PER_SEC;
|
||||
nsecs = record->ts - secs * NSECS_PER_SEC;
|
||||
use_usec_format = is_timestamp_in_us(pevent->trace_clock,
|
||||
use_trace_clock);
|
||||
if (use_usec_format) {
|
||||
secs = record->ts / NSECS_PER_SEC;
|
||||
nsecs = record->ts - secs * NSECS_PER_SEC;
|
||||
}
|
||||
|
||||
if (record->size < 0) {
|
||||
do_warning("ug! negative record size %d", record->size);
|
||||
@ -4484,15 +4520,20 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
|
||||
} else
|
||||
trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
|
||||
|
||||
if (pevent->flags & PEVENT_NSEC_OUTPUT) {
|
||||
usecs = nsecs;
|
||||
p = 9;
|
||||
} else {
|
||||
usecs = (nsecs + 500) / NSECS_PER_USEC;
|
||||
p = 6;
|
||||
}
|
||||
if (use_usec_format) {
|
||||
if (pevent->flags & PEVENT_NSEC_OUTPUT) {
|
||||
usecs = nsecs;
|
||||
p = 9;
|
||||
} else {
|
||||
usecs = (nsecs + 500) / NSECS_PER_USEC;
|
||||
p = 6;
|
||||
}
|
||||
|
||||
trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name);
|
||||
trace_seq_printf(s, " %5lu.%0*lu: %s: ",
|
||||
secs, p, usecs, event->name);
|
||||
} else
|
||||
trace_seq_printf(s, " %12llu: %s: ",
|
||||
record->ts, event->name);
|
||||
|
||||
/* Space out the event names evenly. */
|
||||
len = strlen(event->name);
|
||||
@ -5326,6 +5367,48 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_print_func_field - print a field and a format for function pointers
|
||||
* @s: The seq to print to
|
||||
* @fmt: The printf format to print the field with.
|
||||
* @event: the event that the field is for
|
||||
* @name: The name of the field
|
||||
* @record: The record with the field name.
|
||||
* @err: print default error if failed.
|
||||
*
|
||||
* Returns: 0 on success, -1 field not found, or 1 if buffer is full.
|
||||
*/
|
||||
int pevent_print_func_field(struct trace_seq *s, const char *fmt,
|
||||
struct event_format *event, const char *name,
|
||||
struct pevent_record *record, int err)
|
||||
{
|
||||
struct format_field *field = pevent_find_field(event, name);
|
||||
struct pevent *pevent = event->pevent;
|
||||
unsigned long long val;
|
||||
struct func_map *func;
|
||||
char tmp[128];
|
||||
|
||||
if (!field)
|
||||
goto failed;
|
||||
|
||||
if (pevent_read_number_field(field, record->data, &val))
|
||||
goto failed;
|
||||
|
||||
func = find_func(pevent, val);
|
||||
|
||||
if (func)
|
||||
snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val);
|
||||
else
|
||||
sprintf(tmp, "0x%08llx", val);
|
||||
|
||||
return trace_seq_printf(s, fmt, tmp);
|
||||
|
||||
failed:
|
||||
if (err)
|
||||
trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void free_func_handle(struct pevent_function_handler *func)
|
||||
{
|
||||
struct pevent_func_params *params;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#ifndef _PARSE_EVENTS_H
|
||||
#define _PARSE_EVENTS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <regex.h>
|
||||
|
||||
@ -307,6 +308,8 @@ enum {
|
||||
EVENT_FL_ISBPRINT = 0x04,
|
||||
EVENT_FL_ISFUNCENT = 0x10,
|
||||
EVENT_FL_ISFUNCRET = 0x20,
|
||||
EVENT_FL_NOHANDLE = 0x40,
|
||||
EVENT_FL_PRINTRAW = 0x80,
|
||||
|
||||
EVENT_FL_FAILED = 0x80000000
|
||||
};
|
||||
@ -450,6 +453,8 @@ struct pevent {
|
||||
|
||||
/* cache */
|
||||
struct event_format *last_event;
|
||||
|
||||
char *trace_clock;
|
||||
};
|
||||
|
||||
static inline void pevent_set_flag(struct pevent *pevent, int flag)
|
||||
@ -527,14 +532,15 @@ enum trace_flag_type {
|
||||
};
|
||||
|
||||
int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
|
||||
void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock);
|
||||
int pevent_register_function(struct pevent *pevent, char *name,
|
||||
unsigned long long addr, char *mod);
|
||||
int pevent_register_print_string(struct pevent *pevent, char *fmt,
|
||||
int pevent_register_print_string(struct pevent *pevent, const char *fmt,
|
||||
unsigned long long addr);
|
||||
int pevent_pid_is_registered(struct pevent *pevent, int pid);
|
||||
|
||||
void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
|
||||
struct pevent_record *record);
|
||||
struct pevent_record *record, bool use_trace_clock);
|
||||
|
||||
int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
|
||||
int long_size);
|
||||
@ -563,6 +569,10 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
|
||||
struct event_format *event, const char *name,
|
||||
struct pevent_record *record, int err);
|
||||
|
||||
int pevent_print_func_field(struct trace_seq *s, const char *fmt,
|
||||
struct event_format *event, const char *name,
|
||||
struct pevent_record *record, int err);
|
||||
|
||||
int pevent_register_event_handler(struct pevent *pevent, int id,
|
||||
const char *sys_name, const char *event_name,
|
||||
pevent_event_handler_func func, void *context);
|
||||
|
1
tools/perf/.gitignore
vendored
1
tools/perf/.gitignore
vendored
@ -13,6 +13,7 @@ perf*.html
|
||||
common-cmds.h
|
||||
perf.data
|
||||
perf.data.old
|
||||
output.svg
|
||||
perf-archive
|
||||
tags
|
||||
TAGS
|
||||
|
@ -145,16 +145,17 @@ endif
|
||||
|
||||
ifneq ($(findstring $(MAKEFLAGS),s),s)
|
||||
ifneq ($(V),1)
|
||||
QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
|
||||
QUIET_XMLTO = @echo ' ' XMLTO $@;
|
||||
QUIET_DB2TEXI = @echo ' ' DB2TEXI $@;
|
||||
QUIET_MAKEINFO = @echo ' ' MAKEINFO $@;
|
||||
QUIET_DBLATEX = @echo ' ' DBLATEX $@;
|
||||
QUIET_XSLTPROC = @echo ' ' XSLTPROC $@;
|
||||
QUIET_GEN = @echo ' ' GEN $@;
|
||||
QUIET_ASCIIDOC = @echo ' ASCIIDOC '$@;
|
||||
QUIET_XMLTO = @echo ' XMLTO '$@;
|
||||
QUIET_DB2TEXI = @echo ' DB2TEXI '$@;
|
||||
QUIET_MAKEINFO = @echo ' MAKEINFO '$@;
|
||||
QUIET_DBLATEX = @echo ' DBLATEX '$@;
|
||||
QUIET_XSLTPROC = @echo ' XSLTPROC '$@;
|
||||
QUIET_GEN = @echo ' GEN '$@;
|
||||
QUIET_STDERR = 2> /dev/null
|
||||
QUIET_SUBDIR0 = +@subdir=
|
||||
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
|
||||
QUIET_SUBDIR1 = ;$(NO_SUBDIR) \
|
||||
echo ' SUBDIR ' $$subdir; \
|
||||
$(MAKE) $(PRINT_DIR) -C $$subdir
|
||||
export V
|
||||
endif
|
||||
@ -183,47 +184,43 @@ ifdef missing_tools
|
||||
endif
|
||||
|
||||
do-install-man: man
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
|
||||
# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
|
||||
# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
|
||||
$(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir)
|
||||
# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
|
||||
# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
$(call QUIET_INSTALL, Documentation-man) \
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir); \
|
||||
# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir); \
|
||||
# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir); \
|
||||
$(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir); \
|
||||
# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir); \
|
||||
# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
|
||||
install-man: check-man-tools man
|
||||
|
||||
try-install-man:
|
||||
ifdef missing_tools
|
||||
$(warning Please install $(missing_tools) to have the man pages installed)
|
||||
DO_INSTALL_MAN = $(warning Please install $(missing_tools) to have the man pages installed)
|
||||
else
|
||||
$(MAKE) do-install-man
|
||||
DO_INSTALL_MAN = do-install-man
|
||||
endif
|
||||
|
||||
try-install-man: $(DO_INSTALL_MAN)
|
||||
|
||||
install-info: info
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
|
||||
$(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir)
|
||||
$(call QUIET_INSTALL, Documentation-info) \
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(infodir); \
|
||||
$(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir); \
|
||||
if test -r $(DESTDIR)$(infodir)/dir; then \
|
||||
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
|
||||
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
|
||||
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
|
||||
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
|
||||
else \
|
||||
echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
|
||||
fi
|
||||
|
||||
install-pdf: pdf
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
|
||||
$(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir)
|
||||
$(call QUIET_INSTALL, Documentation-pdf) \
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir); \
|
||||
$(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir)
|
||||
|
||||
#install-html: html
|
||||
# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(MAKECMDGOALS),tags)
|
||||
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
|
||||
$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
|
||||
|
||||
-include $(OUTPUT)PERF-VERSION-FILE
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Determine "include::" file references in asciidoc files.
|
||||
@ -253,15 +250,17 @@ $(OUTPUT)cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
|
||||
$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
|
||||
date >$@
|
||||
|
||||
CLEAN_FILES = \
|
||||
$(MAN_XML) $(addsuffix +,$(MAN_XML)) \
|
||||
$(MAN_HTML) $(addsuffix +,$(MAN_HTML)) \
|
||||
$(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7) \
|
||||
$(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++ \
|
||||
$(OUTPUT)perf.info $(OUTPUT)perfman.info \
|
||||
$(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep \
|
||||
$(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt \
|
||||
$(cmds_txt) $(OUTPUT)*.made
|
||||
clean:
|
||||
$(RM) $(MAN_XML) $(addsuffix +,$(MAN_XML))
|
||||
$(RM) $(MAN_HTML) $(addsuffix +,$(MAN_HTML))
|
||||
$(RM) $(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7)
|
||||
$(RM) $(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++
|
||||
$(RM) $(OUTPUT)perf.info $(OUTPUT)perfman.info
|
||||
$(RM) $(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep
|
||||
$(RM) $(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt
|
||||
$(RM) $(cmds_txt) $(OUTPUT)*.made
|
||||
$(call QUIET_CLEAN, Documentation) $(RM) $(CLEAN_FILES)
|
||||
|
||||
$(MAN_HTML): $(OUTPUT)%.html : %.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
@ -342,5 +341,3 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||
|
||||
#quick-install-html:
|
||||
# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
|
||||
|
||||
.PHONY: .FORCE-PERF-VERSION-FILE
|
||||
|
@ -21,6 +21,19 @@ OPTIONS
|
||||
-a::
|
||||
--add=::
|
||||
Add specified file to the cache.
|
||||
-k::
|
||||
--kcore::
|
||||
Add specified kcore file to the cache. For the current host that is
|
||||
/proc/kcore which requires root permissions to read. Be aware that
|
||||
running 'perf buildid-cache' as root may update root's build-id cache
|
||||
not the user's. Use the -v option to see where the file is created.
|
||||
Note that the copied file contains only code sections not the whole core
|
||||
image. Note also that files "kallsyms" and "modules" must also be in the
|
||||
same directory and are also copied. All 3 files are created with read
|
||||
permissions for root only. kcore will not be added if there is already a
|
||||
kcore in the cache (with the same build-id) that has the same modules at
|
||||
the same addresses. Use the -v option to see if a copy of kcore is
|
||||
actually made.
|
||||
-r::
|
||||
--remove=::
|
||||
Remove specified file from the cache.
|
||||
|
@ -109,7 +109,9 @@ STAT LIVE OPTIONS
|
||||
|
||||
-m::
|
||||
--mmap-pages=::
|
||||
Number of mmap data pages. Must be a power of two.
|
||||
Number of mmap data pages (must be a power of two) or size
|
||||
specification with appended unit character - B/K/M/G. The
|
||||
size is rounded up to have nearest pages power of two value.
|
||||
|
||||
-a::
|
||||
--all-cpus::
|
||||
|
@ -48,7 +48,7 @@ REPORT OPTIONS
|
||||
-k::
|
||||
--key=<value>::
|
||||
Sorting key. Possible values: acquired (default), contended,
|
||||
wait_total, wait_max, wait_min.
|
||||
avg_wait, wait_total, wait_max, wait_min.
|
||||
|
||||
INFO OPTIONS
|
||||
------------
|
||||
|
@ -87,7 +87,9 @@ OPTIONS
|
||||
|
||||
-m::
|
||||
--mmap-pages=::
|
||||
Number of mmap data pages. Must be a power of two.
|
||||
Number of mmap data pages (must be a power of two) or size
|
||||
specification with appended unit character - B/K/M/G. The
|
||||
size is rounded up to have nearest pages power of two value.
|
||||
|
||||
-g::
|
||||
Enables call-graph (stack chain/backtrace) recording.
|
||||
@ -178,6 +180,9 @@ following filters are defined:
|
||||
- u: only when the branch target is at the user level
|
||||
- k: only when the branch target is in the kernel
|
||||
- hv: only when the target is at the hypervisor level
|
||||
- in_tx: only when the target is in a hardware transaction
|
||||
- no_tx: only when the target is not in a hardware transaction
|
||||
- abort_tx: only when the target is a hardware transaction abort
|
||||
|
||||
+
|
||||
The option requires at least one branch type among any, any_call, any_ret, ind_call.
|
||||
@ -188,12 +193,14 @@ is enabled for all the sampling events. The sampled branch type is the same for
|
||||
The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
|
||||
Note that this feature may not be available on all processors.
|
||||
|
||||
-W::
|
||||
--weight::
|
||||
Enable weightened sampling. An additional weight is recorded per sample and can be
|
||||
displayed with the weight and local_weight sort keys. This currently works for TSX
|
||||
abort events and some memory events in precise mode on modern Intel CPUs.
|
||||
|
||||
--transaction::
|
||||
Record transaction flags for transaction related events.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-stat[1], linkperf:perf-list[1]
|
||||
|
@ -71,7 +71,11 @@ OPTIONS
|
||||
entries are displayed as "[other]".
|
||||
- cpu: cpu number the task ran at the time of sample
|
||||
- srcline: filename and line number executed at the time of sample. The
|
||||
DWARF debuggin info must be provided.
|
||||
DWARF debugging info must be provided.
|
||||
- weight: Event specific weight, e.g. memory latency or transaction
|
||||
abort cost. This is the global weight.
|
||||
- local_weight: Local weight version of the weight above.
|
||||
- transaction: Transaction abort flags.
|
||||
|
||||
By default, comm, dso and symbol keys are used.
|
||||
(i.e. --sort comm,dso,symbol)
|
||||
@ -85,6 +89,8 @@ OPTIONS
|
||||
- symbol_from: name of function branched from
|
||||
- symbol_to: name of function branched to
|
||||
- mispredict: "N" for predicted branch, "Y" for mispredicted branch
|
||||
- in_tx: branch in TSX transaction
|
||||
- abort: TSX transaction abort.
|
||||
|
||||
And default sort keys are changed to comm, dso_from, symbol_from, dso_to
|
||||
and symbol_to, see '--branch-stack'.
|
||||
@ -135,6 +141,14 @@ OPTIONS
|
||||
|
||||
Default: fractal,0.5,callee,function.
|
||||
|
||||
--max-stack::
|
||||
Set the stack depth limit when parsing the callchain, anything
|
||||
beyond the specified depth will be ignored. This is a trade-off
|
||||
between information loss and faster processing especially for
|
||||
workloads that can have a very long callchain stack.
|
||||
|
||||
Default: 127
|
||||
|
||||
-G::
|
||||
--inverted::
|
||||
alias for inverted caller based call graph.
|
||||
|
@ -137,6 +137,11 @@ core number and the number of online logical processors on that physical process
|
||||
After starting the program, wait msecs before measuring. This is useful to
|
||||
filter out the startup phase of the program, which is often very different.
|
||||
|
||||
-T::
|
||||
--transaction::
|
||||
|
||||
Print statistics of transactional execution if supported.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
|
@ -8,7 +8,8 @@ perf-timechart - Tool to visualize total system behavior during a workload
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'perf timechart' {record}
|
||||
'perf timechart' record <command>
|
||||
'perf timechart' [<options>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -41,6 +42,18 @@ OPTIONS
|
||||
--symfs=<directory>::
|
||||
Look for files with symbols relative to this directory.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
$ perf timechart record git pull
|
||||
|
||||
[ perf record: Woken up 13 times to write data ]
|
||||
[ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ]
|
||||
|
||||
$ perf timechart
|
||||
|
||||
Written 10.2 seconds of trace to output.svg.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-record[1]
|
||||
|
@ -68,7 +68,9 @@ Default is to monitor all CPUS.
|
||||
|
||||
-m <pages>::
|
||||
--mmap-pages=<pages>::
|
||||
Number of mmapped data pages.
|
||||
Number of mmap data pages (must be a power of two) or size
|
||||
specification with appended unit character - B/K/M/G. The
|
||||
size is rounded up to have nearest pages power of two value.
|
||||
|
||||
-p <pid>::
|
||||
--pid=<pid>::
|
||||
@ -112,7 +114,8 @@ Default is to monitor all CPUS.
|
||||
|
||||
-s::
|
||||
--sort::
|
||||
Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, local_weight.
|
||||
Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight,
|
||||
local_weight, abort, in_tx, transaction
|
||||
|
||||
-n::
|
||||
--show-nr-samples::
|
||||
@ -147,6 +150,14 @@ Default is to monitor all CPUS.
|
||||
Setup and enable call-graph (stack chain/backtrace) recording,
|
||||
implies -G.
|
||||
|
||||
--max-stack::
|
||||
Set the stack depth limit when parsing the callchain, anything
|
||||
beyond the specified depth will be ignored. This is a trade-off
|
||||
between information loss and faster processing especially for
|
||||
workloads that can have a very long callchain stack.
|
||||
|
||||
Default: 127
|
||||
|
||||
--ignore-callees=<regex>::
|
||||
Ignore callees of the function(s) matching the given regex.
|
||||
This has the effect of collecting the callers of each such
|
||||
|
@ -9,6 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'perf trace'
|
||||
'perf trace record'
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -16,9 +17,14 @@ This command will show the events associated with the target, initially
|
||||
syscalls, but other system events like pagefaults, task lifetime events,
|
||||
scheduling events, etc.
|
||||
|
||||
Initially this is a live mode only tool, but eventually will work with
|
||||
perf.data files like the other tools, allowing a detached 'record' from
|
||||
analysis phases.
|
||||
This is a live mode tool in addition to working with perf.data files like
|
||||
the other perf tools. Files can be generated using the 'perf record' command
|
||||
but the session needs to include the raw_syscalls events (-e 'raw_syscalls:*').
|
||||
Alernatively, the 'perf trace record' can be used as a shortcut to
|
||||
automatically include the raw_syscalls events when writing events to a file.
|
||||
|
||||
The following options apply to perf trace; options to perf trace record are
|
||||
found in the perf record man page.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -59,7 +65,9 @@ OPTIONS
|
||||
|
||||
-m::
|
||||
--mmap-pages=::
|
||||
Number of mmap data pages. Must be a power of two.
|
||||
Number of mmap data pages (must be a power of two) or size
|
||||
specification with appended unit character - B/K/M/G. The
|
||||
size is rounded up to have nearest pages power of two value.
|
||||
|
||||
-C::
|
||||
--cpu::
|
||||
@ -78,6 +86,21 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||
--input
|
||||
Process events from a given perf data file.
|
||||
|
||||
-T
|
||||
--time
|
||||
Print full timestamp rather time relative to first sample.
|
||||
|
||||
--comm::
|
||||
Show process COMM right beside its ID, on by default, disable with --no-comm.
|
||||
|
||||
--summary::
|
||||
Show a summary of syscalls by thread with min, max, and average times (in
|
||||
msec) and relative stddev.
|
||||
|
||||
--tool_stats::
|
||||
Show tool stats such as number of times fd->pathname was discovered thru
|
||||
hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-record[1], linkperf:perf-script[1]
|
||||
|
@ -1,819 +1,79 @@
|
||||
include ../scripts/Makefile.include
|
||||
|
||||
# The default target of this Makefile is...
|
||||
all:
|
||||
|
||||
include config/utilities.mak
|
||||
|
||||
# Define V to have a more verbose compile.
|
||||
#
|
||||
# Define O to save output files in a separate directory.
|
||||
# This is a simple wrapper Makefile that calls the main Makefile.perf
|
||||
# with a -j option to do parallel builds
|
||||
#
|
||||
# Define ARCH as name of target architecture if you want cross-builds.
|
||||
#
|
||||
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
|
||||
#
|
||||
# Define NO_LIBPERL to disable perl script extension.
|
||||
#
|
||||
# Define NO_LIBPYTHON to disable python script extension.
|
||||
#
|
||||
# Define PYTHON to point to the python binary if the default
|
||||
# `python' is not correct; for example: PYTHON=python2
|
||||
#
|
||||
# Define PYTHON_CONFIG to point to the python-config binary if
|
||||
# the default `$(PYTHON)-config' is not correct.
|
||||
#
|
||||
# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
|
||||
#
|
||||
# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
|
||||
#
|
||||
# Define LDFLAGS=-static to build a static binary.
|
||||
#
|
||||
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
|
||||
#
|
||||
# Define NO_DWARF if you do not want debug-info analysis feature at all.
|
||||
#
|
||||
# Define WERROR=0 to disable treating any warnings as errors.
|
||||
#
|
||||
# Define NO_NEWT if you do not want TUI support. (deprecated)
|
||||
#
|
||||
# Define NO_SLANG if you do not want TUI support.
|
||||
#
|
||||
# Define NO_GTK2 if you do not want GTK+ GUI support.
|
||||
#
|
||||
# Define NO_DEMANGLE if you do not want C++ symbol demangling.
|
||||
#
|
||||
# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds)
|
||||
#
|
||||
# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf
|
||||
# backtrace post unwind.
|
||||
#
|
||||
# Define NO_BACKTRACE if you do not want stack backtrace debug feature
|
||||
#
|
||||
# Define NO_LIBNUMA if you do not want numa perf benchmark
|
||||
#
|
||||
# Define NO_LIBAUDIT if you do not want libaudit support
|
||||
#
|
||||
# Define NO_LIBBIONIC if you do not want bionic support
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
#$(info Determined 'srctree' to be $(srctree))
|
||||
endif
|
||||
|
||||
ifneq ($(objtree),)
|
||||
#$(info Determined 'objtree' to be $(objtree))
|
||||
endif
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
#$(info Determined 'OUTPUT' to be $(OUTPUT))
|
||||
endif
|
||||
|
||||
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
|
||||
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
AR = $(CROSS_COMPILE)ar
|
||||
|
||||
RM = rm -f
|
||||
MKDIR = mkdir
|
||||
FIND = find
|
||||
INSTALL = install
|
||||
FLEX = flex
|
||||
BISON = bison
|
||||
STRIP = strip
|
||||
|
||||
LK_DIR = $(srctree)/tools/lib/lk/
|
||||
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
|
||||
|
||||
# include config/Makefile by default and rule out
|
||||
# non-config cases
|
||||
config := 1
|
||||
|
||||
NON_CONFIG_TARGETS := clean TAGS tags cscope help
|
||||
|
||||
ifdef MAKECMDGOALS
|
||||
ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
|
||||
config := 0
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(config),1)
|
||||
include config/Makefile
|
||||
endif
|
||||
|
||||
export prefix bindir sharedir sysconfdir
|
||||
|
||||
# sparse is architecture-neutral, which means that we need to tell it
|
||||
# explicitly what architecture to check for. Fix this up for yours..
|
||||
SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
|
||||
|
||||
# Guard against environment variables
|
||||
BUILTIN_OBJS =
|
||||
LIB_H =
|
||||
LIB_OBJS =
|
||||
PYRF_OBJS =
|
||||
SCRIPT_SH =
|
||||
|
||||
SCRIPT_SH += perf-archive.sh
|
||||
|
||||
grep-libs = $(filter -l%,$(1))
|
||||
strip-libs = $(filter-out -l%,$(1))
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
TE_PATH=$(OUTPUT)
|
||||
ifneq ($(subdir),)
|
||||
LK_PATH=$(OUTPUT)/../lib/lk/
|
||||
else
|
||||
LK_PATH=$(OUTPUT)
|
||||
endif
|
||||
else
|
||||
TE_PATH=$(TRACE_EVENT_DIR)
|
||||
LK_PATH=$(LK_DIR)
|
||||
endif
|
||||
|
||||
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
|
||||
export LIBTRACEEVENT
|
||||
|
||||
LIBLK = $(LK_PATH)liblk.a
|
||||
export LIBLK
|
||||
|
||||
# python extension build directories
|
||||
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
|
||||
PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
|
||||
PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
|
||||
export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
|
||||
|
||||
python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
|
||||
|
||||
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
|
||||
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
|
||||
|
||||
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
|
||||
$(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
|
||||
--quiet build_ext; \
|
||||
mkdir -p $(OUTPUT)python && \
|
||||
cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
|
||||
#
|
||||
# No Perl scripts right now:
|
||||
# If you want to invoke the perf build in some non-standard way then
|
||||
# you can use the 'make -f Makefile.perf' method to invoke it.
|
||||
#
|
||||
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
|
||||
#
|
||||
# Clear out the built-in rules GNU make defines by default (such as .o targets),
|
||||
# so that we pass through all targets to Makefile.perf:
|
||||
#
|
||||
.SUFFIXES:
|
||||
|
||||
#
|
||||
# Single 'perf' binary right now:
|
||||
# We don't want to pass along options like -j:
|
||||
#
|
||||
PROGRAMS += $(OUTPUT)perf
|
||||
unexport MAKEFLAGS
|
||||
|
||||
# what 'all' will build and 'install' will install, in perfexecdir
|
||||
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
|
||||
|
||||
# what 'all' will build but not install in perfexecdir
|
||||
OTHER_PROGRAMS = $(OUTPUT)perf
|
||||
|
||||
# Set paths to tools early so that they can be used for version tests.
|
||||
ifndef SHELL_PATH
|
||||
SHELL_PATH = /bin/sh
|
||||
endif
|
||||
ifndef PERL_PATH
|
||||
PERL_PATH = /usr/bin/perl
|
||||
endif
|
||||
|
||||
export PERL_PATH
|
||||
|
||||
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
|
||||
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
|
||||
|
||||
$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
|
||||
$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
|
||||
|
||||
$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
|
||||
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
|
||||
|
||||
$(OUTPUT)util/pmu-bison.c: util/pmu.y
|
||||
$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
|
||||
|
||||
$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
|
||||
$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
|
||||
|
||||
LIB_FILE=$(OUTPUT)libperf.a
|
||||
|
||||
LIB_H += ../../include/uapi/linux/perf_event.h
|
||||
LIB_H += ../../include/linux/rbtree.h
|
||||
LIB_H += ../../include/linux/list.h
|
||||
LIB_H += ../../include/uapi/linux/const.h
|
||||
LIB_H += ../../include/linux/hash.h
|
||||
LIB_H += ../../include/linux/stringify.h
|
||||
LIB_H += util/include/linux/bitmap.h
|
||||
LIB_H += util/include/linux/bitops.h
|
||||
LIB_H += util/include/linux/compiler.h
|
||||
LIB_H += util/include/linux/const.h
|
||||
LIB_H += util/include/linux/ctype.h
|
||||
LIB_H += util/include/linux/kernel.h
|
||||
LIB_H += util/include/linux/list.h
|
||||
LIB_H += util/include/linux/export.h
|
||||
LIB_H += util/include/linux/magic.h
|
||||
LIB_H += util/include/linux/poison.h
|
||||
LIB_H += util/include/linux/prefetch.h
|
||||
LIB_H += util/include/linux/rbtree.h
|
||||
LIB_H += util/include/linux/rbtree_augmented.h
|
||||
LIB_H += util/include/linux/string.h
|
||||
LIB_H += util/include/linux/types.h
|
||||
LIB_H += util/include/linux/linkage.h
|
||||
LIB_H += util/include/asm/asm-offsets.h
|
||||
LIB_H += util/include/asm/bug.h
|
||||
LIB_H += util/include/asm/byteorder.h
|
||||
LIB_H += util/include/asm/hweight.h
|
||||
LIB_H += util/include/asm/swab.h
|
||||
LIB_H += util/include/asm/system.h
|
||||
LIB_H += util/include/asm/uaccess.h
|
||||
LIB_H += util/include/dwarf-regs.h
|
||||
LIB_H += util/include/asm/dwarf2.h
|
||||
LIB_H += util/include/asm/cpufeature.h
|
||||
LIB_H += util/include/asm/unistd_32.h
|
||||
LIB_H += util/include/asm/unistd_64.h
|
||||
LIB_H += perf.h
|
||||
LIB_H += util/annotate.h
|
||||
LIB_H += util/cache.h
|
||||
LIB_H += util/callchain.h
|
||||
LIB_H += util/build-id.h
|
||||
LIB_H += util/debug.h
|
||||
LIB_H += util/sysfs.h
|
||||
LIB_H += util/pmu.h
|
||||
LIB_H += util/event.h
|
||||
LIB_H += util/evsel.h
|
||||
LIB_H += util/evlist.h
|
||||
LIB_H += util/exec_cmd.h
|
||||
LIB_H += util/types.h
|
||||
LIB_H += util/levenshtein.h
|
||||
LIB_H += util/machine.h
|
||||
LIB_H += util/map.h
|
||||
LIB_H += util/parse-options.h
|
||||
LIB_H += util/parse-events.h
|
||||
LIB_H += util/quote.h
|
||||
LIB_H += util/util.h
|
||||
LIB_H += util/xyarray.h
|
||||
LIB_H += util/header.h
|
||||
LIB_H += util/help.h
|
||||
LIB_H += util/session.h
|
||||
LIB_H += util/strbuf.h
|
||||
LIB_H += util/strlist.h
|
||||
LIB_H += util/strfilter.h
|
||||
LIB_H += util/svghelper.h
|
||||
LIB_H += util/tool.h
|
||||
LIB_H += util/run-command.h
|
||||
LIB_H += util/sigchain.h
|
||||
LIB_H += util/dso.h
|
||||
LIB_H += util/symbol.h
|
||||
LIB_H += util/color.h
|
||||
LIB_H += util/values.h
|
||||
LIB_H += util/sort.h
|
||||
LIB_H += util/hist.h
|
||||
LIB_H += util/thread.h
|
||||
LIB_H += util/thread_map.h
|
||||
LIB_H += util/trace-event.h
|
||||
LIB_H += util/probe-finder.h
|
||||
LIB_H += util/dwarf-aux.h
|
||||
LIB_H += util/probe-event.h
|
||||
LIB_H += util/pstack.h
|
||||
LIB_H += util/cpumap.h
|
||||
LIB_H += util/top.h
|
||||
LIB_H += $(ARCH_INCLUDE)
|
||||
LIB_H += util/cgroup.h
|
||||
LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
|
||||
LIB_H += util/target.h
|
||||
LIB_H += util/rblist.h
|
||||
LIB_H += util/intlist.h
|
||||
LIB_H += util/perf_regs.h
|
||||
LIB_H += util/unwind.h
|
||||
LIB_H += util/vdso.h
|
||||
LIB_H += ui/helpline.h
|
||||
LIB_H += ui/progress.h
|
||||
LIB_H += ui/util.h
|
||||
LIB_H += ui/ui.h
|
||||
|
||||
LIB_OBJS += $(OUTPUT)util/abspath.o
|
||||
LIB_OBJS += $(OUTPUT)util/alias.o
|
||||
LIB_OBJS += $(OUTPUT)util/annotate.o
|
||||
LIB_OBJS += $(OUTPUT)util/build-id.o
|
||||
LIB_OBJS += $(OUTPUT)util/config.o
|
||||
LIB_OBJS += $(OUTPUT)util/ctype.o
|
||||
LIB_OBJS += $(OUTPUT)util/sysfs.o
|
||||
LIB_OBJS += $(OUTPUT)util/pmu.o
|
||||
LIB_OBJS += $(OUTPUT)util/environment.o
|
||||
LIB_OBJS += $(OUTPUT)util/event.o
|
||||
LIB_OBJS += $(OUTPUT)util/evlist.o
|
||||
LIB_OBJS += $(OUTPUT)util/evsel.o
|
||||
LIB_OBJS += $(OUTPUT)util/exec_cmd.o
|
||||
LIB_OBJS += $(OUTPUT)util/help.o
|
||||
LIB_OBJS += $(OUTPUT)util/levenshtein.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-options.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-events.o
|
||||
LIB_OBJS += $(OUTPUT)util/path.o
|
||||
LIB_OBJS += $(OUTPUT)util/rbtree.o
|
||||
LIB_OBJS += $(OUTPUT)util/bitmap.o
|
||||
LIB_OBJS += $(OUTPUT)util/hweight.o
|
||||
LIB_OBJS += $(OUTPUT)util/run-command.o
|
||||
LIB_OBJS += $(OUTPUT)util/quote.o
|
||||
LIB_OBJS += $(OUTPUT)util/strbuf.o
|
||||
LIB_OBJS += $(OUTPUT)util/string.o
|
||||
LIB_OBJS += $(OUTPUT)util/strlist.o
|
||||
LIB_OBJS += $(OUTPUT)util/strfilter.o
|
||||
LIB_OBJS += $(OUTPUT)util/top.o
|
||||
LIB_OBJS += $(OUTPUT)util/usage.o
|
||||
LIB_OBJS += $(OUTPUT)util/wrapper.o
|
||||
LIB_OBJS += $(OUTPUT)util/sigchain.o
|
||||
LIB_OBJS += $(OUTPUT)util/dso.o
|
||||
LIB_OBJS += $(OUTPUT)util/symbol.o
|
||||
LIB_OBJS += $(OUTPUT)util/symbol-elf.o
|
||||
LIB_OBJS += $(OUTPUT)util/color.o
|
||||
LIB_OBJS += $(OUTPUT)util/pager.o
|
||||
LIB_OBJS += $(OUTPUT)util/header.o
|
||||
LIB_OBJS += $(OUTPUT)util/callchain.o
|
||||
LIB_OBJS += $(OUTPUT)util/values.o
|
||||
LIB_OBJS += $(OUTPUT)util/debug.o
|
||||
LIB_OBJS += $(OUTPUT)util/machine.o
|
||||
LIB_OBJS += $(OUTPUT)util/map.o
|
||||
LIB_OBJS += $(OUTPUT)util/pstack.o
|
||||
LIB_OBJS += $(OUTPUT)util/session.o
|
||||
LIB_OBJS += $(OUTPUT)util/thread.o
|
||||
LIB_OBJS += $(OUTPUT)util/thread_map.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
|
||||
LIB_OBJS += $(OUTPUT)util/pmu-flex.o
|
||||
LIB_OBJS += $(OUTPUT)util/pmu-bison.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-read.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-info.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
|
||||
LIB_OBJS += $(OUTPUT)util/svghelper.o
|
||||
LIB_OBJS += $(OUTPUT)util/sort.o
|
||||
LIB_OBJS += $(OUTPUT)util/hist.o
|
||||
LIB_OBJS += $(OUTPUT)util/probe-event.o
|
||||
LIB_OBJS += $(OUTPUT)util/util.o
|
||||
LIB_OBJS += $(OUTPUT)util/xyarray.o
|
||||
LIB_OBJS += $(OUTPUT)util/cpumap.o
|
||||
LIB_OBJS += $(OUTPUT)util/cgroup.o
|
||||
LIB_OBJS += $(OUTPUT)util/target.o
|
||||
LIB_OBJS += $(OUTPUT)util/rblist.o
|
||||
LIB_OBJS += $(OUTPUT)util/intlist.o
|
||||
LIB_OBJS += $(OUTPUT)util/vdso.o
|
||||
LIB_OBJS += $(OUTPUT)util/stat.o
|
||||
LIB_OBJS += $(OUTPUT)util/record.o
|
||||
|
||||
LIB_OBJS += $(OUTPUT)ui/setup.o
|
||||
LIB_OBJS += $(OUTPUT)ui/helpline.o
|
||||
LIB_OBJS += $(OUTPUT)ui/progress.o
|
||||
LIB_OBJS += $(OUTPUT)ui/util.o
|
||||
LIB_OBJS += $(OUTPUT)ui/hist.o
|
||||
LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
|
||||
|
||||
LIB_OBJS += $(OUTPUT)arch/common.o
|
||||
|
||||
LIB_OBJS += $(OUTPUT)tests/parse-events.o
|
||||
LIB_OBJS += $(OUTPUT)tests/dso-data.o
|
||||
LIB_OBJS += $(OUTPUT)tests/attr.o
|
||||
LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
|
||||
LIB_OBJS += $(OUTPUT)tests/open-syscall.o
|
||||
LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
|
||||
LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
|
||||
LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
|
||||
LIB_OBJS += $(OUTPUT)tests/perf-record.o
|
||||
LIB_OBJS += $(OUTPUT)tests/rdpmc.o
|
||||
LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
|
||||
LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
|
||||
LIB_OBJS += $(OUTPUT)tests/pmu.o
|
||||
LIB_OBJS += $(OUTPUT)tests/hists_link.o
|
||||
LIB_OBJS += $(OUTPUT)tests/python-use.o
|
||||
LIB_OBJS += $(OUTPUT)tests/bp_signal.o
|
||||
LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
|
||||
LIB_OBJS += $(OUTPUT)tests/task-exit.o
|
||||
LIB_OBJS += $(OUTPUT)tests/sw-clock.o
|
||||
ifeq ($(ARCH),x86)
|
||||
LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
|
||||
endif
|
||||
LIB_OBJS += $(OUTPUT)tests/code-reading.o
|
||||
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
|
||||
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
|
||||
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
|
||||
# Benchmark modules
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
|
||||
ifeq ($(RAW_ARCH),x86_64)
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
|
||||
endif
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
|
||||
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-help.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-list.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-record.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-report.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-top.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-script.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
|
||||
BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
|
||||
|
||||
PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
|
||||
|
||||
# We choose to avoid "if .. else if .. else .. endif endif"
|
||||
# because maintaining the nesting to match is a pain. If
|
||||
# we had "elif" things would have been much nicer...
|
||||
|
||||
-include arch/$(ARCH)/Makefile
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
CFLAGS += -I$(OUTPUT)
|
||||
endif
|
||||
|
||||
ifdef NO_LIBELF
|
||||
EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
|
||||
|
||||
# Remove ELF/DWARF dependent codes
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
|
||||
|
||||
BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
|
||||
|
||||
# Use minimal symbol handling
|
||||
LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
|
||||
|
||||
else # NO_LIBELF
|
||||
ifndef NO_DWARF
|
||||
LIB_OBJS += $(OUTPUT)util/probe-finder.o
|
||||
LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
|
||||
endif # NO_DWARF
|
||||
endif # NO_LIBELF
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
LIB_OBJS += $(OUTPUT)util/unwind.o
|
||||
endif
|
||||
LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
|
||||
|
||||
ifndef NO_LIBAUDIT
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
|
||||
endif
|
||||
|
||||
ifndef NO_SLANG
|
||||
LIB_OBJS += $(OUTPUT)ui/browser.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/map.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/setup.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/util.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/progress.o
|
||||
LIB_H += ui/browser.h
|
||||
LIB_H += ui/browsers/map.h
|
||||
LIB_H += ui/keysyms.h
|
||||
LIB_H += ui/libslang.h
|
||||
endif
|
||||
|
||||
ifndef NO_GTK2
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/util.o
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPERL
|
||||
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
|
||||
LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPYTHON
|
||||
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
|
||||
LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
|
||||
endif
|
||||
|
||||
ifeq ($(NO_PERF_REGS),0)
|
||||
ifeq ($(ARCH),x86)
|
||||
LIB_H += arch/x86/include/perf_regs.h
|
||||
#
|
||||
# Do a parallel build with multiple jobs, based on the number of CPUs online
|
||||
# in this system: 'make -j8' on a 8-CPU system, etc.
|
||||
#
|
||||
# (To override it, run 'make JOBS=1' and similar.)
|
||||
#
|
||||
ifeq ($(JOBS),)
|
||||
JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
|
||||
ifeq ($(JOBS),)
|
||||
JOBS := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_LIBNUMA
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/numa.o
|
||||
#
|
||||
# Only pass canonical directory names as the output directory:
|
||||
#
|
||||
ifneq ($(O),)
|
||||
FULL_O := $(shell readlink -f $(O) || echo $(O))
|
||||
endif
|
||||
|
||||
ifdef ASCIIDOC8
|
||||
export ASCIIDOC8
|
||||
#
|
||||
# Only accept the 'DEBUG' variable from the command line:
|
||||
#
|
||||
ifeq ("$(origin DEBUG)", "command line")
|
||||
ifeq ($(DEBUG),)
|
||||
override DEBUG = 0
|
||||
else
|
||||
SET_DEBUG = "DEBUG=$(DEBUG)"
|
||||
endif
|
||||
else
|
||||
override DEBUG = 0
|
||||
endif
|
||||
|
||||
LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
|
||||
define print_msg
|
||||
@printf ' BUILD: Doing '\''make \033[33m-j'$(JOBS)'\033[m'\'' parallel build\n'
|
||||
endef
|
||||
|
||||
export INSTALL SHELL_PATH
|
||||
define make
|
||||
@$(MAKE) -f Makefile.perf --no-print-directory -j$(JOBS) O=$(FULL_O) $(SET_DEBUG) $@
|
||||
endef
|
||||
|
||||
### Build rules
|
||||
#
|
||||
# Needed if no target specified:
|
||||
#
|
||||
all:
|
||||
$(print_msg)
|
||||
$(make)
|
||||
|
||||
SHELL = $(SHELL_PATH)
|
||||
#
|
||||
# The clean target is not really parallel, don't print the jobs info:
|
||||
#
|
||||
clean:
|
||||
$(make)
|
||||
|
||||
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
|
||||
|
||||
please_set_SHELL_PATH_to_a_more_modern_shell:
|
||||
@$$(:)
|
||||
|
||||
shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
|
||||
|
||||
strip: $(PROGRAMS) $(OUTPUT)perf
|
||||
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
|
||||
|
||||
$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
|
||||
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
|
||||
$(CFLAGS) -c $(filter %.c,$^) -o $@
|
||||
|
||||
$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
|
||||
$(BUILTIN_OBJS) $(LIBS) -o $@
|
||||
|
||||
$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
|
||||
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
|
||||
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
|
||||
|
||||
$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
|
||||
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
|
||||
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
|
||||
|
||||
$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
|
||||
|
||||
$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
|
||||
$(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
|
||||
|
||||
$(SCRIPTS) : % : %.sh
|
||||
$(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
|
||||
|
||||
# These can record PERF_VERSION
|
||||
$(OUTPUT)perf.o perf.spec \
|
||||
$(SCRIPTS) \
|
||||
: $(OUTPUT)PERF-VERSION-FILE
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .c .S .s
|
||||
|
||||
# These two need to be here so that when O= is not used they take precedence
|
||||
# over the general rule for .o
|
||||
|
||||
$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
|
||||
|
||||
$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
|
||||
|
||||
$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
|
||||
$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
|
||||
$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
|
||||
$(OUTPUT)%.o: %.S
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
|
||||
$(OUTPUT)%.s: %.S
|
||||
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
|
||||
|
||||
$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
|
||||
'-DPREFIX="$(prefix_SQ)"' \
|
||||
$<
|
||||
|
||||
$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
|
||||
$<
|
||||
|
||||
$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
-DPYTHONPATH='"$(OUTPUT)python"' \
|
||||
-DPYTHON='"$(PYTHON_WORD)"' \
|
||||
$<
|
||||
|
||||
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
|
||||
|
||||
$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
|
||||
|
||||
$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
|
||||
|
||||
$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
|
||||
|
||||
$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
|
||||
|
||||
$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
|
||||
|
||||
$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
|
||||
|
||||
$(OUTPUT)perf-%: %.o $(PERFLIBS)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
|
||||
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
|
||||
$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
|
||||
|
||||
# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
|
||||
# we depend the various files onto their directories.
|
||||
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
|
||||
$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
|
||||
# In the second step, we make a rule to actually create these directories
|
||||
$(sort $(dir $(DIRECTORY_DEPS))):
|
||||
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
|
||||
|
||||
$(LIB_FILE): $(LIB_OBJS)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
|
||||
|
||||
# libtraceevent.a
|
||||
$(LIBTRACEEVENT):
|
||||
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a
|
||||
|
||||
$(LIBTRACEEVENT)-clean:
|
||||
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
|
||||
|
||||
# if subdir is set, we've been called from above so target has been built
|
||||
# already
|
||||
$(LIBLK):
|
||||
ifeq ($(subdir),)
|
||||
$(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
|
||||
endif
|
||||
|
||||
$(LIBLK)-clean:
|
||||
ifeq ($(subdir),)
|
||||
$(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
|
||||
endif
|
||||
|
||||
help:
|
||||
@echo 'Perf make targets:'
|
||||
@echo ' doc - make *all* documentation (see below)'
|
||||
@echo ' man - make manpage documentation (access with man <foo>)'
|
||||
@echo ' html - make html documentation'
|
||||
@echo ' info - make GNU info documentation (access with info <foo>)'
|
||||
@echo ' pdf - make pdf documentation'
|
||||
@echo ' TAGS - use etags to make tag information for source browsing'
|
||||
@echo ' tags - use ctags to make tag information for source browsing'
|
||||
@echo ' cscope - use cscope to make interactive browsing database'
|
||||
@echo ''
|
||||
@echo 'Perf install targets:'
|
||||
@echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
|
||||
@echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
|
||||
@echo ' path like make prefix=/usr/local install install-doc'
|
||||
@echo ' install - install compiled binaries'
|
||||
@echo ' install-doc - install *all* documentation'
|
||||
@echo ' install-man - install manpage documentation'
|
||||
@echo ' install-html - install html documentation'
|
||||
@echo ' install-info - install GNU info documentation'
|
||||
@echo ' install-pdf - install pdf documentation'
|
||||
@echo ''
|
||||
@echo ' quick-install-doc - alias for quick-install-man'
|
||||
@echo ' quick-install-man - install the documentation quickly'
|
||||
@echo ' quick-install-html - install the html documentation quickly'
|
||||
@echo ''
|
||||
@echo 'Perf maintainer targets:'
|
||||
@echo ' clean - clean all binary objects and build output'
|
||||
|
||||
|
||||
DOC_TARGETS := doc man html info pdf
|
||||
|
||||
INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
|
||||
INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
|
||||
|
||||
# 'make doc' should call 'make -C Documentation all'
|
||||
$(DOC_TARGETS):
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
|
||||
|
||||
TAGS:
|
||||
$(RM) TAGS
|
||||
$(FIND) . -name '*.[hcS]' -print | xargs etags -a
|
||||
|
||||
tags:
|
||||
$(RM) tags
|
||||
$(FIND) . -name '*.[hcS]' -print | xargs ctags -a
|
||||
|
||||
cscope:
|
||||
$(RM) cscope*
|
||||
$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
|
||||
|
||||
### Detect prefix changes
|
||||
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
|
||||
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
|
||||
|
||||
$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
|
||||
@FLAGS='$(TRACK_CFLAGS)'; \
|
||||
if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
|
||||
echo 1>&2 " * new build flags or prefix"; \
|
||||
echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
|
||||
fi
|
||||
|
||||
### Testing rules
|
||||
|
||||
# GNU make supports exporting all variables by "export" without parameters.
|
||||
# However, the environment gets quite big, and some programs have problems
|
||||
# with that.
|
||||
|
||||
check: $(OUTPUT)common-cmds.h
|
||||
if sparse; \
|
||||
then \
|
||||
for i in *.c */*.c; \
|
||||
do \
|
||||
sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
|
||||
done; \
|
||||
else \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
### Installation rules
|
||||
|
||||
install-bin: all
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
|
||||
$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
|
||||
ifndef NO_LIBPERL
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
|
||||
$(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
|
||||
$(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
|
||||
$(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
|
||||
endif
|
||||
ifndef NO_LIBPYTHON
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
|
||||
$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
|
||||
$(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
|
||||
$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
|
||||
endif
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
|
||||
$(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
|
||||
$(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
|
||||
$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
|
||||
|
||||
install: install-bin try-install-man
|
||||
|
||||
install-python_ext:
|
||||
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
|
||||
|
||||
# 'make install-doc' should call 'make -C Documentation install'
|
||||
$(INSTALL_DOC_TARGETS):
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
|
||||
|
||||
### Cleaning rules
|
||||
|
||||
clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean
|
||||
$(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
|
||||
$(RM) $(ALL_PROGRAMS) perf
|
||||
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
|
||||
$(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
|
||||
$(RM) $(OUTPUT)util/*-bison*
|
||||
$(RM) $(OUTPUT)util/*-flex*
|
||||
$(python-clean)
|
||||
|
||||
.PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK)
|
||||
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
|
||||
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
|
||||
#
|
||||
# All other targets get passed through:
|
||||
#
|
||||
%:
|
||||
$(print_msg)
|
||||
$(make)
|
||||
|
892
tools/perf/Makefile.perf
Normal file
892
tools/perf/Makefile.perf
Normal file
@ -0,0 +1,892 @@
|
||||
include ../scripts/Makefile.include
|
||||
|
||||
# The default target of this Makefile is...
|
||||
all:
|
||||
|
||||
include config/utilities.mak
|
||||
|
||||
# Define V to have a more verbose compile.
|
||||
#
|
||||
# Define O to save output files in a separate directory.
|
||||
#
|
||||
# Define ARCH as name of target architecture if you want cross-builds.
|
||||
#
|
||||
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
|
||||
#
|
||||
# Define NO_LIBPERL to disable perl script extension.
|
||||
#
|
||||
# Define NO_LIBPYTHON to disable python script extension.
|
||||
#
|
||||
# Define PYTHON to point to the python binary if the default
|
||||
# `python' is not correct; for example: PYTHON=python2
|
||||
#
|
||||
# Define PYTHON_CONFIG to point to the python-config binary if
|
||||
# the default `$(PYTHON)-config' is not correct.
|
||||
#
|
||||
# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
|
||||
#
|
||||
# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
|
||||
#
|
||||
# Define LDFLAGS=-static to build a static binary.
|
||||
#
|
||||
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
|
||||
#
|
||||
# Define NO_DWARF if you do not want debug-info analysis feature at all.
|
||||
#
|
||||
# Define WERROR=0 to disable treating any warnings as errors.
|
||||
#
|
||||
# Define NO_NEWT if you do not want TUI support. (deprecated)
|
||||
#
|
||||
# Define NO_SLANG if you do not want TUI support.
|
||||
#
|
||||
# Define NO_GTK2 if you do not want GTK+ GUI support.
|
||||
#
|
||||
# Define NO_DEMANGLE if you do not want C++ symbol demangling.
|
||||
#
|
||||
# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds)
|
||||
#
|
||||
# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf
|
||||
# backtrace post unwind.
|
||||
#
|
||||
# Define NO_BACKTRACE if you do not want stack backtrace debug feature
|
||||
#
|
||||
# Define NO_LIBNUMA if you do not want numa perf benchmark
|
||||
#
|
||||
# Define NO_LIBAUDIT if you do not want libaudit support
|
||||
#
|
||||
# Define NO_LIBBIONIC if you do not want bionic support
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
#$(info Determined 'srctree' to be $(srctree))
|
||||
endif
|
||||
|
||||
ifneq ($(objtree),)
|
||||
#$(info Determined 'objtree' to be $(objtree))
|
||||
endif
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
#$(info Determined 'OUTPUT' to be $(OUTPUT))
|
||||
endif
|
||||
|
||||
$(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
|
||||
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
|
||||
@touch $(OUTPUT)PERF-VERSION-FILE
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
AR = $(CROSS_COMPILE)ar
|
||||
|
||||
RM = rm -f
|
||||
LN = ln -f
|
||||
MKDIR = mkdir
|
||||
FIND = find
|
||||
INSTALL = install
|
||||
FLEX = flex
|
||||
BISON = bison
|
||||
STRIP = strip
|
||||
|
||||
LK_DIR = $(srctree)/tools/lib/lk/
|
||||
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
|
||||
|
||||
# include config/Makefile by default and rule out
|
||||
# non-config cases
|
||||
config := 1
|
||||
|
||||
NON_CONFIG_TARGETS := clean TAGS tags cscope help
|
||||
|
||||
ifdef MAKECMDGOALS
|
||||
ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
|
||||
config := 0
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(config),1)
|
||||
include config/Makefile
|
||||
endif
|
||||
|
||||
export prefix bindir sharedir sysconfdir
|
||||
|
||||
# sparse is architecture-neutral, which means that we need to tell it
|
||||
# explicitly what architecture to check for. Fix this up for yours..
|
||||
SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
|
||||
|
||||
# Guard against environment variables
|
||||
BUILTIN_OBJS =
|
||||
LIB_H =
|
||||
LIB_OBJS =
|
||||
GTK_OBJS =
|
||||
PYRF_OBJS =
|
||||
SCRIPT_SH =
|
||||
|
||||
SCRIPT_SH += perf-archive.sh
|
||||
|
||||
grep-libs = $(filter -l%,$(1))
|
||||
strip-libs = $(filter-out -l%,$(1))
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
TE_PATH=$(OUTPUT)
|
||||
ifneq ($(subdir),)
|
||||
LK_PATH=$(OUTPUT)/../lib/lk/
|
||||
else
|
||||
LK_PATH=$(OUTPUT)
|
||||
endif
|
||||
else
|
||||
TE_PATH=$(TRACE_EVENT_DIR)
|
||||
LK_PATH=$(LK_DIR)
|
||||
endif
|
||||
|
||||
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
|
||||
export LIBTRACEEVENT
|
||||
|
||||
LIBLK = $(LK_PATH)liblk.a
|
||||
export LIBLK
|
||||
|
||||
# python extension build directories
|
||||
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
|
||||
PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
|
||||
PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
|
||||
export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
|
||||
|
||||
python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
|
||||
|
||||
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
|
||||
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
|
||||
|
||||
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
|
||||
$(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
|
||||
--quiet build_ext; \
|
||||
mkdir -p $(OUTPUT)python && \
|
||||
cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
|
||||
#
|
||||
# No Perl scripts right now:
|
||||
#
|
||||
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
|
||||
|
||||
#
|
||||
# Single 'perf' binary right now:
|
||||
#
|
||||
PROGRAMS += $(OUTPUT)perf
|
||||
|
||||
# what 'all' will build and 'install' will install, in perfexecdir
|
||||
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
|
||||
|
||||
# what 'all' will build but not install in perfexecdir
|
||||
OTHER_PROGRAMS = $(OUTPUT)perf
|
||||
|
||||
# Set paths to tools early so that they can be used for version tests.
|
||||
ifndef SHELL_PATH
|
||||
SHELL_PATH = /bin/sh
|
||||
endif
|
||||
ifndef PERL_PATH
|
||||
PERL_PATH = /usr/bin/perl
|
||||
endif
|
||||
|
||||
export PERL_PATH
|
||||
|
||||
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
|
||||
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
|
||||
|
||||
$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
|
||||
$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
|
||||
|
||||
$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
|
||||
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
|
||||
|
||||
$(OUTPUT)util/pmu-bison.c: util/pmu.y
|
||||
$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
|
||||
|
||||
$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
|
||||
$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
|
||||
|
||||
LIB_FILE=$(OUTPUT)libperf.a
|
||||
|
||||
LIB_H += ../../include/uapi/linux/perf_event.h
|
||||
LIB_H += ../../include/linux/rbtree.h
|
||||
LIB_H += ../../include/linux/list.h
|
||||
LIB_H += ../../include/uapi/linux/const.h
|
||||
LIB_H += ../../include/linux/hash.h
|
||||
LIB_H += ../../include/linux/stringify.h
|
||||
LIB_H += util/include/linux/bitmap.h
|
||||
LIB_H += util/include/linux/bitops.h
|
||||
LIB_H += util/include/linux/compiler.h
|
||||
LIB_H += util/include/linux/const.h
|
||||
LIB_H += util/include/linux/ctype.h
|
||||
LIB_H += util/include/linux/kernel.h
|
||||
LIB_H += util/include/linux/list.h
|
||||
LIB_H += util/include/linux/export.h
|
||||
LIB_H += util/include/linux/magic.h
|
||||
LIB_H += util/include/linux/poison.h
|
||||
LIB_H += util/include/linux/prefetch.h
|
||||
LIB_H += util/include/linux/rbtree.h
|
||||
LIB_H += util/include/linux/rbtree_augmented.h
|
||||
LIB_H += util/include/linux/string.h
|
||||
LIB_H += util/include/linux/types.h
|
||||
LIB_H += util/include/linux/linkage.h
|
||||
LIB_H += util/include/asm/asm-offsets.h
|
||||
LIB_H += util/include/asm/bug.h
|
||||
LIB_H += util/include/asm/byteorder.h
|
||||
LIB_H += util/include/asm/hweight.h
|
||||
LIB_H += util/include/asm/swab.h
|
||||
LIB_H += util/include/asm/system.h
|
||||
LIB_H += util/include/asm/uaccess.h
|
||||
LIB_H += util/include/dwarf-regs.h
|
||||
LIB_H += util/include/asm/dwarf2.h
|
||||
LIB_H += util/include/asm/cpufeature.h
|
||||
LIB_H += util/include/asm/unistd_32.h
|
||||
LIB_H += util/include/asm/unistd_64.h
|
||||
LIB_H += perf.h
|
||||
LIB_H += util/annotate.h
|
||||
LIB_H += util/cache.h
|
||||
LIB_H += util/callchain.h
|
||||
LIB_H += util/build-id.h
|
||||
LIB_H += util/debug.h
|
||||
LIB_H += util/fs.h
|
||||
LIB_H += util/pmu.h
|
||||
LIB_H += util/event.h
|
||||
LIB_H += util/evsel.h
|
||||
LIB_H += util/evlist.h
|
||||
LIB_H += util/exec_cmd.h
|
||||
LIB_H += util/types.h
|
||||
LIB_H += util/levenshtein.h
|
||||
LIB_H += util/machine.h
|
||||
LIB_H += util/map.h
|
||||
LIB_H += util/parse-options.h
|
||||
LIB_H += util/parse-events.h
|
||||
LIB_H += util/quote.h
|
||||
LIB_H += util/util.h
|
||||
LIB_H += util/xyarray.h
|
||||
LIB_H += util/header.h
|
||||
LIB_H += util/help.h
|
||||
LIB_H += util/session.h
|
||||
LIB_H += util/strbuf.h
|
||||
LIB_H += util/strlist.h
|
||||
LIB_H += util/strfilter.h
|
||||
LIB_H += util/svghelper.h
|
||||
LIB_H += util/tool.h
|
||||
LIB_H += util/run-command.h
|
||||
LIB_H += util/sigchain.h
|
||||
LIB_H += util/dso.h
|
||||
LIB_H += util/symbol.h
|
||||
LIB_H += util/color.h
|
||||
LIB_H += util/values.h
|
||||
LIB_H += util/sort.h
|
||||
LIB_H += util/hist.h
|
||||
LIB_H += util/comm.h
|
||||
LIB_H += util/thread.h
|
||||
LIB_H += util/thread_map.h
|
||||
LIB_H += util/trace-event.h
|
||||
LIB_H += util/probe-finder.h
|
||||
LIB_H += util/dwarf-aux.h
|
||||
LIB_H += util/probe-event.h
|
||||
LIB_H += util/pstack.h
|
||||
LIB_H += util/cpumap.h
|
||||
LIB_H += util/top.h
|
||||
LIB_H += $(ARCH_INCLUDE)
|
||||
LIB_H += util/cgroup.h
|
||||
LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
|
||||
LIB_H += util/target.h
|
||||
LIB_H += util/rblist.h
|
||||
LIB_H += util/intlist.h
|
||||
LIB_H += util/perf_regs.h
|
||||
LIB_H += util/unwind.h
|
||||
LIB_H += util/vdso.h
|
||||
LIB_H += ui/helpline.h
|
||||
LIB_H += ui/progress.h
|
||||
LIB_H += ui/util.h
|
||||
LIB_H += ui/ui.h
|
||||
LIB_H += util/data.h
|
||||
|
||||
LIB_OBJS += $(OUTPUT)util/abspath.o
|
||||
LIB_OBJS += $(OUTPUT)util/alias.o
|
||||
LIB_OBJS += $(OUTPUT)util/annotate.o
|
||||
LIB_OBJS += $(OUTPUT)util/build-id.o
|
||||
LIB_OBJS += $(OUTPUT)util/config.o
|
||||
LIB_OBJS += $(OUTPUT)util/ctype.o
|
||||
LIB_OBJS += $(OUTPUT)util/fs.o
|
||||
LIB_OBJS += $(OUTPUT)util/pmu.o
|
||||
LIB_OBJS += $(OUTPUT)util/environment.o
|
||||
LIB_OBJS += $(OUTPUT)util/event.o
|
||||
LIB_OBJS += $(OUTPUT)util/evlist.o
|
||||
LIB_OBJS += $(OUTPUT)util/evsel.o
|
||||
LIB_OBJS += $(OUTPUT)util/exec_cmd.o
|
||||
LIB_OBJS += $(OUTPUT)util/help.o
|
||||
LIB_OBJS += $(OUTPUT)util/levenshtein.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-options.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-events.o
|
||||
LIB_OBJS += $(OUTPUT)util/path.o
|
||||
LIB_OBJS += $(OUTPUT)util/rbtree.o
|
||||
LIB_OBJS += $(OUTPUT)util/bitmap.o
|
||||
LIB_OBJS += $(OUTPUT)util/hweight.o
|
||||
LIB_OBJS += $(OUTPUT)util/run-command.o
|
||||
LIB_OBJS += $(OUTPUT)util/quote.o
|
||||
LIB_OBJS += $(OUTPUT)util/strbuf.o
|
||||
LIB_OBJS += $(OUTPUT)util/string.o
|
||||
LIB_OBJS += $(OUTPUT)util/strlist.o
|
||||
LIB_OBJS += $(OUTPUT)util/strfilter.o
|
||||
LIB_OBJS += $(OUTPUT)util/top.o
|
||||
LIB_OBJS += $(OUTPUT)util/usage.o
|
||||
LIB_OBJS += $(OUTPUT)util/wrapper.o
|
||||
LIB_OBJS += $(OUTPUT)util/sigchain.o
|
||||
LIB_OBJS += $(OUTPUT)util/dso.o
|
||||
LIB_OBJS += $(OUTPUT)util/symbol.o
|
||||
LIB_OBJS += $(OUTPUT)util/symbol-elf.o
|
||||
LIB_OBJS += $(OUTPUT)util/color.o
|
||||
LIB_OBJS += $(OUTPUT)util/pager.o
|
||||
LIB_OBJS += $(OUTPUT)util/header.o
|
||||
LIB_OBJS += $(OUTPUT)util/callchain.o
|
||||
LIB_OBJS += $(OUTPUT)util/values.o
|
||||
LIB_OBJS += $(OUTPUT)util/debug.o
|
||||
LIB_OBJS += $(OUTPUT)util/machine.o
|
||||
LIB_OBJS += $(OUTPUT)util/map.o
|
||||
LIB_OBJS += $(OUTPUT)util/pstack.o
|
||||
LIB_OBJS += $(OUTPUT)util/session.o
|
||||
LIB_OBJS += $(OUTPUT)util/comm.o
|
||||
LIB_OBJS += $(OUTPUT)util/thread.o
|
||||
LIB_OBJS += $(OUTPUT)util/thread_map.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
|
||||
LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
|
||||
LIB_OBJS += $(OUTPUT)util/pmu-flex.o
|
||||
LIB_OBJS += $(OUTPUT)util/pmu-bison.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-read.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-info.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
|
||||
LIB_OBJS += $(OUTPUT)util/svghelper.o
|
||||
LIB_OBJS += $(OUTPUT)util/sort.o
|
||||
LIB_OBJS += $(OUTPUT)util/hist.o
|
||||
LIB_OBJS += $(OUTPUT)util/probe-event.o
|
||||
LIB_OBJS += $(OUTPUT)util/util.o
|
||||
LIB_OBJS += $(OUTPUT)util/xyarray.o
|
||||
LIB_OBJS += $(OUTPUT)util/cpumap.o
|
||||
LIB_OBJS += $(OUTPUT)util/cgroup.o
|
||||
LIB_OBJS += $(OUTPUT)util/target.o
|
||||
LIB_OBJS += $(OUTPUT)util/rblist.o
|
||||
LIB_OBJS += $(OUTPUT)util/intlist.o
|
||||
LIB_OBJS += $(OUTPUT)util/vdso.o
|
||||
LIB_OBJS += $(OUTPUT)util/stat.o
|
||||
LIB_OBJS += $(OUTPUT)util/record.o
|
||||
LIB_OBJS += $(OUTPUT)util/srcline.o
|
||||
LIB_OBJS += $(OUTPUT)util/data.o
|
||||
|
||||
LIB_OBJS += $(OUTPUT)ui/setup.o
|
||||
LIB_OBJS += $(OUTPUT)ui/helpline.o
|
||||
LIB_OBJS += $(OUTPUT)ui/progress.o
|
||||
LIB_OBJS += $(OUTPUT)ui/util.o
|
||||
LIB_OBJS += $(OUTPUT)ui/hist.o
|
||||
LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
|
||||
|
||||
LIB_OBJS += $(OUTPUT)arch/common.o
|
||||
|
||||
LIB_OBJS += $(OUTPUT)tests/parse-events.o
|
||||
LIB_OBJS += $(OUTPUT)tests/dso-data.o
|
||||
LIB_OBJS += $(OUTPUT)tests/attr.o
|
||||
LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
|
||||
LIB_OBJS += $(OUTPUT)tests/open-syscall.o
|
||||
LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
|
||||
LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
|
||||
LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
|
||||
LIB_OBJS += $(OUTPUT)tests/perf-record.o
|
||||
LIB_OBJS += $(OUTPUT)tests/rdpmc.o
|
||||
LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
|
||||
LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
|
||||
LIB_OBJS += $(OUTPUT)tests/pmu.o
|
||||
LIB_OBJS += $(OUTPUT)tests/hists_link.o
|
||||
LIB_OBJS += $(OUTPUT)tests/python-use.o
|
||||
LIB_OBJS += $(OUTPUT)tests/bp_signal.o
|
||||
LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
|
||||
LIB_OBJS += $(OUTPUT)tests/task-exit.o
|
||||
LIB_OBJS += $(OUTPUT)tests/sw-clock.o
|
||||
ifeq ($(ARCH),x86)
|
||||
LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
|
||||
endif
|
||||
LIB_OBJS += $(OUTPUT)tests/code-reading.o
|
||||
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
|
||||
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
|
||||
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
|
||||
# Benchmark modules
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
|
||||
ifeq ($(RAW_ARCH),x86_64)
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
|
||||
endif
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
|
||||
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-help.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-list.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-record.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-report.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-top.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-script.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
|
||||
BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
|
||||
|
||||
PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
|
||||
|
||||
# We choose to avoid "if .. else if .. else .. endif endif"
|
||||
# because maintaining the nesting to match is a pain. If
|
||||
# we had "elif" things would have been much nicer...
|
||||
|
||||
-include arch/$(ARCH)/Makefile
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
CFLAGS += -I$(OUTPUT)
|
||||
endif
|
||||
|
||||
ifdef NO_LIBELF
|
||||
EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
|
||||
|
||||
# Remove ELF/DWARF dependent codes
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
|
||||
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
|
||||
|
||||
BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
|
||||
|
||||
# Use minimal symbol handling
|
||||
LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
|
||||
|
||||
else # NO_LIBELF
|
||||
ifndef NO_DWARF
|
||||
LIB_OBJS += $(OUTPUT)util/probe-finder.o
|
||||
LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
|
||||
endif # NO_DWARF
|
||||
endif # NO_LIBELF
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
LIB_OBJS += $(OUTPUT)util/unwind.o
|
||||
endif
|
||||
LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
|
||||
|
||||
ifndef NO_LIBAUDIT
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
|
||||
endif
|
||||
|
||||
ifndef NO_SLANG
|
||||
LIB_OBJS += $(OUTPUT)ui/browser.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/map.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/setup.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/util.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/progress.o
|
||||
LIB_H += ui/tui/tui.h
|
||||
LIB_H += ui/browser.h
|
||||
LIB_H += ui/browsers/map.h
|
||||
LIB_H += ui/keysyms.h
|
||||
LIB_H += ui/libslang.h
|
||||
endif
|
||||
|
||||
ifndef NO_GTK2
|
||||
ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so
|
||||
|
||||
GTK_OBJS += $(OUTPUT)ui/gtk/browser.o
|
||||
GTK_OBJS += $(OUTPUT)ui/gtk/hists.o
|
||||
GTK_OBJS += $(OUTPUT)ui/gtk/setup.o
|
||||
GTK_OBJS += $(OUTPUT)ui/gtk/util.o
|
||||
GTK_OBJS += $(OUTPUT)ui/gtk/helpline.o
|
||||
GTK_OBJS += $(OUTPUT)ui/gtk/progress.o
|
||||
GTK_OBJS += $(OUTPUT)ui/gtk/annotate.o
|
||||
|
||||
install-gtk: $(OUTPUT)libperf-gtk.so
|
||||
$(call QUIET_INSTALL, 'GTK UI') \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \
|
||||
$(INSTALL) $(OUTPUT)libperf-gtk.so '$(DESTDIR_SQ)$(libdir_SQ)'
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPERL
|
||||
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
|
||||
LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPYTHON
|
||||
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
|
||||
LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
|
||||
endif
|
||||
|
||||
ifeq ($(NO_PERF_REGS),0)
|
||||
ifeq ($(ARCH),x86)
|
||||
LIB_H += arch/x86/include/perf_regs.h
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_LIBNUMA
|
||||
BUILTIN_OBJS += $(OUTPUT)bench/numa.o
|
||||
endif
|
||||
|
||||
ifdef ASCIIDOC8
|
||||
export ASCIIDOC8
|
||||
endif
|
||||
|
||||
LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
|
||||
|
||||
export INSTALL SHELL_PATH
|
||||
|
||||
### Build rules
|
||||
|
||||
SHELL = $(SHELL_PATH)
|
||||
|
||||
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
|
||||
|
||||
please_set_SHELL_PATH_to_a_more_modern_shell:
|
||||
@$$(:)
|
||||
|
||||
shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
|
||||
|
||||
strip: $(PROGRAMS) $(OUTPUT)perf
|
||||
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
|
||||
|
||||
$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
|
||||
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
|
||||
$(CFLAGS) -c $(filter %.c,$^) -o $@
|
||||
|
||||
$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
|
||||
$(BUILTIN_OBJS) $(LIBS) -o $@
|
||||
|
||||
$(GTK_OBJS): $(OUTPUT)%.o: %.c $(LIB_H)
|
||||
$(QUIET_CC)$(CC) -o $@ -c -fPIC $(CFLAGS) $(GTK_CFLAGS) $<
|
||||
|
||||
$(OUTPUT)libperf-gtk.so: $(GTK_OBJS) $(PERFLIBS)
|
||||
$(QUIET_LINK)$(CC) -o $@ -shared $(ALL_LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
|
||||
|
||||
$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
|
||||
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
|
||||
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
|
||||
|
||||
$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
|
||||
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
|
||||
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
|
||||
|
||||
$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
|
||||
|
||||
$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
|
||||
$(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
|
||||
|
||||
$(SCRIPTS) : % : %.sh
|
||||
$(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
|
||||
|
||||
# These can record PERF_VERSION
|
||||
$(OUTPUT)perf.o perf.spec \
|
||||
$(SCRIPTS) \
|
||||
: $(OUTPUT)PERF-VERSION-FILE
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
#
|
||||
# If a target does not match any of the later rules then prefix it by $(OUTPUT)
|
||||
# This makes targets like 'make O=/tmp/perf perf.o' work in a natural way.
|
||||
#
|
||||
ifneq ($(OUTPUT),)
|
||||
%.o: $(OUTPUT)%.o
|
||||
@echo " # Redirected target $@ => $(OUTPUT)$@"
|
||||
util/%.o: $(OUTPUT)util/%.o
|
||||
@echo " # Redirected target $@ => $(OUTPUT)$@"
|
||||
bench/%.o: $(OUTPUT)bench/%.o
|
||||
@echo " # Redirected target $@ => $(OUTPUT)$@"
|
||||
tests/%.o: $(OUTPUT)tests/%.o
|
||||
@echo " # Redirected target $@ => $(OUTPUT)$@"
|
||||
endif
|
||||
|
||||
# These two need to be here so that when O= is not used they take precedence
|
||||
# over the general rule for .o
|
||||
|
||||
$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
|
||||
|
||||
$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
|
||||
|
||||
$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
|
||||
$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
|
||||
$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
|
||||
$(OUTPUT)%.o: %.S
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
|
||||
$(OUTPUT)%.s: %.S
|
||||
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
|
||||
|
||||
$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
|
||||
'-DPREFIX="$(prefix_SQ)"' \
|
||||
$<
|
||||
|
||||
$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
'-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
|
||||
$<
|
||||
|
||||
$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
|
||||
-DPYTHONPATH='"$(OUTPUT)python"' \
|
||||
-DPYTHON='"$(PYTHON_WORD)"' \
|
||||
$<
|
||||
|
||||
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
|
||||
|
||||
$(OUTPUT)ui/setup.o: ui/setup.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DLIBDIR='"$(libdir_SQ)"' $<
|
||||
|
||||
$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
|
||||
|
||||
$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
|
||||
|
||||
$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
|
||||
|
||||
$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
|
||||
|
||||
$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
|
||||
|
||||
$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
|
||||
|
||||
$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
|
||||
|
||||
$(OUTPUT)perf-%: %.o $(PERFLIBS)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
|
||||
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
|
||||
$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
|
||||
|
||||
# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
|
||||
# we depend the various files onto their directories.
|
||||
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
|
||||
DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
|
||||
$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
|
||||
# In the second step, we make a rule to actually create these directories
|
||||
$(sort $(dir $(DIRECTORY_DEPS))):
|
||||
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
|
||||
|
||||
$(LIB_FILE): $(LIB_OBJS)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
|
||||
|
||||
# libtraceevent.a
|
||||
TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
|
||||
|
||||
$(LIBTRACEEVENT): $(TE_SOURCES)
|
||||
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a
|
||||
|
||||
$(LIBTRACEEVENT)-clean:
|
||||
$(call QUIET_CLEAN, libtraceevent)
|
||||
@$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
|
||||
LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch])
|
||||
|
||||
# if subdir is set, we've been called from above so target has been built
|
||||
# already
|
||||
$(LIBLK): $(LIBLK_SOURCES)
|
||||
ifeq ($(subdir),)
|
||||
$(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
|
||||
endif
|
||||
|
||||
$(LIBLK)-clean:
|
||||
ifeq ($(subdir),)
|
||||
$(call QUIET_CLEAN, liblk)
|
||||
@$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
endif
|
||||
|
||||
help:
|
||||
@echo 'Perf make targets:'
|
||||
@echo ' doc - make *all* documentation (see below)'
|
||||
@echo ' man - make manpage documentation (access with man <foo>)'
|
||||
@echo ' html - make html documentation'
|
||||
@echo ' info - make GNU info documentation (access with info <foo>)'
|
||||
@echo ' pdf - make pdf documentation'
|
||||
@echo ' TAGS - use etags to make tag information for source browsing'
|
||||
@echo ' tags - use ctags to make tag information for source browsing'
|
||||
@echo ' cscope - use cscope to make interactive browsing database'
|
||||
@echo ''
|
||||
@echo 'Perf install targets:'
|
||||
@echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
|
||||
@echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
|
||||
@echo ' path like make prefix=/usr/local install install-doc'
|
||||
@echo ' install - install compiled binaries'
|
||||
@echo ' install-doc - install *all* documentation'
|
||||
@echo ' install-man - install manpage documentation'
|
||||
@echo ' install-html - install html documentation'
|
||||
@echo ' install-info - install GNU info documentation'
|
||||
@echo ' install-pdf - install pdf documentation'
|
||||
@echo ''
|
||||
@echo ' quick-install-doc - alias for quick-install-man'
|
||||
@echo ' quick-install-man - install the documentation quickly'
|
||||
@echo ' quick-install-html - install the html documentation quickly'
|
||||
@echo ''
|
||||
@echo 'Perf maintainer targets:'
|
||||
@echo ' clean - clean all binary objects and build output'
|
||||
|
||||
|
||||
DOC_TARGETS := doc man html info pdf
|
||||
|
||||
INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
|
||||
INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
|
||||
|
||||
# 'make doc' should call 'make -C Documentation all'
|
||||
$(DOC_TARGETS):
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
|
||||
|
||||
TAGS:
|
||||
$(RM) TAGS
|
||||
$(FIND) . -name '*.[hcS]' -print | xargs etags -a
|
||||
|
||||
tags:
|
||||
$(RM) tags
|
||||
$(FIND) . -name '*.[hcS]' -print | xargs ctags -a
|
||||
|
||||
cscope:
|
||||
$(RM) cscope*
|
||||
$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
|
||||
|
||||
### Detect prefix changes
|
||||
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
|
||||
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
|
||||
|
||||
$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
|
||||
@FLAGS='$(TRACK_CFLAGS)'; \
|
||||
if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
|
||||
echo 1>&2 " FLAGS: * new build flags or prefix"; \
|
||||
echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
|
||||
fi
|
||||
|
||||
### Testing rules
|
||||
|
||||
# GNU make supports exporting all variables by "export" without parameters.
|
||||
# However, the environment gets quite big, and some programs have problems
|
||||
# with that.
|
||||
|
||||
check: $(OUTPUT)common-cmds.h
|
||||
if sparse; \
|
||||
then \
|
||||
for i in *.c */*.c; \
|
||||
do \
|
||||
sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
|
||||
done; \
|
||||
else \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
### Installation rules
|
||||
|
||||
install-gtk:
|
||||
|
||||
install-bin: all install-gtk
|
||||
$(call QUIET_INSTALL, binaries) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
|
||||
$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
|
||||
$(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
|
||||
$(call QUIET_INSTALL, libexec) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
|
||||
$(call QUIET_INSTALL, perf-archive) \
|
||||
$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
|
||||
ifndef NO_LIBPERL
|
||||
$(call QUIET_INSTALL, perl-scripts) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
|
||||
$(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
|
||||
$(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \
|
||||
$(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
|
||||
endif
|
||||
ifndef NO_LIBPYTHON
|
||||
$(call QUIET_INSTALL, python-scripts) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'; \
|
||||
$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
|
||||
$(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
|
||||
$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
|
||||
endif
|
||||
$(call QUIET_INSTALL, bash_completion-script) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
|
||||
$(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
|
||||
$(call QUIET_INSTALL, tests) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
|
||||
$(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
|
||||
$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
|
||||
|
||||
install: install-bin try-install-man
|
||||
|
||||
install-python_ext:
|
||||
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
|
||||
|
||||
# 'make install-doc' should call 'make -C Documentation install'
|
||||
$(INSTALL_DOC_TARGETS):
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
|
||||
|
||||
### Cleaning rules
|
||||
|
||||
#
|
||||
# This is here, not in config/Makefile, because config/Makefile does
|
||||
# not get included for the clean target:
|
||||
#
|
||||
config-clean:
|
||||
$(call QUIET_CLEAN, config)
|
||||
@$(MAKE) -C config/feature-checks clean >/dev/null
|
||||
|
||||
clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean
|
||||
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
|
||||
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
|
||||
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
|
||||
$(call QUIET_CLEAN, Documentation)
|
||||
@$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null
|
||||
$(python-clean)
|
||||
|
||||
#
|
||||
# Trick: if ../../.git does not exist - we are building out of tree for example,
|
||||
# then force version regeneration:
|
||||
#
|
||||
ifeq ($(wildcard ../../.git/HEAD),)
|
||||
GIT-HEAD-PHONY = ../../.git/HEAD
|
||||
else
|
||||
GIT-HEAD-PHONY =
|
||||
endif
|
||||
|
||||
.PHONY: all install clean config-clean strip install-gtk
|
||||
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
|
||||
.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope .FORCE-PERF-CFLAGS
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "../../util/types.h"
|
||||
#include <asm/perf_regs.h>
|
||||
|
||||
#ifndef ARCH_X86_64
|
||||
#ifndef HAVE_ARCH_X86_64_SUPPORT
|
||||
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
|
||||
#else
|
||||
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
|
||||
@ -52,7 +52,7 @@ static inline const char *perf_reg_name(int id)
|
||||
return "FS";
|
||||
case PERF_REG_X86_GS:
|
||||
return "GS";
|
||||
#ifdef ARCH_X86_64
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
case PERF_REG_X86_R8:
|
||||
return "R8";
|
||||
case PERF_REG_X86_R9:
|
||||
@ -69,7 +69,7 @@ static inline const char *perf_reg_name(int id)
|
||||
return "R14";
|
||||
case PERF_REG_X86_R15:
|
||||
return "R15";
|
||||
#endif /* ARCH_X86_64 */
|
||||
#endif /* HAVE_ARCH_X86_64_SUPPORT */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "perf_regs.h"
|
||||
#include "../../util/unwind.h"
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
int unwind__arch_reg_id(int regnum)
|
||||
{
|
||||
int id;
|
||||
@ -108,4 +108,4 @@ int unwind__arch_reg_id(int regnum)
|
||||
|
||||
return id;
|
||||
}
|
||||
#endif /* ARCH_X86_64 */
|
||||
#endif /* HAVE_ARCH_X86_64_SUPPORT */
|
||||
|
@ -1,17 +1,87 @@
|
||||
# perf completion
|
||||
|
||||
function_exists()
|
||||
# Taken from git.git's completion script.
|
||||
__my_reassemble_comp_words_by_ref()
|
||||
{
|
||||
declare -F $1 > /dev/null
|
||||
return $?
|
||||
local exclude i j first
|
||||
# Which word separators to exclude?
|
||||
exclude="${1//[^$COMP_WORDBREAKS]}"
|
||||
cword_=$COMP_CWORD
|
||||
if [ -z "$exclude" ]; then
|
||||
words_=("${COMP_WORDS[@]}")
|
||||
return
|
||||
fi
|
||||
# List of word completion separators has shrunk;
|
||||
# re-assemble words to complete.
|
||||
for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
|
||||
# Append each nonempty word consisting of just
|
||||
# word separator characters to the current word.
|
||||
first=t
|
||||
while
|
||||
[ $i -gt 0 ] &&
|
||||
[ -n "${COMP_WORDS[$i]}" ] &&
|
||||
# word consists of excluded word separators
|
||||
[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
|
||||
do
|
||||
# Attach to the previous token,
|
||||
# unless the previous token is the command name.
|
||||
if [ $j -ge 2 ] && [ -n "$first" ]; then
|
||||
((j--))
|
||||
fi
|
||||
first=
|
||||
words_[$j]=${words_[j]}${COMP_WORDS[i]}
|
||||
if [ $i = $COMP_CWORD ]; then
|
||||
cword_=$j
|
||||
fi
|
||||
if (($i < ${#COMP_WORDS[@]} - 1)); then
|
||||
((i++))
|
||||
else
|
||||
# Done.
|
||||
return
|
||||
fi
|
||||
done
|
||||
words_[$j]=${words_[j]}${COMP_WORDS[i]}
|
||||
if [ $i = $COMP_CWORD ]; then
|
||||
cword_=$j
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function_exists __ltrim_colon_completions ||
|
||||
type _get_comp_words_by_ref &>/dev/null ||
|
||||
_get_comp_words_by_ref()
|
||||
{
|
||||
local exclude cur_ words_ cword_
|
||||
if [ "$1" = "-n" ]; then
|
||||
exclude=$2
|
||||
shift 2
|
||||
fi
|
||||
__my_reassemble_comp_words_by_ref "$exclude"
|
||||
cur_=${words_[cword_]}
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
cur)
|
||||
cur=$cur_
|
||||
;;
|
||||
prev)
|
||||
prev=${words_[$cword_-1]}
|
||||
;;
|
||||
words)
|
||||
words=("${words_[@]}")
|
||||
;;
|
||||
cword)
|
||||
cword=$cword_
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
type __ltrim_colon_completions &>/dev/null ||
|
||||
__ltrim_colon_completions()
|
||||
{
|
||||
if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
|
||||
# Remove colon-word prefix from COMPREPLY items
|
||||
local colon_word=${1%${1##*:}}
|
||||
local colon_word=${1%"${1##*:}"}
|
||||
local i=${#COMPREPLY[*]}
|
||||
while [[ $((--i)) -ge 0 ]]; do
|
||||
COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
|
||||
@ -19,23 +89,18 @@ __ltrim_colon_completions()
|
||||
fi
|
||||
}
|
||||
|
||||
have perf &&
|
||||
type perf &>/dev/null &&
|
||||
_perf()
|
||||
{
|
||||
local cur prev cmd
|
||||
local cur words cword prev cmd
|
||||
|
||||
COMPREPLY=()
|
||||
if function_exists _get_comp_words_by_ref; then
|
||||
_get_comp_words_by_ref -n : cur prev
|
||||
else
|
||||
cur=$(_get_cword :)
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
fi
|
||||
_get_comp_words_by_ref -n =: cur words cword prev
|
||||
|
||||
cmd=${COMP_WORDS[0]}
|
||||
cmd=${words[0]}
|
||||
|
||||
# List perf subcommands or long options
|
||||
if [ $COMP_CWORD -eq 1 ]; then
|
||||
if [ $cword -eq 1 ]; then
|
||||
if [[ $cur == --* ]]; then
|
||||
COMPREPLY=( $( compgen -W '--help --version \
|
||||
--exec-path --html-path --paginate --no-pager \
|
||||
@ -45,18 +110,17 @@ _perf()
|
||||
COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
|
||||
fi
|
||||
# List possible events for -e option
|
||||
elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then
|
||||
elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
|
||||
evts=$($cmd list --raw-dump)
|
||||
COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) )
|
||||
__ltrim_colon_completions $cur
|
||||
# List long option names
|
||||
elif [[ $cur == --* ]]; then
|
||||
subcmd=${COMP_WORDS[1]}
|
||||
subcmd=${words[1]}
|
||||
opts=$($cmd $subcmd --list-opts)
|
||||
COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) )
|
||||
# Fall down to list regular files
|
||||
else
|
||||
_filedir
|
||||
fi
|
||||
} &&
|
||||
complete -F _perf perf
|
||||
|
||||
complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \
|
||||
|| complete -o default -o nospace -F _perf perf
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
|
||||
#define MEMCPY_FN(fn, name, desc) \
|
||||
extern void *fn(void *, const void *, size_t);
|
||||
|
@ -58,7 +58,7 @@ struct routine routines[] = {
|
||||
{ "default",
|
||||
"Default memcpy() provided by glibc",
|
||||
memcpy },
|
||||
#ifdef ARCH_X86_64
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
|
||||
#define MEMCPY_FN(fn, name, desc) { name, desc, fn },
|
||||
#include "mem-memcpy-x86-64-asm-def.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
|
||||
#define MEMSET_FN(fn, name, desc) \
|
||||
extern void *fn(void *, int, size_t);
|
||||
|
@ -58,7 +58,7 @@ static const struct routine routines[] = {
|
||||
{ "default",
|
||||
"Default memset() provided by glibc",
|
||||
memset },
|
||||
#ifdef ARCH_X86_64
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
|
||||
#define MEMSET_FN(fn, name, desc) { name, desc, fn },
|
||||
#include "mem-memset-x86-64-asm-def.h"
|
||||
|
@ -429,14 +429,14 @@ static int parse_cpu_list(const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_setup_cpu_list(void)
|
||||
static int parse_setup_cpu_list(void)
|
||||
{
|
||||
struct thread_data *td;
|
||||
char *str0, *str;
|
||||
int t;
|
||||
|
||||
if (!g->p.cpu_list_str)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
|
||||
|
||||
@ -500,8 +500,12 @@ static void parse_setup_cpu_list(void)
|
||||
|
||||
dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul);
|
||||
|
||||
BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus);
|
||||
BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus);
|
||||
if (bind_cpu_0 >= g->p.nr_cpus || bind_cpu_1 >= g->p.nr_cpus) {
|
||||
printf("\nTest not applicable, system has only %d CPUs.\n", g->p.nr_cpus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BUG_ON(bind_cpu_0 < 0 || bind_cpu_1 < 0);
|
||||
BUG_ON(bind_cpu_0 > bind_cpu_1);
|
||||
|
||||
for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) {
|
||||
@ -541,6 +545,7 @@ out:
|
||||
printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
|
||||
|
||||
free(str0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_cpus_opt(const struct option *opt __maybe_unused,
|
||||
@ -561,14 +566,14 @@ static int parse_node_list(const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_setup_node_list(void)
|
||||
static int parse_setup_node_list(void)
|
||||
{
|
||||
struct thread_data *td;
|
||||
char *str0, *str;
|
||||
int t;
|
||||
|
||||
if (!g->p.node_list_str)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
|
||||
|
||||
@ -619,8 +624,12 @@ static void parse_setup_node_list(void)
|
||||
|
||||
dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step);
|
||||
|
||||
BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes);
|
||||
BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes);
|
||||
if (bind_node_0 >= g->p.nr_nodes || bind_node_1 >= g->p.nr_nodes) {
|
||||
printf("\nTest not applicable, system has only %d nodes.\n", g->p.nr_nodes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BUG_ON(bind_node_0 < 0 || bind_node_1 < 0);
|
||||
BUG_ON(bind_node_0 > bind_node_1);
|
||||
|
||||
for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) {
|
||||
@ -651,6 +660,7 @@ out:
|
||||
printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
|
||||
|
||||
free(str0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_nodes_opt(const struct option *opt __maybe_unused,
|
||||
@ -1110,7 +1120,7 @@ static void *worker_thread(void *__tdata)
|
||||
/* Check whether our max runtime timed out: */
|
||||
if (g->p.nr_secs) {
|
||||
timersub(&stop, &start0, &diff);
|
||||
if (diff.tv_sec >= g->p.nr_secs) {
|
||||
if ((u32)diff.tv_sec >= g->p.nr_secs) {
|
||||
g->stop_work = true;
|
||||
break;
|
||||
}
|
||||
@ -1157,7 +1167,7 @@ static void *worker_thread(void *__tdata)
|
||||
runtime_ns_max += diff.tv_usec * 1000;
|
||||
|
||||
if (details >= 0) {
|
||||
printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n",
|
||||
printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016"PRIx64"]\n",
|
||||
process_nr, thread_nr, runtime_ns_max / bytes_done, val);
|
||||
}
|
||||
fflush(stdout);
|
||||
@ -1356,8 +1366,8 @@ static int init(void)
|
||||
init_thread_data();
|
||||
|
||||
tprintf("#\n");
|
||||
parse_setup_cpu_list();
|
||||
parse_setup_node_list();
|
||||
if (parse_setup_cpu_list() || parse_setup_node_list())
|
||||
return -1;
|
||||
tprintf("#\n");
|
||||
|
||||
print_summary();
|
||||
@ -1600,7 +1610,6 @@ static int run_bench_numa(const char *name, const char **argv)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
usage_with_options(numa_usage, options);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1701,8 +1710,7 @@ static int bench_all(void)
|
||||
BUG_ON(ret < 0);
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (run_bench_numa(tests[i][0], tests[i] + 1))
|
||||
return -1;
|
||||
run_bench_numa(tests[i][0], tests[i] + 1);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
@ -7,9 +7,7 @@
|
||||
* Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
|
||||
* http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
|
||||
* Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/parse-options.h"
|
||||
@ -28,12 +26,24 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct thread_data {
|
||||
int nr;
|
||||
int pipe_read;
|
||||
int pipe_write;
|
||||
pthread_t pthread;
|
||||
};
|
||||
|
||||
#define LOOPS_DEFAULT 1000000
|
||||
static int loops = LOOPS_DEFAULT;
|
||||
static int loops = LOOPS_DEFAULT;
|
||||
|
||||
/* Use processes by default: */
|
||||
static bool threaded;
|
||||
|
||||
static const struct option options[] = {
|
||||
OPT_INTEGER('l', "loop", &loops,
|
||||
"Specify number of loops"),
|
||||
OPT_INTEGER('l', "loop", &loops, "Specify number of loops"),
|
||||
OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@ -42,13 +52,37 @@ static const char * const bench_sched_pipe_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int bench_sched_pipe(int argc, const char **argv,
|
||||
const char *prefix __maybe_unused)
|
||||
static void *worker_thread(void *__tdata)
|
||||
{
|
||||
int pipe_1[2], pipe_2[2];
|
||||
struct thread_data *td = __tdata;
|
||||
int m = 0, i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < loops; i++) {
|
||||
if (!td->nr) {
|
||||
ret = read(td->pipe_read, &m, sizeof(int));
|
||||
BUG_ON(ret != sizeof(int));
|
||||
ret = write(td->pipe_write, &m, sizeof(int));
|
||||
BUG_ON(ret != sizeof(int));
|
||||
} else {
|
||||
ret = write(td->pipe_write, &m, sizeof(int));
|
||||
BUG_ON(ret != sizeof(int));
|
||||
ret = read(td->pipe_read, &m, sizeof(int));
|
||||
BUG_ON(ret != sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
struct thread_data threads[2], *td;
|
||||
int pipe_1[2], pipe_2[2];
|
||||
struct timeval start, stop, diff;
|
||||
unsigned long long result_usec = 0;
|
||||
int nr_threads = 2;
|
||||
int t;
|
||||
|
||||
/*
|
||||
* why does "ret" exist?
|
||||
@ -58,43 +92,66 @@ int bench_sched_pipe(int argc, const char **argv,
|
||||
int __maybe_unused ret, wait_stat;
|
||||
pid_t pid, retpid __maybe_unused;
|
||||
|
||||
argc = parse_options(argc, argv, options,
|
||||
bench_sched_pipe_usage, 0);
|
||||
argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0);
|
||||
|
||||
BUG_ON(pipe(pipe_1));
|
||||
BUG_ON(pipe(pipe_2));
|
||||
|
||||
pid = fork();
|
||||
assert(pid >= 0);
|
||||
|
||||
gettimeofday(&start, NULL);
|
||||
|
||||
if (!pid) {
|
||||
for (i = 0; i < loops; i++) {
|
||||
ret = read(pipe_1[0], &m, sizeof(int));
|
||||
ret = write(pipe_2[1], &m, sizeof(int));
|
||||
for (t = 0; t < nr_threads; t++) {
|
||||
td = threads + t;
|
||||
|
||||
td->nr = t;
|
||||
|
||||
if (t == 0) {
|
||||
td->pipe_read = pipe_1[0];
|
||||
td->pipe_write = pipe_2[1];
|
||||
} else {
|
||||
td->pipe_write = pipe_1[1];
|
||||
td->pipe_read = pipe_2[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (threaded) {
|
||||
|
||||
for (t = 0; t < nr_threads; t++) {
|
||||
td = threads + t;
|
||||
|
||||
ret = pthread_create(&td->pthread, NULL, worker_thread, td);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
for (t = 0; t < nr_threads; t++) {
|
||||
td = threads + t;
|
||||
|
||||
ret = pthread_join(td->pthread, NULL);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < loops; i++) {
|
||||
ret = write(pipe_1[1], &m, sizeof(int));
|
||||
ret = read(pipe_2[0], &m, sizeof(int));
|
||||
pid = fork();
|
||||
assert(pid >= 0);
|
||||
|
||||
if (!pid) {
|
||||
worker_thread(threads + 0);
|
||||
exit(0);
|
||||
} else {
|
||||
worker_thread(threads + 1);
|
||||
}
|
||||
|
||||
retpid = waitpid(pid, &wait_stat, 0);
|
||||
assert((retpid == pid) && WIFEXITED(wait_stat));
|
||||
}
|
||||
|
||||
gettimeofday(&stop, NULL);
|
||||
timersub(&stop, &start, &diff);
|
||||
|
||||
if (pid) {
|
||||
retpid = waitpid(pid, &wait_stat, 0);
|
||||
assert((retpid == pid) && WIFEXITED(wait_stat));
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
switch (bench_format) {
|
||||
case BENCH_FORMAT_DEFAULT:
|
||||
printf("# Executed %d pipe operations between two tasks\n\n",
|
||||
loops);
|
||||
printf("# Executed %d pipe operations between two %s\n\n",
|
||||
loops, threaded ? "threads" : "processes");
|
||||
|
||||
result_usec = diff.tv_sec * 1000000;
|
||||
result_usec += diff.tv_usec;
|
||||
|
@ -28,8 +28,10 @@
|
||||
#include "util/hist.h"
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/data.h"
|
||||
#include "arch/common.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <linux/bitmap.h>
|
||||
|
||||
struct perf_annotate {
|
||||
@ -63,7 +65,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1);
|
||||
he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0);
|
||||
if (he == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -116,11 +118,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he,
|
||||
ann->print_line, ann->full_paths, 0, 0);
|
||||
}
|
||||
|
||||
static void hists__find_annotations(struct hists *self,
|
||||
static void hists__find_annotations(struct hists *hists,
|
||||
struct perf_evsel *evsel,
|
||||
struct perf_annotate *ann)
|
||||
{
|
||||
struct rb_node *nd = rb_first(&self->entries), *next;
|
||||
struct rb_node *nd = rb_first(&hists->entries), *next;
|
||||
int key = K_RIGHT;
|
||||
|
||||
while (nd) {
|
||||
@ -142,8 +144,18 @@ find_next:
|
||||
|
||||
if (use_browser == 2) {
|
||||
int ret;
|
||||
int (*annotate)(struct hist_entry *he,
|
||||
struct perf_evsel *evsel,
|
||||
struct hist_browser_timer *hbt);
|
||||
|
||||
ret = hist_entry__gtk_annotate(he, evsel, NULL);
|
||||
annotate = dlsym(perf_gtk_handle,
|
||||
"hist_entry__gtk_annotate");
|
||||
if (annotate == NULL) {
|
||||
ui__error("GTK browser not found!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = annotate(he, evsel, NULL);
|
||||
if (!ret || !ann->skip_missing)
|
||||
return;
|
||||
|
||||
@ -188,9 +200,13 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
struct perf_session *session;
|
||||
struct perf_evsel *pos;
|
||||
u64 total_nr_samples;
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = ann->force,
|
||||
};
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY,
|
||||
ann->force, false, &ann->tool);
|
||||
session = perf_session__new(&file, false, &ann->tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -231,7 +247,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
|
||||
if (nr_samples > 0) {
|
||||
total_nr_samples += nr_samples;
|
||||
hists__collapse_resort(hists);
|
||||
hists__collapse_resort(hists, NULL);
|
||||
hists__output_resort(hists);
|
||||
|
||||
if (symbol_conf.event_group &&
|
||||
@ -243,12 +259,21 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
}
|
||||
|
||||
if (total_nr_samples == 0) {
|
||||
ui__error("The %s file has no samples!\n", session->filename);
|
||||
ui__error("The %s file has no samples!\n", file.path);
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (use_browser == 2)
|
||||
perf_gtk__show_annotations();
|
||||
if (use_browser == 2) {
|
||||
void (*show_annotations)(void);
|
||||
|
||||
show_annotations = dlsym(perf_gtk_handle,
|
||||
"perf_gtk__show_annotations");
|
||||
if (show_annotations == NULL) {
|
||||
ui__error("GTK browser not found!\n");
|
||||
goto out_delete;
|
||||
}
|
||||
show_annotations();
|
||||
}
|
||||
|
||||
out_delete:
|
||||
/*
|
||||
|
@ -1,21 +1,18 @@
|
||||
/*
|
||||
*
|
||||
* builtin-bench.c
|
||||
*
|
||||
* General benchmarking subsystem provided by perf
|
||||
* General benchmarking collections provided by perf
|
||||
*
|
||||
* Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Available benchmark collection list:
|
||||
*
|
||||
* Available subsystem list:
|
||||
* sched ... scheduler and IPC mechanism
|
||||
* sched ... scheduler and IPC performance
|
||||
* mem ... memory access performance
|
||||
*
|
||||
* numa ... NUMA scheduling and MM performance
|
||||
*/
|
||||
|
||||
#include "perf.h"
|
||||
#include "util/util.h"
|
||||
#include "util/parse-options.h"
|
||||
@ -25,112 +22,92 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
struct bench_suite {
|
||||
const char *name;
|
||||
const char *summary;
|
||||
int (*fn)(int, const char **, const char *);
|
||||
typedef int (*bench_fn_t)(int argc, const char **argv, const char *prefix);
|
||||
|
||||
struct bench {
|
||||
const char *name;
|
||||
const char *summary;
|
||||
bench_fn_t fn;
|
||||
};
|
||||
\
|
||||
/* sentinel: easy for help */
|
||||
#define suite_all { "all", "Test all benchmark suites", NULL }
|
||||
|
||||
#ifdef LIBNUMA_SUPPORT
|
||||
static struct bench_suite numa_suites[] = {
|
||||
{ "mem",
|
||||
"Benchmark for NUMA workloads",
|
||||
bench_numa },
|
||||
suite_all,
|
||||
{ NULL,
|
||||
NULL,
|
||||
NULL }
|
||||
#ifdef HAVE_LIBNUMA_SUPPORT
|
||||
static struct bench numa_benchmarks[] = {
|
||||
{ "mem", "Benchmark for NUMA workloads", bench_numa },
|
||||
{ "all", "Test all NUMA benchmarks", NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct bench_suite sched_suites[] = {
|
||||
{ "messaging",
|
||||
"Benchmark for scheduler and IPC mechanisms",
|
||||
bench_sched_messaging },
|
||||
{ "pipe",
|
||||
"Flood of communication over pipe() between two processes",
|
||||
bench_sched_pipe },
|
||||
suite_all,
|
||||
{ NULL,
|
||||
NULL,
|
||||
NULL }
|
||||
static struct bench sched_benchmarks[] = {
|
||||
{ "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging },
|
||||
{ "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe },
|
||||
{ "all", "Test all scheduler benchmarks", NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static struct bench_suite mem_suites[] = {
|
||||
{ "memcpy",
|
||||
"Simple memory copy in various ways",
|
||||
bench_mem_memcpy },
|
||||
{ "memset",
|
||||
"Simple memory set in various ways",
|
||||
bench_mem_memset },
|
||||
suite_all,
|
||||
{ NULL,
|
||||
NULL,
|
||||
NULL }
|
||||
static struct bench mem_benchmarks[] = {
|
||||
{ "memcpy", "Benchmark for memcpy()", bench_mem_memcpy },
|
||||
{ "memset", "Benchmark for memset() tests", bench_mem_memset },
|
||||
{ "all", "Test all memory benchmarks", NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
struct bench_subsys {
|
||||
const char *name;
|
||||
const char *summary;
|
||||
struct bench_suite *suites;
|
||||
struct collection {
|
||||
const char *name;
|
||||
const char *summary;
|
||||
struct bench *benchmarks;
|
||||
};
|
||||
|
||||
static struct bench_subsys subsystems[] = {
|
||||
#ifdef LIBNUMA_SUPPORT
|
||||
{ "numa",
|
||||
"NUMA scheduling and MM behavior",
|
||||
numa_suites },
|
||||
static struct collection collections[] = {
|
||||
{ "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
|
||||
{ "mem", "Memory access benchmarks", mem_benchmarks },
|
||||
#ifdef HAVE_LIBNUMA_SUPPORT
|
||||
{ "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
|
||||
#endif
|
||||
{ "sched",
|
||||
"scheduler and IPC mechanism",
|
||||
sched_suites },
|
||||
{ "mem",
|
||||
"memory access performance",
|
||||
mem_suites },
|
||||
{ "all", /* sentinel: easy for help */
|
||||
"all benchmark subsystem",
|
||||
NULL },
|
||||
{ NULL,
|
||||
NULL,
|
||||
NULL }
|
||||
{ "all", "All benchmarks", NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void dump_suites(int subsys_index)
|
||||
/* Iterate over all benchmark collections: */
|
||||
#define for_each_collection(coll) \
|
||||
for (coll = collections; coll->name; coll++)
|
||||
|
||||
/* Iterate over all benchmarks within a collection: */
|
||||
#define for_each_bench(coll, bench) \
|
||||
for (bench = coll->benchmarks; bench->name; bench++)
|
||||
|
||||
static void dump_benchmarks(struct collection *coll)
|
||||
{
|
||||
int i;
|
||||
struct bench *bench;
|
||||
|
||||
printf("# List of available suites for %s...\n\n",
|
||||
subsystems[subsys_index].name);
|
||||
printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name);
|
||||
|
||||
for (i = 0; subsystems[subsys_index].suites[i].name; i++)
|
||||
printf("%14s: %s\n",
|
||||
subsystems[subsys_index].suites[i].name,
|
||||
subsystems[subsys_index].suites[i].summary);
|
||||
for_each_bench(coll, bench)
|
||||
printf("%14s: %s\n", bench->name, bench->summary);
|
||||
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static const char *bench_format_str;
|
||||
|
||||
/* Output/formatting style, exported to benchmark modules: */
|
||||
int bench_format = BENCH_FORMAT_DEFAULT;
|
||||
|
||||
static const struct option bench_options[] = {
|
||||
OPT_STRING('f', "format", &bench_format_str, "default",
|
||||
"Specify format style"),
|
||||
OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static const char * const bench_usage[] = {
|
||||
"perf bench [<common options>] <subsystem> <suite> [<options>]",
|
||||
"perf bench [<common options>] <collection> <benchmark> [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
struct collection *coll;
|
||||
int i;
|
||||
|
||||
printf("Usage: \n");
|
||||
@ -138,11 +115,10 @@ static void print_usage(void)
|
||||
printf("\t%s\n", bench_usage[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("# List of available subsystems...\n\n");
|
||||
printf(" # List of all available benchmark collections:\n\n");
|
||||
|
||||
for (i = 0; subsystems[i].name; i++)
|
||||
printf("%14s: %s\n",
|
||||
subsystems[i].name, subsystems[i].summary);
|
||||
for_each_collection(coll)
|
||||
printf("%14s: %s\n", coll->name, coll->summary);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@ -159,44 +135,74 @@ static int bench_str2int(const char *str)
|
||||
return BENCH_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
|
||||
/*
|
||||
* Run a specific benchmark but first rename the running task's ->comm[]
|
||||
* to something meaningful:
|
||||
*/
|
||||
static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
|
||||
int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int size;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
|
||||
|
||||
name = zalloc(size);
|
||||
BUG_ON(!name);
|
||||
|
||||
scnprintf(name, size, "%s-%s", coll_name, bench_name);
|
||||
|
||||
prctl(PR_SET_NAME, name);
|
||||
argv[0] = name;
|
||||
|
||||
ret = fn(argc, argv, prefix);
|
||||
|
||||
free(name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void run_collection(struct collection *coll)
|
||||
{
|
||||
struct bench *bench;
|
||||
const char *argv[2];
|
||||
struct bench_suite *suites = subsys->suites;
|
||||
|
||||
argv[1] = NULL;
|
||||
/*
|
||||
* TODO:
|
||||
* preparing preset parameters for
|
||||
*
|
||||
* Preparing preset parameters for
|
||||
* embedded, ordinary PC, HPC, etc...
|
||||
* will be helpful
|
||||
* would be helpful.
|
||||
*/
|
||||
for (i = 0; suites[i].fn; i++) {
|
||||
printf("# Running %s/%s benchmark...\n",
|
||||
subsys->name,
|
||||
suites[i].name);
|
||||
for_each_bench(coll, bench) {
|
||||
if (!bench->fn)
|
||||
break;
|
||||
printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
|
||||
fflush(stdout);
|
||||
|
||||
argv[1] = suites[i].name;
|
||||
suites[i].fn(1, argv, NULL);
|
||||
argv[1] = bench->name;
|
||||
run_bench(coll->name, bench->name, bench->fn, 1, argv, NULL);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void all_subsystem(void)
|
||||
static void run_all_collections(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; subsystems[i].suites; i++)
|
||||
all_suite(&subsystems[i]);
|
||||
struct collection *coll;
|
||||
|
||||
for_each_collection(coll)
|
||||
run_collection(coll);
|
||||
}
|
||||
|
||||
int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
int i, j, status = 0;
|
||||
struct collection *coll;
|
||||
int ret = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
/* No subsystem specified. */
|
||||
/* No collection specified. */
|
||||
print_usage();
|
||||
goto end;
|
||||
}
|
||||
@ -206,7 +212,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
|
||||
bench_format = bench_str2int(bench_format_str);
|
||||
if (bench_format == BENCH_FORMAT_UNKNOWN) {
|
||||
printf("Unknown format descriptor:%s\n", bench_format_str);
|
||||
printf("Unknown format descriptor: '%s'\n", bench_format_str);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -216,52 +222,51 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "all")) {
|
||||
all_subsystem();
|
||||
run_all_collections();
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; subsystems[i].name; i++) {
|
||||
if (strcmp(subsystems[i].name, argv[0]))
|
||||
for_each_collection(coll) {
|
||||
struct bench *bench;
|
||||
|
||||
if (strcmp(coll->name, argv[0]))
|
||||
continue;
|
||||
|
||||
if (argc < 2) {
|
||||
/* No suite specified. */
|
||||
dump_suites(i);
|
||||
/* No bench specified. */
|
||||
dump_benchmarks(coll);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "all")) {
|
||||
all_suite(&subsystems[i]);
|
||||
run_collection(coll);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (j = 0; subsystems[i].suites[j].name; j++) {
|
||||
if (strcmp(subsystems[i].suites[j].name, argv[1]))
|
||||
for_each_bench(coll, bench) {
|
||||
if (strcmp(bench->name, argv[1]))
|
||||
continue;
|
||||
|
||||
if (bench_format == BENCH_FORMAT_DEFAULT)
|
||||
printf("# Running %s/%s benchmark...\n",
|
||||
subsystems[i].name,
|
||||
subsystems[i].suites[j].name);
|
||||
printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
|
||||
fflush(stdout);
|
||||
status = subsystems[i].suites[j].fn(argc - 1,
|
||||
argv + 1, prefix);
|
||||
ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1, prefix);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
|
||||
dump_suites(i);
|
||||
dump_benchmarks(coll);
|
||||
goto end;
|
||||
}
|
||||
|
||||
printf("Unknown suite:%s for %s\n", argv[1], argv[0]);
|
||||
status = 1;
|
||||
printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
printf("Unknown subsystem:%s\n", argv[0]);
|
||||
status = 1;
|
||||
printf("Unknown collection: '%s'\n", argv[0]);
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
return status;
|
||||
return ret;
|
||||
}
|
||||
|
@ -6,6 +6,11 @@
|
||||
* Copyright (C) 2010, Red Hat Inc.
|
||||
* Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include "builtin.h"
|
||||
#include "perf.h"
|
||||
#include "util/cache.h"
|
||||
@ -17,6 +22,140 @@
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
|
||||
static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
|
||||
{
|
||||
char root_dir[PATH_MAX];
|
||||
char notes[PATH_MAX];
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
char *p;
|
||||
|
||||
strlcpy(root_dir, proc_dir, sizeof(root_dir));
|
||||
|
||||
p = strrchr(root_dir, '/');
|
||||
if (!p)
|
||||
return -1;
|
||||
*p = '\0';
|
||||
|
||||
scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
|
||||
|
||||
if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
|
||||
return -1;
|
||||
|
||||
build_id__sprintf(build_id, sizeof(build_id), sbuildid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_id_cache__kcore_dir(char *dir, size_t sz)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct tm tm;
|
||||
char dt[32];
|
||||
|
||||
if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
|
||||
return -1;
|
||||
|
||||
if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
|
||||
return -1;
|
||||
|
||||
scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
|
||||
size_t to_dir_sz)
|
||||
{
|
||||
char from[PATH_MAX];
|
||||
char to[PATH_MAX];
|
||||
struct dirent *dent;
|
||||
int ret = -1;
|
||||
DIR *d;
|
||||
|
||||
d = opendir(to_dir);
|
||||
if (!d)
|
||||
return -1;
|
||||
|
||||
scnprintf(from, sizeof(from), "%s/modules", from_dir);
|
||||
|
||||
while (1) {
|
||||
dent = readdir(d);
|
||||
if (!dent)
|
||||
break;
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
scnprintf(to, sizeof(to), "%s/%s/modules", to_dir,
|
||||
dent->d_name);
|
||||
if (!compare_proc_modules(from, to)) {
|
||||
scnprintf(to, sizeof(to), "%s/%s", to_dir,
|
||||
dent->d_name);
|
||||
strlcpy(to_dir, to, to_dir_sz);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
|
||||
{
|
||||
char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
|
||||
char from_dir[PATH_MAX], to_dir[PATH_MAX];
|
||||
char *p;
|
||||
|
||||
strlcpy(from_dir, filename, sizeof(from_dir));
|
||||
|
||||
p = strrchr(from_dir, '/');
|
||||
if (!p || strcmp(p + 1, "kcore"))
|
||||
return -1;
|
||||
*p = '\0';
|
||||
|
||||
if (build_id_cache__kcore_buildid(from_dir, sbuildid))
|
||||
return -1;
|
||||
|
||||
scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
|
||||
debugdir, sbuildid);
|
||||
|
||||
if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
|
||||
pr_debug("same kcore found in %s\n", to_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (build_id_cache__kcore_dir(dir, sizeof(dir)))
|
||||
return -1;
|
||||
|
||||
scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
|
||||
debugdir, sbuildid, dir);
|
||||
|
||||
if (mkdir_p(to_dir, 0755))
|
||||
return -1;
|
||||
|
||||
if (kcore_copy(from_dir, to_dir)) {
|
||||
/* Remove YYYYmmddHHMMSShh directory */
|
||||
if (!rmdir(to_dir)) {
|
||||
p = strrchr(to_dir, '/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
/* Try to remove buildid directory */
|
||||
if (!rmdir(to_dir)) {
|
||||
p = strrchr(to_dir, '/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
/* Try to remove [kernel.kcore] directory */
|
||||
rmdir(to_dir);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_debug("kcore added to build-id cache directory %s\n", to_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_id_cache__add_file(const char *filename, const char *debugdir)
|
||||
{
|
||||
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
|
||||
@ -82,8 +221,12 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
|
||||
|
||||
static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
|
||||
{
|
||||
struct perf_session *session = perf_session__new(filename, O_RDONLY,
|
||||
force, false, NULL);
|
||||
struct perf_data_file file = {
|
||||
.path = filename,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
};
|
||||
struct perf_session *session = perf_session__new(&file, false, NULL);
|
||||
if (session == NULL)
|
||||
return -1;
|
||||
|
||||
@ -130,11 +273,14 @@ int cmd_buildid_cache(int argc, const char **argv,
|
||||
char const *add_name_list_str = NULL,
|
||||
*remove_name_list_str = NULL,
|
||||
*missing_filename = NULL,
|
||||
*update_name_list_str = NULL;
|
||||
*update_name_list_str = NULL,
|
||||
*kcore_filename;
|
||||
|
||||
const struct option buildid_cache_options[] = {
|
||||
OPT_STRING('a', "add", &add_name_list_str,
|
||||
"file list", "file(s) to add"),
|
||||
OPT_STRING('k', "kcore", &kcore_filename,
|
||||
"file", "kcore file to add"),
|
||||
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
|
||||
"file(s) to remove"),
|
||||
OPT_STRING('M', "missing", &missing_filename, "file",
|
||||
@ -217,5 +363,9 @@ int cmd_buildid_cache(int argc, const char **argv,
|
||||
}
|
||||
}
|
||||
|
||||
if (kcore_filename &&
|
||||
build_id_cache__add_kcore(kcore_filename, debugdir))
|
||||
pr_warning("Couldn't add %s\n", kcore_filename);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util/parse-options.h"
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/data.h"
|
||||
|
||||
static int sysfs__fprintf_build_id(FILE *fp)
|
||||
{
|
||||
@ -52,6 +53,11 @@ static bool dso__skip_buildid(struct dso *dso, int with_hits)
|
||||
static int perf_session__list_build_ids(bool force, bool with_hits)
|
||||
{
|
||||
struct perf_session *session;
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
};
|
||||
|
||||
symbol__elf_init();
|
||||
/*
|
||||
@ -60,15 +66,14 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
|
||||
if (filename__fprintf_build_id(input_name, stdout))
|
||||
goto out;
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, force, false,
|
||||
&build_id__mark_dso_hit_ops);
|
||||
session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
|
||||
if (session == NULL)
|
||||
return -1;
|
||||
/*
|
||||
* in pipe-mode, the only way to get the buildids is to parse
|
||||
* the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
|
||||
*/
|
||||
if (with_hits || session->fd_pipe)
|
||||
if (with_hits || perf_data_file__is_pipe(&file))
|
||||
perf_session__process_events(session, &build_id__mark_dso_hit_ops);
|
||||
|
||||
perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "util/sort.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/util.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
@ -42,7 +43,7 @@ struct diff_hpp_fmt {
|
||||
|
||||
struct data__file {
|
||||
struct perf_session *session;
|
||||
const char *file;
|
||||
struct perf_data_file file;
|
||||
int idx;
|
||||
struct hists *hists;
|
||||
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
|
||||
@ -302,11 +303,12 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int hists__add_entry(struct hists *self,
|
||||
static int hists__add_entry(struct hists *hists,
|
||||
struct addr_location *al, u64 period,
|
||||
u64 weight)
|
||||
u64 weight, u64 transaction)
|
||||
{
|
||||
if (__hists__add_entry(self, al, NULL, period, weight) != NULL)
|
||||
if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
|
||||
transaction) != NULL)
|
||||
return 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -328,7 +330,8 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
if (al.filtered)
|
||||
return 0;
|
||||
|
||||
if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) {
|
||||
if (hists__add_entry(&evsel->hists, &al, sample->period,
|
||||
sample->weight, sample->transaction)) {
|
||||
pr_warning("problem incrementing symbol period, skipping event\n");
|
||||
return -1;
|
||||
}
|
||||
@ -367,7 +370,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
struct hists *hists = &evsel->hists;
|
||||
|
||||
hists__collapse_resort(hists);
|
||||
hists__collapse_resort(hists, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -599,7 +602,7 @@ static void data__fprintf(void)
|
||||
|
||||
data__for_each_file(i, d)
|
||||
fprintf(stdout, "# [%d] %s %s\n",
|
||||
d->idx, d->file,
|
||||
d->idx, d->file.path,
|
||||
!d->idx ? "(Baseline)" : "");
|
||||
|
||||
fprintf(stdout, "#\n");
|
||||
@ -661,17 +664,16 @@ static int __cmd_diff(void)
|
||||
int ret = -EINVAL, i;
|
||||
|
||||
data__for_each_file(i, d) {
|
||||
d->session = perf_session__new(d->file, O_RDONLY, force,
|
||||
false, &tool);
|
||||
d->session = perf_session__new(&d->file, false, &tool);
|
||||
if (!d->session) {
|
||||
pr_err("Failed to open %s\n", d->file);
|
||||
pr_err("Failed to open %s\n", d->file.path);
|
||||
ret = -ENOMEM;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
ret = perf_session__process_events(d->session, &tool);
|
||||
if (ret) {
|
||||
pr_err("Failed to process %s\n", d->file);
|
||||
pr_err("Failed to process %s\n", d->file.path);
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
@ -1014,7 +1016,12 @@ static int data_init(int argc, const char **argv)
|
||||
return -ENOMEM;
|
||||
|
||||
data__for_each_file(i, d) {
|
||||
d->file = use_default ? defaults[i] : argv[i];
|
||||
struct perf_data_file *file = &d->file;
|
||||
|
||||
file->path = use_default ? defaults[i] : argv[i];
|
||||
file->mode = PERF_DATA_MODE_READ,
|
||||
file->force = force,
|
||||
|
||||
d->idx = i;
|
||||
}
|
||||
|
||||
|
@ -14,13 +14,18 @@
|
||||
#include "util/parse-events.h"
|
||||
#include "util/parse-options.h"
|
||||
#include "util/session.h"
|
||||
#include "util/data.h"
|
||||
|
||||
static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
|
||||
{
|
||||
struct perf_session *session;
|
||||
struct perf_evsel *pos;
|
||||
struct perf_data_file file = {
|
||||
.path = file_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
session = perf_session__new(file_name, O_RDONLY, 0, false, NULL);
|
||||
session = perf_session__new(&file, 0, NULL);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util/tool.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/build-id.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
|
||||
@ -71,12 +72,17 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_evlist **pevlist)
|
||||
{
|
||||
struct perf_inject *inject = container_of(tool, struct perf_inject,
|
||||
tool);
|
||||
int ret;
|
||||
|
||||
ret = perf_event__process_attr(tool, event, pevlist);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!inject->pipe_output)
|
||||
return 0;
|
||||
|
||||
return perf_event__repipe_synth(tool, event);
|
||||
}
|
||||
|
||||
@ -100,8 +106,8 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
|
||||
struct perf_evsel *evsel,
|
||||
struct machine *machine)
|
||||
{
|
||||
if (evsel->handler.func) {
|
||||
inject_handler f = evsel->handler.func;
|
||||
if (evsel->handler) {
|
||||
inject_handler f = evsel->handler;
|
||||
return f(tool, event, sample, evsel, machine);
|
||||
}
|
||||
|
||||
@ -161,38 +167,38 @@ static int perf_event__repipe_tracing_data(struct perf_tool *tool,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dso__read_build_id(struct dso *self)
|
||||
static int dso__read_build_id(struct dso *dso)
|
||||
{
|
||||
if (self->has_build_id)
|
||||
if (dso->has_build_id)
|
||||
return 0;
|
||||
|
||||
if (filename__read_build_id(self->long_name, self->build_id,
|
||||
sizeof(self->build_id)) > 0) {
|
||||
self->has_build_id = true;
|
||||
if (filename__read_build_id(dso->long_name, dso->build_id,
|
||||
sizeof(dso->build_id)) > 0) {
|
||||
dso->has_build_id = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
|
||||
static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
|
||||
struct machine *machine)
|
||||
{
|
||||
u16 misc = PERF_RECORD_MISC_USER;
|
||||
int err;
|
||||
|
||||
if (dso__read_build_id(self) < 0) {
|
||||
pr_debug("no build_id found for %s\n", self->long_name);
|
||||
if (dso__read_build_id(dso) < 0) {
|
||||
pr_debug("no build_id found for %s\n", dso->long_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self->kernel)
|
||||
if (dso->kernel)
|
||||
misc = PERF_RECORD_MISC_KERNEL;
|
||||
|
||||
err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
|
||||
err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
|
||||
machine);
|
||||
if (err) {
|
||||
pr_err("Can't synthesize build_id event for %s\n", self->long_name);
|
||||
pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -231,7 +237,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
|
||||
* account this as unresolved.
|
||||
*/
|
||||
} else {
|
||||
#ifdef LIBELF_SUPPORT
|
||||
#ifdef HAVE_LIBELF_SUPPORT
|
||||
pr_warning("no symbols found in %s, maybe "
|
||||
"install a debug package?\n",
|
||||
al.map->dso->long_name);
|
||||
@ -345,6 +351,10 @@ static int __cmd_inject(struct perf_inject *inject)
|
||||
{
|
||||
struct perf_session *session;
|
||||
int ret = -EINVAL;
|
||||
struct perf_data_file file = {
|
||||
.path = inject->input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
@ -355,7 +365,7 @@ static int __cmd_inject(struct perf_inject *inject)
|
||||
inject->tool.tracing_data = perf_event__repipe_tracing_data;
|
||||
}
|
||||
|
||||
session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool);
|
||||
session = perf_session__new(&file, true, &inject->tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -373,11 +383,11 @@ static int __cmd_inject(struct perf_inject *inject)
|
||||
if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
|
||||
return -EINVAL;
|
||||
|
||||
evsel->handler.func = perf_inject__sched_switch;
|
||||
evsel->handler = perf_inject__sched_switch;
|
||||
} else if (!strcmp(name, "sched:sched_process_exit"))
|
||||
evsel->handler.func = perf_inject__sched_process_exit;
|
||||
evsel->handler = perf_inject__sched_process_exit;
|
||||
else if (!strncmp(name, "sched:sched_stat_", 17))
|
||||
evsel->handler.func = perf_inject__sched_stat;
|
||||
evsel->handler = perf_inject__sched_stat;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include "util/trace-event.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#include "util/debug.h"
|
||||
|
||||
@ -314,10 +315,10 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
return -1;
|
||||
}
|
||||
|
||||
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
|
||||
dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
|
||||
|
||||
if (evsel->handler.func != NULL) {
|
||||
tracepoint_handler f = evsel->handler.func;
|
||||
if (evsel->handler != NULL) {
|
||||
tracepoint_handler f = evsel->handler;
|
||||
return f(evsel, sample);
|
||||
}
|
||||
|
||||
@ -486,8 +487,12 @@ static int __cmd_kmem(void)
|
||||
{ "kmem:kfree", perf_evsel__process_free_event, },
|
||||
{ "kmem:kmem_cache_free", perf_evsel__process_free_event, },
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_kmem);
|
||||
session = perf_session__new(&file, false, &perf_kmem);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -17,9 +17,12 @@
|
||||
#include "util/tool.h"
|
||||
#include "util/stat.h"
|
||||
#include "util/top.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#ifdef HAVE_TIMERFD_SUPPORT
|
||||
#include <sys/timerfd.h>
|
||||
#endif
|
||||
|
||||
#include <termios.h>
|
||||
#include <semaphore.h>
|
||||
@ -336,6 +339,7 @@ static void init_kvm_event_record(struct perf_kvm_stat *kvm)
|
||||
INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TIMERFD_SUPPORT
|
||||
static void clear_events_cache_stats(struct list_head *kvm_events_cache)
|
||||
{
|
||||
struct list_head *head;
|
||||
@ -357,6 +361,7 @@ static void clear_events_cache_stats(struct list_head *kvm_events_cache)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int kvm_events_hash_fn(u64 key)
|
||||
{
|
||||
@ -782,6 +787,7 @@ static void print_result(struct perf_kvm_stat *kvm)
|
||||
pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TIMERFD_SUPPORT
|
||||
static int process_lost_event(struct perf_tool *tool,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_sample *sample __maybe_unused,
|
||||
@ -792,6 +798,7 @@ static int process_lost_event(struct perf_tool *tool,
|
||||
kvm->lost_events++;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool skip_sample(struct perf_kvm_stat *kvm,
|
||||
struct perf_sample *sample)
|
||||
@ -871,6 +878,7 @@ static bool verify_vcpu(int vcpu)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TIMERFD_SUPPORT
|
||||
/* keeping the max events to a modest level to keep
|
||||
* the processing of samples per mmap smooth.
|
||||
*/
|
||||
@ -1212,6 +1220,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int read_events(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
@ -1222,10 +1231,13 @@ static int read_events(struct perf_kvm_stat *kvm)
|
||||
.comm = perf_event__process_comm,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
kvm->tool = eops;
|
||||
kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false,
|
||||
&kvm->tool);
|
||||
kvm->session = perf_session__new(&file, false, &kvm->tool);
|
||||
if (!kvm->session) {
|
||||
pr_err("Initializing perf session failed\n");
|
||||
return -EINVAL;
|
||||
@ -1375,6 +1387,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
|
||||
return kvm_events_report_vcpu(kvm);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TIMERFD_SUPPORT
|
||||
static struct perf_evlist *kvm_live_event_list(void)
|
||||
{
|
||||
struct perf_evlist *evlist;
|
||||
@ -1433,8 +1446,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
|
||||
const struct option live_options[] = {
|
||||
OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
|
||||
"record events on existing process id"),
|
||||
OPT_UINTEGER('m', "mmap-pages", &kvm->opts.mmap_pages,
|
||||
"number of mmap data pages"),
|
||||
OPT_CALLBACK('m', "mmap-pages", &kvm->opts.mmap_pages, "pages",
|
||||
"number of mmap data pages",
|
||||
perf_evlist__parse_mmap_pages),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show counter open errors, etc)"),
|
||||
OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
|
||||
@ -1456,6 +1470,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
|
||||
"perf kvm stat live [<options>]",
|
||||
NULL
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.mode = PERF_DATA_MODE_WRITE,
|
||||
};
|
||||
|
||||
|
||||
/* event handling */
|
||||
@ -1520,7 +1537,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
|
||||
/*
|
||||
* perf session
|
||||
*/
|
||||
kvm->session = perf_session__new(NULL, O_WRONLY, false, false, &kvm->tool);
|
||||
kvm->session = perf_session__new(&file, false, &kvm->tool);
|
||||
if (kvm->session == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
@ -1558,6 +1575,7 @@ out:
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void print_kvm_stat_usage(void)
|
||||
{
|
||||
@ -1596,8 +1614,10 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
|
||||
if (!strncmp(argv[1], "rep", 3))
|
||||
return kvm_events_report(&kvm, argc - 1 , argv + 1);
|
||||
|
||||
#ifdef HAVE_TIMERFD_SUPPORT
|
||||
if (!strncmp(argv[1], "live", 4))
|
||||
return kvm_events_live(&kvm, argc - 1 , argv + 1);
|
||||
#endif
|
||||
|
||||
perf_stat:
|
||||
return cmd_stat(argc, argv, NULL);
|
||||
|
@ -14,51 +14,63 @@
|
||||
#include "util/parse-events.h"
|
||||
#include "util/cache.h"
|
||||
#include "util/pmu.h"
|
||||
#include "util/parse-options.h"
|
||||
|
||||
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
int i;
|
||||
const struct option list_options[] = {
|
||||
OPT_END()
|
||||
};
|
||||
const char * const list_usage[] = {
|
||||
"perf list [hw|sw|cache|tracepoint|pmu|event_glob]",
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, list_options, list_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
setup_pager();
|
||||
|
||||
if (argc == 1)
|
||||
if (argc == 0) {
|
||||
print_events(NULL, false);
|
||||
else {
|
||||
int i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (i > 2)
|
||||
putchar('\n');
|
||||
if (strncmp(argv[i], "tracepoint", 10) == 0)
|
||||
print_tracepoint_events(NULL, NULL, false);
|
||||
else if (strcmp(argv[i], "hw") == 0 ||
|
||||
strcmp(argv[i], "hardware") == 0)
|
||||
print_events_type(PERF_TYPE_HARDWARE);
|
||||
else if (strcmp(argv[i], "sw") == 0 ||
|
||||
strcmp(argv[i], "software") == 0)
|
||||
print_events_type(PERF_TYPE_SOFTWARE);
|
||||
else if (strcmp(argv[i], "cache") == 0 ||
|
||||
strcmp(argv[i], "hwcache") == 0)
|
||||
print_hwcache_events(NULL, false);
|
||||
else if (strcmp(argv[i], "pmu") == 0)
|
||||
print_pmu_events(NULL, false);
|
||||
else if (strcmp(argv[i], "--raw-dump") == 0)
|
||||
print_events(NULL, true);
|
||||
else {
|
||||
char *sep = strchr(argv[i], ':'), *s;
|
||||
int sep_idx;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (i)
|
||||
putchar('\n');
|
||||
if (strncmp(argv[i], "tracepoint", 10) == 0)
|
||||
print_tracepoint_events(NULL, NULL, false);
|
||||
else if (strcmp(argv[i], "hw") == 0 ||
|
||||
strcmp(argv[i], "hardware") == 0)
|
||||
print_events_type(PERF_TYPE_HARDWARE);
|
||||
else if (strcmp(argv[i], "sw") == 0 ||
|
||||
strcmp(argv[i], "software") == 0)
|
||||
print_events_type(PERF_TYPE_SOFTWARE);
|
||||
else if (strcmp(argv[i], "cache") == 0 ||
|
||||
strcmp(argv[i], "hwcache") == 0)
|
||||
print_hwcache_events(NULL, false);
|
||||
else if (strcmp(argv[i], "pmu") == 0)
|
||||
print_pmu_events(NULL, false);
|
||||
else if (strcmp(argv[i], "--raw-dump") == 0)
|
||||
print_events(NULL, true);
|
||||
else {
|
||||
char *sep = strchr(argv[i], ':'), *s;
|
||||
int sep_idx;
|
||||
|
||||
if (sep == NULL) {
|
||||
print_events(argv[i], false);
|
||||
continue;
|
||||
}
|
||||
sep_idx = sep - argv[i];
|
||||
s = strdup(argv[i]);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
s[sep_idx] = '\0';
|
||||
print_tracepoint_events(s, s + sep_idx + 1, false);
|
||||
free(s);
|
||||
if (sep == NULL) {
|
||||
print_events(argv[i], false);
|
||||
continue;
|
||||
}
|
||||
sep_idx = sep - argv[i];
|
||||
s = strdup(argv[i]);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
s[sep_idx] = '\0';
|
||||
print_tracepoint_events(s, s + sep_idx + 1, false);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util/debug.h"
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
@ -56,7 +57,9 @@ struct lock_stat {
|
||||
|
||||
unsigned int nr_readlock;
|
||||
unsigned int nr_trylock;
|
||||
|
||||
/* these times are in nano sec. */
|
||||
u64 avg_wait_time;
|
||||
u64 wait_time_total;
|
||||
u64 wait_time_min;
|
||||
u64 wait_time_max;
|
||||
@ -208,6 +211,7 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
|
||||
|
||||
SINGLE_KEY(nr_acquired)
|
||||
SINGLE_KEY(nr_contended)
|
||||
SINGLE_KEY(avg_wait_time)
|
||||
SINGLE_KEY(wait_time_total)
|
||||
SINGLE_KEY(wait_time_max)
|
||||
|
||||
@ -244,6 +248,7 @@ static struct rb_root result; /* place to store sorted data */
|
||||
struct lock_key keys[] = {
|
||||
DEF_KEY_LOCK(acquired, nr_acquired),
|
||||
DEF_KEY_LOCK(contended, nr_contended),
|
||||
DEF_KEY_LOCK(avg_wait, avg_wait_time),
|
||||
DEF_KEY_LOCK(wait_total, wait_time_total),
|
||||
DEF_KEY_LOCK(wait_min, wait_time_min),
|
||||
DEF_KEY_LOCK(wait_max, wait_time_max),
|
||||
@ -321,10 +326,12 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
|
||||
|
||||
new->addr = addr;
|
||||
new->name = zalloc(sizeof(char) * strlen(name) + 1);
|
||||
if (!new->name)
|
||||
if (!new->name) {
|
||||
free(new);
|
||||
goto alloc_failed;
|
||||
strcpy(new->name, name);
|
||||
}
|
||||
|
||||
strcpy(new->name, name);
|
||||
new->wait_time_min = ULLONG_MAX;
|
||||
|
||||
list_add(&new->hash_entry, entry);
|
||||
@ -400,17 +407,17 @@ static int report_lock_acquire_event(struct perf_evsel *evsel,
|
||||
|
||||
ls = lock_stat_findnew(addr, name);
|
||||
if (!ls)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
if (ls->discard)
|
||||
return 0;
|
||||
|
||||
ts = thread_stat_findnew(sample->tid);
|
||||
if (!ts)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
seq = get_seq(ts, addr);
|
||||
if (!seq)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
switch (seq->state) {
|
||||
case SEQ_STATE_UNINITIALIZED:
|
||||
@ -446,7 +453,6 @@ broken:
|
||||
list_del(&seq->list);
|
||||
free(seq);
|
||||
goto end;
|
||||
break;
|
||||
default:
|
||||
BUG_ON("Unknown state of lock sequence found!\n");
|
||||
break;
|
||||
@ -473,17 +479,17 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
|
||||
|
||||
ls = lock_stat_findnew(addr, name);
|
||||
if (!ls)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
if (ls->discard)
|
||||
return 0;
|
||||
|
||||
ts = thread_stat_findnew(sample->tid);
|
||||
if (!ts)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
seq = get_seq(ts, addr);
|
||||
if (!seq)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
switch (seq->state) {
|
||||
case SEQ_STATE_UNINITIALIZED:
|
||||
@ -508,8 +514,6 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
|
||||
list_del(&seq->list);
|
||||
free(seq);
|
||||
goto end;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG_ON("Unknown state of lock sequence found!\n");
|
||||
break;
|
||||
@ -517,6 +521,7 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
|
||||
|
||||
seq->state = SEQ_STATE_ACQUIRED;
|
||||
ls->nr_acquired++;
|
||||
ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
|
||||
seq->prev_event_time = sample->time;
|
||||
end:
|
||||
return 0;
|
||||
@ -536,17 +541,17 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
|
||||
|
||||
ls = lock_stat_findnew(addr, name);
|
||||
if (!ls)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
if (ls->discard)
|
||||
return 0;
|
||||
|
||||
ts = thread_stat_findnew(sample->tid);
|
||||
if (!ts)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
seq = get_seq(ts, addr);
|
||||
if (!seq)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
switch (seq->state) {
|
||||
case SEQ_STATE_UNINITIALIZED:
|
||||
@ -564,7 +569,6 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
|
||||
list_del(&seq->list);
|
||||
free(seq);
|
||||
goto end;
|
||||
break;
|
||||
default:
|
||||
BUG_ON("Unknown state of lock sequence found!\n");
|
||||
break;
|
||||
@ -572,6 +576,7 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
|
||||
|
||||
seq->state = SEQ_STATE_CONTENDED;
|
||||
ls->nr_contended++;
|
||||
ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
|
||||
seq->prev_event_time = sample->time;
|
||||
end:
|
||||
return 0;
|
||||
@ -591,22 +596,21 @@ static int report_lock_release_event(struct perf_evsel *evsel,
|
||||
|
||||
ls = lock_stat_findnew(addr, name);
|
||||
if (!ls)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
if (ls->discard)
|
||||
return 0;
|
||||
|
||||
ts = thread_stat_findnew(sample->tid);
|
||||
if (!ts)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
seq = get_seq(ts, addr);
|
||||
if (!seq)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
switch (seq->state) {
|
||||
case SEQ_STATE_UNINITIALIZED:
|
||||
goto end;
|
||||
break;
|
||||
case SEQ_STATE_ACQUIRED:
|
||||
break;
|
||||
case SEQ_STATE_READ_ACQUIRED:
|
||||
@ -624,7 +628,6 @@ static int report_lock_release_event(struct perf_evsel *evsel,
|
||||
ls->discard = 1;
|
||||
bad_hist[BROKEN_RELEASE]++;
|
||||
goto free_seq;
|
||||
break;
|
||||
default:
|
||||
BUG_ON("Unknown state of lock sequence found!\n");
|
||||
break;
|
||||
@ -690,7 +693,7 @@ static void print_bad_events(int bad, int total)
|
||||
|
||||
pr_info("\n=== output for debug===\n\n");
|
||||
pr_info("bad: %d, total: %d\n", bad, total);
|
||||
pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100);
|
||||
pr_info("bad rate: %.2f %%\n", (double)bad / (double)total * 100);
|
||||
pr_info("histogram of events caused bad sequence\n");
|
||||
for (i = 0; i < BROKEN_MAX; i++)
|
||||
pr_info(" %10s: %d\n", name[i], bad_hist[i]);
|
||||
@ -707,6 +710,7 @@ static void print_result(void)
|
||||
pr_info("%10s ", "acquired");
|
||||
pr_info("%10s ", "contended");
|
||||
|
||||
pr_info("%15s ", "avg wait (ns)");
|
||||
pr_info("%15s ", "total wait (ns)");
|
||||
pr_info("%15s ", "max wait (ns)");
|
||||
pr_info("%15s ", "min wait (ns)");
|
||||
@ -738,6 +742,7 @@ static void print_result(void)
|
||||
pr_info("%10u ", st->nr_acquired);
|
||||
pr_info("%10u ", st->nr_contended);
|
||||
|
||||
pr_info("%15" PRIu64 " ", st->avg_wait_time);
|
||||
pr_info("%15" PRIu64 " ", st->wait_time_total);
|
||||
pr_info("%15" PRIu64 " ", st->wait_time_max);
|
||||
pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
|
||||
@ -762,7 +767,7 @@ static void dump_threads(void)
|
||||
while (node) {
|
||||
st = container_of(node, struct thread_stat, rb);
|
||||
t = perf_session__findnew(session, st->tid);
|
||||
pr_info("%10d: %s\n", st->tid, t->comm);
|
||||
pr_info("%10d: %s\n", st->tid, thread__comm_str(t));
|
||||
node = rb_next(node);
|
||||
};
|
||||
}
|
||||
@ -814,42 +819,14 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (evsel->handler.func != NULL) {
|
||||
tracepoint_handler f = evsel->handler.func;
|
||||
if (evsel->handler != NULL) {
|
||||
tracepoint_handler f = evsel->handler;
|
||||
return f(evsel, sample);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct perf_evsel_str_handler lock_tracepoints[] = {
|
||||
{ "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
|
||||
{ "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
|
||||
{ "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
|
||||
{ "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
|
||||
};
|
||||
|
||||
static int read_events(void)
|
||||
{
|
||||
struct perf_tool eops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = perf_event__process_comm,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
|
||||
if (!session) {
|
||||
pr_err("Initializing perf session failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
|
||||
pr_err("Initializing perf session tracepoint handlers failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return perf_session__process_events(session, &eops);
|
||||
}
|
||||
|
||||
static void sort_result(void)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -862,18 +839,58 @@ static void sort_result(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int __cmd_report(void)
|
||||
static const struct perf_evsel_str_handler lock_tracepoints[] = {
|
||||
{ "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
|
||||
{ "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
|
||||
{ "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
|
||||
{ "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
|
||||
};
|
||||
|
||||
static int __cmd_report(bool display_info)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct perf_tool eops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = perf_event__process_comm,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
session = perf_session__new(&file, false, &eops);
|
||||
if (!session) {
|
||||
pr_err("Initializing perf session failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!perf_session__has_traces(session, "lock record"))
|
||||
goto out_delete;
|
||||
|
||||
if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
|
||||
pr_err("Initializing perf session tracepoint handlers failed\n");
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (select_key())
|
||||
goto out_delete;
|
||||
|
||||
err = perf_session__process_events(session, &eops);
|
||||
if (err)
|
||||
goto out_delete;
|
||||
|
||||
setup_pager();
|
||||
if (display_info) /* used for info subcommand */
|
||||
err = dump_info();
|
||||
else {
|
||||
sort_result();
|
||||
print_result();
|
||||
}
|
||||
|
||||
if ((select_key() != 0) ||
|
||||
(read_events() != 0))
|
||||
return -1;
|
||||
|
||||
sort_result();
|
||||
print_result();
|
||||
|
||||
return 0;
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __cmd_record(int argc, const char **argv)
|
||||
@ -881,7 +898,7 @@ static int __cmd_record(int argc, const char **argv)
|
||||
const char *record_args[] = {
|
||||
"record", "-R", "-m", "1024", "-c", "1",
|
||||
};
|
||||
unsigned int rec_argc, i, j;
|
||||
unsigned int rec_argc, i, j, ret;
|
||||
const char **rec_argv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
|
||||
@ -898,7 +915,7 @@ static int __cmd_record(int argc, const char **argv)
|
||||
rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
|
||||
|
||||
rec_argv = calloc(rec_argc + 1, sizeof(char *));
|
||||
if (rec_argv == NULL)
|
||||
if (!rec_argv)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(record_args); i++)
|
||||
@ -914,7 +931,9 @@ static int __cmd_record(int argc, const char **argv)
|
||||
|
||||
BUG_ON(i != rec_argc);
|
||||
|
||||
return cmd_record(i, rec_argv, NULL);
|
||||
ret = cmd_record(i, rec_argv, NULL);
|
||||
free(rec_argv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
@ -934,7 +953,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
};
|
||||
const struct option report_options[] = {
|
||||
OPT_STRING('k', "key", &sort_key, "acquired",
|
||||
"key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
|
||||
"key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
|
||||
/* TODO: type */
|
||||
OPT_END()
|
||||
};
|
||||
@ -972,7 +991,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (argc)
|
||||
usage_with_options(report_usage, report_options);
|
||||
}
|
||||
__cmd_report();
|
||||
rc = __cmd_report(false);
|
||||
} else if (!strcmp(argv[0], "script")) {
|
||||
/* Aliased to 'perf script' */
|
||||
return cmd_script(argc, argv, prefix);
|
||||
@ -985,11 +1004,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
}
|
||||
/* recycling report_lock_ops */
|
||||
trace_handler = &report_lock_ops;
|
||||
setup_pager();
|
||||
if (read_events() != 0)
|
||||
rc = -1;
|
||||
else
|
||||
rc = dump_info();
|
||||
rc = __cmd_report(true);
|
||||
} else {
|
||||
usage_with_options(lock_usage, lock_options);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "util/trace-event.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/session.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#define MEM_OPERATION_LOAD "load"
|
||||
#define MEM_OPERATION_STORE "store"
|
||||
@ -119,10 +120,14 @@ static int process_sample_event(struct perf_tool *tool,
|
||||
|
||||
static int report_raw_events(struct perf_mem *mem)
|
||||
{
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
int err = -EINVAL;
|
||||
int ret;
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
|
||||
0, false, &mem->tool);
|
||||
struct perf_session *session = perf_session__new(&file, false,
|
||||
&mem->tool);
|
||||
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -173,7 +173,7 @@ static int opt_set_target(const struct option *opt, const char *str,
|
||||
if (str && !params.target) {
|
||||
if (!strcmp(opt->long_name, "exec"))
|
||||
params.uprobes = true;
|
||||
#ifdef DWARF_SUPPORT
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
else if (!strcmp(opt->long_name, "module"))
|
||||
params.uprobes = false;
|
||||
#endif
|
||||
@ -187,7 +187,7 @@ static int opt_set_target(const struct option *opt, const char *str,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DWARF_SUPPORT
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
static int opt_show_lines(const struct option *opt __maybe_unused,
|
||||
const char *str, int unset __maybe_unused)
|
||||
{
|
||||
@ -257,7 +257,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
|
||||
"perf probe [<options>] --del '[GROUP:]EVENT' ...",
|
||||
"perf probe --list",
|
||||
#ifdef DWARF_SUPPORT
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
"perf probe [<options>] --line 'LINEDESC'",
|
||||
"perf probe [<options>] --vars 'PROBEPOINT'",
|
||||
#endif
|
||||
@ -271,7 +271,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
|
||||
opt_del_probe_event),
|
||||
OPT_CALLBACK('a', "add", NULL,
|
||||
#ifdef DWARF_SUPPORT
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
"[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
|
||||
" [[NAME=]ARG ...]",
|
||||
#else
|
||||
@ -283,7 +283,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"\t\tFUNC:\tFunction name\n"
|
||||
"\t\tOFF:\tOffset from function entry (in byte)\n"
|
||||
"\t\t%return:\tPut the probe at function return\n"
|
||||
#ifdef DWARF_SUPPORT
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
"\t\tSRC:\tSource code path\n"
|
||||
"\t\tRL:\tRelative line number from function entry.\n"
|
||||
"\t\tAL:\tAbsolute line number in file.\n"
|
||||
@ -296,7 +296,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
opt_add_probe_event),
|
||||
OPT_BOOLEAN('f', "force", ¶ms.force_add, "forcibly add events"
|
||||
" with existing name"),
|
||||
#ifdef DWARF_SUPPORT
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
OPT_CALLBACK('L', "line", NULL,
|
||||
"FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
|
||||
"Show source code lines.", opt_show_lines),
|
||||
@ -408,7 +408,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DWARF_SUPPORT
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
if (params.show_lines && !params.uprobes) {
|
||||
if (params.mod_events) {
|
||||
pr_err(" Error: Don't use --line with"
|
||||
|
@ -24,12 +24,13 @@
|
||||
#include "util/symbol.h"
|
||||
#include "util/cpumap.h"
|
||||
#include "util/thread_map.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef HAVE_ON_EXIT
|
||||
#ifndef HAVE_ON_EXIT_SUPPORT
|
||||
#ifndef ATEXIT_MAX
|
||||
#define ATEXIT_MAX 32
|
||||
#endif
|
||||
@ -65,31 +66,25 @@ struct perf_record {
|
||||
struct perf_tool tool;
|
||||
struct perf_record_opts opts;
|
||||
u64 bytes_written;
|
||||
const char *output_name;
|
||||
struct perf_data_file file;
|
||||
struct perf_evlist *evlist;
|
||||
struct perf_session *session;
|
||||
const char *progname;
|
||||
int output;
|
||||
unsigned int page_size;
|
||||
int realtime_prio;
|
||||
bool no_buildid;
|
||||
bool no_buildid_cache;
|
||||
long samples;
|
||||
off_t post_processing_offset;
|
||||
};
|
||||
|
||||
static void advance_output(struct perf_record *rec, size_t size)
|
||||
{
|
||||
rec->bytes_written += size;
|
||||
}
|
||||
|
||||
static int write_output(struct perf_record *rec, void *buf, size_t size)
|
||||
{
|
||||
struct perf_data_file *file = &rec->file;
|
||||
|
||||
while (size) {
|
||||
int ret = write(rec->output, buf, size);
|
||||
int ret = write(file->fd, buf, size);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("failed to write\n");
|
||||
pr_err("failed to write perf data, error: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -119,7 +114,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
|
||||
{
|
||||
unsigned int head = perf_mmap__read_head(md);
|
||||
unsigned int old = md->prev;
|
||||
unsigned char *data = md->base + rec->page_size;
|
||||
unsigned char *data = md->base + page_size;
|
||||
unsigned long size;
|
||||
void *buf;
|
||||
int rc = 0;
|
||||
@ -234,10 +229,6 @@ try_again:
|
||||
"or try again with a smaller value of -m/--mmap_pages.\n"
|
||||
"(current value: %d)\n", opts->mmap_pages);
|
||||
rc = -errno;
|
||||
} else if (!is_power_of_2(opts->mmap_pages) &&
|
||||
(opts->mmap_pages != UINT_MAX)) {
|
||||
pr_err("--mmap_pages/-m value must be a power of two.");
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
|
||||
rc = -errno;
|
||||
@ -253,31 +244,34 @@ out:
|
||||
|
||||
static int process_buildids(struct perf_record *rec)
|
||||
{
|
||||
u64 size = lseek(rec->output, 0, SEEK_CUR);
|
||||
struct perf_data_file *file = &rec->file;
|
||||
struct perf_session *session = rec->session;
|
||||
u64 start = session->header.data_offset;
|
||||
|
||||
u64 size = lseek(file->fd, 0, SEEK_CUR);
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
rec->session->fd = rec->output;
|
||||
return __perf_session__process_events(rec->session, rec->post_processing_offset,
|
||||
size - rec->post_processing_offset,
|
||||
return __perf_session__process_events(session, start,
|
||||
size - start,
|
||||
size, &build_id__mark_dso_hit_ops);
|
||||
}
|
||||
|
||||
static void perf_record__exit(int status, void *arg)
|
||||
{
|
||||
struct perf_record *rec = arg;
|
||||
struct perf_data_file *file = &rec->file;
|
||||
|
||||
if (status != 0)
|
||||
return;
|
||||
|
||||
if (!rec->opts.pipe_output) {
|
||||
if (!file->is_pipe) {
|
||||
rec->session->header.data_size += rec->bytes_written;
|
||||
|
||||
if (!rec->no_buildid)
|
||||
process_buildids(rec);
|
||||
perf_session__write_header(rec->session, rec->evlist,
|
||||
rec->output, true);
|
||||
file->fd, true);
|
||||
perf_session__delete(rec->session);
|
||||
perf_evlist__delete(rec->evlist);
|
||||
symbol__exit();
|
||||
@ -343,70 +337,11 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||
static void perf_record__init_features(struct perf_record *rec)
|
||||
{
|
||||
struct stat st;
|
||||
int flags;
|
||||
int err, output, feat;
|
||||
unsigned long waking = 0;
|
||||
const bool forks = argc > 0;
|
||||
struct machine *machine;
|
||||
struct perf_tool *tool = &rec->tool;
|
||||
struct perf_record_opts *opts = &rec->opts;
|
||||
struct perf_evlist *evsel_list = rec->evlist;
|
||||
const char *output_name = rec->output_name;
|
||||
struct perf_session *session;
|
||||
bool disabled = false;
|
||||
|
||||
rec->progname = argv[0];
|
||||
|
||||
rec->page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
on_exit(perf_record__sig_exit, rec);
|
||||
signal(SIGCHLD, sig_handler);
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGUSR1, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
if (!output_name) {
|
||||
if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
|
||||
opts->pipe_output = true;
|
||||
else
|
||||
rec->output_name = output_name = "perf.data";
|
||||
}
|
||||
if (output_name) {
|
||||
if (!strcmp(output_name, "-"))
|
||||
opts->pipe_output = true;
|
||||
else if (!stat(output_name, &st) && st.st_size) {
|
||||
char oldname[PATH_MAX];
|
||||
snprintf(oldname, sizeof(oldname), "%s.old",
|
||||
output_name);
|
||||
unlink(oldname);
|
||||
rename(output_name, oldname);
|
||||
}
|
||||
}
|
||||
|
||||
flags = O_CREAT|O_RDWR|O_TRUNC;
|
||||
|
||||
if (opts->pipe_output)
|
||||
output = STDOUT_FILENO;
|
||||
else
|
||||
output = open(output_name, flags, S_IRUSR | S_IWUSR);
|
||||
if (output < 0) {
|
||||
perror("failed to create output file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rec->output = output;
|
||||
|
||||
session = perf_session__new(output_name, O_WRONLY,
|
||||
true, false, NULL);
|
||||
if (session == NULL) {
|
||||
pr_err("Not enough memory for reading perf file header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rec->session = session;
|
||||
struct perf_session *session = rec->session;
|
||||
int feat;
|
||||
|
||||
for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
|
||||
perf_header__set_feat(&session->header, feat);
|
||||
@ -419,10 +354,42 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||
|
||||
if (!rec->opts.branch_stack)
|
||||
perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
|
||||
}
|
||||
|
||||
static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||
{
|
||||
int err;
|
||||
unsigned long waking = 0;
|
||||
const bool forks = argc > 0;
|
||||
struct machine *machine;
|
||||
struct perf_tool *tool = &rec->tool;
|
||||
struct perf_record_opts *opts = &rec->opts;
|
||||
struct perf_evlist *evsel_list = rec->evlist;
|
||||
struct perf_data_file *file = &rec->file;
|
||||
struct perf_session *session;
|
||||
bool disabled = false;
|
||||
|
||||
rec->progname = argv[0];
|
||||
|
||||
on_exit(perf_record__sig_exit, rec);
|
||||
signal(SIGCHLD, sig_handler);
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGUSR1, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
session = perf_session__new(file, false, NULL);
|
||||
if (session == NULL) {
|
||||
pr_err("Not enough memory for reading perf file header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rec->session = session;
|
||||
|
||||
perf_record__init_features(rec);
|
||||
|
||||
if (forks) {
|
||||
err = perf_evlist__prepare_workload(evsel_list, &opts->target,
|
||||
argv, opts->pipe_output,
|
||||
argv, file->is_pipe,
|
||||
true);
|
||||
if (err < 0) {
|
||||
pr_err("Couldn't run the workload!\n");
|
||||
@ -443,13 +410,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||
*/
|
||||
on_exit(perf_record__exit, rec);
|
||||
|
||||
if (opts->pipe_output) {
|
||||
err = perf_header__write_pipe(output);
|
||||
if (file->is_pipe) {
|
||||
err = perf_header__write_pipe(file->fd);
|
||||
if (err < 0)
|
||||
goto out_delete_session;
|
||||
} else {
|
||||
err = perf_session__write_header(session, evsel_list,
|
||||
output, false);
|
||||
file->fd, false);
|
||||
if (err < 0)
|
||||
goto out_delete_session;
|
||||
}
|
||||
@ -462,11 +429,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||
goto out_delete_session;
|
||||
}
|
||||
|
||||
rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
|
||||
|
||||
machine = &session->machines.host;
|
||||
|
||||
if (opts->pipe_output) {
|
||||
if (file->is_pipe) {
|
||||
err = perf_event__synthesize_attrs(tool, session,
|
||||
process_synthesized_event);
|
||||
if (err < 0) {
|
||||
@ -483,13 +448,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||
* return this more properly and also
|
||||
* propagate errors that now are calling die()
|
||||
*/
|
||||
err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
|
||||
err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
|
||||
process_synthesized_event);
|
||||
if (err <= 0) {
|
||||
pr_err("Couldn't record tracing data.\n");
|
||||
goto out_delete_session;
|
||||
}
|
||||
advance_output(rec, err);
|
||||
rec->bytes_written += err;
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,7 +555,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
|
||||
fprintf(stderr,
|
||||
"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
|
||||
(double)rec->bytes_written / 1024.0 / 1024.0,
|
||||
output_name,
|
||||
file->path,
|
||||
rec->bytes_written / 24);
|
||||
|
||||
return 0;
|
||||
@ -618,6 +583,9 @@ static const struct branch_mode branch_modes[] = {
|
||||
BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
|
||||
BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
|
||||
BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
|
||||
BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
|
||||
BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
|
||||
BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
|
||||
BRANCH_END
|
||||
};
|
||||
|
||||
@ -684,7 +652,7 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef LIBUNWIND_SUPPORT
|
||||
#ifdef HAVE_LIBUNWIND_SUPPORT
|
||||
static int get_stack_size(char *str, unsigned long *_size)
|
||||
{
|
||||
char *endptr;
|
||||
@ -710,7 +678,7 @@ static int get_stack_size(char *str, unsigned long *_size)
|
||||
max_size, str);
|
||||
return -1;
|
||||
}
|
||||
#endif /* LIBUNWIND_SUPPORT */
|
||||
#endif /* HAVE_LIBUNWIND_SUPPORT */
|
||||
|
||||
int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
|
||||
{
|
||||
@ -739,7 +707,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
|
||||
"needed for -g fp\n");
|
||||
break;
|
||||
|
||||
#ifdef LIBUNWIND_SUPPORT
|
||||
#ifdef HAVE_LIBUNWIND_SUPPORT
|
||||
/* Dwarf style */
|
||||
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
|
||||
const unsigned long default_stack_dump_size = 8192;
|
||||
@ -755,7 +723,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
|
||||
ret = get_stack_size(tok, &size);
|
||||
opts->stack_dump_size = size;
|
||||
}
|
||||
#endif /* LIBUNWIND_SUPPORT */
|
||||
#endif /* HAVE_LIBUNWIND_SUPPORT */
|
||||
} else {
|
||||
pr_err("callchain: Unknown --call-graph option "
|
||||
"value: %s\n", arg);
|
||||
@ -841,7 +809,7 @@ static struct perf_record record = {
|
||||
|
||||
#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
|
||||
|
||||
#ifdef LIBUNWIND_SUPPORT
|
||||
#ifdef HAVE_LIBUNWIND_SUPPORT
|
||||
const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
|
||||
#else
|
||||
const char record_callchain_help[] = CALLCHAIN_HELP "fp";
|
||||
@ -875,13 +843,14 @@ const struct option record_options[] = {
|
||||
OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
|
||||
"list of cpus to monitor"),
|
||||
OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
|
||||
OPT_STRING('o', "output", &record.output_name, "file",
|
||||
OPT_STRING('o', "output", &record.file.path, "file",
|
||||
"output file name"),
|
||||
OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
|
||||
"child tasks do not inherit counters"),
|
||||
OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
|
||||
OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
|
||||
"number of mmap data pages"),
|
||||
OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
|
||||
"number of mmap data pages",
|
||||
perf_evlist__parse_mmap_pages),
|
||||
OPT_BOOLEAN(0, "group", &record.opts.group,
|
||||
"put the counters into a counter group"),
|
||||
OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
|
||||
@ -920,6 +889,8 @@ const struct option record_options[] = {
|
||||
parse_branch_stack),
|
||||
OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
|
||||
"sample by weight (on special events only)"),
|
||||
OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
|
||||
"sample transaction flags (special events only)"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@ -989,20 +960,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
|
||||
usage_with_options(record_usage, record_options);
|
||||
|
||||
if (rec->opts.user_interval != ULLONG_MAX)
|
||||
rec->opts.default_interval = rec->opts.user_interval;
|
||||
if (rec->opts.user_freq != UINT_MAX)
|
||||
rec->opts.freq = rec->opts.user_freq;
|
||||
|
||||
/*
|
||||
* User specified count overrides default frequency.
|
||||
*/
|
||||
if (rec->opts.default_interval)
|
||||
rec->opts.freq = 0;
|
||||
else if (rec->opts.freq) {
|
||||
rec->opts.default_interval = rec->opts.freq;
|
||||
} else {
|
||||
ui__error("frequency and count are zero, aborting\n");
|
||||
if (perf_record_opts__config(&rec->opts)) {
|
||||
err = -EINVAL;
|
||||
goto out_free_fd;
|
||||
}
|
||||
|
@ -33,8 +33,10 @@
|
||||
#include "util/thread.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/hist.h"
|
||||
#include "util/data.h"
|
||||
#include "arch/common.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <linux/bitmap.h>
|
||||
|
||||
struct perf_report {
|
||||
@ -47,6 +49,7 @@ struct perf_report {
|
||||
bool show_threads;
|
||||
bool inverted_callchain;
|
||||
bool mem_mode;
|
||||
int max_stack;
|
||||
struct perf_read_values show_threads_values;
|
||||
const char *pretty_printing_style;
|
||||
const char *cpu_list;
|
||||
@ -88,7 +91,8 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
|
||||
if ((sort__has_parent || symbol_conf.use_callchain) &&
|
||||
sample->callchain) {
|
||||
err = machine__resolve_callchain(machine, evsel, al->thread,
|
||||
sample, &parent, al);
|
||||
sample, &parent, al,
|
||||
rep->max_stack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -111,7 +115,8 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
|
||||
* and this is indirectly achieved by passing period=weight here
|
||||
* and the he_stat__add_period() function.
|
||||
*/
|
||||
he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost);
|
||||
he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
|
||||
cost, cost, 0);
|
||||
if (!he)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -179,7 +184,8 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
|
||||
if ((sort__has_parent || symbol_conf.use_callchain)
|
||||
&& sample->callchain) {
|
||||
err = machine__resolve_callchain(machine, evsel, al->thread,
|
||||
sample, &parent, al);
|
||||
sample, &parent, al,
|
||||
rep->max_stack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -195,12 +201,16 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
/* overwrite the 'al' to branch-to info */
|
||||
al->map = bi[i].to.map;
|
||||
al->sym = bi[i].to.sym;
|
||||
al->addr = bi[i].to.addr;
|
||||
/*
|
||||
* The report shows the percentage of total branches captured
|
||||
* and not events sampled. Thus we use a pseudo period of 1.
|
||||
*/
|
||||
he = __hists__add_branch_entry(&evsel->hists, al, parent,
|
||||
&bi[i], 1, 1);
|
||||
he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
|
||||
1, 1, 0);
|
||||
if (he) {
|
||||
struct annotation *notes;
|
||||
bx = he->branch_info;
|
||||
@ -242,24 +252,28 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
|
||||
static int perf_evsel__add_hist_entry(struct perf_tool *tool,
|
||||
struct perf_evsel *evsel,
|
||||
struct addr_location *al,
|
||||
struct perf_sample *sample,
|
||||
struct machine *machine)
|
||||
{
|
||||
struct perf_report *rep = container_of(tool, struct perf_report, tool);
|
||||
struct symbol *parent = NULL;
|
||||
int err = 0;
|
||||
struct hist_entry *he;
|
||||
|
||||
if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
|
||||
err = machine__resolve_callchain(machine, evsel, al->thread,
|
||||
sample, &parent, al);
|
||||
sample, &parent, al,
|
||||
rep->max_stack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
|
||||
sample->weight);
|
||||
he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
|
||||
sample->period, sample->weight,
|
||||
sample->transaction);
|
||||
if (he == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -330,7 +344,8 @@ static int process_sample_event(struct perf_tool *tool,
|
||||
if (al.map != NULL)
|
||||
al.map->dso->hit = 1;
|
||||
|
||||
ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
|
||||
ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample,
|
||||
machine);
|
||||
if (ret < 0)
|
||||
pr_debug("problem incrementing symbol period, skipping event\n");
|
||||
}
|
||||
@ -364,10 +379,11 @@ static int process_read_event(struct perf_tool *tool,
|
||||
/* For pipe mode, sample_type is not currently set */
|
||||
static int perf_report__setup_sample_type(struct perf_report *rep)
|
||||
{
|
||||
struct perf_session *self = rep->session;
|
||||
u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
|
||||
struct perf_session *session = rep->session;
|
||||
u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
|
||||
bool is_pipe = perf_data_file__is_pipe(session->file);
|
||||
|
||||
if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
|
||||
if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
|
||||
if (sort__has_parent) {
|
||||
ui__error("Selected --sort parent, but no "
|
||||
"callchain data. Did you call "
|
||||
@ -390,7 +406,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
|
||||
}
|
||||
|
||||
if (sort__mode == SORT_MODE__BRANCH) {
|
||||
if (!self->fd_pipe &&
|
||||
if (!is_pipe &&
|
||||
!(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
|
||||
ui__error("Selected -b but no branch data. "
|
||||
"Did you call perf record without -b?\n");
|
||||
@ -407,14 +423,14 @@ static void sig_handler(int sig __maybe_unused)
|
||||
}
|
||||
|
||||
static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
|
||||
struct hists *self,
|
||||
struct hists *hists,
|
||||
const char *evname, FILE *fp)
|
||||
{
|
||||
size_t ret;
|
||||
char unit;
|
||||
unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
u64 nr_events = self->stats.total_period;
|
||||
struct perf_evsel *evsel = hists_to_evsel(self);
|
||||
unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
u64 nr_events = hists->stats.total_period;
|
||||
struct perf_evsel *evsel = hists_to_evsel(hists);
|
||||
char buf[512];
|
||||
size_t size = sizeof(buf);
|
||||
|
||||
@ -486,6 +502,8 @@ static int __cmd_report(struct perf_report *rep)
|
||||
struct map *kernel_map;
|
||||
struct kmap *kernel_kmap;
|
||||
const char *help = "For a higher level overview, try: perf report --sort comm,dso";
|
||||
struct ui_progress prog;
|
||||
struct perf_data_file *file = session->file;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
@ -546,6 +564,12 @@ static int __cmd_report(struct perf_report *rep)
|
||||
return 0;
|
||||
}
|
||||
|
||||
nr_samples = 0;
|
||||
list_for_each_entry(pos, &session->evlist->entries, node)
|
||||
nr_samples += pos->hists.nr_entries;
|
||||
|
||||
ui_progress__init(&prog, nr_samples, "Merging related events...");
|
||||
|
||||
nr_samples = 0;
|
||||
list_for_each_entry(pos, &session->evlist->entries, node) {
|
||||
struct hists *hists = &pos->hists;
|
||||
@ -553,7 +577,7 @@ static int __cmd_report(struct perf_report *rep)
|
||||
if (pos->idx == 0)
|
||||
hists->symbol_filter_str = rep->symbol_filter_str;
|
||||
|
||||
hists__collapse_resort(hists);
|
||||
hists__collapse_resort(hists, &prog);
|
||||
nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
|
||||
/* Non-group events are considered as leader */
|
||||
@ -565,12 +589,13 @@ static int __cmd_report(struct perf_report *rep)
|
||||
hists__link(leader_hists, hists);
|
||||
}
|
||||
}
|
||||
ui_progress__finish();
|
||||
|
||||
if (session_done())
|
||||
return 0;
|
||||
|
||||
if (nr_samples == 0) {
|
||||
ui__error("The %s file has no samples!\n", session->filename);
|
||||
ui__error("The %s file has no samples!\n", file->path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -591,8 +616,19 @@ static int __cmd_report(struct perf_report *rep)
|
||||
ret = 0;
|
||||
|
||||
} else if (use_browser == 2) {
|
||||
perf_evlist__gtk_browse_hists(session->evlist, help,
|
||||
NULL, rep->min_percent);
|
||||
int (*hist_browser)(struct perf_evlist *,
|
||||
const char *,
|
||||
struct hist_browser_timer *,
|
||||
float min_pcnt);
|
||||
|
||||
hist_browser = dlsym(perf_gtk_handle,
|
||||
"perf_evlist__gtk_browse_hists");
|
||||
if (hist_browser == NULL) {
|
||||
ui__error("GTK browser not found!\n");
|
||||
return ret;
|
||||
}
|
||||
hist_browser(session->evlist, help, NULL,
|
||||
rep->min_percent);
|
||||
}
|
||||
} else
|
||||
perf_evlist__tty_browse_hists(session->evlist, rep, help);
|
||||
@ -757,6 +793,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
.ordered_samples = true,
|
||||
.ordering_requires_timestamps = true,
|
||||
},
|
||||
.max_stack = PERF_MAX_STACK_DEPTH,
|
||||
.pretty_printing_style = "normal",
|
||||
};
|
||||
const struct option options[] = {
|
||||
@ -787,7 +824,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
|
||||
" dso_to, dso_from, symbol_to, symbol_from, mispredict,"
|
||||
" weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
|
||||
"snoop, locked"),
|
||||
"snoop, locked, abort, in_tx, transaction"),
|
||||
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
|
||||
"Show sample percentage for different cpu modes"),
|
||||
OPT_STRING('p', "parent", &parent_pattern, "regex",
|
||||
@ -797,6 +834,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
|
||||
"Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
|
||||
"Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
|
||||
OPT_INTEGER(0, "max-stack", &report.max_stack,
|
||||
"Set the maximum stack depth when parsing the callchain, "
|
||||
"anything beyond the specified depth will be ignored. "
|
||||
"Default: " __stringify(PERF_MAX_STACK_DEPTH)),
|
||||
OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
|
||||
"alias for inverted call graph"),
|
||||
OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
|
||||
@ -845,6 +886,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"Don't show entries under that percent", parse_percent_limit),
|
||||
OPT_END()
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
perf_config(perf_report_config, &report);
|
||||
|
||||
@ -867,16 +911,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
input_name = "perf.data";
|
||||
}
|
||||
|
||||
if (strcmp(input_name, "-") != 0)
|
||||
setup_browser(true);
|
||||
else {
|
||||
use_browser = 0;
|
||||
perf_hpp__init();
|
||||
}
|
||||
file.path = input_name;
|
||||
file.force = report.force;
|
||||
|
||||
repeat:
|
||||
session = perf_session__new(input_name, O_RDONLY,
|
||||
report.force, false, &report.tool);
|
||||
session = perf_session__new(&file, false, &report.tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -914,8 +953,22 @@ repeat:
|
||||
sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
|
||||
}
|
||||
|
||||
if (setup_sorting() < 0)
|
||||
usage_with_options(report_usage, options);
|
||||
if (setup_sorting() < 0) {
|
||||
parse_options_usage(report_usage, options, "s", 1);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (parent_pattern != default_parent_pattern) {
|
||||
if (sort_dimension__add("parent") < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (strcmp(input_name, "-") != 0)
|
||||
setup_browser(true);
|
||||
else {
|
||||
use_browser = 0;
|
||||
perf_hpp__init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Only in the TUI browser we are doing integrated annotation,
|
||||
@ -946,11 +999,6 @@ repeat:
|
||||
if (symbol__init() < 0)
|
||||
goto error;
|
||||
|
||||
if (parent_pattern != default_parent_pattern) {
|
||||
if (sort_dimension__add("parent") < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
/*
|
||||
* Special case: if there's an argument left then assume that
|
||||
|
@ -737,12 +737,12 @@ static int replay_fork_event(struct perf_sched *sched,
|
||||
|
||||
if (verbose) {
|
||||
printf("fork event\n");
|
||||
printf("... parent: %s/%d\n", parent->comm, parent->tid);
|
||||
printf("... child: %s/%d\n", child->comm, child->tid);
|
||||
printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid);
|
||||
printf("... child: %s/%d\n", thread__comm_str(child), child->tid);
|
||||
}
|
||||
|
||||
register_pid(sched, parent->tid, parent->comm);
|
||||
register_pid(sched, child->tid, child->comm);
|
||||
register_pid(sched, parent->tid, thread__comm_str(parent));
|
||||
register_pid(sched, child->tid, thread__comm_str(child));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1077,7 +1077,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
|
||||
if (!atoms) {
|
||||
if (thread_atoms_insert(sched, migrant))
|
||||
return -1;
|
||||
register_pid(sched, migrant->tid, migrant->comm);
|
||||
register_pid(sched, migrant->tid, thread__comm_str(migrant));
|
||||
atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
|
||||
if (!atoms) {
|
||||
pr_err("migration-event: Internal tree error");
|
||||
@ -1111,13 +1111,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
|
||||
/*
|
||||
* Ignore idle threads:
|
||||
*/
|
||||
if (!strcmp(work_list->thread->comm, "swapper"))
|
||||
if (!strcmp(thread__comm_str(work_list->thread), "swapper"))
|
||||
return;
|
||||
|
||||
sched->all_runtime += work_list->total_runtime;
|
||||
sched->all_count += work_list->nb_atoms;
|
||||
|
||||
ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid);
|
||||
ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid);
|
||||
|
||||
for (i = 0; i < 24 - ret; i++)
|
||||
printf(" ");
|
||||
@ -1334,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
|
||||
printf(" %12.6f secs ", (double)timestamp/1e9);
|
||||
if (new_shortname) {
|
||||
printf("%s => %s:%d\n",
|
||||
sched_in->shortname, sched_in->comm, sched_in->tid);
|
||||
sched_in->shortname, thread__comm_str(sched_in), sched_in->tid);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
@ -1427,8 +1427,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
|
||||
evsel->hists.stats.total_period += sample->period;
|
||||
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
|
||||
|
||||
if (evsel->handler.func != NULL) {
|
||||
tracepoint_handler f = evsel->handler.func;
|
||||
if (evsel->handler != NULL) {
|
||||
tracepoint_handler f = evsel->handler;
|
||||
err = f(tool, evsel, sample, machine);
|
||||
}
|
||||
|
||||
@ -1446,8 +1446,12 @@ static int perf_sched__read_events(struct perf_sched *sched,
|
||||
{ "sched:sched_migrate_task", process_sched_migrate_task_event, },
|
||||
};
|
||||
struct perf_session *session;
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, 0, false, &sched->tool);
|
||||
session = perf_session__new(&file, false, &sched->tool);
|
||||
if (session == NULL) {
|
||||
pr_debug("No Memory for session\n");
|
||||
return -1;
|
||||
@ -1651,29 +1655,27 @@ static int __cmd_record(int argc, const char **argv)
|
||||
return cmd_record(i, rec_argv, NULL);
|
||||
}
|
||||
|
||||
static const char default_sort_order[] = "avg, max, switch, runtime";
|
||||
static struct perf_sched sched = {
|
||||
.tool = {
|
||||
.sample = perf_sched__process_tracepoint_sample,
|
||||
.comm = perf_event__process_comm,
|
||||
.lost = perf_event__process_lost,
|
||||
.fork = perf_sched__process_fork_event,
|
||||
.ordered_samples = true,
|
||||
},
|
||||
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
|
||||
.sort_list = LIST_HEAD_INIT(sched.sort_list),
|
||||
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
.curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
|
||||
.sort_order = default_sort_order,
|
||||
.replay_repeat = 10,
|
||||
.profile_cpu = -1,
|
||||
.next_shortname1 = 'A',
|
||||
.next_shortname2 = '0',
|
||||
};
|
||||
|
||||
int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
const char default_sort_order[] = "avg, max, switch, runtime";
|
||||
struct perf_sched sched = {
|
||||
.tool = {
|
||||
.sample = perf_sched__process_tracepoint_sample,
|
||||
.comm = perf_event__process_comm,
|
||||
.lost = perf_event__process_lost,
|
||||
.fork = perf_sched__process_fork_event,
|
||||
.ordered_samples = true,
|
||||
},
|
||||
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
|
||||
.sort_list = LIST_HEAD_INIT(sched.sort_list),
|
||||
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
.sort_order = default_sort_order,
|
||||
.replay_repeat = 10,
|
||||
.profile_cpu = -1,
|
||||
.next_shortname1 = 'A',
|
||||
.next_shortname2 = '0',
|
||||
};
|
||||
const struct option latency_options[] = {
|
||||
OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
|
||||
"sort by key(s): runtime, switch, avg, max"),
|
||||
@ -1729,6 +1731,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
.switch_event = replay_switch_event,
|
||||
.fork_event = replay_fork_event,
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
|
||||
sched.curr_pid[i] = -1;
|
||||
|
||||
argc = parse_options(argc, argv, sched_options, sched_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/data.h"
|
||||
#include <linux/bitmap.h>
|
||||
|
||||
static char const *script_name;
|
||||
@ -228,6 +229,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_print_ip_opts(struct perf_event_attr *attr)
|
||||
{
|
||||
unsigned int type = attr->type;
|
||||
|
||||
output[type].print_ip_opts = 0;
|
||||
if (PRINT_FIELD(IP))
|
||||
output[type].print_ip_opts |= PRINT_IP_OPT_IP;
|
||||
|
||||
if (PRINT_FIELD(SYM))
|
||||
output[type].print_ip_opts |= PRINT_IP_OPT_SYM;
|
||||
|
||||
if (PRINT_FIELD(DSO))
|
||||
output[type].print_ip_opts |= PRINT_IP_OPT_DSO;
|
||||
|
||||
if (PRINT_FIELD(SYMOFFSET))
|
||||
output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
|
||||
}
|
||||
|
||||
/*
|
||||
* verify all user requested events exist and the samples
|
||||
* have the expected data
|
||||
@ -236,7 +255,6 @@ static int perf_session__check_output_opt(struct perf_session *session)
|
||||
{
|
||||
int j;
|
||||
struct perf_evsel *evsel;
|
||||
struct perf_event_attr *attr;
|
||||
|
||||
for (j = 0; j < PERF_TYPE_MAX; ++j) {
|
||||
evsel = perf_session__find_first_evtype(session, j);
|
||||
@ -259,20 +277,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
|
||||
if (evsel == NULL)
|
||||
continue;
|
||||
|
||||
attr = &evsel->attr;
|
||||
|
||||
output[j].print_ip_opts = 0;
|
||||
if (PRINT_FIELD(IP))
|
||||
output[j].print_ip_opts |= PRINT_IP_OPT_IP;
|
||||
|
||||
if (PRINT_FIELD(SYM))
|
||||
output[j].print_ip_opts |= PRINT_IP_OPT_SYM;
|
||||
|
||||
if (PRINT_FIELD(DSO))
|
||||
output[j].print_ip_opts |= PRINT_IP_OPT_DSO;
|
||||
|
||||
if (PRINT_FIELD(SYMOFFSET))
|
||||
output[j].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
|
||||
set_print_ip_opts(&evsel->attr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -290,11 +295,11 @@ static void print_sample_start(struct perf_sample *sample,
|
||||
|
||||
if (PRINT_FIELD(COMM)) {
|
||||
if (latency_format)
|
||||
printf("%8.8s ", thread->comm);
|
||||
printf("%8.8s ", thread__comm_str(thread));
|
||||
else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
|
||||
printf("%s ", thread->comm);
|
||||
printf("%s ", thread__comm_str(thread));
|
||||
else
|
||||
printf("%16s ", thread->comm);
|
||||
printf("%16s ", thread__comm_str(thread));
|
||||
}
|
||||
|
||||
if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
|
||||
@ -409,7 +414,9 @@ static void print_sample_bts(union perf_event *event,
|
||||
printf(" => ");
|
||||
|
||||
/* print branch_to information */
|
||||
if (PRINT_FIELD(ADDR))
|
||||
if (PRINT_FIELD(ADDR) ||
|
||||
((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
|
||||
!output[attr->type].user_set))
|
||||
print_sample_addr(event, sample, machine, thread, attr);
|
||||
|
||||
printf("\n");
|
||||
@ -539,32 +546,51 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct perf_tool perf_script = {
|
||||
.sample = process_sample_event,
|
||||
.mmap = perf_event__process_mmap,
|
||||
.mmap2 = perf_event__process_mmap2,
|
||||
.comm = perf_event__process_comm,
|
||||
.exit = perf_event__process_exit,
|
||||
.fork = perf_event__process_fork,
|
||||
.attr = perf_event__process_attr,
|
||||
.tracing_data = perf_event__process_tracing_data,
|
||||
.build_id = perf_event__process_build_id,
|
||||
.ordered_samples = true,
|
||||
.ordering_requires_timestamps = true,
|
||||
struct perf_script {
|
||||
struct perf_tool tool;
|
||||
struct perf_session *session;
|
||||
};
|
||||
|
||||
static int process_attr(struct perf_tool *tool, union perf_event *event,
|
||||
struct perf_evlist **pevlist)
|
||||
{
|
||||
struct perf_script *scr = container_of(tool, struct perf_script, tool);
|
||||
struct perf_evlist *evlist;
|
||||
struct perf_evsel *evsel, *pos;
|
||||
int err;
|
||||
|
||||
err = perf_event__process_attr(tool, event, pevlist);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
evlist = *pevlist;
|
||||
evsel = perf_evlist__last(*pevlist);
|
||||
|
||||
if (evsel->attr.type >= PERF_TYPE_MAX)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(pos, &evlist->entries, node) {
|
||||
if (pos->attr.type == evsel->attr.type && pos != evsel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_print_ip_opts(&evsel->attr);
|
||||
|
||||
return perf_evsel__check_attr(evsel, scr->session);
|
||||
}
|
||||
|
||||
static void sig_handler(int sig __maybe_unused)
|
||||
{
|
||||
session_done = 1;
|
||||
}
|
||||
|
||||
static int __cmd_script(struct perf_session *session)
|
||||
static int __cmd_script(struct perf_script *script)
|
||||
{
|
||||
int ret;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
ret = perf_session__process_events(session, &perf_script);
|
||||
ret = perf_session__process_events(script->session, &script->tool);
|
||||
|
||||
if (debug_mode)
|
||||
pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
|
||||
@ -1113,10 +1139,14 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
|
||||
char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
|
||||
DIR *scripts_dir, *lang_dir;
|
||||
struct perf_session *session;
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
char *temp;
|
||||
int i = 0;
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
|
||||
session = perf_session__new(&file, false, NULL);
|
||||
if (!session)
|
||||
return -1;
|
||||
|
||||
@ -1266,6 +1296,21 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
char *script_path = NULL;
|
||||
const char **__argv;
|
||||
int i, j, err;
|
||||
struct perf_script script = {
|
||||
.tool = {
|
||||
.sample = process_sample_event,
|
||||
.mmap = perf_event__process_mmap,
|
||||
.mmap2 = perf_event__process_mmap2,
|
||||
.comm = perf_event__process_comm,
|
||||
.exit = perf_event__process_exit,
|
||||
.fork = perf_event__process_fork,
|
||||
.attr = process_attr,
|
||||
.tracing_data = perf_event__process_tracing_data,
|
||||
.build_id = perf_event__process_build_id,
|
||||
.ordered_samples = true,
|
||||
.ordering_requires_timestamps = true,
|
||||
},
|
||||
};
|
||||
const struct option options[] = {
|
||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
||||
"dump raw trace in ASCII"),
|
||||
@ -1317,12 +1362,17 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"perf script [<options>] <top-script> [script-args]",
|
||||
NULL
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
setup_scripting();
|
||||
|
||||
argc = parse_options(argc, argv, options, script_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
file.path = input_name;
|
||||
|
||||
if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
|
||||
rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
|
||||
if (!rec_script_path)
|
||||
@ -1486,11 +1536,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (!script_name)
|
||||
setup_pager();
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, 0, false,
|
||||
&perf_script);
|
||||
session = perf_session__new(&file, false, &script.tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
script.session = session;
|
||||
|
||||
if (cpu_list) {
|
||||
if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
|
||||
return -1;
|
||||
@ -1514,7 +1565,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
return -1;
|
||||
}
|
||||
|
||||
input = open(session->filename, O_RDONLY); /* input_name */
|
||||
input = open(file.path, O_RDONLY); /* input_name */
|
||||
if (input < 0) {
|
||||
perror("failed to open file");
|
||||
return -1;
|
||||
@ -1554,7 +1605,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = __cmd_script(session);
|
||||
err = __cmd_script(&script);
|
||||
|
||||
perf_session__delete(session);
|
||||
cleanup_scripting();
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "util/util.h"
|
||||
#include "util/parse-options.h"
|
||||
#include "util/parse-events.h"
|
||||
#include "util/pmu.h"
|
||||
#include "util/event.h"
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
@ -70,6 +71,41 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
|
||||
static void print_counter(struct perf_evsel *counter, char *prefix);
|
||||
static void print_aggr(char *prefix);
|
||||
|
||||
/* Default events used for perf stat -T */
|
||||
static const char * const transaction_attrs[] = {
|
||||
"task-clock",
|
||||
"{"
|
||||
"instructions,"
|
||||
"cycles,"
|
||||
"cpu/cycles-t/,"
|
||||
"cpu/tx-start/,"
|
||||
"cpu/el-start/,"
|
||||
"cpu/cycles-ct/"
|
||||
"}"
|
||||
};
|
||||
|
||||
/* More limited version when the CPU does not have all events. */
|
||||
static const char * const transaction_limited_attrs[] = {
|
||||
"task-clock",
|
||||
"{"
|
||||
"instructions,"
|
||||
"cycles,"
|
||||
"cpu/cycles-t/,"
|
||||
"cpu/tx-start/"
|
||||
"}"
|
||||
};
|
||||
|
||||
/* must match transaction_attrs and the beginning limited_attrs */
|
||||
enum {
|
||||
T_TASK_CLOCK,
|
||||
T_INSTRUCTIONS,
|
||||
T_CYCLES,
|
||||
T_CYCLES_IN_TX,
|
||||
T_TRANSACTION_START,
|
||||
T_ELISION_START,
|
||||
T_CYCLES_IN_TX_CP,
|
||||
};
|
||||
|
||||
static struct perf_evlist *evsel_list;
|
||||
|
||||
static struct perf_target target = {
|
||||
@ -90,6 +126,7 @@ static enum aggr_mode aggr_mode = AGGR_GLOBAL;
|
||||
static volatile pid_t child_pid = -1;
|
||||
static bool null_run = false;
|
||||
static int detailed_run = 0;
|
||||
static bool transaction_run;
|
||||
static bool big_num = true;
|
||||
static int big_num_opt = -1;
|
||||
static const char *csv_sep = NULL;
|
||||
@ -214,7 +251,10 @@ static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
|
||||
static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
|
||||
static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
|
||||
static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
|
||||
static struct stats runtime_cycles_in_tx_stats[MAX_NR_CPUS];
|
||||
static struct stats walltime_nsecs_stats;
|
||||
static struct stats runtime_transaction_stats[MAX_NR_CPUS];
|
||||
static struct stats runtime_elision_stats[MAX_NR_CPUS];
|
||||
|
||||
static void perf_stat__reset_stats(struct perf_evlist *evlist)
|
||||
{
|
||||
@ -236,6 +276,11 @@ static void perf_stat__reset_stats(struct perf_evlist *evlist)
|
||||
memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats));
|
||||
memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats));
|
||||
memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats));
|
||||
memset(runtime_cycles_in_tx_stats, 0,
|
||||
sizeof(runtime_cycles_in_tx_stats));
|
||||
memset(runtime_transaction_stats, 0,
|
||||
sizeof(runtime_transaction_stats));
|
||||
memset(runtime_elision_stats, 0, sizeof(runtime_elision_stats));
|
||||
memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
|
||||
}
|
||||
|
||||
@ -274,6 +319,29 @@ static inline int nsec_counter(struct perf_evsel *evsel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct perf_evsel *nth_evsel(int n)
|
||||
{
|
||||
static struct perf_evsel **array;
|
||||
static int array_len;
|
||||
struct perf_evsel *ev;
|
||||
int j;
|
||||
|
||||
/* Assumes this only called when evsel_list does not change anymore. */
|
||||
if (!array) {
|
||||
list_for_each_entry(ev, &evsel_list->entries, node)
|
||||
array_len++;
|
||||
array = malloc(array_len * sizeof(void *));
|
||||
if (!array)
|
||||
exit(ENOMEM);
|
||||
j = 0;
|
||||
list_for_each_entry(ev, &evsel_list->entries, node)
|
||||
array[j++] = ev;
|
||||
}
|
||||
if (n < array_len)
|
||||
return array[n];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update various tracking values we maintain to print
|
||||
* more semantic information such as miss/hit ratios,
|
||||
@ -285,6 +353,15 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count)
|
||||
update_stats(&runtime_nsecs_stats[0], count[0]);
|
||||
else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
|
||||
update_stats(&runtime_cycles_stats[0], count[0]);
|
||||
else if (transaction_run &&
|
||||
perf_evsel__cmp(counter, nth_evsel(T_CYCLES_IN_TX)))
|
||||
update_stats(&runtime_cycles_in_tx_stats[0], count[0]);
|
||||
else if (transaction_run &&
|
||||
perf_evsel__cmp(counter, nth_evsel(T_TRANSACTION_START)))
|
||||
update_stats(&runtime_transaction_stats[0], count[0]);
|
||||
else if (transaction_run &&
|
||||
perf_evsel__cmp(counter, nth_evsel(T_ELISION_START)))
|
||||
update_stats(&runtime_elision_stats[0], count[0]);
|
||||
else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
|
||||
update_stats(&runtime_stalled_cycles_front_stats[0], count[0]);
|
||||
else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
|
||||
@ -629,10 +706,13 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
|
||||
{
|
||||
double msecs = avg / 1e6;
|
||||
const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
|
||||
char name[25];
|
||||
|
||||
aggr_printout(evsel, cpu, nr);
|
||||
|
||||
fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel));
|
||||
scnprintf(name, sizeof(name), "%s%s",
|
||||
perf_evsel__name(evsel), csv_output ? "" : " (msec)");
|
||||
fprintf(output, fmt, msecs, csv_sep, name);
|
||||
|
||||
if (evsel->cgrp)
|
||||
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
|
||||
@ -828,7 +908,7 @@ static void print_ll_cache_misses(int cpu,
|
||||
|
||||
static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
|
||||
{
|
||||
double total, ratio = 0.0;
|
||||
double total, ratio = 0.0, total2;
|
||||
const char *fmt;
|
||||
|
||||
if (csv_output)
|
||||
@ -853,11 +933,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
|
||||
|
||||
if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
|
||||
total = avg_stats(&runtime_cycles_stats[cpu]);
|
||||
if (total)
|
||||
if (total) {
|
||||
ratio = avg / total;
|
||||
|
||||
fprintf(output, " # %5.2f insns per cycle ", ratio);
|
||||
|
||||
fprintf(output, " # %5.2f insns per cycle ", ratio);
|
||||
}
|
||||
total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
|
||||
total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
|
||||
|
||||
@ -920,10 +999,47 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
|
||||
} else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
|
||||
total = avg_stats(&runtime_nsecs_stats[cpu]);
|
||||
|
||||
if (total) {
|
||||
ratio = avg / total;
|
||||
fprintf(output, " # %8.3f GHz ", ratio);
|
||||
}
|
||||
} else if (transaction_run &&
|
||||
perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) {
|
||||
total = avg_stats(&runtime_cycles_stats[cpu]);
|
||||
if (total)
|
||||
ratio = 1.0 * avg / total;
|
||||
fprintf(output,
|
||||
" # %5.2f%% transactional cycles ",
|
||||
100.0 * (avg / total));
|
||||
} else if (transaction_run &&
|
||||
perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX_CP))) {
|
||||
total = avg_stats(&runtime_cycles_stats[cpu]);
|
||||
total2 = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
|
||||
if (total2 < avg)
|
||||
total2 = avg;
|
||||
if (total)
|
||||
fprintf(output,
|
||||
" # %5.2f%% aborted cycles ",
|
||||
100.0 * ((total2-avg) / total));
|
||||
} else if (transaction_run &&
|
||||
perf_evsel__cmp(evsel, nth_evsel(T_TRANSACTION_START)) &&
|
||||
avg > 0 &&
|
||||
runtime_cycles_in_tx_stats[cpu].n != 0) {
|
||||
total = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
|
||||
|
||||
fprintf(output, " # %8.3f GHz ", ratio);
|
||||
if (total)
|
||||
ratio = total / avg;
|
||||
|
||||
fprintf(output, " # %8.0f cycles / transaction ", ratio);
|
||||
} else if (transaction_run &&
|
||||
perf_evsel__cmp(evsel, nth_evsel(T_ELISION_START)) &&
|
||||
avg > 0 &&
|
||||
runtime_cycles_in_tx_stats[cpu].n != 0) {
|
||||
total = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
|
||||
|
||||
if (total)
|
||||
ratio = total / avg;
|
||||
|
||||
fprintf(output, " # %8.0f cycles / elision ", ratio);
|
||||
} else if (runtime_nsecs_stats[cpu].n != 0) {
|
||||
char unit = 'M';
|
||||
|
||||
@ -1116,7 +1232,11 @@ static void print_stat(int argc, const char **argv)
|
||||
if (!csv_output) {
|
||||
fprintf(output, "\n");
|
||||
fprintf(output, " Performance counter stats for ");
|
||||
if (!perf_target__has_task(&target)) {
|
||||
if (target.system_wide)
|
||||
fprintf(output, "\'system wide");
|
||||
else if (target.cpu_list)
|
||||
fprintf(output, "\'CPU(s) %s", target.cpu_list);
|
||||
else if (!perf_target__has_task(&target)) {
|
||||
fprintf(output, "\'%s", argv[0]);
|
||||
for (i = 1; i < argc; i++)
|
||||
fprintf(output, " %s", argv[i]);
|
||||
@ -1237,6 +1357,16 @@ static int perf_stat_init_aggr_mode(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_events(const char * const *attrs, unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (parse_events(evsel_list, attrs[i]))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add default attributes, if there were no attributes specified or
|
||||
@ -1355,6 +1485,22 @@ static int add_default_attributes(void)
|
||||
if (null_run)
|
||||
return 0;
|
||||
|
||||
if (transaction_run) {
|
||||
int err;
|
||||
if (pmu_have_event("cpu", "cycles-ct") &&
|
||||
pmu_have_event("cpu", "el-start"))
|
||||
err = setup_events(transaction_attrs,
|
||||
ARRAY_SIZE(transaction_attrs));
|
||||
else
|
||||
err = setup_events(transaction_limited_attrs,
|
||||
ARRAY_SIZE(transaction_limited_attrs));
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "Cannot set up transaction events\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!evsel_list->nr_entries) {
|
||||
if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0)
|
||||
return -1;
|
||||
@ -1389,6 +1535,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
int output_fd = 0;
|
||||
const char *output_name = NULL;
|
||||
const struct option options[] = {
|
||||
OPT_BOOLEAN('T', "transaction", &transaction_run,
|
||||
"hardware transaction statistics"),
|
||||
OPT_CALLBACK('e', "event", &evsel_list, "event",
|
||||
"event selector. use 'perf list' to list available events",
|
||||
parse_events_option),
|
||||
@ -1448,7 +1596,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"perf stat [<options>] [<command>]",
|
||||
NULL
|
||||
};
|
||||
int status = -ENOMEM, run_idx;
|
||||
int status = -EINVAL, run_idx;
|
||||
const char *mode;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
@ -1466,12 +1614,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
|
||||
if (output_name && output_fd) {
|
||||
fprintf(stderr, "cannot use both --output and --log-fd\n");
|
||||
usage_with_options(stat_usage, options);
|
||||
parse_options_usage(stat_usage, options, "o", 1);
|
||||
parse_options_usage(NULL, options, "log-fd", 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (output_fd < 0) {
|
||||
fprintf(stderr, "argument to --log-fd must be a > 0\n");
|
||||
usage_with_options(stat_usage, options);
|
||||
parse_options_usage(stat_usage, options, "log-fd", 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!output) {
|
||||
@ -1508,16 +1659,21 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
/* User explicitly passed -B? */
|
||||
if (big_num_opt == 1) {
|
||||
fprintf(stderr, "-B option not supported with -x\n");
|
||||
usage_with_options(stat_usage, options);
|
||||
parse_options_usage(stat_usage, options, "B", 1);
|
||||
parse_options_usage(NULL, options, "x", 1);
|
||||
goto out;
|
||||
} else /* Nope, so disable big number formatting */
|
||||
big_num = false;
|
||||
} else if (big_num_opt == 0) /* User passed --no-big-num */
|
||||
big_num = false;
|
||||
|
||||
if (!argc && !perf_target__has_task(&target))
|
||||
if (!argc && perf_target__none(&target))
|
||||
usage_with_options(stat_usage, options);
|
||||
|
||||
if (run_count < 0) {
|
||||
usage_with_options(stat_usage, options);
|
||||
pr_err("Run count must be a positive number\n");
|
||||
parse_options_usage(stat_usage, options, "r", 1);
|
||||
goto out;
|
||||
} else if (run_count == 0) {
|
||||
forever = true;
|
||||
run_count = 1;
|
||||
@ -1529,8 +1685,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
fprintf(stderr, "both cgroup and no-aggregation "
|
||||
"modes only available in system-wide mode\n");
|
||||
|
||||
usage_with_options(stat_usage, options);
|
||||
return -1;
|
||||
parse_options_usage(stat_usage, options, "G", 1);
|
||||
parse_options_usage(NULL, options, "A", 1);
|
||||
parse_options_usage(NULL, options, "a", 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (add_default_attributes())
|
||||
@ -1539,25 +1697,28 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
perf_target__validate(&target);
|
||||
|
||||
if (perf_evlist__create_maps(evsel_list, &target) < 0) {
|
||||
if (perf_target__has_task(&target))
|
||||
if (perf_target__has_task(&target)) {
|
||||
pr_err("Problems finding threads of monitor\n");
|
||||
if (perf_target__has_cpu(&target))
|
||||
parse_options_usage(stat_usage, options, "p", 1);
|
||||
parse_options_usage(NULL, options, "t", 1);
|
||||
} else if (perf_target__has_cpu(&target)) {
|
||||
perror("failed to parse CPUs map");
|
||||
|
||||
usage_with_options(stat_usage, options);
|
||||
return -1;
|
||||
parse_options_usage(stat_usage, options, "C", 1);
|
||||
parse_options_usage(NULL, options, "a", 1);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
if (interval && interval < 100) {
|
||||
pr_err("print interval must be >= 100ms\n");
|
||||
usage_with_options(stat_usage, options);
|
||||
return -1;
|
||||
parse_options_usage(stat_usage, options, "I", 1);
|
||||
goto out_free_maps;
|
||||
}
|
||||
|
||||
if (perf_evlist__alloc_stats(evsel_list, interval))
|
||||
goto out_free_maps;
|
||||
|
||||
if (perf_stat_init_aggr_mode())
|
||||
goto out;
|
||||
goto out_free_maps;
|
||||
|
||||
/*
|
||||
* We dont want to block the signals - that would cause
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "util/session.h"
|
||||
#include "util/svghelper.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/data.h"
|
||||
|
||||
#define SUPPORT_OLD_POWER_EVENTS 1
|
||||
#define PWR_EVENT_EXIT -1
|
||||
@ -482,8 +483,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
if (sample->cpu > numcpus)
|
||||
numcpus = sample->cpu;
|
||||
|
||||
if (evsel->handler.func != NULL) {
|
||||
tracepoint_handler f = evsel->handler.func;
|
||||
if (evsel->handler != NULL) {
|
||||
tracepoint_handler f = evsel->handler;
|
||||
return f(evsel, sample);
|
||||
}
|
||||
|
||||
@ -990,8 +991,13 @@ static int __cmd_timechart(const char *output_name)
|
||||
{ "power:power_frequency", process_sample_power_frequency },
|
||||
#endif
|
||||
};
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
|
||||
0, false, &perf_timechart);
|
||||
struct perf_data_file file = {
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
|
||||
struct perf_session *session = perf_session__new(&file, false,
|
||||
&perf_timechart);
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (session == NULL)
|
||||
|
@ -246,10 +246,10 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
|
||||
struct hist_entry *he;
|
||||
|
||||
pthread_mutex_lock(&evsel->hists.lock);
|
||||
he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
|
||||
sample->weight);
|
||||
he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL,
|
||||
sample->period, sample->weight,
|
||||
sample->transaction);
|
||||
pthread_mutex_unlock(&evsel->hists.lock);
|
||||
|
||||
if (he == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -287,7 +287,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
|
||||
return;
|
||||
}
|
||||
|
||||
hists__collapse_resort(&top->sym_evsel->hists);
|
||||
hists__collapse_resort(&top->sym_evsel->hists, NULL);
|
||||
hists__output_resort(&top->sym_evsel->hists);
|
||||
hists__decay_entries(&top->sym_evsel->hists,
|
||||
top->hide_user_symbols,
|
||||
@ -553,7 +553,7 @@ static void perf_top__sort_new_samples(void *arg)
|
||||
if (t->evlist->selected != NULL)
|
||||
t->sym_evsel = t->evlist->selected;
|
||||
|
||||
hists__collapse_resort(&t->sym_evsel->hists);
|
||||
hists__collapse_resort(&t->sym_evsel->hists, NULL);
|
||||
hists__output_resort(&t->sym_evsel->hists);
|
||||
hists__decay_entries(&t->sym_evsel->hists,
|
||||
t->hide_user_symbols,
|
||||
@ -771,7 +771,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||
sample->callchain) {
|
||||
err = machine__resolve_callchain(machine, evsel,
|
||||
al.thread, sample,
|
||||
&parent, &al);
|
||||
&parent, &al,
|
||||
top->max_stack);
|
||||
if (err)
|
||||
return;
|
||||
}
|
||||
@ -856,7 +857,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
|
||||
&sample, machine);
|
||||
} else if (event->header.type < PERF_RECORD_MAX) {
|
||||
hists__inc_nr_events(&evsel->hists, event->header.type);
|
||||
machine__process_event(machine, event);
|
||||
machine__process_event(machine, event, &sample);
|
||||
} else
|
||||
++session->stats.nr_unknown_events;
|
||||
next_event:
|
||||
@ -932,11 +933,8 @@ static int __cmd_top(struct perf_top *top)
|
||||
struct perf_record_opts *opts = &top->record_opts;
|
||||
pthread_t thread;
|
||||
int ret;
|
||||
/*
|
||||
* FIXME: perf_session__new should allow passing a O_MMAP, so that all this
|
||||
* mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
|
||||
*/
|
||||
top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
|
||||
|
||||
top->session = perf_session__new(NULL, false, NULL);
|
||||
if (top->session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1043,7 +1041,7 @@ parse_percent_limit(const struct option *opt, const char *arg,
|
||||
|
||||
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
int status;
|
||||
int status = -1;
|
||||
char errbuf[BUFSIZ];
|
||||
struct perf_top top = {
|
||||
.count_filter = 5,
|
||||
@ -1053,10 +1051,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
.user_freq = UINT_MAX,
|
||||
.user_interval = ULLONG_MAX,
|
||||
.freq = 4000, /* 4 KHz */
|
||||
.target = {
|
||||
.target = {
|
||||
.uses_mmap = true,
|
||||
},
|
||||
},
|
||||
.max_stack = PERF_MAX_STACK_DEPTH,
|
||||
.sym_pcnt_filter = 5,
|
||||
};
|
||||
struct perf_record_opts *opts = &top.record_opts;
|
||||
@ -1076,10 +1075,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"list of cpus to monitor"),
|
||||
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||
"file", "vmlinux pathname"),
|
||||
OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
|
||||
"don't load vmlinux even if found"),
|
||||
OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
|
||||
"hide kernel symbols"),
|
||||
OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages,
|
||||
"number of mmap data pages"),
|
||||
OPT_CALLBACK('m', "mmap-pages", &opts->mmap_pages, "pages",
|
||||
"number of mmap data pages",
|
||||
perf_evlist__parse_mmap_pages),
|
||||
OPT_INTEGER('r', "realtime", &top.realtime_prio,
|
||||
"collect data with this RT SCHED_FIFO priority"),
|
||||
OPT_INTEGER('d', "delay", &top.delay_secs,
|
||||
@ -1105,7 +1107,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show counter open errors, etc)"),
|
||||
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
|
||||
"sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"),
|
||||
"sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight,"
|
||||
" abort, in_tx, transaction"),
|
||||
OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
|
||||
"Show a column with the number of samples"),
|
||||
OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts,
|
||||
@ -1114,6 +1117,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
OPT_CALLBACK(0, "call-graph", &top.record_opts,
|
||||
"mode[,dump_size]", record_callchain_help,
|
||||
&parse_callchain_opt),
|
||||
OPT_INTEGER(0, "max-stack", &top.max_stack,
|
||||
"Set the maximum stack depth when parsing the callchain. "
|
||||
"Default: " __stringify(PERF_MAX_STACK_DEPTH)),
|
||||
OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
|
||||
"ignore callees of these functions in call graphs",
|
||||
report_parse_ignore_callees_opt),
|
||||
@ -1154,8 +1160,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (sort_order == default_sort_order)
|
||||
sort_order = "dso,symbol";
|
||||
|
||||
if (setup_sorting() < 0)
|
||||
usage_with_options(top_usage, options);
|
||||
if (setup_sorting() < 0) {
|
||||
parse_options_usage(top_usage, options, "s", 1);
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
/* display thread wants entries to be collapsed in a different tree */
|
||||
sort__need_collapse = 1;
|
||||
@ -1201,20 +1209,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (top.delay_secs < 1)
|
||||
top.delay_secs = 1;
|
||||
|
||||
if (opts->user_interval != ULLONG_MAX)
|
||||
opts->default_interval = opts->user_interval;
|
||||
if (opts->user_freq != UINT_MAX)
|
||||
opts->freq = opts->user_freq;
|
||||
|
||||
/*
|
||||
* User specified count overrides default frequency.
|
||||
*/
|
||||
if (opts->default_interval)
|
||||
opts->freq = 0;
|
||||
else if (opts->freq) {
|
||||
opts->default_interval = opts->freq;
|
||||
} else {
|
||||
ui__error("frequency and count are zero, aborting\n");
|
||||
if (perf_record_opts__config(opts)) {
|
||||
status = -EINVAL;
|
||||
goto out_delete_maps;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -23,15 +23,17 @@ ifeq ($(ARCH),x86_64)
|
||||
endif
|
||||
ifeq (${IS_X86_64}, 1)
|
||||
RAW_ARCH := x86_64
|
||||
CFLAGS += -DARCH_X86_64
|
||||
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
|
||||
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
|
||||
LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
|
||||
else
|
||||
LIBUNWIND_LIBS = -lunwind -lunwind-x86
|
||||
endif
|
||||
NO_PERF_REGS := 0
|
||||
LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
|
||||
endif
|
||||
|
||||
ifeq ($(NO_PERF_REGS),0)
|
||||
CFLAGS += -DHAVE_PERF_REGS
|
||||
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
|
||||
endif
|
||||
|
||||
ifeq ($(src-perf),)
|
||||
@ -51,7 +53,6 @@ LIB_INCLUDE := $(srctree)/tools/lib/
|
||||
# include ARCH specific config
|
||||
-include $(src-perf)/arch/$(ARCH)/Makefile
|
||||
|
||||
include $(src-perf)/config/feature-tests.mak
|
||||
include $(src-perf)/config/utilities.mak
|
||||
|
||||
ifeq ($(call get-executable,$(FLEX)),)
|
||||
@ -67,10 +68,11 @@ ifneq ($(WERROR),0)
|
||||
CFLAGS += -Werror
|
||||
endif
|
||||
|
||||
ifeq ("$(origin DEBUG)", "command line")
|
||||
PERF_DEBUG = $(DEBUG)
|
||||
ifndef DEBUG
|
||||
DEBUG := 0
|
||||
endif
|
||||
ifndef PERF_DEBUG
|
||||
|
||||
ifeq ($(DEBUG),0)
|
||||
CFLAGS += -O6
|
||||
endif
|
||||
|
||||
@ -89,20 +91,125 @@ CFLAGS += -std=gnu99
|
||||
|
||||
EXTLIBS = -lelf -lpthread -lrt -lm -ldl
|
||||
|
||||
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
|
||||
ifneq ($(OUTPUT),)
|
||||
OUTPUT_FEATURES = $(OUTPUT)config/feature-checks/
|
||||
$(shell mkdir -p $(OUTPUT_FEATURES))
|
||||
endif
|
||||
|
||||
feature_check = $(eval $(feature_check_code))
|
||||
define feature_check_code
|
||||
feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
endef
|
||||
|
||||
feature_set = $(eval $(feature_set_code))
|
||||
define feature_set_code
|
||||
feature-$(1) := 1
|
||||
endef
|
||||
|
||||
#
|
||||
# Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output:
|
||||
#
|
||||
|
||||
#
|
||||
# Note that this is not a complete list of all feature tests, just
|
||||
# those that are typically built on a fully configured system.
|
||||
#
|
||||
# [ Feature tests not mentioned here have to be built explicitly in
|
||||
# the rule that uses them - an example for that is the 'bionic'
|
||||
# feature check. ]
|
||||
#
|
||||
CORE_FEATURE_TESTS = \
|
||||
backtrace \
|
||||
dwarf \
|
||||
fortify-source \
|
||||
glibc \
|
||||
gtk2 \
|
||||
gtk2-infobar \
|
||||
libaudit \
|
||||
libbfd \
|
||||
libelf \
|
||||
libelf-getphdrnum \
|
||||
libelf-mmap \
|
||||
libnuma \
|
||||
libperl \
|
||||
libpython \
|
||||
libpython-version \
|
||||
libslang \
|
||||
libunwind \
|
||||
on-exit \
|
||||
stackprotector \
|
||||
stackprotector-all
|
||||
|
||||
#
|
||||
# So here we detect whether test-all was rebuilt, to be able
|
||||
# to skip the print-out of the long features list if the file
|
||||
# existed before and after it was built:
|
||||
#
|
||||
ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all),)
|
||||
test-all-failed := 1
|
||||
else
|
||||
test-all-failed := 0
|
||||
endif
|
||||
|
||||
#
|
||||
# Special fast-path for the 'all features are available' case:
|
||||
#
|
||||
$(call feature_check,all,$(MSG))
|
||||
|
||||
#
|
||||
# Just in case the build freshly failed, make sure we print the
|
||||
# feature matrix:
|
||||
#
|
||||
ifeq ($(feature-all), 0)
|
||||
test-all-failed := 1
|
||||
endif
|
||||
|
||||
ifeq ($(test-all-failed),1)
|
||||
$(info )
|
||||
$(info Auto-detecting system features:)
|
||||
endif
|
||||
|
||||
ifeq ($(feature-all), 1)
|
||||
#
|
||||
# test-all.c passed - just set all the core feature flags to 1:
|
||||
#
|
||||
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat)))
|
||||
else
|
||||
$(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1)
|
||||
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
|
||||
endif
|
||||
|
||||
#
|
||||
# Print the result of the feature test:
|
||||
#
|
||||
feature_print = $(eval $(feature_print_code)) $(info $(MSG))
|
||||
|
||||
define feature_print_code
|
||||
ifeq ($(feature-$(1)), 1)
|
||||
MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
|
||||
else
|
||||
MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
|
||||
endif
|
||||
endef
|
||||
|
||||
#
|
||||
# Only print out our features if we rebuilt the testcases or if a test failed:
|
||||
#
|
||||
ifeq ($(test-all-failed), 1)
|
||||
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_print,$(feat)))
|
||||
$(info )
|
||||
endif
|
||||
|
||||
ifeq ($(feature-stackprotector-all), 1)
|
||||
CFLAGS += -fstack-protector-all
|
||||
endif
|
||||
|
||||
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
|
||||
ifeq ($(feature-stackprotector), 1)
|
||||
CFLAGS += -Wstack-protector
|
||||
endif
|
||||
|
||||
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
|
||||
CFLAGS += -Wvolatile-register-var
|
||||
endif
|
||||
|
||||
ifndef PERF_DEBUG
|
||||
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y)
|
||||
ifeq ($(DEBUG),0)
|
||||
ifeq ($(feature-fortify-source), 1)
|
||||
CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
endif
|
||||
@ -128,84 +235,74 @@ CFLAGS += -I$(LIB_INCLUDE)
|
||||
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
|
||||
|
||||
ifndef NO_BIONIC
|
||||
ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
|
||||
BIONIC := 1
|
||||
EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
|
||||
EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
|
||||
$(call feature_check,bionic)
|
||||
ifeq ($(feature-bionic), 1)
|
||||
BIONIC := 1
|
||||
EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
|
||||
EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
|
||||
endif
|
||||
endif
|
||||
endif # NO_BIONIC
|
||||
|
||||
ifdef NO_LIBELF
|
||||
NO_DWARF := 1
|
||||
NO_DEMANGLE := 1
|
||||
NO_LIBUNWIND := 1
|
||||
else
|
||||
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
|
||||
ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
|
||||
FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS)
|
||||
ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
|
||||
LIBC_SUPPORT := 1
|
||||
endif
|
||||
ifeq ($(BIONIC),1)
|
||||
LIBC_SUPPORT := 1
|
||||
endif
|
||||
ifeq ($(LIBC_SUPPORT),1)
|
||||
msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
|
||||
ifeq ($(feature-libelf), 0)
|
||||
ifeq ($(feature-glibc), 1)
|
||||
LIBC_SUPPORT := 1
|
||||
endif
|
||||
ifeq ($(BIONIC),1)
|
||||
LIBC_SUPPORT := 1
|
||||
endif
|
||||
ifeq ($(LIBC_SUPPORT),1)
|
||||
msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
|
||||
|
||||
NO_LIBELF := 1
|
||||
NO_DWARF := 1
|
||||
NO_DEMANGLE := 1
|
||||
NO_LIBELF := 1
|
||||
NO_DWARF := 1
|
||||
NO_DEMANGLE := 1
|
||||
else
|
||||
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
|
||||
endif
|
||||
else
|
||||
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
|
||||
endif
|
||||
else
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
|
||||
ifdef LIBDW_DIR
|
||||
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
|
||||
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
|
||||
endif
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
|
||||
ifdef LIBDW_DIR
|
||||
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
|
||||
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
|
||||
endif
|
||||
|
||||
FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lz -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS)
|
||||
ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
|
||||
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
|
||||
NO_DWARF := 1
|
||||
endif # Dwarf support
|
||||
endif # SOURCE_LIBELF
|
||||
ifneq ($(feature-dwarf), 1)
|
||||
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
|
||||
NO_DWARF := 1
|
||||
endif # Dwarf support
|
||||
endif # libelf support
|
||||
endif # NO_LIBELF
|
||||
|
||||
ifndef NO_LIBELF
|
||||
CFLAGS += -DLIBELF_SUPPORT
|
||||
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
|
||||
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
|
||||
CFLAGS += -DLIBELF_MMAP
|
||||
endif
|
||||
ifeq ($(call try-cc,$(SOURCE_ELF_GETPHDRNUM),$(FLAGS_LIBELF),-DHAVE_ELF_GETPHDRNUM),y)
|
||||
CFLAGS += -DHAVE_ELF_GETPHDRNUM
|
||||
endif
|
||||
CFLAGS += -DHAVE_LIBELF_SUPPORT
|
||||
|
||||
# include ARCH specific config
|
||||
-include $(src-perf)/arch/$(ARCH)/Makefile
|
||||
ifeq ($(feature-libelf-mmap), 1)
|
||||
CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
|
||||
endif
|
||||
|
||||
ifndef NO_DWARF
|
||||
ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
|
||||
msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
|
||||
NO_DWARF := 1
|
||||
else
|
||||
CFLAGS += -DDWARF_SUPPORT $(LIBDW_CFLAGS)
|
||||
LDFLAGS += $(LIBDW_LDFLAGS)
|
||||
EXTLIBS += -lelf -ldw
|
||||
endif # PERF_HAVE_DWARF_REGS
|
||||
endif # NO_DWARF
|
||||
ifeq ($(feature-libelf-getphdrnum), 1)
|
||||
CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
|
||||
endif
|
||||
|
||||
endif # NO_LIBELF
|
||||
# include ARCH specific config
|
||||
-include $(src-perf)/arch/$(ARCH)/Makefile
|
||||
|
||||
ifndef NO_LIBELF
|
||||
CFLAGS += -DLIBELF_SUPPORT
|
||||
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
|
||||
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
|
||||
CFLAGS += -DLIBELF_MMAP
|
||||
endif # try-cc
|
||||
ifndef NO_DWARF
|
||||
ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
|
||||
msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
|
||||
NO_DWARF := 1
|
||||
else
|
||||
CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
|
||||
LDFLAGS += $(LIBDW_LDFLAGS)
|
||||
EXTLIBS += -lelf -ldw
|
||||
endif # PERF_HAVE_DWARF_REGS
|
||||
endif # NO_DWARF
|
||||
endif # NO_LIBELF
|
||||
|
||||
# There's only x86 (both 32 and 64) support for CFI unwind so far
|
||||
@ -214,34 +311,35 @@ ifneq ($(ARCH),x86)
|
||||
endif
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
|
||||
ifdef LIBUNWIND_DIR
|
||||
LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
|
||||
LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
|
||||
#
|
||||
# For linking with debug library, run like:
|
||||
#
|
||||
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
|
||||
#
|
||||
ifdef LIBUNWIND_DIR
|
||||
LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
|
||||
LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
|
||||
endif
|
||||
|
||||
ifneq ($(feature-libunwind), 1)
|
||||
msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
|
||||
NO_LIBUNWIND := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
|
||||
ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
|
||||
msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
|
||||
NO_LIBUNWIND := 1
|
||||
endif # Libunwind support
|
||||
endif # NO_LIBUNWIND
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
CFLAGS += -DLIBUNWIND_SUPPORT
|
||||
CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
|
||||
EXTLIBS += $(LIBUNWIND_LIBS)
|
||||
CFLAGS += $(LIBUNWIND_CFLAGS)
|
||||
LDFLAGS += $(LIBUNWIND_LDFLAGS)
|
||||
endif # NO_LIBUNWIND
|
||||
endif
|
||||
|
||||
ifndef NO_LIBAUDIT
|
||||
FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit
|
||||
ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
|
||||
ifneq ($(feature-libaudit), 1)
|
||||
msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
|
||||
NO_LIBAUDIT := 1
|
||||
else
|
||||
CFLAGS += -DLIBAUDIT_SUPPORT
|
||||
CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
|
||||
EXTLIBS += -laudit
|
||||
endif
|
||||
endif
|
||||
@ -251,30 +349,30 @@ ifdef NO_NEWT
|
||||
endif
|
||||
|
||||
ifndef NO_SLANG
|
||||
FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
|
||||
ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
|
||||
ifneq ($(feature-libslang), 1)
|
||||
msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
|
||||
NO_SLANG := 1
|
||||
else
|
||||
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
|
||||
CFLAGS += -I/usr/include/slang
|
||||
CFLAGS += -DSLANG_SUPPORT
|
||||
CFLAGS += -DHAVE_SLANG_SUPPORT
|
||||
EXTLIBS += -lslang
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_GTK2
|
||||
FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
|
||||
ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
|
||||
ifneq ($(feature-gtk2), 1)
|
||||
msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
|
||||
NO_GTK2 := 1
|
||||
else
|
||||
ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
|
||||
CFLAGS += -DHAVE_GTK_INFO_BAR
|
||||
ifeq ($(feature-gtk2-infobar), 1)
|
||||
GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT
|
||||
endif
|
||||
CFLAGS += -DGTK2_SUPPORT
|
||||
CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
|
||||
EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
|
||||
CFLAGS += -DHAVE_GTK2_SUPPORT
|
||||
GTK_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
|
||||
GTK_LIBS := $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
|
||||
EXTLIBS += -ldl
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -290,7 +388,7 @@ else
|
||||
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
|
||||
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
|
||||
|
||||
ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
|
||||
ifneq ($(feature-libperl), 1)
|
||||
CFLAGS += -DNO_LIBPERL
|
||||
NO_LIBPERL := 1
|
||||
else
|
||||
@ -299,6 +397,13 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
$(call feature_check,timerfd)
|
||||
ifeq ($(feature-timerfd), 1)
|
||||
CFLAGS += -DHAVE_TIMERFD_SUPPORT
|
||||
else
|
||||
msg := $(warning No timerfd support. Disables 'perf kvm stat live');
|
||||
endif
|
||||
|
||||
disable-python = $(eval $(disable-python_code))
|
||||
define disable-python_code
|
||||
CFLAGS += -DNO_LIBPYTHON
|
||||
@ -335,11 +440,11 @@ else
|
||||
PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
|
||||
FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
|
||||
|
||||
ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
|
||||
ifneq ($(feature-libpython), 1)
|
||||
$(call disable-python,Python.h (for Python 2.x))
|
||||
else
|
||||
|
||||
ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
|
||||
ifneq ($(feature-libpython-version), 1)
|
||||
$(warning Python 3 is not yet supported; please set)
|
||||
$(warning PYTHON and/or PYTHON_CONFIG appropriately.)
|
||||
$(warning If you also have Python 2 installed, then)
|
||||
@ -362,33 +467,30 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(feature-libbfd), 1)
|
||||
EXTLIBS += -lbfd
|
||||
endif
|
||||
|
||||
ifdef NO_DEMANGLE
|
||||
CFLAGS += -DNO_DEMANGLE
|
||||
else
|
||||
ifdef HAVE_CPLUS_DEMANGLE
|
||||
ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
|
||||
EXTLIBS += -liberty
|
||||
CFLAGS += -DHAVE_CPLUS_DEMANGLE
|
||||
CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
|
||||
else
|
||||
FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
|
||||
has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
|
||||
ifeq ($(has_bfd),y)
|
||||
EXTLIBS += -lbfd
|
||||
else
|
||||
FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
|
||||
has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
|
||||
ifeq ($(has_bfd_iberty),y)
|
||||
ifneq ($(feature-libbfd), 1)
|
||||
$(call feature_check,liberty)
|
||||
ifeq ($(feature-liberty), 1)
|
||||
EXTLIBS += -lbfd -liberty
|
||||
else
|
||||
FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
|
||||
has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
|
||||
ifeq ($(has_bfd_iberty_z),y)
|
||||
$(call feature_check,liberty-z)
|
||||
ifeq ($(feature-liberty-z), 1)
|
||||
EXTLIBS += -lbfd -liberty -lz
|
||||
else
|
||||
FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty
|
||||
has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
|
||||
ifeq ($(has_cplus_demangle),y)
|
||||
$(call feature_check,cplus-demangle)
|
||||
ifeq ($(feature-cplus-demangle), 1)
|
||||
EXTLIBS += -liberty
|
||||
CFLAGS += -DHAVE_CPLUS_DEMANGLE
|
||||
CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
|
||||
else
|
||||
msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
|
||||
CFLAGS += -DNO_DEMANGLE
|
||||
@ -399,31 +501,28 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_STRLCPY
|
||||
ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
|
||||
CFLAGS += -DHAVE_STRLCPY
|
||||
endif
|
||||
ifneq ($(filter -lbfd,$(EXTLIBS)),)
|
||||
CFLAGS += -DHAVE_LIBBFD_SUPPORT
|
||||
endif
|
||||
|
||||
ifndef NO_ON_EXIT
|
||||
ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
|
||||
CFLAGS += -DHAVE_ON_EXIT
|
||||
ifeq ($(feature-on-exit), 1)
|
||||
CFLAGS += -DHAVE_ON_EXIT_SUPPORT
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_BACKTRACE
|
||||
ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
|
||||
CFLAGS += -DBACKTRACE_SUPPORT
|
||||
ifeq ($(feature-backtrace), 1)
|
||||
CFLAGS += -DHAVE_BACKTRACE_SUPPORT
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_LIBNUMA
|
||||
FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma
|
||||
ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
|
||||
ifeq ($(feature-libnuma), 0)
|
||||
msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
|
||||
NO_LIBNUMA := 1
|
||||
else
|
||||
CFLAGS += -DLIBNUMA_SUPPORT
|
||||
CFLAGS += -DHAVE_LIBNUMA_SUPPORT
|
||||
EXTLIBS += -lnuma
|
||||
endif
|
||||
endif
|
||||
@ -459,7 +558,12 @@ else
|
||||
sysconfdir = $(prefix)/etc
|
||||
ETC_PERFCONFIG = etc/perfconfig
|
||||
endif
|
||||
ifeq ($(IS_X86_64),1)
|
||||
lib = lib64
|
||||
else
|
||||
lib = lib
|
||||
endif
|
||||
libdir = $(prefix)/$(lib)
|
||||
|
||||
# Shell quote (do not use $(call) to accommodate ancient setups);
|
||||
ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
|
||||
@ -472,6 +576,7 @@ template_dir_SQ = $(subst ','\'',$(template_dir))
|
||||
htmldir_SQ = $(subst ','\'',$(htmldir))
|
||||
prefix_SQ = $(subst ','\'',$(prefix))
|
||||
sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
|
||||
libdir_SQ = $(subst ','\'',$(libdir))
|
||||
|
||||
ifneq ($(filter /%,$(firstword $(perfexecdir))),)
|
||||
perfexec_instdir = $(perfexecdir)
|
||||
|
148
tools/perf/config/feature-checks/Makefile
Normal file
148
tools/perf/config/feature-checks/Makefile
Normal file
@ -0,0 +1,148 @@
|
||||
|
||||
FILES= \
|
||||
test-all \
|
||||
test-backtrace \
|
||||
test-bionic \
|
||||
test-dwarf \
|
||||
test-fortify-source \
|
||||
test-glibc \
|
||||
test-gtk2 \
|
||||
test-gtk2-infobar \
|
||||
test-hello \
|
||||
test-libaudit \
|
||||
test-libbfd \
|
||||
test-liberty \
|
||||
test-liberty-z \
|
||||
test-cplus-demangle \
|
||||
test-libelf \
|
||||
test-libelf-getphdrnum \
|
||||
test-libelf-mmap \
|
||||
test-libnuma \
|
||||
test-libperl \
|
||||
test-libpython \
|
||||
test-libpython-version \
|
||||
test-libslang \
|
||||
test-libunwind \
|
||||
test-on-exit \
|
||||
test-stackprotector-all \
|
||||
test-stackprotector \
|
||||
test-timerfd
|
||||
|
||||
CC := $(CC) -MD
|
||||
|
||||
all: $(FILES)
|
||||
|
||||
BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
|
||||
|
||||
###############################
|
||||
|
||||
test-all:
|
||||
$(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
|
||||
|
||||
test-hello:
|
||||
$(BUILD)
|
||||
|
||||
test-stackprotector-all:
|
||||
$(BUILD) -Werror -fstack-protector-all
|
||||
|
||||
test-stackprotector:
|
||||
$(BUILD) -Werror -fstack-protector -Wstack-protector
|
||||
|
||||
test-fortify-source:
|
||||
$(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
|
||||
|
||||
test-bionic:
|
||||
$(BUILD)
|
||||
|
||||
test-libelf:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-glibc:
|
||||
$(BUILD)
|
||||
|
||||
test-dwarf:
|
||||
$(BUILD) -ldw
|
||||
|
||||
test-libelf-mmap:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libelf-getphdrnum:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libnuma:
|
||||
$(BUILD) -lnuma
|
||||
|
||||
test-libunwind:
|
||||
$(BUILD) $(LIBUNWIND_LIBS) -lelf
|
||||
|
||||
test-libaudit:
|
||||
$(BUILD) -laudit
|
||||
|
||||
test-libslang:
|
||||
$(BUILD) -I/usr/include/slang -lslang
|
||||
|
||||
test-gtk2:
|
||||
$(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
|
||||
|
||||
test-gtk2-infobar:
|
||||
$(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
|
||||
|
||||
grep-libs = $(filter -l%,$(1))
|
||||
strip-libs = $(filter-out -l%,$(1))
|
||||
|
||||
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
|
||||
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
|
||||
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
|
||||
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
|
||||
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
|
||||
|
||||
test-libperl:
|
||||
$(BUILD) $(FLAGS_PERL_EMBED)
|
||||
|
||||
override PYTHON := python
|
||||
override PYTHON_CONFIG := python-config
|
||||
|
||||
escape-for-shell-sq = $(subst ','\'',$(1))
|
||||
shell-sq = '$(escape-for-shell-sq)'
|
||||
|
||||
PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG))
|
||||
|
||||
PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
|
||||
PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
|
||||
PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
|
||||
PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
|
||||
FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
|
||||
|
||||
test-libpython:
|
||||
$(BUILD) $(FLAGS_PYTHON_EMBED)
|
||||
|
||||
test-libpython-version:
|
||||
$(BUILD) $(FLAGS_PYTHON_EMBED)
|
||||
|
||||
test-libbfd:
|
||||
$(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
|
||||
|
||||
test-liberty:
|
||||
$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
|
||||
|
||||
test-liberty-z:
|
||||
$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz
|
||||
|
||||
test-cplus-demangle:
|
||||
$(BUILD) -liberty
|
||||
|
||||
test-on-exit:
|
||||
$(BUILD)
|
||||
|
||||
test-backtrace:
|
||||
$(BUILD)
|
||||
|
||||
test-timerfd:
|
||||
$(BUILD)
|
||||
|
||||
-include *.d
|
||||
|
||||
###############################
|
||||
|
||||
clean:
|
||||
rm -f $(FILES) *.d
|
111
tools/perf/config/feature-checks/test-all.c
Normal file
111
tools/perf/config/feature-checks/test-all.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* test-all.c: Try to build all the main testcases at once.
|
||||
*
|
||||
* A well-configured system will have all the prereqs installed, so we can speed
|
||||
* up auto-detection on such systems.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Quirk: Python and Perl headers cannot be in arbitrary places, so keep
|
||||
* these 3 testcases at the top:
|
||||
*/
|
||||
#define main main_test_libpython
|
||||
# include "test-libpython.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libpython_version
|
||||
# include "test-libpython-version.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libperl
|
||||
# include "test-libperl.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_hello
|
||||
# include "test-hello.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libelf
|
||||
# include "test-libelf.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libelf_mmap
|
||||
# include "test-libelf-mmap.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_glibc
|
||||
# include "test-glibc.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_dwarf
|
||||
# include "test-dwarf.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libelf_getphdrnum
|
||||
# include "test-libelf-getphdrnum.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libunwind
|
||||
# include "test-libunwind.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libaudit
|
||||
# include "test-libaudit.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libslang
|
||||
# include "test-libslang.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_gtk2
|
||||
# include "test-gtk2.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_gtk2_infobar
|
||||
# include "test-gtk2-infobar.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libbfd
|
||||
# include "test-libbfd.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_on_exit
|
||||
# include "test-on-exit.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_backtrace
|
||||
# include "test-backtrace.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libnuma
|
||||
# include "test-libnuma.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_timerfd
|
||||
# include "test-timerfd.c"
|
||||
#undef main
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
main_test_libpython();
|
||||
main_test_libpython_version();
|
||||
main_test_libperl();
|
||||
main_test_hello();
|
||||
main_test_libelf();
|
||||
main_test_libelf_mmap();
|
||||
main_test_glibc();
|
||||
main_test_dwarf();
|
||||
main_test_libelf_getphdrnum();
|
||||
main_test_libunwind();
|
||||
main_test_libaudit();
|
||||
main_test_libslang();
|
||||
main_test_gtk2(argc, argv);
|
||||
main_test_gtk2_infobar(argc, argv);
|
||||
main_test_libbfd();
|
||||
main_test_on_exit();
|
||||
main_test_backtrace();
|
||||
main_test_libnuma();
|
||||
main_test_timerfd();
|
||||
|
||||
return 0;
|
||||
}
|
13
tools/perf/config/feature-checks/test-backtrace.c
Normal file
13
tools/perf/config/feature-checks/test-backtrace.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <execinfo.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void *backtrace_fns[10];
|
||||
size_t entries;
|
||||
|
||||
entries = backtrace(backtrace_fns, 10);
|
||||
backtrace_symbols_fd(backtrace_fns, entries, 1);
|
||||
|
||||
return 0;
|
||||
}
|
6
tools/perf/config/feature-checks/test-bionic.c
Normal file
6
tools/perf/config/feature-checks/test-bionic.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <android/api-level.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return __ANDROID_API__;
|
||||
}
|
14
tools/perf/config/feature-checks/test-cplus-demangle.c
Normal file
14
tools/perf/config/feature-checks/test-cplus-demangle.c
Normal file
@ -0,0 +1,14 @@
|
||||
extern int printf(const char *format, ...);
|
||||
extern char *cplus_demangle(const char *, int);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char symbol[4096] = "FieldName__9ClassNameFd";
|
||||
char *tmp;
|
||||
|
||||
tmp = cplus_demangle(symbol, 0);
|
||||
|
||||
printf("demangled symbol: {%s}\n", tmp);
|
||||
|
||||
return 0;
|
||||
}
|
10
tools/perf/config/feature-checks/test-dwarf.c
Normal file
10
tools/perf/config/feature-checks/test-dwarf.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <dwarf.h>
|
||||
#include <elfutils/libdw.h>
|
||||
#include <elfutils/version.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
|
||||
|
||||
return (long)dbg;
|
||||
}
|
6
tools/perf/config/feature-checks/test-fortify-source.c
Normal file
6
tools/perf/config/feature-checks/test-fortify-source.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return puts("hi");
|
||||
}
|
8
tools/perf/config/feature-checks/test-glibc.c
Normal file
8
tools/perf/config/feature-checks/test-glibc.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <gnu/libc-version.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *version = gnu_get_libc_version();
|
||||
|
||||
return (long)version;
|
||||
}
|
11
tools/perf/config/feature-checks/test-gtk2-infobar.c
Normal file
11
tools/perf/config/feature-checks/test-gtk2-infobar.c
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <gtk/gtk.h>
|
||||
#pragma GCC diagnostic error "-Wstrict-prototypes"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
gtk_init(&argc, &argv);
|
||||
gtk_info_bar_new();
|
||||
|
||||
return 0;
|
||||
}
|
10
tools/perf/config/feature-checks/test-gtk2.c
Normal file
10
tools/perf/config/feature-checks/test-gtk2.c
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <gtk/gtk.h>
|
||||
#pragma GCC diagnostic error "-Wstrict-prototypes"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
return 0;
|
||||
}
|
6
tools/perf/config/feature-checks/test-hello.c
Normal file
6
tools/perf/config/feature-checks/test-hello.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return puts("hi");
|
||||
}
|
10
tools/perf/config/feature-checks/test-libaudit.c
Normal file
10
tools/perf/config/feature-checks/test-libaudit.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <libaudit.h>
|
||||
|
||||
extern int printf(const char *format, ...);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("error message: %s\n", audit_errno_to_name(0));
|
||||
|
||||
return audit_open();
|
||||
}
|
15
tools/perf/config/feature-checks/test-libbfd.c
Normal file
15
tools/perf/config/feature-checks/test-libbfd.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <bfd.h>
|
||||
|
||||
extern int printf(const char *format, ...);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char symbol[4096] = "FieldName__9ClassNameFd";
|
||||
char *tmp;
|
||||
|
||||
tmp = bfd_demangle(0, symbol, 0);
|
||||
|
||||
printf("demangled symbol: {%s}\n", tmp);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#include <libelf.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
size_t dst;
|
||||
|
||||
return elf_getphdrnum(0, &dst);
|
||||
}
|
8
tools/perf/config/feature-checks/test-libelf-mmap.c
Normal file
8
tools/perf/config/feature-checks/test-libelf-mmap.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <libelf.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
|
||||
|
||||
return (long)elf;
|
||||
}
|
8
tools/perf/config/feature-checks/test-libelf.c
Normal file
8
tools/perf/config/feature-checks/test-libelf.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <libelf.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Elf *elf = elf_begin(0, ELF_C_READ, 0);
|
||||
|
||||
return (long)elf;
|
||||
}
|
9
tools/perf/config/feature-checks/test-libnuma.c
Normal file
9
tools/perf/config/feature-checks/test-libnuma.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <numa.h>
|
||||
#include <numaif.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
numa_available();
|
||||
|
||||
return 0;
|
||||
}
|
9
tools/perf/config/feature-checks/test-libperl.c
Normal file
9
tools/perf/config/feature-checks/test-libperl.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
perl_alloc();
|
||||
|
||||
return 0;
|
||||
}
|
10
tools/perf/config/feature-checks/test-libpython-version.c
Normal file
10
tools/perf/config/feature-checks/test-libpython-version.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <Python.h>
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
#error
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
8
tools/perf/config/feature-checks/test-libpython.c
Normal file
8
tools/perf/config/feature-checks/test-libpython.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <Python.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Py_Initialize();
|
||||
|
||||
return 0;
|
||||
}
|
6
tools/perf/config/feature-checks/test-libslang.c
Normal file
6
tools/perf/config/feature-checks/test-libslang.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <slang.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return SLsmg_init_smg();
|
||||
}
|
27
tools/perf/config/feature-checks/test-libunwind.c
Normal file
27
tools/perf/config/feature-checks/test-libunwind.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <libunwind.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
|
||||
unw_word_t ip,
|
||||
unw_dyn_info_t *di,
|
||||
unw_proc_info_t *pi,
|
||||
int need_unwind_info, void *arg);
|
||||
|
||||
|
||||
#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
|
||||
|
||||
static unw_accessors_t accessors;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unw_addr_space_t addr_space;
|
||||
|
||||
addr_space = unw_create_addr_space(&accessors, 0);
|
||||
if (addr_space)
|
||||
return 0;
|
||||
|
||||
unw_init_remote(NULL, addr_space, NULL);
|
||||
dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
16
tools/perf/config/feature-checks/test-on-exit.c
Normal file
16
tools/perf/config/feature-checks/test-on-exit.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void exit_fn(int status, void *__data)
|
||||
{
|
||||
printf("exit status: %d, data: %d\n", status, *(int *)__data);
|
||||
}
|
||||
|
||||
static int data = 123;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
on_exit(exit_fn, &data);
|
||||
|
||||
return 321;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return puts("hi");
|
||||
}
|
6
tools/perf/config/feature-checks/test-stackprotector.c
Normal file
6
tools/perf/config/feature-checks/test-stackprotector.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return puts("hi");
|
||||
}
|
18
tools/perf/config/feature-checks/test-timerfd.c
Normal file
18
tools/perf/config/feature-checks/test-timerfd.c
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* test for timerfd functions used by perf-kvm-stat-live
|
||||
*/
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct itimerspec new_value;
|
||||
|
||||
int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
||||
if (timerfd_settime(fd, 0, &new_value, NULL) != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return puts("hi");
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
define SOURCE_HELLO
|
||||
#include <stdio.h>
|
||||
int main(void)
|
||||
{
|
||||
return puts(\"hi\");
|
||||
}
|
||||
endef
|
||||
|
||||
ifndef NO_DWARF
|
||||
define SOURCE_DWARF
|
||||
#include <dwarf.h>
|
||||
#include <elfutils/libdw.h>
|
||||
#include <elfutils/version.h>
|
||||
#ifndef _ELFUTILS_PREREQ
|
||||
#error
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
|
||||
return (long)dbg;
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
define SOURCE_LIBELF
|
||||
#include <libelf.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Elf *elf = elf_begin(0, ELF_C_READ, 0);
|
||||
return (long)elf;
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_GLIBC
|
||||
#include <gnu/libc-version.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *version = gnu_get_libc_version();
|
||||
return (long)version;
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_BIONIC
|
||||
#include <android/api-level.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return __ANDROID_API__;
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_ELF_MMAP
|
||||
#include <libelf.h>
|
||||
int main(void)
|
||||
{
|
||||
Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
|
||||
return (long)elf;
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_ELF_GETPHDRNUM
|
||||
#include <libelf.h>
|
||||
int main(void)
|
||||
{
|
||||
size_t dst;
|
||||
return elf_getphdrnum(0, &dst);
|
||||
}
|
||||
endef
|
||||
|
||||
ifndef NO_SLANG
|
||||
define SOURCE_SLANG
|
||||
#include <slang.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return SLsmg_init_smg();
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef NO_GTK2
|
||||
define SOURCE_GTK2
|
||||
#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
|
||||
#include <gtk/gtk.h>
|
||||
#pragma GCC diagnostic error \"-Wstrict-prototypes\"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_GTK2_INFOBAR
|
||||
#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
|
||||
#include <gtk/gtk.h>
|
||||
#pragma GCC diagnostic error \"-Wstrict-prototypes\"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
gtk_info_bar_new();
|
||||
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPERL
|
||||
define SOURCE_PERL_EMBED
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
perl_alloc();
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPYTHON
|
||||
define SOURCE_PYTHON_VERSION
|
||||
#include <Python.h>
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
#error
|
||||
#endif
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
define SOURCE_PYTHON_EMBED
|
||||
#include <Python.h>
|
||||
int main(void)
|
||||
{
|
||||
Py_Initialize();
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
define SOURCE_BFD
|
||||
#include <bfd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bfd_demangle(0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_CPLUS_DEMANGLE
|
||||
extern char *cplus_demangle(const char *, int);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
cplus_demangle(0, 0);
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_STRLCPY
|
||||
#include <stdlib.h>
|
||||
extern size_t strlcpy(char *dest, const char *src, size_t size);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
strlcpy(NULL, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
define SOURCE_LIBUNWIND
|
||||
#include <libunwind.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
|
||||
unw_word_t ip,
|
||||
unw_dyn_info_t *di,
|
||||
unw_proc_info_t *pi,
|
||||
int need_unwind_info, void *arg);
|
||||
|
||||
|
||||
#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unw_addr_space_t addr_space;
|
||||
addr_space = unw_create_addr_space(NULL, 0);
|
||||
unw_init_remote(NULL, addr_space, NULL);
|
||||
dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef NO_BACKTRACE
|
||||
define SOURCE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
backtrace(NULL, 0);
|
||||
backtrace_symbols(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef NO_LIBAUDIT
|
||||
define SOURCE_LIBAUDIT
|
||||
#include <libaudit.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf(\"error message: %s\", audit_errno_to_name(0));
|
||||
return audit_open();
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
define SOURCE_ON_EXIT
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return on_exit(NULL, NULL);
|
||||
}
|
||||
endef
|
||||
|
||||
define SOURCE_LIBNUMA
|
||||
#include <numa.h>
|
||||
#include <numaif.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
numa_available();
|
||||
return 0;
|
||||
}
|
||||
endef
|
@ -179,16 +179,9 @@ _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_e
|
||||
_gea_warn = $(warning The path '$(1)' is not executable.)
|
||||
_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
|
||||
|
||||
# try-cc
|
||||
# Usage: option = $(call try-cc, source-to-build, cc-options, msg)
|
||||
ifneq ($(V),1)
|
||||
TRY_CC_OUTPUT= > /dev/null 2>&1
|
||||
ifneq ($(findstring $(MAKEFLAGS),s),s)
|
||||
ifneq ($(V),1)
|
||||
QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
|
||||
QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
|
||||
endif
|
||||
endif
|
||||
TRY_CC_MSG=echo " CHK $(3)" 1>&2;
|
||||
|
||||
try-cc = $(shell sh -c \
|
||||
'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
|
||||
$(TRY_CC_MSG) \
|
||||
echo "$(1)" | \
|
||||
$(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \
|
||||
rm -f "$$TMP"')
|
||||
|
@ -49,14 +49,14 @@ static struct cmd_struct commands[] = {
|
||||
{ "version", cmd_version, 0 },
|
||||
{ "script", cmd_script, 0 },
|
||||
{ "sched", cmd_sched, 0 },
|
||||
#ifdef LIBELF_SUPPORT
|
||||
#ifdef HAVE_LIBELF_SUPPORT
|
||||
{ "probe", cmd_probe, 0 },
|
||||
#endif
|
||||
{ "kmem", cmd_kmem, 0 },
|
||||
{ "lock", cmd_lock, 0 },
|
||||
{ "kvm", cmd_kvm, 0 },
|
||||
{ "test", cmd_test, 0 },
|
||||
#ifdef LIBAUDIT_SUPPORT
|
||||
#ifdef HAVE_LIBAUDIT_SUPPORT
|
||||
{ "trace", cmd_trace, 0 },
|
||||
#endif
|
||||
{ "inject", cmd_inject, 0 },
|
||||
@ -456,6 +456,7 @@ int main(int argc, const char **argv)
|
||||
{
|
||||
const char *cmd;
|
||||
|
||||
/* The page_size is placed in util object. */
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
cmd = perf_extract_argv0_path(argv[0]);
|
||||
@ -480,7 +481,14 @@ int main(int argc, const char **argv)
|
||||
fprintf(stderr, "cannot handle %s internally", cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBAUDIT_SUPPORT
|
||||
if (!prefixcmp(cmd, "trace")) {
|
||||
set_buildid_dir();
|
||||
setup_path();
|
||||
argv[0] = "trace";
|
||||
return cmd_trace(argc, argv, NULL);
|
||||
}
|
||||
#endif
|
||||
/* Look for flags.. */
|
||||
argv++;
|
||||
argc--;
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#if defined(__i386__)
|
||||
#define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
|
||||
#define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
|
||||
#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
|
||||
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
|
||||
#define CPUINFO_PROC "model name"
|
||||
@ -13,6 +15,8 @@
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#define mb() asm volatile("mfence" ::: "memory")
|
||||
#define wmb() asm volatile("sfence" ::: "memory")
|
||||
#define rmb() asm volatile("lfence" ::: "memory")
|
||||
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
|
||||
#define CPUINFO_PROC "model name"
|
||||
@ -23,45 +27,61 @@
|
||||
|
||||
#ifdef __powerpc__
|
||||
#include "../../arch/powerpc/include/uapi/asm/unistd.h"
|
||||
#define mb() asm volatile ("sync" ::: "memory")
|
||||
#define wmb() asm volatile ("sync" ::: "memory")
|
||||
#define rmb() asm volatile ("sync" ::: "memory")
|
||||
#define cpu_relax() asm volatile ("" ::: "memory");
|
||||
#define CPUINFO_PROC "cpu"
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
#define mb() asm volatile("bcr 15,0" ::: "memory")
|
||||
#define wmb() asm volatile("bcr 15,0" ::: "memory")
|
||||
#define rmb() asm volatile("bcr 15,0" ::: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory");
|
||||
#endif
|
||||
|
||||
#ifdef __sh__
|
||||
#if defined(__SH4A__) || defined(__SH5__)
|
||||
# define mb() asm volatile("synco" ::: "memory")
|
||||
# define wmb() asm volatile("synco" ::: "memory")
|
||||
# define rmb() asm volatile("synco" ::: "memory")
|
||||
#else
|
||||
# define mb() asm volatile("" ::: "memory")
|
||||
# define wmb() asm volatile("" ::: "memory")
|
||||
# define rmb() asm volatile("" ::: "memory")
|
||||
#endif
|
||||
#define cpu_relax() asm volatile("" ::: "memory")
|
||||
#define CPUINFO_PROC "cpu type"
|
||||
#endif
|
||||
|
||||
#ifdef __hppa__
|
||||
#define mb() asm volatile("" ::: "memory")
|
||||
#define wmb() asm volatile("" ::: "memory")
|
||||
#define rmb() asm volatile("" ::: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory");
|
||||
#define CPUINFO_PROC "cpu"
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
#ifdef __LP64__
|
||||
#define mb() asm volatile("ba,pt %%xcc, 1f\n" \
|
||||
"membar #StoreLoad\n" \
|
||||
"1:\n":::"memory")
|
||||
#else
|
||||
#define mb() asm volatile("":::"memory")
|
||||
#endif
|
||||
#define wmb() asm volatile("":::"memory")
|
||||
#define rmb() asm volatile("":::"memory")
|
||||
#define cpu_relax() asm volatile("":::"memory")
|
||||
#define CPUINFO_PROC "cpu"
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
#define mb() asm volatile("mb" ::: "memory")
|
||||
#define wmb() asm volatile("wmb" ::: "memory")
|
||||
#define rmb() asm volatile("mb" ::: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory")
|
||||
#define CPUINFO_PROC "cpu model"
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
#define mb() asm volatile ("mf" ::: "memory")
|
||||
#define wmb() asm volatile ("mf" ::: "memory")
|
||||
#define rmb() asm volatile ("mf" ::: "memory")
|
||||
#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
|
||||
#define CPUINFO_PROC "model name"
|
||||
@ -72,40 +92,55 @@
|
||||
* Use the __kuser_memory_barrier helper in the CPU helper page. See
|
||||
* arch/arm/kernel/entry-armv.S in the kernel source for details.
|
||||
*/
|
||||
#define mb() ((void(*)(void))0xffff0fa0)()
|
||||
#define wmb() ((void(*)(void))0xffff0fa0)()
|
||||
#define rmb() ((void(*)(void))0xffff0fa0)()
|
||||
#define cpu_relax() asm volatile("":::"memory")
|
||||
#define CPUINFO_PROC "Processor"
|
||||
#endif
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define rmb() asm volatile("dmb ld" ::: "memory")
|
||||
#define mb() asm volatile("dmb ish" ::: "memory")
|
||||
#define wmb() asm volatile("dmb ishld" ::: "memory")
|
||||
#define rmb() asm volatile("dmb ishst" ::: "memory")
|
||||
#define cpu_relax() asm volatile("yield" ::: "memory")
|
||||
#endif
|
||||
|
||||
#ifdef __mips__
|
||||
#define rmb() asm volatile( \
|
||||
#define mb() asm volatile( \
|
||||
".set mips2\n\t" \
|
||||
"sync\n\t" \
|
||||
".set mips0" \
|
||||
: /* no output */ \
|
||||
: /* no input */ \
|
||||
: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory")
|
||||
#define wmb() mb()
|
||||
#define rmb() mb()
|
||||
#define CPUINFO_PROC "cpu model"
|
||||
#endif
|
||||
|
||||
#ifdef __arc__
|
||||
#define mb() asm volatile("" ::: "memory")
|
||||
#define wmb() asm volatile("" ::: "memory")
|
||||
#define rmb() asm volatile("" ::: "memory")
|
||||
#define cpu_relax() rmb()
|
||||
#define CPUINFO_PROC "Processor"
|
||||
#endif
|
||||
|
||||
#ifdef __metag__
|
||||
#define mb() asm volatile("" ::: "memory")
|
||||
#define wmb() asm volatile("" ::: "memory")
|
||||
#define rmb() asm volatile("" ::: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory")
|
||||
#define CPUINFO_PROC "CPU"
|
||||
#endif
|
||||
|
||||
#define barrier() asm volatile ("" ::: "memory")
|
||||
|
||||
#ifndef cpu_relax
|
||||
#define cpu_relax() barrier()
|
||||
#endif
|
||||
|
||||
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
|
||||
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
@ -182,7 +217,9 @@ struct ip_callchain {
|
||||
struct branch_flags {
|
||||
u64 mispred:1;
|
||||
u64 predicted:1;
|
||||
u64 reserved:62;
|
||||
u64 in_tx:1;
|
||||
u64 abort:1;
|
||||
u64 reserved:60;
|
||||
};
|
||||
|
||||
struct branch_entry {
|
||||
@ -218,7 +255,6 @@ struct perf_record_opts {
|
||||
bool no_delay;
|
||||
bool no_inherit;
|
||||
bool no_samples;
|
||||
bool pipe_output;
|
||||
bool raw_samples;
|
||||
bool sample_address;
|
||||
bool sample_weight;
|
||||
@ -231,6 +267,7 @@ struct perf_record_opts {
|
||||
u64 default_interval;
|
||||
u64 user_interval;
|
||||
u16 stack_dump_size;
|
||||
bool sample_transaction;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
PyMODINIT_FUNC initperf_trace_context(void);
|
||||
|
||||
static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args)
|
||||
static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args)
|
||||
{
|
||||
static struct scripting_context *scripting_context;
|
||||
PyObject *context;
|
||||
@ -40,7 +40,7 @@ static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args)
|
||||
return Py_BuildValue("i", retval);
|
||||
}
|
||||
|
||||
static PyObject *perf_trace_context_common_flags(PyObject *self,
|
||||
static PyObject *perf_trace_context_common_flags(PyObject *obj,
|
||||
PyObject *args)
|
||||
{
|
||||
static struct scripting_context *scripting_context;
|
||||
@ -56,7 +56,7 @@ static PyObject *perf_trace_context_common_flags(PyObject *self,
|
||||
return Py_BuildValue("i", retval);
|
||||
}
|
||||
|
||||
static PyObject *perf_trace_context_common_lock_depth(PyObject *self,
|
||||
static PyObject *perf_trace_context_common_lock_depth(PyObject *obj,
|
||||
PyObject *args)
|
||||
{
|
||||
static struct scripting_context *scripting_context;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user