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 /tools/perf/tests | |
| 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>
Diffstat (limited to 'tools/perf/tests')
| -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 |
3 files changed, 320 insertions, 0 deletions
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 |
