[PATCH 2/4] perf: Add exclude_task perf event attribute

From: Frederic Weisbecker
Date: Fri May 21 2010 - 10:10:59 EST


Excluding is useful when you want to trace only hard and softirqs.

For this we use a new generic perf_exclude_event() (the previous
one beeing turned into perf_exclude_swevent) to which you can pass
the preemption offset to which your events trigger.

Computing preempt_count() - offset gives us the preempt_count() of
the context that the event has interrupted, on top of which we
can filter the non-irq contexts.

Signed-off-by: Frederic Weisbecker <fweisbec@xxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxx>
Cc: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: Paul Mackerras <paulus@xxxxxxxxx>
---
include/linux/perf_event.h | 3 ++-
kernel/perf_event.c | 41 ++++++++++++++++++++++++++++++++++-------
2 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fe50347..d939fc7 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -214,8 +214,9 @@ struct perf_event_attr {
* See also PERF_RECORD_MISC_EXACT_IP
*/
precise_ip : 2, /* skid constraint */
+ exclude_task : 1, /* don't count task context */

- __reserved_1 : 47;
+ __reserved_1 : 46;

union {
__u32 wakeup_events; /* wakeup every n events */
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 45b7aec..ab96411 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -3907,10 +3907,33 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
return ret;
}

+static bool
+perf_exclude_event(struct perf_event *event, int offset)
+{
+ if (!in_interrupt_offset(preempt_count() - offset)) {
+ if (event->attr.exclude_task)
+ return true;
+ }
+
+ return false;
+}
+
int perf_event_overflow(struct perf_event *event, int nmi,
struct perf_sample_data *data,
struct pt_regs *regs)
{
+ int offset = HARDIRQ_OFFSET;
+
+ if (nmi)
+ offset += NMI_OFFSET;
+ /*
+ * Hardware events trigger on NMI or simple hardirq, which offset we
+ * need to substract to get the preempt_count() of the interrupted
+ * context.
+ */
+ if (perf_exclude_event(event, offset))
+ return 0;
+
return __perf_event_overflow(event, nmi, 1, data, regs);
}

@@ -4008,8 +4031,8 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data);

-static int perf_exclude_event(struct perf_event *event,
- struct pt_regs *regs)
+static int perf_exclude_swevent(struct perf_event *event,
+ struct pt_regs *regs, int offset)
{
if (regs) {
if (event->attr.exclude_user && user_mode(regs))
@@ -4019,7 +4042,7 @@ static int perf_exclude_event(struct perf_event *event,
return 1;
}

- return 0;
+ return perf_exclude_event(event, offset);
}

static int perf_swevent_match(struct perf_event *event,
@@ -4034,7 +4057,7 @@ static int perf_swevent_match(struct perf_event *event,
if (event->attr.config != event_id)
return 0;

- if (perf_exclude_event(event, regs))
+ if (perf_exclude_swevent(event, regs, 0))
return 0;

if (event->attr.type == PERF_TYPE_TRACEPOINT &&
@@ -4230,9 +4253,13 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
data.period = event->hw.last_period;
regs = get_irq_regs();

- if (regs && !perf_exclude_event(event, regs)) {
+ /*
+ * we are in hardirq, so we need to substract our preempt offset
+ * to retrieve the interrupted one
+ */
+ if (regs && !perf_exclude_swevent(event, regs, HARDIRQ_OFFSET)) {
if (!(event->attr.exclude_idle && current->pid == 0))
- if (perf_event_overflow(event, 0, &data, regs))
+ if (__perf_event_overflow(event, 0, 1, &data, regs))
ret = HRTIMER_NORESTART;
}

@@ -4624,7 +4651,7 @@ void perf_bp_event(struct perf_event *bp, void *data)

perf_sample_data_init(&sample, bp->attr.bp_addr);

- if (!perf_exclude_event(bp, regs))
+ if (!perf_exclude_swevent(bp, regs, 0))
perf_swevent_add(bp, 1, 1, &sample, regs);
}
#else
--
1.6.2.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/