1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/types.h> |
3 | #include <limits.h> |
4 | #include <unistd.h> |
5 | #include <sys/prctl.h> |
6 | #include <perf/cpumap.h> |
7 | #include <perf/evlist.h> |
8 | #include <perf/mmap.h> |
9 | |
10 | #include "debug.h" |
11 | #include "parse-events.h" |
12 | #include "evlist.h" |
13 | #include "evsel.h" |
14 | #include "record.h" |
15 | #include "thread_map.h" |
16 | #include "tests.h" |
17 | #include "util/mmap.h" |
18 | |
19 | #define CHECK__(x) { \ |
20 | while ((x) < 0) { \ |
21 | pr_debug(#x " failed!\n"); \ |
22 | goto out_err; \ |
23 | } \ |
24 | } |
25 | |
26 | #define CHECK_NOT_NULL__(x) { \ |
27 | while ((x) == NULL) { \ |
28 | pr_debug(#x " failed!\n"); \ |
29 | goto out_err; \ |
30 | } \ |
31 | } |
32 | |
33 | static int find_comm(struct evlist *evlist, const char *comm) |
34 | { |
35 | union perf_event *event; |
36 | struct mmap *md; |
37 | int i, found; |
38 | |
39 | found = 0; |
40 | for (i = 0; i < evlist->core.nr_mmaps; i++) { |
41 | md = &evlist->mmap[i]; |
42 | if (perf_mmap__read_init(&md->core) < 0) |
43 | continue; |
44 | while ((event = perf_mmap__read_event(&md->core)) != NULL) { |
45 | if (event->header.type == PERF_RECORD_COMM && |
46 | (pid_t)event->comm.pid == getpid() && |
47 | (pid_t)event->comm.tid == getpid() && |
48 | strcmp(event->comm.comm, comm) == 0) |
49 | found += 1; |
50 | perf_mmap__consume(&md->core); |
51 | } |
52 | perf_mmap__read_done(&md->core); |
53 | } |
54 | return found; |
55 | } |
56 | |
57 | /** |
58 | * test__keep_tracking - test using a dummy software event to keep tracking. |
59 | * |
60 | * This function implements a test that checks that tracking events continue |
61 | * when an event is disabled but a dummy software event is not disabled. If the |
62 | * test passes %0 is returned, otherwise %-1 is returned. |
63 | */ |
64 | static int test__keep_tracking(struct test_suite *test __maybe_unused, int subtest __maybe_unused) |
65 | { |
66 | struct record_opts opts = { |
67 | .mmap_pages = UINT_MAX, |
68 | .user_freq = UINT_MAX, |
69 | .user_interval = ULLONG_MAX, |
70 | .target = { |
71 | .uses_mmap = true, |
72 | }, |
73 | }; |
74 | struct perf_thread_map *threads = NULL; |
75 | struct perf_cpu_map *cpus = NULL; |
76 | struct evlist *evlist = NULL; |
77 | struct evsel *evsel = NULL; |
78 | int found, err = -1; |
79 | const char *comm; |
80 | |
81 | threads = thread_map__new(-1, getpid(), UINT_MAX); |
82 | CHECK_NOT_NULL__(threads); |
83 | |
84 | cpus = perf_cpu_map__new_online_cpus(); |
85 | CHECK_NOT_NULL__(cpus); |
86 | |
87 | evlist = evlist__new(); |
88 | CHECK_NOT_NULL__(evlist); |
89 | |
90 | perf_evlist__set_maps(&evlist->core, cpus, threads); |
91 | |
92 | CHECK__(parse_event(evlist, "dummy:u" )); |
93 | CHECK__(parse_event(evlist, "cycles:u" )); |
94 | |
95 | evlist__config(evlist, &opts, NULL); |
96 | |
97 | evsel = evlist__first(evlist); |
98 | |
99 | evsel->core.attr.comm = 1; |
100 | evsel->core.attr.disabled = 1; |
101 | evsel->core.attr.enable_on_exec = 0; |
102 | |
103 | if (evlist__open(evlist) < 0) { |
104 | pr_debug("Unable to open dummy and cycles event\n" ); |
105 | err = TEST_SKIP; |
106 | goto out_err; |
107 | } |
108 | |
109 | CHECK__(evlist__mmap(evlist, UINT_MAX)); |
110 | |
111 | /* |
112 | * First, test that a 'comm' event can be found when the event is |
113 | * enabled. |
114 | */ |
115 | |
116 | evlist__enable(evlist); |
117 | |
118 | comm = "Test COMM 1" ; |
119 | CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); |
120 | |
121 | evlist__disable(evlist); |
122 | |
123 | found = find_comm(evlist, comm); |
124 | if (found != 1) { |
125 | pr_debug("First time, failed to find tracking event.\n" ); |
126 | goto out_err; |
127 | } |
128 | |
129 | /* |
130 | * Secondly, test that a 'comm' event can be found when the event is |
131 | * disabled with the dummy event still enabled. |
132 | */ |
133 | |
134 | evlist__enable(evlist); |
135 | |
136 | evsel = evlist__last(evlist); |
137 | |
138 | CHECK__(evsel__disable(evsel)); |
139 | |
140 | comm = "Test COMM 2" ; |
141 | CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); |
142 | |
143 | evlist__disable(evlist); |
144 | |
145 | found = find_comm(evlist, comm); |
146 | if (found != 1) { |
147 | pr_debug("Second time, failed to find tracking event.\n" ); |
148 | goto out_err; |
149 | } |
150 | |
151 | err = 0; |
152 | |
153 | out_err: |
154 | if (evlist) { |
155 | evlist__disable(evlist); |
156 | evlist__delete(evlist); |
157 | } |
158 | perf_cpu_map__put(cpus); |
159 | perf_thread_map__put(threads); |
160 | |
161 | return err; |
162 | } |
163 | |
164 | DEFINE_SUITE("Use a dummy software event to keep tracking" , keep_tracking); |
165 | |