Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf intel-pt: Fix PEBS-via-PT data_src

The Fixes commit did not add support for decoding PEBS-via-PT data_src.
Fix by adding support.

PEBS-via-PT is a feature of some E-core processors, starting with
processors based on Tremont microarchitecture. Because the kernel only
supports Intel PT features that are on all processors, there is no support
for PEBS-via-PT on hybrids.

Currently that leaves processors based on Tremont, Gracemont and Crestmont,
however there are no events on Tremont that produce data_src information,
and for Gracemont and Crestmont there are only:

mem-loads event=0xd0,umask=0x5,ldlat=3
mem-stores event=0xd0,umask=0x6

Affected processors include Alder Lake N (Gracemont), Sierra Forest
(Crestmont) and Grand Ridge (Crestmont).

Example:

# perf record -d -e intel_pt/branch=0/ -e mem-loads/aux-output/pp uname

Before:

# perf.before script --itrace=o -Fdata_src
0 |OP No|LVL N/A|SNP N/A|TLB N/A|LCK No|BLK N/A
0 |OP No|LVL N/A|SNP N/A|TLB N/A|LCK No|BLK N/A

After:

# perf script --itrace=o -Fdata_src
10268100142 |OP LOAD|LVL L1 hit|SNP None|TLB L1 or L2 hit|LCK No|BLK N/A
10450100442 |OP LOAD|LVL L2 hit|SNP None|TLB L2 miss|LCK No|BLK N/A

Fixes: 975846eddf907297 ("perf intel-pt: Add memory information to synthesized PEBS sample")
Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20250512093932.79854-2-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
e00eac6b cd17a9b1

+202 -3
+202 -3
tools/perf/util/intel-pt.c
··· 127 127 128 128 bool single_pebs; 129 129 bool sample_pebs; 130 + int pebs_data_src_fmt; 130 131 struct evsel *pebs_evsel; 131 132 132 133 u64 evt_sample_type; ··· 176 175 struct intel_pt_pebs_event { 177 176 struct evsel *evsel; 178 177 u64 id; 178 + int data_src_fmt; 179 179 }; 180 180 181 181 struct intel_pt_queue { ··· 2274 2272 } 2275 2273 } 2276 2274 2277 - static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evsel *evsel, u64 id) 2275 + #define P(a, b) PERF_MEM_S(a, b) 2276 + #define OP_LH (P(OP, LOAD) | P(LVL, HIT)) 2277 + #define LEVEL(x) P(LVLNUM, x) 2278 + #define REM P(REMOTE, REMOTE) 2279 + #define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS)) 2280 + 2281 + #define PERF_PEBS_DATA_SOURCE_GRT_MAX 0x10 2282 + #define PERF_PEBS_DATA_SOURCE_GRT_MASK (PERF_PEBS_DATA_SOURCE_GRT_MAX - 1) 2283 + 2284 + /* Based on kernel __intel_pmu_pebs_data_source_grt() and pebs_data_source */ 2285 + static const u64 pebs_data_source_grt[PERF_PEBS_DATA_SOURCE_GRT_MAX] = { 2286 + P(OP, LOAD) | P(LVL, MISS) | LEVEL(L3) | P(SNOOP, NA), /* L3 miss|SNP N/A */ 2287 + OP_LH | P(LVL, L1) | LEVEL(L1) | P(SNOOP, NONE), /* L1 hit|SNP None */ 2288 + OP_LH | P(LVL, LFB) | LEVEL(LFB) | P(SNOOP, NONE), /* LFB/MAB hit|SNP None */ 2289 + OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* L2 hit|SNP None */ 2290 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, NONE), /* L3 hit|SNP None */ 2291 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HIT), /* L3 hit|SNP Hit */ 2292 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HITM), /* L3 hit|SNP HitM */ 2293 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HITM), /* L3 hit|SNP HitM */ 2294 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOPX, FWD), /* L3 hit|SNP Fwd */ 2295 + OP_LH | P(LVL, REM_CCE1) | REM | LEVEL(L3) | P(SNOOP, HITM), /* Remote L3 hit|SNP HitM */ 2296 + OP_LH | P(LVL, LOC_RAM) | LEVEL(RAM) | P(SNOOP, HIT), /* RAM hit|SNP Hit */ 2297 + OP_LH | P(LVL, REM_RAM1) | REM | LEVEL(L3) | P(SNOOP, HIT), /* Remote L3 hit|SNP Hit */ 2298 + OP_LH | P(LVL, LOC_RAM) | LEVEL(RAM) | SNOOP_NONE_MISS, /* RAM hit|SNP None or Miss */ 2299 + OP_LH | P(LVL, REM_RAM1) | LEVEL(RAM) | REM | SNOOP_NONE_MISS, /* Remote RAM hit|SNP None or Miss */ 2300 + OP_LH | P(LVL, IO) | LEVEL(NA) | P(SNOOP, NONE), /* I/O hit|SNP None */ 2301 + OP_LH | P(LVL, UNC) | LEVEL(NA) | P(SNOOP, NONE), /* Uncached hit|SNP None */ 2302 + }; 2303 + 2304 + /* Based on kernel __intel_pmu_pebs_data_source_cmt() and pebs_data_source */ 2305 + static const u64 pebs_data_source_cmt[PERF_PEBS_DATA_SOURCE_GRT_MAX] = { 2306 + P(OP, LOAD) | P(LVL, MISS) | LEVEL(L3) | P(SNOOP, NA), /* L3 miss|SNP N/A */ 2307 + OP_LH | P(LVL, L1) | LEVEL(L1) | P(SNOOP, NONE), /* L1 hit|SNP None */ 2308 + OP_LH | P(LVL, LFB) | LEVEL(LFB) | P(SNOOP, NONE), /* LFB/MAB hit|SNP None */ 2309 + OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* L2 hit|SNP None */ 2310 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, NONE), /* L3 hit|SNP None */ 2311 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, MISS), /* L3 hit|SNP Hit */ 2312 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HIT), /* L3 hit|SNP HitM */ 2313 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOPX, FWD), /* L3 hit|SNP HitM */ 2314 + OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HITM), /* L3 hit|SNP Fwd */ 2315 + OP_LH | P(LVL, REM_CCE1) | REM | LEVEL(L3) | P(SNOOP, HITM), /* Remote L3 hit|SNP HitM */ 2316 + OP_LH | P(LVL, LOC_RAM) | LEVEL(RAM) | P(SNOOP, NONE), /* RAM hit|SNP Hit */ 2317 + OP_LH | LEVEL(RAM) | REM | P(SNOOP, NONE), /* Remote L3 hit|SNP Hit */ 2318 + OP_LH | LEVEL(RAM) | REM | P(SNOOPX, FWD), /* RAM hit|SNP None or Miss */ 2319 + OP_LH | LEVEL(RAM) | REM | P(SNOOP, HITM), /* Remote RAM hit|SNP None or Miss */ 2320 + OP_LH | P(LVL, IO) | LEVEL(NA) | P(SNOOP, NONE), /* I/O hit|SNP None */ 2321 + OP_LH | P(LVL, UNC) | LEVEL(NA) | P(SNOOP, NONE), /* Uncached hit|SNP None */ 2322 + }; 2323 + 2324 + /* Based on kernel pebs_set_tlb_lock() */ 2325 + static inline void pebs_set_tlb_lock(u64 *val, bool tlb, bool lock) 2326 + { 2327 + /* 2328 + * TLB access 2329 + * 0 = did not miss 2nd level TLB 2330 + * 1 = missed 2nd level TLB 2331 + */ 2332 + if (tlb) 2333 + *val |= P(TLB, MISS) | P(TLB, L2); 2334 + else 2335 + *val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2); 2336 + 2337 + /* locked prefix */ 2338 + if (lock) 2339 + *val |= P(LOCK, LOCKED); 2340 + } 2341 + 2342 + /* Based on kernel __grt_latency_data() */ 2343 + static u64 intel_pt_grt_latency_data(u8 dse, bool tlb, bool lock, bool blk, 2344 + const u64 *pebs_data_source) 2345 + { 2346 + u64 val; 2347 + 2348 + dse &= PERF_PEBS_DATA_SOURCE_GRT_MASK; 2349 + val = pebs_data_source[dse]; 2350 + 2351 + pebs_set_tlb_lock(&val, tlb, lock); 2352 + 2353 + if (blk) 2354 + val |= P(BLK, DATA); 2355 + else 2356 + val |= P(BLK, NA); 2357 + 2358 + return val; 2359 + } 2360 + 2361 + /* Default value for data source */ 2362 + #define PERF_MEM_NA (PERF_MEM_S(OP, NA) |\ 2363 + PERF_MEM_S(LVL, NA) |\ 2364 + PERF_MEM_S(SNOOP, NA) |\ 2365 + PERF_MEM_S(LOCK, NA) |\ 2366 + PERF_MEM_S(TLB, NA) |\ 2367 + PERF_MEM_S(LVLNUM, NA)) 2368 + 2369 + enum DATA_SRC_FORMAT { 2370 + DATA_SRC_FORMAT_ERR = -1, 2371 + DATA_SRC_FORMAT_NA = 0, 2372 + DATA_SRC_FORMAT_GRT = 1, 2373 + DATA_SRC_FORMAT_CMT = 2, 2374 + }; 2375 + 2376 + /* Based on kernel grt_latency_data() and cmt_latency_data */ 2377 + static u64 intel_pt_get_data_src(u64 mem_aux_info, int data_src_fmt) 2378 + { 2379 + switch (data_src_fmt) { 2380 + case DATA_SRC_FORMAT_GRT: { 2381 + union { 2382 + u64 val; 2383 + struct { 2384 + unsigned int dse:4; 2385 + unsigned int locked:1; 2386 + unsigned int stlb_miss:1; 2387 + unsigned int fwd_blk:1; 2388 + unsigned int reserved:25; 2389 + }; 2390 + } x = {.val = mem_aux_info}; 2391 + return intel_pt_grt_latency_data(x.dse, x.stlb_miss, x.locked, x.fwd_blk, 2392 + pebs_data_source_grt); 2393 + } 2394 + case DATA_SRC_FORMAT_CMT: { 2395 + union { 2396 + u64 val; 2397 + struct { 2398 + unsigned int dse:5; 2399 + unsigned int locked:1; 2400 + unsigned int stlb_miss:1; 2401 + unsigned int fwd_blk:1; 2402 + unsigned int reserved:24; 2403 + }; 2404 + } x = {.val = mem_aux_info}; 2405 + return intel_pt_grt_latency_data(x.dse, x.stlb_miss, x.locked, x.fwd_blk, 2406 + pebs_data_source_cmt); 2407 + } 2408 + default: 2409 + return PERF_MEM_NA; 2410 + } 2411 + } 2412 + 2413 + static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evsel *evsel, 2414 + u64 id, int data_src_fmt) 2278 2415 { 2279 2416 const struct intel_pt_blk_items *items = &ptq->state->items; 2280 2417 struct perf_sample sample; ··· 2534 2393 } 2535 2394 } 2536 2395 2396 + if (sample_type & PERF_SAMPLE_DATA_SRC) { 2397 + if (items->has_mem_aux_info && data_src_fmt) { 2398 + if (data_src_fmt < 0) { 2399 + pr_err("Intel PT missing data_src info\n"); 2400 + return -1; 2401 + } 2402 + sample.data_src = intel_pt_get_data_src(items->mem_aux_info, data_src_fmt); 2403 + } else { 2404 + sample.data_src = PERF_MEM_NA; 2405 + } 2406 + } 2407 + 2537 2408 if (sample_type & PERF_SAMPLE_TRANSACTION && items->has_tsx_aux_info) { 2538 2409 u64 ax = items->has_rax ? items->rax : 0; 2539 2410 /* Refer kernel's intel_hsw_transaction() */ ··· 2566 2413 { 2567 2414 struct intel_pt *pt = ptq->pt; 2568 2415 struct evsel *evsel = pt->pebs_evsel; 2416 + int data_src_fmt = pt->pebs_data_src_fmt; 2569 2417 u64 id = evsel->core.id[0]; 2570 2418 2571 - return intel_pt_do_synth_pebs_sample(ptq, evsel, id); 2419 + return intel_pt_do_synth_pebs_sample(ptq, evsel, id, data_src_fmt); 2572 2420 } 2573 2421 2574 2422 static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) ··· 2594 2440 hw_id); 2595 2441 return intel_pt_synth_single_pebs_sample(ptq); 2596 2442 } 2597 - err = intel_pt_do_synth_pebs_sample(ptq, pe->evsel, pe->id); 2443 + err = intel_pt_do_synth_pebs_sample(ptq, pe->evsel, pe->id, pe->data_src_fmt); 2598 2444 if (err) 2599 2445 return err; 2600 2446 } ··· 3561 3407 event->itrace_start.tid); 3562 3408 } 3563 3409 3410 + /* 3411 + * Events with data_src are identified by L1_Hit_Indication 3412 + * refer https://github.com/intel/perfmon 3413 + */ 3414 + static int intel_pt_data_src_fmt(struct intel_pt *pt, struct evsel *evsel) 3415 + { 3416 + struct perf_env *env = pt->machine->env; 3417 + int fmt = DATA_SRC_FORMAT_NA; 3418 + 3419 + if (!env->cpuid) 3420 + return DATA_SRC_FORMAT_ERR; 3421 + 3422 + /* 3423 + * PEBS-via-PT is only supported on E-core non-hybrid. Of those only 3424 + * Gracemont and Crestmont have data_src. Check for: 3425 + * Alderlake N (Gracemont) 3426 + * Sierra Forest (Crestmont) 3427 + * Grand Ridge (Crestmont) 3428 + */ 3429 + 3430 + if (!strncmp(env->cpuid, "GenuineIntel,6,190,", 19)) 3431 + fmt = DATA_SRC_FORMAT_GRT; 3432 + 3433 + if (!strncmp(env->cpuid, "GenuineIntel,6,175,", 19) || 3434 + !strncmp(env->cpuid, "GenuineIntel,6,182,", 19)) 3435 + fmt = DATA_SRC_FORMAT_CMT; 3436 + 3437 + if (fmt == DATA_SRC_FORMAT_NA) 3438 + return fmt; 3439 + 3440 + /* 3441 + * Only data_src events are: 3442 + * mem-loads event=0xd0,umask=0x5 3443 + * mem-stores event=0xd0,umask=0x6 3444 + */ 3445 + if (evsel->core.attr.type == PERF_TYPE_RAW && 3446 + ((evsel->core.attr.config & 0xffff) == 0x5d0 || 3447 + (evsel->core.attr.config & 0xffff) == 0x6d0)) 3448 + return fmt; 3449 + 3450 + return DATA_SRC_FORMAT_NA; 3451 + } 3452 + 3564 3453 static int intel_pt_process_aux_output_hw_id(struct intel_pt *pt, 3565 3454 union perf_event *event, 3566 3455 struct perf_sample *sample) ··· 3624 3427 3625 3428 ptq->pebs[hw_id].evsel = evsel; 3626 3429 ptq->pebs[hw_id].id = sample->id; 3430 + ptq->pebs[hw_id].data_src_fmt = intel_pt_data_src_fmt(pt, evsel); 3627 3431 3628 3432 return 0; 3629 3433 } ··· 4174 3976 } 4175 3977 pt->single_pebs = true; 4176 3978 pt->sample_pebs = true; 3979 + pt->pebs_data_src_fmt = intel_pt_data_src_fmt(pt, evsel); 4177 3980 pt->pebs_evsel = evsel; 4178 3981 } 4179 3982 }