File Index
Files and directories
Sign in
FILE

hists_filter.c

File preview with syntax highlighting.

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