12ae41f5dSLike Xu #include "x86/msr.h" 22ae41f5dSLike Xu #include "x86/processor.h" 32ae41f5dSLike Xu #include "x86/pmu.h" 42ae41f5dSLike Xu #include "x86/isr.h" 52ae41f5dSLike Xu #include "x86/apic.h" 62ae41f5dSLike Xu #include "x86/apic-defs.h" 72ae41f5dSLike Xu #include "x86/desc.h" 82ae41f5dSLike Xu #include "alloc.h" 92ae41f5dSLike Xu 102ae41f5dSLike Xu #include "vm.h" 112ae41f5dSLike Xu #include "processor.h" 122ae41f5dSLike Xu #include "vmalloc.h" 132ae41f5dSLike Xu #include "alloc_page.h" 142ae41f5dSLike Xu 152ae41f5dSLike Xu /* bits [63:48] provides the size of the current record in bytes */ 162ae41f5dSLike Xu #define RECORD_SIZE_OFFSET 48 172ae41f5dSLike Xu 182ae41f5dSLike Xu static unsigned int max_nr_gp_events; 192ae41f5dSLike Xu static unsigned long *ds_bufer; 202ae41f5dSLike Xu static unsigned long *pebs_buffer; 212ae41f5dSLike Xu static u64 ctr_start_val; 222ae41f5dSLike Xu static bool has_baseline; 232ae41f5dSLike Xu 242ae41f5dSLike Xu struct debug_store { 252ae41f5dSLike Xu u64 bts_buffer_base; 262ae41f5dSLike Xu u64 bts_index; 272ae41f5dSLike Xu u64 bts_absolute_maximum; 282ae41f5dSLike Xu u64 bts_interrupt_threshold; 292ae41f5dSLike Xu u64 pebs_buffer_base; 302ae41f5dSLike Xu u64 pebs_index; 312ae41f5dSLike Xu u64 pebs_absolute_maximum; 322ae41f5dSLike Xu u64 pebs_interrupt_threshold; 332ae41f5dSLike Xu u64 pebs_event_reset[64]; 342ae41f5dSLike Xu }; 352ae41f5dSLike Xu 362ae41f5dSLike Xu struct pebs_basic { 372ae41f5dSLike Xu u64 format_size; 382ae41f5dSLike Xu u64 ip; 392ae41f5dSLike Xu u64 applicable_counters; 402ae41f5dSLike Xu u64 tsc; 412ae41f5dSLike Xu }; 422ae41f5dSLike Xu 432ae41f5dSLike Xu struct pebs_meminfo { 442ae41f5dSLike Xu u64 address; 452ae41f5dSLike Xu u64 aux; 462ae41f5dSLike Xu u64 latency; 472ae41f5dSLike Xu u64 tsx_tuning; 482ae41f5dSLike Xu }; 492ae41f5dSLike Xu 502ae41f5dSLike Xu struct pebs_gprs { 512ae41f5dSLike Xu u64 flags, ip, ax, cx, dx, bx, sp, bp, si, di; 522ae41f5dSLike Xu u64 r8, r9, r10, r11, r12, r13, r14, r15; 532ae41f5dSLike Xu }; 542ae41f5dSLike Xu 552ae41f5dSLike Xu struct pebs_xmm { 562ae41f5dSLike Xu u64 xmm[16*2]; /* two entries for each register */ 572ae41f5dSLike Xu }; 582ae41f5dSLike Xu 592ae41f5dSLike Xu struct lbr_entry { 602ae41f5dSLike Xu u64 from; 612ae41f5dSLike Xu u64 to; 622ae41f5dSLike Xu u64 info; 632ae41f5dSLike Xu }; 642ae41f5dSLike Xu 652ae41f5dSLike Xu enum pmc_type { 662ae41f5dSLike Xu GP = 0, 672ae41f5dSLike Xu FIXED, 682ae41f5dSLike Xu }; 692ae41f5dSLike Xu 702ae41f5dSLike Xu static uint32_t intel_arch_events[] = { 712ae41f5dSLike Xu 0x00c4, /* PERF_COUNT_HW_BRANCH_INSTRUCTIONS */ 722ae41f5dSLike Xu 0x00c5, /* PERF_COUNT_HW_BRANCH_MISSES */ 732ae41f5dSLike Xu 0x0300, /* PERF_COUNT_HW_REF_CPU_CYCLES */ 742ae41f5dSLike Xu 0x003c, /* PERF_COUNT_HW_CPU_CYCLES */ 752ae41f5dSLike Xu 0x00c0, /* PERF_COUNT_HW_INSTRUCTIONS */ 762ae41f5dSLike Xu 0x013c, /* PERF_COUNT_HW_BUS_CYCLES */ 772ae41f5dSLike Xu 0x4f2e, /* PERF_COUNT_HW_CACHE_REFERENCES */ 782ae41f5dSLike Xu 0x412e, /* PERF_COUNT_HW_CACHE_MISSES */ 792ae41f5dSLike Xu }; 802ae41f5dSLike Xu 812ae41f5dSLike Xu /* Iterating each counter value is a waste of time, pick a few typical values. */ 822ae41f5dSLike Xu static u64 counter_start_values[] = { 832ae41f5dSLike Xu /* if PEBS counter doesn't overflow at all */ 842ae41f5dSLike Xu 0, 852ae41f5dSLike Xu 0xfffffffffff0, 862ae41f5dSLike Xu /* normal counter overflow to have PEBS records */ 872ae41f5dSLike Xu 0xfffffffffffe, 882ae41f5dSLike Xu /* test whether emulated instructions should trigger PEBS */ 892ae41f5dSLike Xu 0xffffffffffff, 902ae41f5dSLike Xu }; 912ae41f5dSLike Xu 922cb2af7fSSean Christopherson static unsigned int get_pebs_record_size(u64 pebs_data_cfg, bool use_adaptive) 932ae41f5dSLike Xu { 942ae41f5dSLike Xu unsigned int sz = sizeof(struct pebs_basic); 952ae41f5dSLike Xu 962cb2af7fSSean Christopherson if (!use_adaptive) 972ae41f5dSLike Xu return sz; 982ae41f5dSLike Xu 992ae41f5dSLike Xu if (pebs_data_cfg & PEBS_DATACFG_MEMINFO) 1002ae41f5dSLike Xu sz += sizeof(struct pebs_meminfo); 101fc17d527SSean Christopherson if (pebs_data_cfg & PEBS_DATACFG_GPRS) 1022ae41f5dSLike Xu sz += sizeof(struct pebs_gprs); 1032ae41f5dSLike Xu if (pebs_data_cfg & PEBS_DATACFG_XMMS) 1042ae41f5dSLike Xu sz += sizeof(struct pebs_xmm); 1052ae41f5dSLike Xu if (pebs_data_cfg & PEBS_DATACFG_LBRS) 1062ae41f5dSLike Xu sz += MAX_NUM_LBR_ENTRY * sizeof(struct lbr_entry); 1072ae41f5dSLike Xu 1082ae41f5dSLike Xu return sz; 1092ae41f5dSLike Xu } 1102ae41f5dSLike Xu 1112ae41f5dSLike Xu static void cnt_overflow(isr_regs_t *regs) 1122ae41f5dSLike Xu { 113*c595c361SMingwei Zhang apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); 1142ae41f5dSLike Xu apic_write(APIC_EOI, 0); 1152ae41f5dSLike Xu } 1162ae41f5dSLike Xu 1172ae41f5dSLike Xu static inline void workload(void) 1182ae41f5dSLike Xu { 1192ae41f5dSLike Xu asm volatile( 1202ae41f5dSLike Xu "mov $0x0, %%eax\n" 1212ae41f5dSLike Xu "cmp $0x0, %%eax\n" 1222ae41f5dSLike Xu "jne label2\n" 1232ae41f5dSLike Xu "jne label2\n" 1242ae41f5dSLike Xu "jne label2\n" 1252ae41f5dSLike Xu "jne label2\n" 1262ae41f5dSLike Xu "mov $0x0, %%eax\n" 1272ae41f5dSLike Xu "cmp $0x0, %%eax\n" 1282ae41f5dSLike Xu "jne label2\n" 1292ae41f5dSLike Xu "jne label2\n" 1302ae41f5dSLike Xu "jne label2\n" 1312ae41f5dSLike Xu "jne label2\n" 1322ae41f5dSLike Xu "mov $0xa, %%eax\n" 1332ae41f5dSLike Xu "cpuid\n" 1342ae41f5dSLike Xu "mov $0xa, %%eax\n" 1352ae41f5dSLike Xu "cpuid\n" 1362ae41f5dSLike Xu "mov $0xa, %%eax\n" 1372ae41f5dSLike Xu "cpuid\n" 1382ae41f5dSLike Xu "mov $0xa, %%eax\n" 1392ae41f5dSLike Xu "cpuid\n" 1402ae41f5dSLike Xu "mov $0xa, %%eax\n" 1412ae41f5dSLike Xu "cpuid\n" 1422ae41f5dSLike Xu "mov $0xa, %%eax\n" 1432ae41f5dSLike Xu "cpuid\n" 1442ae41f5dSLike Xu "label2:\n" 1452ae41f5dSLike Xu : 1462ae41f5dSLike Xu : 1472ae41f5dSLike Xu : "eax", "ebx", "ecx", "edx"); 1482ae41f5dSLike Xu } 1492ae41f5dSLike Xu 1502ae41f5dSLike Xu static inline void workload2(void) 1512ae41f5dSLike Xu { 1522ae41f5dSLike Xu asm volatile( 1532ae41f5dSLike Xu "mov $0x0, %%eax\n" 1542ae41f5dSLike Xu "cmp $0x0, %%eax\n" 1552ae41f5dSLike Xu "jne label3\n" 1562ae41f5dSLike Xu "jne label3\n" 1572ae41f5dSLike Xu "jne label3\n" 1582ae41f5dSLike Xu "jne label3\n" 1592ae41f5dSLike Xu "mov $0x0, %%eax\n" 1602ae41f5dSLike Xu "cmp $0x0, %%eax\n" 1612ae41f5dSLike Xu "jne label3\n" 1622ae41f5dSLike Xu "jne label3\n" 1632ae41f5dSLike Xu "jne label3\n" 1642ae41f5dSLike Xu "jne label3\n" 1652ae41f5dSLike Xu "mov $0xa, %%eax\n" 1662ae41f5dSLike Xu "cpuid\n" 1672ae41f5dSLike Xu "mov $0xa, %%eax\n" 1682ae41f5dSLike Xu "cpuid\n" 1692ae41f5dSLike Xu "mov $0xa, %%eax\n" 1702ae41f5dSLike Xu "cpuid\n" 1712ae41f5dSLike Xu "mov $0xa, %%eax\n" 1722ae41f5dSLike Xu "cpuid\n" 1732ae41f5dSLike Xu "mov $0xa, %%eax\n" 1742ae41f5dSLike Xu "cpuid\n" 1752ae41f5dSLike Xu "mov $0xa, %%eax\n" 1762ae41f5dSLike Xu "cpuid\n" 1772ae41f5dSLike Xu "label3:\n" 1782ae41f5dSLike Xu : 1792ae41f5dSLike Xu : 1802ae41f5dSLike Xu : "eax", "ebx", "ecx", "edx"); 1812ae41f5dSLike Xu } 1822ae41f5dSLike Xu 1832ae41f5dSLike Xu static void alloc_buffers(void) 1842ae41f5dSLike Xu { 1852ae41f5dSLike Xu ds_bufer = alloc_page(); 1862ae41f5dSLike Xu force_4k_page(ds_bufer); 1872ae41f5dSLike Xu memset(ds_bufer, 0x0, PAGE_SIZE); 1882ae41f5dSLike Xu 1892ae41f5dSLike Xu pebs_buffer = alloc_page(); 1902ae41f5dSLike Xu force_4k_page(pebs_buffer); 1912ae41f5dSLike Xu memset(pebs_buffer, 0x0, PAGE_SIZE); 1922ae41f5dSLike Xu } 1932ae41f5dSLike Xu 1942ae41f5dSLike Xu static void free_buffers(void) 1952ae41f5dSLike Xu { 1962ae41f5dSLike Xu if (ds_bufer) 1972ae41f5dSLike Xu free_page(ds_bufer); 1982ae41f5dSLike Xu 1992ae41f5dSLike Xu if (pebs_buffer) 2002ae41f5dSLike Xu free_page(pebs_buffer); 2012ae41f5dSLike Xu } 2022ae41f5dSLike Xu 2032cb2af7fSSean Christopherson static void pebs_enable(u64 bitmask, u64 pebs_data_cfg, bool use_adaptive) 2042ae41f5dSLike Xu { 2052ae41f5dSLike Xu static struct debug_store *ds; 2062cb2af7fSSean Christopherson u64 adaptive_ctrl = 0, fixed_ctr_ctrl = 0; 2072ae41f5dSLike Xu unsigned int idx; 2082ae41f5dSLike Xu 2092ae41f5dSLike Xu if (has_baseline) 2102ae41f5dSLike Xu wrmsr(MSR_PEBS_DATA_CFG, pebs_data_cfg); 2112ae41f5dSLike Xu 2122ae41f5dSLike Xu ds = (struct debug_store *)ds_bufer; 2132ae41f5dSLike Xu ds->pebs_index = ds->pebs_buffer_base = (unsigned long)pebs_buffer; 2142ae41f5dSLike Xu ds->pebs_absolute_maximum = (unsigned long)pebs_buffer + PAGE_SIZE; 2152ae41f5dSLike Xu ds->pebs_interrupt_threshold = ds->pebs_buffer_base + 2162cb2af7fSSean Christopherson get_pebs_record_size(pebs_data_cfg, use_adaptive); 2172ae41f5dSLike Xu 2182ae41f5dSLike Xu for (idx = 0; idx < pmu.nr_fixed_counters; idx++) { 2192ae41f5dSLike Xu if (!(BIT_ULL(FIXED_CNT_INDEX + idx) & bitmask)) 2202ae41f5dSLike Xu continue; 2212cb2af7fSSean Christopherson if (use_adaptive) 2222cb2af7fSSean Christopherson adaptive_ctrl = BIT(FIXED_CNT_INDEX + idx * 4); 2232ae41f5dSLike Xu wrmsr(MSR_PERF_FIXED_CTRx(idx), ctr_start_val); 2242cb2af7fSSean Christopherson fixed_ctr_ctrl |= (0xbULL << (idx * 4) | adaptive_ctrl); 2252ae41f5dSLike Xu } 2262ae41f5dSLike Xu if (fixed_ctr_ctrl) 2272ae41f5dSLike Xu wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, fixed_ctr_ctrl); 2282ae41f5dSLike Xu 2292ae41f5dSLike Xu for (idx = 0; idx < max_nr_gp_events; idx++) { 2302ae41f5dSLike Xu if (!(BIT_ULL(idx) & bitmask)) 2312ae41f5dSLike Xu continue; 2322cb2af7fSSean Christopherson if (use_adaptive) 2332cb2af7fSSean Christopherson adaptive_ctrl = ICL_EVENTSEL_ADAPTIVE; 2342ae41f5dSLike Xu wrmsr(MSR_GP_EVENT_SELECTx(idx), EVNTSEL_EN | EVNTSEL_OS | EVNTSEL_USR | 2352cb2af7fSSean Christopherson intel_arch_events[idx] | adaptive_ctrl); 2362ae41f5dSLike Xu wrmsr(MSR_GP_COUNTERx(idx), ctr_start_val); 2372ae41f5dSLike Xu } 2382ae41f5dSLike Xu 2392ae41f5dSLike Xu wrmsr(MSR_IA32_DS_AREA, (unsigned long)ds_bufer); 2402ae41f5dSLike Xu wrmsr(MSR_IA32_PEBS_ENABLE, bitmask); 2412ae41f5dSLike Xu wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, bitmask); 2422ae41f5dSLike Xu } 2432ae41f5dSLike Xu 2442ae41f5dSLike Xu static void reset_pebs(void) 2452ae41f5dSLike Xu { 2462ae41f5dSLike Xu memset(ds_bufer, 0x0, PAGE_SIZE); 2472ae41f5dSLike Xu memset(pebs_buffer, 0x0, PAGE_SIZE); 2482ae41f5dSLike Xu wrmsr(MSR_IA32_PEBS_ENABLE, 0); 2492ae41f5dSLike Xu wrmsr(MSR_IA32_DS_AREA, 0); 2502ae41f5dSLike Xu if (has_baseline) 2512ae41f5dSLike Xu wrmsr(MSR_PEBS_DATA_CFG, 0); 2522ae41f5dSLike Xu 2532ae41f5dSLike Xu wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); 2542ae41f5dSLike Xu wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_STATUS)); 2552ae41f5dSLike Xu 2562ae41f5dSLike Xu pmu_reset_all_counters(); 2572ae41f5dSLike Xu } 2582ae41f5dSLike Xu 2592ae41f5dSLike Xu static void pebs_disable(unsigned int idx) 2602ae41f5dSLike Xu { 2612ae41f5dSLike Xu /* 2622ae41f5dSLike Xu * If we only clear the PEBS_ENABLE bit, the counter will continue to increment. 2632ae41f5dSLike Xu * In this very tiny time window, if the counter overflows no pebs record will be generated, 2642ae41f5dSLike Xu * but a normal counter irq. Test this fully with two ways. 2652ae41f5dSLike Xu */ 2662ae41f5dSLike Xu if (idx % 2) 2672ae41f5dSLike Xu wrmsr(MSR_IA32_PEBS_ENABLE, 0); 2682ae41f5dSLike Xu 2692ae41f5dSLike Xu wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); 2702ae41f5dSLike Xu } 2712ae41f5dSLike Xu 2722cb2af7fSSean Christopherson static void check_pebs_records(u64 bitmask, u64 pebs_data_cfg, bool use_adaptive) 2732ae41f5dSLike Xu { 2742ae41f5dSLike Xu struct pebs_basic *pebs_rec = (struct pebs_basic *)pebs_buffer; 2752ae41f5dSLike Xu struct debug_store *ds = (struct debug_store *)ds_bufer; 2762cb2af7fSSean Christopherson unsigned int pebs_record_size; 2772ae41f5dSLike Xu unsigned int count = 0; 2782ae41f5dSLike Xu bool expected, pebs_idx_match, pebs_size_match, data_cfg_match; 2792ae41f5dSLike Xu void *cur_record; 2802ae41f5dSLike Xu 2812ae41f5dSLike Xu expected = (ds->pebs_index == ds->pebs_buffer_base) && !pebs_rec->format_size; 2822ae41f5dSLike Xu if (!(rdmsr(MSR_CORE_PERF_GLOBAL_STATUS) & GLOBAL_STATUS_BUFFER_OVF)) { 2832ae41f5dSLike Xu report(expected, "No OVF irq, none PEBS records."); 2842ae41f5dSLike Xu return; 2852ae41f5dSLike Xu } 2862ae41f5dSLike Xu 2872ae41f5dSLike Xu if (expected) { 2882ae41f5dSLike Xu report(!expected, "A OVF irq, but none PEBS records."); 2892ae41f5dSLike Xu return; 2902ae41f5dSLike Xu } 2912ae41f5dSLike Xu 2922ae41f5dSLike Xu expected = ds->pebs_index >= ds->pebs_interrupt_threshold; 2932ae41f5dSLike Xu cur_record = (void *)pebs_buffer; 2942ae41f5dSLike Xu do { 2952ae41f5dSLike Xu pebs_rec = (struct pebs_basic *)cur_record; 2962ae41f5dSLike Xu pebs_record_size = pebs_rec->format_size >> RECORD_SIZE_OFFSET; 2972cb2af7fSSean Christopherson pebs_idx_match = pebs_rec->applicable_counters & bitmask; 2982cb2af7fSSean Christopherson pebs_size_match = pebs_record_size == get_pebs_record_size(pebs_data_cfg, use_adaptive); 2992cb2af7fSSean Christopherson data_cfg_match = (pebs_rec->format_size & GENMASK_ULL(47, 0)) == pebs_data_cfg; 3002ae41f5dSLike Xu expected = pebs_idx_match && pebs_size_match && data_cfg_match; 3012ae41f5dSLike Xu report(expected, 302d4ae0a71SThomas Huth "PEBS record (written seq %d) is verified (including size, counters and cfg).", count); 3038d0f574fSSean Christopherson if (use_adaptive && (pebs_data_cfg & PEBS_DATACFG_LBRS)) { 3048d0f574fSSean Christopherson unsigned int lbrs_offset = get_pebs_record_size(pebs_data_cfg & ~PEBS_DATACFG_LBRS, true); 3058d0f574fSSean Christopherson struct lbr_entry *pebs_lbrs = cur_record + lbrs_offset; 3068d0f574fSSean Christopherson int i; 3078d0f574fSSean Christopherson 3088d0f574fSSean Christopherson for (i = 0; i < MAX_NUM_LBR_ENTRY; i++) { 3098d0f574fSSean Christopherson if (!pebs_lbrs[i].from && !pebs_lbrs[i].to) 3108d0f574fSSean Christopherson continue; 3118d0f574fSSean Christopherson 3128d0f574fSSean Christopherson report_fail("PEBS LBR record %u isn't empty, got from = '%lx', to = '%lx', info = '%lx'", 3138d0f574fSSean Christopherson i, pebs_lbrs[i].from, pebs_lbrs[i].to, pebs_lbrs[i].info); 3148d0f574fSSean Christopherson } 3158d0f574fSSean Christopherson } 3162ae41f5dSLike Xu cur_record = cur_record + pebs_record_size; 3172ae41f5dSLike Xu count++; 3182ae41f5dSLike Xu } while (expected && (void *)cur_record < (void *)ds->pebs_index); 3192ae41f5dSLike Xu 3202ae41f5dSLike Xu if (!expected) { 3212ae41f5dSLike Xu if (!pebs_idx_match) 3222ae41f5dSLike Xu printf("FAIL: The applicable_counters (0x%lx) doesn't match with pmc_bitmask (0x%lx).\n", 3232ae41f5dSLike Xu pebs_rec->applicable_counters, bitmask); 3242ae41f5dSLike Xu if (!pebs_size_match) 3252cb2af7fSSean Christopherson printf("FAIL: The pebs_record_size (%d) doesn't match with expected record size (%d).\n", 3262cb2af7fSSean Christopherson pebs_record_size, get_pebs_record_size(pebs_data_cfg, use_adaptive)); 3272ae41f5dSLike Xu if (!data_cfg_match) 3282cb2af7fSSean Christopherson printf("FAIL: The pebs_data_cfg (0x%lx) doesn't match with the effective MSR_PEBS_DATA_CFG (0x%lx).\n", 3292cb2af7fSSean Christopherson pebs_rec->format_size & 0xffffffffffff, use_adaptive ? pebs_data_cfg : 0); 3302ae41f5dSLike Xu } 3312ae41f5dSLike Xu } 3322ae41f5dSLike Xu 3332cb2af7fSSean Christopherson static void check_one_counter(enum pmc_type type, unsigned int idx, 3342cb2af7fSSean Christopherson u64 pebs_data_cfg, bool use_adaptive) 3352ae41f5dSLike Xu { 3362ae41f5dSLike Xu int pebs_bit = BIT_ULL(type == FIXED ? FIXED_CNT_INDEX + idx : idx); 3372ae41f5dSLike Xu 3382ae41f5dSLike Xu report_prefix_pushf("%s counter %d (0x%lx)", 3392ae41f5dSLike Xu type == FIXED ? "Extended Fixed" : "GP", idx, ctr_start_val); 3402ae41f5dSLike Xu reset_pebs(); 3412cb2af7fSSean Christopherson pebs_enable(pebs_bit, pebs_data_cfg, use_adaptive); 3422ae41f5dSLike Xu workload(); 3432ae41f5dSLike Xu pebs_disable(idx); 3442cb2af7fSSean Christopherson check_pebs_records(pebs_bit, pebs_data_cfg, use_adaptive); 3452ae41f5dSLike Xu report_prefix_pop(); 3462ae41f5dSLike Xu } 3472ae41f5dSLike Xu 3482ae41f5dSLike Xu /* more than one PEBS records will be generated. */ 3492cb2af7fSSean Christopherson static void check_multiple_counters(u64 bitmask, u64 pebs_data_cfg, 3502cb2af7fSSean Christopherson bool use_adaptive) 3512ae41f5dSLike Xu { 3522ae41f5dSLike Xu reset_pebs(); 3532cb2af7fSSean Christopherson pebs_enable(bitmask, pebs_data_cfg, use_adaptive); 3542ae41f5dSLike Xu workload2(); 3552ae41f5dSLike Xu pebs_disable(0); 3562cb2af7fSSean Christopherson check_pebs_records(bitmask, pebs_data_cfg, use_adaptive); 3572ae41f5dSLike Xu } 3582ae41f5dSLike Xu 3592cb2af7fSSean Christopherson static void check_pebs_counters(u64 pebs_data_cfg, bool use_adaptive) 3602ae41f5dSLike Xu { 3612ae41f5dSLike Xu unsigned int idx; 3622ae41f5dSLike Xu u64 bitmask = 0; 3632ae41f5dSLike Xu 36479aa106cSSean Christopherson for (idx = 0; has_baseline && idx < pmu.nr_fixed_counters; idx++) 3652cb2af7fSSean Christopherson check_one_counter(FIXED, idx, pebs_data_cfg, use_adaptive); 3662ae41f5dSLike Xu 3672ae41f5dSLike Xu for (idx = 0; idx < max_nr_gp_events; idx++) 3682cb2af7fSSean Christopherson check_one_counter(GP, idx, pebs_data_cfg, use_adaptive); 3692ae41f5dSLike Xu 37079aa106cSSean Christopherson for (idx = 0; has_baseline && idx < pmu.nr_fixed_counters; idx++) 3712ae41f5dSLike Xu bitmask |= BIT_ULL(FIXED_CNT_INDEX + idx); 3722ae41f5dSLike Xu for (idx = 0; idx < max_nr_gp_events; idx += 2) 3732ae41f5dSLike Xu bitmask |= BIT_ULL(idx); 3742ae41f5dSLike Xu report_prefix_pushf("Multiple (0x%lx)", bitmask); 3752cb2af7fSSean Christopherson check_multiple_counters(bitmask, pebs_data_cfg, use_adaptive); 3762ae41f5dSLike Xu report_prefix_pop(); 3772ae41f5dSLike Xu } 3782ae41f5dSLike Xu 3792ae41f5dSLike Xu /* 3802ae41f5dSLike Xu * Known reasons for none PEBS records: 3812ae41f5dSLike Xu * 1. The selected event does not support PEBS; 3822ae41f5dSLike Xu * 2. From a core pmu perspective, the vCPU and pCPU models are not same; 3832ae41f5dSLike Xu * 3. Guest counter has not yet overflowed or been cross-mapped by the host; 3842ae41f5dSLike Xu */ 3852ae41f5dSLike Xu int main(int ac, char **av) 3862ae41f5dSLike Xu { 3872ae41f5dSLike Xu unsigned int i, j; 3882ae41f5dSLike Xu 3892ae41f5dSLike Xu setup_vm(); 3902ae41f5dSLike Xu 3912ae41f5dSLike Xu max_nr_gp_events = MIN(pmu.nr_gp_counters, ARRAY_SIZE(intel_arch_events)); 3922ae41f5dSLike Xu 3932ae41f5dSLike Xu printf("PMU version: %d\n", pmu.version); 3942ae41f5dSLike Xu 3952ae41f5dSLike Xu has_baseline = pmu_has_pebs_baseline(); 3962ae41f5dSLike Xu if (pmu_has_full_writes()) 3972ae41f5dSLike Xu pmu_activate_full_writes(); 3982ae41f5dSLike Xu 399dd602b6fSSean Christopherson if (!pmu.is_intel) { 4002ae41f5dSLike Xu report_skip("PEBS requires Intel ICX or later, non-Intel detected"); 4012ae41f5dSLike Xu return report_summary(); 4022ae41f5dSLike Xu } else if (!pmu_has_pebs()) { 4032ae41f5dSLike Xu report_skip("PEBS required PMU version 2, reported version is %d", pmu.version); 4042ae41f5dSLike Xu return report_summary(); 4052ae41f5dSLike Xu } else if (!pmu_pebs_format()) { 4062ae41f5dSLike Xu report_skip("PEBS not enumerated in PERF_CAPABILITIES"); 4072ae41f5dSLike Xu return report_summary(); 4082ae41f5dSLike Xu } else if (rdmsr(MSR_IA32_MISC_ENABLE) & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL) { 4092ae41f5dSLike Xu report_skip("PEBS unavailable according to MISC_ENABLE"); 4102ae41f5dSLike Xu return report_summary(); 4112ae41f5dSLike Xu } 4122ae41f5dSLike Xu 4132ae41f5dSLike Xu printf("PEBS format: %d\n", pmu_pebs_format()); 4142ae41f5dSLike Xu printf("PEBS GP counters: %d\n", pmu.nr_gp_counters); 4152ae41f5dSLike Xu printf("PEBS Fixed counters: %d\n", pmu.nr_fixed_counters); 4162ae41f5dSLike Xu printf("PEBS baseline (Adaptive PEBS): %d\n", has_baseline); 4172ae41f5dSLike Xu 4182ae41f5dSLike Xu handle_irq(PMI_VECTOR, cnt_overflow); 4192ae41f5dSLike Xu alloc_buffers(); 4202ae41f5dSLike Xu 4212ae41f5dSLike Xu for (i = 0; i < ARRAY_SIZE(counter_start_values); i++) { 4222ae41f5dSLike Xu ctr_start_val = counter_start_values[i]; 4232cb2af7fSSean Christopherson check_pebs_counters(0, false); 4242ae41f5dSLike Xu if (!has_baseline) 4252ae41f5dSLike Xu continue; 4262ae41f5dSLike Xu 427fc17d527SSean Christopherson for (j = 0; j <= PEBS_DATACFG_MASK; j++) { 428fc17d527SSean Christopherson u64 pebs_data_cfg = j; 429fc17d527SSean Christopherson 430fc17d527SSean Christopherson if (pebs_data_cfg & PEBS_DATACFG_LBRS) 431fc17d527SSean Christopherson pebs_data_cfg |= ((MAX_NUM_LBR_ENTRY -1) << PEBS_DATACFG_LBR_SHIFT); 432fc17d527SSean Christopherson 433fc17d527SSean Christopherson report_prefix_pushf("Adaptive (0x%lx)", pebs_data_cfg); 4342cb2af7fSSean Christopherson check_pebs_counters(pebs_data_cfg, true); 4352cb2af7fSSean Christopherson report_prefix_pop(); 4362cb2af7fSSean Christopherson 4372cb2af7fSSean Christopherson report_prefix_pushf("Ignored Adaptive (0x%lx)", pebs_data_cfg); 4382cb2af7fSSean Christopherson check_pebs_counters(pebs_data_cfg, false); 4392ae41f5dSLike Xu report_prefix_pop(); 4402ae41f5dSLike Xu } 4412ae41f5dSLike Xu } 4422ae41f5dSLike Xu 4432ae41f5dSLike Xu free_buffers(); 4442ae41f5dSLike Xu 4452ae41f5dSLike Xu return report_summary(); 4462ae41f5dSLike Xu } 447