1*f8ebb0cdSNamhyung Kim #include "perf.h" 2*f8ebb0cdSNamhyung Kim #include "tests.h" 3*f8ebb0cdSNamhyung Kim #include "debug.h" 4*f8ebb0cdSNamhyung Kim #include "symbol.h" 5*f8ebb0cdSNamhyung Kim #include "sort.h" 6*f8ebb0cdSNamhyung Kim #include "evsel.h" 7*f8ebb0cdSNamhyung Kim #include "evlist.h" 8*f8ebb0cdSNamhyung Kim #include "machine.h" 9*f8ebb0cdSNamhyung Kim #include "thread.h" 10*f8ebb0cdSNamhyung Kim #include "parse-events.h" 11*f8ebb0cdSNamhyung Kim 12*f8ebb0cdSNamhyung Kim static struct { 13*f8ebb0cdSNamhyung Kim u32 pid; 14*f8ebb0cdSNamhyung Kim const char *comm; 15*f8ebb0cdSNamhyung Kim } fake_threads[] = { 16*f8ebb0cdSNamhyung Kim { 100, "perf" }, 17*f8ebb0cdSNamhyung Kim { 200, "perf" }, 18*f8ebb0cdSNamhyung Kim { 300, "bash" }, 19*f8ebb0cdSNamhyung Kim }; 20*f8ebb0cdSNamhyung Kim 21*f8ebb0cdSNamhyung Kim static struct { 22*f8ebb0cdSNamhyung Kim u32 pid; 23*f8ebb0cdSNamhyung Kim u64 start; 24*f8ebb0cdSNamhyung Kim const char *filename; 25*f8ebb0cdSNamhyung Kim } fake_mmap_info[] = { 26*f8ebb0cdSNamhyung Kim { 100, 0x40000, "perf" }, 27*f8ebb0cdSNamhyung Kim { 100, 0x50000, "libc" }, 28*f8ebb0cdSNamhyung Kim { 100, 0xf0000, "[kernel]" }, 29*f8ebb0cdSNamhyung Kim { 200, 0x40000, "perf" }, 30*f8ebb0cdSNamhyung Kim { 200, 0x50000, "libc" }, 31*f8ebb0cdSNamhyung Kim { 200, 0xf0000, "[kernel]" }, 32*f8ebb0cdSNamhyung Kim { 300, 0x40000, "bash" }, 33*f8ebb0cdSNamhyung Kim { 300, 0x50000, "libc" }, 34*f8ebb0cdSNamhyung Kim { 300, 0xf0000, "[kernel]" }, 35*f8ebb0cdSNamhyung Kim }; 36*f8ebb0cdSNamhyung Kim 37*f8ebb0cdSNamhyung Kim struct fake_sym { 38*f8ebb0cdSNamhyung Kim u64 start; 39*f8ebb0cdSNamhyung Kim u64 length; 40*f8ebb0cdSNamhyung Kim const char *name; 41*f8ebb0cdSNamhyung Kim }; 42*f8ebb0cdSNamhyung Kim 43*f8ebb0cdSNamhyung Kim static struct fake_sym perf_syms[] = { 44*f8ebb0cdSNamhyung Kim { 700, 100, "main" }, 45*f8ebb0cdSNamhyung Kim { 800, 100, "run_command" }, 46*f8ebb0cdSNamhyung Kim { 900, 100, "cmd_record" }, 47*f8ebb0cdSNamhyung Kim }; 48*f8ebb0cdSNamhyung Kim 49*f8ebb0cdSNamhyung Kim static struct fake_sym bash_syms[] = { 50*f8ebb0cdSNamhyung Kim { 700, 100, "main" }, 51*f8ebb0cdSNamhyung Kim { 800, 100, "xmalloc" }, 52*f8ebb0cdSNamhyung Kim { 900, 100, "xfree" }, 53*f8ebb0cdSNamhyung Kim }; 54*f8ebb0cdSNamhyung Kim 55*f8ebb0cdSNamhyung Kim static struct fake_sym libc_syms[] = { 56*f8ebb0cdSNamhyung Kim { 700, 100, "malloc" }, 57*f8ebb0cdSNamhyung Kim { 800, 100, "free" }, 58*f8ebb0cdSNamhyung Kim { 900, 100, "realloc" }, 59*f8ebb0cdSNamhyung Kim }; 60*f8ebb0cdSNamhyung Kim 61*f8ebb0cdSNamhyung Kim static struct fake_sym kernel_syms[] = { 62*f8ebb0cdSNamhyung Kim { 700, 100, "schedule" }, 63*f8ebb0cdSNamhyung Kim { 800, 100, "page_fault" }, 64*f8ebb0cdSNamhyung Kim { 900, 100, "sys_perf_event_open" }, 65*f8ebb0cdSNamhyung Kim }; 66*f8ebb0cdSNamhyung Kim 67*f8ebb0cdSNamhyung Kim static struct { 68*f8ebb0cdSNamhyung Kim const char *dso_name; 69*f8ebb0cdSNamhyung Kim struct fake_sym *syms; 70*f8ebb0cdSNamhyung Kim size_t nr_syms; 71*f8ebb0cdSNamhyung Kim } fake_symbols[] = { 72*f8ebb0cdSNamhyung Kim { "perf", perf_syms, ARRAY_SIZE(perf_syms) }, 73*f8ebb0cdSNamhyung Kim { "bash", bash_syms, ARRAY_SIZE(bash_syms) }, 74*f8ebb0cdSNamhyung Kim { "libc", libc_syms, ARRAY_SIZE(libc_syms) }, 75*f8ebb0cdSNamhyung Kim { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) }, 76*f8ebb0cdSNamhyung Kim }; 77*f8ebb0cdSNamhyung Kim 78*f8ebb0cdSNamhyung Kim static struct machine *setup_fake_machine(void) 79*f8ebb0cdSNamhyung Kim { 80*f8ebb0cdSNamhyung Kim struct rb_root machine_root = RB_ROOT; 81*f8ebb0cdSNamhyung Kim struct machine *machine; 82*f8ebb0cdSNamhyung Kim size_t i; 83*f8ebb0cdSNamhyung Kim 84*f8ebb0cdSNamhyung Kim machine = machines__findnew(&machine_root, HOST_KERNEL_ID); 85*f8ebb0cdSNamhyung Kim if (machine == NULL) { 86*f8ebb0cdSNamhyung Kim pr_debug("Not enough memory for machine setup\n"); 87*f8ebb0cdSNamhyung Kim return NULL; 88*f8ebb0cdSNamhyung Kim } 89*f8ebb0cdSNamhyung Kim 90*f8ebb0cdSNamhyung Kim for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { 91*f8ebb0cdSNamhyung Kim struct thread *thread; 92*f8ebb0cdSNamhyung Kim 93*f8ebb0cdSNamhyung Kim thread = machine__findnew_thread(machine, fake_threads[i].pid); 94*f8ebb0cdSNamhyung Kim if (thread == NULL) 95*f8ebb0cdSNamhyung Kim goto out; 96*f8ebb0cdSNamhyung Kim 97*f8ebb0cdSNamhyung Kim thread__set_comm(thread, fake_threads[i].comm); 98*f8ebb0cdSNamhyung Kim } 99*f8ebb0cdSNamhyung Kim 100*f8ebb0cdSNamhyung Kim for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { 101*f8ebb0cdSNamhyung Kim union perf_event fake_mmap_event = { 102*f8ebb0cdSNamhyung Kim .mmap = { 103*f8ebb0cdSNamhyung Kim .header = { .misc = PERF_RECORD_MISC_USER, }, 104*f8ebb0cdSNamhyung Kim .pid = fake_mmap_info[i].pid, 105*f8ebb0cdSNamhyung Kim .start = fake_mmap_info[i].start, 106*f8ebb0cdSNamhyung Kim .len = 0x1000ULL, 107*f8ebb0cdSNamhyung Kim .pgoff = 0ULL, 108*f8ebb0cdSNamhyung Kim }, 109*f8ebb0cdSNamhyung Kim }; 110*f8ebb0cdSNamhyung Kim 111*f8ebb0cdSNamhyung Kim strcpy(fake_mmap_event.mmap.filename, 112*f8ebb0cdSNamhyung Kim fake_mmap_info[i].filename); 113*f8ebb0cdSNamhyung Kim 114*f8ebb0cdSNamhyung Kim machine__process_mmap_event(machine, &fake_mmap_event); 115*f8ebb0cdSNamhyung Kim } 116*f8ebb0cdSNamhyung Kim 117*f8ebb0cdSNamhyung Kim for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { 118*f8ebb0cdSNamhyung Kim size_t k; 119*f8ebb0cdSNamhyung Kim struct dso *dso; 120*f8ebb0cdSNamhyung Kim 121*f8ebb0cdSNamhyung Kim dso = __dsos__findnew(&machine->user_dsos, 122*f8ebb0cdSNamhyung Kim fake_symbols[i].dso_name); 123*f8ebb0cdSNamhyung Kim if (dso == NULL) 124*f8ebb0cdSNamhyung Kim goto out; 125*f8ebb0cdSNamhyung Kim 126*f8ebb0cdSNamhyung Kim /* emulate dso__load() */ 127*f8ebb0cdSNamhyung Kim dso__set_loaded(dso, MAP__FUNCTION); 128*f8ebb0cdSNamhyung Kim 129*f8ebb0cdSNamhyung Kim for (k = 0; k < fake_symbols[i].nr_syms; k++) { 130*f8ebb0cdSNamhyung Kim struct symbol *sym; 131*f8ebb0cdSNamhyung Kim struct fake_sym *fsym = &fake_symbols[i].syms[k]; 132*f8ebb0cdSNamhyung Kim 133*f8ebb0cdSNamhyung Kim sym = symbol__new(fsym->start, fsym->length, 134*f8ebb0cdSNamhyung Kim STB_GLOBAL, fsym->name); 135*f8ebb0cdSNamhyung Kim if (sym == NULL) 136*f8ebb0cdSNamhyung Kim goto out; 137*f8ebb0cdSNamhyung Kim 138*f8ebb0cdSNamhyung Kim symbols__insert(&dso->symbols[MAP__FUNCTION], sym); 139*f8ebb0cdSNamhyung Kim } 140*f8ebb0cdSNamhyung Kim } 141*f8ebb0cdSNamhyung Kim 142*f8ebb0cdSNamhyung Kim return machine; 143*f8ebb0cdSNamhyung Kim 144*f8ebb0cdSNamhyung Kim out: 145*f8ebb0cdSNamhyung Kim pr_debug("Not enough memory for machine setup\n"); 146*f8ebb0cdSNamhyung Kim machine__delete_threads(machine); 147*f8ebb0cdSNamhyung Kim machine__delete(machine); 148*f8ebb0cdSNamhyung Kim return NULL; 149*f8ebb0cdSNamhyung Kim } 150*f8ebb0cdSNamhyung Kim 151*f8ebb0cdSNamhyung Kim struct sample { 152*f8ebb0cdSNamhyung Kim u32 pid; 153*f8ebb0cdSNamhyung Kim u64 ip; 154*f8ebb0cdSNamhyung Kim struct thread *thread; 155*f8ebb0cdSNamhyung Kim struct map *map; 156*f8ebb0cdSNamhyung Kim struct symbol *sym; 157*f8ebb0cdSNamhyung Kim }; 158*f8ebb0cdSNamhyung Kim 159*f8ebb0cdSNamhyung Kim static struct sample fake_common_samples[] = { 160*f8ebb0cdSNamhyung Kim /* perf [kernel] schedule() */ 161*f8ebb0cdSNamhyung Kim { .pid = 100, .ip = 0xf0000 + 700, }, 162*f8ebb0cdSNamhyung Kim /* perf [perf] main() */ 163*f8ebb0cdSNamhyung Kim { .pid = 200, .ip = 0x40000 + 700, }, 164*f8ebb0cdSNamhyung Kim /* perf [perf] cmd_record() */ 165*f8ebb0cdSNamhyung Kim { .pid = 200, .ip = 0x40000 + 900, }, 166*f8ebb0cdSNamhyung Kim /* bash [bash] xmalloc() */ 167*f8ebb0cdSNamhyung Kim { .pid = 300, .ip = 0x40000 + 800, }, 168*f8ebb0cdSNamhyung Kim /* bash [libc] malloc() */ 169*f8ebb0cdSNamhyung Kim { .pid = 300, .ip = 0x50000 + 700, }, 170*f8ebb0cdSNamhyung Kim }; 171*f8ebb0cdSNamhyung Kim 172*f8ebb0cdSNamhyung Kim static struct sample fake_samples[][5] = { 173*f8ebb0cdSNamhyung Kim { 174*f8ebb0cdSNamhyung Kim /* perf [perf] run_command() */ 175*f8ebb0cdSNamhyung Kim { .pid = 100, .ip = 0x40000 + 800, }, 176*f8ebb0cdSNamhyung Kim /* perf [libc] malloc() */ 177*f8ebb0cdSNamhyung Kim { .pid = 100, .ip = 0x50000 + 700, }, 178*f8ebb0cdSNamhyung Kim /* perf [kernel] page_fault() */ 179*f8ebb0cdSNamhyung Kim { .pid = 100, .ip = 0xf0000 + 800, }, 180*f8ebb0cdSNamhyung Kim /* perf [kernel] sys_perf_event_open() */ 181*f8ebb0cdSNamhyung Kim { .pid = 200, .ip = 0xf0000 + 900, }, 182*f8ebb0cdSNamhyung Kim /* bash [libc] free() */ 183*f8ebb0cdSNamhyung Kim { .pid = 300, .ip = 0x50000 + 800, }, 184*f8ebb0cdSNamhyung Kim }, 185*f8ebb0cdSNamhyung Kim { 186*f8ebb0cdSNamhyung Kim /* perf [libc] free() */ 187*f8ebb0cdSNamhyung Kim { .pid = 200, .ip = 0x50000 + 800, }, 188*f8ebb0cdSNamhyung Kim /* bash [libc] malloc() */ 189*f8ebb0cdSNamhyung Kim { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */ 190*f8ebb0cdSNamhyung Kim /* bash [bash] xfee() */ 191*f8ebb0cdSNamhyung Kim { .pid = 300, .ip = 0x40000 + 900, }, 192*f8ebb0cdSNamhyung Kim /* bash [libc] realloc() */ 193*f8ebb0cdSNamhyung Kim { .pid = 300, .ip = 0x50000 + 900, }, 194*f8ebb0cdSNamhyung Kim /* bash [kernel] page_fault() */ 195*f8ebb0cdSNamhyung Kim { .pid = 300, .ip = 0xf0000 + 800, }, 196*f8ebb0cdSNamhyung Kim }, 197*f8ebb0cdSNamhyung Kim }; 198*f8ebb0cdSNamhyung Kim 199*f8ebb0cdSNamhyung Kim static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) 200*f8ebb0cdSNamhyung Kim { 201*f8ebb0cdSNamhyung Kim struct perf_evsel *evsel; 202*f8ebb0cdSNamhyung Kim struct addr_location al; 203*f8ebb0cdSNamhyung Kim struct hist_entry *he; 204*f8ebb0cdSNamhyung Kim struct perf_sample sample = { .cpu = 0, }; 205*f8ebb0cdSNamhyung Kim size_t i = 0, k; 206*f8ebb0cdSNamhyung Kim 207*f8ebb0cdSNamhyung Kim /* 208*f8ebb0cdSNamhyung Kim * each evsel will have 10 samples - 5 common and 5 distinct. 209*f8ebb0cdSNamhyung Kim * However the second evsel also has a collapsed entry for 210*f8ebb0cdSNamhyung Kim * "bash [libc] malloc" so total 9 entries will be in the tree. 211*f8ebb0cdSNamhyung Kim */ 212*f8ebb0cdSNamhyung Kim list_for_each_entry(evsel, &evlist->entries, node) { 213*f8ebb0cdSNamhyung Kim for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 214*f8ebb0cdSNamhyung Kim const union perf_event event = { 215*f8ebb0cdSNamhyung Kim .ip = { 216*f8ebb0cdSNamhyung Kim .header = { 217*f8ebb0cdSNamhyung Kim .misc = PERF_RECORD_MISC_USER, 218*f8ebb0cdSNamhyung Kim }, 219*f8ebb0cdSNamhyung Kim .pid = fake_common_samples[k].pid, 220*f8ebb0cdSNamhyung Kim .ip = fake_common_samples[k].ip, 221*f8ebb0cdSNamhyung Kim }, 222*f8ebb0cdSNamhyung Kim }; 223*f8ebb0cdSNamhyung Kim 224*f8ebb0cdSNamhyung Kim if (perf_event__preprocess_sample(&event, machine, &al, 225*f8ebb0cdSNamhyung Kim &sample, 0) < 0) 226*f8ebb0cdSNamhyung Kim goto out; 227*f8ebb0cdSNamhyung Kim 228*f8ebb0cdSNamhyung Kim he = __hists__add_entry(&evsel->hists, &al, NULL, 1); 229*f8ebb0cdSNamhyung Kim if (he == NULL) 230*f8ebb0cdSNamhyung Kim goto out; 231*f8ebb0cdSNamhyung Kim 232*f8ebb0cdSNamhyung Kim fake_common_samples[k].thread = al.thread; 233*f8ebb0cdSNamhyung Kim fake_common_samples[k].map = al.map; 234*f8ebb0cdSNamhyung Kim fake_common_samples[k].sym = al.sym; 235*f8ebb0cdSNamhyung Kim } 236*f8ebb0cdSNamhyung Kim 237*f8ebb0cdSNamhyung Kim for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { 238*f8ebb0cdSNamhyung Kim const union perf_event event = { 239*f8ebb0cdSNamhyung Kim .ip = { 240*f8ebb0cdSNamhyung Kim .header = { 241*f8ebb0cdSNamhyung Kim .misc = PERF_RECORD_MISC_USER, 242*f8ebb0cdSNamhyung Kim }, 243*f8ebb0cdSNamhyung Kim .pid = fake_samples[i][k].pid, 244*f8ebb0cdSNamhyung Kim .ip = fake_samples[i][k].ip, 245*f8ebb0cdSNamhyung Kim }, 246*f8ebb0cdSNamhyung Kim }; 247*f8ebb0cdSNamhyung Kim 248*f8ebb0cdSNamhyung Kim if (perf_event__preprocess_sample(&event, machine, &al, 249*f8ebb0cdSNamhyung Kim &sample, 0) < 0) 250*f8ebb0cdSNamhyung Kim goto out; 251*f8ebb0cdSNamhyung Kim 252*f8ebb0cdSNamhyung Kim he = __hists__add_entry(&evsel->hists, &al, NULL, 1); 253*f8ebb0cdSNamhyung Kim if (he == NULL) 254*f8ebb0cdSNamhyung Kim goto out; 255*f8ebb0cdSNamhyung Kim 256*f8ebb0cdSNamhyung Kim fake_samples[i][k].thread = al.thread; 257*f8ebb0cdSNamhyung Kim fake_samples[i][k].map = al.map; 258*f8ebb0cdSNamhyung Kim fake_samples[i][k].sym = al.sym; 259*f8ebb0cdSNamhyung Kim } 260*f8ebb0cdSNamhyung Kim i++; 261*f8ebb0cdSNamhyung Kim } 262*f8ebb0cdSNamhyung Kim 263*f8ebb0cdSNamhyung Kim return 0; 264*f8ebb0cdSNamhyung Kim 265*f8ebb0cdSNamhyung Kim out: 266*f8ebb0cdSNamhyung Kim pr_debug("Not enough memory for adding a hist entry\n"); 267*f8ebb0cdSNamhyung Kim return -1; 268*f8ebb0cdSNamhyung Kim } 269*f8ebb0cdSNamhyung Kim 270*f8ebb0cdSNamhyung Kim static int find_sample(struct sample *samples, size_t nr_samples, 271*f8ebb0cdSNamhyung Kim struct thread *t, struct map *m, struct symbol *s) 272*f8ebb0cdSNamhyung Kim { 273*f8ebb0cdSNamhyung Kim while (nr_samples--) { 274*f8ebb0cdSNamhyung Kim if (samples->thread == t && samples->map == m && 275*f8ebb0cdSNamhyung Kim samples->sym == s) 276*f8ebb0cdSNamhyung Kim return 1; 277*f8ebb0cdSNamhyung Kim samples++; 278*f8ebb0cdSNamhyung Kim } 279*f8ebb0cdSNamhyung Kim return 0; 280*f8ebb0cdSNamhyung Kim } 281*f8ebb0cdSNamhyung Kim 282*f8ebb0cdSNamhyung Kim static int __validate_match(struct hists *hists) 283*f8ebb0cdSNamhyung Kim { 284*f8ebb0cdSNamhyung Kim size_t count = 0; 285*f8ebb0cdSNamhyung Kim struct rb_root *root; 286*f8ebb0cdSNamhyung Kim struct rb_node *node; 287*f8ebb0cdSNamhyung Kim 288*f8ebb0cdSNamhyung Kim /* 289*f8ebb0cdSNamhyung Kim * Only entries from fake_common_samples should have a pair. 290*f8ebb0cdSNamhyung Kim */ 291*f8ebb0cdSNamhyung Kim if (sort__need_collapse) 292*f8ebb0cdSNamhyung Kim root = &hists->entries_collapsed; 293*f8ebb0cdSNamhyung Kim else 294*f8ebb0cdSNamhyung Kim root = hists->entries_in; 295*f8ebb0cdSNamhyung Kim 296*f8ebb0cdSNamhyung Kim node = rb_first(root); 297*f8ebb0cdSNamhyung Kim while (node) { 298*f8ebb0cdSNamhyung Kim struct hist_entry *he; 299*f8ebb0cdSNamhyung Kim 300*f8ebb0cdSNamhyung Kim he = rb_entry(node, struct hist_entry, rb_node_in); 301*f8ebb0cdSNamhyung Kim 302*f8ebb0cdSNamhyung Kim if (hist_entry__has_pairs(he)) { 303*f8ebb0cdSNamhyung Kim if (find_sample(fake_common_samples, 304*f8ebb0cdSNamhyung Kim ARRAY_SIZE(fake_common_samples), 305*f8ebb0cdSNamhyung Kim he->thread, he->ms.map, he->ms.sym)) { 306*f8ebb0cdSNamhyung Kim count++; 307*f8ebb0cdSNamhyung Kim } else { 308*f8ebb0cdSNamhyung Kim pr_debug("Can't find the matched entry\n"); 309*f8ebb0cdSNamhyung Kim return -1; 310*f8ebb0cdSNamhyung Kim } 311*f8ebb0cdSNamhyung Kim } 312*f8ebb0cdSNamhyung Kim 313*f8ebb0cdSNamhyung Kim node = rb_next(node); 314*f8ebb0cdSNamhyung Kim } 315*f8ebb0cdSNamhyung Kim 316*f8ebb0cdSNamhyung Kim if (count != ARRAY_SIZE(fake_common_samples)) { 317*f8ebb0cdSNamhyung Kim pr_debug("Invalid count for matched entries: %zd of %zd\n", 318*f8ebb0cdSNamhyung Kim count, ARRAY_SIZE(fake_common_samples)); 319*f8ebb0cdSNamhyung Kim return -1; 320*f8ebb0cdSNamhyung Kim } 321*f8ebb0cdSNamhyung Kim 322*f8ebb0cdSNamhyung Kim return 0; 323*f8ebb0cdSNamhyung Kim } 324*f8ebb0cdSNamhyung Kim 325*f8ebb0cdSNamhyung Kim static int validate_match(struct hists *leader, struct hists *other) 326*f8ebb0cdSNamhyung Kim { 327*f8ebb0cdSNamhyung Kim return __validate_match(leader) || __validate_match(other); 328*f8ebb0cdSNamhyung Kim } 329*f8ebb0cdSNamhyung Kim 330*f8ebb0cdSNamhyung Kim static int __validate_link(struct hists *hists, int idx) 331*f8ebb0cdSNamhyung Kim { 332*f8ebb0cdSNamhyung Kim size_t count = 0; 333*f8ebb0cdSNamhyung Kim size_t count_pair = 0; 334*f8ebb0cdSNamhyung Kim size_t count_dummy = 0; 335*f8ebb0cdSNamhyung Kim struct rb_root *root; 336*f8ebb0cdSNamhyung Kim struct rb_node *node; 337*f8ebb0cdSNamhyung Kim 338*f8ebb0cdSNamhyung Kim /* 339*f8ebb0cdSNamhyung Kim * Leader hists (idx = 0) will have dummy entries from other, 340*f8ebb0cdSNamhyung Kim * and some entries will have no pair. However every entry 341*f8ebb0cdSNamhyung Kim * in other hists should have (dummy) pair. 342*f8ebb0cdSNamhyung Kim */ 343*f8ebb0cdSNamhyung Kim if (sort__need_collapse) 344*f8ebb0cdSNamhyung Kim root = &hists->entries_collapsed; 345*f8ebb0cdSNamhyung Kim else 346*f8ebb0cdSNamhyung Kim root = hists->entries_in; 347*f8ebb0cdSNamhyung Kim 348*f8ebb0cdSNamhyung Kim node = rb_first(root); 349*f8ebb0cdSNamhyung Kim while (node) { 350*f8ebb0cdSNamhyung Kim struct hist_entry *he; 351*f8ebb0cdSNamhyung Kim 352*f8ebb0cdSNamhyung Kim he = rb_entry(node, struct hist_entry, rb_node_in); 353*f8ebb0cdSNamhyung Kim 354*f8ebb0cdSNamhyung Kim if (hist_entry__has_pairs(he)) { 355*f8ebb0cdSNamhyung Kim if (!find_sample(fake_common_samples, 356*f8ebb0cdSNamhyung Kim ARRAY_SIZE(fake_common_samples), 357*f8ebb0cdSNamhyung Kim he->thread, he->ms.map, he->ms.sym) && 358*f8ebb0cdSNamhyung Kim !find_sample(fake_samples[idx], 359*f8ebb0cdSNamhyung Kim ARRAY_SIZE(fake_samples[idx]), 360*f8ebb0cdSNamhyung Kim he->thread, he->ms.map, he->ms.sym)) { 361*f8ebb0cdSNamhyung Kim count_dummy++; 362*f8ebb0cdSNamhyung Kim } 363*f8ebb0cdSNamhyung Kim count_pair++; 364*f8ebb0cdSNamhyung Kim } else if (idx) { 365*f8ebb0cdSNamhyung Kim pr_debug("A entry from the other hists should have pair\n"); 366*f8ebb0cdSNamhyung Kim return -1; 367*f8ebb0cdSNamhyung Kim } 368*f8ebb0cdSNamhyung Kim 369*f8ebb0cdSNamhyung Kim count++; 370*f8ebb0cdSNamhyung Kim node = rb_next(node); 371*f8ebb0cdSNamhyung Kim } 372*f8ebb0cdSNamhyung Kim 373*f8ebb0cdSNamhyung Kim /* 374*f8ebb0cdSNamhyung Kim * Note that we have a entry collapsed in the other (idx = 1) hists. 375*f8ebb0cdSNamhyung Kim */ 376*f8ebb0cdSNamhyung Kim if (idx == 0) { 377*f8ebb0cdSNamhyung Kim if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) { 378*f8ebb0cdSNamhyung Kim pr_debug("Invalid count of dummy entries: %zd of %zd\n", 379*f8ebb0cdSNamhyung Kim count_dummy, ARRAY_SIZE(fake_samples[1]) - 1); 380*f8ebb0cdSNamhyung Kim return -1; 381*f8ebb0cdSNamhyung Kim } 382*f8ebb0cdSNamhyung Kim if (count != count_pair + ARRAY_SIZE(fake_samples[0])) { 383*f8ebb0cdSNamhyung Kim pr_debug("Invalid count of total leader entries: %zd of %zd\n", 384*f8ebb0cdSNamhyung Kim count, count_pair + ARRAY_SIZE(fake_samples[0])); 385*f8ebb0cdSNamhyung Kim return -1; 386*f8ebb0cdSNamhyung Kim } 387*f8ebb0cdSNamhyung Kim } else { 388*f8ebb0cdSNamhyung Kim if (count != count_pair) { 389*f8ebb0cdSNamhyung Kim pr_debug("Invalid count of total other entries: %zd of %zd\n", 390*f8ebb0cdSNamhyung Kim count, count_pair); 391*f8ebb0cdSNamhyung Kim return -1; 392*f8ebb0cdSNamhyung Kim } 393*f8ebb0cdSNamhyung Kim if (count_dummy > 0) { 394*f8ebb0cdSNamhyung Kim pr_debug("Other hists should not have dummy entries: %zd\n", 395*f8ebb0cdSNamhyung Kim count_dummy); 396*f8ebb0cdSNamhyung Kim return -1; 397*f8ebb0cdSNamhyung Kim } 398*f8ebb0cdSNamhyung Kim } 399*f8ebb0cdSNamhyung Kim 400*f8ebb0cdSNamhyung Kim return 0; 401*f8ebb0cdSNamhyung Kim } 402*f8ebb0cdSNamhyung Kim 403*f8ebb0cdSNamhyung Kim static int validate_link(struct hists *leader, struct hists *other) 404*f8ebb0cdSNamhyung Kim { 405*f8ebb0cdSNamhyung Kim return __validate_link(leader, 0) || __validate_link(other, 1); 406*f8ebb0cdSNamhyung Kim } 407*f8ebb0cdSNamhyung Kim 408*f8ebb0cdSNamhyung Kim static void print_hists(struct hists *hists) 409*f8ebb0cdSNamhyung Kim { 410*f8ebb0cdSNamhyung Kim int i = 0; 411*f8ebb0cdSNamhyung Kim struct rb_root *root; 412*f8ebb0cdSNamhyung Kim struct rb_node *node; 413*f8ebb0cdSNamhyung Kim 414*f8ebb0cdSNamhyung Kim if (sort__need_collapse) 415*f8ebb0cdSNamhyung Kim root = &hists->entries_collapsed; 416*f8ebb0cdSNamhyung Kim else 417*f8ebb0cdSNamhyung Kim root = hists->entries_in; 418*f8ebb0cdSNamhyung Kim 419*f8ebb0cdSNamhyung Kim pr_info("----- %s --------\n", __func__); 420*f8ebb0cdSNamhyung Kim node = rb_first(root); 421*f8ebb0cdSNamhyung Kim while (node) { 422*f8ebb0cdSNamhyung Kim struct hist_entry *he; 423*f8ebb0cdSNamhyung Kim 424*f8ebb0cdSNamhyung Kim he = rb_entry(node, struct hist_entry, rb_node_in); 425*f8ebb0cdSNamhyung Kim 426*f8ebb0cdSNamhyung Kim pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", 427*f8ebb0cdSNamhyung Kim i, he->thread->comm, he->ms.map->dso->short_name, 428*f8ebb0cdSNamhyung Kim he->ms.sym->name, he->stat.period); 429*f8ebb0cdSNamhyung Kim 430*f8ebb0cdSNamhyung Kim i++; 431*f8ebb0cdSNamhyung Kim node = rb_next(node); 432*f8ebb0cdSNamhyung Kim } 433*f8ebb0cdSNamhyung Kim } 434*f8ebb0cdSNamhyung Kim 435*f8ebb0cdSNamhyung Kim int test__hists_link(void) 436*f8ebb0cdSNamhyung Kim { 437*f8ebb0cdSNamhyung Kim int err = -1; 438*f8ebb0cdSNamhyung Kim struct machine *machine = NULL; 439*f8ebb0cdSNamhyung Kim struct perf_evsel *evsel, *first; 440*f8ebb0cdSNamhyung Kim struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 441*f8ebb0cdSNamhyung Kim 442*f8ebb0cdSNamhyung Kim if (evlist == NULL) 443*f8ebb0cdSNamhyung Kim return -ENOMEM; 444*f8ebb0cdSNamhyung Kim 445*f8ebb0cdSNamhyung Kim err = parse_events(evlist, "cpu-clock", 0); 446*f8ebb0cdSNamhyung Kim if (err) 447*f8ebb0cdSNamhyung Kim goto out; 448*f8ebb0cdSNamhyung Kim err = parse_events(evlist, "task-clock", 0); 449*f8ebb0cdSNamhyung Kim if (err) 450*f8ebb0cdSNamhyung Kim goto out; 451*f8ebb0cdSNamhyung Kim 452*f8ebb0cdSNamhyung Kim /* default sort order (comm,dso,sym) will be used */ 453*f8ebb0cdSNamhyung Kim setup_sorting(NULL, NULL); 454*f8ebb0cdSNamhyung Kim 455*f8ebb0cdSNamhyung Kim /* setup threads/dso/map/symbols also */ 456*f8ebb0cdSNamhyung Kim machine = setup_fake_machine(); 457*f8ebb0cdSNamhyung Kim if (!machine) 458*f8ebb0cdSNamhyung Kim goto out; 459*f8ebb0cdSNamhyung Kim 460*f8ebb0cdSNamhyung Kim if (verbose > 1) 461*f8ebb0cdSNamhyung Kim machine__fprintf(machine, stderr); 462*f8ebb0cdSNamhyung Kim 463*f8ebb0cdSNamhyung Kim /* process sample events */ 464*f8ebb0cdSNamhyung Kim err = add_hist_entries(evlist, machine); 465*f8ebb0cdSNamhyung Kim if (err < 0) 466*f8ebb0cdSNamhyung Kim goto out; 467*f8ebb0cdSNamhyung Kim 468*f8ebb0cdSNamhyung Kim list_for_each_entry(evsel, &evlist->entries, node) { 469*f8ebb0cdSNamhyung Kim hists__collapse_resort(&evsel->hists); 470*f8ebb0cdSNamhyung Kim 471*f8ebb0cdSNamhyung Kim if (verbose > 2) 472*f8ebb0cdSNamhyung Kim print_hists(&evsel->hists); 473*f8ebb0cdSNamhyung Kim } 474*f8ebb0cdSNamhyung Kim 475*f8ebb0cdSNamhyung Kim first = perf_evlist__first(evlist); 476*f8ebb0cdSNamhyung Kim evsel = perf_evlist__last(evlist); 477*f8ebb0cdSNamhyung Kim 478*f8ebb0cdSNamhyung Kim /* match common entries */ 479*f8ebb0cdSNamhyung Kim hists__match(&first->hists, &evsel->hists); 480*f8ebb0cdSNamhyung Kim err = validate_match(&first->hists, &evsel->hists); 481*f8ebb0cdSNamhyung Kim if (err) 482*f8ebb0cdSNamhyung Kim goto out; 483*f8ebb0cdSNamhyung Kim 484*f8ebb0cdSNamhyung Kim /* link common and/or dummy entries */ 485*f8ebb0cdSNamhyung Kim hists__link(&first->hists, &evsel->hists); 486*f8ebb0cdSNamhyung Kim err = validate_link(&first->hists, &evsel->hists); 487*f8ebb0cdSNamhyung Kim if (err) 488*f8ebb0cdSNamhyung Kim goto out; 489*f8ebb0cdSNamhyung Kim 490*f8ebb0cdSNamhyung Kim err = 0; 491*f8ebb0cdSNamhyung Kim 492*f8ebb0cdSNamhyung Kim out: 493*f8ebb0cdSNamhyung Kim /* tear down everything */ 494*f8ebb0cdSNamhyung Kim perf_evlist__delete(evlist); 495*f8ebb0cdSNamhyung Kim 496*f8ebb0cdSNamhyung Kim if (machine) { 497*f8ebb0cdSNamhyung Kim machine__delete_threads(machine); 498*f8ebb0cdSNamhyung Kim machine__delete(machine); 499*f8ebb0cdSNamhyung Kim } 500*f8ebb0cdSNamhyung Kim 501*f8ebb0cdSNamhyung Kim return err; 502*f8ebb0cdSNamhyung Kim } 503