Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 191086
b: refs/heads/master
c: 0308635
h: refs/heads/master
v: v3
  • Loading branch information
Ingo Molnar committed Mar 12, 2010
1 parent c6fa34b commit a010ea0
Show file tree
Hide file tree
Showing 45 changed files with 837 additions and 260 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0b861225a5890f22445f08ca9cc7a87cff276ff7
refs/heads/master: 0308635917273030db6121d67c41ef2279b30340
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ static void power_pmu_setup(int cpu)
}

static int __cpuinit
power_pmu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;

Expand Down
25 changes: 16 additions & 9 deletions trunk/arch/x86/kernel/cpu/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,6 @@ void hw_perf_enable(void)
* step2: reprogram moved events into new counters
*/
for (i = 0; i < n_running; i++) {

event = cpuc->event_list[i];
hwc = &event->hw;

Expand All @@ -813,21 +812,16 @@ void hw_perf_enable(void)
continue;

x86_pmu_stop(event);

hwc->idx = -1;
}

for (i = 0; i < cpuc->n_events; i++) {

event = cpuc->event_list[i];
hwc = &event->hw;

if (i < n_running &&
match_prev_assignment(hwc, cpuc, i))
continue;

if (hwc->idx == -1)
if (!match_prev_assignment(hwc, cpuc, i))
x86_assign_hw_event(event, cpuc, i);
else if (i < n_running)
continue;

x86_pmu_start(event);
}
Expand Down Expand Up @@ -1700,3 +1694,16 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)

return entry;
}

void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
{
regs->ip = ip;
/*
* perf_arch_fetch_caller_regs adds another call, we need to increment
* the skip level
*/
regs->bp = rewind_frame_pointer(skip + 1);
regs->cs = __KERNEL_CS;
local_save_flags(regs->flags);
}
EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
15 changes: 15 additions & 0 deletions trunk/arch/x86/kernel/dumpstack.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,19 @@ struct stack_frame {
struct stack_frame *next_frame;
unsigned long return_address;
};

static inline unsigned long rewind_frame_pointer(int n)
{
struct stack_frame *frame;

get_bp(frame);

#ifdef CONFIG_FRAME_POINTER
while (n--)
frame = frame->next_frame;
#endif

return (unsigned long)frame;
}

#endif /* DUMPSTACK_H */
4 changes: 2 additions & 2 deletions trunk/arch/x86/kernel/dumpstack_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
if (ops->stack(data, "IRQ") < 0)
break;
bp = print_context_stack(tinfo, stack, bp,
bp = ops->walk_stack(tinfo, stack, bp,
ops, data, irq_stack_end, &graph);
/*
* We link to the next stack (which would be
Expand All @@ -229,7 +229,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
/*
* This handles the process stack:
*/
bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph);
bp = ops->walk_stack(tinfo, stack, bp, ops, data, NULL, &graph);
put_cpu();
}
EXPORT_SYMBOL(dump_trace);
Expand Down
23 changes: 13 additions & 10 deletions trunk/include/linux/ftrace_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,12 @@ struct ftrace_event_call {
void *mod;
void *data;

int profile_count;
int (*profile_enable)(struct ftrace_event_call *);
void (*profile_disable)(struct ftrace_event_call *);
int perf_refcount;
int (*perf_event_enable)(struct ftrace_event_call *);
void (*perf_event_disable)(struct ftrace_event_call *);
};

#define FTRACE_MAX_PROFILE_SIZE 2048
#define PERF_MAX_TRACE_SIZE 2048

#define MAX_FILTER_PRED 32
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
Expand Down Expand Up @@ -187,22 +187,25 @@ do { \

#ifdef CONFIG_PERF_EVENTS
struct perf_event;
extern int ftrace_profile_enable(int event_id);
extern void ftrace_profile_disable(int event_id);

DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);

extern int perf_trace_enable(int event_id);
extern void perf_trace_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);
extern void *
ftrace_perf_buf_prepare(int size, unsigned short type, int *rctxp,
perf_trace_buf_prepare(int size, unsigned short type, int *rctxp,
unsigned long *irq_flags);

static inline void
ftrace_perf_buf_submit(void *raw_data, int size, int rctx, u64 addr,
u64 count, unsigned long irq_flags)
perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
u64 count, unsigned long irq_flags, struct pt_regs *regs)
{
struct trace_entry *entry = raw_data;

perf_tp_event(entry->type, addr, count, raw_data, size);
perf_tp_event(entry->type, addr, count, raw_data, size, regs);
perf_swevent_put_recursion_context(rctx);
local_irq_restore(irq_flags);
}
Expand Down
43 changes: 42 additions & 1 deletion trunk/include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ enum perf_callchain_context {
#include <linux/fs.h>
#include <linux/pid_namespace.h>
#include <linux/workqueue.h>
#include <linux/ftrace.h>
#include <linux/cpu.h>
#include <asm/atomic.h>

#define PERF_MAX_STACK_DEPTH 255
Expand Down Expand Up @@ -865,6 +867,44 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
__perf_sw_event(event_id, nr, nmi, regs, addr);
}

