Skip to content

Commit

Permalink
perf: Add ability to sample machine state on interrupt
Browse files Browse the repository at this point in the history
Enable capture of interrupted machine state for each sample.

Registers to sample are passed per event in the sample_regs_intr bitmask.

To sample interrupt machine state, the PERF_SAMPLE_INTR_REGS must be passed in
sample_type.

The list of available registers is arch dependent and provided by asm/perf_regs.h

Registers are laid out as u64 in the order of the bit order of sample_intr_regs.

This patch also adds a new ABI version PERF_ATTR_SIZE_VER4 because we extend
the perf_event_attr struct with a new u64 field.

Reviewed-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: cebbert.lkml@gmail.com
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-api@vger.kernel.org
Link: http://lkml.kernel.org/r/1411559322-16548-2-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Stephane Eranian authored and Ingo Molnar committed Nov 16, 2014
1 parent af4bdcf commit 60e2364
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
7 changes: 5 additions & 2 deletions include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ struct perf_branch_stack {
struct perf_branch_entry entries[0];
};

struct perf_regs_user {
struct perf_regs {
__u64 abi;
struct pt_regs *regs;
};
Expand Down Expand Up @@ -600,7 +600,8 @@ struct perf_sample_data {
struct perf_callchain_entry *callchain;
struct perf_raw_record *raw;
struct perf_branch_stack *br_stack;
struct perf_regs_user regs_user;
struct perf_regs regs_user;
struct perf_regs regs_intr;
u64 stack_user_size;
u64 weight;
/*
Expand Down Expand Up @@ -630,6 +631,8 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
data->weight = 0;
data->data_src.val = PERF_MEM_NA;
data->txn = 0;
data->regs_intr.abi = PERF_SAMPLE_REGS_ABI_NONE;
data->regs_intr.regs = NULL;
}

extern void perf_output_sample(struct perf_output_handle *handle,
Expand Down
15 changes: 14 additions & 1 deletion include/uapi/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ enum perf_event_sample_format {
PERF_SAMPLE_DATA_SRC = 1U << 15,
PERF_SAMPLE_IDENTIFIER = 1U << 16,
PERF_SAMPLE_TRANSACTION = 1U << 17,
PERF_SAMPLE_REGS_INTR = 1U << 18,

PERF_SAMPLE_MAX = 1U << 18, /* non-ABI */
PERF_SAMPLE_MAX = 1U << 19, /* non-ABI */
};

/*
Expand Down Expand Up @@ -238,6 +239,7 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
/* add: sample_stack_user */
#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */

/*
* Hardware event_id to monitor via a performance monitoring event:
Expand Down Expand Up @@ -334,6 +336,15 @@ struct perf_event_attr {

/* Align to u64. */
__u32 __reserved_2;
/*
* Defines set of regs to dump for each sample
* state captured on:
* - precise = 0: PMU interrupt
* - precise > 0: sampled instruction
*
* See asm/perf_regs.h for details.
*/
__u64 sample_regs_intr;
};

#define perf_flags(attr) (*(&(attr)->read_format + 1))
Expand Down Expand Up @@ -686,6 +697,8 @@ enum perf_event_type {
* { u64 weight; } && PERF_SAMPLE_WEIGHT
* { u64 data_src; } && PERF_SAMPLE_DATA_SRC
* { u64 transaction; } && PERF_SAMPLE_TRANSACTION
* { u64 abi; # enum perf_sample_regs_abi
* u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
* };
*/
PERF_RECORD_SAMPLE = 9,
Expand Down
46 changes: 44 additions & 2 deletions kernel/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4460,7 +4460,7 @@ perf_output_sample_regs(struct perf_output_handle *handle,
}
}

static void perf_sample_regs_user(struct perf_regs_user *regs_user,
static void perf_sample_regs_user(struct perf_regs *regs_user,
struct pt_regs *regs)
{
if (!user_mode(regs)) {
Expand All @@ -4476,6 +4476,14 @@ static void perf_sample_regs_user(struct perf_regs_user *regs_user,
}
}

static void perf_sample_regs_intr(struct perf_regs *regs_intr,
struct pt_regs *regs)
{
regs_intr->regs = regs;
regs_intr->abi = perf_reg_abi(current);
}


/*
* Get remaining task size from user stack pointer.
*
Expand Down Expand Up @@ -4857,6 +4865,23 @@ void perf_output_sample(struct perf_output_handle *handle,
if (sample_type & PERF_SAMPLE_TRANSACTION)
perf_output_put(handle, data->txn);

if (sample_type & PERF_SAMPLE_REGS_INTR) {
u64 abi = data->regs_intr.abi;
/*
* If there are no regs to dump, notice it through
* first u64 being zero (PERF_SAMPLE_REGS_ABI_NONE).
*/
perf_output_put(handle, abi);

if (abi) {
u64 mask = event->attr.sample_regs_intr;

perf_output_sample_regs(handle,
data->regs_intr.regs,
mask);
}
}

if (!event->attr.watermark) {
int wakeup_events = event->attr.wakeup_events;

Expand Down Expand Up @@ -4943,7 +4968,7 @@ void perf_prepare_sample(struct perf_event_header *header,
* in case new sample type is added, because we could eat
* up the rest of the sample size.
*/
struct perf_regs_user *uregs = &data->regs_user;
struct perf_regs *uregs = &data->regs_user;
u16 stack_size = event->attr.sample_stack_user;
u16 size = sizeof(u64);

Expand All @@ -4964,6 +4989,21 @@ void perf_prepare_sample(struct perf_event_header *header,
data->stack_user_size = stack_size;
header->size += size;
}

if (sample_type & PERF_SAMPLE_REGS_INTR) {
/* regs dump ABI info */
int size = sizeof(u64);

perf_sample_regs_intr(&data->regs_intr, regs);

if (data->regs_intr.regs) {
u64 mask = event->attr.sample_regs_intr;

size += hweight64(mask) * sizeof(u64);
}

header->size += size;
}
}

static void perf_event_output(struct perf_event *event,
Expand Down Expand Up @@ -7151,6 +7191,8 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
ret = -EINVAL;
}

if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
ret = perf_reg_validate(attr->sample_regs_intr);
out:
return ret;

Expand Down

0 comments on commit 60e2364

Please sign in to comment.