Skip to content

Commit d21954c

Browse files
Dapeng MiPeter Zijlstra
authored andcommitted
perf/x86/intel: Process arch-PEBS records or record fragments
A significant difference with adaptive PEBS is that arch-PEBS record supports fragments which means an arch-PEBS record could be split into several independent fragments which have its own arch-PEBS header in each fragment. This patch defines architectural PEBS record layout structures and add helpers to process arch-PEBS records or fragments. Only legacy PEBS groups like basic, GPR, XMM and LBR groups are supported in this patch, the new added YMM/ZMM/OPMASK vector registers capturing would be supported in the future. Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20251029102136.61364-9-dapeng1.mi@linux.intel.com
1 parent 167cde7 commit d21954c

4 files changed

Lines changed: 299 additions & 0 deletions

File tree

arch/x86/events/intel/core.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3215,6 +3215,19 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
32153215
status &= ~GLOBAL_STATUS_PERF_METRICS_OVF_BIT;
32163216
}
32173217

3218+
/*
3219+
* Arch PEBS sets bit 54 in the global status register
3220+
*/
3221+
if (__test_and_clear_bit(GLOBAL_STATUS_ARCH_PEBS_THRESHOLD_BIT,
3222+
(unsigned long *)&status)) {
3223+
handled++;
3224+
static_call(x86_pmu_drain_pebs)(regs, &data);
3225+
3226+
if (cpuc->events[INTEL_PMC_IDX_FIXED_SLOTS] &&
3227+
is_pebs_counter_event_group(cpuc->events[INTEL_PMC_IDX_FIXED_SLOTS]))
3228+
status &= ~GLOBAL_STATUS_PERF_METRICS_OVF_BIT;
3229+
}
3230+
32183231
/*
32193232
* Intel PT
32203233
*/

arch/x86/events/intel/ds.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,117 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event,
22702270
format_group);
22712271
}
22722272

2273+
static inline bool arch_pebs_record_continued(struct arch_pebs_header *header)
2274+
{
2275+
/* Continue bit or null PEBS record indicates fragment follows. */
2276+
return header->cont || !(header->format & GENMASK_ULL(63, 16));
2277+
}
2278+
2279+
static void setup_arch_pebs_sample_data(struct perf_event *event,
2280+
struct pt_regs *iregs,
2281+
void *__pebs,
2282+
struct perf_sample_data *data,
2283+
struct pt_regs *regs)
2284+
{
2285+
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
2286+
u64 sample_type = event->attr.sample_type;
2287+
struct arch_pebs_header *header = NULL;
2288+
struct arch_pebs_aux *meminfo = NULL;
2289+
struct arch_pebs_gprs *gprs = NULL;
2290+
struct x86_perf_regs *perf_regs;
2291+
void *next_record;
2292+
void *at = __pebs;
2293+
2294+
if (at == NULL)
2295+
return;
2296+
2297+
perf_regs = container_of(regs, struct x86_perf_regs, regs);
2298+
perf_regs->xmm_regs = NULL;
2299+
2300+
__setup_perf_sample_data(event, iregs, data);
2301+
2302+
*regs = *iregs;
2303+
2304+
again:
2305+
header = at;
2306+
next_record = at + sizeof(struct arch_pebs_header);
2307+
if (header->basic) {
2308+
struct arch_pebs_basic *basic = next_record;
2309+
u16 retire = 0;
2310+
2311+
next_record = basic + 1;
2312+
2313+
if (sample_type & PERF_SAMPLE_WEIGHT_STRUCT)
2314+
retire = basic->valid ? basic->retire : 0;
2315+
__setup_pebs_basic_group(event, regs, data, sample_type,
2316+
basic->ip, basic->tsc, retire);
2317+
}
2318+
2319+
/*
2320+
* The record for MEMINFO is in front of GP
2321+
* But PERF_SAMPLE_TRANSACTION needs gprs->ax.
2322+
* Save the pointer here but process later.
2323+
*/
2324+
if (header->aux) {
2325+
meminfo = next_record;
2326+
next_record = meminfo + 1;
2327+
}
2328+
2329+
if (header->gpr) {
2330+
gprs = next_record;
2331+
next_record = gprs + 1;
2332+
2333+
__setup_pebs_gpr_group(event, regs,
2334+
(struct pebs_gprs *)gprs,
2335+
sample_type);
2336+
}
2337+
2338+
if (header->aux) {
2339+
u64 ax = gprs ? gprs->ax : 0;
2340+
2341+
__setup_pebs_meminfo_group(event, data, sample_type,
2342+
meminfo->cache_latency,
2343+
meminfo->instr_latency,
2344+
meminfo->address, meminfo->aux,
2345+
meminfo->tsx_tuning, ax);
2346+
}
2347+
2348+
if (header->xmm) {
2349+
struct pebs_xmm *xmm;
2350+
2351+
next_record += sizeof(struct arch_pebs_xer_header);
2352+
2353+
xmm = next_record;
2354+
perf_regs->xmm_regs = xmm->xmm;
2355+
next_record = xmm + 1;
2356+
}
2357+
2358+
if (header->lbr) {
2359+
struct arch_pebs_lbr_header *lbr_header = next_record;
2360+
struct lbr_entry *lbr;
2361+
int num_lbr;
2362+
2363+
next_record = lbr_header + 1;
2364+
lbr = next_record;
2365+
2366+
num_lbr = header->lbr == ARCH_PEBS_LBR_NUM_VAR ?
2367+
lbr_header->depth :
2368+
header->lbr * ARCH_PEBS_BASE_LBR_ENTRIES;
2369+
next_record += num_lbr * sizeof(struct lbr_entry);
2370+
2371+
if (has_branch_stack(event)) {
2372+
intel_pmu_store_pebs_lbrs(lbr);
2373+
intel_pmu_lbr_save_brstack(data, cpuc, event);
2374+
}
2375+
}
2376+
2377+
/* Parse followed fragments if there are. */
2378+
if (arch_pebs_record_continued(header)) {
2379+
at = at + header->size;
2380+
goto again;
2381+
}
2382+
}
2383+
22732384
static inline void *
22742385
get_next_pebs_record_by_bit(void *base, void *top, int bit)
22752386
{
@@ -2753,6 +2864,78 @@ static void intel_pmu_drain_pebs_icl(struct pt_regs *iregs, struct perf_sample_d
27532864
setup_pebs_adaptive_sample_data);
27542865
}
27552866