extern void
perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);

/*
* Take a snapshot of the regs. Skip ip and frame pointer to
* the nth caller. We only need a few of the regs:
* - ip for PERF_SAMPLE_IP
* - cs for user_mode() tests
* - bp for callchains
* - eflags, for future purposes, just in case
*/
static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip)
{
unsigned long ip;

memset(regs, 0, sizeof(*regs));

switch (skip) {
case 1 :
ip = CALLER_ADDR0;
break;
case 2 :
ip = CALLER_ADDR1;
break;
case 3 :
ip = CALLER_ADDR2;
break;
case 4:
ip = CALLER_ADDR3;
break;
/* No need to support further for now */
default:
ip = 0;
}

return perf_arch_fetch_caller_regs(regs, ip, skip);
}

extern void __perf_event_mmap(struct vm_area_struct *vma);

static inline void perf_event_mmap(struct vm_area_struct *vma)
Expand Down Expand Up @@ -898,7 +938,8 @@ static inline bool perf_paranoid_kernel(void)
}

extern void perf_event_init(void);
extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, int entry_size);
extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size, struct pt_regs *regs);
extern void perf_bp_event(struct perf_event *event, void *data);

#ifndef perf_misc_flags
Expand Down
24 changes: 12 additions & 12 deletions trunk/include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,18 @@ struct perf_event_attr;

#ifdef CONFIG_PERF_EVENTS

#define TRACE_SYS_ENTER_PROFILE_INIT(sname) \
.profile_enable = prof_sysenter_enable, \
.profile_disable = prof_sysenter_disable,
#define TRACE_SYS_ENTER_PERF_INIT(sname) \
.perf_event_enable = perf_sysenter_enable, \
.perf_event_disable = perf_sysenter_disable,

#define TRACE_SYS_EXIT_PROFILE_INIT(sname) \
.profile_enable = prof_sysexit_enable, \
.profile_disable = prof_sysexit_disable,
#define TRACE_SYS_EXIT_PERF_INIT(sname) \
.perf_event_enable = perf_sysexit_enable, \
.perf_event_disable = perf_sysexit_disable,
#else
#define TRACE_SYS_ENTER_PROFILE(sname)
#define TRACE_SYS_ENTER_PROFILE_INIT(sname)
#define TRACE_SYS_EXIT_PROFILE(sname)
#define TRACE_SYS_EXIT_PROFILE_INIT(sname)
#define TRACE_SYS_ENTER_PERF(sname)
#define TRACE_SYS_ENTER_PERF_INIT(sname)
#define TRACE_SYS_EXIT_PERF(sname)
#define TRACE_SYS_EXIT_PERF_INIT(sname)
#endif /* CONFIG_PERF_EVENTS */

#ifdef CONFIG_FTRACE_SYSCALLS
Expand Down Expand Up @@ -149,7 +149,7 @@ struct perf_event_attr;
.regfunc = reg_event_syscall_enter, \
.unregfunc = unreg_event_syscall_enter, \
.data = (void *)&__syscall_meta_##sname,\
TRACE_SYS_ENTER_PROFILE_INIT(sname) \
TRACE_SYS_ENTER_PERF_INIT(sname) \
}

#define SYSCALL_TRACE_EXIT_EVENT(sname) \
Expand All @@ -171,7 +171,7 @@ struct perf_event_attr;
.regfunc = reg_event_syscall_exit, \
.unregfunc = unreg_event_syscall_exit, \
.data = (void *)&__syscall_meta_##sname,\
TRACE_SYS_EXIT_PROFILE_INIT(sname) \
TRACE_SYS_EXIT_PERF_INIT(sname) \
}

