Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit bb447c2

Browse files
namhyungIngo Molnar
authored andcommitted
perf/core: Set data->sample_flags in perf_prepare_sample()
The perf_prepare_sample() function sets the perf_sample_data according to the attr->sample_type before copying it to the ring buffer. But BPF also wants to access the sample data so it needs to prepare the sample even before the regular path. That means perf_prepare_sample() can be called more than once. Set the data->sample_flags consistently so that it can indicate which fields are set already and skip them if sets. Also update the filtered_sample_type to have the dependent flags to reduce the number of branches. Suggested-by: Peter Zijlstra <[email protected]> Signed-off-by: Namhyung Kim <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Tested-by: Jiri Olsa <[email protected]> Acked-by: Jiri Olsa <[email protected]> Acked-by: Peter Zijlstra <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent eb55b45 commit bb447c2

File tree

1 file changed

+65
-20
lines changed

1 file changed

+65
-20
lines changed

kernel/events/core.c

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7046,12 +7046,21 @@ static void perf_aux_sample_output(struct perf_event *event,
70467046
ring_buffer_put(rb);
70477047
}
70487048

7049+
/*
7050+
* A set of common sample data types saved even for non-sample records
7051+
* when event->attr.sample_id_all is set.
7052+
*/
7053+
#define PERF_SAMPLE_ID_ALL (PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \
7054+
PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
7055+
PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER)
7056+
70497057
static void __perf_event_header__init_id(struct perf_event_header *header,
70507058
struct perf_sample_data *data,
70517059
struct perf_event *event,
70527060
u64 sample_type)
70537061
{
70547062
data->type = event->attr.sample_type;
7063+
data->sample_flags |= data->type & PERF_SAMPLE_ID_ALL;
70557064
header->size += event->id_header_size;
70567065

70577066
if (sample_type & PERF_SAMPLE_TID) {
@@ -7554,6 +7563,11 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)
75547563
return callchain ?: &__empty_callchain;
75557564
}
75567565

