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