#define SYSCALL_METADATA(sname, nb) \
Expand Down
44 changes: 24 additions & 20 deletions trunk/include/trace/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,18 +401,18 @@ static inline notrace int ftrace_get_offsets_##call( \
#undef DEFINE_EVENT
#define DEFINE_EVENT(template, name, proto, args) \
\
static void ftrace_profile_##name(proto); \
static void perf_trace_##name(proto); \
\
static notrace int \
ftrace_profile_enable_##name(struct ftrace_event_call *unused) \
perf_trace_enable_##name(struct ftrace_event_call *unused) \
{ \
return register_trace_##name(ftrace_profile_##name); \
return register_trace_##name(perf_trace_##name); \
} \
\
static notrace void \
ftrace_profile_disable_##name(struct ftrace_event_call *unused) \
perf_trace_disable_##name(struct ftrace_event_call *unused) \
{ \
unregister_trace_##name(ftrace_profile_##name); \
unregister_trace_##name(perf_trace_##name); \
}

#undef DEFINE_EVENT_PRINT
Expand Down Expand Up @@ -507,12 +507,12 @@ ftrace_profile_disable_##name(struct ftrace_event_call *unused) \

#ifdef CONFIG_PERF_EVENTS

#define _TRACE_PROFILE_INIT(call) \
.profile_enable = ftrace_profile_enable_##call, \
.profile_disable = ftrace_profile_disable_##call,
#define _TRACE_PERF_INIT(call) \
.perf_event_enable = perf_trace_enable_##call, \
.perf_event_disable = perf_trace_disable_##call,

#else
#define _TRACE_PROFILE_INIT(call)
#define _TRACE_PERF_INIT(call)
#endif /* CONFIG_PERF_EVENTS */

#undef __entry
Expand Down Expand Up @@ -638,7 +638,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
.unregfunc = ftrace_raw_unreg_event_##call, \
.print_fmt = print_fmt_##template, \
.define_fields = ftrace_define_fields_##template, \
_TRACE_PROFILE_INIT(call) \
_TRACE_PERF_INIT(call) \
}

#undef DEFINE_EVENT_PRINT
Expand All @@ -657,18 +657,18 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
.unregfunc = ftrace_raw_unreg_event_##call, \
.print_fmt = print_fmt_##call, \
.define_fields = ftrace_define_fields_##template, \
_TRACE_PROFILE_INIT(call) \
_TRACE_PERF_INIT(call) \
}

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

/*
* Define the insertion callback to profile events
* Define the insertion callback to perf events
*
* The job is very similar to ftrace_raw_event_<call> except that we don't
* insert in the ring buffer but in a perf counter.
*
* static void ftrace_profile_<call>(proto)
* static void ftrace_perf_<call>(proto)
* {
* struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
* struct ftrace_event_call *event_call = &event_<call>;
Expand Down Expand Up @@ -757,13 +757,14 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
static notrace void \
ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \
perf_trace_templ_##call(struct ftrace_event_call *event_call, \
proto) \
{ \
struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
struct ftrace_raw_##call *entry; \
u64 __addr = 0, __count = 1; \
unsigned long irq_flags; \
struct pt_regs *__regs; \
int __entry_size; \
int __data_size; \
int rctx; \
Expand All @@ -773,28 +774,31 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \
sizeof(u64)); \
__entry_size -= sizeof(u32); \
\
if (WARN_ONCE(__entry_size > FTRACE_MAX_PROFILE_SIZE, \
if (WARN_ONCE(__entry_size > PERF_MAX_TRACE_SIZE, \
"profile buffer not large enough")) \
return; \
entry = (struct ftrace_raw_##call *)ftrace_perf_buf_prepare( \
entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare( \
__entry_size, event_call->id, &rctx, &irq_flags); \
if (!entry) \
return; \
tstruct \
\
{ assign; } \
\
ftrace_perf_buf_submit(entry, __entry_size, rctx, __addr, \
__count, irq_flags); \
__regs = &__get_cpu_var(perf_trace_regs); \
perf_fetch_caller_regs(__regs, 2); \
\
perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \
__count, irq_flags, __regs); \
}

#undef DEFINE_EVENT
#define DEFINE_EVENT(template, call, proto, args) \
static notrace void ftrace_profile_##call(proto) \
static notrace void perf_trace_##call(proto) \
{ \
struct ftrace_event_call *event_call = &event_##call; \
\
ftrace_profile_templ_##template(event_call, args); \
perf_trace_templ_##template(event_call, args); \
}

#undef DEFINE_EVENT_PRINT
Expand Down
Loading

0 comments on commit a010ea0

Please sign in to comment.