xref: /kvm-unit-tests/x86/pmu_pebs.c (revision 2ae41f5d8730d2748538cbb6bbebceaee6a63a03)
1*2ae41f5dSLike Xu #include "x86/msr.h"
2*2ae41f5dSLike Xu #include "x86/processor.h"
3*2ae41f5dSLike Xu #include "x86/pmu.h"
4*2ae41f5dSLike Xu #include "x86/isr.h"
5*2ae41f5dSLike Xu #include "x86/apic.h"
6*2ae41f5dSLike Xu #include "x86/apic-defs.h"
7*2ae41f5dSLike Xu #include "x86/desc.h"
8*2ae41f5dSLike Xu #include "alloc.h"
9*2ae41f5dSLike Xu 
10*2ae41f5dSLike Xu #include "vm.h"
11*2ae41f5dSLike Xu #include "types.h"
12*2ae41f5dSLike Xu #include "processor.h"
13*2ae41f5dSLike Xu #include "vmalloc.h"
14*2ae41f5dSLike Xu #include "alloc_page.h"
15*2ae41f5dSLike Xu 
16*2ae41f5dSLike Xu /* bits [63:48] provides the size of the current record in bytes */
17*2ae41f5dSLike Xu #define	RECORD_SIZE_OFFSET	48
18*2ae41f5dSLike Xu 
19*2ae41f5dSLike Xu static unsigned int max_nr_gp_events;
20*2ae41f5dSLike Xu static unsigned long *ds_bufer;
21*2ae41f5dSLike Xu static unsigned long *pebs_buffer;
22*2ae41f5dSLike Xu static u64 ctr_start_val;
23*2ae41f5dSLike Xu static bool has_baseline;
24*2ae41f5dSLike Xu 
25*2ae41f5dSLike Xu struct debug_store {
26*2ae41f5dSLike Xu 	u64	bts_buffer_base;
27*2ae41f5dSLike Xu 	u64	bts_index;
28*2ae41f5dSLike Xu 	u64	bts_absolute_maximum;
29*2ae41f5dSLike Xu 	u64	bts_interrupt_threshold;
30*2ae41f5dSLike Xu 	u64	pebs_buffer_base;
31*2ae41f5dSLike Xu 	u64	pebs_index;
32*2ae41f5dSLike Xu 	u64	pebs_absolute_maximum;
33*2ae41f5dSLike Xu 	u64	pebs_interrupt_threshold;
34*2ae41f5dSLike Xu 	u64	pebs_event_reset[64];
35*2ae41f5dSLike Xu };
36*2ae41f5dSLike Xu 
37*2ae41f5dSLike Xu struct pebs_basic {
38*2ae41f5dSLike Xu 	u64 format_size;
39*2ae41f5dSLike Xu 	u64 ip;
40*2ae41f5dSLike Xu 	u64 applicable_counters;
41*2ae41f5dSLike Xu 	u64 tsc;
42*2ae41f5dSLike Xu };
43*2ae41f5dSLike Xu 
44*2ae41f5dSLike Xu struct pebs_meminfo {
45*2ae41f5dSLike Xu 	u64 address;
46*2ae41f5dSLike Xu 	u64 aux;
47*2ae41f5dSLike Xu 	u64 latency;
48*2ae41f5dSLike Xu 	u64 tsx_tuning;
49*2ae41f5dSLike Xu };
50*2ae41f5dSLike Xu 
51*2ae41f5dSLike Xu struct pebs_gprs {
52*2ae41f5dSLike Xu 	u64 flags, ip, ax, cx, dx, bx, sp, bp, si, di;
53*2ae41f5dSLike Xu 	u64 r8, r9, r10, r11, r12, r13, r14, r15;
54*2ae41f5dSLike Xu };
55*2ae41f5dSLike Xu 
56*2ae41f5dSLike Xu struct pebs_xmm {
57*2ae41f5dSLike Xu 	u64 xmm[16*2];	/* two entries for each register */
58*2ae41f5dSLike Xu };
59*2ae41f5dSLike Xu 
60*2ae41f5dSLike Xu struct lbr_entry {
61*2ae41f5dSLike Xu 	u64 from;
62*2ae41f5dSLike Xu 	u64 to;
63*2ae41f5dSLike Xu 	u64 info;
64*2ae41f5dSLike Xu };
65*2ae41f5dSLike Xu 
66*2ae41f5dSLike Xu enum pmc_type {
67*2ae41f5dSLike Xu 	GP = 0,
68*2ae41f5dSLike Xu 	FIXED,
69*2ae41f5dSLike Xu };
70*2ae41f5dSLike Xu 
71*2ae41f5dSLike Xu static uint32_t intel_arch_events[] = {
72*2ae41f5dSLike Xu 	0x00c4, /* PERF_COUNT_HW_BRANCH_INSTRUCTIONS */
73*2ae41f5dSLike Xu 	0x00c5, /* PERF_COUNT_HW_BRANCH_MISSES */
74*2ae41f5dSLike Xu 	0x0300, /* PERF_COUNT_HW_REF_CPU_CYCLES */
75*2ae41f5dSLike Xu 	0x003c, /* PERF_COUNT_HW_CPU_CYCLES */
76*2ae41f5dSLike Xu 	0x00c0, /* PERF_COUNT_HW_INSTRUCTIONS */
77*2ae41f5dSLike Xu 	0x013c, /* PERF_COUNT_HW_BUS_CYCLES */
78*2ae41f5dSLike Xu 	0x4f2e, /* PERF_COUNT_HW_CACHE_REFERENCES */
79*2ae41f5dSLike Xu 	0x412e, /* PERF_COUNT_HW_CACHE_MISSES */
80*2ae41f5dSLike Xu };
81*2ae41f5dSLike Xu 
82*2ae41f5dSLike Xu static u64 pebs_data_cfgs[] = {
83*2ae41f5dSLike Xu 	PEBS_DATACFG_MEMINFO,
84*2ae41f5dSLike Xu 	PEBS_DATACFG_GP,
85*2ae41f5dSLike Xu 	PEBS_DATACFG_XMMS,
86*2ae41f5dSLike Xu 	PEBS_DATACFG_LBRS | ((MAX_NUM_LBR_ENTRY -1) << PEBS_DATACFG_LBR_SHIFT),
87*2ae41f5dSLike Xu };
88*2ae41f5dSLike Xu 
89*2ae41f5dSLike Xu /* Iterating each counter value is a waste of time, pick a few typical values. */
90*2ae41f5dSLike Xu static u64 counter_start_values[] = {
91*2ae41f5dSLike Xu 	/* if PEBS counter doesn't overflow at all */
92*2ae41f5dSLike Xu 	0,
93*2ae41f5dSLike Xu 	0xfffffffffff0,
94*2ae41f5dSLike Xu 	/* normal counter overflow to have PEBS records */
95*2ae41f5dSLike Xu 	0xfffffffffffe,
96*2ae41f5dSLike Xu 	/* test whether emulated instructions should trigger PEBS */
97*2ae41f5dSLike Xu 	0xffffffffffff,
98*2ae41f5dSLike Xu };
99*2ae41f5dSLike Xu 
100*2ae41f5dSLike Xu static unsigned int get_adaptive_pebs_record_size(u64 pebs_data_cfg)
101*2ae41f5dSLike Xu {
102*2ae41f5dSLike Xu 	unsigned int sz = sizeof(struct pebs_basic);
103*2ae41f5dSLike Xu 
104*2ae41f5dSLike Xu 	if (!has_baseline)
105*2ae41f5dSLike Xu 		return sz;
106*2ae41f5dSLike Xu 
107*2ae41f5dSLike Xu 	if (pebs_data_cfg & PEBS_DATACFG_MEMINFO)
108*2ae41f5dSLike Xu 		sz += sizeof(struct pebs_meminfo);
109*2ae41f5dSLike Xu 	if (pebs_data_cfg & PEBS_DATACFG_GP)
110*2ae41f5dSLike Xu 		sz += sizeof(struct pebs_gprs);
111*2ae41f5dSLike Xu 	if (pebs_data_cfg & PEBS_DATACFG_XMMS)
112*2ae41f5dSLike Xu 		sz += sizeof(struct pebs_xmm);
113*2ae41f5dSLike Xu 	if (pebs_data_cfg & PEBS_DATACFG_LBRS)
114*2ae41f5dSLike Xu 		sz += MAX_NUM_LBR_ENTRY * sizeof(struct lbr_entry);
115*2ae41f5dSLike Xu 
116*2ae41f5dSLike Xu 	return sz;
117*2ae41f5dSLike Xu }
118*2ae41f5dSLike Xu 
119*2ae41f5dSLike Xu static void cnt_overflow(isr_regs_t *regs)
120*2ae41f5dSLike Xu {
121*2ae41f5dSLike Xu 	apic_write(APIC_EOI, 0);
122*2ae41f5dSLike Xu }
123*2ae41f5dSLike Xu 
124*2ae41f5dSLike Xu static inline void workload(void)
125*2ae41f5dSLike Xu {
126*2ae41f5dSLike Xu 	asm volatile(
127*2ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
128*2ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
129*2ae41f5dSLike Xu 		"jne label2\n"
130*2ae41f5dSLike Xu 		"jne label2\n"
131*2ae41f5dSLike Xu 		"jne label2\n"
132*2ae41f5dSLike Xu 		"jne label2\n"
133*2ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
134*2ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
135*2ae41f5dSLike Xu 		"jne label2\n"
136*2ae41f5dSLike Xu 		"jne label2\n"
137*2ae41f5dSLike Xu 		"jne label2\n"
138*2ae41f5dSLike Xu 		"jne label2\n"
139*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
140*2ae41f5dSLike Xu 		"cpuid\n"
141*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
142*2ae41f5dSLike Xu 		"cpuid\n"
143*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
144*2ae41f5dSLike Xu 		"cpuid\n"
145*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
146*2ae41f5dSLike Xu 		"cpuid\n"
147*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
148*2ae41f5dSLike Xu 		"cpuid\n"
149*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
150*2ae41f5dSLike Xu 		"cpuid\n"
151*2ae41f5dSLike Xu 		"label2:\n"
152*2ae41f5dSLike Xu 		:
153*2ae41f5dSLike Xu 		:
154*2ae41f5dSLike Xu 		: "eax", "ebx", "ecx", "edx");
155*2ae41f5dSLike Xu }
156*2ae41f5dSLike Xu 
157*2ae41f5dSLike Xu static inline void workload2(void)
158*2ae41f5dSLike Xu {
159*2ae41f5dSLike Xu 	asm volatile(
160*2ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
161*2ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
162*2ae41f5dSLike Xu 		"jne label3\n"
163*2ae41f5dSLike Xu 		"jne label3\n"
164*2ae41f5dSLike Xu 		"jne label3\n"
165*2ae41f5dSLike Xu 		"jne label3\n"
166*2ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
167*2ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
168*2ae41f5dSLike Xu 		"jne label3\n"
169*2ae41f5dSLike Xu 		"jne label3\n"
170*2ae41f5dSLike Xu 		"jne label3\n"
171*2ae41f5dSLike Xu 		"jne label3\n"
172*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
173*2ae41f5dSLike Xu 		"cpuid\n"
174*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
175*2ae41f5dSLike Xu 		"cpuid\n"
176*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
177*2ae41f5dSLike Xu 		"cpuid\n"
178*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
179*2ae41f5dSLike Xu 		"cpuid\n"
180*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
181*2ae41f5dSLike Xu 		"cpuid\n"
182*2ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
183*2ae41f5dSLike Xu 		"cpuid\n"
184*2ae41f5dSLike Xu 		"label3:\n"
185*2ae41f5dSLike Xu 		:
186*2ae41f5dSLike Xu 		:
187*2ae41f5dSLike Xu 		: "eax", "ebx", "ecx", "edx");
188*2ae41f5dSLike Xu }
189*2ae41f5dSLike Xu 
190*2ae41f5dSLike Xu static void alloc_buffers(void)
191*2ae41f5dSLike Xu {
192*2ae41f5dSLike Xu 	ds_bufer = alloc_page();
193*2ae41f5dSLike Xu 	force_4k_page(ds_bufer);
194*2ae41f5dSLike Xu 	memset(ds_bufer, 0x0, PAGE_SIZE);
195*2ae41f5dSLike Xu 
196*2ae41f5dSLike Xu 	pebs_buffer = alloc_page();
197*2ae41f5dSLike Xu 	force_4k_page(pebs_buffer);
198*2ae41f5dSLike Xu 	memset(pebs_buffer, 0x0, PAGE_SIZE);
199*2ae41f5dSLike Xu }
200*2ae41f5dSLike Xu 
201*2ae41f5dSLike Xu static void free_buffers(void)
202*2ae41f5dSLike Xu {
203*2ae41f5dSLike Xu 	if (ds_bufer)
204*2ae41f5dSLike Xu 		free_page(ds_bufer);
205*2ae41f5dSLike Xu 
206*2ae41f5dSLike Xu 	if (pebs_buffer)
207*2ae41f5dSLike Xu 		free_page(pebs_buffer);
208*2ae41f5dSLike Xu }
209*2ae41f5dSLike Xu 
210*2ae41f5dSLike Xu static void pebs_enable(u64 bitmask, u64 pebs_data_cfg)
211*2ae41f5dSLike Xu {
212*2ae41f5dSLike Xu 	static struct debug_store *ds;
213*2ae41f5dSLike Xu 	u64 baseline_extra_ctrl = 0, fixed_ctr_ctrl = 0;
214*2ae41f5dSLike Xu 	unsigned int idx;
215*2ae41f5dSLike Xu 
216*2ae41f5dSLike Xu 	if (has_baseline)
217*2ae41f5dSLike Xu 		wrmsr(MSR_PEBS_DATA_CFG, pebs_data_cfg);
218*2ae41f5dSLike Xu 
219*2ae41f5dSLike Xu 	ds = (struct debug_store *)ds_bufer;
220*2ae41f5dSLike Xu 	ds->pebs_index = ds->pebs_buffer_base = (unsigned long)pebs_buffer;
221*2ae41f5dSLike Xu 	ds->pebs_absolute_maximum = (unsigned long)pebs_buffer + PAGE_SIZE;
222*2ae41f5dSLike Xu 	ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
223*2ae41f5dSLike Xu 		get_adaptive_pebs_record_size(pebs_data_cfg);
224*2ae41f5dSLike Xu 
225*2ae41f5dSLike Xu 	for (idx = 0; idx < pmu.nr_fixed_counters; idx++) {
226*2ae41f5dSLike Xu 		if (!(BIT_ULL(FIXED_CNT_INDEX + idx) & bitmask))
227*2ae41f5dSLike Xu 			continue;
228*2ae41f5dSLike Xu 		if (has_baseline)
229*2ae41f5dSLike Xu 			baseline_extra_ctrl = BIT(FIXED_CNT_INDEX + idx * 4);
230*2ae41f5dSLike Xu 		wrmsr(MSR_PERF_FIXED_CTRx(idx), ctr_start_val);
231*2ae41f5dSLike Xu 		fixed_ctr_ctrl |= (0xbULL << (idx * 4) | baseline_extra_ctrl);
232*2ae41f5dSLike Xu 	}
233*2ae41f5dSLike Xu 	if (fixed_ctr_ctrl)
234*2ae41f5dSLike Xu 		wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, fixed_ctr_ctrl);
235*2ae41f5dSLike Xu 
236*2ae41f5dSLike Xu 	for (idx = 0; idx < max_nr_gp_events; idx++) {
237*2ae41f5dSLike Xu 		if (!(BIT_ULL(idx) & bitmask))
238*2ae41f5dSLike Xu 			continue;
239*2ae41f5dSLike Xu 		if (has_baseline)
240*2ae41f5dSLike Xu 			baseline_extra_ctrl = ICL_EVENTSEL_ADAPTIVE;
241*2ae41f5dSLike Xu 		wrmsr(MSR_GP_EVENT_SELECTx(idx), EVNTSEL_EN | EVNTSEL_OS | EVNTSEL_USR |
242*2ae41f5dSLike Xu 						 intel_arch_events[idx] | baseline_extra_ctrl);
243*2ae41f5dSLike Xu 		wrmsr(MSR_GP_COUNTERx(idx), ctr_start_val);
244*2ae41f5dSLike Xu 	}
245*2ae41f5dSLike Xu 
246*2ae41f5dSLike Xu 	wrmsr(MSR_IA32_DS_AREA,  (unsigned long)ds_bufer);
247*2ae41f5dSLike Xu 	wrmsr(MSR_IA32_PEBS_ENABLE, bitmask);
248*2ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, bitmask);
249*2ae41f5dSLike Xu }
250*2ae41f5dSLike Xu 
251*2ae41f5dSLike Xu static void reset_pebs(void)
252*2ae41f5dSLike Xu {
253*2ae41f5dSLike Xu 	memset(ds_bufer, 0x0, PAGE_SIZE);
254*2ae41f5dSLike Xu 	memset(pebs_buffer, 0x0, PAGE_SIZE);
255*2ae41f5dSLike Xu 	wrmsr(MSR_IA32_PEBS_ENABLE, 0);
256*2ae41f5dSLike Xu 	wrmsr(MSR_IA32_DS_AREA,  0);
257*2ae41f5dSLike Xu 	if (has_baseline)
258*2ae41f5dSLike Xu 		wrmsr(MSR_PEBS_DATA_CFG, 0);
259*2ae41f5dSLike Xu 
260*2ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
261*2ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_STATUS));
262*2ae41f5dSLike Xu 
263*2ae41f5dSLike Xu 	pmu_reset_all_counters();
264*2ae41f5dSLike Xu }
265*2ae41f5dSLike Xu 
266*2ae41f5dSLike Xu static void pebs_disable(unsigned int idx)
267*2ae41f5dSLike Xu {
268*2ae41f5dSLike Xu 	/*
269*2ae41f5dSLike Xu 	* If we only clear the PEBS_ENABLE bit, the counter will continue to increment.
270*2ae41f5dSLike Xu 	* In this very tiny time window, if the counter overflows no pebs record will be generated,
271*2ae41f5dSLike Xu 	* but a normal counter irq. Test this fully with two ways.
272*2ae41f5dSLike Xu 	*/
273*2ae41f5dSLike Xu 	if (idx % 2)
274*2ae41f5dSLike Xu 		wrmsr(MSR_IA32_PEBS_ENABLE, 0);
275*2ae41f5dSLike Xu 
276*2ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
277*2ae41f5dSLike Xu }
278*2ae41f5dSLike Xu 
279*2ae41f5dSLike Xu static void check_pebs_records(u64 bitmask, u64 pebs_data_cfg)
280*2ae41f5dSLike Xu {
281*2ae41f5dSLike Xu 	struct pebs_basic *pebs_rec = (struct pebs_basic *)pebs_buffer;
282*2ae41f5dSLike Xu 	struct debug_store *ds = (struct debug_store *)ds_bufer;
283*2ae41f5dSLike Xu 	unsigned int pebs_record_size = get_adaptive_pebs_record_size(pebs_data_cfg);
284*2ae41f5dSLike Xu 	unsigned int count = 0;
285*2ae41f5dSLike Xu 	bool expected, pebs_idx_match, pebs_size_match, data_cfg_match;
286*2ae41f5dSLike Xu 	void *cur_record;
287*2ae41f5dSLike Xu 
288*2ae41f5dSLike Xu 	expected = (ds->pebs_index == ds->pebs_buffer_base) && !pebs_rec->format_size;
289*2ae41f5dSLike Xu 	if (!(rdmsr(MSR_CORE_PERF_GLOBAL_STATUS) & GLOBAL_STATUS_BUFFER_OVF)) {
290*2ae41f5dSLike Xu 		report(expected, "No OVF irq, none PEBS records.");
291*2ae41f5dSLike Xu 		return;
292*2ae41f5dSLike Xu 	}
293*2ae41f5dSLike Xu 
294*2ae41f5dSLike Xu 	if (expected) {
295*2ae41f5dSLike Xu 		report(!expected, "A OVF irq, but none PEBS records.");
296*2ae41f5dSLike Xu 		return;
297*2ae41f5dSLike Xu 	}
298*2ae41f5dSLike Xu 
299*2ae41f5dSLike Xu 	expected = ds->pebs_index >= ds->pebs_interrupt_threshold;
300*2ae41f5dSLike Xu 	cur_record = (void *)pebs_buffer;
301*2ae41f5dSLike Xu 	do {
302*2ae41f5dSLike Xu 		pebs_rec = (struct pebs_basic *)cur_record;
303*2ae41f5dSLike Xu 		pebs_record_size = pebs_rec->format_size >> RECORD_SIZE_OFFSET;
304*2ae41f5dSLike Xu 		pebs_idx_match =
305*2ae41f5dSLike Xu 			pebs_rec->applicable_counters & bitmask;
306*2ae41f5dSLike Xu 		pebs_size_match =
307*2ae41f5dSLike Xu 			pebs_record_size == get_adaptive_pebs_record_size(pebs_data_cfg);
308*2ae41f5dSLike Xu 		data_cfg_match =
309*2ae41f5dSLike Xu 			(pebs_rec->format_size & GENMASK_ULL(47, 0)) == pebs_data_cfg;
310*2ae41f5dSLike Xu 		expected = pebs_idx_match && pebs_size_match && data_cfg_match;
311*2ae41f5dSLike Xu 		report(expected,
312*2ae41f5dSLike Xu 		       "PEBS record (written seq %d) is verified (inclduing size, counters and cfg).", count);
313*2ae41f5dSLike Xu 		cur_record = cur_record + pebs_record_size;
314*2ae41f5dSLike Xu 		count++;
315*2ae41f5dSLike Xu 	} while (expected && (void *)cur_record < (void *)ds->pebs_index);
316*2ae41f5dSLike Xu 
317*2ae41f5dSLike Xu 	if (!expected) {
318*2ae41f5dSLike Xu 		if (!pebs_idx_match)
319*2ae41f5dSLike Xu 			printf("FAIL: The applicable_counters (0x%lx) doesn't match with pmc_bitmask (0x%lx).\n",
320*2ae41f5dSLike Xu 			       pebs_rec->applicable_counters, bitmask);
321*2ae41f5dSLike Xu 		if (!pebs_size_match)
322*2ae41f5dSLike Xu 			printf("FAIL: The pebs_record_size (%d) doesn't match with MSR_PEBS_DATA_CFG (%d).\n",
323*2ae41f5dSLike Xu 			       pebs_record_size, get_adaptive_pebs_record_size(pebs_data_cfg));
324*2ae41f5dSLike Xu 		if (!data_cfg_match)
325*2ae41f5dSLike Xu 			printf("FAIL: The pebs_data_cfg (0x%lx) doesn't match with MSR_PEBS_DATA_CFG (0x%lx).\n",
326*2ae41f5dSLike Xu 			       pebs_rec->format_size & 0xffffffffffff, pebs_data_cfg);
327*2ae41f5dSLike Xu 	}
328*2ae41f5dSLike Xu }
329*2ae41f5dSLike Xu 
330*2ae41f5dSLike Xu static void check_one_counter(enum pmc_type type,
331*2ae41f5dSLike Xu 			      unsigned int idx, u64 pebs_data_cfg)
332*2ae41f5dSLike Xu {
333*2ae41f5dSLike Xu 	int pebs_bit = BIT_ULL(type == FIXED ? FIXED_CNT_INDEX + idx : idx);
334*2ae41f5dSLike Xu 
335*2ae41f5dSLike Xu 	report_prefix_pushf("%s counter %d (0x%lx)",
336*2ae41f5dSLike Xu 			    type == FIXED ? "Extended Fixed" : "GP", idx, ctr_start_val);
337*2ae41f5dSLike Xu 	reset_pebs();
338*2ae41f5dSLike Xu 	pebs_enable(pebs_bit, pebs_data_cfg);
339*2ae41f5dSLike Xu 	workload();
340*2ae41f5dSLike Xu 	pebs_disable(idx);
341*2ae41f5dSLike Xu 	check_pebs_records(pebs_bit, pebs_data_cfg);
342*2ae41f5dSLike Xu 	report_prefix_pop();
343*2ae41f5dSLike Xu }
344*2ae41f5dSLike Xu 
345*2ae41f5dSLike Xu /* more than one PEBS records will be generated. */
346*2ae41f5dSLike Xu static void check_multiple_counters(u64 bitmask, u64 pebs_data_cfg)
347*2ae41f5dSLike Xu {
348*2ae41f5dSLike Xu 	reset_pebs();
349*2ae41f5dSLike Xu 	pebs_enable(bitmask, pebs_data_cfg);
350*2ae41f5dSLike Xu 	workload2();
351*2ae41f5dSLike Xu 	pebs_disable(0);
352*2ae41f5dSLike Xu 	check_pebs_records(bitmask, pebs_data_cfg);
353*2ae41f5dSLike Xu }
354*2ae41f5dSLike Xu 
355*2ae41f5dSLike Xu static void check_pebs_counters(u64 pebs_data_cfg)
356*2ae41f5dSLike Xu {
357*2ae41f5dSLike Xu 	unsigned int idx;
358*2ae41f5dSLike Xu 	u64 bitmask = 0;
359*2ae41f5dSLike Xu 
360*2ae41f5dSLike Xu 	for (idx = 0; idx < pmu.nr_fixed_counters; idx++)
361*2ae41f5dSLike Xu 		check_one_counter(FIXED, idx, pebs_data_cfg);
362*2ae41f5dSLike Xu 
363*2ae41f5dSLike Xu 	for (idx = 0; idx < max_nr_gp_events; idx++)
364*2ae41f5dSLike Xu 		check_one_counter(GP, idx, pebs_data_cfg);
365*2ae41f5dSLike Xu 
366*2ae41f5dSLike Xu 	for (idx = 0; idx < pmu.nr_fixed_counters; idx++)
367*2ae41f5dSLike Xu 		bitmask |= BIT_ULL(FIXED_CNT_INDEX + idx);
368*2ae41f5dSLike Xu 	for (idx = 0; idx < max_nr_gp_events; idx += 2)
369*2ae41f5dSLike Xu 		bitmask |= BIT_ULL(idx);
370*2ae41f5dSLike Xu 	report_prefix_pushf("Multiple (0x%lx)", bitmask);
371*2ae41f5dSLike Xu 	check_multiple_counters(bitmask, pebs_data_cfg);
372*2ae41f5dSLike Xu 	report_prefix_pop();
373*2ae41f5dSLike Xu }
374*2ae41f5dSLike Xu 
375*2ae41f5dSLike Xu /*
376*2ae41f5dSLike Xu  * Known reasons for none PEBS records:
377*2ae41f5dSLike Xu  *	1. The selected event does not support PEBS;
378*2ae41f5dSLike Xu  *	2. From a core pmu perspective, the vCPU and pCPU models are not same;
379*2ae41f5dSLike Xu  * 	3. Guest counter has not yet overflowed or been cross-mapped by the host;
380*2ae41f5dSLike Xu  */
381*2ae41f5dSLike Xu int main(int ac, char **av)
382*2ae41f5dSLike Xu {
383*2ae41f5dSLike Xu 	unsigned int i, j;
384*2ae41f5dSLike Xu 
385*2ae41f5dSLike Xu 	setup_vm();
386*2ae41f5dSLike Xu 
387*2ae41f5dSLike Xu 	max_nr_gp_events = MIN(pmu.nr_gp_counters, ARRAY_SIZE(intel_arch_events));
388*2ae41f5dSLike Xu 
389*2ae41f5dSLike Xu 	printf("PMU version: %d\n", pmu.version);
390*2ae41f5dSLike Xu 
391*2ae41f5dSLike Xu 	has_baseline = pmu_has_pebs_baseline();
392*2ae41f5dSLike Xu 	if (pmu_has_full_writes())
393*2ae41f5dSLike Xu 		pmu_activate_full_writes();
394*2ae41f5dSLike Xu 
395*2ae41f5dSLike Xu 	if (!is_intel()) {
396*2ae41f5dSLike Xu 		report_skip("PEBS requires Intel ICX or later, non-Intel detected");
397*2ae41f5dSLike Xu 		return report_summary();
398*2ae41f5dSLike Xu 	} else if (!pmu_has_pebs()) {
399*2ae41f5dSLike Xu 		report_skip("PEBS required PMU version 2, reported version is %d", pmu.version);
400*2ae41f5dSLike Xu 		return report_summary();
401*2ae41f5dSLike Xu 	} else if (!pmu_pebs_format()) {
402*2ae41f5dSLike Xu 		report_skip("PEBS not enumerated in PERF_CAPABILITIES");
403*2ae41f5dSLike Xu 		return report_summary();
404*2ae41f5dSLike Xu 	} else if (rdmsr(MSR_IA32_MISC_ENABLE) & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL) {
405*2ae41f5dSLike Xu 		report_skip("PEBS unavailable according to MISC_ENABLE");
406*2ae41f5dSLike Xu 		return report_summary();
407*2ae41f5dSLike Xu 	}
408*2ae41f5dSLike Xu 
409*2ae41f5dSLike Xu 	printf("PEBS format: %d\n", pmu_pebs_format());
410*2ae41f5dSLike Xu 	printf("PEBS GP counters: %d\n", pmu.nr_gp_counters);
411*2ae41f5dSLike Xu 	printf("PEBS Fixed counters: %d\n", pmu.nr_fixed_counters);
412*2ae41f5dSLike Xu 	printf("PEBS baseline (Adaptive PEBS): %d\n", has_baseline);
413*2ae41f5dSLike Xu 
414*2ae41f5dSLike Xu 	handle_irq(PMI_VECTOR, cnt_overflow);
415*2ae41f5dSLike Xu 	alloc_buffers();
416*2ae41f5dSLike Xu 
417*2ae41f5dSLike Xu 	for (i = 0; i < ARRAY_SIZE(counter_start_values); i++) {
418*2ae41f5dSLike Xu 		ctr_start_val = counter_start_values[i];
419*2ae41f5dSLike Xu 		check_pebs_counters(0);
420*2ae41f5dSLike Xu 		if (!has_baseline)
421*2ae41f5dSLike Xu 			continue;
422*2ae41f5dSLike Xu 
423*2ae41f5dSLike Xu 		for (j = 0; j < ARRAY_SIZE(pebs_data_cfgs); j++) {
424*2ae41f5dSLike Xu 			report_prefix_pushf("Adaptive (0x%lx)", pebs_data_cfgs[j]);
425*2ae41f5dSLike Xu 			check_pebs_counters(pebs_data_cfgs[j]);
426*2ae41f5dSLike Xu 			report_prefix_pop();
427*2ae41f5dSLike Xu 		}
428*2ae41f5dSLike Xu 	}
429*2ae41f5dSLike Xu 
430*2ae41f5dSLike Xu 	free_buffers();
431*2ae41f5dSLike Xu 
432*2ae41f5dSLike Xu 	return report_summary();
433*2ae41f5dSLike Xu }
434