aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNamhyung Kim <namhyung@kernel.org>2014-04-24 23:28:14 -0400
committerJiri Olsa <jolsa@kernel.org>2014-04-28 07:42:45 -0400
commit3c3cfd99c8988e568a5243f38c600a6a03d1b148 (patch)
tree1c89600fdbd31d342ce8cc3cd7df2e0b01ab9e94
parent6e344a952dcfa45b8bfef8eaf8423ab73c5adaf2 (diff)
perf tests: Add a test case for hists filtering
Now we have changed how hists stats are accounted especially when filter(s) applied. So add a test case to verify it. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Link: http://lkml.kernel.org/r/1398396494-12811-2-git-send-email-namhyung@kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org>
-rw-r--r--tools/perf/Makefile.perf1
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/hists_filter.c315
-rw-r--r--tools/perf/tests/tests.h1
4 files changed, 321 insertions, 0 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index a4aad7844b2b..0807e4c38505 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -399,6 +399,7 @@ LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
399LIB_OBJS += $(OUTPUT)tests/pmu.o 399LIB_OBJS += $(OUTPUT)tests/pmu.o
400LIB_OBJS += $(OUTPUT)tests/hists_common.o 400LIB_OBJS += $(OUTPUT)tests/hists_common.o
401LIB_OBJS += $(OUTPUT)tests/hists_link.o 401LIB_OBJS += $(OUTPUT)tests/hists_link.o
402LIB_OBJS += $(OUTPUT)tests/hists_filter.o
402LIB_OBJS += $(OUTPUT)tests/python-use.o 403LIB_OBJS += $(OUTPUT)tests/python-use.o
403LIB_OBJS += $(OUTPUT)tests/bp_signal.o 404LIB_OBJS += $(OUTPUT)tests/bp_signal.o
404LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 405LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index b11bf8a08430..ceb9daebc389 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -124,6 +124,10 @@ static struct test {
124#endif 124#endif
125#endif 125#endif
126 { 126 {
127 .desc = "Test filtering hist entries",
128 .func = test__hists_filter,
129 },
130 {
127 .func = NULL, 131 .func = NULL,
128 }, 132 },
129}; 133};
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
new file mode 100644
index 000000000000..23dc2f4d12c3
--- /dev/null
+++ b/tools/perf/tests/hists_filter.c
@@ -0,0 +1,315 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 pid;
15 u64 ip;
16 struct thread *thread;
17 struct map *map;
18 struct symbol *sym;
19};
20
21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */
24 { .pid = 100, .ip = 0xf0000 + 700, },
25 /* perf [perf] main() */
26 { .pid = 100, .ip = 0x40000 + 700, },
27 /* perf [libc] malloc() */
28 { .pid = 100, .ip = 0x50000 + 700, },
29 /* perf [perf] main() */
30 { .pid = 200, .ip = 0x40000 + 700, }, /* will be merged */
31 /* perf [perf] cmd_record() */
32 { .pid = 200, .ip = 0x40000 + 900, },
33 /* perf [kernel] page_fault() */
34 { .pid = 200, .ip = 0xf0000 + 800, },
35 /* bash [bash] main() */
36 { .pid = 300, .ip = 0x40000 + 700, },
37 /* bash [bash] xmalloc() */
38 { .pid = 300, .ip = 0x40000 + 800, },
39 /* bash [libc] malloc() */
40 { .pid = 300, .ip = 0x50000 + 700, },
41 /* bash [kernel] page_fault() */
42 { .pid = 300, .ip = 0xf0000 + 800, },
43};
44
45static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
46{
47 struct perf_evsel *evsel;
48 struct addr_location al;
49 struct hist_entry *he;
50 struct perf_sample sample = { .cpu = 0, };
51 size_t i;
52
53 /*
54 * each evsel will have 10 samples but the 4th sample
55 * (perf [perf] main) will be collapsed to an existing entry
56 * so total 9 entries will be in the tree.
57 */
58 evlist__for_each(evlist, evsel) {
59 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
60 const union perf_event event = {
61 .header = {
62 .misc = PERF_RECORD_MISC_USER,
63 },
64 };
65
66 /* make sure it has no filter at first */
67 evsel->hists.thread_filter = NULL;
68 evsel->hists.dso_filter = NULL;
69 evsel->hists.symbol_filter_str = NULL;
70
71 sample.pid = fake_samples[i].pid;
72 sample.ip = fake_samples[i].ip;
73
74 if (perf_event__preprocess_sample(&event, machine, &al,
75 &sample) < 0)
76 goto out;
77
78 he = __hists__add_entry(&evsel->hists, &al, NULL,
79 NULL, NULL, 100, 1, 0);
80 if (he == NULL)
81 goto out;
82
83 fake_samples[i].thread = al.thread;
84 fake_samples[i].map = al.map;
85 fake_samples[i].sym = al.sym;
86
87 hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE);
88 if (!he->filtered)
89 he->hists->stats.nr_non_filtered_samples++;
90 }
91 }
92
93 return 0;
94
95out:
96 pr_debug("Not enough memory for adding a hist entry\n");
97 return TEST_FAIL;
98}
99
100static void print_hists(struct hists *hists)
101{
102 int i = 0;
103 struct rb_root *root;
104 struct rb_node *node;
105
106 root = &hists->entries;
107
108 pr_info("----- %s --------\n", __func__);
109 node = rb_first(root);
110 while (node) {
111 struct hist_entry *he;
112
113 he = rb_entry(node, struct hist_entry, rb_node);
114
115 if (!he->filtered) {
116 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
117 i, thread__comm_str(he->thread),
118 he->ms.map->dso->short_name,
119 he->ms.sym->name, he->stat.period);
120 }
121
122 i++;
123 node = rb_next(node);
124 }
125}
126
127int test__hists_filter(void)
128{
129 int err = TEST_FAIL;
130 struct machines machines;
131 struct machine *machine;
132 struct perf_evsel *evsel;
133 struct perf_evlist *evlist = perf_evlist__new();
134
135 TEST_ASSERT_VAL("No memory", evlist);
136
137 err = parse_events(evlist, "cpu-clock");
138 if (err)
139 goto out;
140 err = parse_events(evlist, "task-clock");
141 if (err)
142 goto out;
143
144 /* default sort order (comm,dso,sym) will be used */
145 if (setup_sorting() < 0)
146 goto out;
147
148 machines__init(&machines);
149
150 /* setup threads/dso/map/symbols also */
151 machine = setup_fake_machine(&machines);
152 if (!machine)
153 goto out;
154
155 if (verbose > 1)
156 machine__fprintf(machine, stderr);
157
158 /* process sample events */
159 err = add_hist_entries(evlist, machine);
160 if (err < 0)
161 goto out;
162
163 evlist__for_each(evlist, evsel) {
164 struct hists *hists = &evsel->hists;
165
166 hists__collapse_resort(hists, NULL);
167 hists__output_resort(hists);
168
169 if (verbose > 2) {
170 pr_info("Normal histogram\n");
171 print_hists(hists);
172 }
173
174 TEST_ASSERT_VAL("Invalid nr samples",
175 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
176 TEST_ASSERT_VAL("Invalid nr hist entries",
177 hists->nr_entries == 9);
178 TEST_ASSERT_VAL("Invalid total period",
179 hists->stats.total_period == 1000);
180 TEST_ASSERT_VAL("Unmatched nr samples",
181 hists->stats.nr_events[PERF_RECORD_SAMPLE] ==
182 hists->stats.nr_non_filtered_samples);
183 TEST_ASSERT_VAL("Unmatched nr hist entries",
184 hists->nr_entries == hists->nr_non_filtered_entries);
185 TEST_ASSERT_VAL("Unmatched total period",
186 hists->stats.total_period ==
187 hists->stats.total_non_filtered_period);
188
189 /* now applying thread filter for 'bash' */
190 evsel->hists.thread_filter = fake_samples[9].thread;
191 hists__filter_by_thread(hists);
192
193 if (verbose > 2) {
194 pr_info("Histogram for thread filter\n");
195 print_hists(hists);
196 }
197
198 /* normal stats should be invariant */
199 TEST_ASSERT_VAL("Invalid nr samples",
200 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
201 TEST_ASSERT_VAL("Invalid nr hist entries",
202 hists->nr_entries == 9);
203 TEST_ASSERT_VAL("Invalid total period",
204 hists->stats.total_period == 1000);
205
206 /* but filter stats are changed */
207 TEST_ASSERT_VAL("Unmatched nr samples for thread filter",
208 hists->stats.nr_non_filtered_samples == 4);
209 TEST_ASSERT_VAL("Unmatched nr hist entries for thread filter",
210 hists->nr_non_filtered_entries == 4);
211 TEST_ASSERT_VAL("Unmatched total period for thread filter",
212 hists->stats.total_non_filtered_period == 400);
213
214 /* remove thread filter first */
215 evsel->hists.thread_filter = NULL;
216 hists__filter_by_thread(hists);
217
218 /* now applying dso filter for 'kernel' */
219 evsel->hists.dso_filter = fake_samples[0].map->dso;
220 hists__filter_by_dso(hists);
221
222 if (verbose > 2) {
223 pr_info("Histogram for dso filter\n");
224 print_hists(hists);
225 }
226
227 /* normal stats should be invariant */
228 TEST_ASSERT_VAL("Invalid nr samples",
229 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
230 TEST_ASSERT_VAL("Invalid nr hist entries",
231 hists->nr_entries == 9);
232 TEST_ASSERT_VAL("Invalid total period",
233 hists->stats.total_period == 1000);
234
235 /* but filter stats are changed */
236 TEST_ASSERT_VAL("Unmatched nr samples for dso filter",
237 hists->stats.nr_non_filtered_samples == 3);
238 TEST_ASSERT_VAL("Unmatched nr hist entries for dso filter",
239 hists->nr_non_filtered_entries == 3);
240 TEST_ASSERT_VAL("Unmatched total period for dso filter",
241 hists->stats.total_non_filtered_period == 300);
242
243 /* remove dso filter first */
244 evsel->hists.dso_filter = NULL;
245 hists__filter_by_dso(hists);
246
247 /*
248 * now applying symbol filter for 'main'. Also note that
249 * there's 3 samples that have 'main' symbol but the 4th
250 * entry of fake_samples was collapsed already so it won't
251 * be counted as a separate entry but the sample count and
252 * total period will be remained.
253 */
254 evsel->hists.symbol_filter_str = "main";
255 hists__filter_by_symbol(hists);
256
257 if (verbose > 2) {
258 pr_info("Histogram for symbol filter\n");
259 print_hists(hists);
260 }
261
262 /* normal stats should be invariant */
263 TEST_ASSERT_VAL("Invalid nr samples",
264 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
265 TEST_ASSERT_VAL("Invalid nr hist entries",
266 hists->nr_entries == 9);
267 TEST_ASSERT_VAL("Invalid total period",
268 hists->stats.total_period == 1000);
269
270 /* but filter stats are changed */
271 TEST_ASSERT_VAL("Unmatched nr samples for symbol filter",
272 hists->stats.nr_non_filtered_samples == 3);
273 TEST_ASSERT_VAL("Unmatched nr hist entries for symbol filter",
274 hists->nr_non_filtered_entries == 2);
275 TEST_ASSERT_VAL("Unmatched total period for symbol filter",
276 hists->stats.total_non_filtered_period == 300);
277
278 /* now applying all filters at once. */
279 evsel->hists.thread_filter = fake_samples[1].thread;
280 evsel->hists.dso_filter = fake_samples[1].map->dso;
281 hists__filter_by_thread(hists);
282 hists__filter_by_dso(hists);
283
284 if (verbose > 2) {
285 pr_info("Histogram for all filters\n");
286 print_hists(hists);
287 }
288
289 /* normal stats should be invariant */
290 TEST_ASSERT_VAL("Invalid nr samples",
291 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
292 TEST_ASSERT_VAL("Invalid nr hist entries",
293 hists->nr_entries == 9);
294 TEST_ASSERT_VAL("Invalid total period",
295 hists->stats.total_period == 1000);
296
297 /* but filter stats are changed */
298 TEST_ASSERT_VAL("Unmatched nr samples for all filter",
299 hists->stats.nr_non_filtered_samples == 2);
300 TEST_ASSERT_VAL("Unmatched nr hist entries for all filter",
301 hists->nr_non_filtered_entries == 1);
302 TEST_ASSERT_VAL("Unmatched total period for all filter",
303 hists->stats.total_non_filtered_period == 200);
304 }
305
306
307 err = TEST_OK;
308
309out:
310 /* tear down everything */
311 perf_evlist__delete(evlist);
312 machines__exit(&machines);
313
314 return err;
315}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index a24795ca002d..fe39163e9ea7 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -41,6 +41,7 @@ int test__sample_parsing(void);
41int test__keep_tracking(void); 41int test__keep_tracking(void);
42int test__parse_no_sample_id_all(void); 42int test__parse_no_sample_id_all(void);
43int test__dwarf_unwind(void); 43int test__dwarf_unwind(void);
44int test__hists_filter(void);
44 45
45#if defined(__x86_64__) || defined(__i386__) 46#if defined(__x86_64__) || defined(__i386__)
46#ifdef HAVE_DWARF_UNWIND_SUPPORT 47#ifdef HAVE_DWARF_UNWIND_SUPPORT