7566+
static __always_inline u64 __cond_set(u64 flags, u64 s, u64 d)
7567+
{
7568+
return d * !!(flags & s);
7569+
}
7570+
75577571
void perf_prepare_sample(struct perf_event_header *header,
75587572
struct perf_sample_data *data,
75597573
struct perf_event *event,
@@ -7569,14 +7583,24 @@ void perf_prepare_sample(struct perf_event_header *header,
75697583
header->misc |= perf_misc_flags(regs);
75707584

75717585
/*
7572-
* Clear the sample flags that have already been done by the
7573-
* PMU driver.
7586+
* Add the sample flags that are dependent to others. And clear the
7587+
* sample flags that have already been done by the PMU driver.
75747588
*/
7575-
filtered_sample_type = sample_type & ~data->sample_flags;
7589+
filtered_sample_type = sample_type;
7590+
filtered_sample_type |= __cond_set(sample_type, PERF_SAMPLE_CODE_PAGE_SIZE,
7591+
PERF_SAMPLE_IP);
7592+
filtered_sample_type |= __cond_set(sample_type, PERF_SAMPLE_DATA_PAGE_SIZE |
7593+
PERF_SAMPLE_PHYS_ADDR, PERF_SAMPLE_ADDR);
7594+
filtered_sample_type |= __cond_set(sample_type, PERF_SAMPLE_STACK_USER,
7595+
PERF_SAMPLE_REGS_USER);
7596+
filtered_sample_type &= ~data->sample_flags;
7597+
75767598
__perf_event_header__init_id(header, data, event, filtered_sample_type);
75777599

7578-
if (sample_type & (PERF_SAMPLE_IP | PERF_SAMPLE_CODE_PAGE_SIZE))
7600+
if (filtered_sample_type & PERF_SAMPLE_IP) {
75797601
data->ip = perf_instruction_pointer(regs);
7602+
data->sample_flags |= PERF_SAMPLE_IP;
7603+
}
75807604

75817605
if (filtered_sample_type & PERF_SAMPLE_CALLCHAIN)
75827606
perf_sample_save_callchain(data, event, regs);
@@ -7593,10 +7617,15 @@ void perf_prepare_sample(struct perf_event_header *header,
75937617
data->sample_flags |= PERF_SAMPLE_BRANCH_STACK;
75947618
}
75957619

7596-
if (sample_type & (PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER))
7620+
if (filtered_sample_type & PERF_SAMPLE_REGS_USER)
75977621
perf_sample_regs_user(&data->regs_user, regs);
75987622

7599-
if (sample_type & PERF_SAMPLE_REGS_USER) {
7623+
/*
7624+
* It cannot use the filtered_sample_type here as REGS_USER can be set
7625+
* by STACK_USER (using __cond_set() above) and we don't want to update
7626+
* the dyn_size if it's not requested by users.
7627+
*/
7628+
if ((sample_type & ~data->sample_flags) & PERF_SAMPLE_REGS_USER) {
76007629
/* regs dump ABI info */
76017630
int size = sizeof(u64);
76027631

@@ -7606,9 +7635,10 @@ void perf_prepare_sample(struct perf_event_header *header,
76067635
}
76077636

76087637
data->dyn_size += size;
7638+
data->sample_flags |= PERF_SAMPLE_REGS_USER;
76097639
}
76107640

7611-
if (sample_type & PERF_SAMPLE_STACK_USER) {
7641+
if (filtered_sample_type & PERF_SAMPLE_STACK_USER) {
76127642
/*
76137643
* Either we need PERF_SAMPLE_STACK_USER bit to be always
76147644
* processed as the last one or have additional check added
@@ -7631,23 +7661,30 @@ void perf_prepare_sample(struct perf_event_header *header,
76317661

76327662
data->stack_user_size = stack_size;
76337663
data->dyn_size += size;
7664+
data->sample_flags |= PERF_SAMPLE_STACK_USER;
76347665
}
76357666

7636-
if (filtered_sample_type & PERF_SAMPLE_WEIGHT_TYPE)
7667+
if (filtered_sample_type & PERF_SAMPLE_WEIGHT_TYPE) {
76377668
data->weight.full = 0;
7669+
data->sample_flags |= PERF_SAMPLE_WEIGHT_TYPE;
7670+
}
76387671

7639-
if (filtered_sample_type & PERF_SAMPLE_DATA_SRC)
7672+
if (filtered_sample_type & PERF_SAMPLE_DATA_SRC) {
76407673
data->data_src.val = PERF_MEM_NA;
7674+
data->sample_flags |= PERF_SAMPLE_DATA_SRC;
7675+
}
76417676

7642-
if (filtered_sample_type & PERF_SAMPLE_TRANSACTION)
7677+
if (filtered_sample_type & PERF_SAMPLE_TRANSACTION) {
76437678
data->txn = 0;
7679+
data->sample_flags |= PERF_SAMPLE_TRANSACTION;
7680+
}
76447681

7645-
if (sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR | PERF_SAMPLE_DATA_PAGE_SIZE)) {
7646-
if (filtered_sample_type & PERF_SAMPLE_ADDR)
7647-
data->addr = 0;
7682+
if (filtered_sample_type & PERF_SAMPLE_ADDR) {
7683+
data->addr = 0;
7684+
data->sample_flags |= PERF_SAMPLE_ADDR;
76487685
}
76497686

7650-
if (sample_type & PERF_SAMPLE_REGS_INTR) {
7687+
if (filtered_sample_type & PERF_SAMPLE_REGS_INTR) {
76517688
/* regs dump ABI info */
76527689
int size = sizeof(u64);
76537690

@@ -7660,19 +7697,22 @@ void perf_prepare_sample(struct perf_event_header *header,
76607697
}
76617698

76627699
data->dyn_size += size;
7700+
data->sample_flags |= PERF_SAMPLE_REGS_INTR;
76637701
}
76647702

7665-
if (sample_type & PERF_SAMPLE_PHYS_ADDR &&
7666-
filtered_sample_type & PERF_SAMPLE_PHYS_ADDR)
7703+
if (filtered_sample_type & PERF_SAMPLE_PHYS_ADDR) {
76677704
data->phys_addr = perf_virt_to_phys(data->addr);
7705+
data->sample_flags |= PERF_SAMPLE_PHYS_ADDR;
7706+
}
76687707

76697708
#ifdef CONFIG_CGROUP_PERF
7670-
if (sample_type & PERF_SAMPLE_CGROUP) {
7709+
if (filtered_sample_type & PERF_SAMPLE_CGROUP) {
76717710
struct cgroup *cgrp;
76727711

76737712
/* protected by RCU */
76747713
cgrp = task_css_check(current, perf_event_cgrp_id, 1)->cgroup;
76757714
data->cgroup = cgroup_id(cgrp);
7715+
data->sample_flags |= PERF_SAMPLE_CGROUP;
76767716
}
76777717
#endif
76787718

@@ -7681,13 +7721,17 @@ void perf_prepare_sample(struct perf_event_header *header,
76817721
* require PERF_SAMPLE_ADDR, kernel implicitly retrieve the data->addr,
76827722
* but the value will not dump to the userspace.
76837723
*/
7684-
if (sample_type & PERF_SAMPLE_DATA_PAGE_SIZE)
7724+
if (filtered_sample_type & PERF_SAMPLE_DATA_PAGE_SIZE) {
76857725
data->data_page_size = perf_get_page_size(data->addr);
7726+
data->sample_flags |= PERF_SAMPLE_DATA_PAGE_SIZE;
7727+
}
76867728

7687-
if (sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)
7729+
if (filtered_sample_type & PERF_SAMPLE_CODE_PAGE_SIZE) {
76887730
data->code_page_size = perf_get_page_size(data->ip);
7731+
data->sample_flags |= PERF_SAMPLE_CODE_PAGE_SIZE;
7732+
}
76897733

7690-
if (sample_type & PERF_SAMPLE_AUX) {
7734+
if (filtered_sample_type & PERF_SAMPLE_AUX) {
76917735
u64 size;
76927736

76937737
header->size += sizeof(u64); /* size */
@@ -7705,6 +7749,7 @@ void perf_prepare_sample(struct perf_event_header *header,
77057749

77067750
WARN_ON_ONCE(size + header->size > U16_MAX);
77077751
data->dyn_size += size + sizeof(u64); /* size above */
7752+
data->sample_flags |= PERF_SAMPLE_AUX;
77087753
}
77097754

77107755
header->size += data->dyn_size;

0 commit comments

Comments
 (0)