Linux Perf
hists_filter.c
Go to the documentation of this file.
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] ==
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 ==
167 
168  /* now applying thread filter for 'bash' */
169  hists->thread_filter = fake_samples[9].thread;
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;
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";
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;
260 
261  /* now applying socket filters */
262  hists->socket_filter = 2;
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;
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;
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);
325  machines__exit(&machines);
326 
327  return err;
328 }
#define FAKE_IP_BASH_XMALLOC
Definition: hists_common.h:27
static void setup_sorting(struct perf_sched *sched, const struct option *options, const char *const usage_msg[])
void hists__filter_by_symbol(struct hists *hists)
Definition: hist.c:2098
struct perf_sample * sample
Definition: hist.h:113
void machines__exit(struct machines *machines)
Definition: machine.c:228
int machine__resolve(struct machine *machine, struct addr_location *al, struct perf_sample *sample)
Definition: event.c:1601
void reset_output_field(void)
Definition: sort.c:2997
Definition: hist.h:106
s32 socket
Definition: symbol.h:218
int int err
Definition: 5sec.c:44
int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
Definition: hist.c:1464
#define FAKE_IP_LIBC_MALLOC
Definition: hists_common.h:29
#define TEST_ASSERT_VAL(text, cond)
Definition: tests.h:7
u64 nr_non_filtered_entries
Definition: hist.h:77
void perf_evlist__delete(struct perf_evlist *evlist)
Definition: evlist.c:133
static struct hists * evsel__hists(struct perf_evsel *evsel)
Definition: hist.h:217
struct map * map
u64 ip
Definition: event.h:192
int parse_events(struct perf_evlist *evlist, const char *str, struct parse_events_error *err)
void addr_location__put(struct addr_location *al)
Definition: event.c:1661
struct map * map
Definition: symbol.h:210
static struct sample fake_samples[]
Definition: hists_filter.c:26
Definition: thread.h:18
struct symbol * sym
#define pr_debug(fmt,...)
Definition: json.h:27
#define FAKE_IP_PERF_MAIN
Definition: hists_common.h:23
#define FAKE_IP_KERNEL_SCHEDULE
Definition: hists_common.h:32
u64 nr_entries
Definition: hist.h:76
#define evlist__for_each_entry(evlist, evsel)
Definition: evlist.h:247
u32 nr_non_filtered_samples
Definition: event.h:408
struct dso * dso
Definition: map.h:45
u64 total_period
Definition: event.h:400
#define FAKE_PID_PERF2
Definition: hists_common.h:9
u64 period
Definition: event.h:198
u32 pid
Definition: event.h:193
u32 tid
Definition: event.h:193
static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
Definition: hists_filter.c:49
int socket
Definition: hists_filter.c:22
struct symbol * sym
Definition: symbol.h:211
const struct dso * dso_filter
Definition: hist.h:81
const char * symbol_filter_str
Definition: hist.h:83
#define FAKE_IP_PERF_CMD_RECORD
Definition: hists_common.h:25
struct thread * thread
Definition: symbol.h:209
int test__hists_filter(struct test *test __maybe_unused, int subtest __maybe_unused)
Definition: hists_filter.c:105
struct thread * thread_filter
Definition: hist.h:80
const struct hist_iter_ops hist_iter_normal
Definition: hist.c:1020
#define FAKE_PID_PERF1
Definition: hists_common.h:8
void hists__filter_by_socket(struct hists *hists)
Definition: hist.c:2108
Definition: jevents.c:228
int socket_filter
Definition: hist.h:88
void machines__init(struct machines *machines)
Definition: machine.c:222
void print_hists_out(struct hists *hists)
Definition: hists_common.c:191
Definition: tests.h:30
void hists__filter_by_thread(struct hists *hists)
Definition: hist.c:2078
#define FAKE_IP_BASH_MAIN
Definition: hists_common.h:26
struct perf_evsel * evsel
Definition: hist.h:112
#define pr_info(fmt,...)
Definition: json.h:24
struct events_stats stats
Definition: hist.h:85
u32 nr_events[PERF_RECORD_HEADER_MAX]
Definition: event.h:407
void hists__filter_by_dso(struct hists *hists)
Definition: hist.c:2088
#define FAKE_IP_KERNEL_PAGE_FAULT
Definition: hists_common.h:33
void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog)
Definition: hist.c:1756
int verbose
Definition: jevents.c:53
Definition: symbol.h:55
struct machine * setup_fake_machine(struct machines *machines)
Definition: hists_common.c:83
#define FAKE_PID_BASH
Definition: hists_common.h:10
Definition: hist.h:71
u64 total_non_filtered_period
Definition: event.h:401
int sysctl_perf_event_max_stack
Definition: util.c:62
struct thread * thread
u8 cpumode
Definition: event.h:207
size_t machine__fprintf(struct machine *machine, FILE *fp)
Definition: machine.c:756
struct perf_evlist * perf_evlist__new(void)
Definition: evlist.c:54
int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, int max_stack_depth, void *arg)
Definition: hist.c:1036
Definition: tests.h:25