Commit 43315956 authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'perf/core' into perf/probes

Conflicts:
	tools/perf/Makefile

Merge reason:

 - fix the conflict
 - pick up the pr_*() infrastructure to queue up dependent patch
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parents 9bf4e7fb 6beba7ad
......@@ -779,6 +779,13 @@ and is between 256 and 4096 characters. It is defined in the file
by the set_ftrace_notrace file in the debugfs
tracing directory.
ftrace_graph_filter=[function-list]
[FTRACE] Limit the top level callers functions traced
by the function graph tracer at boot up.
function-list is a comma separated list of functions
that can be changed at run time by the
set_graph_function file in the debugfs tracing directory.
gamecon.map[2|3]=
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
support via parallel port (up to 5 devices per port)
......
......@@ -213,10 +213,19 @@ If you can't trace NMI functions, then skip this option.
<details to be filled>
HAVE_FTRACE_SYSCALLS
HAVE_SYSCALL_TRACEPOINTS
---------------------
<details to be filled>
You need very few things to get the syscalls tracing in an arch.
- Have a NR_syscalls variable in <asm/unistd.h> that provides the number
of syscalls supported by the arch.
- Implement arch_syscall_addr() that resolves a syscall address from a
syscall number.
- Support the TIF_SYSCALL_TRACEPOINT thread flags
- Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace
in the ptrace syscalls tracing path.
- Tag this arch as HAVE_SYSCALL_TRACEPOINTS.
HAVE_FTRACE_MCOUNT_RECORD
......
......@@ -203,73 +203,10 @@ unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent)
#ifdef CONFIG_FTRACE_SYSCALLS
extern unsigned long __start_syscalls_metadata[];
extern unsigned long __stop_syscalls_metadata[];
extern unsigned int sys_call_table[];
static struct syscall_metadata **syscalls_metadata;
struct syscall_metadata *syscall_nr_to_meta(int nr)
{
if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
return NULL;
return syscalls_metadata[nr];
}
int syscall_name_to_nr(char *name)
{
int i;
if (!syscalls_metadata)
return -1;
for (i = 0; i < NR_syscalls; i++)
if (syscalls_metadata[i])
if (!strcmp(syscalls_metadata[i]->name, name))
return i;
return -1;
}
void set_syscall_enter_id(int num, int id)
{
syscalls_metadata[num]->enter_id = id;
}
void set_syscall_exit_id(int num, int id)
unsigned long __init arch_syscall_addr(int nr)
{
syscalls_metadata[num]->exit_id = id;
}
static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
{
struct syscall_metadata *start;
struct syscall_metadata *stop;
char str[KSYM_SYMBOL_LEN];
start = (struct syscall_metadata *)__start_syscalls_metadata;
stop = (struct syscall_metadata *)__stop_syscalls_metadata;
kallsyms_lookup(syscall, NULL, NULL, NULL, str);
for ( ; start < stop; start++) {
if (start->name && !strcmp(start->name + 3, str + 3))
return start;
}
return NULL;
}
static int __init arch_init_ftrace_syscalls(void)
{
struct syscall_metadata *meta;
int i;
syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls,
GFP_KERNEL);
if (!syscalls_metadata)
return -ENOMEM;
for (i = 0; i < NR_syscalls; i++) {
meta = find_syscall_meta((unsigned long)sys_call_table[i]);
syscalls_metadata[i] = meta;
}
return 0;
return (unsigned long)sys_call_table[nr];
}
arch_initcall(arch_init_ftrace_syscalls);
#endif
......@@ -28,9 +28,20 @@
*/
#define ARCH_PERFMON_EVENT_MASK 0xffff
/*
* filter mask to validate fixed counter events.
* the following filters disqualify for fixed counters:
* - inv
* - edge
* - cnt-mask
* The other filters are supported by fixed counters.
* The any-thread option is supported starting with v3.
*/
#define ARCH_PERFMON_EVENT_FILTER_MASK 0xff840000
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
(1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
......
......@@ -77,6 +77,18 @@ struct cpu_hw_events {
struct debug_store *ds;
};
struct event_constraint {
unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
int code;
};
#define EVENT_CONSTRAINT(c, m) { .code = (c), .idxmsk[0] = (m) }
#define EVENT_CONSTRAINT_END { .code = 0, .idxmsk[0] = 0 }
#define for_each_event_constraint(e, c) \
for ((e) = (c); (e)->idxmsk[0]; (e)++)
/*
* struct x86_pmu - generic x86 pmu
*/
......@@ -102,6 +114,8 @@ struct x86_pmu {
u64 intel_ctrl;
void (*enable_bts)(u64 config);
void (*disable_bts)(void);
int (*get_event_idx)(struct cpu_hw_events *cpuc,
struct hw_perf_event *hwc);
};
static struct x86_pmu x86_pmu __read_mostly;
......@@ -110,6 +124,8 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
.enabled = 1,
};
static const struct event_constraint *event_constraints;
/*
* Not sure about some of these
*/
......@@ -155,6 +171,16 @@ static u64 p6_pmu_raw_event(u64 hw_event)
return hw_event & P6_EVNTSEL_MASK;
}
static const struct event_constraint intel_p6_event_constraints[] =
{
EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */
EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
EVENT_CONSTRAINT(0x11, 0x1), /* FP_ASSIST */
EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
EVENT_CONSTRAINT_END
};
/*
* Intel PerfMon v3. Used on Core2 and later.
......@@ -170,6 +196,35 @@ static const u64 intel_perfmon_event_map[] =
[PERF_COUNT_HW_BUS_CYCLES] = 0x013c,
};
static const struct event_constraint intel_core_event_constraints[] =
{
EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */
EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */
EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */
EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */
EVENT_CONSTRAINT_END
};
static const struct event_constraint intel_nehalem_event_constraints[] =
{
EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */
EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */
EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */
EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */
EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */
EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */
EVENT_CONSTRAINT(0x51, 0x3), /* L1D */
EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */
EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */
EVENT_CONSTRAINT_END
};
static u64 intel_pmu_event_map(int hw_event)
{
return intel_perfmon_event_map[hw_event];
......@@ -469,7 +524,7 @@ static u64 intel_pmu_raw_event(u64 hw_event)
#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL
#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL
#define CORE_EVNTSEL_INV_MASK 0x00800000ULL
#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL
#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL
#define CORE_EVNTSEL_MASK \
(CORE_EVNTSEL_EVENT_MASK | \
......@@ -932,6 +987,8 @@ static int __hw_perf_event_init(struct perf_event *event)
*/
hwc->config = ARCH_PERFMON_EVENTSEL_INT;
hwc->idx = -1;
/*
* Count user and OS events unless requested not to.
*/
......@@ -1334,8 +1391,7 @@ static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx)
x86_pmu_enable_event(hwc, idx);
}
static int
fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
static int fixed_mode_idx(struct hw_perf_event *hwc)
{
unsigned int hw_event;
......@@ -1349,6 +1405,12 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
if (!x86_pmu.num_events_fixed)
return -1;
/*
* fixed counters do not take all possible filters
*/
if (hwc->config & ARCH_PERFMON_EVENT_FILTER_MASK)
return -1;
if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
return X86_PMC_IDX_FIXED_INSTRUCTIONS;
if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES)))
......@@ -1360,22 +1422,57 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
}
/*
* Find a PMC slot for the freshly enabled / scheduled in event:
* generic counter allocator: get next free counter
*/
static int x86_pmu_enable(struct perf_event *event)
static int
gen_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
{
int idx;
idx = find_first_zero_bit(cpuc->used_mask, x86_pmu.num_events);
return idx == x86_pmu.num_events ? -1 : idx;
}
/*
* intel-specific counter allocator: check event constraints
*/
static int
intel_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
{
const struct event_constraint *event_constraint;
int i, code;
if (!event_constraints)
goto skip;
code = hwc->config & CORE_EVNTSEL_EVENT_MASK;
for_each_event_constraint(event_constraint, event_constraints) {
if (code == event_constraint->code) {
for_each_bit(i, event_constraint->idxmsk, X86_PMC_IDX_MAX) {
if (!test_and_set_bit(i, cpuc->used_mask))
return i;
}
return -1;
}
}
skip:
return gen_get_event_idx(cpuc, hwc);
}
static int
x86_schedule_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
struct hw_perf_event *hwc = &event->hw;
int idx;
idx = fixed_mode_idx(event, hwc);
idx = fixed_mode_idx(hwc);
if (idx == X86_PMC_IDX_FIXED_BTS) {
/* BTS is already occupied. */
if (test_and_set_bit(idx, cpuc->used_mask))
return -EAGAIN;
hwc->config_base = 0;
hwc->event_base = 0;
hwc->event_base = 0;
hwc->idx = idx;
} else if (idx >= 0) {
/*
......@@ -1396,20 +1493,35 @@ static int x86_pmu_enable(struct perf_event *event)
} else {
idx = hwc->idx;
/* Try to get the previous generic event again */
if (test_and_set_bit(idx, cpuc->used_mask)) {
if (idx == -1 || test_and_set_bit(idx, cpuc->used_mask)) {
try_generic:
idx = find_first_zero_bit(cpuc->used_mask,
x86_pmu.num_events);
if (idx == x86_pmu.num_events)
idx = x86_pmu.get_event_idx(cpuc, hwc);
if (idx == -1)
return -EAGAIN;
set_bit(idx, cpuc->used_mask);
hwc->idx = idx;
}
hwc->config_base = x86_pmu.eventsel;
hwc->event_base = x86_pmu.perfctr;
hwc->config_base = x86_pmu.eventsel;
hwc->event_base = x86_pmu.perfctr;
}
return idx;
}
/*
* Find a PMC slot for the freshly enabled / scheduled in event:
*/
static int x86_pmu_enable(struct perf_event *event)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
struct hw_perf_event *hwc = &event->hw;
int idx;
idx = x86_schedule_event(cpuc, hwc);
if (idx < 0)
return idx;
perf_events_lapic_init();
x86_pmu.disable(hwc, idx);
......@@ -1877,6 +1989,7 @@ static struct x86_pmu p6_pmu = {
*/
.event_bits = 32,
.event_mask = (1ULL << 32) - 1,
.get_event_idx = intel_get_event_idx,
};
static struct x86_pmu intel_pmu = {
......@@ -1900,6 +2013,7 @@ static struct x86_pmu intel_pmu = {
.max_period = (1ULL << 31) - 1,
.enable_bts = intel_pmu_enable_bts,
.disable_bts = intel_pmu_disable_bts,
.get_event_idx = intel_get_event_idx,
};
static struct x86_pmu amd_pmu = {
......@@ -1920,6 +2034,7 @@ static struct x86_pmu amd_pmu = {
.apic = 1,
/* use highest bit to detect overflow */
.max_period = (1ULL << 47) - 1,
.get_event_idx = gen_get_event_idx,
};
static int p6_pmu_init(void)
......@@ -1932,10 +2047,12 @@ static int p6_pmu_init(void)
case 7:
case 8:
case 11: /* Pentium III */
event_constraints = intel_p6_event_constraints;
break;
case 9:
case 13:
/* Pentium M */
event_constraints = intel_p6_event_constraints;
break;
default:
pr_cont("unsupported p6 CPU model %d ",
......@@ -2007,12 +2124,14 @@ static int intel_pmu_init(void)
sizeof(hw_cache_event_ids));
pr_cont("Core2 events, ");
event_constraints = intel_core_event_constraints;
break;
default:
case 26:
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
event_constraints = intel_nehalem_event_constraints;
pr_cont("Nehalem/Corei7 events, ");
break;
case 28:
......@@ -2105,11 +2224,47 @@ static const struct pmu pmu = {
.unthrottle = x86_pmu_unthrottle,
};
static int
validate_event(struct cpu_hw_events *cpuc, struct perf_event *event)
{
struct hw_perf_event fake_event = event->hw;
if (event->pmu != &pmu)
return 0;
return x86_schedule_event(cpuc, &fake_event);
}
static int validate_group(struct perf_event *event)
{
struct perf_event *sibling, *leader = event->group_leader;
struct cpu_hw_events fake_pmu;
memset(&fake_pmu, 0, sizeof(fake_pmu));
if (!validate_event(&fake_pmu, leader))
return -ENOSPC;
list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
if (!validate_event(&fake_pmu, sibling))
return -ENOSPC;
}
if (!validate_event(&fake_pmu, event))
return -ENOSPC;
return 0;
}
const struct pmu *hw_perf_event_init(struct perf_event *event)
{
int err;
err = __hw_perf_event_init(event);
if (!err) {
if (event->group_leader != event)
err = validate_group(event);
}
if (err) {
if (event->destroy)
event->destroy(event);
......
......@@ -1209,17 +1209,14 @@ END(ftrace_graph_caller)
.globl return_to_handler
return_to_handler:
pushl $0
pushl %eax
pushl %ecx
pushl %edx
movl %ebp, %eax
call ftrace_return_to_handler
movl %eax, 0xc(%esp)
movl %eax, %ecx
popl %edx
popl %ecx
popl %eax
ret
jmp *%ecx
#endif
.section .rodata,"a"
......
......@@ -155,11 +155,11 @@ GLOBAL(return_to_handler)
call ftrace_return_to_handler
movq %rax, 16(%rsp)
movq %rax, %rdi
movq 8(%rsp), %rdx
movq (%rsp), %rax
addq $16, %rsp
retq
addq $24, %rsp
jmp *%rdi
#endif
......
......@@ -9,6 +9,8 @@
* the dangers of modifying code on the run.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/spinlock.h>
#include <linux/hardirq.h>
#include <linux/uaccess.h>
......@@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data)
switch (faulted) {
case 0:
pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n");
pr_info("converting mcount calls to 0f 1f 44 00 00\n");
memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
break;
case 1:
pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n");
pr_info("converting mcount calls to 66 66 66 66 90\n");
memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
break;
case 2:
pr_info("ftrace: converting mcount calls to jmp . + 5\n");
pr_info("converting mcount calls to jmp . + 5\n");
memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
break;
}
......@@ -468,82 +470,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
#ifdef CONFIG_FTRACE_SYSCALLS
extern unsigned long __start_syscalls_metadata[];
extern unsigned long __stop_syscalls_metadata[];
extern unsigned long *sys_call_table;
static struct syscall_metadata **syscalls_metadata;
static struct syscall_metadata *find_syscall_meta(unsigned long *syscall)
{
struct syscall_metadata *start;
struct syscall_metadata *stop;
char str[KSYM_SYMBOL_LEN];
start = (struct syscall_metadata *)__start_syscalls_metadata;
stop = (struct syscall_metadata *)__stop_syscalls_metadata;
kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str);
for ( ; start < stop; start++) {
if (start->name && !strcmp(start->name, str))
return start;
}
return NULL;
}
struct syscall_metadata *syscall_nr_to_meta(int nr)
{
if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
return NULL;
return syscalls_metadata[nr];
}
int syscall_name_to_nr(char *name)
unsigned long __init arch_syscall_addr(int nr)
{
int i;
if (!syscalls_metadata)
return -1;
for (i = 0; i < NR_syscalls; i++) {
if (syscalls_metadata[i]) {
if (!strcmp(syscalls_metadata[i]->name, name))
return i;
}
}
return -1;
}
void set_syscall_enter_id(int num, int id)
{
syscalls_metadata[num]->enter_id = id;
}
void set_syscall_exit_id(int num, int id)
{
syscalls_metadata[num]->exit_id = id;
}
static int __init arch_init_ftrace_syscalls(void)
{
int i;
struct syscall_metadata *meta;
unsigned long **psys_syscall_table = &sys_call_table;
syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
NR_syscalls, GFP_KERNEL);
if (!syscalls_metadata) {
WARN_ON(1);
return -ENOMEM;
}
for (i = 0; i < NR_syscalls; i++) {
meta = find_syscall_meta(psys_syscall_table[i]);
syscalls_metadata[i] = meta;
}
return 0;
return (unsigned long)(&sys_call_table)[nr];
}
arch_initcall(arch_init_ftrace_syscalls);
#endif
/*
* Written by Pekka Paalanen, 2008-2009 <pq@iki.fi>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/io.h>
#include <linux/mmiotrace.h>
#define MODULE_NAME "testmmiotrace"
static unsigned long mmio_address;
module_param(mmio_address, ulong, 0);
MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
......@@ -30,7 +31,7 @@ static unsigned v32(unsigned i)
static void do_write_test(void __iomem *p)
{
unsigned int i;
pr_info(MODULE_NAME ": write test.\n");
pr_info("write test.\n");
mmiotrace_printk("Write test.\n");
for (i = 0; i < 256; i++)
......@@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p)
{
unsigned int i;
unsigned errs[3] = { 0 };
pr_info(MODULE_NAME ": read test.\n");
pr_info("read test.\n");
mmiotrace_printk("Read test.\n");
for (i = 0; i < 256; i++)
......@@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p)
static void do_read_far_test(void __iomem *p)
{
pr_info(MODULE_NAME ": read far test.\n");
pr_info("read far test.\n");
mmiotrace_printk("Read far test.\n");
ioread32(p + read_far);
......@@ -78,7 +79,7 @@ static void do_test(unsigned long size)
{
void __iomem *p = ioremap_nocache(mmio_address, size);
if (!p) {
pr_err(MODULE_NAME ": could not ioremap, aborting.\n");
pr_err("could not ioremap, aborting.\n");
return;
}
mmiotrace_printk("ioremap returned %p.\n", p);
......@@ -94,24 +95,22 @@ static int __init init(void)
unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
if (mmio_address == 0) {
pr_err(MODULE_NAME ": you have to use the module argument "
"mmio_address.\n");
pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS"
" YOU REALLY KNOW WHAT YOU ARE DOING!\n");
pr_err("you have to use the module argument mmio_address.\n");
pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n");
return -ENXIO;
}
pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI "
"address space, and writing 16 kB of rubbish in there.\n",
size >> 10, mmio_address);
pr_warning("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, "
"and writing 16 kB of rubbish in there.\n",
size >> 10, mmio_address);
do_test(size);
pr_info(MODULE_NAME ": All done.\n");
pr_info("All done.\n");
return 0;
}
static void __exit cleanup(void)
{
pr_debug(MODULE_NAME ": unloaded.\n");
pr_debug("unloaded.\n");
}
module_init(init);
......
......@@ -144,7 +144,7 @@ extern char *trace_profile_buf_nmi;
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
extern void destroy_preds(struct ftrace_event_call *call);
extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
extern int filter_match_preds(struct event_filter *filter, void *rec);
extern int filter_current_check_discard(struct ring_buffer *buffer,
struct ftrace_event_call *call,
void *rec,
......@@ -187,4 +187,13 @@ do { \
__trace_printk(ip, fmt, ##args); \
} while (0)
#ifdef CONFIG_EVENT_PROFILE
struct perf_event;
extern int ftrace_profile_enable(int event_id);
extern void ftrace_profile_disable(int event_id);
extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
char *filter_str);
extern void ftrace_profile_free_filter(struct perf_event *event);
#endif
#endif /* _LINUX_FTRACE_EVENT_H */
......@@ -225,6 +225,7 @@ struct perf_counter_attr {
#define PERF_COUNTER_IOC_RESET _IO ('$', 3)
#define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5)
#define PERF_COUNTER_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_counter_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
......
......@@ -221,6 +221,7 @@ struct perf_event_attr {
#define PERF_EVENT_IOC_RESET _IO ('$', 3)
#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
......@@ -633,7 +634,12 @@ struct perf_event {
struct pid_namespace *ns;
u64 id;
#ifdef CONFIG_EVENT_PROFILE
struct event_filter *filter;
#endif
#endif /* CONFIG_PERF_EVENTS */
};
/**
......
......@@ -24,8 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task)
return 0;
}
extern void __lockfunc lock_kernel(void) __acquires(kernel_lock);
extern void __lockfunc unlock_kernel(void) __releases(kernel_lock);
extern void __lockfunc
_lock_kernel(const char *func, const char *file, int line)
__acquires(kernel_lock);
extern void __lockfunc
_unlock_kernel(const char *func, const char *file, int line)
__releases(kernel_lock);
#define lock_kernel() do { \
_lock_kernel(__func__, __FILE__, __LINE__); \
} while (0)
#define unlock_kernel() do { \
_unlock_kernel(__func__, __FILE__, __LINE__); \
} while (0)
/*
* Various legacy drivers don't really need the BKL in a specific
......@@ -41,8 +54,8 @@ static inline void cycle_kernel_lock(void)
#else
#define lock_kernel() do { } while(0)
#define unlock_kernel() do { } while(0)
#define lock_kernel()
#define unlock_kernel()
#define release_kernel_lock(task) do { } while(0)
#define cycle_kernel_lock() do { } while(0)
#define reacquire_kernel_lock(task) 0
......
#undef TRACE_SYSTEM
#define TRACE_SYSTEM bkl
#if !defined(_TRACE_BKL_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_BKL_H
#include <linux/tracepoint.h>
TRACE_EVENT(lock_kernel,
TP_PROTO(const char *func, const char *file, int line),
TP_ARGS(func, file, line),
TP_STRUCT__entry(
__field( int, depth )
__field_ext( const char *, func, FILTER_PTR_STRING )
__field_ext( const char *, file, FILTER_PTR_STRING )
__field( int, line )
),
TP_fast_assign(
/* We want to record the lock_depth after lock is acquired */
__entry->depth = current->lock_depth + 1;
__entry->func = func;
__entry->file = file;
__entry->line = line;
),
TP_printk("depth=%d file:line=%s:%d func=%s()", __entry->depth,
__entry->file, __entry->line, __entry->func)
);
TRACE_EVENT(unlock_kernel,
TP_PROTO(const char *func, const char *file, int line),
TP_ARGS(func, file, line),
TP_STRUCT__entry(
__field(int, depth )
__field(const char *, func )
__field(const char *, file )
__field(int, line )
),
TP_fast_assign(
__entry->depth = current->lock_depth;
__entry->func = func;
__entry->file = file;
__entry->line = line;
),
TP_printk("depth=%d file:line=%s:%d func=%s()", __entry->depth,
__entry->file, __entry->line, __entry->func)
);
#endif /* _TRACE_BKL_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
......@@ -48,7 +48,7 @@ TRACE_EVENT(irq_handler_entry,
__assign_str(name, action->name);
),
TP_printk("irq=%d handler=%s", __entry->irq, __get_str(name))
TP_printk("irq=%d name=%s", __entry->irq, __get_str(name))
);
/**
......@@ -78,7 +78,7 @@ TRACE_EVENT(irq_handler_exit,
__entry->ret = ret;
),
TP_printk("irq=%d return=%s",
TP_printk("irq=%d ret=%s",
__entry->irq, __entry->ret ? "handled" : "unhandled")
);
......@@ -107,7 +107,7 @@ TRACE_EVENT(softirq_entry,
__entry->vec = (int)(h - vec);
),
TP_printk("softirq=%d action=%s", __entry->vec,
TP_printk("vec=%d [action=%s]", __entry->vec,
show_softirq_name(__entry->vec))
);
......@@ -136,7 +136,7 @@ TRACE_EVENT(softirq_exit,
__entry->vec = (int)(h - vec);
),
TP_printk("softirq=%d action=%s", __entry->vec,
TP_printk("vec=%d [action=%s]", __entry->vec,
show_softirq_name(__entry->vec))
);
......
......@@ -16,8 +16,6 @@ enum {
};
#endif
TRACE_EVENT(power_start,
TP_PROTO(unsigned int type, unsigned int state),
......
......@@ -26,7 +26,7 @@ TRACE_EVENT(sched_kthread_stop,
__entry->pid = t->pid;
),
TP_printk("task %s:%d", __entry->comm, __entry->pid)
TP_printk("comm=%s pid=%d", __entry->comm, __entry->pid)
);
/*
......@@ -46,7 +46,7 @@ TRACE_EVENT(sched_kthread_stop_ret,
__entry->ret = ret;
),
TP_printk("ret %d", __entry->ret)
TP_printk("ret=%d", __entry->ret)
);
/*
......@@ -73,7 +73,7 @@ TRACE_EVENT(sched_wait_task,
__entry->prio = p->prio;
),
TP_printk("task %s:%d [%d]",
TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
......@@ -94,7 +94,7 @@ TRACE_EVENT(sched_wakeup,
__field( pid_t, pid )
__field( int, prio )
__field( int, success )
__field( int, cpu )
__field( int, target_cpu )
),
TP_fast_assign(
......@@ -102,12 +102,12 @@ TRACE_EVENT(sched_wakeup,
__entry->pid = p->pid;
__entry->prio = p->prio;
__entry->success = success;
__entry->cpu = task_cpu(p);
__entry->target_cpu = task_cpu(p);
),
TP_printk("task %s:%d [%d] success=%d [%03d]",
TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
__entry->comm, __entry->pid, __entry->prio,
__entry->success, __entry->cpu)
__entry->success, __entry->target_cpu)
);
/*
......@@ -127,7 +127,7 @@ TRACE_EVENT(sched_wakeup_new,
__field( pid_t, pid )
__field( int, prio )
__field( int, success )
__field( int, cpu )
__field( int, target_cpu )
),
TP_fast_assign(
......@@ -135,12 +135,12 @@ TRACE_EVENT(sched_wakeup_new,
__entry->pid = p->pid;
__entry->prio = p->prio;
__entry->success = success;
__entry->cpu = task_cpu(p);
__entry->target_cpu = task_cpu(p);
),
TP_printk("task %s:%d [%d] success=%d [%03d]",
TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
__entry->comm, __entry->pid, __entry->prio,
__entry->success, __entry->cpu)
__entry->success, __entry->target_cpu)
);
/*
......@@ -176,7 +176,7 @@ TRACE_EVENT(sched_switch,
__entry->next_prio = next->prio;
),
TP_printk("task %s:%d [%d] (%s) ==> %s:%d [%d]",
TP_printk("prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s ==> next_comm=%s next_pid=%d next_prio=%d",
__entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
__entry->prev_state ?
__print_flags(__entry->prev_state, "|",
......@@ -211,7 +211,7 @@ TRACE_EVENT(sched_migrate_task,
__entry->dest_cpu = dest_cpu;
),
TP_printk("task %s:%d [%d] from: %d to: %d",
TP_printk("comm=%s pid=%d prio=%d orig_cpu=%d dest_cpu=%d",
__entry->comm, __entry->pid, __entry->prio,
__entry->orig_cpu, __entry->dest_cpu)
);
......@@ -237,7 +237,7 @@ TRACE_EVENT(sched_process_free,
__entry->prio = p->prio;
),
TP_printk("task %s:%d [%d]",
TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
......@@ -262,7 +262,7 @@ TRACE_EVENT(sched_process_exit,
__entry->prio = p->prio;
),
TP_printk("task %s:%d [%d]",
TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
......@@ -287,7 +287,7 @@ TRACE_EVENT(sched_process_wait,
__entry->prio = current->prio;
),
TP_printk("task %s:%d [%d]",
TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
......@@ -314,7 +314,7 @@ TRACE_EVENT(sched_process_fork,
__entry->child_pid = child->pid;
),
TP_printk("parent %s:%d child %s:%d",
TP_printk("comm=%s pid=%d child_comm=%s child_pid=%d",
__entry->parent_comm, __entry->parent_pid,
__entry->child_comm, __entry->child_pid)
);
......@@ -340,7 +340,7 @@ TRACE_EVENT(sched_signal_send,
__entry->sig = sig;
),
TP_printk("sig: %d task %s:%d",
TP_printk("sig=%d comm=%s pid=%d",
__entry->sig, __entry->comm, __entry->pid)
);
......@@ -374,7 +374,7 @@ TRACE_EVENT(sched_stat_wait,
__perf_count(delay);
),
TP_printk("task: %s:%d wait: %Lu [ns]",
TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->delay)
);
......@@ -406,7 +406,7 @@ TRACE_EVENT(sched_stat_runtime,
__perf_count(runtime);
),
TP_printk("task: %s:%d runtime: %Lu [ns], vruntime: %Lu [ns]",
TP_printk("comm=%s pid=%d runtime=%Lu [ns] vruntime=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->runtime,
(unsigned long long)__entry->vruntime)
......@@ -437,7 +437,7 @@ TRACE_EVENT(sched_stat_sleep,
__perf_count(delay);
),
TP_printk("task: %s:%d sleep: %Lu [ns]",
TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->delay)
);
......@@ -467,7 +467,7 @@ TRACE_EVENT(sched_stat_iowait,
__perf_count(delay);
),
TP_printk("task: %s:%d iowait: %Lu [ns]",
TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->delay)
);
......
......@@ -26,7 +26,7 @@ TRACE_EVENT(timer_init,
__entry->timer = timer;
),
TP_printk("timer %p", __entry->timer)
TP_printk("timer=%p", __entry->timer)
);
/**
......@@ -54,7 +54,7 @@ TRACE_EVENT(timer_start,
__entry->now = jiffies;
),
TP_printk("timer %p: func %pf, expires %lu, timeout %ld",
TP_printk("timer=%p function=%pf expires=%lu [timeout=%ld]",
__entry->timer, __entry->function, __entry->expires,
(long)__entry->expires - __entry->now)
);
......@@ -81,7 +81,7 @@ TRACE_EVENT(timer_expire_entry,
__entry->now = jiffies;
),
TP_printk("timer %p: now %lu", __entry->timer, __entry->now)
TP_printk("timer=%p now=%lu", __entry->timer, __entry->now)
);
/**
......@@ -108,7 +108,7 @@ TRACE_EVENT(timer_expire_exit,
__entry->timer = timer;
),
TP_printk("timer %p", __entry->timer)
TP_printk("timer=%p", __entry->timer)
);
/**
......@@ -129,7 +129,7 @@ TRACE_EVENT(timer_cancel,
__entry->timer = timer;
),
TP_printk("timer %p", __entry->timer)
TP_printk("timer=%p", __entry->timer)
);
/**
......@@ -140,24 +140,24 @@ TRACE_EVENT(timer_cancel,
*/
TRACE_EVENT(hrtimer_init,
TP_PROTO(struct hrtimer *timer, clockid_t clockid,
TP_PROTO(struct hrtimer *hrtimer, clockid_t clockid,
enum hrtimer_mode mode),
TP_ARGS(timer, clockid, mode),
TP_ARGS(hrtimer, clockid, mode),
TP_STRUCT__entry(
__field( void *, timer )
__field( void *, hrtimer )
__field( clockid_t, clockid )
__field( enum hrtimer_mode, mode )
),
TP_fast_assign(
__entry->timer = timer;
__entry->hrtimer = hrtimer;
__entry->clockid = clockid;
__entry->mode = mode;
),
TP_printk("hrtimer %p, clockid %s, mode %s", __entry->timer,
TP_printk("hrtimer=%p clockid=%s mode=%s", __entry->hrtimer,
__entry->clockid == CLOCK_REALTIME ?
"CLOCK_REALTIME" : "CLOCK_MONOTONIC",
__entry->mode == HRTIMER_MODE_ABS ?
......@@ -170,26 +170,26 @@ TRACE_EVENT(hrtimer_init,
*/
TRACE_EVENT(hrtimer_start,
TP_PROTO(struct hrtimer *timer),
TP_PROTO(struct hrtimer *hrtimer),
TP_ARGS(timer),
TP_ARGS(hrtimer),
TP_STRUCT__entry(
__field( void *, timer )
__field( void *, hrtimer )
__field( void *, function )
__field( s64, expires )
__field( s64, softexpires )
),
TP_fast_assign(
__entry->timer = timer;
__entry->function = timer->function;
__entry->expires = hrtimer_get_expires(timer).tv64;
__entry->softexpires = hrtimer_get_softexpires(timer).tv64;
__entry->hrtimer = hrtimer;
__entry->function = hrtimer->function;
__entry->expires = hrtimer_get_expires(hrtimer).tv64;
__entry->softexpires = hrtimer_get_softexpires(hrtimer).tv64;
),
TP_printk("hrtimer %p, func %pf, expires %llu, softexpires %llu",
__entry->timer, __entry->function,
TP_printk("hrtimer=%p function=%pf expires=%llu softexpires=%llu",
__entry->hrtimer, __entry->function,
(unsigned long long)ktime_to_ns((ktime_t) {
.tv64 = __entry->expires }),
(unsigned long long)ktime_to_ns((ktime_t) {
......@@ -206,23 +206,22 @@ TRACE_EVENT(hrtimer_start,
*/
TRACE_EVENT(hrtimer_expire_entry,
TP_PROTO(struct hrtimer *timer, ktime_t *now),
TP_PROTO(struct hrtimer *hrtimer, ktime_t *now),
TP_ARGS(timer, now),
TP_ARGS(hrtimer, now),
TP_STRUCT__entry(
__field( void *, timer )
__field( void *, hrtimer )
__field( s64, now )
),
TP_fast_assign(
__entry->timer = timer;
__entry->now = now->tv64;
__entry->hrtimer = hrtimer;
__entry->now = now->tv64;
),
TP_printk("hrtimer %p, now %llu", __entry->timer,
(unsigned long long)ktime_to_ns((ktime_t) {
.tv64 = __entry->now }))
TP_printk("hrtimer=%p now=%llu", __entry->hrtimer,
(unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now }))
);
/**
......@@ -234,40 +233,40 @@ TRACE_EVENT(hrtimer_expire_entry,
*/
TRACE_EVENT(hrtimer_expire_exit,
TP_PROTO(struct hrtimer *timer),
TP_PROTO(struct hrtimer *hrtimer),
TP_ARGS(timer),
TP_ARGS(hrtimer),
TP_STRUCT__entry(
__field( void *, timer )
__field( void *, hrtimer )
),
TP_fast_assign(
__entry->timer = timer;
__entry->hrtimer = hrtimer;
),
TP_printk("hrtimer %p", __entry->timer)
TP_printk("hrtimer=%p", __entry->hrtimer)
);
/**
* hrtimer_cancel - called when the hrtimer is canceled
* @timer: pointer to struct hrtimer
* @hrtimer: pointer to struct hrtimer
*/
TRACE_EVENT(hrtimer_cancel,
TP_PROTO(struct hrtimer *timer),
TP_PROTO(struct hrtimer *hrtimer),
TP_ARGS(timer),
TP_ARGS(hrtimer),
TP_STRUCT__entry(
__field( void *, timer )
__field( void *, hrtimer )
),
TP_fast_assign(
__entry->timer = timer;
__entry->hrtimer = hrtimer;
),
TP_printk("hrtimer %p", __entry->timer)
TP_printk("hrtimer=%p", __entry->hrtimer)
);
/**
......@@ -302,7 +301,7 @@ TRACE_EVENT(itimer_state,
__entry->interval_usec = value->it_interval.tv_usec;
),
TP_printk("which %d, expires %lu, it_value %lu.%lu, it_interval %lu.%lu",
TP_printk("which=%d expires=%lu it_value=%lu.%lu it_interval=%lu.%lu",
__entry->which, __entry->expires,
__entry->value_sec, __entry->value_usec,
__entry->interval_sec, __entry->interval_usec)
......@@ -332,7 +331,7 @@ TRACE_EVENT(itimer_expire,
__entry->pid = pid_nr(pid);
),
TP_printk("which %d, pid %d, now %lu", __entry->which,
TP_printk("which=%d pid=%d now=%lu", __entry->which,
(int) __entry->pid, __entry->now)
);
......
......@@ -120,9 +120,10 @@
#undef __field
#define __field(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
"offset:%u;\tsize:%u;\n", \
"offset:%u;\tsize:%u;\tsigned:%u;\n", \
(unsigned int)offsetof(typeof(field), item), \
(unsigned int)sizeof(field.item)); \
(unsigned int)sizeof(field.item), \
(unsigned int)is_signed_type(type)); \
if (!ret) \
return 0;
......@@ -132,19 +133,21 @@
#undef __array
#define __array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
"offset:%u;\tsize:%u;\n", \
"offset:%u;\tsize:%u;\tsigned:%u;\n", \
(unsigned int)offsetof(typeof(field), item), \
(unsigned int)sizeof(field.item)); \
(unsigned int)sizeof(field.item), \
(unsigned int)is_signed_type(type)); \
if (!ret) \
return 0;
#undef __dynamic_array
#define __dynamic_array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\
"offset:%u;\tsize:%u;\n", \
"offset:%u;\tsize:%u;\tsigned:%u;\n", \
(unsigned int)offsetof(typeof(field), \
__data_loc_##item), \
(unsigned int)sizeof(field.__data_loc_##item)); \
(unsigned int)sizeof(field.__data_loc_##item), \
(unsigned int)is_signed_type(type)); \
if (!ret) \
return 0;
......
......@@ -33,7 +33,7 @@ struct syscall_metadata {
};
#ifdef CONFIG_FTRACE_SYSCALLS
extern struct syscall_metadata *syscall_nr_to_meta(int nr);
extern unsigned long arch_syscall_addr(int nr);
extern int syscall_name_to_nr(char *name);
void set_syscall_enter_id(int num, int id);
void set_syscall_exit_id(int num, int id);
......
......@@ -28,6 +28,7 @@
#include <linux/anon_inodes.h>
#include <linux/kernel_stat.h>
#include <linux/perf_event.h>
#include <linux/ftrace_event.h>
#include <asm/irq_regs.h>
......@@ -1355,7 +1356,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
u64 interrupts, freq;
spin_lock(&ctx->lock);
list_for_each_entry(event, &ctx->group_list, group_entry) {
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
if (event->state != PERF_EVENT_STATE_ACTIVE)
continue;
......@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
return ERR_PTR(err);
}
static void perf_event_free_filter(struct perf_event *event);
static void free_event_rcu(struct rcu_head *head)
{
struct perf_event *event;
......@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head)
event = container_of(head, struct perf_event, rcu_head);
if (event->ns)
put_pid_ns(event->ns);
perf_event_free_filter(event);
kfree(event);
}
......@@ -1974,7 +1978,8 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
return ret;
}
int perf_event_set_output(struct perf_event *event, int output_fd);
static int perf_event_set_output(struct perf_event *event, int output_fd);
static int perf_event_set_filter(struct perf_event *event, void __user *arg);
static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
......@@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PERF_EVENT_IOC_SET_OUTPUT:
return perf_event_set_output(event, arg);
case PERF_EVENT_IOC_SET_FILTER:
return perf_event_set_filter(event, (void __user *)arg);
default:
return -ENOTTY;
}
......@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event)
return 1;
}
static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data);
static int perf_swevent_match(struct perf_event *event,
enum perf_type_id type,
u32 event_id, struct pt_regs *regs)
u32 event_id,
struct perf_sample_data *data,
struct pt_regs *regs)
{
if (!perf_swevent_is_counting(event))
return 0;
......@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event,
return 0;
}
if (event->attr.type == PERF_TYPE_TRACEPOINT &&
!perf_tp_event_match(event, data))
return 0;
return 1;
}
......@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,
rcu_read_lock();
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
if (perf_swevent_match(event, type, event_id, regs))
if (perf_swevent_match(event, type, event_id, data, regs))
perf_swevent_add(event, nr, nmi, data, regs);
}
rcu_read_unlock();
......@@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = {
};
#ifdef CONFIG_EVENT_PROFILE
void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size)
{
......@@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
}
EXPORT_SYMBOL_GPL(perf_tp_event);
extern int ftrace_profile_enable(int);
extern void ftrace_profile_disable(int);
static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data)
{
void *record = data->raw->data;
if (likely(!event->filter) || filter_match_preds(event->filter, record))
return 1;
return 0;
}
static void tp_perf_event_destroy(struct perf_event *event)
{
......@@ -4135,12 +4160,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
return &perf_ops_generic;
}
static int perf_event_set_filter(struct perf_event *event, void __user *arg)
{
char *filter_str;
int ret;
if (event->attr.type != PERF_TYPE_TRACEPOINT)
return -EINVAL;
filter_str = strndup_user(arg, PAGE_SIZE);
if (IS_ERR(filter_str))
return PTR_ERR(filter_str);
ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
kfree(filter_str);
return ret;
}
static void perf_event_free_filter(struct perf_event *event)
{
ftrace_profile_free_filter(event);
}
#else
static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data)
{
return 1;
}
static const struct pmu *tp_perf_event_init(struct perf_event *event)
{
return NULL;
}
#endif
static int perf_event_set_filter(struct perf_event *event, void __user *arg)
{
return -ENOENT;
}
static void perf_event_free_filter(struct perf_event *event)
{
}
#endif /* CONFIG_EVENT_PROFILE */
atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
......@@ -4394,7 +4460,7 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
goto out;
}
int perf_event_set_output(struct perf_event *event, int output_fd)
static int perf_event_set_output(struct perf_event *event, int output_fd)
{
struct perf_event *output_event = NULL;
struct file *output_file = NULL;
......
This diff is collapsed.
......@@ -397,18 +397,21 @@ int ring_buffer_print_page_header(struct trace_seq *s)
int ret;
ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
"offset:0;\tsize:%u;\n",
(unsigned int)sizeof(field.time_stamp));
"offset:0;\tsize:%u;\tsigned:%u;\n",
(unsigned int)sizeof(field.time_stamp),
(unsigned int)is_signed_type(u64));
ret = trace_seq_printf(s, "\tfield: local_t commit;\t"
"offset:%u;\tsize:%u;\n",
"offset:%u;\tsize:%u;\tsigned:%u;\n",
(unsigned int)offsetof(typeof(field), commit),
(unsigned int)sizeof(field.commit));
(unsigned int)sizeof(field.commit),
(unsigned int)is_signed_type(long));
ret = trace_seq_printf(s, "\tfield: char data;\t"
"offset:%u;\tsize:%u;\n",
"offset:%u;\tsize:%u;\tsigned:%u;\n",
(unsigned int)offsetof(typeof(field), data),
(unsigned int)BUF_PAGE_SIZE);
(unsigned int)BUF_PAGE_SIZE,
(unsigned int)is_signed_type(char));
return ret;
}
......
......@@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf);
static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;
static char *default_bootup_tracer;
static int __init set_ftrace(char *str)
static int __init set_cmdline_ftrace(char *str)
{
strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
default_bootup_tracer = bootup_tracer_buf;
......@@ -137,7 +137,7 @@ static int __init set_ftrace(char *str)
ring_buffer_expanded = 1;
return 1;
}
__setup("ftrace=", set_ftrace);
__setup("ftrace=", set_cmdline_ftrace);
static int __init set_ftrace_dump_on_oops(char *str)
{
......
......@@ -506,10 +506,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
return 0;
}
#else
static inline int ftrace_trace_addr(unsigned long addr)
{
return 1;
}
static inline int ftrace_graph_addr(unsigned long addr)
{
return 1;
......@@ -523,12 +519,12 @@ print_graph_function(struct trace_iterator *iter)
}
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
extern struct pid *ftrace_pid_trace;
extern struct list_head ftrace_pids;
#ifdef CONFIG_FUNCTION_TRACER
static inline int ftrace_trace_task(struct task_struct *task)
{
if (!ftrace_pid_trace)
if (list_empty(&ftrace_pids))
return 1;
return test_tsk_trace_trace(task);
......@@ -710,7 +706,6 @@ struct event_filter {
int n_preds;
struct filter_pred **preds;
char *filter_string;
bool no_reset;
};
struct event_subsystem {
......@@ -722,22 +717,40 @@ struct event_subsystem {
};
struct filter_pred;
struct regex;
typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
int val1, int val2);
typedef int (*regex_match_func)(char *str, struct regex *r, int len);
enum regex_type {
MATCH_FULL = 0,
MATCH_FRONT_ONLY,
MATCH_MIDDLE_ONLY,
MATCH_END_ONLY,
};
struct regex {
char pattern[MAX_FILTER_STR_VAL];
int len;
int field_len;
regex_match_func match;
};
struct filter_pred {
filter_pred_fn_t fn;
u64 val;
char str_val[MAX_FILTER_STR_VAL];
int str_len;
char *field_name;
int offset;
int not;
int op;
int pop_n;
filter_pred_fn_t fn;
u64 val;
struct regex regex;
char *field_name;
int offset;
int not;
int op;
int pop_n;
};
extern enum regex_type
filter_parse_regex(char *buff, int len, char **search, int *not);
extern void print_event_filter(struct ftrace_event_call *call,
struct trace_seq *s);
extern int apply_event_filter(struct ftrace_event_call *call,
......@@ -753,7 +766,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
struct ring_buffer *buffer,
struct ring_buffer_event *event)
{
if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) {
if (unlikely(call->filter_active) &&
!filter_match_preds(call->filter, rec)) {
ring_buffer_discard_commit(buffer, event);
return 1;
}
......
......@@ -503,7 +503,7 @@ extern char *__bad_type_size(void);
#define FIELD(type, name) \
sizeof(type) != sizeof(field.name) ? __bad_type_size() : \
#type, "common_" #name, offsetof(typeof(field), name), \
sizeof(field.name)
sizeof(field.name), is_signed_type(type)
static int trace_write_header(struct trace_seq *s)
{
......@@ -511,17 +511,17 @@ static int trace_write_header(struct trace_seq *s)
/* struct trace_entry */
return trace_seq_printf(s,
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
"\n",
FIELD(unsigned short, type),
FIELD(unsigned char, flags),
FIELD(unsigned char, preempt_count),
FIELD(int, pid),
FIELD(int, lock_depth));
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
"\n",
FIELD(unsigned short, type),
FIELD(unsigned char, flags),
FIELD(unsigned char, preempt_count),
FIELD(int, pid),
FIELD(int, lock_depth));
}
static ssize_t
......@@ -874,9 +874,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
"'%s/filter' entry\n", name);
}
entry = trace_create_file("enable", 0644, system->entry,
(void *)system->name,
&ftrace_system_enable_fops);
trace_create_file("enable", 0644, system->entry,
(void *)system->name,
&ftrace_system_enable_fops);
return system->entry;
}
......@@ -888,7 +888,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
const struct file_operations *filter,
const struct file_operations *format)
{
struct dentry *entry;
int ret;
/*
......@@ -906,12 +905,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
}
if (call->regfunc)
entry = trace_create_file("enable", 0644, call->dir, call,
enable);
trace_create_file("enable", 0644, call->dir, call,
enable);
if (call->id && call->profile_enable)
entry = trace_create_file("id", 0444, call->dir, call,
id);
trace_create_file("id", 0444, call->dir, call,
id);
if (call->define_fields) {
ret = call->define_fields(call);
......@@ -920,16 +919,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
" events/%s\n", call->name);
return ret;
}
entry = trace_create_file("filter", 0644, call->dir, call,
filter);
trace_create_file("filter", 0644, call->dir, call,
filter);
}
/* A trace may not want to export its format */
if (!call->show_format)
return 0;
entry = trace_create_file("format", 0444, call->dir, call,
format);
trace_create_file("format", 0444, call->dir, call,
format);
return 0;
}
......
This diff is collapsed.
......@@ -66,44 +66,47 @@ static void __used ____ftrace_check_##name(void) \
#undef __field
#define __field(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
"offset:%zu;\tsize:%zu;\n", \
"offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
offsetof(typeof(field), item), \
sizeof(field.item)); \
sizeof(field.item), is_signed_type(type)); \
if (!ret) \
return 0;
#undef __field_desc
#define __field_desc(type, container, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
"offset:%zu;\tsize:%zu;\n", \
"offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
offsetof(typeof(field), container.item), \
sizeof(field.container.item)); \
sizeof(field.container.item), \
is_signed_type(type)); \
if (!ret) \
return 0;
#undef __array
#define __array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
"offset:%zu;\tsize:%zu;\n", \
offsetof(typeof(field), item), \
sizeof(field.item)); \
"offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
offsetof(typeof(field), item), \
sizeof(field.item), is_signed_type(type)); \
if (!ret) \
return 0;
#undef __array_desc
#define __array_desc(type, container, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
"offset:%zu;\tsize:%zu;\n", \
"offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
offsetof(typeof(field), container.item), \
sizeof(field.container.item)); \
sizeof(field.container.item), \
is_signed_type(type)); \
if (!ret) \
return 0;
#undef __dynamic_array
#define __dynamic_array(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
"offset:%zu;\tsize:0;\n", \
offsetof(typeof(field), item)); \
"offset:%zu;\tsize:0;\tsigned:%u;\n", \
offsetof(typeof(field), item), \
is_signed_type(type)); \
if (!ret) \
return 0;
......
......@@ -14,6 +14,69 @@ static int sys_refcount_exit;
static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
extern unsigned long __start_syscalls_metadata[];
extern unsigned long __stop_syscalls_metadata[];
static struct syscall_metadata **syscalls_metadata;
static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
{
struct syscall_metadata *start;
struct syscall_metadata *stop;
char str[KSYM_SYMBOL_LEN];
start = (struct syscall_metadata *)__start_syscalls_metadata;
stop = (struct syscall_metadata *)__stop_syscalls_metadata;
kallsyms_lookup(syscall, NULL, NULL, NULL, str);
for ( ; start < stop; start++) {
/*
* Only compare after the "sys" prefix. Archs that use
* syscall wrappers may have syscalls symbols aliases prefixed
* with "SyS" instead of "sys", leading to an unwanted
* mismatch.
*/
if (start->name && !strcmp(start->name + 3, str + 3))
return start;
}
return NULL;
}
static struct syscall_metadata *syscall_nr_to_meta(int nr)
{
if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
return NULL;
return syscalls_metadata[nr];
}
int syscall_name_to_nr(char *name)
{
int i;
if (!syscalls_metadata)
return -1;
for (i = 0; i < NR_syscalls; i++) {
if (syscalls_metadata[i]) {
if (!strcmp(syscalls_metadata[i]->name, name))
return i;
}
}
return -1;
}
void set_syscall_enter_id(int num, int id)
{
syscalls_metadata[num]->enter_id = id;
}
void set_syscall_exit_id(int num, int id)
{
syscalls_metadata[num]->exit_id = id;
}
enum print_line_t
print_syscall_enter(struct trace_iterator *iter, int flags)
{
......@@ -103,7 +166,8 @@ extern char *__bad_type_size(void);
#define SYSCALL_FIELD(type, name) \
sizeof(type) != sizeof(trace.name) ? \
__bad_type_size() : \
#type, #name, offsetof(typeof(trace), name), sizeof(trace.name)
#type, #name, offsetof(typeof(trace), name), \
sizeof(trace.name), is_signed_type(type)
int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
{
......@@ -120,7 +184,8 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
if (!entry)
return 0;
ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
"\tsigned:%u;\n",
SYSCALL_FIELD(int, nr));
if (!ret)
return 0;
......@@ -130,8 +195,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
entry->args[i]);
if (!ret)
return 0;
ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset,
sizeof(unsigned long));
ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;"
"\tsigned:%u;\n", offset,
sizeof(unsigned long),
is_signed_type(unsigned long));
if (!ret)
return 0;
offset += sizeof(unsigned long);
......@@ -163,8 +230,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
struct syscall_trace_exit trace;
ret = trace_seq_printf(s,
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
"\tsigned:%u;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
"\tsigned:%u;\n",
SYSCALL_FIELD(int, nr),
SYSCALL_FIELD(long, ret));
if (!ret)
......@@ -212,7 +281,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
if (ret)
return ret;
ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0,
ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
FILTER_OTHER);
return ret;
......@@ -375,6 +444,29 @@ struct trace_event event_syscall_exit = {
.trace = print_syscall_exit,
};
int __init init_ftrace_syscalls(void)
{
struct syscall_metadata *meta;
unsigned long addr;
int i;
syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
NR_syscalls, GFP_KERNEL);
if (!syscalls_metadata) {
WARN_ON(1);
return -ENOMEM;
}
for (i = 0; i < NR_syscalls; i++) {
addr = arch_syscall_addr(i);
meta = find_syscall_meta(addr);
syscalls_metadata[i] = meta;
}
return 0;
}
core_initcall(init_ftrace_syscalls);
#ifdef CONFIG_EVENT_PROFILE
static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls);
......
......@@ -5,10 +5,13 @@
* relegated to obsolescence, but used by various less
* important (or lazy) subsystems.
*/
#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/semaphore.h>
#include <linux/smp_lock.h>
#define CREATE_TRACE_POINTS
#include <trace/events/bkl.h>
/*
* The 'big kernel lock'
......@@ -113,21 +116,26 @@ static inline void __unlock_kernel(void)
* This cannot happen asynchronously, so we only need to
* worry about other CPU's.
*/
void __lockfunc lock_kernel(void)
void __lockfunc _lock_kernel(const char *func, const char *file, int line)
{
int depth = current->lock_depth+1;
int depth = current->lock_depth + 1;
trace_lock_kernel(func, file, line);
if (likely(!depth))
__lock_kernel();
current->lock_depth = depth;
}
void __lockfunc unlock_kernel(void)
void __lockfunc _unlock_kernel(const char *func, const char *file, int line)
{
BUG_ON(current->lock_depth < 0);
if (likely(--current->lock_depth < 0))
__unlock_kernel();
trace_unlock_kernel(func, file, line);
}
EXPORT_SYMBOL(lock_kernel);
EXPORT_SYMBOL(unlock_kernel);
EXPORT_SYMBOL(_lock_kernel);
EXPORT_SYMBOL(_unlock_kernel);
......@@ -119,6 +119,7 @@ my %text_sections = (
".sched.text" => 1,
".spinlock.text" => 1,
".irqentry.text" => 1,
".text.unlikely" => 1,
);
$objdump = "objdump" if ((length $objdump) == 0);
......
......@@ -31,9 +31,12 @@ OPTIONS
-w::
--width=::
Select the width of the SVG file (default: 1000)
-p::
-P::
--power-only::
Only output the CPU power section of the diagram
-p::
--process::
Select the processes to display, by name or PID
SEE ALSO
......
......@@ -201,7 +201,14 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
ifeq ("$(origin DEBUG)", "command line")
PERF_DEBUG = $(DEBUG)
endif
ifndef PERF_DEBUG
CFLAGS_OPTIMIZE = -O6
endif
CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
LDFLAGS = -lpthread -lrt -lelf -lm
ALL_CFLAGS = $(CFLAGS)
ALL_LDFLAGS = $(LDFLAGS)
......@@ -329,8 +336,26 @@ LIB_H += ../../include/linux/perf_event.h
LIB_H += ../../include/linux/rbtree.h
LIB_H += ../../include/linux/list.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/ctype.h
LIB_H += util/include/linux/kernel.h
LIB_H += util/include/linux/list.h
LIB_H += util/include/linux/module.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/string.h
LIB_H += util/include/linux/types.h
LIB_H += util/include/asm/asm-offsets.h
LIB_H += util/include/asm/bitops.h
LIB_H += util/include/asm/byteorder.h
LIB_H += util/include/asm/swab.h
LIB_H += util/include/asm/system.h
LIB_H += util/include/asm/uaccess.h
LIB_H += perf.h
LIB_H += util/event.h
LIB_H += util/types.h
LIB_H += util/levenshtein.h
LIB_H += util/parse-options.h
......@@ -344,9 +369,12 @@ LIB_H += util/strlist.h
LIB_H += util/run-command.h
LIB_H += util/sigchain.h
LIB_H += util/symbol.h
LIB_H += util/module.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/data_map.h
LIB_OBJS += util/abspath.o
LIB_OBJS += util/alias.o
......@@ -360,6 +388,9 @@ LIB_OBJS += util/parse-options.o
LIB_OBJS += util/parse-events.o
LIB_OBJS += util/path.o
LIB_OBJS += util/rbtree.o
LIB_OBJS += util/bitmap.o
LIB_OBJS += util/hweight.o
LIB_OBJS += util/find_next_bit.o
LIB_OBJS += util/run-command.o
LIB_OBJS += util/quote.o
LIB_OBJS += util/strbuf.o
......@@ -369,7 +400,6 @@ LIB_OBJS += util/usage.o
LIB_OBJS += util/wrapper.o
LIB_OBJS += util/sigchain.o
LIB_OBJS += util/symbol.o
LIB_OBJS += util/module.o
LIB_OBJS += util/color.o
LIB_OBJS += util/pager.o
LIB_OBJS += util/header.o
......@@ -382,6 +412,9 @@ LIB_OBJS += util/trace-event-parse.o
LIB_OBJS += util/trace-event-read.o
LIB_OBJS += util/trace-event-info.o
LIB_OBJS += util/svghelper.o
LIB_OBJS += util/sort.o
LIB_OBJS += util/hist.o
LIB_OBJS += util/data_map.o
BUILTIN_OBJS += builtin-annotate.o
BUILTIN_OBJS += builtin-help.o
......@@ -424,8 +457,12 @@ ifeq ($(uname_S),Darwin)
PTHREAD_LIBS =
endif
ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]);
endif
ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
endif
ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
......@@ -795,6 +832,19 @@ util/config.o: util/config.c PERF-CFLAGS
util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
$(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing
# from <string.h> that comes from kernel headers wrapping.
KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS
$(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
$(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
$(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
perf-%$X: %.o $(PERFLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
......
This diff is collapsed.
......@@ -17,55 +17,51 @@
#include "util/header.h"
#include "util/event.h"
#include "util/debug.h"
#include "util/trace-event.h"
#include <unistd.h>
#include <sched.h>
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static long default_interval = 100000;
static long default_interval = 0;
static int nr_cpus = 0;
static int nr_cpus = 0;
static unsigned int page_size;
static unsigned int mmap_pages = 128;
static int freq = 0;
static unsigned int mmap_pages = 128;
static int freq = 1000;
static int output;
static const char *output_name = "perf.data";
static int group = 0;
static unsigned int realtime_prio = 0;
static int raw_samples = 0;
static int system_wide = 0;
static int profile_cpu = -1;
static pid_t target_pid = -1;
static pid_t child_pid = -1;
static int inherit = 1;
static int force = 0;
static int append_file = 0;
static int call_graph = 0;
static int inherit_stat = 0;
static int no_samples = 0;
static int sample_address = 0;
static int multiplex = 0;
static int multiplex_fd = -1;
static long samples;
static int group = 0;
static unsigned int realtime_prio = 0;
static int raw_samples = 0;
static int system_wide = 0;
static int profile_cpu = -1;
static pid_t target_pid = -1;
static pid_t child_pid = -1;
static int inherit = 1;
static int force = 0;
static int append_file = 0;
static int call_graph = 0;
static int inherit_stat = 0;
static int no_samples = 0;
static int sample_address = 0;
static int multiplex = 0;
static int multiplex_fd = -1;
static long samples = 0;
static struct timeval last_read;
static struct timeval this_read;
static u64 bytes_written;
static u64 bytes_written = 0;
static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
static int nr_poll;
static int nr_cpu;
static int nr_poll = 0;
static int nr_cpu = 0;
static int file_new = 1;
static int file_new = 1;
struct perf_header *header;
struct perf_header *header = NULL;
struct mmap_data {
int counter;
......@@ -375,9 +371,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
static void create_counter(int counter, int cpu, pid_t pid)
{
char *filter = filters[counter];
struct perf_event_attr *attr = attrs + counter;
struct perf_header_attr *h_attr;
int track = !counter; /* only the first counter needs these */
int ret;
struct {
u64 count;
u64 time_enabled;
......@@ -480,7 +478,6 @@ static void create_counter(int counter, int cpu, pid_t pid)
multiplex_fd = fd[nr_cpu][counter];
if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
int ret;
ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
assert(ret != -1);
......@@ -500,6 +497,16 @@ static void create_counter(int counter, int cpu, pid_t pid)
}
}
if (filter != NULL) {
ret = ioctl(fd[nr_cpu][counter],
PERF_EVENT_IOC_SET_FILTER, filter);
if (ret) {
error("failed to set filter with %d (%s)\n", errno,
strerror(errno));
exit(-1);
}
}
ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
}
......@@ -566,17 +573,17 @@ static int __cmd_record(int argc, const char **argv)
else
header = perf_header__new();
if (raw_samples) {
read_tracing_data(attrs, nr_counters);
perf_header__feat_trace_info(header);
} else {
for (i = 0; i < nr_counters; i++) {
if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
read_tracing_data(attrs, nr_counters);
perf_header__feat_trace_info(header);
break;
}
}
}
atexit(atexit_header);
if (!system_wide) {
......@@ -623,7 +630,7 @@ static int __cmd_record(int argc, const char **argv)
param.sched_priority = realtime_prio;
if (sched_setscheduler(0, SCHED_FIFO, &param)) {
printf("Could not set realtime priority.\n");
pr_err("Could not set realtime priority.\n");
exit(-1);
}
}
......@@ -677,6 +684,8 @@ static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
"event selector. use 'perf list' to list available events",
parse_events),
OPT_CALLBACK(0, "filter", NULL, "filter",
"event filter", parse_filter),
OPT_INTEGER('p', "pid", &target_pid,
"record events on existing pid"),
OPT_INTEGER('r', "realtime", &realtime_prio,
......@@ -731,6 +740,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
}
/*
* User specified count overrides default frequency.
*/
if (default_interval)
freq = 0;
else if (freq) {
default_interval = freq;
} else {
fprintf(stderr, "frequency and count are zero, aborting\n");
exit(EXIT_FAILURE);
}
for (counter = 0; counter < nr_counters; counter++) {
if (attrs[counter].sample_period)
continue;
......
This diff is collapsed.
This diff is collapsed.
......@@ -50,15 +50,17 @@
static struct perf_event_attr default_attrs[] = {
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
};
......@@ -125,6 +127,7 @@ struct stats event_res_stats[MAX_COUNTERS][3];
struct stats runtime_nsecs_stats;
struct stats walltime_nsecs_stats;
struct stats runtime_cycles_stats;
struct stats runtime_branches_stats;
#define MATCH_EVENT(t, c, counter) \
(attrs[counter].type == PERF_TYPE_##t && \
......@@ -235,6 +238,8 @@ static void read_counter(int counter)
update_stats(&runtime_nsecs_stats, count[0]);
if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
update_stats(&runtime_cycles_stats, count[0]);
if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
update_stats(&runtime_branches_stats, count[0]);
}
static int run_perf_stat(int argc __used, const char **argv)
......@@ -352,6 +357,14 @@ static void abs_printout(int counter, double avg)
ratio = avg / total;
fprintf(stderr, " # %10.3f IPC ", ratio);
} else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter)) {
total = avg_stats(&runtime_branches_stats);
if (total)
ratio = avg * 100 / total;
fprintf(stderr, " # %10.3f %% ", ratio);
} else {
total = avg_stats(&runtime_nsecs_stats);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -89,8 +89,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
/*
* Check remaining flags.
*/
if (!prefixcmp(cmd, "--exec-path")) {
cmd += 11;
if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
cmd += strlen(CMD_EXEC_PATH);
if (*cmd == '=')
perf_set_argv_exec_path(cmd + 1);
else {
......@@ -117,8 +117,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
(*argv)++;
(*argc)--;
handled++;
} else if (!prefixcmp(cmd, "--perf-dir=")) {
setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1);
} else if (!prefixcmp(cmd, CMD_PERF_DIR)) {
setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--work-tree")) {
......@@ -131,8 +131,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, "--work-tree=")) {
setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
} else if (!prefixcmp(cmd, CMD_WORK_TREE)) {
setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--debugfs-dir")) {
......@@ -146,8 +146,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, "--debugfs-dir=")) {
strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN);
} else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
debugfs_mntpt[MAXPATHLEN - 1] = '\0';
if (envchanged)
*envchanged = 1;
......
#!/bin/sh
GVF=PERF-VERSION-FILE
DEF_VER=v0.0.1.PERF
DEF_VER=v0.0.2.PERF
LF='
'
......
#ifndef CACHE_H
#define CACHE_H
#ifndef __PERF_CACHE_H
#define __PERF_CACHE_H
#include "util.h"
#include "strbuf.h"
#include "../perf.h"
#define CMD_EXEC_PATH "--exec-path"
#define CMD_PERF_DIR "--perf-dir="
#define CMD_WORK_TREE "--work-tree="
#define CMD_DEBUGFS_DIR "--debugfs-dir="
#define PERF_DIR_ENVIRONMENT "PERF_DIR"
#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
......@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
extern size_t strlcpy(char *dest, const char *src, size_t size);
#endif /* CACHE_H */
#endif /* __PERF_CACHE_H */
......@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
}
node->val_nr = chain->nr - start;
if (!node->val_nr)
printf("Warning: empty node in callchain tree\n");
pr_warning("Warning: empty node in callchain tree\n");
}
static void
......
......@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
int register_callchain_param(struct callchain_param *param);
void append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct symbol **syms);
#endif
#endif /* __PERF_CALLCHAIN_H */
#ifndef COLOR_H
#define COLOR_H
#ifndef __PERF_COLOR_H
#define __PERF_COLOR_H
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
#define COLOR_MAXLEN 24
......@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
const char *get_percent_color(double percent);
#endif /* COLOR_H */
#endif /* __PERF_COLOR_H */
This diff is collapsed.
#ifndef __PERF_DATAMAP_H
#define __PERF_DATAMAP_H
#include "event.h"
#include "header.h"
typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long);
struct perf_file_handler {
event_type_handler_t process_sample_event;
event_type_handler_t process_mmap_event;
event_type_handler_t process_comm_event;
event_type_handler_t process_fork_event;
event_type_handler_t process_exit_event;
event_type_handler_t process_lost_event;
event_type_handler_t process_read_event;
event_type_handler_t process_throttle_event;
event_type_handler_t process_unthrottle_event;
int (*sample_type_check)(u64 sample_type);
unsigned long total_unknown;
};
void register_perf_file_handler(struct perf_file_handler *handler);
int mmap_dispatch_perf_file(struct perf_header **pheader,
const char *input_name,
int force,
int full_paths,
int *cwdlen,
char **cwd);
#endif
......@@ -13,12 +13,12 @@
int verbose = 0;
int dump_trace = 0;
int eprintf(const char *fmt, ...)
int eprintf(int level, const char *fmt, ...)
{
va_list args;
int ret = 0;
if (verbose) {
if (verbose >= level) {
va_start(args, fmt);
ret = vfprintf(stderr, fmt, args);
va_end(args);
......
/* For debugging general purposes */
#ifndef __PERF_DEBUG_H
#define __PERF_DEBUG_H
extern int verbose;
extern int dump_trace;
int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
int eprintf(int level,
const char *fmt, ...) __attribute__((format(printf, 2, 3)));
int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void trace_event(event_t *event);
#endif /* __PERF_DEBUG_H */
This diff is collapsed.
#ifndef PERF_EXEC_CMD_H
#define PERF_EXEC_CMD_H
#ifndef __PERF_EXEC_CMD_H
#define __PERF_EXEC_CMD_H
extern void perf_set_argv_exec_path(const char *exec_path);
extern const char *perf_extract_argv0_path(const char *path);
......@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
extern int execl_perf_cmd(const char *cmd, ...);
extern const char *system_path(const char *path);
#endif /* PERF_EXEC_CMD_H */
#endif /* __PERF_EXEC_CMD_H */
This diff is collapsed.
This diff is collapsed.
#ifndef HELP_H
#define HELP_H
#ifndef __PERF_HELP_H
#define __PERF_HELP_H
struct cmdnames {
size_t alloc;
......@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
void list_commands(const char *title, struct cmdnames *main_cmds,
struct cmdnames *other_cmds);
#endif /* HELP_H */
#endif /* __PERF_HELP_H */
This diff is collapsed.
This diff is collapsed.
#ifndef _PERF_ASM_BITOPS_H_
#define _PERF_ASM_BITOPS_H_
#include <sys/types.h>
#include "../../types.h"
#include <linux/compiler.h>
/* CHECKME: Not sure both always match */
#define BITS_PER_LONG __WORDSIZE
#include "../../../../include/asm-generic/bitops/__fls.h"
#include "../../../../include/asm-generic/bitops/fls.h"
#include "../../../../include/asm-generic/bitops/fls64.h"
#include "../../../../include/asm-generic/bitops/__ffs.h"
#include "../../../../include/asm-generic/bitops/ffz.h"
#include "../../../../include/asm-generic/bitops/hweight.h"
#endif
#include <asm/types.h>
#include "../../../../include/linux/swab.h"
This diff is collapsed.
#include "../../../../include/linux/bitmap.h"
#include "../../../../include/asm-generic/bitops/find.h"
This diff is collapsed.
This diff is collapsed.
#include "../../../../include/linux/ctype.h"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment