diff --git a/[refs] b/[refs] index ebb45517628b..2567c0cf071f 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ffabd99e051e73344efe4e53d58f11643f180512 +refs/heads/master: bfde744863eab22a3a400c9003f4f555c903f61d diff --git a/trunk/arch/x86/include/asm/hw_breakpoint.h b/trunk/arch/x86/include/asm/hw_breakpoint.h index 528a11e8d3e3..942255310e6a 100644 --- a/trunk/arch/x86/include/asm/hw_breakpoint.h +++ b/trunk/arch/x86/include/asm/hw_breakpoint.h @@ -20,10 +20,10 @@ struct arch_hw_breakpoint { #include /* Available HW breakpoint length encodings */ -#define X86_BREAKPOINT_LEN_X 0x00 #define X86_BREAKPOINT_LEN_1 0x40 #define X86_BREAKPOINT_LEN_2 0x44 #define X86_BREAKPOINT_LEN_4 0x4c +#define X86_BREAKPOINT_LEN_EXECUTE 0x40 #ifdef CONFIG_X86_64 #define X86_BREAKPOINT_LEN_8 0x48 diff --git a/trunk/arch/x86/kernel/hw_breakpoint.c b/trunk/arch/x86/kernel/hw_breakpoint.c index a474ec37c32f..a8f1b803d2fd 100644 --- a/trunk/arch/x86/kernel/hw_breakpoint.c +++ b/trunk/arch/x86/kernel/hw_breakpoint.c @@ -208,9 +208,6 @@ int arch_bp_generic_fields(int x86_len, int x86_type, { /* Len */ switch (x86_len) { - case X86_BREAKPOINT_LEN_X: - *gen_len = sizeof(long); - break; case X86_BREAKPOINT_LEN_1: *gen_len = HW_BREAKPOINT_LEN_1; break; @@ -254,29 +251,6 @@ static int arch_build_bp_info(struct perf_event *bp) info->address = bp->attr.bp_addr; - /* Type */ - switch (bp->attr.bp_type) { - case HW_BREAKPOINT_W: - info->type = X86_BREAKPOINT_WRITE; - break; - case HW_BREAKPOINT_W | HW_BREAKPOINT_R: - info->type = X86_BREAKPOINT_RW; - break; - case HW_BREAKPOINT_X: - info->type = X86_BREAKPOINT_EXECUTE; - /* - * x86 inst breakpoints need to have a specific undefined len. - * But we still need to check userspace is not trying to setup - * an unsupported length, to get a range breakpoint for example. - */ - if (bp->attr.bp_len == sizeof(long)) { - info->len = X86_BREAKPOINT_LEN_X; - return 0; - } - default: - return -EINVAL; - } - /* Len */ switch (bp->attr.bp_len) { case HW_BREAKPOINT_LEN_1: @@ -297,6 +271,21 @@ static int arch_build_bp_info(struct perf_event *bp) return -EINVAL; } + /* Type */ + switch (bp->attr.bp_type) { + case HW_BREAKPOINT_W: + info->type = X86_BREAKPOINT_WRITE; + break; + case HW_BREAKPOINT_W | HW_BREAKPOINT_R: + info->type = X86_BREAKPOINT_RW; + break; + case HW_BREAKPOINT_X: + info->type = X86_BREAKPOINT_EXECUTE; + break; + default: + return -EINVAL; + } + return 0; } /* @@ -316,9 +305,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) ret = -EINVAL; switch (info->len) { - case X86_BREAKPOINT_LEN_X: - align = sizeof(long) -1; - break; case X86_BREAKPOINT_LEN_1: align = 0; break; @@ -480,13 +466,6 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) perf_bp_event(bp, args->regs); - /* - * Set up resume flag to avoid breakpoint recursion when - * returning back to origin. - */ - if (bp->hw.info.type == X86_BREAKPOINT_EXECUTE) - args->regs->flags |= X86_EFLAGS_RF; - rcu_read_unlock(); } /* diff --git a/trunk/include/linux/perf_event.h b/trunk/include/linux/perf_event.h index 937495c25073..63b5aa5dce69 100644 --- a/trunk/include/linux/perf_event.h +++ b/trunk/include/linux/perf_event.h @@ -533,10 +533,8 @@ struct hw_perf_event { struct hrtimer hrtimer; }; #ifdef CONFIG_HAVE_HW_BREAKPOINT - struct { /* breakpoint */ - struct arch_hw_breakpoint info; - struct list_head bp_list; - }; + /* breakpoint */ + struct arch_hw_breakpoint info; #endif }; local64_t prev_count; @@ -936,7 +934,7 @@ extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); #ifndef perf_arch_fetch_caller_regs static inline void -perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip) { } +perf_arch_fetch_caller_regs(struct regs *regs, unsigned long ip) { } #endif /* diff --git a/trunk/kernel/hw_breakpoint.c b/trunk/kernel/hw_breakpoint.c index e34d94d50924..7a56b22e0602 100644 --- a/trunk/kernel/hw_breakpoint.c +++ b/trunk/kernel/hw_breakpoint.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -63,9 +62,6 @@ static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]); static int nr_slots[TYPE_MAX]; -/* Keep track of the breakpoints attached to tasks */ -static LIST_HEAD(bp_task_head); - static int constraints_initialized; /* Gather the number of total pinned and un-pinned bp in a cpuset */ @@ -107,21 +103,33 @@ static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) return 0; } -/* - * Count the number of breakpoints of the same type and same task. - * The given event must be not on the list. - */ -static int task_bp_pinned(struct perf_event *bp, enum bp_type_idx type) +static int task_bp_pinned(struct task_struct *tsk, enum bp_type_idx type) { - struct perf_event_context *ctx = bp->ctx; - struct perf_event *iter; + struct perf_event_context *ctx = tsk->perf_event_ctxp; + struct list_head *list; + struct perf_event *bp; + unsigned long flags; int count = 0; - list_for_each_entry(iter, &bp_task_head, hw.bp_list) { - if (iter->ctx == ctx && find_slot_idx(iter) == type) - count += hw_breakpoint_weight(iter); + if (WARN_ONCE(!ctx, "No perf context for this task")) + return 0; + + list = &ctx->event_list; + + raw_spin_lock_irqsave(&ctx->lock, flags); + + /* + * The current breakpoint counter is not included in the list + * at the open() callback time + */ + list_for_each_entry(bp, list, event_entry) { + if (bp->attr.type == PERF_TYPE_BREAKPOINT) + if (find_slot_idx(bp) == type) + count += hw_breakpoint_weight(bp); } + raw_spin_unlock_irqrestore(&ctx->lock, flags); + return count; } @@ -141,7 +149,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, if (!tsk) slots->pinned += max_task_bp_pinned(cpu, type); else - slots->pinned += task_bp_pinned(bp, type); + slots->pinned += task_bp_pinned(tsk, type); slots->flexible = per_cpu(nr_bp_flexible[type], cpu); return; @@ -154,7 +162,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, if (!tsk) nr += max_task_bp_pinned(cpu, type); else - nr += task_bp_pinned(bp, type); + nr += task_bp_pinned(tsk, type); if (nr > slots->pinned) slots->pinned = nr; @@ -180,7 +188,7 @@ fetch_this_slot(struct bp_busy_slots *slots, int weight) /* * Add a pinned breakpoint for the given task in our constraint table */ -static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable, +static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable, enum bp_type_idx type, int weight) { unsigned int *tsk_pinned; @@ -188,11 +196,10 @@ static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable, int old_idx = 0; int idx = 0; - old_count = task_bp_pinned(bp, type); + old_count = task_bp_pinned(tsk, type); old_idx = old_count - 1; idx = old_idx + weight; - /* tsk_pinned[n] is the number of tasks having n breakpoints */ tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); if (enable) { tsk_pinned[idx]++; @@ -215,30 +222,23 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, int cpu = bp->cpu; struct task_struct *tsk = bp->ctx->task; - /* Pinned counter cpu profiling */ - if (!tsk) { - - if (enable) - per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight; - else - per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight; - return; - } - /* Pinned counter task profiling */ + if (tsk) { + if (cpu >= 0) { + toggle_bp_task_slot(tsk, cpu, enable, type, weight); + return; + } - if (!enable) - list_del(&bp->hw.bp_list); - - if (cpu >= 0) { - toggle_bp_task_slot(bp, cpu, enable, type, weight); - } else { for_each_online_cpu(cpu) - toggle_bp_task_slot(bp, cpu, enable, type, weight); + toggle_bp_task_slot(tsk, cpu, enable, type, weight); + return; } + /* Pinned counter cpu profiling */ if (enable) - list_add_tail(&bp->hw.bp_list, &bp_task_head); + per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight; + else + per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight; } /* @@ -301,10 +301,6 @@ static int __reserve_bp_slot(struct perf_event *bp) weight = hw_breakpoint_weight(bp); fetch_bp_busy_slots(&slots, bp, type); - /* - * Simulate the addition of this breakpoint to the constraints - * and see the result. - */ fetch_this_slot(&slots, weight); /* Flexible counters need to keep at least one slot */ diff --git a/trunk/tools/perf/Makefile b/trunk/tools/perf/Makefile index 6aa2fe323db1..17a3692397c5 100644 --- a/trunk/tools/perf/Makefile +++ b/trunk/tools/perf/Makefile @@ -577,7 +577,7 @@ ifdef NO_LIBPERL else PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` - PERL_EMBED_FLAGS=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) + FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y) BASIC_CFLAGS += -DNO_LIBPERL diff --git a/trunk/tools/perf/builtin-trace.c b/trunk/tools/perf/builtin-trace.c index 294da725a57d..dddf3f01b5ab 100644 --- a/trunk/tools/perf/builtin-trace.c +++ b/trunk/tools/perf/builtin-trace.c @@ -11,9 +11,8 @@ static char const *script_name; static char const *generate_script_lang; -static bool debug_mode; +static bool debug_ordering; static u64 last_timestamp; -static u64 nr_unordered; static int default_start_script(const char *script __unused, int argc __unused, @@ -92,15 +91,13 @@ static int process_sample_event(event_t *event, struct perf_session *session) } if (session->sample_type & PERF_SAMPLE_RAW) { - if (debug_mode) { + if (debug_ordering) { if (data.time < last_timestamp) { pr_err("Samples misordered, previous: %llu " "this: %llu\n", last_timestamp, data.time); - nr_unordered++; } last_timestamp = data.time; - return 0; } /* * FIXME: better resolve from pid from the struct trace_entry @@ -116,15 +113,6 @@ static int process_sample_event(event_t *event, struct perf_session *session) return 0; } -static u64 nr_lost; - -static int process_lost_event(event_t *event, struct perf_session *session __used) -{ - nr_lost += event->lost.lost; - - return 0; -} - static struct perf_event_ops event_ops = { .sample = process_sample_event, .comm = event__process_comm, @@ -132,7 +120,6 @@ static struct perf_event_ops event_ops = { .event_type = event__process_event_type, .tracing_data = event__process_tracing_data, .build_id = event__process_build_id, - .lost = process_lost_event, .ordered_samples = true, }; @@ -145,18 +132,9 @@ static void sig_handler(int sig __unused) static int __cmd_trace(struct perf_session *session) { - int ret; - signal(SIGINT, sig_handler); - ret = perf_session__process_events(session, &event_ops); - - if (debug_mode) { - pr_err("Misordered timestamps: %llu\n", nr_unordered); - pr_err("Lost events: %llu\n", nr_lost); - } - - return ret; + return perf_session__process_events(session, &event_ops); } struct script_spec { @@ -566,8 +544,8 @@ static const struct option options[] = { "generate perf-trace.xx script in specified language"), OPT_STRING('i', "input", &input_name, "file", "input file name"), - OPT_BOOLEAN('d', "debug-mode", &debug_mode, - "do various checks like samples ordering and lost events"), + OPT_BOOLEAN('d', "debug-ordering", &debug_ordering, + "check that samples time ordering is monotonic"), OPT_END() }; diff --git a/trunk/tools/perf/util/parse-events.c b/trunk/tools/perf/util/parse-events.c index 4af5bd59cfd1..9bf0f402ca73 100644 --- a/trunk/tools/perf/util/parse-events.c +++ b/trunk/tools/perf/util/parse-events.c @@ -602,15 +602,8 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr) return EVT_FAILED; } - /* - * We should find a nice way to override the access length - * Provide some defaults for now - */ - if (attr->bp_type == HW_BREAKPOINT_X) - attr->bp_len = sizeof(long); - else - attr->bp_len = HW_BREAKPOINT_LEN_4; - + /* We should find a nice way to override the access type */ + attr->bp_len = HW_BREAKPOINT_LEN_4; attr->type = PERF_TYPE_BREAKPOINT; return EVT_HANDLED;