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 ...@@ -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 by the set_ftrace_notrace file in the debugfs
tracing directory. 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]= gamecon.map[2|3]=
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad [HW,JOY] Multisystem joystick and NES/SNES/PSX pad
support via parallel port (up to 5 devices per port) 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. ...@@ -213,10 +213,19 @@ If you can't trace NMI functions, then skip this option.
<details to be filled> <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 HAVE_FTRACE_MCOUNT_RECORD
......
...@@ -203,73 +203,10 @@ unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent) ...@@ -203,73 +203,10 @@ unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent)
#ifdef CONFIG_FTRACE_SYSCALLS #ifdef CONFIG_FTRACE_SYSCALLS
extern unsigned long __start_syscalls_metadata[];
extern unsigned long __stop_syscalls_metadata[];
extern unsigned int sys_call_table[]; extern unsigned int sys_call_table[];
static struct syscall_metadata **syscalls_metadata; unsigned long __init arch_syscall_addr(int nr)
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; return (unsigned long)sys_call_table[nr];
}
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;
} }
arch_initcall(arch_init_ftrace_syscalls);
#endif #endif
...@@ -28,9 +28,20 @@ ...@@ -28,9 +28,20 @@
*/ */
#define ARCH_PERFMON_EVENT_MASK 0xffff #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_SEL 0x3c
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) #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 \ #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
(1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
......
...@@ -77,6 +77,18 @@ struct cpu_hw_events { ...@@ -77,6 +77,18 @@ struct cpu_hw_events {
struct debug_store *ds; 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 * struct x86_pmu - generic x86 pmu
*/ */
...@@ -102,6 +114,8 @@ struct x86_pmu { ...@@ -102,6 +114,8 @@ struct x86_pmu {
u64 intel_ctrl; u64 intel_ctrl;
void (*enable_bts)(u64 config); void (*enable_bts)(u64 config);
void (*disable_bts)(void); 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; static struct x86_pmu x86_pmu __read_mostly;
...@@ -110,6 +124,8 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { ...@@ -110,6 +124,8 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
.enabled = 1, .enabled = 1,
}; };
static const struct event_constraint *event_constraints;
/* /*
* Not sure about some of these * Not sure about some of these
*/ */
...@@ -155,6 +171,16 @@ static u64 p6_pmu_raw_event(u64 hw_event) ...@@ -155,6 +171,16 @@ static u64 p6_pmu_raw_event(u64 hw_event)
return hw_event & P6_EVNTSEL_MASK; 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. * Intel PerfMon v3. Used on Core2 and later.
...@@ -170,6 +196,35 @@ static const u64 intel_perfmon_event_map[] = ...@@ -170,6 +196,35 @@ static const u64 intel_perfmon_event_map[] =
[PERF_COUNT_HW_BUS_CYCLES] = 0x013c, [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) static u64 intel_pmu_event_map(int hw_event)
{ {
return intel_perfmon_event_map[hw_event]; return intel_perfmon_event_map[hw_event];
...@@ -469,7 +524,7 @@ static u64 intel_pmu_raw_event(u64 hw_event) ...@@ -469,7 +524,7 @@ static u64 intel_pmu_raw_event(u64 hw_event)
#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL #define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL
#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL #define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL
#define CORE_EVNTSEL_INV_MASK 0x00800000ULL #define CORE_EVNTSEL_INV_MASK 0x00800000ULL
#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL #define CORE_EVNTSEL_REG_MASK 0xFF000000ULL
#define CORE_EVNTSEL_MASK \ #define CORE_EVNTSEL_MASK \
(CORE_EVNTSEL_EVENT_MASK | \ (CORE_EVNTSEL_EVENT_MASK | \
...@@ -932,6 +987,8 @@ static int __hw_perf_event_init(struct perf_event *event) ...@@ -932,6 +987,8 @@ static int __hw_perf_event_init(struct perf_event *event)
*/ */
hwc->config = ARCH_PERFMON_EVENTSEL_INT; hwc->config = ARCH_PERFMON_EVENTSEL_INT;
hwc->idx = -1;
/* /*
* Count user and OS events unless requested not to. * 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) ...@@ -1334,8 +1391,7 @@ static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx)
x86_pmu_enable_event(hwc, idx); x86_pmu_enable_event(hwc, idx);
} }
static int static int fixed_mode_idx(struct hw_perf_event *hwc)
fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
{ {
unsigned int hw_event; unsigned int hw_event;
...@@ -1349,6 +1405,12 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc) ...@@ -1349,6 +1405,12 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
if (!x86_pmu.num_events_fixed) if (!x86_pmu.num_events_fixed)
return -1; 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))) if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
return X86_PMC_IDX_FIXED_INSTRUCTIONS; return X86_PMC_IDX_FIXED_INSTRUCTIONS;
if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES))) 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) ...@@ -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; int idx;
idx = fixed_mode_idx(event, hwc); idx = fixed_mode_idx(hwc);
if (idx == X86_PMC_IDX_FIXED_BTS) { if (idx == X86_PMC_IDX_FIXED_BTS) {
/* BTS is already occupied. */ /* BTS is already occupied. */
if (test_and_set_bit(idx, cpuc->used_mask)) if (test_and_set_bit(idx, cpuc->used_mask))
return -EAGAIN; return -EAGAIN;
hwc->config_base = 0; hwc->config_base = 0;
hwc->event_base = 0; hwc->event_base = 0;
hwc->idx = idx; hwc->idx = idx;
} else if (idx >= 0) { } else if (idx >= 0) {
/* /*
...@@ -1396,20 +1493,35 @@ static int x86_pmu_enable(struct perf_event *event) ...@@ -1396,20 +1493,35 @@ static int x86_pmu_enable(struct perf_event *event)
} else { } else {
idx = hwc->idx; idx = hwc->idx;
/* Try to get the previous generic event again */ /* 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: try_generic:
idx = find_first_zero_bit(cpuc->used_mask, idx = x86_pmu.get_event_idx(cpuc, hwc);
x86_pmu.num_events); if (idx == -1)
if (idx == x86_pmu.num_events)
return -EAGAIN; return -EAGAIN;
set_bit(idx, cpuc->used_mask); set_bit(idx, cpuc->used_mask);
hwc->idx = idx; hwc->idx = idx;
} }
hwc->config_base = x86_pmu.eventsel; hwc->config_base = x86_pmu.eventsel;
hwc->event_base = x86_pmu.perfctr; 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(); perf_events_lapic_init();
x86_pmu.disable(hwc, idx); x86_pmu.disable(hwc, idx);
...@@ -1877,6 +1989,7 @@ static struct x86_pmu p6_pmu = { ...@@ -1877,6 +1989,7 @@ static struct x86_pmu p6_pmu = {
*/ */
.event_bits = 32, .event_bits = 32,
.event_mask = (1ULL << 32) - 1, .event_mask = (1ULL << 32) - 1,
.get_event_idx = intel_get_event_idx,
}; };
static struct x86_pmu intel_pmu = { static struct x86_pmu intel_pmu = {
...@@ -1900,6 +2013,7 @@ static struct x86_pmu intel_pmu = { ...@@ -1900,6 +2013,7 @@ static struct x86_pmu intel_pmu = {
.max_period = (1ULL << 31) - 1, .max_period = (1ULL << 31) - 1,
.enable_bts = intel_pmu_enable_bts, .enable_bts = intel_pmu_enable_bts,
.disable_bts = intel_pmu_disable_bts, .disable_bts = intel_pmu_disable_bts,
.get_event_idx = intel_get_event_idx,
}; };
static struct x86_pmu amd_pmu = { static struct x86_pmu amd_pmu = {
...@@ -1920,6 +2034,7 @@ static struct x86_pmu amd_pmu = { ...@@ -1920,6 +2034,7 @@ static struct x86_pmu amd_pmu = {
.apic = 1, .apic = 1,
/* use highest bit to detect overflow */ /* use highest bit to detect overflow */
.max_period = (1ULL << 47) - 1, .max_period = (1ULL << 47) - 1,
.get_event_idx = gen_get_event_idx,
}; };
static int p6_pmu_init(void) static int p6_pmu_init(void)
...@@ -1932,10 +2047,12 @@ static int p6_pmu_init(void) ...@@ -1932,10 +2047,12 @@ static int p6_pmu_init(void)
case 7: case 7:
case 8: case 8:
case 11: /* Pentium III */ case 11: /* Pentium III */
event_constraints = intel_p6_event_constraints;
break; break;
case 9: case 9:
case 13: case 13:
/* Pentium M */ /* Pentium M */
event_constraints = intel_p6_event_constraints;
break; break;
default: default:
pr_cont("unsupported p6 CPU model %d ", pr_cont("unsupported p6 CPU model %d ",
...@@ -2007,12 +2124,14 @@ static int intel_pmu_init(void) ...@@ -2007,12 +2124,14 @@ static int intel_pmu_init(void)
sizeof(hw_cache_event_ids)); sizeof(hw_cache_event_ids));
pr_cont("Core2 events, "); pr_cont("Core2 events, ");
event_constraints = intel_core_event_constraints;
break; break;
default: default:
case 26: case 26:
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
sizeof(hw_cache_event_ids)); sizeof(hw_cache_event_ids));
event_constraints = intel_nehalem_event_constraints;
pr_cont("Nehalem/Corei7 events, "); pr_cont("Nehalem/Corei7 events, ");
break; break;
case 28: case 28:
...@@ -2105,11 +2224,47 @@ static const struct pmu pmu = { ...@@ -2105,11 +2224,47 @@ static const struct pmu pmu = {
.unthrottle = x86_pmu_unthrottle, .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) const struct pmu *hw_perf_event_init(struct perf_event *event)
{ {
int err; int err;
err = __hw_perf_event_init(event); err = __hw_perf_event_init(event);
if (!err) {
if (event->group_leader != event)
err = validate_group(event);
}
if (err) { if (err) {
if (event->destroy) if (event->destroy)
event->destroy(event); event->destroy(event);
......
...@@ -1209,17 +1209,14 @@ END(ftrace_graph_caller) ...@@ -1209,17 +1209,14 @@ END(ftrace_graph_caller)
.globl return_to_handler .globl return_to_handler
return_to_handler: return_to_handler:
pushl $0
pushl %eax pushl %eax
pushl %ecx
pushl %edx pushl %edx
movl %ebp, %eax movl %ebp, %eax
call ftrace_return_to_handler call ftrace_return_to_handler
movl %eax, 0xc(%esp) movl %eax, %ecx
popl %edx popl %edx
popl %ecx
popl %eax popl %eax
ret jmp *%ecx
#endif #endif
.section .rodata,"a" .section .rodata,"a"
......
...@@ -155,11 +155,11 @@ GLOBAL(return_to_handler) ...@@ -155,11 +155,11 @@ GLOBAL(return_to_handler)
call ftrace_return_to_handler call ftrace_return_to_handler
movq %rax, 16(%rsp) movq %rax, %rdi
movq 8(%rsp), %rdx movq 8(%rsp), %rdx
movq (%rsp), %rax movq (%rsp), %rax
addq $16, %rsp addq $24, %rsp
retq jmp *%rdi
#endif #endif
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* the dangers of modifying code on the run. * the dangers of modifying code on the run.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data) ...@@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data)
switch (faulted) { switch (faulted) {
case 0: 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); memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
break; break;
case 1: 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); memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
break; break;
case 2: 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); memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
break; break;
} }
...@@ -468,82 +470,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ...@@ -468,82 +470,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
#ifdef CONFIG_FTRACE_SYSCALLS #ifdef CONFIG_FTRACE_SYSCALLS
extern unsigned long __start_syscalls_metadata[];
extern unsigned long __stop_syscalls_metadata[];
extern unsigned long *sys_call_table; extern unsigned long *sys_call_table;
static struct syscall_metadata **syscalls_metadata; unsigned long __init arch_syscall_addr(int nr)
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)
{ {
int i; return (unsigned long)(&sys_call_table)[nr];
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;
} }
arch_initcall(arch_init_ftrace_syscalls);
#endif #endif
/* /*
* Written by Pekka Paalanen, 2008-2009 <pq@iki.fi> * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi>
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mmiotrace.h> #include <linux/mmiotrace.h>
#define MODULE_NAME "testmmiotrace"
static unsigned long mmio_address; static unsigned long mmio_address;
module_param(mmio_address, ulong, 0); module_param(mmio_address, ulong, 0);
MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB " MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
...@@ -30,7 +31,7 @@ static unsigned v32(unsigned i) ...@@ -30,7 +31,7 @@ static unsigned v32(unsigned i)
static void do_write_test(void __iomem *p) static void do_write_test(void __iomem *p)
{ {
unsigned int i; unsigned int i;
pr_info(MODULE_NAME ": write test.\n"); pr_info("write test.\n");
mmiotrace_printk("Write test.\n"); mmiotrace_printk("Write test.\n");
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
...@@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p) ...@@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p)
{ {
unsigned int i; unsigned int i;
unsigned errs[3] = { 0 }; unsigned errs[3] = { 0 };
pr_info(MODULE_NAME ": read test.\n"); pr_info("read test.\n");
mmiotrace_printk("Read test.\n"); mmiotrace_printk("Read test.\n");
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
...@@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p) ...@@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p)
static void do_read_far_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"); mmiotrace_printk("Read far test.\n");
ioread32(p + read_far); ioread32(p + read_far);
...@@ -78,7 +79,7 @@ static void do_test(unsigned long size) ...@@ -78,7 +79,7 @@ static void do_test(unsigned long size)
{ {
void __iomem *p = ioremap_nocache(mmio_address, size); void __iomem *p = ioremap_nocache(mmio_address, size);
if (!p) { if (!p) {
pr_err(MODULE_NAME ": could not ioremap, aborting.\n"); pr_err("could not ioremap, aborting.\n");
return; return;
} }
mmiotrace_printk("ioremap returned %p.\n", p); mmiotrace_printk("ioremap returned %p.\n", p);
...@@ -94,24 +95,22 @@ static int __init init(void) ...@@ -94,24 +95,22 @@ static int __init init(void)
unsigned long size = (read_far) ? (8 << 20) : (16 << 10); unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
if (mmio_address == 0) { if (mmio_address == 0) {
pr_err(MODULE_NAME ": you have to use the module argument " pr_err("you have to use the module argument mmio_address.\n");
"mmio_address.\n"); pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n");
pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS"
" YOU REALLY KNOW WHAT YOU ARE DOING!\n");
return -ENXIO; return -ENXIO;
} }
pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI " pr_warning("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, "
"address space, and writing 16 kB of rubbish in there.\n", "and writing 16 kB of rubbish in there.\n",
size >> 10, mmio_address); size >> 10, mmio_address);
do_test(size); do_test(size);
pr_info(MODULE_NAME ": All done.\n"); pr_info("All done.\n");
return 0; return 0;
} }
static void __exit cleanup(void) static void __exit cleanup(void)
{ {
pr_debug(MODULE_NAME ": unloaded.\n"); pr_debug("unloaded.\n");
} }
module_init(init); module_init(init);
......
...@@ -144,7 +144,7 @@ extern char *trace_profile_buf_nmi; ...@@ -144,7 +144,7 @@ extern char *trace_profile_buf_nmi;
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
extern void destroy_preds(struct ftrace_event_call *call); 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, extern int filter_current_check_discard(struct ring_buffer *buffer,
struct ftrace_event_call *call, struct ftrace_event_call *call,
void *rec, void *rec,
...@@ -187,4 +187,13 @@ do { \ ...@@ -187,4 +187,13 @@ do { \
__trace_printk(ip, fmt, ##args); \ __trace_printk(ip, fmt, ##args); \
} while (0) } 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 */ #endif /* _LINUX_FTRACE_EVENT_H */
...@@ -225,6 +225,7 @@ struct perf_counter_attr { ...@@ -225,6 +225,7 @@ struct perf_counter_attr {
#define PERF_COUNTER_IOC_RESET _IO ('$', 3) #define PERF_COUNTER_IOC_RESET _IO ('$', 3)
#define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64) #define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5) #define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5)
#define PERF_COUNTER_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_counter_ioc_flags { enum perf_counter_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0, PERF_IOC_FLAG_GROUP = 1U << 0,
......
...@@ -221,6 +221,7 @@ struct perf_event_attr { ...@@ -221,6 +221,7 @@ struct perf_event_attr {
#define PERF_EVENT_IOC_RESET _IO ('$', 3) #define PERF_EVENT_IOC_RESET _IO ('$', 3)
#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64) #define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) #define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_event_ioc_flags { enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0, PERF_IOC_FLAG_GROUP = 1U << 0,
...@@ -633,7 +634,12 @@ struct perf_event { ...@@ -633,7 +634,12 @@ struct perf_event {
struct pid_namespace *ns; struct pid_namespace *ns;
u64 id; u64 id;
#ifdef CONFIG_EVENT_PROFILE
struct event_filter *filter;
#endif #endif
#endif /* CONFIG_PERF_EVENTS */
}; };
/** /**
......
...@@ -24,8 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task) ...@@ -24,8 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task)
return 0; return 0;
} }
extern void __lockfunc lock_kernel(void) __acquires(kernel_lock); extern void __lockfunc
extern void __lockfunc unlock_kernel(void) __releases(kernel_lock); _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 * Various legacy drivers don't really need the BKL in a specific
...@@ -41,8 +54,8 @@ static inline void cycle_kernel_lock(void) ...@@ -41,8 +54,8 @@ static inline void cycle_kernel_lock(void)
#else #else
#define lock_kernel() do { } while(0) #define lock_kernel()
#define unlock_kernel() do { } while(0) #define unlock_kernel()
#define release_kernel_lock(task) do { } while(0) #define release_kernel_lock(task) do { } while(0)
#define cycle_kernel_lock() do { } while(0) #define cycle_kernel_lock() do { } while(0)
#define reacquire_kernel_lock(task) 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, ...@@ -48,7 +48,7 @@ TRACE_EVENT(irq_handler_entry,
__assign_str(name, action->name); __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, ...@@ -78,7 +78,7 @@ TRACE_EVENT(irq_handler_exit,
__entry->ret = ret; __entry->ret = ret;
), ),
TP_printk("irq=%d return=%s", TP_printk("irq=%d ret=%s",
__entry->irq, __entry->ret ? "handled" : "unhandled") __entry->irq, __entry->ret ? "handled" : "unhandled")
); );
...@@ -107,7 +107,7 @@ TRACE_EVENT(softirq_entry, ...@@ -107,7 +107,7 @@ TRACE_EVENT(softirq_entry,
__entry->vec = (int)(h - vec); __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)) show_softirq_name(__entry->vec))
); );
...@@ -136,7 +136,7 @@ TRACE_EVENT(softirq_exit, ...@@ -136,7 +136,7 @@ TRACE_EVENT(softirq_exit,
__entry->vec = (int)(h - vec); __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)) show_softirq_name(__entry->vec))
); );
......
...@@ -16,8 +16,6 @@ enum { ...@@ -16,8 +16,6 @@ enum {
}; };
#endif #endif
TRACE_EVENT(power_start, TRACE_EVENT(power_start,
TP_PROTO(unsigned int type, unsigned int state), TP_PROTO(unsigned int type, unsigned int state),
......
...@@ -26,7 +26,7 @@ TRACE_EVENT(sched_kthread_stop, ...@@ -26,7 +26,7 @@ TRACE_EVENT(sched_kthread_stop,
__entry->pid = t->pid; __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, ...@@ -46,7 +46,7 @@ TRACE_EVENT(sched_kthread_stop_ret,
__entry->ret = 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, ...@@ -73,7 +73,7 @@ TRACE_EVENT(sched_wait_task,
__entry->prio = p->prio; __entry->prio = p->prio;
), ),
TP_printk("task %s:%d [%d]", TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio) __entry->comm, __entry->pid, __entry->prio)
); );
...@@ -94,7 +94,7 @@ TRACE_EVENT(sched_wakeup, ...@@ -94,7 +94,7 @@ TRACE_EVENT(sched_wakeup,
__field( pid_t, pid ) __field( pid_t, pid )
__field( int, prio ) __field( int, prio )
__field( int, success ) __field( int, success )
__field( int, cpu ) __field( int, target_cpu )
), ),
TP_fast_assign( TP_fast_assign(
...@@ -102,12 +102,12 @@ TRACE_EVENT(sched_wakeup, ...@@ -102,12 +102,12 @@ TRACE_EVENT(sched_wakeup,
__entry->pid = p->pid; __entry->pid = p->pid;
__entry->prio = p->prio; __entry->prio = p->prio;
__entry->success = success; __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->comm, __entry->pid, __entry->prio,
__entry->success, __entry->cpu) __entry->success, __entry->target_cpu)
); );
/* /*
...@@ -127,7 +127,7 @@ TRACE_EVENT(sched_wakeup_new, ...@@ -127,7 +127,7 @@ TRACE_EVENT(sched_wakeup_new,
__field( pid_t, pid ) __field( pid_t, pid )
__field( int, prio ) __field( int, prio )
__field( int, success ) __field( int, success )
__field( int, cpu ) __field( int, target_cpu )
), ),
TP_fast_assign( TP_fast_assign(
...@@ -135,12 +135,12 @@ TRACE_EVENT(sched_wakeup_new, ...@@ -135,12 +135,12 @@ TRACE_EVENT(sched_wakeup_new,
__entry->pid = p->pid; __entry->pid = p->pid;
__entry->prio = p->prio; __entry->prio = p->prio;
__entry->success = success; __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->comm, __entry->pid, __entry->prio,
__entry->success, __entry->cpu) __entry->success, __entry->target_cpu)
); );
/* /*
...@@ -176,7 +176,7 @@ TRACE_EVENT(sched_switch, ...@@ -176,7 +176,7 @@ TRACE_EVENT(sched_switch,
__entry->next_prio = next->prio; __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_comm, __entry->prev_pid, __entry->prev_prio,
__entry->prev_state ? __entry->prev_state ?
__print_flags(__entry->prev_state, "|", __print_flags(__entry->prev_state, "|",
...@@ -211,7 +211,7 @@ TRACE_EVENT(sched_migrate_task, ...@@ -211,7 +211,7 @@ TRACE_EVENT(sched_migrate_task,
__entry->dest_cpu = dest_cpu; __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->comm, __entry->pid, __entry->prio,
__entry->orig_cpu, __entry->dest_cpu) __entry->orig_cpu, __entry->dest_cpu)
); );
...@@ -237,7 +237,7 @@ TRACE_EVENT(sched_process_free, ...@@ -237,7 +237,7 @@ TRACE_EVENT(sched_process_free,
__entry->prio = p->prio; __entry->prio = p->prio;
), ),
TP_printk("task %s:%d [%d]", TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio) __entry->comm, __entry->pid, __entry->prio)
); );
...@@ -262,7 +262,7 @@ TRACE_EVENT(sched_process_exit, ...@@ -262,7 +262,7 @@ TRACE_EVENT(sched_process_exit,
__entry->prio = p->prio; __entry->prio = p->prio;
), ),
TP_printk("task %s:%d [%d]", TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio) __entry->comm, __entry->pid, __entry->prio)
); );
...@@ -287,7 +287,7 @@ TRACE_EVENT(sched_process_wait, ...@@ -287,7 +287,7 @@ TRACE_EVENT(sched_process_wait,
__entry->prio = current->prio; __entry->prio = current->prio;
), ),
TP_printk("task %s:%d [%d]", TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio) __entry->comm, __entry->pid, __entry->prio)
); );
...@@ -314,7 +314,7 @@ TRACE_EVENT(sched_process_fork, ...@@ -314,7 +314,7 @@ TRACE_EVENT(sched_process_fork,
__entry->child_pid = child->pid; __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->parent_comm, __entry->parent_pid,
__entry->child_comm, __entry->child_pid) __entry->child_comm, __entry->child_pid)
); );
...@@ -340,7 +340,7 @@ TRACE_EVENT(sched_signal_send, ...@@ -340,7 +340,7 @@ TRACE_EVENT(sched_signal_send,
__entry->sig = sig; __entry->sig = sig;
), ),
TP_printk("sig: %d task %s:%d", TP_printk("sig=%d comm=%s pid=%d",
__entry->sig, __entry->comm, __entry->pid) __entry->sig, __entry->comm, __entry->pid)
); );
...@@ -374,7 +374,7 @@ TRACE_EVENT(sched_stat_wait, ...@@ -374,7 +374,7 @@ TRACE_EVENT(sched_stat_wait,
__perf_count(delay); __perf_count(delay);
), ),
TP_printk("task: %s:%d wait: %Lu [ns]", TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid, __entry->comm, __entry->pid,
(unsigned long long)__entry->delay) (unsigned long long)__entry->delay)
); );
...@@ -406,7 +406,7 @@ TRACE_EVENT(sched_stat_runtime, ...@@ -406,7 +406,7 @@ TRACE_EVENT(sched_stat_runtime,
__perf_count(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, __entry->comm, __entry->pid,
(unsigned long long)__entry->runtime, (unsigned long long)__entry->runtime,
(unsigned long long)__entry->vruntime) (unsigned long long)__entry->vruntime)
...@@ -437,7 +437,7 @@ TRACE_EVENT(sched_stat_sleep, ...@@ -437,7 +437,7 @@ TRACE_EVENT(sched_stat_sleep,
__perf_count(delay); __perf_count(delay);
), ),
TP_printk("task: %s:%d sleep: %Lu [ns]", TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid, __entry->comm, __entry->pid,
(unsigned long long)__entry->delay) (unsigned long long)__entry->delay)
); );
...@@ -467,7 +467,7 @@ TRACE_EVENT(sched_stat_iowait, ...@@ -467,7 +467,7 @@ TRACE_EVENT(sched_stat_iowait,
__perf_count(delay); __perf_count(delay);
), ),
TP_printk("task: %s:%d iowait: %Lu [ns]", TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid, __entry->comm, __entry->pid,
(unsigned long long)__entry->delay) (unsigned long long)__entry->delay)
); );
......
...@@ -26,7 +26,7 @@ TRACE_EVENT(timer_init, ...@@ -26,7 +26,7 @@ TRACE_EVENT(timer_init,
__entry->timer = timer; __entry->timer = timer;
), ),
TP_printk("timer %p", __entry->timer) TP_printk("timer=%p", __entry->timer)
); );
/** /**
...@@ -54,7 +54,7 @@ TRACE_EVENT(timer_start, ...@@ -54,7 +54,7 @@ TRACE_EVENT(timer_start,
__entry->now = jiffies; __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, __entry->timer, __entry->function, __entry->expires,
(long)__entry->expires - __entry->now) (long)__entry->expires - __entry->now)
); );
...@@ -81,7 +81,7 @@ TRACE_EVENT(timer_expire_entry, ...@@ -81,7 +81,7 @@ TRACE_EVENT(timer_expire_entry,
__entry->now = jiffies; __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, ...@@ -108,7 +108,7 @@ TRACE_EVENT(timer_expire_exit,
__entry->timer = timer; __entry->timer = timer;
), ),
TP_printk("timer %p", __entry->timer) TP_printk("timer=%p", __entry->timer)
); );
/** /**
...@@ -129,7 +129,7 @@ TRACE_EVENT(timer_cancel, ...@@ -129,7 +129,7 @@ TRACE_EVENT(timer_cancel,
__entry->timer = timer; __entry->timer = timer;
), ),
TP_printk("timer %p", __entry->timer) TP_printk("timer=%p", __entry->timer)
); );
/** /**
...@@ -140,24 +140,24 @@ TRACE_EVENT(timer_cancel, ...@@ -140,24 +140,24 @@ TRACE_EVENT(timer_cancel,
*/ */
TRACE_EVENT(hrtimer_init, TRACE_EVENT(hrtimer_init,
TP_PROTO(struct hrtimer *timer, clockid_t clockid, TP_PROTO(struct hrtimer *hrtimer, clockid_t clockid,
enum hrtimer_mode mode), enum hrtimer_mode mode),
TP_ARGS(timer, clockid, mode), TP_ARGS(hrtimer, clockid, mode),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( void *, timer ) __field( void *, hrtimer )
__field( clockid_t, clockid ) __field( clockid_t, clockid )
__field( enum hrtimer_mode, mode ) __field( enum hrtimer_mode, mode )
), ),
TP_fast_assign( TP_fast_assign(
__entry->timer = timer; __entry->hrtimer = hrtimer;
__entry->clockid = clockid; __entry->clockid = clockid;
__entry->mode = mode; __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 ? __entry->clockid == CLOCK_REALTIME ?
"CLOCK_REALTIME" : "CLOCK_MONOTONIC", "CLOCK_REALTIME" : "CLOCK_MONOTONIC",
__entry->mode == HRTIMER_MODE_ABS ? __entry->mode == HRTIMER_MODE_ABS ?
...@@ -170,26 +170,26 @@ TRACE_EVENT(hrtimer_init, ...@@ -170,26 +170,26 @@ TRACE_EVENT(hrtimer_init,
*/ */
TRACE_EVENT(hrtimer_start, TRACE_EVENT(hrtimer_start,
TP_PROTO(struct hrtimer *timer), TP_PROTO(struct hrtimer *hrtimer),
TP_ARGS(timer), TP_ARGS(hrtimer),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( void *, timer ) __field( void *, hrtimer )
__field( void *, function ) __field( void *, function )
__field( s64, expires ) __field( s64, expires )
__field( s64, softexpires ) __field( s64, softexpires )
), ),
TP_fast_assign( TP_fast_assign(
__entry->timer = timer; __entry->hrtimer = hrtimer;
__entry->function = timer->function; __entry->function = hrtimer->function;
__entry->expires = hrtimer_get_expires(timer).tv64; __entry->expires = hrtimer_get_expires(hrtimer).tv64;
__entry->softexpires = hrtimer_get_softexpires(timer).tv64; __entry->softexpires = hrtimer_get_softexpires(hrtimer).tv64;
), ),
TP_printk("hrtimer %p, func %pf, expires %llu, softexpires %llu", TP_printk("hrtimer=%p function=%pf expires=%llu softexpires=%llu",
__entry->timer, __entry->function, __entry->hrtimer, __entry->function,
(unsigned long long)ktime_to_ns((ktime_t) { (unsigned long long)ktime_to_ns((ktime_t) {
.tv64 = __entry->expires }), .tv64 = __entry->expires }),
(unsigned long long)ktime_to_ns((ktime_t) { (unsigned long long)ktime_to_ns((ktime_t) {
...@@ -206,23 +206,22 @@ TRACE_EVENT(hrtimer_start, ...@@ -206,23 +206,22 @@ TRACE_EVENT(hrtimer_start,
*/ */
TRACE_EVENT(hrtimer_expire_entry, 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( TP_STRUCT__entry(
__field( void *, timer ) __field( void *, hrtimer )
__field( s64, now ) __field( s64, now )
), ),
TP_fast_assign( TP_fast_assign(
__entry->timer = timer; __entry->hrtimer = hrtimer;
__entry->now = now->tv64; __entry->now = now->tv64;
), ),
TP_printk("hrtimer %p, now %llu", __entry->timer, TP_printk("hrtimer=%p now=%llu", __entry->hrtimer,
(unsigned long long)ktime_to_ns((ktime_t) { (unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now }))
.tv64 = __entry->now }))
); );
/** /**
...@@ -234,40 +233,40 @@ TRACE_EVENT(hrtimer_expire_entry, ...@@ -234,40 +233,40 @@ TRACE_EVENT(hrtimer_expire_entry,
*/ */
TRACE_EVENT(hrtimer_expire_exit, TRACE_EVENT(hrtimer_expire_exit,
TP_PROTO(struct hrtimer *timer), TP_PROTO(struct hrtimer *hrtimer),
TP_ARGS(timer), TP_ARGS(hrtimer),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( void *, timer ) __field( void *, hrtimer )
), ),
TP_fast_assign( 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 * hrtimer_cancel - called when the hrtimer is canceled
* @timer: pointer to struct hrtimer * @hrtimer: pointer to struct hrtimer
*/ */
TRACE_EVENT(hrtimer_cancel, TRACE_EVENT(hrtimer_cancel,
TP_PROTO(struct hrtimer *timer), TP_PROTO(struct hrtimer *hrtimer),
TP_ARGS(timer), TP_ARGS(hrtimer),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( void *, timer ) __field( void *, hrtimer )
), ),
TP_fast_assign( 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, ...@@ -302,7 +301,7 @@ TRACE_EVENT(itimer_state,
__entry->interval_usec = value->it_interval.tv_usec; __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->which, __entry->expires,
__entry->value_sec, __entry->value_usec, __entry->value_sec, __entry->value_usec,
__entry->interval_sec, __entry->interval_usec) __entry->interval_sec, __entry->interval_usec)
...@@ -332,7 +331,7 @@ TRACE_EVENT(itimer_expire, ...@@ -332,7 +331,7 @@ TRACE_EVENT(itimer_expire,
__entry->pid = pid_nr(pid); __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) (int) __entry->pid, __entry->now)
); );
......
...@@ -120,9 +120,10 @@ ...@@ -120,9 +120,10 @@
#undef __field #undef __field
#define __field(type, item) \ #define __field(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ 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)offsetof(typeof(field), item), \
(unsigned int)sizeof(field.item)); \ (unsigned int)sizeof(field.item), \
(unsigned int)is_signed_type(type)); \
if (!ret) \ if (!ret) \
return 0; return 0;
...@@ -132,19 +133,21 @@ ...@@ -132,19 +133,21 @@
#undef __array #undef __array
#define __array(type, item, len) \ #define __array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ 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)offsetof(typeof(field), item), \
(unsigned int)sizeof(field.item)); \ (unsigned int)sizeof(field.item), \
(unsigned int)is_signed_type(type)); \
if (!ret) \ if (!ret) \
return 0; return 0;
#undef __dynamic_array #undef __dynamic_array
#define __dynamic_array(type, item, len) \ #define __dynamic_array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\ 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), \ (unsigned int)offsetof(typeof(field), \
__data_loc_##item), \ __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) \ if (!ret) \
return 0; return 0;
......
...@@ -33,7 +33,7 @@ struct syscall_metadata { ...@@ -33,7 +33,7 @@ struct syscall_metadata {
}; };
#ifdef CONFIG_FTRACE_SYSCALLS #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); extern int syscall_name_to_nr(char *name);
void set_syscall_enter_id(int num, int id); void set_syscall_enter_id(int num, int id);
void set_syscall_exit_id(int num, int id); void set_syscall_exit_id(int num, int id);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/anon_inodes.h> #include <linux/anon_inodes.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/ftrace_event.h>
#include <asm/irq_regs.h> #include <asm/irq_regs.h>
...@@ -1355,7 +1356,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx) ...@@ -1355,7 +1356,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
u64 interrupts, freq; u64 interrupts, freq;
spin_lock(&ctx->lock); 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) if (event->state != PERF_EVENT_STATE_ACTIVE)
continue; continue;
...@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu) ...@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
return ERR_PTR(err); return ERR_PTR(err);
} }
static void perf_event_free_filter(struct perf_event *event);
static void free_event_rcu(struct rcu_head *head) static void free_event_rcu(struct rcu_head *head)
{ {
struct perf_event *event; struct perf_event *event;
...@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head) ...@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head)
event = container_of(head, struct perf_event, rcu_head); event = container_of(head, struct perf_event, rcu_head);
if (event->ns) if (event->ns)
put_pid_ns(event->ns); put_pid_ns(event->ns);
perf_event_free_filter(event);
kfree(event); kfree(event);
} }
...@@ -1974,7 +1978,8 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg) ...@@ -1974,7 +1978,8 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
return ret; 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) 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) ...@@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PERF_EVENT_IOC_SET_OUTPUT: case PERF_EVENT_IOC_SET_OUTPUT:
return perf_event_set_output(event, arg); return perf_event_set_output(event, arg);
case PERF_EVENT_IOC_SET_FILTER:
return perf_event_set_filter(event, (void __user *)arg);
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event) ...@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event)
return 1; 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, static int perf_swevent_match(struct perf_event *event,
enum perf_type_id type, 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)) if (!perf_swevent_is_counting(event))
return 0; return 0;
...@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event, ...@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event,
return 0; return 0;
} }
if (event->attr.type == PERF_TYPE_TRACEPOINT &&
!perf_tp_event_match(event, data))
return 0;
return 1; return 1;
} }
...@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx, ...@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { 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); perf_swevent_add(event, nr, nmi, data, regs);
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = { ...@@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = {
}; };
#ifdef CONFIG_EVENT_PROFILE #ifdef CONFIG_EVENT_PROFILE
void perf_tp_event(int event_id, u64 addr, u64 count, void *record, void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size) int entry_size)
{ {
...@@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, ...@@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
} }
EXPORT_SYMBOL_GPL(perf_tp_event); EXPORT_SYMBOL_GPL(perf_tp_event);
extern int ftrace_profile_enable(int); static int perf_tp_event_match(struct perf_event *event,
extern void ftrace_profile_disable(int); 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) 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) ...@@ -4135,12 +4160,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
return &perf_ops_generic; 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 #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) static const struct pmu *tp_perf_event_init(struct perf_event *event)
{ {
return NULL; 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]; atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
...@@ -4394,7 +4460,7 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, ...@@ -4394,7 +4460,7 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
goto out; 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 perf_event *output_event = NULL;
struct file *output_file = NULL; struct file *output_file = NULL;
......
This diff is collapsed.
...@@ -397,18 +397,21 @@ int ring_buffer_print_page_header(struct trace_seq *s) ...@@ -397,18 +397,21 @@ int ring_buffer_print_page_header(struct trace_seq *s)
int ret; int ret;
ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t" ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
"offset:0;\tsize:%u;\n", "offset:0;\tsize:%u;\tsigned:%u;\n",
(unsigned int)sizeof(field.time_stamp)); (unsigned int)sizeof(field.time_stamp),
(unsigned int)is_signed_type(u64));
ret = trace_seq_printf(s, "\tfield: local_t commit;\t" 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)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" 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)offsetof(typeof(field), data),
(unsigned int)BUF_PAGE_SIZE); (unsigned int)BUF_PAGE_SIZE,
(unsigned int)is_signed_type(char));
return ret; return ret;
} }
......
...@@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf); ...@@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf);
static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;
static char *default_bootup_tracer; 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); strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
default_bootup_tracer = bootup_tracer_buf; default_bootup_tracer = bootup_tracer_buf;
...@@ -137,7 +137,7 @@ static int __init set_ftrace(char *str) ...@@ -137,7 +137,7 @@ static int __init set_ftrace(char *str)
ring_buffer_expanded = 1; ring_buffer_expanded = 1;
return 1; return 1;
} }
__setup("ftrace=", set_ftrace); __setup("ftrace=", set_cmdline_ftrace);
static int __init set_ftrace_dump_on_oops(char *str) static int __init set_ftrace_dump_on_oops(char *str)
{ {
......
...@@ -506,10 +506,6 @@ static inline int ftrace_graph_addr(unsigned long addr) ...@@ -506,10 +506,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
return 0; return 0;
} }
#else #else
static inline int ftrace_trace_addr(unsigned long addr)
{
return 1;
}
static inline int ftrace_graph_addr(unsigned long addr) static inline int ftrace_graph_addr(unsigned long addr)
{ {
return 1; return 1;
...@@ -523,12 +519,12 @@ print_graph_function(struct trace_iterator *iter) ...@@ -523,12 +519,12 @@ print_graph_function(struct trace_iterator *iter)
} }
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
extern struct pid *ftrace_pid_trace; extern struct list_head ftrace_pids;
#ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_FUNCTION_TRACER
static inline int ftrace_trace_task(struct task_struct *task) static inline int ftrace_trace_task(struct task_struct *task)
{ {
if (!ftrace_pid_trace) if (list_empty(&ftrace_pids))
return 1; return 1;
return test_tsk_trace_trace(task); return test_tsk_trace_trace(task);
...@@ -710,7 +706,6 @@ struct event_filter { ...@@ -710,7 +706,6 @@ struct event_filter {
int n_preds; int n_preds;
struct filter_pred **preds; struct filter_pred **preds;
char *filter_string; char *filter_string;
bool no_reset;
}; };
struct event_subsystem { struct event_subsystem {
...@@ -722,22 +717,40 @@ struct event_subsystem { ...@@ -722,22 +717,40 @@ struct event_subsystem {
}; };
struct filter_pred; struct filter_pred;
struct regex;
typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
int val1, int val2); 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 { struct filter_pred {
filter_pred_fn_t fn; filter_pred_fn_t fn;
u64 val; u64 val;
char str_val[MAX_FILTER_STR_VAL]; struct regex regex;
int str_len; char *field_name;
char *field_name; int offset;
int offset; int not;
int not; int op;
int op; int pop_n;
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, extern void print_event_filter(struct ftrace_event_call *call,
struct trace_seq *s); struct trace_seq *s);
extern int apply_event_filter(struct ftrace_event_call *call, extern int apply_event_filter(struct ftrace_event_call *call,
...@@ -753,7 +766,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec, ...@@ -753,7 +766,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
struct ring_buffer *buffer, struct ring_buffer *buffer,
struct ring_buffer_event *event) 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); ring_buffer_discard_commit(buffer, event);
return 1; return 1;
} }
......
...@@ -503,7 +503,7 @@ extern char *__bad_type_size(void); ...@@ -503,7 +503,7 @@ extern char *__bad_type_size(void);
#define FIELD(type, name) \ #define FIELD(type, name) \
sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ sizeof(type) != sizeof(field.name) ? __bad_type_size() : \
#type, "common_" #name, offsetof(typeof(field), name), \ #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) static int trace_write_header(struct trace_seq *s)
{ {
...@@ -511,17 +511,17 @@ 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 */ /* struct trace_entry */
return trace_seq_printf(s, return trace_seq_printf(s,
"\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;\n" "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\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;\n" "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
"\n", "\n",
FIELD(unsigned short, type), FIELD(unsigned short, type),
FIELD(unsigned char, flags), FIELD(unsigned char, flags),
FIELD(unsigned char, preempt_count), FIELD(unsigned char, preempt_count),
FIELD(int, pid), FIELD(int, pid),
FIELD(int, lock_depth)); FIELD(int, lock_depth));
} }
static ssize_t static ssize_t
...@@ -874,9 +874,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) ...@@ -874,9 +874,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
"'%s/filter' entry\n", name); "'%s/filter' entry\n", name);
} }
entry = trace_create_file("enable", 0644, system->entry, trace_create_file("enable", 0644, system->entry,
(void *)system->name, (void *)system->name,
&ftrace_system_enable_fops); &ftrace_system_enable_fops);
return system->entry; return system->entry;
} }
...@@ -888,7 +888,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, ...@@ -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 *filter,
const struct file_operations *format) const struct file_operations *format)
{ {
struct dentry *entry;
int ret; int ret;
/* /*
...@@ -906,12 +905,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, ...@@ -906,12 +905,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
} }
if (call->regfunc) if (call->regfunc)
entry = trace_create_file("enable", 0644, call->dir, call, trace_create_file("enable", 0644, call->dir, call,
enable); enable);
if (call->id && call->profile_enable) if (call->id && call->profile_enable)
entry = trace_create_file("id", 0444, call->dir, call, trace_create_file("id", 0444, call->dir, call,
id); id);
if (call->define_fields) { if (call->define_fields) {
ret = call->define_fields(call); ret = call->define_fields(call);
...@@ -920,16 +919,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, ...@@ -920,16 +919,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
" events/%s\n", call->name); " events/%s\n", call->name);
return ret; return ret;
} }
entry = trace_create_file("filter", 0644, call->dir, call, trace_create_file("filter", 0644, call->dir, call,
filter); filter);
} }
/* A trace may not want to export its format */ /* A trace may not want to export its format */
if (!call->show_format) if (!call->show_format)
return 0; return 0;
entry = trace_create_file("format", 0444, call->dir, call, trace_create_file("format", 0444, call->dir, call,
format); format);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -66,44 +66,47 @@ static void __used ____ftrace_check_##name(void) \ ...@@ -66,44 +66,47 @@ static void __used ____ftrace_check_##name(void) \
#undef __field #undef __field
#define __field(type, item) \ #define __field(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ 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), \ offsetof(typeof(field), item), \
sizeof(field.item)); \ sizeof(field.item), is_signed_type(type)); \
if (!ret) \ if (!ret) \
return 0; return 0;
#undef __field_desc #undef __field_desc
#define __field_desc(type, container, item) \ #define __field_desc(type, container, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ 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), \ offsetof(typeof(field), container.item), \
sizeof(field.container.item)); \ sizeof(field.container.item), \
is_signed_type(type)); \
if (!ret) \ if (!ret) \
return 0; return 0;
#undef __array #undef __array
#define __array(type, item, len) \ #define __array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ 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), item), \ offsetof(typeof(field), item), \
sizeof(field.item)); \ sizeof(field.item), is_signed_type(type)); \
if (!ret) \ if (!ret) \
return 0; return 0;
#undef __array_desc #undef __array_desc
#define __array_desc(type, container, item, len) \ #define __array_desc(type, container, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ 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), \ offsetof(typeof(field), container.item), \
sizeof(field.container.item)); \ sizeof(field.container.item), \
is_signed_type(type)); \
if (!ret) \ if (!ret) \
return 0; return 0;
#undef __dynamic_array #undef __dynamic_array
#define __dynamic_array(type, item) \ #define __dynamic_array(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
"offset:%zu;\tsize:0;\n", \ "offset:%zu;\tsize:0;\tsigned:%u;\n", \
offsetof(typeof(field), item)); \ offsetof(typeof(field), item), \
is_signed_type(type)); \
if (!ret) \ if (!ret) \
return 0; return 0;
......
...@@ -14,6 +14,69 @@ static int sys_refcount_exit; ...@@ -14,6 +14,69 @@ static int sys_refcount_exit;
static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
static DECLARE_BITMAP(enabled_exit_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 enum print_line_t
print_syscall_enter(struct trace_iterator *iter, int flags) print_syscall_enter(struct trace_iterator *iter, int flags)
{ {
...@@ -103,7 +166,8 @@ extern char *__bad_type_size(void); ...@@ -103,7 +166,8 @@ extern char *__bad_type_size(void);
#define SYSCALL_FIELD(type, name) \ #define SYSCALL_FIELD(type, name) \
sizeof(type) != sizeof(trace.name) ? \ sizeof(type) != sizeof(trace.name) ? \
__bad_type_size() : \ __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) 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) ...@@ -120,7 +184,8 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
if (!entry) if (!entry)
return 0; 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)); SYSCALL_FIELD(int, nr));
if (!ret) if (!ret)
return 0; return 0;
...@@ -130,8 +195,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) ...@@ -130,8 +195,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
entry->args[i]); entry->args[i]);
if (!ret) if (!ret)
return 0; return 0;
ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset, ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;"
sizeof(unsigned long)); "\tsigned:%u;\n", offset,
sizeof(unsigned long),
is_signed_type(unsigned long));
if (!ret) if (!ret)
return 0; return 0;
offset += sizeof(unsigned long); offset += sizeof(unsigned long);
...@@ -163,8 +230,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) ...@@ -163,8 +230,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
struct syscall_trace_exit trace; struct syscall_trace_exit trace;
ret = trace_seq_printf(s, ret = trace_seq_printf(s,
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", "\tsigned:%u;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
"\tsigned:%u;\n",
SYSCALL_FIELD(int, nr), SYSCALL_FIELD(int, nr),
SYSCALL_FIELD(long, ret)); SYSCALL_FIELD(long, ret));
if (!ret) if (!ret)
...@@ -212,7 +281,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call) ...@@ -212,7 +281,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
if (ret) if (ret)
return ret; return ret;
ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0, ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
FILTER_OTHER); FILTER_OTHER);
return ret; return ret;
...@@ -375,6 +444,29 @@ struct trace_event event_syscall_exit = { ...@@ -375,6 +444,29 @@ struct trace_event event_syscall_exit = {
.trace = print_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 #ifdef CONFIG_EVENT_PROFILE
static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls);
......
...@@ -5,10 +5,13 @@ ...@@ -5,10 +5,13 @@
* relegated to obsolescence, but used by various less * relegated to obsolescence, but used by various less
* important (or lazy) subsystems. * important (or lazy) subsystems.
*/ */
#include <linux/smp_lock.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
#include <linux/smp_lock.h>
#define CREATE_TRACE_POINTS
#include <trace/events/bkl.h>
/* /*
* The 'big kernel lock' * The 'big kernel lock'
...@@ -113,21 +116,26 @@ static inline void __unlock_kernel(void) ...@@ -113,21 +116,26 @@ static inline void __unlock_kernel(void)
* This cannot happen asynchronously, so we only need to * This cannot happen asynchronously, so we only need to
* worry about other CPU's. * 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)) if (likely(!depth))
__lock_kernel(); __lock_kernel();
current->lock_depth = depth; 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); BUG_ON(current->lock_depth < 0);
if (likely(--current->lock_depth < 0)) if (likely(--current->lock_depth < 0))
__unlock_kernel(); __unlock_kernel();
trace_unlock_kernel(func, file, line);
} }
EXPORT_SYMBOL(lock_kernel); EXPORT_SYMBOL(_lock_kernel);
EXPORT_SYMBOL(unlock_kernel); EXPORT_SYMBOL(_unlock_kernel);
...@@ -119,6 +119,7 @@ my %text_sections = ( ...@@ -119,6 +119,7 @@ my %text_sections = (
".sched.text" => 1, ".sched.text" => 1,
".spinlock.text" => 1, ".spinlock.text" => 1,
".irqentry.text" => 1, ".irqentry.text" => 1,
".text.unlikely" => 1,
); );
$objdump = "objdump" if ((length $objdump) == 0); $objdump = "objdump" if ((length $objdump) == 0);
......
...@@ -31,9 +31,12 @@ OPTIONS ...@@ -31,9 +31,12 @@ OPTIONS
-w:: -w::
--width=:: --width=::
Select the width of the SVG file (default: 1000) Select the width of the SVG file (default: 1000)
-p:: -P::
--power-only:: --power-only::
Only output the CPU power section of the diagram Only output the CPU power section of the diagram
-p::
--process::
Select the processes to display, by name or PID
SEE ALSO SEE ALSO
......
...@@ -201,7 +201,14 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition ...@@ -201,7 +201,14 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement 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 LDFLAGS = -lpthread -lrt -lelf -lm
ALL_CFLAGS = $(CFLAGS) ALL_CFLAGS = $(CFLAGS)
ALL_LDFLAGS = $(LDFLAGS) ALL_LDFLAGS = $(LDFLAGS)
...@@ -329,8 +336,26 @@ LIB_H += ../../include/linux/perf_event.h ...@@ -329,8 +336,26 @@ LIB_H += ../../include/linux/perf_event.h
LIB_H += ../../include/linux/rbtree.h LIB_H += ../../include/linux/rbtree.h
LIB_H += ../../include/linux/list.h LIB_H += ../../include/linux/list.h
LIB_H += ../../include/linux/stringify.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/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 += perf.h
LIB_H += util/event.h
LIB_H += util/types.h LIB_H += util/types.h
LIB_H += util/levenshtein.h LIB_H += util/levenshtein.h
LIB_H += util/parse-options.h LIB_H += util/parse-options.h
...@@ -344,9 +369,12 @@ LIB_H += util/strlist.h ...@@ -344,9 +369,12 @@ LIB_H += util/strlist.h
LIB_H += util/run-command.h LIB_H += util/run-command.h
LIB_H += util/sigchain.h LIB_H += util/sigchain.h
LIB_H += util/symbol.h LIB_H += util/symbol.h
LIB_H += util/module.h
LIB_H += util/color.h LIB_H += util/color.h
LIB_H += util/values.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/abspath.o
LIB_OBJS += util/alias.o LIB_OBJS += util/alias.o
...@@ -360,6 +388,9 @@ LIB_OBJS += util/parse-options.o ...@@ -360,6 +388,9 @@ LIB_OBJS += util/parse-options.o
LIB_OBJS += util/parse-events.o LIB_OBJS += util/parse-events.o
LIB_OBJS += util/path.o LIB_OBJS += util/path.o
LIB_OBJS += util/rbtree.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/run-command.o
LIB_OBJS += util/quote.o LIB_OBJS += util/quote.o
LIB_OBJS += util/strbuf.o LIB_OBJS += util/strbuf.o
...@@ -369,7 +400,6 @@ LIB_OBJS += util/usage.o ...@@ -369,7 +400,6 @@ LIB_OBJS += util/usage.o
LIB_OBJS += util/wrapper.o LIB_OBJS += util/wrapper.o
LIB_OBJS += util/sigchain.o LIB_OBJS += util/sigchain.o
LIB_OBJS += util/symbol.o LIB_OBJS += util/symbol.o
LIB_OBJS += util/module.o
LIB_OBJS += util/color.o LIB_OBJS += util/color.o
LIB_OBJS += util/pager.o LIB_OBJS += util/pager.o
LIB_OBJS += util/header.o LIB_OBJS += util/header.o
...@@ -382,6 +412,9 @@ LIB_OBJS += util/trace-event-parse.o ...@@ -382,6 +412,9 @@ LIB_OBJS += util/trace-event-parse.o
LIB_OBJS += util/trace-event-read.o LIB_OBJS += util/trace-event-read.o
LIB_OBJS += util/trace-event-info.o LIB_OBJS += util/trace-event-info.o
LIB_OBJS += util/svghelper.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-annotate.o
BUILTIN_OBJS += builtin-help.o BUILTIN_OBJS += builtin-help.o
...@@ -424,8 +457,12 @@ ifeq ($(uname_S),Darwin) ...@@ -424,8 +457,12 @@ ifeq ($(uname_S),Darwin)
PTHREAD_LIBS = PTHREAD_LIBS =
endif 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) 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 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) 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 ...@@ -795,6 +832,19 @@ util/config.o: util/config.c PERF-CFLAGS
util/rbtree.o: ../../lib/rbtree.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)"' $< $(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) perf-%$X: %.o $(PERFLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
......
This diff is collapsed.
...@@ -17,55 +17,51 @@ ...@@ -17,55 +17,51 @@
#include "util/header.h" #include "util/header.h"
#include "util/event.h" #include "util/event.h"
#include "util/debug.h" #include "util/debug.h"
#include "util/trace-event.h"
#include <unistd.h> #include <unistd.h>
#include <sched.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 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 page_size;
static unsigned int mmap_pages = 128; static unsigned int mmap_pages = 128;
static int freq = 0; static int freq = 1000;
static int output; static int output;
static const char *output_name = "perf.data"; static const char *output_name = "perf.data";
static int group = 0; static int group = 0;
static unsigned int realtime_prio = 0; static unsigned int realtime_prio = 0;
static int raw_samples = 0; static int raw_samples = 0;
static int system_wide = 0; static int system_wide = 0;
static int profile_cpu = -1; static int profile_cpu = -1;
static pid_t target_pid = -1; static pid_t target_pid = -1;
static pid_t child_pid = -1; static pid_t child_pid = -1;
static int inherit = 1; static int inherit = 1;
static int force = 0; static int force = 0;
static int append_file = 0; static int append_file = 0;
static int call_graph = 0; static int call_graph = 0;
static int inherit_stat = 0; static int inherit_stat = 0;
static int no_samples = 0; static int no_samples = 0;
static int sample_address = 0; static int sample_address = 0;
static int multiplex = 0; static int multiplex = 0;
static int multiplex_fd = -1; static int multiplex_fd = -1;
static long samples; static long samples = 0;
static struct timeval last_read; static struct timeval last_read;
static struct timeval this_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 struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
static int nr_poll; static int nr_poll = 0;
static int nr_cpu; 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 { struct mmap_data {
int counter; int counter;
...@@ -375,9 +371,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n ...@@ -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) static void create_counter(int counter, int cpu, pid_t pid)
{ {
char *filter = filters[counter];
struct perf_event_attr *attr = attrs + counter; struct perf_event_attr *attr = attrs + counter;
struct perf_header_attr *h_attr; struct perf_header_attr *h_attr;
int track = !counter; /* only the first counter needs these */ int track = !counter; /* only the first counter needs these */
int ret;
struct { struct {
u64 count; u64 count;
u64 time_enabled; u64 time_enabled;
...@@ -480,7 +478,6 @@ static void create_counter(int counter, int cpu, pid_t pid) ...@@ -480,7 +478,6 @@ static void create_counter(int counter, int cpu, pid_t pid)
multiplex_fd = fd[nr_cpu][counter]; multiplex_fd = fd[nr_cpu][counter];
if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
int ret;
ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
assert(ret != -1); assert(ret != -1);
...@@ -500,6 +497,16 @@ static void create_counter(int counter, int cpu, pid_t pid) ...@@ -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); ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
} }
...@@ -566,17 +573,17 @@ static int __cmd_record(int argc, const char **argv) ...@@ -566,17 +573,17 @@ static int __cmd_record(int argc, const char **argv)
else else
header = perf_header__new(); header = perf_header__new();
if (raw_samples) { if (raw_samples) {
read_tracing_data(attrs, nr_counters); perf_header__feat_trace_info(header);
} else { } else {
for (i = 0; i < nr_counters; i++) { for (i = 0; i < nr_counters; i++) {
if (attrs[i].sample_type & PERF_SAMPLE_RAW) { if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
read_tracing_data(attrs, nr_counters); perf_header__feat_trace_info(header);
break; break;
} }
} }
} }
atexit(atexit_header); atexit(atexit_header);
if (!system_wide) { if (!system_wide) {
...@@ -623,7 +630,7 @@ static int __cmd_record(int argc, const char **argv) ...@@ -623,7 +630,7 @@ static int __cmd_record(int argc, const char **argv)
param.sched_priority = realtime_prio; param.sched_priority = realtime_prio;
if (sched_setscheduler(0, SCHED_FIFO, &param)) { if (sched_setscheduler(0, SCHED_FIFO, &param)) {
printf("Could not set realtime priority.\n"); pr_err("Could not set realtime priority.\n");
exit(-1); exit(-1);
} }
} }
...@@ -677,6 +684,8 @@ static const struct option options[] = { ...@@ -677,6 +684,8 @@ static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event", OPT_CALLBACK('e', "event", NULL, "event",
"event selector. use 'perf list' to list available events", "event selector. use 'perf list' to list available events",
parse_events), parse_events),
OPT_CALLBACK(0, "filter", NULL, "filter",
"event filter", parse_filter),
OPT_INTEGER('p', "pid", &target_pid, OPT_INTEGER('p', "pid", &target_pid,
"record events on existing pid"), "record events on existing pid"),
OPT_INTEGER('r', "realtime", &realtime_prio, OPT_INTEGER('r', "realtime", &realtime_prio,
...@@ -731,6 +740,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) ...@@ -731,6 +740,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 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++) { for (counter = 0; counter < nr_counters; counter++) {
if (attrs[counter].sample_period) if (attrs[counter].sample_period)
continue; continue;
......
This diff is collapsed.
This diff is collapsed.
...@@ -50,15 +50,17 @@ ...@@ -50,15 +50,17 @@
static struct perf_event_attr default_attrs[] = { 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_TASK_CLOCK },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, { .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_CPU_MIGRATIONS },
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, { .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_CPU_CYCLES },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, { .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_BRANCH_INSTRUCTIONS },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, { .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]; ...@@ -125,6 +127,7 @@ struct stats event_res_stats[MAX_COUNTERS][3];
struct stats runtime_nsecs_stats; struct stats runtime_nsecs_stats;
struct stats walltime_nsecs_stats; struct stats walltime_nsecs_stats;
struct stats runtime_cycles_stats; struct stats runtime_cycles_stats;
struct stats runtime_branches_stats;
#define MATCH_EVENT(t, c, counter) \ #define MATCH_EVENT(t, c, counter) \
(attrs[counter].type == PERF_TYPE_##t && \ (attrs[counter].type == PERF_TYPE_##t && \
...@@ -235,6 +238,8 @@ static void read_counter(int counter) ...@@ -235,6 +238,8 @@ static void read_counter(int counter)
update_stats(&runtime_nsecs_stats, count[0]); update_stats(&runtime_nsecs_stats, count[0]);
if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
update_stats(&runtime_cycles_stats, count[0]); 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) static int run_perf_stat(int argc __used, const char **argv)
...@@ -352,6 +357,14 @@ static void abs_printout(int counter, double avg) ...@@ -352,6 +357,14 @@ static void abs_printout(int counter, double avg)
ratio = avg / total; ratio = avg / total;
fprintf(stderr, " # %10.3f IPC ", ratio); 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 { } else {
total = avg_stats(&runtime_nsecs_stats); 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) ...@@ -89,8 +89,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
/* /*
* Check remaining flags. * Check remaining flags.
*/ */
if (!prefixcmp(cmd, "--exec-path")) { if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
cmd += 11; cmd += strlen(CMD_EXEC_PATH);
if (*cmd == '=') if (*cmd == '=')
perf_set_argv_exec_path(cmd + 1); perf_set_argv_exec_path(cmd + 1);
else { else {
...@@ -117,8 +117,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) ...@@ -117,8 +117,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
(*argv)++; (*argv)++;
(*argc)--; (*argc)--;
handled++; handled++;
} else if (!prefixcmp(cmd, "--perf-dir=")) { } else if (!prefixcmp(cmd, CMD_PERF_DIR)) {
setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1); setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1);
if (envchanged) if (envchanged)
*envchanged = 1; *envchanged = 1;
} else if (!strcmp(cmd, "--work-tree")) { } else if (!strcmp(cmd, "--work-tree")) {
...@@ -131,8 +131,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) ...@@ -131,8 +131,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
*envchanged = 1; *envchanged = 1;
(*argv)++; (*argv)++;
(*argc)--; (*argc)--;
} else if (!prefixcmp(cmd, "--work-tree=")) { } else if (!prefixcmp(cmd, CMD_WORK_TREE)) {
setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1);
if (envchanged) if (envchanged)
*envchanged = 1; *envchanged = 1;
} else if (!strcmp(cmd, "--debugfs-dir")) { } else if (!strcmp(cmd, "--debugfs-dir")) {
...@@ -146,8 +146,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) ...@@ -146,8 +146,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
*envchanged = 1; *envchanged = 1;
(*argv)++; (*argv)++;
(*argc)--; (*argc)--;
} else if (!prefixcmp(cmd, "--debugfs-dir=")) { } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN); strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
debugfs_mntpt[MAXPATHLEN - 1] = '\0'; debugfs_mntpt[MAXPATHLEN - 1] = '\0';
if (envchanged) if (envchanged)
*envchanged = 1; *envchanged = 1;
......
#!/bin/sh #!/bin/sh
GVF=PERF-VERSION-FILE GVF=PERF-VERSION-FILE
DEF_VER=v0.0.1.PERF DEF_VER=v0.0.2.PERF
LF=' LF='
' '
......
#ifndef CACHE_H #ifndef __PERF_CACHE_H
#define CACHE_H #define __PERF_CACHE_H
#include "util.h" #include "util.h"
#include "strbuf.h" #include "strbuf.h"
#include "../perf.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_DIR_ENVIRONMENT "PERF_DIR"
#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
...@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...) ...@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
extern size_t strlcpy(char *dest, const char *src, size_t size); 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, ...@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
} }
node->val_nr = chain->nr - start; node->val_nr = chain->nr - start;
if (!node->val_nr) if (!node->val_nr)
printf("Warning: empty node in callchain tree\n"); pr_warning("Warning: empty node in callchain tree\n");
} }
static void static void
......
...@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node) ...@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
int register_callchain_param(struct callchain_param *param); int register_callchain_param(struct callchain_param *param);
void append_chain(struct callchain_node *root, struct ip_callchain *chain, void append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct symbol **syms); struct symbol **syms);
#endif #endif /* __PERF_CALLCHAIN_H */
#ifndef COLOR_H #ifndef __PERF_COLOR_H
#define COLOR_H #define __PERF_COLOR_H
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
#define COLOR_MAXLEN 24 #define COLOR_MAXLEN 24
...@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu ...@@ -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); int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
const char *get_percent_color(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 @@ ...@@ -13,12 +13,12 @@
int verbose = 0; int verbose = 0;
int dump_trace = 0; int dump_trace = 0;
int eprintf(const char *fmt, ...) int eprintf(int level, const char *fmt, ...)
{ {
va_list args; va_list args;
int ret = 0; int ret = 0;
if (verbose) { if (verbose >= level) {
va_start(args, fmt); va_start(args, fmt);
ret = vfprintf(stderr, fmt, args); ret = vfprintf(stderr, fmt, args);
va_end(args); va_end(args);
......
/* For debugging general purposes */ /* For debugging general purposes */
#ifndef __PERF_DEBUG_H
#define __PERF_DEBUG_H
extern int verbose; extern int verbose;
extern int dump_trace; 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))); int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void trace_event(event_t *event); void trace_event(event_t *event);
#endif /* __PERF_DEBUG_H */
This diff is collapsed.
#ifndef PERF_EXEC_CMD_H #ifndef __PERF_EXEC_CMD_H
#define PERF_EXEC_CMD_H #define __PERF_EXEC_CMD_H
extern void perf_set_argv_exec_path(const char *exec_path); extern void perf_set_argv_exec_path(const char *exec_path);
extern const char *perf_extract_argv0_path(const char *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 */ ...@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
extern int execl_perf_cmd(const char *cmd, ...); extern int execl_perf_cmd(const char *cmd, ...);
extern const char *system_path(const char *path); 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 #ifndef __PERF_HELP_H
#define HELP_H #define __PERF_HELP_H
struct cmdnames { struct cmdnames {
size_t alloc; size_t alloc;
...@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s); ...@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
void list_commands(const char *title, struct cmdnames *main_cmds, void list_commands(const char *title, struct cmdnames *main_cmds,
struct cmdnames *other_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