Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 323661
b: refs/heads/master
c: 4018994
h: refs/heads/master
i:
  323659: 38eb329
v: v3
  • Loading branch information
Jiri Olsa authored and Arnaldo Carvalho de Melo committed Aug 10, 2012
1 parent e6b1efe commit f4311ef
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 4 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: c5e63197db519bae1c33e41ea0342a50f39e7a93
refs/heads/master: 4018994f3d8785275ef0e7391b75c3462c029e56
15 changes: 15 additions & 0 deletions trunk/arch/x86/kernel/perf_regs.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/perf_event.h>
#include <linux/bug.h>
#include <linux/stddef.h>
#include <asm/perf_regs.h>
Expand Down Expand Up @@ -71,6 +73,11 @@ int perf_reg_validate(u64 mask)

return 0;
}

u64 perf_reg_abi(struct task_struct *task)
{
return PERF_SAMPLE_REGS_ABI_32;
}
#else /* CONFIG_X86_64 */
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
(1ULL << PERF_REG_X86_ES) | \
Expand All @@ -87,4 +94,12 @@ int perf_reg_validate(u64 mask)

return 0;
}

u64 perf_reg_abi(struct task_struct *task)
{
if (test_tsk_thread_flag(task, TIF_IA32))
return PERF_SAMPLE_REGS_ABI_32;
else
return PERF_SAMPLE_REGS_ABI_64;
}
#endif /* CONFIG_X86_32 */
35 changes: 32 additions & 3 deletions trunk/include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,9 @@ enum perf_event_sample_format {
PERF_SAMPLE_STREAM_ID = 1U << 9,
PERF_SAMPLE_RAW = 1U << 10,
PERF_SAMPLE_BRANCH_STACK = 1U << 11,
PERF_SAMPLE_REGS_USER = 1U << 12,

PERF_SAMPLE_MAX = 1U << 12, /* non-ABI */
PERF_SAMPLE_MAX = 1U << 13, /* non-ABI */
};

/*
Expand Down Expand Up @@ -162,6 +163,15 @@ enum perf_branch_sample_type {
PERF_SAMPLE_BRANCH_KERNEL|\
PERF_SAMPLE_BRANCH_HV)

/*
* Values to determine ABI of the registers dump.
*/
enum perf_sample_regs_abi {
PERF_SAMPLE_REGS_ABI_NONE = 0,
PERF_SAMPLE_REGS_ABI_32 = 1,
PERF_SAMPLE_REGS_ABI_64 = 2,
};

/*
* The format of the data returned by read() on a perf event fd,
* as specified by attr.read_format:
Expand Down Expand Up @@ -194,6 +204,7 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
#define PERF_ATTR_SIZE_VER3 88 /* add: sample_regs_user */

/*
* Hardware event_id to monitor via a performance monitoring event:
Expand Down Expand Up @@ -271,7 +282,13 @@ struct perf_event_attr {
__u64 bp_len;
__u64 config2; /* extension of config1 */
};
__u64 branch_sample_type; /* enum branch_sample_type */
__u64 branch_sample_type; /* enum perf_branch_sample_type */

/*
* Defines set of user regs to dump on samples.
* See asm/perf_regs.h for details.
*/
__u64 sample_regs_user;
};

/*
Expand Down Expand Up @@ -548,6 +565,9 @@ enum perf_event_type {
* char data[size];}&& PERF_SAMPLE_RAW
*
* { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
*
* { u64 abi; # enum perf_sample_regs_abi
* u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
* };
*/
PERF_RECORD_SAMPLE = 9,
Expand Down Expand Up @@ -609,6 +629,7 @@ struct perf_guest_info_callbacks {
#include <linux/static_key.h>
#include <linux/atomic.h>
#include <linux/sysfs.h>
#include <linux/perf_regs.h>
#include <asm/local.h>

struct perf_callchain_entry {
Expand Down Expand Up @@ -654,6 +675,11 @@ struct perf_branch_stack {
struct perf_branch_entry entries[0];
};

struct perf_regs_user {
__u64 abi;
struct pt_regs *regs;
};

struct task_struct;

/*
Expand Down Expand Up @@ -1133,6 +1159,7 @@ 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;
};

static inline void perf_sample_data_init(struct perf_sample_data *data,
Expand All @@ -1142,7 +1169,9 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
data->addr = addr;
data->raw = NULL;
data->br_stack = NULL;
data->period = period;
data->period = period;
data->regs_user.abi = PERF_SAMPLE_REGS_ABI_NONE;
data->regs_user.regs = NULL;
}

extern void perf_output_sample(struct perf_output_handle *handle,
Expand Down
6 changes: 6 additions & 0 deletions trunk/include/linux/perf_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <asm/perf_regs.h>
u64 perf_reg_value(struct pt_regs *regs, int idx);
int perf_reg_validate(u64 mask);
u64 perf_reg_abi(struct task_struct *task);
#else
static inline u64 perf_reg_value(struct pt_regs *regs, int idx)
{
Expand All @@ -15,5 +16,10 @@ static inline int perf_reg_validate(u64 mask)
{
return mask ? -ENOSYS : 0;
}

static inline u64 perf_reg_abi(struct task_struct *task)
{
return PERF_SAMPLE_REGS_ABI_NONE;
}
#endif /* CONFIG_HAVE_PERF_REGS */
#endif /* _LINUX_PERF_REGS_H */
66 changes: 66 additions & 0 deletions trunk/kernel/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -3756,6 +3756,37 @@ int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
}
EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);

static void
perf_output_sample_regs(struct perf_output_handle *handle,
struct pt_regs *regs, u64 mask)
{
int bit;

for_each_set_bit(bit, (const unsigned long *) &mask,
sizeof(mask) * BITS_PER_BYTE) {
u64 val;

val = perf_reg_value(regs, bit);
perf_output_put(handle, val);
}
}

static void perf_sample_regs_user(struct perf_regs_user *regs_user,
struct pt_regs *regs)
{
if (!user_mode(regs)) {
if (current->mm)
regs = task_pt_regs(current);
else
regs = NULL;
}

if (regs) {
regs_user->regs = regs;
regs_user->abi = perf_reg_abi(current);
}
}

static void __perf_event_header__init_id(struct perf_event_header *header,
struct perf_sample_data *data,
struct perf_event *event)
Expand Down Expand Up @@ -4016,6 +4047,23 @@ void perf_output_sample(struct perf_output_handle *handle,
perf_output_put(handle, nr);
}
}

if (sample_type & PERF_SAMPLE_REGS_USER) {
u64 abi = data->regs_user.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_user;
perf_output_sample_regs(handle,
data->regs_user.regs,
mask);
}
}
}

void perf_prepare_sample(struct perf_event_header *header,
Expand Down Expand Up @@ -4067,6 +4115,20 @@ void perf_prepare_sample(struct perf_event_header *header,
}
header->size += size;
}

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

perf_sample_regs_user(&data->regs_user, regs);

if (data->regs_user.regs) {
u64 mask = event->attr.sample_regs_user;
size += hweight64(mask) * sizeof(u64);
}

header->size += size;
}
}

static void perf_event_output(struct perf_event *event,
Expand Down Expand Up @@ -6142,6 +6204,10 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
attr->branch_sample_type = mask;
}
}

if (attr->sample_type & PERF_SAMPLE_REGS_USER)
ret = perf_reg_validate(attr->sample_regs_user);

out:
return ret;

Expand Down

0 comments on commit f4311ef

Please sign in to comment.