Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 205278
b: refs/heads/master
c: bfde744
h: refs/heads/master
v: v3
  • Loading branch information
Tom Zanussi authored and Arnaldo Carvalho de Melo committed Jun 18, 2010
1 parent 445777e commit dd507bc
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 121 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: ffabd99e051e73344efe4e53d58f11643f180512
refs/heads/master: bfde744863eab22a3a400c9003f4f555c903f61d
2 changes: 1 addition & 1 deletion trunk/arch/x86/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ struct arch_hw_breakpoint {
#include <linux/list.h>

/* 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
Expand Down
51 changes: 15 additions & 36 deletions trunk/arch/x86/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -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;
}
/*
Expand All @@ -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;
Expand Down Expand Up @@ -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();
}
/*
Expand Down
8 changes: 3 additions & 5 deletions trunk/include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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

/*
Expand Down
78 changes: 37 additions & 41 deletions trunk/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/cpu.h>
#include <linux/smp.h>

Expand All @@ -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 */
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -180,19 +188,18 @@ 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;
int old_count = 0;
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]++;
Expand All @@ -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;
}

/*
Expand Down Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion trunk/tools/perf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 5 additions & 27 deletions trunk/tools/perf/builtin-trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -116,23 +113,13 @@ 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,
.attr = event__process_attr,
.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,
};

Expand All @@ -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 {
Expand Down Expand Up @@ -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()
};
Expand Down
11 changes: 2 additions & 9 deletions trunk/tools/perf/util/parse-events.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit dd507bc

Please sign in to comment.