2867+
static void intel_pmu_drain_arch_pebs(struct pt_regs *iregs,
2868+
struct perf_sample_data *data)
2869+
{
2870+
short counts[INTEL_PMC_IDX_FIXED + MAX_FIXED_PEBS_EVENTS] = {};
2871+
void *last[INTEL_PMC_IDX_FIXED + MAX_FIXED_PEBS_EVENTS];
2872+
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
2873+
union arch_pebs_index index;
2874+
struct x86_perf_regs perf_regs;
2875+
struct pt_regs *regs = &perf_regs.regs;
2876+
void *base, *at, *top;
2877+
u64 mask;
2878+
2879+
rdmsrq(MSR_IA32_PEBS_INDEX, index.whole);
2880+
2881+
if (unlikely(!index.wr)) {
2882+
intel_pmu_pebs_event_update_no_drain(cpuc, X86_PMC_IDX_MAX);
2883+
return;
2884+
}
2885+
2886+
base = cpuc->ds_pebs_vaddr;
2887+
top = (void *)((u64)cpuc->ds_pebs_vaddr +
2888+
(index.wr << ARCH_PEBS_INDEX_WR_SHIFT));
2889+
2890+
index.wr = 0;
2891+
index.full = 0;
2892+
wrmsrq(MSR_IA32_PEBS_INDEX, index.whole);
2893+
2894+
mask = hybrid(cpuc->pmu, arch_pebs_cap).counters & cpuc->pebs_enabled;
2895+
2896+
if (!iregs)
2897+
iregs = &dummy_iregs;
2898+
2899+
/* Process all but the last event for each counter. */
2900+
for (at = base; at < top;) {
2901+
struct arch_pebs_header *header;
2902+
struct arch_pebs_basic *basic;
2903+
u64 pebs_status;
2904+
2905+
header = at;
2906+
2907+
if (WARN_ON_ONCE(!header->size))
2908+
break;
2909+
2910+
/* 1st fragment or single record must have basic group */
2911+
if (!header->basic) {
2912+
at += header->size;
2913+
continue;
2914+
}
2915+
2916+
basic = at + sizeof(struct arch_pebs_header);
2917+
pebs_status = mask & basic->applicable_counters;
2918+
__intel_pmu_handle_pebs_record(iregs, regs, data, at,
2919+
pebs_status, counts, last,
2920+
setup_arch_pebs_sample_data);
2921+
2922+
/* Skip non-last fragments */
2923+
while (arch_pebs_record_continued(header)) {
2924+
if (!header->size)
2925+
break;
2926+
at += header->size;
2927+
header = at;
2928+
}
2929+
2930+
/* Skip last fragment or the single record */
2931+
at += header->size;
2932+
}
2933+
2934+
__intel_pmu_handle_last_pebs_record(iregs, regs, data, mask,
2935+
counts, last,
2936+
setup_arch_pebs_sample_data);
2937+
}
2938+
27562939
static void __init intel_arch_pebs_init(void)
27572940
{
27582941
/*
@@ -2762,6 +2945,7 @@ static void __init intel_arch_pebs_init(void)
27622945
*/
27632946
x86_pmu.arch_pebs = 1;
27642947
x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE;
2948+
x86_pmu.drain_pebs = intel_pmu_drain_arch_pebs;
27652949
x86_pmu.pebs_capable = ~0ULL;
27662950

27672951
x86_pmu.pebs_enable = __intel_pmu_pebs_enable;

arch/x86/include/asm/msr-index.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,12 @@
327327
PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE | \
328328
PERF_CAP_PEBS_TIMING_INFO)
329329

