]>
Commit | Line | Data |
---|---|---|
1c6a800c ACM |
1 | /* |
2 | * builtin-test.c | |
3 | * | |
4 | * Builtin regression testing command: ever growing number of sanity tests | |
5 | */ | |
0d8a5faa JO |
6 | #include <unistd.h> |
7 | #include <string.h> | |
1c6a800c | 8 | #include "builtin.h" |
a635fc51 | 9 | #include "hist.h" |
2ae82878 | 10 | #include "intlist.h" |
0a4e1ae6 | 11 | #include "tests.h" |
c81251e8 JO |
12 | #include "debug.h" |
13 | #include "color.h" | |
14 | #include "parse-options.h" | |
15 | #include "symbol.h" | |
0252208e | 16 | |
1c6a800c ACM |
17 | static struct test { |
18 | const char *desc; | |
19 | int (*func)(void); | |
20 | } tests[] = { | |
21 | { | |
22 | .desc = "vmlinux symtab matches kallsyms", | |
23 | .func = test__vmlinux_matches_kallsyms, | |
24 | }, | |
d854861c ACM |
25 | { |
26 | .desc = "detect open syscall event", | |
27 | .func = test__open_syscall_event, | |
28 | }, | |
0252208e ACM |
29 | { |
30 | .desc = "detect open syscall event on all cpus", | |
31 | .func = test__open_syscall_event_on_all_cpus, | |
32 | }, | |
de5fa3a8 ACM |
33 | { |
34 | .desc = "read samples using the mmap interface", | |
35 | .func = test__basic_mmap, | |
36 | }, | |
13b62567 JO |
37 | { |
38 | .desc = "parse events tests", | |
c81251e8 | 39 | .func = test__parse_events, |
13b62567 | 40 | }, |
08aa0d1f PZ |
41 | #if defined(__x86_64__) || defined(__i386__) |
42 | { | |
43 | .desc = "x86 rdpmc test", | |
44 | .func = test__rdpmc, | |
45 | }, | |
46 | #endif | |
3e7c439a ACM |
47 | { |
48 | .desc = "Validate PERF_RECORD_* events & perf_sample fields", | |
49 | .func = test__PERF_RECORD, | |
50 | }, | |
cd82a32e JO |
51 | { |
52 | .desc = "Test perf pmu format parsing", | |
cff7f956 | 53 | .func = test__pmu, |
cd82a32e | 54 | }, |
f7add556 | 55 | { |
4ebbcb84 | 56 | .desc = "Test dso data read", |
c81251e8 | 57 | .func = test__dso_data, |
f7add556 | 58 | }, |
4ebbcb84 JO |
59 | { |
60 | .desc = "Test dso data cache", | |
61 | .func = test__dso_data_cache, | |
62 | }, | |
45dc1bb5 JO |
63 | { |
64 | .desc = "Test dso data reopen", | |
65 | .func = test__dso_data_reopen, | |
66 | }, | |
8ad7013b ACM |
67 | { |
68 | .desc = "roundtrip evsel->name check", | |
cfffae2e | 69 | .func = test__perf_evsel__roundtrip_name_test, |
8ad7013b | 70 | }, |
6a6cd11d ACM |
71 | { |
72 | .desc = "Check parsing of sched tracepoints fields", | |
5e24a090 | 73 | .func = test__perf_evsel__tp_sched_test, |
6a6cd11d | 74 | }, |
eb2f2703 ACM |
75 | { |
76 | .desc = "Generate and check syscalls:sys_enter_open event fields", | |
77 | .func = test__syscall_open_tp_fields, | |
78 | }, | |
d898b241 JO |
79 | { |
80 | .desc = "struct perf_event_attr setup", | |
c81251e8 | 81 | .func = test__attr, |
d898b241 | 82 | }, |
f8ebb0cd | 83 | { |
ffcbaa14 | 84 | .desc = "Test matching and linking multiple hists", |
f8ebb0cd NK |
85 | .func = test__hists_link, |
86 | }, | |
54359d33 | 87 | { |
887e73d7 | 88 | .desc = "Try 'import perf' in python, checking link problems", |
54359d33 ACM |
89 | .func = test__python_use, |
90 | }, | |
5a6bef47 JO |
91 | { |
92 | .desc = "Test breakpoint overflow signal handler", | |
93 | .func = test__bp_signal, | |
94 | }, | |
06933e3a JO |
95 | { |
96 | .desc = "Test breakpoint overflow sampling", | |
97 | .func = test__bp_signal_overflow, | |
98 | }, | |
d723a550 NK |
99 | { |
100 | .desc = "Test number of exit event of a simple workload", | |
101 | .func = test__task_exit, | |
102 | }, | |
bc96b361 NK |
103 | { |
104 | .desc = "Test software clock events have valid period values", | |
105 | .func = test__sw_clock_freq, | |
106 | }, | |
3bd5a5fc AH |
107 | #if defined(__x86_64__) || defined(__i386__) |
108 | { | |
109 | .desc = "Test converting perf time to TSC", | |
110 | .func = test__perf_time_to_tsc, | |
111 | }, | |
112 | #endif | |
b55ae0a9 AH |
113 | { |
114 | .desc = "Test object code reading", | |
115 | .func = test__code_reading, | |
116 | }, | |
045f8cd8 AH |
117 | { |
118 | .desc = "Test sample parsing", | |
119 | .func = test__sample_parsing, | |
120 | }, | |
395c3070 AH |
121 | { |
122 | .desc = "Test using a dummy software event to keep tracking", | |
123 | .func = test__keep_tracking, | |
124 | }, | |
53a277e5 AH |
125 | { |
126 | .desc = "Test parsing with no sample_id_all bit set", | |
127 | .func = test__parse_no_sample_id_all, | |
128 | }, | |
3237f281 | 129 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) |
9ff125d1 | 130 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
aa16b81f JO |
131 | { |
132 | .desc = "Test dwarf unwind", | |
133 | .func = test__dwarf_unwind, | |
134 | }, | |
135 | #endif | |
136 | #endif | |
3c3cfd99 NK |
137 | { |
138 | .desc = "Test filtering hist entries", | |
139 | .func = test__hists_filter, | |
140 | }, | |
4e85edfc JO |
141 | { |
142 | .desc = "Test mmap thread lookup", | |
143 | .func = test__mmap_thread_lookup, | |
144 | }, | |
fabf0123 JO |
145 | { |
146 | .desc = "Test thread mg sharing", | |
147 | .func = test__thread_mg_share, | |
148 | }, | |
f21d1815 NK |
149 | { |
150 | .desc = "Test output sorting of hist entries", | |
151 | .func = test__hists_output, | |
152 | }, | |
0506aecc NK |
153 | { |
154 | .desc = "Test cumulation of child hist entries", | |
155 | .func = test__hists_cumulate, | |
156 | }, | |
d44bc558 AH |
157 | { |
158 | .desc = "Test tracking with sched_switch", | |
159 | .func = test__switch_tracking, | |
160 | }, | |
54dbfae3 | 161 | { |
1b85337d ACM |
162 | .desc = "Filter fds with revents mask in a fdarray", |
163 | .func = test__fdarray__filter, | |
54dbfae3 | 164 | }, |
9ae28035 | 165 | { |
1b85337d ACM |
166 | .desc = "Add fd to a fdarray, making it autogrow", |
167 | .func = test__fdarray__add, | |
9ae28035 | 168 | }, |
3c8a67f5 JO |
169 | { |
170 | .desc = "Test kmod_path__parse function", | |
171 | .func = test__kmod_path__parse, | |
172 | }, | |
1c6a800c ACM |
173 | { |
174 | .func = NULL, | |
175 | }, | |
176 | }; | |
177 | ||
e60770a0 | 178 | static bool perf_test__matches(int curr, int argc, const char *argv[]) |
1c6a800c | 179 | { |
e60770a0 ACM |
180 | int i; |
181 | ||
182 | if (argc == 0) | |
183 | return true; | |
184 | ||
185 | for (i = 0; i < argc; ++i) { | |
186 | char *end; | |
187 | long nr = strtoul(argv[i], &end, 10); | |
188 | ||
189 | if (*end == '\0') { | |
190 | if (nr == curr + 1) | |
191 | return true; | |
192 | continue; | |
193 | } | |
1c6a800c | 194 | |
e60770a0 ACM |
195 | if (strstr(tests[curr].desc, argv[i])) |
196 | return true; | |
197 | } | |
198 | ||
199 | return false; | |
200 | } | |
201 | ||
0d8a5faa JO |
202 | static int run_test(struct test *test) |
203 | { | |
204 | int status, err = -1, child = fork(); | |
ba3dfff8 | 205 | char sbuf[STRERR_BUFSIZE]; |
0d8a5faa JO |
206 | |
207 | if (child < 0) { | |
ba3dfff8 MH |
208 | pr_err("failed to fork test: %s\n", |
209 | strerror_r(errno, sbuf, sizeof(sbuf))); | |
0d8a5faa JO |
210 | return -1; |
211 | } | |
212 | ||
213 | if (!child) { | |
214 | pr_debug("test child forked, pid %d\n", getpid()); | |
215 | err = test->func(); | |
216 | exit(err); | |
217 | } | |
218 | ||
219 | wait(&status); | |
220 | ||
221 | if (WIFEXITED(status)) { | |
189c466f | 222 | err = (signed char)WEXITSTATUS(status); |
0d8a5faa JO |
223 | pr_debug("test child finished with %d\n", err); |
224 | } else if (WIFSIGNALED(status)) { | |
225 | err = -1; | |
226 | pr_debug("test child interrupted\n"); | |
227 | } | |
228 | ||
229 | return err; | |
230 | } | |
231 | ||
2ae82878 | 232 | static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) |
e60770a0 ACM |
233 | { |
234 | int i = 0; | |
9a8e85ad | 235 | int width = 0; |
1c6a800c | 236 | |
9a8e85ad ACM |
237 | while (tests[i].func) { |
238 | int len = strlen(tests[i].desc); | |
239 | ||
240 | if (width < len) | |
241 | width = len; | |
242 | ++i; | |
243 | } | |
945aea22 | 244 | |
9a8e85ad | 245 | i = 0; |
1c6a800c | 246 | while (tests[i].func) { |
e60770a0 ACM |
247 | int curr = i++, err; |
248 | ||
249 | if (!perf_test__matches(curr, argc, argv)) | |
250 | continue; | |
251 | ||
9a8e85ad | 252 | pr_info("%2d: %-*s:", i, width, tests[curr].desc); |
2ae82878 ACM |
253 | |
254 | if (intlist__find(skiplist, i)) { | |
255 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); | |
256 | continue; | |
257 | } | |
258 | ||
1c6a800c | 259 | pr_debug("\n--- start ---\n"); |
0d8a5faa | 260 | err = run_test(&tests[curr]); |
e60770a0 | 261 | pr_debug("---- end ----\n%s:", tests[curr].desc); |
f4c1ea5f JO |
262 | |
263 | switch (err) { | |
264 | case TEST_OK: | |
9a8e85ad | 265 | pr_info(" Ok\n"); |
f4c1ea5f JO |
266 | break; |
267 | case TEST_SKIP: | |
268 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); | |
269 | break; | |
270 | case TEST_FAIL: | |
271 | default: | |
272 | color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); | |
273 | break; | |
274 | } | |
1c6a800c ACM |
275 | } |
276 | ||
277 | return 0; | |
278 | } | |
279 | ||
e60770a0 ACM |
280 | static int perf_test__list(int argc, const char **argv) |
281 | { | |
282 | int i = 0; | |
283 | ||
284 | while (tests[i].func) { | |
285 | int curr = i++; | |
286 | ||
287 | if (argc > 1 && !strstr(tests[curr].desc, argv[1])) | |
288 | continue; | |
289 | ||
290 | pr_info("%2d: %s\n", i, tests[curr].desc); | |
291 | } | |
292 | ||
293 | return 0; | |
294 | } | |
1c6a800c | 295 | |
1d037ca1 | 296 | int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) |
e60770a0 | 297 | { |
1f9975f1 | 298 | const char *test_usage[] = { |
e60770a0 ACM |
299 | "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", |
300 | NULL, | |
301 | }; | |
2ae82878 | 302 | const char *skip = NULL; |
e60770a0 | 303 | const struct option test_options[] = { |
2ae82878 | 304 | OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), |
c30ab8aa | 305 | OPT_INCR('v', "verbose", &verbose, |
1c6a800c ACM |
306 | "be more verbose (show symbol address, etc)"), |
307 | OPT_END() | |
e60770a0 | 308 | }; |
1f9975f1 | 309 | const char * const test_subcommands[] = { "list", NULL }; |
2ae82878 | 310 | struct intlist *skiplist = NULL; |
a635fc51 ACM |
311 | int ret = hists__init(); |
312 | ||
313 | if (ret < 0) | |
314 | return ret; | |
1c6a800c | 315 | |
1f9975f1 | 316 | argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0); |
e60770a0 ACM |
317 | if (argc >= 1 && !strcmp(argv[0], "list")) |
318 | return perf_test__list(argc, argv); | |
1c6a800c ACM |
319 | |
320 | symbol_conf.priv_size = sizeof(int); | |
321 | symbol_conf.sort_by_name = true; | |
322 | symbol_conf.try_vmlinux_path = true; | |
323 | ||
0a7e6d1b | 324 | if (symbol__init(NULL) < 0) |
1c6a800c ACM |
325 | return -1; |
326 | ||
2ae82878 ACM |
327 | if (skip != NULL) |
328 | skiplist = intlist__new(skip); | |
329 | ||
330 | return __cmd_test(argc, argv, skiplist); | |
1c6a800c | 331 | } |