GNU Linux-libre 4.19.264-gnu1
[releases.git] / tools / perf / tests / hists_filter.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "perf.h"
3 #include "util/debug.h"
4 #include "util/symbol.h"
5 #include "util/sort.h"
6 #include "util/evsel.h"
7 #include "util/event.h"
8 #include "util/evlist.h"
9 #include "util/machine.h"
10 #include "util/thread.h"
11 #include "util/parse-events.h"
12 #include "tests/tests.h"
13 #include "tests/hists_common.h"
14 #include <linux/kernel.h>
15
16 struct sample {
17         u32 pid;
18         u64 ip;
19         struct thread *thread;
20         struct map *map;
21         struct symbol *sym;
22         int socket;
23 };
24
25 /* For the numbers, see hists_common.c */
26 static struct sample fake_samples[] = {
27         /* perf [kernel] schedule() */
28         { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, .socket = 0 },
29         /* perf [perf]   main() */
30         { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, .socket = 0 },
31         /* perf [libc]   malloc() */
32         { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, .socket = 0 },
33         /* perf [perf]   main() */
34         { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, .socket = 0 }, /* will be merged */
35         /* perf [perf]   cmd_record() */
36         { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, .socket = 1 },
37         /* perf [kernel] page_fault() */
38         { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 1 },
39         /* bash [bash]   main() */
40         { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_MAIN, .socket = 2 },
41         /* bash [bash]   xmalloc() */
42         { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_XMALLOC, .socket = 2 },
43         /* bash [libc]   malloc() */
44         { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_LIBC_MALLOC, .socket = 3 },
45         /* bash [kernel] page_fault() */
46         { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 3 },
47 };
48
49 static int add_hist_entries(struct perf_evlist *evlist,
50                             struct machine *machine)
51 {
52         struct perf_evsel *evsel;
53         struct addr_location al;
54         struct perf_sample sample = { .period = 100, };
55         size_t i;
56
57         /*
58          * each evsel will have 10 samples but the 4th sample
59          * (perf [perf] main) will be collapsed to an existing entry
60          * so total 9 entries will be in the tree.
61          */
62         evlist__for_each_entry(evlist, evsel) {
63                 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
64                         struct hist_entry_iter iter = {
65                                 .evsel = evsel,
66                                 .sample = &sample,
67                                 .ops = &hist_iter_normal,
68                                 .hide_unresolved = false,
69                         };
70                         struct hists *hists = evsel__hists(evsel);
71
72                         /* make sure it has no filter at first */
73                         hists->thread_filter = NULL;
74                         hists->dso_filter = NULL;
75                         hists->symbol_filter_str = NULL;
76
77                         sample.cpumode = PERF_RECORD_MISC_USER;
78                         sample.pid = fake_samples[i].pid;
79                         sample.tid = fake_samples[i].pid;
80                         sample.ip = fake_samples[i].ip;
81
82                         if (machine__resolve(machine, &al, &sample) < 0)
83                                 goto out;
84
85                         al.socket = fake_samples[i].socket;
86                         if (hist_entry_iter__add(&iter, &al,
87                                                  sysctl_perf_event_max_stack, NULL) < 0) {
88                                 addr_location__put(&al);
89                                 goto out;
90                         }
91
92                         fake_samples[i].thread = al.thread;
93                         fake_samples[i].map = al.map;
94                         fake_samples[i].sym = al.sym;
95                 }
96         }
97
98         return 0;
99
100 out:
101         pr_debug("Not enough memory for adding a hist entry\n");
102         return TEST_FAIL;
103 }
104
105 int test__hists_filter(struct test *test __maybe_unused, int subtest __maybe_unused)
106 {
107         int err = TEST_FAIL;
108         struct machines machines;
109         struct machine *machine;
110         struct perf_evsel *evsel;
111         struct perf_evlist *evlist = perf_evlist__new();
112
113         TEST_ASSERT_VAL("No memory", evlist);
114
115         err = parse_events(evlist, "cpu-clock", NULL);
116         if (err)
117                 goto out;
118         err = parse_events(evlist, "task-clock", NULL);
119         if (err)
120                 goto out;
121         err = TEST_FAIL;
122
123         /* default sort order (comm,dso,sym) will be used */
124         if (setup_sorting(NULL) < 0)
125                 goto out;
126
127         machines__init(&machines);
128
129         /* setup threads/dso/map/symbols also */
130         machine = setup_fake_machine(&machines);
131         if (!machine)
132                 goto out;
133
134         if (verbose > 1)
135                 machine__fprintf(machine, stderr);
136
137         /* process sample events */
138         err = add_hist_entries(evlist, machine);
139         if (err < 0)
140                 goto out;
141
142         evlist__for_each_entry(evlist, evsel) {
143                 struct hists *hists = evsel__hists(evsel);
144
145                 hists__collapse_resort(hists, NULL);
146                 perf_evsel__output_resort(evsel, NULL);
147
148                 if (verbose > 2) {
149                         pr_info("Normal histogram\n");
150                         print_hists_out(hists);
151                 }
152
153                 TEST_ASSERT_VAL("Invalid nr samples",
154                                 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
155                 TEST_ASSERT_VAL("Invalid nr hist entries",
156                                 hists->nr_entries == 9);
157                 TEST_ASSERT_VAL("Invalid total period",
158                                 hists->stats.total_period == 1000);
159                 TEST_ASSERT_VAL("Unmatched nr samples",
160                                 hists->stats.nr_events[PERF_RECORD_SAMPLE] ==
161                                 hists->stats.nr_non_filtered_samples);
162                 TEST_ASSERT_VAL("Unmatched nr hist entries",
163                                 hists->nr_entries == hists->nr_non_filtered_entries);
164                 TEST_ASSERT_VAL("Unmatched total period",
165                                 hists->stats.total_period ==
166                                 hists->stats.total_non_filtered_period);
167
168                 /* now applying thread filter for 'bash' */
169                 hists->thread_filter = fake_samples[9].thread;
170                 hists__filter_by_thread(hists);
171
172                 if (verbose > 2) {
173                         pr_info("Histogram for thread filter\n");
174                         print_hists_out(hists);
175                 }
176
177                 /* normal stats should be invariant */
178                 TEST_ASSERT_VAL("Invalid nr samples",
179                                 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
180                 TEST_ASSERT_VAL("Invalid nr hist entries",
181                                 hists->nr_entries == 9);
182                 TEST_ASSERT_VAL("Invalid total period",
183                                 hists->stats.total_period == 1000);
184
185                 /* but filter stats are changed */
186                 TEST_ASSERT_VAL("Unmatched nr samples for thread filter",
187                                 hists->stats.nr_non_filtered_samples == 4);
188                 TEST_ASSERT_VAL("Unmatched nr hist entries for thread filter",
189                                 hists->nr_non_filtered_entries == 4);
190                 TEST_ASSERT_VAL("Unmatched total period for thread filter",
191                                 hists->stats.total_non_filtered_period == 400);
192
193                 /* remove thread filter first */
194                 hists->thread_filter = NULL;
195                 hists__filter_by_thread(hists);
196
197                 /* now applying dso filter for 'kernel' */
198                 hists->dso_filter = fake_samples[0].map->dso;
199                 hists__filter_by_dso(hists);
200
201                 if (verbose > 2) {
202                         pr_info("Histogram for dso filter\n");
203                         print_hists_out(hists);
204                 }
205
206                 /* normal stats should be invariant */
207                 TEST_ASSERT_VAL("Invalid nr samples",
208                                 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
209                 TEST_ASSERT_VAL("Invalid nr hist entries",
210                                 hists->nr_entries == 9);
211                 TEST_ASSERT_VAL("Invalid total period",
212                                 hists->stats.total_period == 1000);
213
214                 /* but filter stats are changed */
215                 TEST_ASSERT_VAL("Unmatched nr samples for dso filter",
216                                 hists->stats.nr_non_filtered_samples == 3);
217                 TEST_ASSERT_VAL("Unmatched nr hist entries for dso filter",
218                                 hists->nr_non_filtered_entries == 3);
219                 TEST_ASSERT_VAL("Unmatched total period for dso filter",
220                                 hists->stats.total_non_filtered_period == 300);
221
222                 /* remove dso filter first */
223                 hists->dso_filter = NULL;
224                 hists__filter_by_dso(hists);
225
226                 /*
227                  * now applying symbol filter for 'main'.  Also note that
228                  * there's 3 samples that have 'main' symbol but the 4th
229                  * entry of fake_samples was collapsed already so it won't
230                  * be counted as a separate entry but the sample count and
231                  * total period will be remained.
232                  */
233                 hists->symbol_filter_str = "main";
234                 hists__filter_by_symbol(hists);
235
236                 if (verbose > 2) {
237                         pr_info("Histogram for symbol filter\n");
238                         print_hists_out(hists);
239                 }
240
241                 /* normal stats should be invariant */
242                 TEST_ASSERT_VAL("Invalid nr samples",
243                                 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
244                 TEST_ASSERT_VAL("Invalid nr hist entries",
245                                 hists->nr_entries == 9);
246                 TEST_ASSERT_VAL("Invalid total period",
247                                 hists->stats.total_period == 1000);
248
249                 /* but filter stats are changed */
250                 TEST_ASSERT_VAL("Unmatched nr samples for symbol filter",
251                                 hists->stats.nr_non_filtered_samples == 3);
252                 TEST_ASSERT_VAL("Unmatched nr hist entries for symbol filter",
253                                 hists->nr_non_filtered_entries == 2);
254                 TEST_ASSERT_VAL("Unmatched total period for symbol filter",
255                                 hists->stats.total_non_filtered_period == 300);
256
257                 /* remove symbol filter first */
258                 hists->symbol_filter_str = NULL;
259                 hists__filter_by_symbol(hists);
260
261                 /* now applying socket filters */
262                 hists->socket_filter = 2;
263                 hists__filter_by_socket(hists);
264
265                 if (verbose > 2) {
266                         pr_info("Histogram for socket filters\n");
267                         print_hists_out(hists);
268                 }
269
270                 /* normal stats should be invariant */
271                 TEST_ASSERT_VAL("Invalid nr samples",
272                                 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
273                 TEST_ASSERT_VAL("Invalid nr hist entries",
274                                 hists->nr_entries == 9);
275                 TEST_ASSERT_VAL("Invalid total period",
276                                 hists->stats.total_period == 1000);
277
278                 /* but filter stats are changed */
279                 TEST_ASSERT_VAL("Unmatched nr samples for socket filter",
280                                 hists->stats.nr_non_filtered_samples == 2);
281                 TEST_ASSERT_VAL("Unmatched nr hist entries for socket filter",
282                                 hists->nr_non_filtered_entries == 2);
283                 TEST_ASSERT_VAL("Unmatched total period for socket filter",
284                                 hists->stats.total_non_filtered_period == 200);
285
286                 /* remove socket filter first */
287                 hists->socket_filter = -1;
288                 hists__filter_by_socket(hists);
289
290                 /* now applying all filters at once. */
291                 hists->thread_filter = fake_samples[1].thread;
292                 hists->dso_filter = fake_samples[1].map->dso;
293                 hists__filter_by_thread(hists);
294                 hists__filter_by_dso(hists);
295
296                 if (verbose > 2) {
297                         pr_info("Histogram for all filters\n");
298                         print_hists_out(hists);
299                 }
300
301                 /* normal stats should be invariant */
302                 TEST_ASSERT_VAL("Invalid nr samples",
303                                 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
304                 TEST_ASSERT_VAL("Invalid nr hist entries",
305                                 hists->nr_entries == 9);
306                 TEST_ASSERT_VAL("Invalid total period",
307                                 hists->stats.total_period == 1000);
308
309                 /* but filter stats are changed */
310                 TEST_ASSERT_VAL("Unmatched nr samples for all filter",
311                                 hists->stats.nr_non_filtered_samples == 2);
312                 TEST_ASSERT_VAL("Unmatched nr hist entries for all filter",
313                                 hists->nr_non_filtered_entries == 1);
314                 TEST_ASSERT_VAL("Unmatched total period for all filter",
315                                 hists->stats.total_non_filtered_period == 200);
316         }
317
318
319         err = TEST_OK;
320
321 out:
322         /* tear down everything */
323         perf_evlist__delete(evlist);
324         reset_output_field();
325         machines__exit(&machines);
326
327         return err;
328 }