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