Skip to content

Commit ef21831

Browse files
committed
Merge tag 'perf_urgent_for_v6.4_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Borislav Petkov: - Make sure the PEBS buffer is flushed before reprogramming the hardware so that the correct record sizes are used - Update the sample size for AMD BRS events - Fix a confusion with using the same on-stack struct with different events in the event processing path * tag 'perf_urgent_for_v6.4_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf/x86/intel/ds: Flush PEBS DS when changing PEBS_DATA_CFG perf/x86: Fix missing sample size update on AMD BRS perf/core: Fix perf_sample_data not properly initialized for different swevents in perf_tp_event()
2 parents f3b9e8e + b752ea0 commit ef21831

File tree

4 files changed

+50
-29
lines changed

4 files changed

+50
-29
lines changed

arch/x86/events/core.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,10 +1703,8 @@ int x86_pmu_handle_irq(struct pt_regs *regs)
17031703

17041704
perf_sample_data_init(&data, 0, event->hw.last_period);
17051705

1706-
if (has_branch_stack(event)) {
1707-
data.br_stack = &cpuc->lbr_stack;
1708-
data.sample_flags |= PERF_SAMPLE_BRANCH_STACK;
1709-
}
1706+
if (has_branch_stack(event))
1707+
perf_sample_save_brstack(&data, event, &cpuc->lbr_stack);
17101708

17111709
if (perf_event_overflow(event, &data, regs))
17121710
x86_pmu_stop(event, 0);

arch/x86/events/intel/ds.c

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,20 +1229,22 @@ pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc,
12291229
struct perf_event *event, bool add)
12301230
{
12311231
struct pmu *pmu = event->pmu;
1232+
12321233
/*
12331234
* Make sure we get updated with the first PEBS
12341235
* event. It will trigger also during removal, but
12351236
* that does not hurt:
12361237
*/
1237-
bool update = cpuc->n_pebs == 1;
1238+
if (cpuc->n_pebs == 1)
1239+
cpuc->pebs_data_cfg = PEBS_UPDATE_DS_SW;
12381240

12391241
if (needed_cb != pebs_needs_sched_cb(cpuc)) {
12401242
if (!needed_cb)
12411243
perf_sched_cb_inc(pmu);
12421244
else
12431245
perf_sched_cb_dec(pmu);
12441246

1245-
update = true;
1247+
cpuc->pebs_data_cfg |= PEBS_UPDATE_DS_SW;
12461248
}
12471249

12481250
/*
@@ -1252,24 +1254,13 @@ pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc,
12521254
if (x86_pmu.intel_cap.pebs_baseline && add) {
12531255
u64 pebs_data_cfg;
12541256

1255-
/* Clear pebs_data_cfg and pebs_record_size for first PEBS. */
1256-
if (cpuc->n_pebs == 1) {
1257-
cpuc->pebs_data_cfg = 0;
1258-
cpuc->pebs_record_size = sizeof(struct pebs_basic);
1259-
}
1260-
12611257
pebs_data_cfg = pebs_update_adaptive_cfg(event);
1262-
1263-
/* Update pebs_record_size if new event requires more data. */
1264-
if (pebs_data_cfg & ~cpuc->pebs_data_cfg) {
1265-
cpuc->pebs_data_cfg |= pebs_data_cfg;
1266-
adaptive_pebs_record_size_update();
1267-
update = true;
1268-
}
1258+
/*
1259+
* Be sure to update the thresholds when we change the record.
1260+
*/
1261+
if (pebs_data_cfg & ~cpuc->pebs_data_cfg)
1262+
cpuc->pebs_data_cfg |= pebs_data_cfg | PEBS_UPDATE_DS_SW;
12691263
}
1270-
1271-
if (update)
1272-
pebs_update_threshold(cpuc);
12731264
}
12741265

12751266
void intel_pmu_pebs_add(struct perf_event *event)
@@ -1326,9 +1317,17 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
13261317
wrmsrl(base + idx, value);
13271318
}
13281319

