1 // SPDX-License-Identifier: GPL-2.0
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <linux/perf_event.h>
5 #include <perf/cpumap.h>
6 #include <perf/threadmap.h>
7 #include <perf/evsel.h>
8 #include <internal/tests.h>
9 
libperf_print(enum libperf_print_level level,const char * fmt,va_list ap)10 static int libperf_print(enum libperf_print_level level,
11 			 const char *fmt, va_list ap)
12 {
13 	return vfprintf(stderr, fmt, ap);
14 }
15 
test_stat_cpu(void)16 static int test_stat_cpu(void)
17 {
18 	struct perf_cpu_map *cpus;
19 	struct perf_evsel *evsel;
20 	struct perf_event_attr attr = {
21 		.type	= PERF_TYPE_SOFTWARE,
22 		.config	= PERF_COUNT_SW_CPU_CLOCK,
23 	};
24 	int err, cpu, tmp;
25 
26 	cpus = perf_cpu_map__new(NULL);
27 	__T("failed to create cpus", cpus);
28 
29 	evsel = perf_evsel__new(&attr);
30 	__T("failed to create evsel", evsel);
31 
32 	err = perf_evsel__open(evsel, cpus, NULL);
33 	__T("failed to open evsel", err == 0);
34 
35 	perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
36 		struct perf_counts_values counts = { .val = 0 };
37 
38 		perf_evsel__read(evsel, cpu, 0, &counts);
39 		__T("failed to read value for evsel", counts.val != 0);
40 	}
41 
42 	perf_evsel__close(evsel);
43 	perf_evsel__delete(evsel);
44 
45 	perf_cpu_map__put(cpus);
46 	return 0;
47 }
48 
test_stat_thread(void)49 static int test_stat_thread(void)
50 {
51 	struct perf_counts_values counts = { .val = 0 };
52 	struct perf_thread_map *threads;
53 	struct perf_evsel *evsel;
54 	struct perf_event_attr attr = {
55 		.type	= PERF_TYPE_SOFTWARE,
56 		.config	= PERF_COUNT_SW_TASK_CLOCK,
57 	};
58 	int err;
59 
60 	threads = perf_thread_map__new_dummy();
61 	__T("failed to create threads", threads);
62 
63 	perf_thread_map__set_pid(threads, 0, 0);
64 
65 	evsel = perf_evsel__new(&attr);
66 	__T("failed to create evsel", evsel);
67 
68 	err = perf_evsel__open(evsel, NULL, threads);
69 	__T("failed to open evsel", err == 0);
70 
71 	perf_evsel__read(evsel, 0, 0, &counts);
72 	__T("failed to read value for evsel", counts.val != 0);
73 
74 	perf_evsel__close(evsel);
75 	perf_evsel__delete(evsel);
76 
77 	perf_thread_map__put(threads);
78 	return 0;
79 }
80 
test_stat_thread_enable(void)81 static int test_stat_thread_enable(void)
82 {
83 	struct perf_counts_values counts = { .val = 0 };
84 	struct perf_thread_map *threads;
85 	struct perf_evsel *evsel;
86 	struct perf_event_attr attr = {
87 		.type	  = PERF_TYPE_SOFTWARE,
88 		.config	  = PERF_COUNT_SW_TASK_CLOCK,
89 		.disabled = 1,
90 	};
91 	int err;
92 
93 	threads = perf_thread_map__new_dummy();
94 	__T("failed to create threads", threads);
95 
96 	perf_thread_map__set_pid(threads, 0, 0);
97 
98 	evsel = perf_evsel__new(&attr);
99 	__T("failed to create evsel", evsel);
100 
101 	err = perf_evsel__open(evsel, NULL, threads);
102 	__T("failed to open evsel", err == 0);
103 
104 	perf_evsel__read(evsel, 0, 0, &counts);
105 	__T("failed to read value for evsel", counts.val == 0);
106 
107 	err = perf_evsel__enable(evsel);
108 	__T("failed to enable evsel", err == 0);
109 
110 	perf_evsel__read(evsel, 0, 0, &counts);
111 	__T("failed to read value for evsel", counts.val != 0);
112 
113 	err = perf_evsel__disable(evsel);
114 	__T("failed to enable evsel", err == 0);
115 
116 	perf_evsel__close(evsel);
117 	perf_evsel__delete(evsel);
118 
119 	perf_thread_map__put(threads);
120 	return 0;
121 }
122 
test_stat_user_read(int event)123 static int test_stat_user_read(int event)
124 {
125 	struct perf_counts_values counts = { .val = 0 };
126 	struct perf_thread_map *threads;
127 	struct perf_evsel *evsel;
128 	struct perf_event_mmap_page *pc;
129 	struct perf_event_attr attr = {
130 		.type	= PERF_TYPE_HARDWARE,
131 		.config	= event,
132 	};
133 	int err, i;
134 
135 	threads = perf_thread_map__new_dummy();
136 	__T("failed to create threads", threads);
137 
138 	perf_thread_map__set_pid(threads, 0, 0);
139 
140 	evsel = perf_evsel__new(&attr);
141 	__T("failed to create evsel", evsel);
142 
143 	err = perf_evsel__open(evsel, NULL, threads);
144 	__T("failed to open evsel", err == 0);
145 
146 	err = perf_evsel__mmap(evsel, 0);
147 	__T("failed to mmap evsel", err == 0);
148 
149 	pc = perf_evsel__mmap_base(evsel, 0, 0);
150 
151 #if defined(__i386__) || defined(__x86_64__)
152 	__T("userspace counter access not supported", pc->cap_user_rdpmc);
153 	__T("userspace counter access not enabled", pc->index);
154 	__T("userspace counter width not set", pc->pmc_width >= 32);
155 #endif
156 
157 	perf_evsel__read(evsel, 0, 0, &counts);
158 	__T("failed to read value for evsel", counts.val != 0);
159 
160 	for (i = 0; i < 5; i++) {
161 		volatile int count = 0x10000 << i;
162 		__u64 start, end, last = 0;
163 
164 		__T_VERBOSE("\tloop = %u, ", count);
165 
166 		perf_evsel__read(evsel, 0, 0, &counts);
167 		start = counts.val;
168 
169 		while (count--) ;
170 
171 		perf_evsel__read(evsel, 0, 0, &counts);
172 		end = counts.val;
173 
174 		__T("invalid counter data", (end - start) > last);
175 		last = end - start;
176 		__T_VERBOSE("count = %llu\n", end - start);
177 	}
178 
179 	perf_evsel__munmap(evsel);
180 	perf_evsel__close(evsel);
181 	perf_evsel__delete(evsel);
182 
183 	perf_thread_map__put(threads);
184 	return 0;
185 }
186 
main(int argc,char ** argv)187 int main(int argc, char **argv)
188 {
189 	__T_START;
190 
191 	libperf_init(libperf_print);
192 
193 	test_stat_cpu();
194 	test_stat_thread();
195 	test_stat_thread_enable();
196 	test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
197 	test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
198 
199 	__T_END;
200 	return tests_failed == 0 ? 0 : -1;
201 }
202