1a9f8b16fSGleb Natapov 2a9f8b16fSGleb Natapov #include "x86/msr.h" 3a9f8b16fSGleb Natapov #include "x86/processor.h" 49f17508dSLike Xu #include "x86/pmu.h" 5a9f8b16fSGleb Natapov #include "x86/apic-defs.h" 6a9f8b16fSGleb Natapov #include "x86/apic.h" 7a9f8b16fSGleb Natapov #include "x86/desc.h" 8a9f8b16fSGleb Natapov #include "x86/isr.h" 995a94088SNicholas Piggin #include "vmalloc.h" 10dcda215bSPaolo Bonzini #include "alloc.h" 11a9f8b16fSGleb Natapov 12a9f8b16fSGleb Natapov #include "libcflat.h" 13a9f8b16fSGleb Natapov #include <stdint.h> 14a9f8b16fSGleb Natapov 15a9f8b16fSGleb Natapov #define N 1000000 16a9f8b16fSGleb Natapov 1720cf9147SJim Mattson // These values match the number of instructions and branches in the 1820cf9147SJim Mattson // assembly block in check_emulated_instr(). 1920cf9147SJim Mattson #define EXPECTED_INSTR 17 2020cf9147SJim Mattson #define EXPECTED_BRNCH 5 2120cf9147SJim Mattson 22a9f8b16fSGleb Natapov typedef struct { 23a9f8b16fSGleb Natapov uint32_t ctr; 249720e46cSDapeng Mi uint32_t idx; 25006b089dSLike Xu uint64_t config; 26a9f8b16fSGleb Natapov uint64_t count; 27a9f8b16fSGleb Natapov } pmu_counter_t; 28a9f8b16fSGleb Natapov 29a9f8b16fSGleb Natapov struct pmu_event { 30797d79a2SThomas Huth const char *name; 31a9f8b16fSGleb Natapov uint32_t unit_sel; 32a9f8b16fSGleb Natapov int min; 33a9f8b16fSGleb Natapov int max; 347c648ce2SLike Xu } intel_gp_events[] = { 35a9f8b16fSGleb Natapov {"core cycles", 0x003c, 1*N, 50*N}, 36a9f8b16fSGleb Natapov {"instructions", 0x00c0, 10*N, 10.2*N}, 37290f4213SJim Mattson {"ref cycles", 0x013c, 1*N, 30*N}, 38290f4213SJim Mattson {"llc references", 0x4f2e, 1, 2*N}, 39a9f8b16fSGleb Natapov {"llc misses", 0x412e, 1, 1*N}, 40a9f8b16fSGleb Natapov {"branches", 0x00c4, 1*N, 1.1*N}, 41a9f8b16fSGleb Natapov {"branch misses", 0x00c5, 0, 0.1*N}, 42b883751aSLike Xu }, amd_gp_events[] = { 43b883751aSLike Xu {"core cycles", 0x0076, 1*N, 50*N}, 44b883751aSLike Xu {"instructions", 0x00c0, 10*N, 10.2*N}, 45b883751aSLike Xu {"branches", 0x00c2, 1*N, 1.1*N}, 46b883751aSLike Xu {"branch misses", 0x00c3, 0, 0.1*N}, 47a9f8b16fSGleb Natapov }, fixed_events[] = { 485d6a3a54SDapeng Mi {"fixed 0", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N}, 495d6a3a54SDapeng Mi {"fixed 1", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N}, 505d6a3a54SDapeng Mi {"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N} 51a9f8b16fSGleb Natapov }; 52a9f8b16fSGleb Natapov 53f4e97f59SDapeng Mi /* 54f4e97f59SDapeng Mi * Events index in intel_gp_events[], ensure consistent with 55f4e97f59SDapeng Mi * intel_gp_events[]. 56f4e97f59SDapeng Mi */ 57f4e97f59SDapeng Mi enum { 58*85c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX = 1, 5925cc1ea7SDapeng Mi INTEL_REF_CYCLES_IDX = 2, 60f4e97f59SDapeng Mi INTEL_BRANCHES_IDX = 5, 61f4e97f59SDapeng Mi }; 62f4e97f59SDapeng Mi 63f4e97f59SDapeng Mi /* 64f4e97f59SDapeng Mi * Events index in amd_gp_events[], ensure consistent with 65f4e97f59SDapeng Mi * amd_gp_events[]. 66f4e97f59SDapeng Mi */ 67f4e97f59SDapeng Mi enum { 68*85c75578SDapeng Mi AMD_INSTRUCTIONS_IDX = 1, 69f4e97f59SDapeng Mi AMD_BRANCHES_IDX = 2, 70f4e97f59SDapeng Mi }; 71f4e97f59SDapeng Mi 72a9f8b16fSGleb Natapov char *buf; 73a9f8b16fSGleb Natapov 747c648ce2SLike Xu static struct pmu_event *gp_events; 757c648ce2SLike Xu static unsigned int gp_events_size; 769c07c92bSDapeng Mi static unsigned int fixed_counters_num; 777c648ce2SLike Xu 787db17e21SThomas Huth static inline void loop(void) 79a9f8b16fSGleb Natapov { 80a9f8b16fSGleb Natapov unsigned long tmp, tmp2, tmp3; 81a9f8b16fSGleb Natapov 82a9f8b16fSGleb Natapov asm volatile("1: mov (%1), %2; add $64, %1; nop; nop; nop; nop; nop; nop; nop; loop 1b" 83a9f8b16fSGleb Natapov : "=c"(tmp), "=r"(tmp2), "=r"(tmp3): "0"(N), "1"(buf)); 84a9f8b16fSGleb Natapov 85a9f8b16fSGleb Natapov } 86a9f8b16fSGleb Natapov 87a9f8b16fSGleb Natapov volatile uint64_t irq_received; 88a9f8b16fSGleb Natapov 89a9f8b16fSGleb Natapov static void cnt_overflow(isr_regs_t *regs) 90a9f8b16fSGleb Natapov { 91a9f8b16fSGleb Natapov irq_received++; 92c595c361SMingwei Zhang apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); 93a9f8b16fSGleb Natapov apic_write(APIC_EOI, 0); 94a9f8b16fSGleb Natapov } 95a9f8b16fSGleb Natapov 96a9f8b16fSGleb Natapov static bool check_irq(void) 97a9f8b16fSGleb Natapov { 98a9f8b16fSGleb Natapov int i; 99a9f8b16fSGleb Natapov irq_received = 0; 100787f0aebSMaxim Levitsky sti(); 101a9f8b16fSGleb Natapov for (i = 0; i < 100000 && !irq_received; i++) 102a9f8b16fSGleb Natapov asm volatile("pause"); 103787f0aebSMaxim Levitsky cli(); 104a9f8b16fSGleb Natapov return irq_received; 105a9f8b16fSGleb Natapov } 106a9f8b16fSGleb Natapov 107a9f8b16fSGleb Natapov static bool is_gp(pmu_counter_t *evt) 108a9f8b16fSGleb Natapov { 109b883751aSLike Xu if (!pmu.is_intel) 110b883751aSLike Xu return true; 111b883751aSLike Xu 11222f2901aSLike Xu return evt->ctr < MSR_CORE_PERF_FIXED_CTR0 || 11322f2901aSLike Xu evt->ctr >= MSR_IA32_PMC0; 114a9f8b16fSGleb Natapov } 115a9f8b16fSGleb Natapov 116a9f8b16fSGleb Natapov static int event_to_global_idx(pmu_counter_t *cnt) 117a9f8b16fSGleb Natapov { 118b883751aSLike Xu if (pmu.is_intel) 119cda64e80SLike Xu return cnt->ctr - (is_gp(cnt) ? pmu.msr_gp_counter_base : 120a9f8b16fSGleb Natapov (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); 121b883751aSLike Xu 122b883751aSLike Xu if (pmu.msr_gp_counter_base == MSR_F15H_PERF_CTR0) 123b883751aSLike Xu return (cnt->ctr - pmu.msr_gp_counter_base) / 2; 124b883751aSLike Xu else 125b883751aSLike Xu return cnt->ctr - pmu.msr_gp_counter_base; 126a9f8b16fSGleb Natapov } 127a9f8b16fSGleb Natapov 128a9f8b16fSGleb Natapov static struct pmu_event* get_counter_event(pmu_counter_t *cnt) 129a9f8b16fSGleb Natapov { 130a9f8b16fSGleb Natapov if (is_gp(cnt)) { 131a9f8b16fSGleb Natapov int i; 132a9f8b16fSGleb Natapov 1337c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 134a9f8b16fSGleb Natapov if (gp_events[i].unit_sel == (cnt->config & 0xffff)) 135a9f8b16fSGleb Natapov return &gp_events[i]; 1369c07c92bSDapeng Mi } else { 1379c07c92bSDapeng Mi unsigned int idx = cnt->ctr - MSR_CORE_PERF_FIXED_CTR0; 1389c07c92bSDapeng Mi 1399c07c92bSDapeng Mi if (idx < ARRAY_SIZE(fixed_events)) 1409c07c92bSDapeng Mi return &fixed_events[idx]; 1419c07c92bSDapeng Mi } 142a9f8b16fSGleb Natapov 143a9f8b16fSGleb Natapov return (void*)0; 144a9f8b16fSGleb Natapov } 145a9f8b16fSGleb Natapov 146a9f8b16fSGleb Natapov static void global_enable(pmu_counter_t *cnt) 147a9f8b16fSGleb Natapov { 14862ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 14962ba5036SLike Xu return; 15062ba5036SLike Xu 151a9f8b16fSGleb Natapov cnt->idx = event_to_global_idx(cnt); 1528a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) | BIT_ULL(cnt->idx)); 153a9f8b16fSGleb Natapov } 154a9f8b16fSGleb Natapov 155a9f8b16fSGleb Natapov static void global_disable(pmu_counter_t *cnt) 156a9f8b16fSGleb Natapov { 15762ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 15862ba5036SLike Xu return; 15962ba5036SLike Xu 1608a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) & ~BIT_ULL(cnt->idx)); 161a9f8b16fSGleb Natapov } 162a9f8b16fSGleb Natapov 163e9e7577bSLike Xu static void __start_event(pmu_counter_t *evt, uint64_t count) 164a9f8b16fSGleb Natapov { 165e9e7577bSLike Xu evt->count = count; 166a9f8b16fSGleb Natapov wrmsr(evt->ctr, evt->count); 167cda64e80SLike Xu if (is_gp(evt)) { 168cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 169a9f8b16fSGleb Natapov evt->config | EVNTSEL_EN); 170cda64e80SLike Xu } else { 171a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 172a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 173a9f8b16fSGleb Natapov uint32_t usrospmi = 0; 174a9f8b16fSGleb Natapov 175a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_OS) 176a9f8b16fSGleb Natapov usrospmi |= (1 << 0); 177a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_USR) 178a9f8b16fSGleb Natapov usrospmi |= (1 << 1); 179a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_INT) 180a9f8b16fSGleb Natapov usrospmi |= (1 << 3); // PMI on overflow 181a9f8b16fSGleb Natapov ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift); 182a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl); 183a9f8b16fSGleb Natapov } 184a9f8b16fSGleb Natapov global_enable(evt); 1855a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 186a9f8b16fSGleb Natapov } 187a9f8b16fSGleb Natapov 188e9e7577bSLike Xu static void start_event(pmu_counter_t *evt) 189e9e7577bSLike Xu { 190e9e7577bSLike Xu __start_event(evt, 0); 191e9e7577bSLike Xu } 192e9e7577bSLike Xu 193a9f8b16fSGleb Natapov static void stop_event(pmu_counter_t *evt) 194a9f8b16fSGleb Natapov { 195a9f8b16fSGleb Natapov global_disable(evt); 196cda64e80SLike Xu if (is_gp(evt)) { 197cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 198a9f8b16fSGleb Natapov evt->config & ~EVNTSEL_EN); 199cda64e80SLike Xu } else { 200a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 201a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 202a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift)); 203a9f8b16fSGleb Natapov } 204a9f8b16fSGleb Natapov evt->count = rdmsr(evt->ctr); 205a9f8b16fSGleb Natapov } 206a9f8b16fSGleb Natapov 2078554261fSLike Xu static noinline void measure_many(pmu_counter_t *evt, int count) 208a9f8b16fSGleb Natapov { 209a9f8b16fSGleb Natapov int i; 210a9f8b16fSGleb Natapov for (i = 0; i < count; i++) 211a9f8b16fSGleb Natapov start_event(&evt[i]); 212a9f8b16fSGleb Natapov loop(); 213a9f8b16fSGleb Natapov for (i = 0; i < count; i++) 214a9f8b16fSGleb Natapov stop_event(&evt[i]); 215a9f8b16fSGleb Natapov } 216a9f8b16fSGleb Natapov 2178554261fSLike Xu static void measure_one(pmu_counter_t *evt) 2188554261fSLike Xu { 2198554261fSLike Xu measure_many(evt, 1); 2208554261fSLike Xu } 2218554261fSLike Xu 222e9e7577bSLike Xu static noinline void __measure(pmu_counter_t *evt, uint64_t count) 223e9e7577bSLike Xu { 224e9e7577bSLike Xu __start_event(evt, count); 225e9e7577bSLike Xu loop(); 226e9e7577bSLike Xu stop_event(evt); 227e9e7577bSLike Xu } 228e9e7577bSLike Xu 229a9f8b16fSGleb Natapov static bool verify_event(uint64_t count, struct pmu_event *e) 230a9f8b16fSGleb Natapov { 2319c07c92bSDapeng Mi bool pass; 232d24d3381SDapeng Mi 2339c07c92bSDapeng Mi if (!e) 2349c07c92bSDapeng Mi return false; 2359c07c92bSDapeng Mi 2369c07c92bSDapeng Mi pass = count >= e->min && count <= e->max; 237d24d3381SDapeng Mi if (!pass) 238d24d3381SDapeng Mi printf("FAIL: %d <= %"PRId64" <= %d\n", e->min, count, e->max); 239d24d3381SDapeng Mi 240d24d3381SDapeng Mi return pass; 241a9f8b16fSGleb Natapov } 242a9f8b16fSGleb Natapov 243a9f8b16fSGleb Natapov static bool verify_counter(pmu_counter_t *cnt) 244a9f8b16fSGleb Natapov { 245a9f8b16fSGleb Natapov return verify_event(cnt->count, get_counter_event(cnt)); 246a9f8b16fSGleb Natapov } 247a9f8b16fSGleb Natapov 248a9f8b16fSGleb Natapov static void check_gp_counter(struct pmu_event *evt) 249a9f8b16fSGleb Natapov { 250a9f8b16fSGleb Natapov pmu_counter_t cnt = { 251a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, 252a9f8b16fSGleb Natapov }; 253a9f8b16fSGleb Natapov int i; 254a9f8b16fSGleb Natapov 255cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 256cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 2578554261fSLike Xu measure_one(&cnt); 258a299895bSThomas Huth report(verify_event(cnt.count, evt), "%s-%d", evt->name, i); 259a9f8b16fSGleb Natapov } 260a9f8b16fSGleb Natapov } 261a9f8b16fSGleb Natapov 262a9f8b16fSGleb Natapov static void check_gp_counters(void) 263a9f8b16fSGleb Natapov { 264a9f8b16fSGleb Natapov int i; 265a9f8b16fSGleb Natapov 2667c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 2672719b92cSYang Weijiang if (pmu_gp_counter_is_available(i)) 268a9f8b16fSGleb Natapov check_gp_counter(&gp_events[i]); 269a9f8b16fSGleb Natapov else 270a9f8b16fSGleb Natapov printf("GP event '%s' is disabled\n", 271a9f8b16fSGleb Natapov gp_events[i].name); 272a9f8b16fSGleb Natapov } 273a9f8b16fSGleb Natapov 274a9f8b16fSGleb Natapov static void check_fixed_counters(void) 275a9f8b16fSGleb Natapov { 276a9f8b16fSGleb Natapov pmu_counter_t cnt = { 277a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR, 278a9f8b16fSGleb Natapov }; 279a9f8b16fSGleb Natapov int i; 280a9f8b16fSGleb Natapov 2819c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 282a9f8b16fSGleb Natapov cnt.ctr = fixed_events[i].unit_sel; 2838554261fSLike Xu measure_one(&cnt); 2842719b92cSYang Weijiang report(verify_event(cnt.count, &fixed_events[i]), "fixed-%d", i); 285a9f8b16fSGleb Natapov } 286a9f8b16fSGleb Natapov } 287a9f8b16fSGleb Natapov 288a9f8b16fSGleb Natapov static void check_counters_many(void) 289a9f8b16fSGleb Natapov { 290f21c809eSDapeng Mi pmu_counter_t cnt[48]; 291a9f8b16fSGleb Natapov int i, n; 292a9f8b16fSGleb Natapov 293414ee7d1SSean Christopherson for (i = 0, n = 0; n < pmu.nr_gp_counters; i++) { 2942719b92cSYang Weijiang if (!pmu_gp_counter_is_available(i)) 295a9f8b16fSGleb Natapov continue; 296a9f8b16fSGleb Natapov 297cda64e80SLike Xu cnt[n].ctr = MSR_GP_COUNTERx(n); 2984ac45293SWei Huang cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | 2997c648ce2SLike Xu gp_events[i % gp_events_size].unit_sel; 300a9f8b16fSGleb Natapov n++; 301a9f8b16fSGleb Natapov } 3029c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 303a9f8b16fSGleb Natapov cnt[n].ctr = fixed_events[i].unit_sel; 304a9f8b16fSGleb Natapov cnt[n].config = EVNTSEL_OS | EVNTSEL_USR; 305a9f8b16fSGleb Natapov n++; 306a9f8b16fSGleb Natapov } 307a9f8b16fSGleb Natapov 308f21c809eSDapeng Mi assert(n <= ARRAY_SIZE(cnt)); 3098554261fSLike Xu measure_many(cnt, n); 310a9f8b16fSGleb Natapov 311a9f8b16fSGleb Natapov for (i = 0; i < n; i++) 312a9f8b16fSGleb Natapov if (!verify_counter(&cnt[i])) 313a9f8b16fSGleb Natapov break; 314a9f8b16fSGleb Natapov 315a299895bSThomas Huth report(i == n, "all counters"); 316a9f8b16fSGleb Natapov } 317a9f8b16fSGleb Natapov 3187ec3b67aSLike Xu static uint64_t measure_for_overflow(pmu_counter_t *cnt) 3197ec3b67aSLike Xu { 3207ec3b67aSLike Xu __measure(cnt, 0); 3217ec3b67aSLike Xu /* 3227ec3b67aSLike Xu * To generate overflow, i.e. roll over to '0', the initial count just 3237ec3b67aSLike Xu * needs to be preset to the negative expected count. However, as per 3247ec3b67aSLike Xu * Intel's SDM, the preset count needs to be incremented by 1 to ensure 3257ec3b67aSLike Xu * the overflow interrupt is generated immediately instead of possibly 3267ec3b67aSLike Xu * waiting for the overflow to propagate through the counter. 3277ec3b67aSLike Xu */ 3287ec3b67aSLike Xu assert(cnt->count > 1); 3297ec3b67aSLike Xu return 1 - cnt->count; 3307ec3b67aSLike Xu } 3317ec3b67aSLike Xu 332a9f8b16fSGleb Natapov static void check_counter_overflow(void) 333a9f8b16fSGleb Natapov { 334a9f8b16fSGleb Natapov int i; 335*85c75578SDapeng Mi uint64_t overflow_preset; 336*85c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 337*85c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 338*85c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 339*85c75578SDapeng Mi 340a9f8b16fSGleb Natapov pmu_counter_t cnt = { 341cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 342*85c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 343*85c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 344a9f8b16fSGleb Natapov }; 3457ec3b67aSLike Xu overflow_preset = measure_for_overflow(&cnt); 346a9f8b16fSGleb Natapov 347a9f8b16fSGleb Natapov /* clear status before test */ 34862ba5036SLike Xu if (this_cpu_has_perf_global_status()) 3498a2866d1SLike Xu pmu_clear_global_status(); 350a9f8b16fSGleb Natapov 3515bba1769SAndrew Jones report_prefix_push("overflow"); 3525bba1769SAndrew Jones 353cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters + 1; i++) { 354a9f8b16fSGleb Natapov uint64_t status; 355a9f8b16fSGleb Natapov int idx; 35633cfc1b0SNadav Amit 3577ec3b67aSLike Xu cnt.count = overflow_preset; 358cda64e80SLike Xu if (pmu_use_full_writes()) 359414ee7d1SSean Christopherson cnt.count &= (1ull << pmu.gp_counter_width) - 1; 36033cfc1b0SNadav Amit 361414ee7d1SSean Christopherson if (i == pmu.nr_gp_counters) { 362b883751aSLike Xu if (!pmu.is_intel) 363b883751aSLike Xu break; 364b883751aSLike Xu 365a9f8b16fSGleb Natapov cnt.ctr = fixed_events[0].unit_sel; 3667ec3b67aSLike Xu cnt.count = measure_for_overflow(&cnt); 367cda64e80SLike Xu cnt.count &= (1ull << pmu.gp_counter_width) - 1; 368cda64e80SLike Xu } else { 369cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 37033cfc1b0SNadav Amit } 37133cfc1b0SNadav Amit 372a9f8b16fSGleb Natapov if (i % 2) 373a9f8b16fSGleb Natapov cnt.config |= EVNTSEL_INT; 374a9f8b16fSGleb Natapov else 375a9f8b16fSGleb Natapov cnt.config &= ~EVNTSEL_INT; 376a9f8b16fSGleb Natapov idx = event_to_global_idx(&cnt); 377e9e7577bSLike Xu __measure(&cnt, cnt.count); 378b883751aSLike Xu if (pmu.is_intel) 379a299895bSThomas Huth report(cnt.count == 1, "cntr-%d", i); 380b883751aSLike Xu else 381b883751aSLike Xu report(cnt.count == 0xffffffffffff || cnt.count < 7, "cntr-%d", i); 38262ba5036SLike Xu 38362ba5036SLike Xu if (!this_cpu_has_perf_global_status()) 38462ba5036SLike Xu continue; 38562ba5036SLike Xu 3868a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 387a299895bSThomas Huth report(status & (1ull << idx), "status-%d", i); 3888a2866d1SLike Xu wrmsr(pmu.msr_global_status_clr, status); 3898a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 390a299895bSThomas Huth report(!(status & (1ull << idx)), "status clear-%d", i); 391a299895bSThomas Huth report(check_irq() == (i % 2), "irq-%d", i); 392a9f8b16fSGleb Natapov } 3935bba1769SAndrew Jones 3945bba1769SAndrew Jones report_prefix_pop(); 395a9f8b16fSGleb Natapov } 396a9f8b16fSGleb Natapov 397a9f8b16fSGleb Natapov static void check_gp_counter_cmask(void) 398a9f8b16fSGleb Natapov { 399*85c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 400*85c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 401*85c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 402*85c75578SDapeng Mi 403a9f8b16fSGleb Natapov pmu_counter_t cnt = { 404cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 405*85c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 406*85c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 407a9f8b16fSGleb Natapov }; 408a9f8b16fSGleb Natapov cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); 4098554261fSLike Xu measure_one(&cnt); 410*85c75578SDapeng Mi report(cnt.count < gp_events[instruction_idx].min, "cmask"); 411a9f8b16fSGleb Natapov } 412a9f8b16fSGleb Natapov 413ca1b9de9SNadav Amit static void do_rdpmc_fast(void *ptr) 414ca1b9de9SNadav Amit { 415ca1b9de9SNadav Amit pmu_counter_t *cnt = ptr; 416ca1b9de9SNadav Amit uint32_t idx = (uint32_t)cnt->idx | (1u << 31); 417ca1b9de9SNadav Amit 418ca1b9de9SNadav Amit if (!is_gp(cnt)) 419ca1b9de9SNadav Amit idx |= 1 << 30; 420ca1b9de9SNadav Amit 421ca1b9de9SNadav Amit cnt->count = rdpmc(idx); 422ca1b9de9SNadav Amit } 423ca1b9de9SNadav Amit 424ca1b9de9SNadav Amit 425a9f8b16fSGleb Natapov static void check_rdpmc(void) 426a9f8b16fSGleb Natapov { 42722f2901aSLike Xu uint64_t val = 0xff0123456789ull; 428ca1b9de9SNadav Amit bool exc; 429a9f8b16fSGleb Natapov int i; 430a9f8b16fSGleb Natapov 4315bba1769SAndrew Jones report_prefix_push("rdpmc"); 4325bba1769SAndrew Jones 433414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 43433cfc1b0SNadav Amit uint64_t x; 435ca1b9de9SNadav Amit pmu_counter_t cnt = { 436cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(i), 437ca1b9de9SNadav Amit .idx = i 438ca1b9de9SNadav Amit }; 43933cfc1b0SNadav Amit 44033cfc1b0SNadav Amit /* 44122f2901aSLike Xu * Without full-width writes, only the low 32 bits are writable, 44222f2901aSLike Xu * and the value is sign-extended. 44333cfc1b0SNadav Amit */ 444cda64e80SLike Xu if (pmu.msr_gp_counter_base == MSR_IA32_PERFCTR0) 44533cfc1b0SNadav Amit x = (uint64_t)(int64_t)(int32_t)val; 44622f2901aSLike Xu else 44722f2901aSLike Xu x = (uint64_t)(int64_t)val; 44833cfc1b0SNadav Amit 44933cfc1b0SNadav Amit /* Mask according to the number of supported bits */ 450414ee7d1SSean Christopherson x &= (1ull << pmu.gp_counter_width) - 1; 45133cfc1b0SNadav Amit 452cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(i), val); 453a299895bSThomas Huth report(rdpmc(i) == x, "cntr-%d", i); 454ca1b9de9SNadav Amit 455ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 456ca1b9de9SNadav Amit if (exc) 457ca1b9de9SNadav Amit report_skip("fast-%d", i); 458ca1b9de9SNadav Amit else 459a299895bSThomas Huth report(cnt.count == (u32)val, "fast-%d", i); 460a9f8b16fSGleb Natapov } 4619c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 462414ee7d1SSean Christopherson uint64_t x = val & ((1ull << pmu.fixed_counter_width) - 1); 463ca1b9de9SNadav Amit pmu_counter_t cnt = { 464ca1b9de9SNadav Amit .ctr = MSR_CORE_PERF_FIXED_CTR0 + i, 465ca1b9de9SNadav Amit .idx = i 466ca1b9de9SNadav Amit }; 46733cfc1b0SNadav Amit 4683f914933SLike Xu wrmsr(MSR_PERF_FIXED_CTRx(i), x); 469a299895bSThomas Huth report(rdpmc(i | (1 << 30)) == x, "fixed cntr-%d", i); 470ca1b9de9SNadav Amit 471ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 472ca1b9de9SNadav Amit if (exc) 473ca1b9de9SNadav Amit report_skip("fixed fast-%d", i); 474ca1b9de9SNadav Amit else 475a299895bSThomas Huth report(cnt.count == (u32)x, "fixed fast-%d", i); 476a9f8b16fSGleb Natapov } 4775bba1769SAndrew Jones 4785bba1769SAndrew Jones report_prefix_pop(); 479a9f8b16fSGleb Natapov } 480a9f8b16fSGleb Natapov 481ddade902SEric Hankland static void check_running_counter_wrmsr(void) 482ddade902SEric Hankland { 48359ca1413SEric Hankland uint64_t status; 48422f2901aSLike Xu uint64_t count; 485*85c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 486*85c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 487*85c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 488*85c75578SDapeng Mi 489ddade902SEric Hankland pmu_counter_t evt = { 490cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 491*85c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 492*85c75578SDapeng Mi gp_events[instruction_idx].unit_sel, 493ddade902SEric Hankland }; 494ddade902SEric Hankland 49559ca1413SEric Hankland report_prefix_push("running counter wrmsr"); 49659ca1413SEric Hankland 497ddade902SEric Hankland start_event(&evt); 498ddade902SEric Hankland loop(); 499cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), 0); 500ddade902SEric Hankland stop_event(&evt); 501*85c75578SDapeng Mi report(evt.count < gp_events[instruction_idx].min, "cntr"); 50259ca1413SEric Hankland 50359ca1413SEric Hankland /* clear status before overflow test */ 50462ba5036SLike Xu if (this_cpu_has_perf_global_status()) 5058a2866d1SLike Xu pmu_clear_global_status(); 50659ca1413SEric Hankland 50759ca1413SEric Hankland start_event(&evt); 50822f2901aSLike Xu 50922f2901aSLike Xu count = -1; 510cda64e80SLike Xu if (pmu_use_full_writes()) 511414ee7d1SSean Christopherson count &= (1ull << pmu.gp_counter_width) - 1; 51222f2901aSLike Xu 513cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), count); 51422f2901aSLike Xu 51559ca1413SEric Hankland loop(); 51659ca1413SEric Hankland stop_event(&evt); 51762ba5036SLike Xu 51862ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 5198a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 5208a2866d1SLike Xu report(status & 1, "status msr bit"); 52162ba5036SLike Xu } 52259ca1413SEric Hankland 52359ca1413SEric Hankland report_prefix_pop(); 524ddade902SEric Hankland } 525ddade902SEric Hankland 52620cf9147SJim Mattson static void check_emulated_instr(void) 52720cf9147SJim Mattson { 52820cf9147SJim Mattson uint64_t status, instr_start, brnch_start; 5298b547cc2SLike Xu uint64_t gp_counter_width = (1ull << pmu.gp_counter_width) - 1; 530f4e97f59SDapeng Mi unsigned int branch_idx = pmu.is_intel ? 531f4e97f59SDapeng Mi INTEL_BRANCHES_IDX : AMD_BRANCHES_IDX; 532*85c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 533*85c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 534*85c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 53520cf9147SJim Mattson pmu_counter_t brnch_cnt = { 536cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 53720cf9147SJim Mattson /* branch instructions */ 538b883751aSLike Xu .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[branch_idx].unit_sel, 53920cf9147SJim Mattson }; 54020cf9147SJim Mattson pmu_counter_t instr_cnt = { 541cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(1), 54220cf9147SJim Mattson /* instructions */ 543*85c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[instruction_idx].unit_sel, 54420cf9147SJim Mattson }; 54520cf9147SJim Mattson report_prefix_push("emulated instruction"); 54620cf9147SJim Mattson 54762ba5036SLike Xu if (this_cpu_has_perf_global_status()) 5488a2866d1SLike Xu pmu_clear_global_status(); 54920cf9147SJim Mattson 55020cf9147SJim Mattson start_event(&brnch_cnt); 55120cf9147SJim Mattson start_event(&instr_cnt); 55220cf9147SJim Mattson 55320cf9147SJim Mattson brnch_start = -EXPECTED_BRNCH; 55420cf9147SJim Mattson instr_start = -EXPECTED_INSTR; 5558b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(0), brnch_start & gp_counter_width); 5568b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(1), instr_start & gp_counter_width); 55720cf9147SJim Mattson // KVM_FEP is a magic prefix that forces emulation so 55820cf9147SJim Mattson // 'KVM_FEP "jne label\n"' just counts as a single instruction. 55920cf9147SJim Mattson asm volatile( 56020cf9147SJim Mattson "mov $0x0, %%eax\n" 56120cf9147SJim Mattson "cmp $0x0, %%eax\n" 56220cf9147SJim Mattson KVM_FEP "jne label\n" 56320cf9147SJim Mattson KVM_FEP "jne label\n" 56420cf9147SJim Mattson KVM_FEP "jne label\n" 56520cf9147SJim Mattson KVM_FEP "jne label\n" 56620cf9147SJim Mattson KVM_FEP "jne label\n" 56720cf9147SJim Mattson "mov $0xa, %%eax\n" 56820cf9147SJim Mattson "cpuid\n" 56920cf9147SJim Mattson "mov $0xa, %%eax\n" 57020cf9147SJim Mattson "cpuid\n" 57120cf9147SJim Mattson "mov $0xa, %%eax\n" 57220cf9147SJim Mattson "cpuid\n" 57320cf9147SJim Mattson "mov $0xa, %%eax\n" 57420cf9147SJim Mattson "cpuid\n" 57520cf9147SJim Mattson "mov $0xa, %%eax\n" 57620cf9147SJim Mattson "cpuid\n" 57720cf9147SJim Mattson "label:\n" 57820cf9147SJim Mattson : 57920cf9147SJim Mattson : 58020cf9147SJim Mattson : "eax", "ebx", "ecx", "edx"); 58120cf9147SJim Mattson 58262ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 5838a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 58420cf9147SJim Mattson 58520cf9147SJim Mattson stop_event(&brnch_cnt); 58620cf9147SJim Mattson stop_event(&instr_cnt); 58720cf9147SJim Mattson 58820cf9147SJim Mattson // Check that the end count - start count is at least the expected 58920cf9147SJim Mattson // number of instructions and branches. 59020cf9147SJim Mattson report(instr_cnt.count - instr_start >= EXPECTED_INSTR, 59120cf9147SJim Mattson "instruction count"); 59220cf9147SJim Mattson report(brnch_cnt.count - brnch_start >= EXPECTED_BRNCH, 59320cf9147SJim Mattson "branch count"); 59462ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 59520cf9147SJim Mattson // Additionally check that those counters overflowed properly. 5968a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 5974070b9c6SLike Xu report(status & 1, "branch counter overflow"); 5984070b9c6SLike Xu report(status & 2, "instruction counter overflow"); 59962ba5036SLike Xu } 60020cf9147SJim Mattson 60120cf9147SJim Mattson report_prefix_pop(); 60220cf9147SJim Mattson } 60320cf9147SJim Mattson 604006b089dSLike Xu #define XBEGIN_STARTED (~0u) 605006b089dSLike Xu static void check_tsx_cycles(void) 606006b089dSLike Xu { 607006b089dSLike Xu pmu_counter_t cnt; 608006b089dSLike Xu unsigned int i, ret = 0; 609006b089dSLike Xu 610006b089dSLike Xu if (!this_cpu_has(X86_FEATURE_RTM)) 611006b089dSLike Xu return; 612006b089dSLike Xu 613006b089dSLike Xu report_prefix_push("TSX cycles"); 614006b089dSLike Xu 615006b089dSLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 616006b089dSLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 617006b089dSLike Xu 618006b089dSLike Xu if (i == 2) { 619d4ae0a71SThomas Huth /* Transactional cycles committed only on gp counter 2 */ 620006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x30000003c; 621006b089dSLike Xu } else { 622006b089dSLike Xu /* Transactional cycles */ 623006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x10000003c; 624006b089dSLike Xu } 625006b089dSLike Xu 626006b089dSLike Xu start_event(&cnt); 627006b089dSLike Xu 628006b089dSLike Xu asm volatile("xbegin 1f\n\t" 629006b089dSLike Xu "1:\n\t" 630006b089dSLike Xu : "+a" (ret) :: "memory"); 631006b089dSLike Xu 632006b089dSLike Xu /* Generate a non-canonical #GP to trigger ABORT. */ 633006b089dSLike Xu if (ret == XBEGIN_STARTED) 634006b089dSLike Xu *(int *)NONCANONICAL = 0; 635006b089dSLike Xu 636006b089dSLike Xu stop_event(&cnt); 637006b089dSLike Xu 638006b089dSLike Xu report(cnt.count > 0, "gp cntr-%d with a value of %" PRId64 "", i, cnt.count); 639006b089dSLike Xu } 640006b089dSLike Xu 641006b089dSLike Xu report_prefix_pop(); 642006b089dSLike Xu } 643006b089dSLike Xu 644f2a56148SDapeng Mi static void warm_up(void) 645f2a56148SDapeng Mi { 646f2a56148SDapeng Mi int i; 647f2a56148SDapeng Mi 648f2a56148SDapeng Mi /* 649f2a56148SDapeng Mi * Since cycles event is always run as the first event, there would be 650f2a56148SDapeng Mi * a warm-up state to warm up the cache, it leads to the measured cycles 651f2a56148SDapeng Mi * value may exceed the pre-defined cycles upper boundary and cause 652f2a56148SDapeng Mi * false positive. To avoid this, introduce an warm-up state before 653f2a56148SDapeng Mi * the real verification. 654f2a56148SDapeng Mi */ 655f2a56148SDapeng Mi for (i = 0; i < 10; i++) 656f2a56148SDapeng Mi loop(); 657f2a56148SDapeng Mi } 658f2a56148SDapeng Mi 65922f2901aSLike Xu static void check_counters(void) 66022f2901aSLike Xu { 66100dca75cSLike Xu if (is_fep_available()) 66200dca75cSLike Xu check_emulated_instr(); 66300dca75cSLike Xu 664f2a56148SDapeng Mi warm_up(); 66522f2901aSLike Xu check_gp_counters(); 66622f2901aSLike Xu check_fixed_counters(); 66722f2901aSLike Xu check_rdpmc(); 66822f2901aSLike Xu check_counters_many(); 66922f2901aSLike Xu check_counter_overflow(); 67022f2901aSLike Xu check_gp_counter_cmask(); 67122f2901aSLike Xu check_running_counter_wrmsr(); 672006b089dSLike Xu check_tsx_cycles(); 67322f2901aSLike Xu } 67422f2901aSLike Xu 67522f2901aSLike Xu static void do_unsupported_width_counter_write(void *index) 67622f2901aSLike Xu { 67722f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + *((int *) index), 0xffffff0123456789ull); 67822f2901aSLike Xu } 67922f2901aSLike Xu 68022f2901aSLike Xu static void check_gp_counters_write_width(void) 68122f2901aSLike Xu { 68222f2901aSLike Xu u64 val_64 = 0xffffff0123456789ull; 6834b74c718SThomas Huth u64 val_32 = val_64 & ((1ull << 32) - 1); 684414ee7d1SSean Christopherson u64 val_max_width = val_64 & ((1ull << pmu.gp_counter_width) - 1); 68522f2901aSLike Xu int i; 68622f2901aSLike Xu 68722f2901aSLike Xu /* 68822f2901aSLike Xu * MSR_IA32_PERFCTRn supports 64-bit writes, 68922f2901aSLike Xu * but only the lowest 32 bits are valid. 69022f2901aSLike Xu */ 691414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 69222f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_32); 69322f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 69422f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 69522f2901aSLike Xu 69622f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_max_width); 69722f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 69822f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 69922f2901aSLike Xu 70022f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_64); 70122f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 70222f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 70322f2901aSLike Xu } 70422f2901aSLike Xu 70522f2901aSLike Xu /* 7064340720eSLike Xu * MSR_IA32_PMCn supports writing values up to GP counter width, 70722f2901aSLike Xu * and only the lowest bits of GP counter width are valid. 70822f2901aSLike Xu */ 709414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 71022f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_32); 71122f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 71222f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 71322f2901aSLike Xu 71422f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_max_width); 71522f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_max_width); 71622f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_max_width); 71722f2901aSLike Xu 71822f2901aSLike Xu report(test_for_exception(GP_VECTOR, 71922f2901aSLike Xu do_unsupported_width_counter_write, &i), 72022f2901aSLike Xu "writing unsupported width to MSR_IA32_PMC%d raises #GP", i); 72122f2901aSLike Xu } 72222f2901aSLike Xu } 72322f2901aSLike Xu 724290f4213SJim Mattson /* 725290f4213SJim Mattson * Per the SDM, reference cycles are currently implemented using the 726290f4213SJim Mattson * core crystal clock, TSC, or bus clock. Calibrate to the TSC 727290f4213SJim Mattson * frequency to set reasonable expectations. 728290f4213SJim Mattson */ 729290f4213SJim Mattson static void set_ref_cycle_expectations(void) 730290f4213SJim Mattson { 731290f4213SJim Mattson pmu_counter_t cnt = { 732290f4213SJim Mattson .ctr = MSR_IA32_PERFCTR0, 73325cc1ea7SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 73425cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].unit_sel, 735290f4213SJim Mattson }; 736290f4213SJim Mattson uint64_t tsc_delta; 737290f4213SJim Mattson uint64_t t0, t1, t2, t3; 738290f4213SJim Mattson 7392719b92cSYang Weijiang /* Bit 2 enumerates the availability of reference cycles events. */ 740414ee7d1SSean Christopherson if (!pmu.nr_gp_counters || !pmu_gp_counter_is_available(2)) 741290f4213SJim Mattson return; 742290f4213SJim Mattson 74362ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 7448a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 745290f4213SJim Mattson 746290f4213SJim Mattson t0 = fenced_rdtsc(); 747290f4213SJim Mattson start_event(&cnt); 748290f4213SJim Mattson t1 = fenced_rdtsc(); 749290f4213SJim Mattson 750290f4213SJim Mattson /* 751290f4213SJim Mattson * This loop has to run long enough to dominate the VM-exit 752290f4213SJim Mattson * costs for playing with the PMU MSRs on start and stop. 753290f4213SJim Mattson * 754290f4213SJim Mattson * On a 2.6GHz Ice Lake, with the TSC frequency at 104 times 755290f4213SJim Mattson * the core crystal clock, this function calculated a guest 756290f4213SJim Mattson * TSC : ref cycles ratio of around 105 with ECX initialized 757290f4213SJim Mattson * to one billion. 758290f4213SJim Mattson */ 759290f4213SJim Mattson asm volatile("loop ." : "+c"((int){1000000000ull})); 760290f4213SJim Mattson 761290f4213SJim Mattson t2 = fenced_rdtsc(); 762290f4213SJim Mattson stop_event(&cnt); 763290f4213SJim Mattson t3 = fenced_rdtsc(); 764290f4213SJim Mattson 765290f4213SJim Mattson tsc_delta = ((t2 - t1) + (t3 - t0)) / 2; 766290f4213SJim Mattson 767290f4213SJim Mattson if (!tsc_delta) 768290f4213SJim Mattson return; 769290f4213SJim Mattson 77025cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].min = 77125cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].min * cnt.count) / tsc_delta; 77225cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].max = 77325cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].max * cnt.count) / tsc_delta; 774290f4213SJim Mattson } 775290f4213SJim Mattson 77685c21181SLike Xu static void check_invalid_rdpmc_gp(void) 77785c21181SLike Xu { 77885c21181SLike Xu uint64_t val; 77985c21181SLike Xu 78085c21181SLike Xu report(rdpmc_safe(64, &val) == GP_VECTOR, 78185c21181SLike Xu "Expected #GP on RDPMC(64)"); 78285c21181SLike Xu } 78385c21181SLike Xu 784a9f8b16fSGleb Natapov int main(int ac, char **av) 785a9f8b16fSGleb Natapov { 786a9f8b16fSGleb Natapov setup_vm(); 7875a2cb3e6SLike Xu handle_irq(PMI_VECTOR, cnt_overflow); 788dcda215bSPaolo Bonzini buf = malloc(N*64); 789a9f8b16fSGleb Natapov 79085c21181SLike Xu check_invalid_rdpmc_gp(); 79185c21181SLike Xu 792b883751aSLike Xu if (pmu.is_intel) { 793414ee7d1SSean Christopherson if (!pmu.version) { 79403041e97SLike Xu report_skip("No Intel Arch PMU is detected!"); 79532b9603cSRadim Krčmář return report_summary(); 796a9f8b16fSGleb Natapov } 7977c648ce2SLike Xu gp_events = (struct pmu_event *)intel_gp_events; 7987c648ce2SLike Xu gp_events_size = sizeof(intel_gp_events)/sizeof(intel_gp_events[0]); 799b883751aSLike Xu report_prefix_push("Intel"); 800290f4213SJim Mattson set_ref_cycle_expectations(); 801b883751aSLike Xu } else { 802b883751aSLike Xu gp_events_size = sizeof(amd_gp_events)/sizeof(amd_gp_events[0]); 803b883751aSLike Xu gp_events = (struct pmu_event *)amd_gp_events; 804b883751aSLike Xu report_prefix_push("AMD"); 805b883751aSLike Xu } 806290f4213SJim Mattson 807414ee7d1SSean Christopherson printf("PMU version: %d\n", pmu.version); 808414ee7d1SSean Christopherson printf("GP counters: %d\n", pmu.nr_gp_counters); 809414ee7d1SSean Christopherson printf("GP counter width: %d\n", pmu.gp_counter_width); 810414ee7d1SSean Christopherson printf("Mask length: %d\n", pmu.gp_counter_mask_length); 811414ee7d1SSean Christopherson printf("Fixed counters: %d\n", pmu.nr_fixed_counters); 812414ee7d1SSean Christopherson printf("Fixed counter width: %d\n", pmu.fixed_counter_width); 8130ef1f6a8SPaolo Bonzini 8149c07c92bSDapeng Mi fixed_counters_num = MIN(pmu.nr_fixed_counters, ARRAY_SIZE(fixed_events)); 8159c07c92bSDapeng Mi if (pmu.nr_fixed_counters > ARRAY_SIZE(fixed_events)) 8169c07c92bSDapeng Mi report_info("Fixed counters number %d > defined fixed events %u. " 8179c07c92bSDapeng Mi "Please update test case.", pmu.nr_fixed_counters, 8189c07c92bSDapeng Mi (uint32_t)ARRAY_SIZE(fixed_events)); 8199c07c92bSDapeng Mi 8205a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 821a9f8b16fSGleb Natapov 822afa714b2SPaolo Bonzini check_counters(); 82320cf9147SJim Mattson 824879e7f07SLike Xu if (pmu_has_full_writes()) { 825cda64e80SLike Xu pmu.msr_gp_counter_base = MSR_IA32_PMC0; 826cda64e80SLike Xu 82722f2901aSLike Xu report_prefix_push("full-width writes"); 82822f2901aSLike Xu check_counters(); 82922f2901aSLike Xu check_gp_counters_write_width(); 830d7714e16SLike Xu report_prefix_pop(); 83122f2901aSLike Xu } 832a9f8b16fSGleb Natapov 833b883751aSLike Xu if (!pmu.is_intel) { 834b883751aSLike Xu report_prefix_push("K7"); 835b883751aSLike Xu pmu.nr_gp_counters = AMD64_NUM_COUNTERS; 836b883751aSLike Xu pmu.msr_gp_counter_base = MSR_K7_PERFCTR0; 837b883751aSLike Xu pmu.msr_gp_event_select_base = MSR_K7_EVNTSEL0; 838b883751aSLike Xu check_counters(); 839b883751aSLike Xu report_prefix_pop(); 840b883751aSLike Xu } 841b883751aSLike Xu 842f3cdd159SJan Kiszka return report_summary(); 843a9f8b16fSGleb Natapov } 844