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