1320+
static inline void intel_pmu_drain_large_pebs(struct cpu_hw_events *cpuc)
1321+
{
1322+
if (cpuc->n_pebs == cpuc->n_large_pebs &&
1323+
cpuc->n_pebs != cpuc->n_pebs_via_pt)
1324+
intel_pmu_drain_pebs_buffer();
1325+
}
1326+
13291327
void intel_pmu_pebs_enable(struct perf_event *event)
13301328
{
13311329
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
1330+
u64 pebs_data_cfg = cpuc->pebs_data_cfg & ~PEBS_UPDATE_DS_SW;
13321331
struct hw_perf_event *hwc = &event->hw;
13331332
struct debug_store *ds = cpuc->ds;
13341333
unsigned int idx = hwc->idx;
@@ -1344,11 +1343,22 @@ void intel_pmu_pebs_enable(struct perf_event *event)
13441343

13451344
if (x86_pmu.intel_cap.pebs_baseline) {
13461345
hwc->config |= ICL_EVENTSEL_ADAPTIVE;
1347-
if (cpuc->pebs_data_cfg != cpuc->active_pebs_data_cfg) {
1348-
wrmsrl(MSR_PEBS_DATA_CFG, cpuc->pebs_data_cfg);
1349-
cpuc->active_pebs_data_cfg = cpuc->pebs_data_cfg;
1346+
if (pebs_data_cfg != cpuc->active_pebs_data_cfg) {
1347+
/*
1348+
* drain_pebs() assumes uniform record size;
1349+
* hence we need to drain when changing said
1350+
* size.
1351+
*/
1352+
intel_pmu_drain_large_pebs(cpuc);
1353+
adaptive_pebs_record_size_update();
1354+
wrmsrl(MSR_PEBS_DATA_CFG, pebs_data_cfg);
1355+
cpuc->active_pebs_data_cfg = pebs_data_cfg;
13501356
}
13511357
}
1358+
if (cpuc->pebs_data_cfg & PEBS_UPDATE_DS_SW) {
1359+
cpuc->pebs_data_cfg = pebs_data_cfg;
1360+
pebs_update_threshold(cpuc);
1361+
}
13521362

13531363
if (idx >= INTEL_PMC_IDX_FIXED) {
13541364
if (x86_pmu.intel_cap.pebs_format < 5)
@@ -1391,9 +1401,7 @@ void intel_pmu_pebs_disable(struct perf_event *event)
13911401
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
13921402
struct hw_perf_event *hwc = &event->hw;
13931403

1394-
if (cpuc->n_pebs == cpuc->n_large_pebs &&
1395-
cpuc->n_pebs != cpuc->n_pebs_via_pt)
1396-
intel_pmu_drain_pebs_buffer();
1404+
intel_pmu_drain_large_pebs(cpuc);
13971405

13981406
cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
13991407

arch/x86/include/asm/perf_event.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@
121121
#define PEBS_DATACFG_LBRS BIT_ULL(3)
122122
#define PEBS_DATACFG_LBR_SHIFT 24
123123

124+
/* Steal the highest bit of pebs_data_cfg for SW usage */
125+
#define PEBS_UPDATE_DS_SW BIT_ULL(63)
126+
124127
/*
125128
* Intel "Architectural Performance Monitoring" CPUID
126129
* detection/enumeration details:

kernel/events/core.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10150,8 +10150,20 @@ void perf_tp_event(u16 event_type, u64 count, void *record, int entry_size,
1015010150
perf_trace_buf_update(record, event_type);
1015110151

1015210152
hlist_for_each_entry_rcu(event, head, hlist_entry) {
10153-
if (perf_tp_event_match(event, &data, regs))
10153+
if (perf_tp_event_match(event, &data, regs)) {
1015410154
perf_swevent_event(event, count, &data, regs);
10155+
10156+
/*
10157+
* Here use the same on-stack perf_sample_data,
10158+
* some members in data are event-specific and
10159+
* need to be re-computed for different sweveents.
10160+
* Re-initialize data->sample_flags safely to avoid
10161+
* the problem that next event skips preparing data
10162+
* because data->sample_flags is set.
10163+
*/
10164+
perf_sample_data_init(&data, 0, 0);
10165+
perf_sample_save_raw_data(&data, &raw);
10166+
}
1015510167
}
1015610168

1015710169
/*

0 commit comments

Comments
 (0)