perf: add ability to sample interrupted machine state
Subsystems (2)
v3 cover perf: add ability to sample interrupted machine state
This short patch series add the ability to sample the interrupted machine state for each hardware sample. This is useful to analyze the state after certain events, for instance for function value profiling after a call instruction.
The patch extends the interface with a new PERF_SAMPLE_REGS_INTR smaple_type flag. The register to sample can be named in the sample_regs_intr bitmask for each event. The name and bit position for each register is architecture dependent and provided, just like for PERF_SAMPLE_REGS_USER by asm/perf_regs.h.
The support is similar to PERF_SAMPLE_REGS_USER.
On Intel x86, the series includes support for capturing the PEBS state as well. When precise sampling is used, the interrupted state is collect from the PEBS records, at least partially. The PEBS machine state is a subset of the machine state.
The series provides access to this new feature in perf record with the -I option. It is possible to display the sampled register values using perf report -D.
This patch series is the fundation for a future series adding function value profiling.
In V2, we address the issues raised during reviews:
- add sample parsing test
- shorten perf record option to --intr-regs
- added man page for perf record -I/--intr-regs option
- refactor register printf code between user and intr regs
- rebase to v3.16-rc3
In V3, we rebase to 3.16.0+ and made the modifications suggested by PeterZ. We also integrated his patch to improve the layout of perf_sample_data.
Peter Zijlstra (1):
perf: improve perf_sample_data struct layout
Stephane Eranian (5):
perf: add ability to sample machine state on interrupt perf/x86: add support for sampling PEBS machine state registers perf tools: add core support for sampling intr machine state regs perf/tests: add interrupted state sample parsing test perf record: add new -I option to sample interrupted machine state
arch/x86/kernel/cpu/perf_event_intel_ds.c | 17 +++++++++ include/linux/perf_event.h | 37 ++++++++++--------- include/uapi/linux/perf_event.h | 14 +++++++- kernel/events/core.c | 49 +++++++++++++++++++++++-- tools/perf/Documentation/perf-record.txt | 6 ++++ tools/perf/builtin-record.c | 2 ++ tools/perf/perf.h | 1 + tools/perf/tests/sample-parsing.c | 55 +++++++++++++++++++++-------- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 46 +++++++++++++++++++++++- tools/perf/util/session.c | 44 ++++++++++++++++++++--- 11 files changed, 230 insertions(+), 42 deletions(-)
Signature · 1 line
1.7.9.5
PATCH v3 1/6 perf: add ability to sample machine state on interrupt
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.
--- include/linux/perf_event.h | 7 +++++-- include/uapi/linux/perf_event.h | 14 ++++++++++++- kernel/events/core.c | 44 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 5 deletions(-)
include/linux/perf_event.h +5 -2
@@ -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; };
@@ -599,7 +599,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;/*
@@ -629,6 +630,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,
include/uapi/linux/perf_event.h +13 -1
@@ -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 */ };/*
@@ -334,6 +335,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))
@@ -686,6 +696,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,
kernel/events/core.c +42 -2
80 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Namhyung Kim
maintainerRe: [PATCH v3 1/6] perf: add ability to sample machine state on interrupt
Hi Stephane,
Quoted 15 lines · Stephane Eranian
Enable capture of interrupted machine state for each sample.
Registers to sample are passed per event in the
sample_regs_intrbitmask.To sample interrupt machine state, the
PERF_SAMPLE_INTR_REGSmust be passed insample_type.The list of available registers is arch dependent and provided by
asm/perf_regs.hRegisters are laid out as u64 in the order of the bit order of
sample_intr_regs.
[SNIP]
Quoted 4 lines
include/uapi/linux/perf_event.h +0
-0@@ -334,6 +335,15 @@ struct perf_event_attr {/* Align to u64. */ __u32 __reserved_2;
include/uapi/linux/perf_event.h struct perf_event_attr { · line 347
Quoted 10 lines
include/uapi/linux/perf_event.h +9
-0+/* +* 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; };
Hmm.. this increases the size of perf_event_attr. It seems you need to also define PERF_ATTR_SIZE_VER4 and update attr_file_abi_sizes.
Thanks,
Namhyung
PATCH v3 2/6 perf/x86: add support for sampling PEBS machine state registers
In reply to Stephane EranianPEBS can capture machine state regs at retiremnt of the sampled instructions. When precise sampling is enabled on an event, PEBS is used, so substitute the interrupted state with the PEBS state. Note that not all registers are captured by PEBS. Those missing are replaced by the interrupt state counter-parts.
--- arch/x86/kernel/cpu/perf_event_intel_ds.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
arch/x86/kernel/cpu/perf_event_intel_ds.c +17 -0
@@ -886,6 +886,23 @@ static void __intel_pmu_pebs_event(struct perf_event *event, regs.bp = pebs->bp; regs.sp = pebs->sp; +if (sample_type &PERF_SAMPLE_REGS_INTR ) { + regs.ax = pebs->ax; + regs.bx = pebs->bx; + regs.cx = pebs->cx; + regs.si = pebs->si; + regs.di = pebs->di; + + regs.r8 = pebs->r8; + regs.r9 = pebs->r9; + regs.r10 = pebs->r10; + regs.r11 = pebs->r11; + regs.r12 = pebs->r12; + regs.r13 = pebs->r13; + regs.r14 = pebs->r14; + regs.r14 = pebs->r15; + } +if (event->attr.precise_ip >1 && x86_pmu.intel_cap.pebs_format >=2 ) { regs.ip = pebs->real_ip; regs.flags |=PERF_EFLAGS_EXACT ;
Signature · 1 line
1.7.9.5
PATCH v3 3/6 perf tools: add core support for sampling intr machine state regs
In reply to Stephane EranianAdd the infrastructure to setup, collect and report the interrupt machine state regs which can be captured by the kernel.
--- tools/perf/perf.h | 1 + tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 46 ++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/session.c | 44 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 86 insertions(+), 6 deletions(-)
tools/perf/perf.h +1 -0
@@ -54,6 +54,7 @@ struct record_opts {bool sample_weight;bool sample_time;bool period; +bool sample_intr_regs;unsigned int freq;unsigned int mmap_pages;unsigned int user_freq;
tools/perf/util/event.h +1 -0
@@ -162,6 +162,7 @@ struct perf_sample {struct ip_callchain *callchain;struct branch_stack *branch_stack;struct regs_dump user_regs; +struct regs_dump intr_regs;struct stack_dump user_stack;struct sample_read read; };
tools/perf/util/evsel.c +45 -1
82 lines not on this page · raw message
tools/perf/util/session.c +39 -5
60 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH v3 4/6 perf/tests: add interrupted state sample parsing test
In reply to Stephane EranianThis patch updates the sample parsing test with support for the sampling of machine interrupted state.
The patch modifies the do_test() code to sahred the sample regts bitmask between user and intr regs.
--- tools/perf/tests/sample-parsing.c | 55 +++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-)
tools/perf/tests/sample-parsing.c +40 -15
@@ -126,16 +126,28 @@ static bool samples_same(const struct perf_sample *s1,if (type &PERF_SAMPLE_TRANSACTION )COMP (transaction); +if (type &PERF_SAMPLE_REGS_INTR ) { +size_t sz =hweight_long (s1->intr_regs.mask) *sizeof (u64); + +COMP (intr_regs.mask); +COMP (intr_regs.abi); +if (s1->intr_regs.abi && + (!s1->intr_regs.regs || !s2->intr_regs.regs || +memcmp (s1->intr_regs.regs, s2->intr_regs.regs, sz))) { +pr_debug ("Samples differ at 'intr_regs'\n" ); +return false; + } + } +return true; } -static int do_test (u64 sample_type,u64 sample_regs_user,u64 read_format) +static int do_test (u64 sample_type,u64 sample_regs,u64 read_format) {struct perf_evsel evsel = { .needs_swap = false, .attr = { .sample_type = sample_type, - .sample_regs_user = sample_regs_user, .read_format = read_format, }, };
@@ -154,7 +166,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)/* 1 branch_entry */ .data = {1, 211, 212, 213}, }; -u64 user_regs[64 ]; +u64 regs[64 ];const u64 raw_data[] = {0x123456780a0b0c0dULL ,0x1102030405060708ULL };const u64 data[] = {0x2211443366558877ULL ,0 ,0xaabbccddeeff4321ULL }; struct perf_sample sample = {
@@ -176,8 +188,8 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) .branch_stack = &branch_stack.branch_stack, .user_regs = { .abi = PERF_SAMPLE_REGS_ABI_64, - .mask = sample_regs_user, - .regs = user_regs, + .mask = sample_regs, + .regs = regs, }, .user_stack = { .size = sizeof(data),
@@ -187,14 +199,25 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) .time_enabled = 0x030a59d664fca7deULL, .time_running = 0x011b6ae553eb98edULL, }, + .intr_regs = { + .abi = PERF_SAMPLE_REGS_ABI_64, + .mask = sample_regs, + .regs = regs, + }, };struct sample_read_value values[] = {{1 ,5 }, {9 ,3 }, {2 ,7 }, {6 ,4 },};struct perf_sample sample_out;size_t i, sz, bufsz;int err, ret =-1 ; -for (i =0 ; i <sizeof (user_regs); i++) - *(i + (u8 *)user_regs) = i &0xfe ; +if (sample_type &PERF_SAMPLE_REGS_USER ) + evsel.attr.sample_regs_user = sample_regs; + +if (sample_type &PERF_SAMPLE_REGS_INTR ) + evsel.attr.sample_regs_intr = sample_regs; + +for (i =0 ; i <sizeof (regs); i++) + *(i + (u8 *)regs) = i &0xfe ;if (read_format &PERF_FORMAT_GROUP ) { sample.read.group.nr =4 ;
@@ -271,7 +294,7 @@ int test__sample_parsing(void) {const u64 rf[] = {4 ,5 ,6 ,7 ,12 ,13 ,14 ,15 };u64 sample_type; -u64 sample_regs_user; +u64 sample_regs;size_t i;int err;
@@ -280,7 +303,7 @@ int test__sample_parsing(void)* were added. Please actually update the test rather than just change * the condition below. */ -if (PERF_SAMPLE_MAX >PERF_SAMPLE_TRANSACTION <<1 ) { +if (PERF_SAMPLE_MAX >PERF_SAMPLE_REGS_INTR <<1 ) {pr_debug ("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n" );return -1 ; }
@@ -297,22 +320,24 @@ int test__sample_parsing(void) }continue ; } + sample_regs =0 ;if (sample_type ==PERF_SAMPLE_REGS_USER ) - sample_regs_user =0x3fff ; -else - sample_regs_user =0 ; + sample_regs =0x3fff ; + +if (sample_type ==PERF_SAMPLE_REGS_INTR ) + sample_regs =0xff0fff ; - err =do_test (sample_type, sample_regs_user,0 ); + err =do_test (sample_type, sample_regs,0 );if (err)return err; }/* Test all sample format bits together */ sample_type =PERF_SAMPLE_MAX -1 ; - sample_regs_user =0x3fff ; + sample_regs =0x3fff ;/* shared yb intr and user regs */ for (i =0 ; i <ARRAY_SIZE (rf); i++) { - err =do_test (sample_type, sample_regs_user, rf[i]); + err =do_test (sample_type, sample_regs, rf[i]);if (err)return err; }
Signature · 1 line
1.7.9.5
PATCH v3 5/6 perf record: add new -I option to sample interrupted machine state
In reply to Stephane EranianAdd -I/--intr-regs option to capture machine state registers at interrupt.
Add the corresponding man page description
--- tools/perf/Documentation/perf-record.txt | 6 ++++++ tools/perf/builtin-record.c | 2 ++ 2 files changed, 8 insertions(+)
tools/perf/Documentation/perf-record.txt +6 -0
@@ -214,6 +214,12 @@ if combined with -a or -C options. After starting the program, wait msecs before measuring. This is useful to filter out the startup phase of the program, which is often very different. +-I:: +--intr-regs:: +Capture machine state (registers) at interrupt, i.e., on counter overflows for +each sample. List of captured registers depends on the architecture. This option +is off by default. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1]
tools/perf/builtin-record.c +2 -0
@@ -882,6 +882,8 @@ const struct option record_options[] = { "sample transaction flags (special events only)"),OPT_BOOLEAN (0 ,"per-thread" , &record.opts.target.per_thread,"use per-thread mmaps" ), +OPT_BOOLEAN ('I' ,"intr-regs" , &record.opts.sample_intr_regs, +"Sample machine registers on interrupt" ), OPT_END() };
Signature · 1 line
1.7.9.5
PATCH v3 6/6 perf: improve perf_sample_data struct layout
In reply to Stephane EranianFrom: Peter Zijlstra <[email protected]>
This patch reorders fields in the perf_sample_data struct in order to minimize the number of cachelines touched in perf_sample_data_init(). It also removes some intializations which are redundant with the code in kernel/events/core.c
--- include/linux/perf_event.h | 34 +++++++++++++++++----------------- kernel/events/core.c | 5 ++++- 2 files changed, 21 insertions(+), 18 deletions(-)
include/linux/perf_event.h +17 -17
@@ -579,35 +579,40 @@ extern u64 perf_event_read_value(struct perf_event *event,struct perf_sample_data { -u64 type; +/* +* Fields set by perf_sample_data_init(), group so as to +* minimize the cachelines touched. +*/ +u64 addr; +struct perf_raw_record *raw; +struct perf_branch_stack *br_stack; +u64 period; +u64 weight; +u64 txn; +union perf_mem_data_src data_src; +/* +* The other fields, optionally {set,used} by +* perf_{prepare,output}_sample(). +*/ +u64 type;u64 ip;struct {u32 pid;u32 tid; } tid_entry;u64 time; -u64 addr;u64 id;u64 stream_id;struct {u32 cpu;u32 reserved; } cpu_entry; -u64 period; -union perf_mem_data_src data_src;struct perf_callchain_entry *callchain; -struct perf_raw_record *raw; -struct perf_branch_stack *br_stack;struct perf_regs regs_user;struct perf_regs regs_intr;u64 stack_user_size; -u64 weight; -/* -* Transaction flags for abort events: -*/ -u64 txn; -}; +}____cacheline_aligned ;/* default value for data source */ #define PERF_MEM_NA (PERF_MEM_S(OP, NA) |\
@@ -624,14 +629,9 @@ static inline void perf_sample_data_init(struct perf_sample_data *data, data->raw =NULL ; data->br_stack =NULL ; data->period = period; - data->regs_user.abi =PERF_SAMPLE_REGS_ABI_NONE ; - data->regs_user.regs =NULL ; - data->stack_user_size =0 ; 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,
kernel/events/core.c +4 -1
@@ -4406,8 +4406,11 @@ static void perf_sample_regs_user(struct perf_regs *regs_user, }if (regs) { - regs_user->regs = regs; regs_user->abi =perf_reg_abi (current); + regs_user->regs = regs; + }else { + regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ; + regs_user->regs =NULL ; } }
Signature · 1 line
1.7.9.5
Hi,
Quoted 40 lines · Stephane Eranian
This short patch series add the ability to sample the interrupted machine state for each hardware sample. This is useful to analyze the state after certain events, for instance for function value profiling after a call instruction.
The patch extends the interface with a new
PERF_SAMPLE_REGS_INTRsmaple_typeflag. The register to sample can be named in thesample_regs_intrbitmask for each event. The name and bit position for each register is architecture dependent and provided, just like forPERF_SAMPLE_REGS_USERbyasm/perf_regs.h.The support is similar to
PERF_SAMPLE_REGS_USER.On Intel x86, the series includes support for capturing the PEBS state as well. When precise sampling is used, the interrupted state is collect from the PEBS records, at least partially. The PEBS machine state is a subset of the machine state.
The series provides access to this new feature in perf record with the -I option. It is possible to display the sampled register values using perf report -D.
This patch series is the fundation for a future series adding function value profiling.
In V2, we address the issues raised during reviews:
- add sample parsing test
- shorten perf record option to --intr-regs
- added man page for perf record -I/--intr-regs option
- refactor register printf code between user and intr regs
- rebase to v3.16-rc3In V3, we rebase to 3.16.0+ and made the modifications suggested by PeterZ. We also integrated his patch to improve the layout of
perf_sample_data.Peter Zijlstra (1):
perf: improveperf_sample_datastruct layout
Quoted 7 lines
Stephane Eranian (5):
perf: add ability to sample machine state on interrupt perf/x86: add support for sampling PEBS machine state registers perf tools: add core support for sampling intr machine state regs perf/tests: add interrupted state sample parsing test perf record: add new -I option to sample interrupted machine state
any comment on this updated series?
Quoted 16 lines
arch/x86/kernel/cpu/perf_event_intel_ds.c | 17 +++++++++ include/linux/perf_event.h | 37 ++++++++++--------- include/uapi/linux/perf_event.h | 14 +++++++- kernel/events/core.c | 49 +++++++++++++++++++++++-- tools/perf/Documentation/perf-record.txt | 6 ++++ tools/perf/builtin-record.c | 2 ++ tools/perf/perf.h | 1 + tools/perf/tests/sample-parsing.c | 55 +++++++++++++++++++++-------- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 46 +++++++++++++++++++++++- tools/perf/util/session.c | 44 ++++++++++++++++++++--- 11 files changed, 230 insertions(+), 42 deletions(-)--
1.7.9.5