From: Linus Torvalds Date: Thu, 27 May 2010 22:23:47 +0000 (-0700) Subject: Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git... X-Git-Tag: v2.6.35-rc1~30 X-Git-Url: https://repo.jachan.dev/J-linux.git/commitdiff_plain/c5617b200ac52e35f7e8cf05a17b0a2d50f6b3e9?hp=-c Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (61 commits) tracing: Add __used annotation to event variable perf, trace: Fix !x86 build bug perf report: Support multiple events on the TUI perf annotate: Fix up usage of the build id cache x86/mmiotrace: Remove redundant instruction prefix checks perf annotate: Add TUI interface perf tui: Remove annotate from popup menu after failure perf report: Don't start the TUI if -D is used perf: Fix getline undeclared perf: Optimize perf_tp_event_match() perf: Remove more code from the fastpath perf: Optimize the !vmalloc backed buffer perf: Optimize perf_output_copy() perf: Fix wakeup storm for RO mmap()s perf-record: Share per-cpu buffers perf-record: Remove -M perf: Ensure that IOC_OUTPUT isn't used to create multi-writer buffers perf, trace: Optimize tracepoints by using per-tracepoint-per-cpu hlist to track events perf, trace: Optimize tracepoints by removing IRQ-disable from perf/tracepoint interaction perf tui: Allow disabling the TUI on a per command basis in ~/.perfconfig ... --- c5617b200ac52e35f7e8cf05a17b0a2d50f6b3e9 diff --combined arch/sparc/kernel/perf_event.c index 34ce49f80eac,cf4ce263ff81..0ec92c8861dd --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@@ -14,7 -14,6 +14,7 @@@ #include #include +#include #include #include #include @@@ -92,6 -91,8 +92,8 @@@ struct cpu_hw_events /* Enabled/disable state. */ int enabled; + + unsigned int group_flag; }; DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; @@@ -981,53 -982,6 +983,6 @@@ static int collect_events(struct perf_e return n; } - static void event_sched_in(struct perf_event *event) - { - event->state = PERF_EVENT_STATE_ACTIVE; - event->oncpu = smp_processor_id(); - event->tstamp_running += event->ctx->time - event->tstamp_stopped; - if (is_software_event(event)) - event->pmu->enable(event); - } - - int hw_perf_group_sched_in(struct perf_event *group_leader, - struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) - { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - struct perf_event *sub; - int n0, n; - - if (!sparc_pmu) - return 0; - - n0 = cpuc->n_events; - n = collect_events(group_leader, perf_max_events - n0, - &cpuc->event[n0], &cpuc->events[n0], - &cpuc->current_idx[n0]); - if (n < 0) - return -EAGAIN; - if (check_excludes(cpuc->event, n0, n)) - return -EINVAL; - if (sparc_check_constraints(cpuc->event, cpuc->events, n + n0)) - return -EAGAIN; - cpuc->n_events = n0 + n; - cpuc->n_added += n; - - cpuctx->active_oncpu += n; - n = 1; - event_sched_in(group_leader); - list_for_each_entry(sub, &group_leader->sibling_list, group_entry) { - if (sub->state != PERF_EVENT_STATE_OFF) { - event_sched_in(sub); - n++; - } - } - ctx->nr_active += n; - - return 1; - } - static int sparc_pmu_enable(struct perf_event *event) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); @@@ -1045,11 -999,20 +1000,20 @@@ cpuc->events[n0] = event->hw.event_base; cpuc->current_idx[n0] = PIC_NO_INDEX; + /* + * If group events scheduling transaction was started, + * skip the schedulability test here, it will be peformed + * at commit time(->commit_txn) as a whole + */ + if (cpuc->group_flag & PERF_EVENT_TXN_STARTED) + goto nocheck; + if (check_excludes(cpuc->event, n0, 1)) goto out; if (sparc_check_constraints(cpuc->event, cpuc->events, n0 + 1)) goto out; + nocheck: cpuc->n_events++; cpuc->n_added++; @@@ -1129,11 -1092,61 +1093,61 @@@ static int __hw_perf_event_init(struct return 0; } + /* + * Start group events scheduling transaction + * Set the flag to make pmu::enable() not perform the + * schedulability test, it will be performed at commit time + */ + static void sparc_pmu_start_txn(const struct pmu *pmu) + { + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + + cpuhw->group_flag |= PERF_EVENT_TXN_STARTED; + } + + /* + * Stop group events scheduling transaction + * Clear the flag and pmu::enable() will perform the + * schedulability test. + */ + static void sparc_pmu_cancel_txn(const struct pmu *pmu) + { + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + + cpuhw->group_flag &= ~PERF_EVENT_TXN_STARTED; + } + + /* + * Commit group events scheduling transaction + * Perform the group schedulability test as a whole + * Return 0 if success + */ + static int sparc_pmu_commit_txn(const struct pmu *pmu) + { + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + int n; + + if (!sparc_pmu) + return -EINVAL; + + cpuc = &__get_cpu_var(cpu_hw_events); + n = cpuc->n_events; + if (check_excludes(cpuc->event, 0, n)) + return -EINVAL; + if (sparc_check_constraints(cpuc->event, cpuc->events, n)) + return -EAGAIN; + + return 0; + } + static const struct pmu pmu = { .enable = sparc_pmu_enable, .disable = sparc_pmu_disable, .read = sparc_pmu_read, .unthrottle = sparc_pmu_unthrottle, + .start_txn = sparc_pmu_start_txn, + .cancel_txn = sparc_pmu_cancel_txn, + .commit_txn = sparc_pmu_commit_txn, }; const struct pmu *hw_perf_event_init(struct perf_event *event) @@@ -1277,9 -1290,6 +1291,9 @@@ static void perf_callchain_kernel(struc struct perf_callchain_entry *entry) { unsigned long ksp, fp; +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + int graph = 0; +#endif callchain_store(entry, PERF_CONTEXT_KERNEL); callchain_store(entry, regs->tpc); @@@ -1307,16 -1317,6 +1321,16 @@@ fp = (unsigned long)sf->fp + STACK_BIAS; } callchain_store(entry, pc); +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + if ((pc + 8UL) == (unsigned long) &return_to_handler) { + int index = current->curr_ret_stack; + if (current->ret_stack && index >= graph) { + pc = current->ret_stack[index - graph].ret; + callchain_store(entry, pc); + graph++; + } + } +#endif } while (entry->nr < PERF_MAX_STACK_DEPTH); } diff --combined include/linux/ftrace_event.h index c082f223e2fe,ee8a8411b055..3167f2df4126 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@@ -25,9 -25,6 +25,9 @@@ const char *ftrace_print_flags_seq(stru const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val, const struct trace_print_flags *symbol_array); +const char *ftrace_print_hex_seq(struct trace_seq *p, + const unsigned char *buf, int len); + /* * The trace entry - the most basic unit of tracing. This is what * is printed in the end as a single line in the trace output, such as: @@@ -73,18 -70,25 +73,25 @@@ struct trace_iterator }; + struct trace_event; + typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter, - int flags); - struct trace_event { - struct hlist_node node; - struct list_head list; - int type; + int flags, struct trace_event *event); + + struct trace_event_functions { trace_print_func trace; trace_print_func raw; trace_print_func hex; trace_print_func binary; }; + struct trace_event { + struct hlist_node node; + struct list_head list; + int type; + struct trace_event_functions *funcs; + }; + extern int register_ftrace_event(struct trace_event *event); extern int unregister_ftrace_event(struct trace_event *event); @@@ -116,28 -120,70 +123,70 @@@ void tracing_record_cmdline(struct task struct event_filter; + enum trace_reg { + TRACE_REG_REGISTER, + TRACE_REG_UNREGISTER, + TRACE_REG_PERF_REGISTER, + TRACE_REG_PERF_UNREGISTER, + }; + + struct ftrace_event_call; + + struct ftrace_event_class { + char *system; + void *probe; + #ifdef CONFIG_PERF_EVENTS + void *perf_probe; + #endif + int (*reg)(struct ftrace_event_call *event, + enum trace_reg type); + int (*define_fields)(struct ftrace_event_call *); + struct list_head *(*get_fields)(struct ftrace_event_call *); + struct list_head fields; + int (*raw_init)(struct ftrace_event_call *); + }; + + enum { + TRACE_EVENT_FL_ENABLED_BIT, + TRACE_EVENT_FL_FILTERED_BIT, + }; + + enum { + TRACE_EVENT_FL_ENABLED = (1 << TRACE_EVENT_FL_ENABLED_BIT), + TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT), + }; + struct ftrace_event_call { struct list_head list; + struct ftrace_event_class *class; char *name; - char *system; struct dentry *dir; - struct trace_event *event; - int enabled; - int (*regfunc)(struct ftrace_event_call *); - void (*unregfunc)(struct ftrace_event_call *); - int id; + struct trace_event event; const char *print_fmt; - int (*raw_init)(struct ftrace_event_call *); - int (*define_fields)(struct ftrace_event_call *); - struct list_head fields; - int filter_active; struct event_filter *filter; void *mod; void *data; + /* + * 32 bit flags: + * bit 1: enabled + * bit 2: filter_active + * + * Changes to flags must hold the event_mutex. + * + * Note: Reads of flags do not hold the event_mutex since + * they occur in critical sections. But the way flags + * is currently used, these changes do no affect the code + * except that when a change is made, it may have a slight + * delay in propagating the changes to other CPUs due to + * caching and such. + */ + unsigned int flags; + + #ifdef CONFIG_PERF_EVENTS int perf_refcount; - int (*perf_event_enable)(struct ftrace_event_call *); - void (*perf_event_disable)(struct ftrace_event_call *); + struct hlist_head *perf_events; + #endif }; #define PERF_MAX_TRACE_SIZE 2048 @@@ -194,24 -240,22 +243,22 @@@ struct perf_event 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, + extern int perf_trace_init(struct perf_event *event); + extern void perf_trace_destroy(struct perf_event *event); + extern int perf_trace_enable(struct perf_event *event); + extern void perf_trace_disable(struct perf_event *event); + 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 * - perf_trace_buf_prepare(int size, unsigned short type, int *rctxp, - unsigned long *irq_flags); + extern void *perf_trace_buf_prepare(int size, unsigned short type, + struct pt_regs *regs, int *rctxp); static inline void perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, - u64 count, unsigned long irq_flags, struct pt_regs *regs) + u64 count, struct pt_regs *regs, void *head) { - struct trace_entry *entry = raw_data; - - perf_tp_event(entry->type, addr, count, raw_data, size, regs); + perf_tp_event(addr, count, raw_data, size, regs, head); perf_swevent_put_recursion_context(rctx); - local_irq_restore(irq_flags); } #endif diff --combined include/trace/ftrace.h index 88c59c13ea7b,34bead70d178..3d685d1f2a03 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@@ -62,10 -62,13 +62,13 @@@ struct trace_entry ent; \ tstruct \ char __data[0]; \ - }; + }; \ + \ + static struct ftrace_event_class event_class_##name; + #undef DEFINE_EVENT #define DEFINE_EVENT(template, name, proto, args) \ - static struct ftrace_event_call \ + static struct ftrace_event_call __used \ __attribute__((__aligned__(4))) event_##name #undef DEFINE_EVENT_PRINT @@@ -147,7 -150,7 +150,7 @@@ * * entry = iter->ent; * - * if (entry->type != event_.id) { + * if (entry->type != event_->event.type) { * WARN_ON_ONCE(1); * return TRACE_TYPE_UNHANDLED; * } @@@ -200,24 -203,25 +203,28 @@@ ftrace_print_symbols_seq(p, value, symbols); \ }) +#undef __print_hex +#define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len) + #undef DECLARE_EVENT_CLASS #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ static notrace enum print_line_t \ - ftrace_raw_output_id_##call(int event_id, const char *name, \ - struct trace_iterator *iter, int flags) \ + ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \ + struct trace_event *trace_event) \ { \ + struct ftrace_event_call *event; \ struct trace_seq *s = &iter->seq; \ struct ftrace_raw_##call *field; \ struct trace_entry *entry; \ struct trace_seq *p; \ int ret; \ \ + event = container_of(trace_event, struct ftrace_event_call, \ + event); \ + \ entry = iter->ent; \ \ - if (entry->type != event_id) { \ + if (entry->type != event->event.type) { \ WARN_ON_ONCE(1); \ return TRACE_TYPE_UNHANDLED; \ } \ @@@ -226,7 -230,7 +233,7 @@@ \ p = &get_cpu_var(ftrace_event_seq); \ trace_seq_init(p); \ - ret = trace_seq_printf(s, "%s: ", name); \ + ret = trace_seq_printf(s, "%s: ", event->name); \ if (ret) \ ret = trace_seq_printf(s, print); \ put_cpu(); \ @@@ -234,21 -238,16 +241,16 @@@ return TRACE_TYPE_PARTIAL_LINE; \ \ return TRACE_TYPE_HANDLED; \ - } - - #undef DEFINE_EVENT - #define DEFINE_EVENT(template, name, proto, args) \ - static notrace enum print_line_t \ - ftrace_raw_output_##name(struct trace_iterator *iter, int flags) \ - { \ - return ftrace_raw_output_id_##template(event_##name.id, \ - #name, iter, flags); \ - } + } \ + static struct trace_event_functions ftrace_event_type_funcs_##call = { \ + .trace = ftrace_raw_output_##call, \ + }; #undef DEFINE_EVENT_PRINT #define DEFINE_EVENT_PRINT(template, call, proto, args, print) \ static notrace enum print_line_t \ - ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ + ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \ + struct trace_event *event) \ { \ struct trace_seq *s = &iter->seq; \ struct ftrace_raw_##template *field; \ @@@ -258,7 -257,7 +260,7 @@@ \ entry = iter->ent; \ \ - if (entry->type != event_##call.id) { \ + if (entry->type != event_##call.event.type) { \ WARN_ON_ONCE(1); \ return TRACE_TYPE_UNHANDLED; \ } \ @@@ -275,7 -274,10 +277,10 @@@ return TRACE_TYPE_PARTIAL_LINE; \ \ return TRACE_TYPE_HANDLED; \ - } + } \ + static struct trace_event_functions ftrace_event_type_funcs_##call = { \ + .trace = ftrace_raw_output_##call, \ + }; #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) @@@ -381,80 -383,18 +386,18 @@@ static inline notrace int ftrace_get_of #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) - #ifdef CONFIG_PERF_EVENTS - - /* - * Generate the functions needed for tracepoint perf_event support. - * - * NOTE: The insertion profile callback (ftrace_profile_) is defined later - * - * static int ftrace_profile_enable_(void) - * { - * return register_trace_(ftrace_profile_); - * } - * - * static void ftrace_profile_disable_(void) - * { - * unregister_trace_(ftrace_profile_); - * } - * - */ - - #undef DECLARE_EVENT_CLASS - #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) - - #undef DEFINE_EVENT - #define DEFINE_EVENT(template, name, proto, args) \ - \ - static void perf_trace_##name(proto); \ - \ - static notrace int \ - perf_trace_enable_##name(struct ftrace_event_call *unused) \ - { \ - return register_trace_##name(perf_trace_##name); \ - } \ - \ - static notrace void \ - perf_trace_disable_##name(struct ftrace_event_call *unused) \ - { \ - unregister_trace_##name(perf_trace_##name); \ - } - - #undef DEFINE_EVENT_PRINT - #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ - DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) - - #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) - - #endif /* CONFIG_PERF_EVENTS */ - /* * Stage 4 of the trace events. * * Override the macros in to include the following: * - * static void ftrace_event_(proto) - * { - * event_trace_printk(_RET_IP_, ": " ); - * } - * - * static int ftrace_reg_event_(struct ftrace_event_call *unused) - * { - * return register_trace_(ftrace_event_); - * } - * - * static void ftrace_unreg_event_(struct ftrace_event_call *unused) - * { - * unregister_trace_(ftrace_event_); - * } - * - * * For those macros defined with TRACE_EVENT: * * static struct ftrace_event_call event_; * - * static void ftrace_raw_event_(proto) + * static void ftrace_raw_event_(void *__data, proto) * { + * struct ftrace_event_call *event_call = __data; * struct ftrace_data_offsets_ __maybe_unused __data_offsets; * struct ring_buffer_event *event; * struct ftrace_raw_ *entry; <-- defined in stage 1 @@@ -469,7 -409,7 +412,7 @@@ * __data_size = ftrace_get_offsets_(&__data_offsets, args); * * event = trace_current_buffer_lock_reserve(&buffer, - * event_.id, + * event_->event.type, * sizeof(*entry) + __data_size, * irq_flags, pc); * if (!event) @@@ -484,43 -424,42 +427,42 @@@ * event, irq_flags, pc); * } * - * static int ftrace_raw_reg_event_(struct ftrace_event_call *unused) - * { - * return register_trace_(ftrace_raw_event_); - * } - * - * static void ftrace_unreg_event_(struct ftrace_event_call *unused) - * { - * unregister_trace_(ftrace_raw_event_); - * } - * * static struct trace_event ftrace_event_type_ = { * .trace = ftrace_raw_output_, <-- stage 2 * }; * * static const char print_fmt_[] = ; * + * static struct ftrace_event_class __used event_class_