18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include "tests.h" 38c2ecf20Sopenharmony_ci#include "debug.h" 48c2ecf20Sopenharmony_ci#include "symbol.h" 58c2ecf20Sopenharmony_ci#include "sort.h" 68c2ecf20Sopenharmony_ci#include "evsel.h" 78c2ecf20Sopenharmony_ci#include "evlist.h" 88c2ecf20Sopenharmony_ci#include "machine.h" 98c2ecf20Sopenharmony_ci#include "parse-events.h" 108c2ecf20Sopenharmony_ci#include "hists_common.h" 118c2ecf20Sopenharmony_ci#include "util/mmap.h" 128c2ecf20Sopenharmony_ci#include <errno.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct sample { 168c2ecf20Sopenharmony_ci u32 pid; 178c2ecf20Sopenharmony_ci u64 ip; 188c2ecf20Sopenharmony_ci struct thread *thread; 198c2ecf20Sopenharmony_ci struct map *map; 208c2ecf20Sopenharmony_ci struct symbol *sym; 218c2ecf20Sopenharmony_ci}; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* For the numbers, see hists_common.c */ 248c2ecf20Sopenharmony_cistatic struct sample fake_common_samples[] = { 258c2ecf20Sopenharmony_ci /* perf [kernel] schedule() */ 268c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, }, 278c2ecf20Sopenharmony_ci /* perf [perf] main() */ 288c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, }, 298c2ecf20Sopenharmony_ci /* perf [perf] cmd_record() */ 308c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, }, 318c2ecf20Sopenharmony_ci /* bash [bash] xmalloc() */ 328c2ecf20Sopenharmony_ci { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, }, 338c2ecf20Sopenharmony_ci /* bash [libc] malloc() */ 348c2ecf20Sopenharmony_ci { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, }, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct sample fake_samples[][5] = { 388c2ecf20Sopenharmony_ci { 398c2ecf20Sopenharmony_ci /* perf [perf] run_command() */ 408c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_RUN_COMMAND, }, 418c2ecf20Sopenharmony_ci /* perf [libc] malloc() */ 428c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, }, 438c2ecf20Sopenharmony_ci /* perf [kernel] page_fault() */ 448c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_PAGE_FAULT, }, 458c2ecf20Sopenharmony_ci /* perf [kernel] sys_perf_event_open() */ 468c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN, }, 478c2ecf20Sopenharmony_ci /* bash [libc] free() */ 488c2ecf20Sopenharmony_ci { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_FREE, }, 498c2ecf20Sopenharmony_ci }, 508c2ecf20Sopenharmony_ci { 518c2ecf20Sopenharmony_ci /* perf [libc] free() */ 528c2ecf20Sopenharmony_ci { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_LIBC_FREE, }, 538c2ecf20Sopenharmony_ci /* bash [libc] malloc() */ 548c2ecf20Sopenharmony_ci { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, }, /* will be merged */ 558c2ecf20Sopenharmony_ci /* bash [bash] xfee() */ 568c2ecf20Sopenharmony_ci { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XFREE, }, 578c2ecf20Sopenharmony_ci /* bash [libc] realloc() */ 588c2ecf20Sopenharmony_ci { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_REALLOC, }, 598c2ecf20Sopenharmony_ci /* bash [kernel] page_fault() */ 608c2ecf20Sopenharmony_ci { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, }, 618c2ecf20Sopenharmony_ci }, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int add_hist_entries(struct evlist *evlist, struct machine *machine) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct evsel *evsel; 678c2ecf20Sopenharmony_ci struct addr_location al; 688c2ecf20Sopenharmony_ci struct hist_entry *he; 698c2ecf20Sopenharmony_ci struct perf_sample sample = { .period = 1, .weight = 1, }; 708c2ecf20Sopenharmony_ci size_t i = 0, k; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* 738c2ecf20Sopenharmony_ci * each evsel will have 10 samples - 5 common and 5 distinct. 748c2ecf20Sopenharmony_ci * However the second evsel also has a collapsed entry for 758c2ecf20Sopenharmony_ci * "bash [libc] malloc" so total 9 entries will be in the tree. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 788c2ecf20Sopenharmony_ci struct hists *hists = evsel__hists(evsel); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 818c2ecf20Sopenharmony_ci sample.cpumode = PERF_RECORD_MISC_USER; 828c2ecf20Sopenharmony_ci sample.pid = fake_common_samples[k].pid; 838c2ecf20Sopenharmony_ci sample.tid = fake_common_samples[k].pid; 848c2ecf20Sopenharmony_ci sample.ip = fake_common_samples[k].ip; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (machine__resolve(machine, &al, &sample) < 0) 878c2ecf20Sopenharmony_ci goto out; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci he = hists__add_entry(hists, &al, NULL, 908c2ecf20Sopenharmony_ci NULL, NULL, &sample, true); 918c2ecf20Sopenharmony_ci if (he == NULL) { 928c2ecf20Sopenharmony_ci addr_location__put(&al); 938c2ecf20Sopenharmony_ci goto out; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci fake_common_samples[k].thread = al.thread; 978c2ecf20Sopenharmony_ci fake_common_samples[k].map = al.map; 988c2ecf20Sopenharmony_ci fake_common_samples[k].sym = al.sym; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { 1028c2ecf20Sopenharmony_ci sample.pid = fake_samples[i][k].pid; 1038c2ecf20Sopenharmony_ci sample.tid = fake_samples[i][k].pid; 1048c2ecf20Sopenharmony_ci sample.ip = fake_samples[i][k].ip; 1058c2ecf20Sopenharmony_ci if (machine__resolve(machine, &al, &sample) < 0) 1068c2ecf20Sopenharmony_ci goto out; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci he = hists__add_entry(hists, &al, NULL, 1098c2ecf20Sopenharmony_ci NULL, NULL, &sample, true); 1108c2ecf20Sopenharmony_ci if (he == NULL) { 1118c2ecf20Sopenharmony_ci addr_location__put(&al); 1128c2ecf20Sopenharmony_ci goto out; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci fake_samples[i][k].thread = al.thread; 1168c2ecf20Sopenharmony_ci fake_samples[i][k].map = al.map; 1178c2ecf20Sopenharmony_ci fake_samples[i][k].sym = al.sym; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci i++; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ciout: 1258c2ecf20Sopenharmony_ci pr_debug("Not enough memory for adding a hist entry\n"); 1268c2ecf20Sopenharmony_ci return -1; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int find_sample(struct sample *samples, size_t nr_samples, 1308c2ecf20Sopenharmony_ci struct thread *t, struct map *m, struct symbol *s) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci while (nr_samples--) { 1338c2ecf20Sopenharmony_ci if (samples->thread == t && samples->map == m && 1348c2ecf20Sopenharmony_ci samples->sym == s) 1358c2ecf20Sopenharmony_ci return 1; 1368c2ecf20Sopenharmony_ci samples++; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int __validate_match(struct hists *hists) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci size_t count = 0; 1448c2ecf20Sopenharmony_ci struct rb_root_cached *root; 1458c2ecf20Sopenharmony_ci struct rb_node *node; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* 1488c2ecf20Sopenharmony_ci * Only entries from fake_common_samples should have a pair. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci if (hists__has(hists, need_collapse)) 1518c2ecf20Sopenharmony_ci root = &hists->entries_collapsed; 1528c2ecf20Sopenharmony_ci else 1538c2ecf20Sopenharmony_ci root = hists->entries_in; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci node = rb_first_cached(root); 1568c2ecf20Sopenharmony_ci while (node) { 1578c2ecf20Sopenharmony_ci struct hist_entry *he; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci he = rb_entry(node, struct hist_entry, rb_node_in); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (hist_entry__has_pairs(he)) { 1628c2ecf20Sopenharmony_ci if (find_sample(fake_common_samples, 1638c2ecf20Sopenharmony_ci ARRAY_SIZE(fake_common_samples), 1648c2ecf20Sopenharmony_ci he->thread, he->ms.map, he->ms.sym)) { 1658c2ecf20Sopenharmony_ci count++; 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci pr_debug("Can't find the matched entry\n"); 1688c2ecf20Sopenharmony_ci return -1; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci node = rb_next(node); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (count != ARRAY_SIZE(fake_common_samples)) { 1768c2ecf20Sopenharmony_ci pr_debug("Invalid count for matched entries: %zd of %zd\n", 1778c2ecf20Sopenharmony_ci count, ARRAY_SIZE(fake_common_samples)); 1788c2ecf20Sopenharmony_ci return -1; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int validate_match(struct hists *leader, struct hists *other) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return __validate_match(leader) || __validate_match(other); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int __validate_link(struct hists *hists, int idx) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci size_t count = 0; 1928c2ecf20Sopenharmony_ci size_t count_pair = 0; 1938c2ecf20Sopenharmony_ci size_t count_dummy = 0; 1948c2ecf20Sopenharmony_ci struct rb_root_cached *root; 1958c2ecf20Sopenharmony_ci struct rb_node *node; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * Leader hists (idx = 0) will have dummy entries from other, 1998c2ecf20Sopenharmony_ci * and some entries will have no pair. However every entry 2008c2ecf20Sopenharmony_ci * in other hists should have (dummy) pair. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci if (hists__has(hists, need_collapse)) 2038c2ecf20Sopenharmony_ci root = &hists->entries_collapsed; 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci root = hists->entries_in; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci node = rb_first_cached(root); 2088c2ecf20Sopenharmony_ci while (node) { 2098c2ecf20Sopenharmony_ci struct hist_entry *he; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci he = rb_entry(node, struct hist_entry, rb_node_in); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (hist_entry__has_pairs(he)) { 2148c2ecf20Sopenharmony_ci if (!find_sample(fake_common_samples, 2158c2ecf20Sopenharmony_ci ARRAY_SIZE(fake_common_samples), 2168c2ecf20Sopenharmony_ci he->thread, he->ms.map, he->ms.sym) && 2178c2ecf20Sopenharmony_ci !find_sample(fake_samples[idx], 2188c2ecf20Sopenharmony_ci ARRAY_SIZE(fake_samples[idx]), 2198c2ecf20Sopenharmony_ci he->thread, he->ms.map, he->ms.sym)) { 2208c2ecf20Sopenharmony_ci count_dummy++; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci count_pair++; 2238c2ecf20Sopenharmony_ci } else if (idx) { 2248c2ecf20Sopenharmony_ci pr_debug("A entry from the other hists should have pair\n"); 2258c2ecf20Sopenharmony_ci return -1; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci count++; 2298c2ecf20Sopenharmony_ci node = rb_next(node); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * Note that we have a entry collapsed in the other (idx = 1) hists. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci if (idx == 0) { 2368c2ecf20Sopenharmony_ci if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) { 2378c2ecf20Sopenharmony_ci pr_debug("Invalid count of dummy entries: %zd of %zd\n", 2388c2ecf20Sopenharmony_ci count_dummy, ARRAY_SIZE(fake_samples[1]) - 1); 2398c2ecf20Sopenharmony_ci return -1; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci if (count != count_pair + ARRAY_SIZE(fake_samples[0])) { 2428c2ecf20Sopenharmony_ci pr_debug("Invalid count of total leader entries: %zd of %zd\n", 2438c2ecf20Sopenharmony_ci count, count_pair + ARRAY_SIZE(fake_samples[0])); 2448c2ecf20Sopenharmony_ci return -1; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci } else { 2478c2ecf20Sopenharmony_ci if (count != count_pair) { 2488c2ecf20Sopenharmony_ci pr_debug("Invalid count of total other entries: %zd of %zd\n", 2498c2ecf20Sopenharmony_ci count, count_pair); 2508c2ecf20Sopenharmony_ci return -1; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci if (count_dummy > 0) { 2538c2ecf20Sopenharmony_ci pr_debug("Other hists should not have dummy entries: %zd\n", 2548c2ecf20Sopenharmony_ci count_dummy); 2558c2ecf20Sopenharmony_ci return -1; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int validate_link(struct hists *leader, struct hists *other) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci return __validate_link(leader, 0) || __validate_link(other, 1); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ciint test__hists_link(struct test *test __maybe_unused, int subtest __maybe_unused) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci int err = -1; 2708c2ecf20Sopenharmony_ci struct hists *hists, *first_hists; 2718c2ecf20Sopenharmony_ci struct machines machines; 2728c2ecf20Sopenharmony_ci struct machine *machine = NULL; 2738c2ecf20Sopenharmony_ci struct evsel *evsel, *first; 2748c2ecf20Sopenharmony_ci struct evlist *evlist = evlist__new(); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (evlist == NULL) 2778c2ecf20Sopenharmony_ci return -ENOMEM; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci err = parse_events(evlist, "cpu-clock", NULL); 2808c2ecf20Sopenharmony_ci if (err) 2818c2ecf20Sopenharmony_ci goto out; 2828c2ecf20Sopenharmony_ci err = parse_events(evlist, "task-clock", NULL); 2838c2ecf20Sopenharmony_ci if (err) 2848c2ecf20Sopenharmony_ci goto out; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci err = TEST_FAIL; 2878c2ecf20Sopenharmony_ci /* default sort order (comm,dso,sym) will be used */ 2888c2ecf20Sopenharmony_ci if (setup_sorting(NULL) < 0) 2898c2ecf20Sopenharmony_ci goto out; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci machines__init(&machines); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* setup threads/dso/map/symbols also */ 2948c2ecf20Sopenharmony_ci machine = setup_fake_machine(&machines); 2958c2ecf20Sopenharmony_ci if (!machine) 2968c2ecf20Sopenharmony_ci goto out; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (verbose > 1) 2998c2ecf20Sopenharmony_ci machine__fprintf(machine, stderr); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* process sample events */ 3028c2ecf20Sopenharmony_ci err = add_hist_entries(evlist, machine); 3038c2ecf20Sopenharmony_ci if (err < 0) 3048c2ecf20Sopenharmony_ci goto out; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 3078c2ecf20Sopenharmony_ci hists = evsel__hists(evsel); 3088c2ecf20Sopenharmony_ci hists__collapse_resort(hists, NULL); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (verbose > 2) 3118c2ecf20Sopenharmony_ci print_hists_in(hists); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci first = evlist__first(evlist); 3158c2ecf20Sopenharmony_ci evsel = evlist__last(evlist); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci first_hists = evsel__hists(first); 3188c2ecf20Sopenharmony_ci hists = evsel__hists(evsel); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* match common entries */ 3218c2ecf20Sopenharmony_ci hists__match(first_hists, hists); 3228c2ecf20Sopenharmony_ci err = validate_match(first_hists, hists); 3238c2ecf20Sopenharmony_ci if (err) 3248c2ecf20Sopenharmony_ci goto out; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* link common and/or dummy entries */ 3278c2ecf20Sopenharmony_ci hists__link(first_hists, hists); 3288c2ecf20Sopenharmony_ci err = validate_link(first_hists, hists); 3298c2ecf20Sopenharmony_ci if (err) 3308c2ecf20Sopenharmony_ci goto out; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci err = 0; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciout: 3358c2ecf20Sopenharmony_ci /* tear down everything */ 3368c2ecf20Sopenharmony_ci evlist__delete(evlist); 3378c2ecf20Sopenharmony_ci reset_output_field(); 3388c2ecf20Sopenharmony_ci machines__exit(&machines); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return err; 3418c2ecf20Sopenharmony_ci} 342