1 /*
2  * Copyright 2014, Michael Ellerman, IBM Corp.
3  * Licensed under GPLv2.
4  */
5 
6 #define _GNU_SOURCE
7 
8 #include <elf.h>
9 #include <limits.h>
10 #include <stdio.h>
11 #include <stdbool.h>
12 #include <string.h>
13 #include <sys/prctl.h>
14 
15 #include "event.h"
16 #include "lib.h"
17 #include "utils.h"
18 
19 /*
20  * Test that per-event excludes work.
21  */
22 
23 static int per_event_excludes(void)
24 {
25 	struct event *e, events[4];
26 	char *platform;
27 	int i;
28 
29 	platform = (char *)get_auxv_entry(AT_BASE_PLATFORM);
30 	FAIL_IF(!platform);
31 	SKIP_IF(strcmp(platform, "power8") != 0);
32 
33 	/*
34 	 * We need to create the events disabled, otherwise the running/enabled
35 	 * counts don't match up.
36 	 */
37 	e = &events[0];
38 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
39 			PERF_TYPE_HARDWARE, "instructions");
40 	e->attr.disabled = 1;
41 
42 	e = &events[1];
43 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
44 			PERF_TYPE_HARDWARE, "instructions(k)");
45 	e->attr.disabled = 1;
46 	e->attr.exclude_user = 1;
47 	e->attr.exclude_hv = 1;
48 
49 	e = &events[2];
50 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
51 			PERF_TYPE_HARDWARE, "instructions(h)");
52 	e->attr.disabled = 1;
53 	e->attr.exclude_user = 1;
54 	e->attr.exclude_kernel = 1;
55 
56 	e = &events[3];
57 	event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
58 			PERF_TYPE_HARDWARE, "instructions(u)");
59 	e->attr.disabled = 1;
60 	e->attr.exclude_hv = 1;
61 	e->attr.exclude_kernel = 1;
62 
63 	FAIL_IF(event_open(&events[0]));
64 
65 	/*
66 	 * The open here will fail if we don't have per event exclude support,
67 	 * because the second event has an incompatible set of exclude settings
68 	 * and we're asking for the events to be in a group.
69 	 */
70 	for (i = 1; i < 4; i++)
71 		FAIL_IF(event_open_with_group(&events[i], events[0].fd));
72 
73 	/*
74 	 * Even though the above will fail without per-event excludes we keep
75 	 * testing in order to be thorough.
76 	 */
77 	prctl(PR_TASK_PERF_EVENTS_ENABLE);
78 
79 	/* Spin for a while */
80 	for (i = 0; i < INT_MAX; i++)
81 		asm volatile("" : : : "memory");
82 
83 	prctl(PR_TASK_PERF_EVENTS_DISABLE);
84 
85 	for (i = 0; i < 4; i++) {
86 		FAIL_IF(event_read(&events[i]));
87 		event_report(&events[i]);
88 	}
89 
90 	/*
91 	 * We should see that all events have enabled == running. That
92 	 * shows that they were all on the PMU at once.
93 	 */
94 	for (i = 0; i < 4; i++)
95 		FAIL_IF(events[i].result.running != events[i].result.enabled);
96 
97 	/*
98 	 * We can also check that the result for instructions is >= all the
99 	 * other counts. That's because it is counting all instructions while
100 	 * the others are counting a subset.
101 	 */
102 	for (i = 1; i < 4; i++)
103 		FAIL_IF(events[0].result.value < events[i].result.value);
104 
105 	for (i = 0; i < 4; i++)
106 		event_close(&events[i]);
107 
108 	return 0;
109 }
110 
111 int main(void)
112 {
113 	return test_harness(per_event_excludes, "per_event_excludes");
114 }
115