diff options
author | Namhyung Kim <namhyung@kernel.org> | 2014-04-24 23:28:14 -0400 |
---|---|---|
committer | Jiri Olsa <jolsa@kernel.org> | 2014-04-28 07:42:45 -0400 |
commit | 3c3cfd99c8988e568a5243f38c600a6a03d1b148 (patch) | |
tree | 1c89600fdbd31d342ce8cc3cd7df2e0b01ab9e94 | |
parent | 6e344a952dcfa45b8bfef8eaf8423ab73c5adaf2 (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.perf | 1 | ||||
-rw-r--r-- | tools/perf/tests/builtin-test.c | 4 | ||||
-rw-r--r-- | tools/perf/tests/hists_filter.c | 315 | ||||
-rw-r--r-- | tools/perf/tests/tests.h | 1 |
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 | |||
399 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 399 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
400 | LIB_OBJS += $(OUTPUT)tests/hists_common.o | 400 | LIB_OBJS += $(OUTPUT)tests/hists_common.o |
401 | LIB_OBJS += $(OUTPUT)tests/hists_link.o | 401 | LIB_OBJS += $(OUTPUT)tests/hists_link.o |
402 | LIB_OBJS += $(OUTPUT)tests/hists_filter.o | ||
402 | LIB_OBJS += $(OUTPUT)tests/python-use.o | 403 | LIB_OBJS += $(OUTPUT)tests/python-use.o |
403 | LIB_OBJS += $(OUTPUT)tests/bp_signal.o | 404 | LIB_OBJS += $(OUTPUT)tests/bp_signal.o |
404 | LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o | 405 | LIB_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 | |||
13 | struct 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 */ | ||
22 | static 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 | |||
45 | static 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 | |||
95 | out: | ||
96 | pr_debug("Not enough memory for adding a hist entry\n"); | ||
97 | return TEST_FAIL; | ||
98 | } | ||
99 | |||
100 | static 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 | |||
127 | int 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 | |||
309 | out: | ||
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); | |||
41 | int test__keep_tracking(void); | 41 | int test__keep_tracking(void); |
42 | int test__parse_no_sample_id_all(void); | 42 | int test__parse_no_sample_id_all(void); |
43 | int test__dwarf_unwind(void); | 43 | int test__dwarf_unwind(void); |
44 | int 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 |