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