330+
/* Arch PEBS */
331+
#define MSR_IA32_PEBS_BASE 0x000003f4
332+
#define MSR_IA32_PEBS_INDEX 0x000003f5
333+
#define ARCH_PEBS_OFFSET_MASK 0x7fffff
334+
#define ARCH_PEBS_INDEX_WR_SHIFT 4
335+
330336
#define MSR_IA32_RTIT_CTL 0x00000570
331337
#define RTIT_CTL_TRACEEN BIT(0)
332338
#define RTIT_CTL_CYCLEACC BIT(1)

arch/x86/include/asm/perf_event.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,8 @@ static inline bool is_topdown_idx(int idx)
437437
#define GLOBAL_STATUS_LBRS_FROZEN BIT_ULL(GLOBAL_STATUS_LBRS_FROZEN_BIT)
438438
#define GLOBAL_STATUS_TRACE_TOPAPMI_BIT 55
439439
#define GLOBAL_STATUS_TRACE_TOPAPMI BIT_ULL(GLOBAL_STATUS_TRACE_TOPAPMI_BIT)
440+
#define GLOBAL_STATUS_ARCH_PEBS_THRESHOLD_BIT 54
441+
#define GLOBAL_STATUS_ARCH_PEBS_THRESHOLD BIT_ULL(GLOBAL_STATUS_ARCH_PEBS_THRESHOLD_BIT)
440442
#define GLOBAL_STATUS_PERF_METRICS_OVF_BIT 48
441443

442444
#define GLOBAL_CTRL_EN_PERF_METRICS BIT_ULL(48)
@@ -507,6 +509,100 @@ struct pebs_cntr_header {
507509

508510
#define INTEL_CNTR_METRICS 0x3
509511

512+
/*
513+
* Arch PEBS
514+
*/
515+
union arch_pebs_index {
516+
struct {
517+
u64 rsvd:4,
518+
wr:23,
519+
rsvd2:4,
520+
full:1,
521+
en:1,
522+
rsvd3:3,
523+
thresh:23,
524+
rsvd4:5;
525+
};
526+
u64 whole;
527+
};
528+
529+
struct arch_pebs_header {
530+
union {
531+
u64 format;
532+
struct {
533+
u64 size:16, /* Record size */
534+
rsvd:14,
535+
mode:1, /* 64BIT_MODE */
536+
cont:1,
537+
rsvd2:3,
538+
cntr:5,
539+
lbr:2,
540+
rsvd3:7,
541+
xmm:1,
542+
ymmh:1,
543+
rsvd4:2,
544+
opmask:1,
545+
zmmh:1,
546+
h16zmm:1,
547+
rsvd5:5,
548+
gpr:1,
549+
aux:1,
550+
basic:1;
551+
};
552+
};
553+
u64 rsvd6;
554+
};
555+
556+
struct arch_pebs_basic {
557+
u64 ip;
558+
u64 applicable_counters;
559+
u64 tsc;
560+
u64 retire :16, /* Retire Latency */
561+
valid :1,
562+
rsvd :47;
563+
u64 rsvd2;
564+
u64 rsvd3;
565+
};
566+
567+
struct arch_pebs_aux {
568+
u64 address;
569+
u64 rsvd;
570+
u64 rsvd2;
571+
u64 rsvd3;
572+
u64 rsvd4;
573+
u64 aux;
574+
u64 instr_latency :16,
575+
pad2 :16,
576+
cache_latency :16,
577+
pad3 :16;
578+
u64 tsx_tuning;
579+
};
580+
581+
struct arch_pebs_gprs {
582+
u64 flags, ip, ax, cx, dx, bx, sp, bp, si, di;
583+
u64 r8, r9, r10, r11, r12, r13, r14, r15, ssp;
584+
u64 rsvd;
585+
};
586+
587+
struct arch_pebs_xer_header {
588+
u64 xstate;
589+
u64 rsvd;
590+
};
591+
592+
#define ARCH_PEBS_LBR_NAN 0x0
593+
#define ARCH_PEBS_LBR_NUM_8 0x1
594+
#define ARCH_PEBS_LBR_NUM_16 0x2
595+
#define ARCH_PEBS_LBR_NUM_VAR 0x3
596+
#define ARCH_PEBS_BASE_LBR_ENTRIES 8
597+
struct arch_pebs_lbr_header {
598+
u64 rsvd;
599+
u64 ctl;
600+
u64 depth;
601+
u64 ler_from;
602+
u64 ler_to;
603+
u64 ler_info;
604+
};
605+
510606
/*
511607
* AMD Extended Performance Monitoring and Debug cpuid feature detection
512608
*/

0 commit comments

Comments
 (0)