xref: /openbmc/linux/tools/perf/tests/event-times.c (revision 74ce1896)
1 #include <linux/compiler.h>
2 #include <errno.h>
3 #include <inttypes.h>
4 #include <string.h>
5 #include <sys/wait.h>
6 #include "tests.h"
7 #include "evlist.h"
8 #include "evsel.h"
9 #include "util.h"
10 #include "debug.h"
11 #include "thread_map.h"
12 #include "target.h"
13 
14 static int attach__enable_on_exec(struct perf_evlist *evlist)
15 {
16 	struct perf_evsel *evsel = perf_evlist__last(evlist);
17 	struct target target = {
18 		.uid = UINT_MAX,
19 	};
20 	const char *argv[] = { "true", NULL, };
21 	char sbuf[STRERR_BUFSIZE];
22 	int err;
23 
24 	pr_debug("attaching to spawned child, enable on exec\n");
25 
26 	err = perf_evlist__create_maps(evlist, &target);
27 	if (err < 0) {
28 		pr_debug("Not enough memory to create thread/cpu maps\n");
29 		return err;
30 	}
31 
32 	err = perf_evlist__prepare_workload(evlist, &target, argv, false, NULL);
33 	if (err < 0) {
34 		pr_debug("Couldn't run the workload!\n");
35 		return err;
36 	}
37 
38 	evsel->attr.enable_on_exec = 1;
39 
40 	err = perf_evlist__open(evlist);
41 	if (err < 0) {
42 		pr_debug("perf_evlist__open: %s\n",
43 			 str_error_r(errno, sbuf, sizeof(sbuf)));
44 		return err;
45 	}
46 
47 	return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL;
48 }
49 
50 static int detach__enable_on_exec(struct perf_evlist *evlist)
51 {
52 	waitpid(evlist->workload.pid, NULL, 0);
53 	return 0;
54 }
55 
56 static int attach__current_disabled(struct perf_evlist *evlist)
57 {
58 	struct perf_evsel *evsel = perf_evlist__last(evlist);
59 	struct thread_map *threads;
60 	int err;
61 
62 	pr_debug("attaching to current thread as disabled\n");
63 
64 	threads = thread_map__new(-1, getpid(), UINT_MAX);
65 	if (threads == NULL) {
66 		pr_debug("thread_map__new\n");
67 		return -1;
68 	}
69 
70 	evsel->attr.disabled = 1;
71 
72 	err = perf_evsel__open_per_thread(evsel, threads);
73 	if (err) {
74 		pr_debug("Failed to open event cpu-clock:u\n");
75 		return err;
76 	}
77 
78 	thread_map__put(threads);
79 	return perf_evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL;
80 }
81 
82 static int attach__current_enabled(struct perf_evlist *evlist)
83 {
84 	struct perf_evsel *evsel = perf_evlist__last(evlist);
85 	struct thread_map *threads;
86 	int err;
87 
88 	pr_debug("attaching to current thread as enabled\n");
89 
90 	threads = thread_map__new(-1, getpid(), UINT_MAX);
91 	if (threads == NULL) {
92 		pr_debug("failed to call thread_map__new\n");
93 		return -1;
94 	}
95 
96 	err = perf_evsel__open_per_thread(evsel, threads);
97 
98 	thread_map__put(threads);
99 	return err == 0 ? TEST_OK : TEST_FAIL;
100 }
101 
102 static int detach__disable(struct perf_evlist *evlist)
103 {
104 	struct perf_evsel *evsel = perf_evlist__last(evlist);
105 
106 	return perf_evsel__enable(evsel);
107 }
108 
109 static int attach__cpu_disabled(struct perf_evlist *evlist)
110 {
111 	struct perf_evsel *evsel = perf_evlist__last(evlist);
112 	struct cpu_map *cpus;
113 	int err;
114 
115 	pr_debug("attaching to CPU 0 as enabled\n");
116 
117 	cpus = cpu_map__new("0");
118 	if (cpus == NULL) {
119 		pr_debug("failed to call cpu_map__new\n");
120 		return -1;
121 	}
122 
123 	evsel->attr.disabled = 1;
124 
125 	err = perf_evsel__open_per_cpu(evsel, cpus);
126 	if (err) {
127 		if (err == -EACCES)
128 			return TEST_SKIP;
129 
130 		pr_debug("Failed to open event cpu-clock:u\n");
131 		return err;
132 	}
133 
134 	cpu_map__put(cpus);
135 	return perf_evsel__enable(evsel);
136 }
137 
138 static int attach__cpu_enabled(struct perf_evlist *evlist)
139 {
140 	struct perf_evsel *evsel = perf_evlist__last(evlist);
141 	struct cpu_map *cpus;
142 	int err;
143 
144 	pr_debug("attaching to CPU 0 as enabled\n");
145 
146 	cpus = cpu_map__new("0");
147 	if (cpus == NULL) {
148 		pr_debug("failed to call cpu_map__new\n");
149 		return -1;
150 	}
151 
152 	err = perf_evsel__open_per_cpu(evsel, cpus);
153 	if (err == -EACCES)
154 		return TEST_SKIP;
155 
156 	cpu_map__put(cpus);
157 	return err ? TEST_FAIL : TEST_OK;
158 }
159 
160 static int test_times(int (attach)(struct perf_evlist *),
161 		      int (detach)(struct perf_evlist *))
162 {
163 	struct perf_counts_values count;
164 	struct perf_evlist *evlist = NULL;
165 	struct perf_evsel *evsel;
166 	int err = -1, i;
167 
168 	evlist = perf_evlist__new();
169 	if (!evlist) {
170 		pr_debug("failed to create event list\n");
171 		goto out_err;
172 	}
173 
174 	err = parse_events(evlist, "cpu-clock:u", NULL);
175 	if (err) {
176 		pr_debug("failed to parse event cpu-clock:u\n");
177 		goto out_err;
178 	}
179 
180 	evsel = perf_evlist__last(evlist);
181 	evsel->attr.read_format |=
182 		PERF_FORMAT_TOTAL_TIME_ENABLED |
183 		PERF_FORMAT_TOTAL_TIME_RUNNING;
184 
185 	err = attach(evlist);
186 	if (err == TEST_SKIP) {
187 		pr_debug("  SKIP  : not enough rights\n");
188 		return err;
189 	}
190 
191 	TEST_ASSERT_VAL("failed to attach", !err);
192 
193 	for (i = 0; i < 100000000; i++) { }
194 
195 	TEST_ASSERT_VAL("failed to detach", !detach(evlist));
196 
197 	perf_evsel__read(evsel, 0, 0, &count);
198 
199 	err = !(count.ena == count.run);
200 
201 	pr_debug("  %s: ena %" PRIu64", run %" PRIu64"\n",
202 		 !err ? "OK    " : "FAILED",
203 		 count.ena, count.run);
204 
205 out_err:
206 	perf_evlist__delete(evlist);
207 	return !err ? TEST_OK : TEST_FAIL;
208 }
209 
210 /*
211  * This test creates software event 'cpu-clock'
212  * attaches it in several ways (explained below)
213  * and checks that enabled and running times
214  * match.
215  */
216 int test__event_times(struct test *test __maybe_unused, int subtest __maybe_unused)
217 {
218 	int err, ret = 0;
219 
220 #define _T(attach, detach)			\
221 	err = test_times(attach, detach);	\
222 	if (err && (ret == TEST_OK || ret == TEST_SKIP))	\
223 		ret = err;
224 
225 	/* attach on newly spawned process after exec */
226 	_T(attach__enable_on_exec,   detach__enable_on_exec)
227 	/* attach on current process as enabled */
228 	_T(attach__current_enabled,  detach__disable)
229 	/* attach on current process as disabled */
230 	_T(attach__current_disabled, detach__disable)
231 	/* attach on cpu as disabled */
232 	_T(attach__cpu_disabled,     detach__disable)
233 	/* attach on cpu as enabled */
234 	_T(attach__cpu_enabled,      detach__disable)
235 
236 #undef _T
237 	return ret;
238 }
239