cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hists_cumulate.c (20943B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include "util/debug.h"
      3#include "util/dso.h"
      4#include "util/event.h"
      5#include "util/map.h"
      6#include "util/symbol.h"
      7#include "util/sort.h"
      8#include "util/evsel.h"
      9#include "util/evlist.h"
     10#include "util/machine.h"
     11#include "util/thread.h"
     12#include "util/parse-events.h"
     13#include "tests/tests.h"
     14#include "tests/hists_common.h"
     15#include <linux/kernel.h>
     16
     17struct sample {
     18	u32 pid;
     19	u64 ip;
     20	struct thread *thread;
     21	struct map *map;
     22	struct symbol *sym;
     23};
     24
     25/* For the numbers, see hists_common.c */
     26static struct sample fake_samples[] = {
     27	/* perf [kernel] schedule() */
     28	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
     29	/* perf [perf]   main() */
     30	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
     31	/* perf [perf]   cmd_record() */
     32	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
     33	/* perf [libc]   malloc() */
     34	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
     35	/* perf [libc]   free() */
     36	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
     37	/* perf [perf]   main() */
     38	{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
     39	/* perf [kernel] page_fault() */
     40	{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
     41	/* bash [bash]   main() */
     42	{ .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_MAIN, },
     43	/* bash [bash]   xmalloc() */
     44	{ .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_XMALLOC, },
     45	/* bash [kernel] page_fault() */
     46	{ .pid = FAKE_PID_BASH,  .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
     47};
     48
     49/*
     50 * Will be cast to struct ip_callchain which has all 64 bit entries
     51 * of nr and ips[].
     52 */
     53static u64 fake_callchains[][10] = {
     54	/*   schedule => run_command => main */
     55	{ 3, FAKE_IP_KERNEL_SCHEDULE, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
     56	/*   main  */
     57	{ 1, FAKE_IP_PERF_MAIN, },
     58	/*   cmd_record => run_command => main */
     59	{ 3, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
     60	/*   malloc => cmd_record => run_command => main */
     61	{ 4, FAKE_IP_LIBC_MALLOC, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
     62	     FAKE_IP_PERF_MAIN, },
     63	/*   free => cmd_record => run_command => main */
     64	{ 4, FAKE_IP_LIBC_FREE, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
     65	     FAKE_IP_PERF_MAIN, },
     66	/*   main */
     67	{ 1, FAKE_IP_PERF_MAIN, },
     68	/*   page_fault => sys_perf_event_open => run_command => main */
     69	{ 4, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN,
     70	     FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
     71	/*   main */
     72	{ 1, FAKE_IP_BASH_MAIN, },
     73	/*   xmalloc => malloc => xmalloc => malloc => xmalloc => main */
     74	{ 6, FAKE_IP_BASH_XMALLOC, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC,
     75	     FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC, FAKE_IP_BASH_MAIN, },
     76	/*   page_fault => malloc => main */
     77	{ 3, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_MAIN, },
     78};
     79
     80static int add_hist_entries(struct hists *hists, struct machine *machine)
     81{
     82	struct addr_location al;
     83	struct evsel *evsel = hists_to_evsel(hists);
     84	struct perf_sample sample = { .period = 1000, };
     85	size_t i;
     86
     87	for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
     88		struct hist_entry_iter iter = {
     89			.evsel = evsel,
     90			.sample	= &sample,
     91			.hide_unresolved = false,
     92		};
     93
     94		if (symbol_conf.cumulate_callchain)
     95			iter.ops = &hist_iter_cumulative;
     96		else
     97			iter.ops = &hist_iter_normal;
     98
     99		sample.cpumode = PERF_RECORD_MISC_USER;
    100		sample.pid = fake_samples[i].pid;
    101		sample.tid = fake_samples[i].pid;
    102		sample.ip = fake_samples[i].ip;
    103		sample.callchain = (struct ip_callchain *)fake_callchains[i];
    104
    105		if (machine__resolve(machine, &al, &sample) < 0)
    106			goto out;
    107
    108		if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
    109					 NULL) < 0) {
    110			addr_location__put(&al);
    111			goto out;
    112		}
    113
    114		fake_samples[i].thread = al.thread;
    115		fake_samples[i].map = al.map;
    116		fake_samples[i].sym = al.sym;
    117	}
    118
    119	return TEST_OK;
    120
    121out:
    122	pr_debug("Not enough memory for adding a hist entry\n");
    123	return TEST_FAIL;
    124}
    125
    126static void del_hist_entries(struct hists *hists)
    127{
    128	struct hist_entry *he;
    129	struct rb_root_cached *root_in;
    130	struct rb_root_cached *root_out;
    131	struct rb_node *node;
    132
    133	if (hists__has(hists, need_collapse))
    134		root_in = &hists->entries_collapsed;
    135	else
    136		root_in = hists->entries_in;
    137
    138	root_out = &hists->entries;
    139
    140	while (!RB_EMPTY_ROOT(&root_out->rb_root)) {
    141		node = rb_first_cached(root_out);
    142
    143		he = rb_entry(node, struct hist_entry, rb_node);
    144		rb_erase_cached(node, root_out);
    145		rb_erase_cached(&he->rb_node_in, root_in);
    146		hist_entry__delete(he);
    147	}
    148}
    149
    150typedef int (*test_fn_t)(struct evsel *, struct machine *);
    151
    152#define COMM(he)  (thread__comm_str(he->thread))
    153#define DSO(he)   (he->ms.map->dso->short_name)
    154#define SYM(he)   (he->ms.sym->name)
    155#define CPU(he)   (he->cpu)
    156#define PID(he)   (he->thread->tid)
    157#define DEPTH(he) (he->callchain->max_depth)
    158#define CDSO(cl)  (cl->ms.map->dso->short_name)
    159#define CSYM(cl)  (cl->ms.sym->name)
    160
    161struct result {
    162	u64 children;
    163	u64 self;
    164	const char *comm;
    165	const char *dso;
    166	const char *sym;
    167};
    168
    169struct callchain_result {
    170	u64 nr;
    171	struct {
    172		const char *dso;
    173		const char *sym;
    174	} node[10];
    175};
    176
    177static int do_test(struct hists *hists, struct result *expected, size_t nr_expected,
    178		   struct callchain_result *expected_callchain, size_t nr_callchain)
    179{
    180	char buf[32];
    181	size_t i, c;
    182	struct hist_entry *he;
    183	struct rb_root *root;
    184	struct rb_node *node;
    185	struct callchain_node *cnode;
    186	struct callchain_list *clist;
    187
    188	/*
    189	 * adding and deleting hist entries must be done outside of this
    190	 * function since TEST_ASSERT_VAL() returns in case of failure.
    191	 */
    192	hists__collapse_resort(hists, NULL);
    193	evsel__output_resort(hists_to_evsel(hists), NULL);
    194
    195	if (verbose > 2) {
    196		pr_info("use callchain: %d, cumulate callchain: %d\n",
    197			symbol_conf.use_callchain,
    198			symbol_conf.cumulate_callchain);
    199		print_hists_out(hists);
    200	}
    201
    202	root = &hists->entries.rb_root;
    203	for (node = rb_first(root), i = 0;
    204	     node && (he = rb_entry(node, struct hist_entry, rb_node));
    205	     node = rb_next(node), i++) {
    206		scnprintf(buf, sizeof(buf), "Invalid hist entry #%zd", i);
    207
    208		TEST_ASSERT_VAL("Incorrect number of hist entry",
    209				i < nr_expected);
    210		TEST_ASSERT_VAL(buf, he->stat.period == expected[i].self &&
    211				!strcmp(COMM(he), expected[i].comm) &&
    212				!strcmp(DSO(he), expected[i].dso) &&
    213				!strcmp(SYM(he), expected[i].sym));
    214
    215		if (symbol_conf.cumulate_callchain)
    216			TEST_ASSERT_VAL(buf, he->stat_acc->period == expected[i].children);
    217
    218		if (!symbol_conf.use_callchain)
    219			continue;
    220
    221		/* check callchain entries */
    222		root = &he->callchain->node.rb_root;
    223
    224		TEST_ASSERT_VAL("callchains expected", !RB_EMPTY_ROOT(root));
    225		cnode = rb_entry(rb_first(root), struct callchain_node, rb_node);
    226
    227		c = 0;
    228		list_for_each_entry(clist, &cnode->val, list) {
    229			scnprintf(buf, sizeof(buf), "Invalid callchain entry #%zd/%zd", i, c);
    230
    231			TEST_ASSERT_VAL("Incorrect number of callchain entry",
    232					c < expected_callchain[i].nr);
    233			TEST_ASSERT_VAL(buf,
    234				!strcmp(CDSO(clist), expected_callchain[i].node[c].dso) &&
    235				!strcmp(CSYM(clist), expected_callchain[i].node[c].sym));
    236			c++;
    237		}
    238		/* TODO: handle multiple child nodes properly */
    239		TEST_ASSERT_VAL("Incorrect number of callchain entry",
    240				c <= expected_callchain[i].nr);
    241	}
    242	TEST_ASSERT_VAL("Incorrect number of hist entry",
    243			i == nr_expected);
    244	TEST_ASSERT_VAL("Incorrect number of callchain entry",
    245			!symbol_conf.use_callchain || nr_expected == nr_callchain);
    246	return 0;
    247}
    248
    249/* NO callchain + NO children */
    250static int test1(struct evsel *evsel, struct machine *machine)
    251{
    252	int err;
    253	struct hists *hists = evsel__hists(evsel);
    254	/*
    255	 * expected output:
    256	 *
    257	 * Overhead  Command  Shared Object          Symbol
    258	 * ========  =======  =============  ==============
    259	 *   20.00%     perf  perf           [.] main
    260	 *   10.00%     bash  [kernel]       [k] page_fault
    261	 *   10.00%     bash  bash           [.] main
    262	 *   10.00%     bash  bash           [.] xmalloc
    263	 *   10.00%     perf  [kernel]       [k] page_fault
    264	 *   10.00%     perf  [kernel]       [k] schedule
    265	 *   10.00%     perf  libc           [.] free
    266	 *   10.00%     perf  libc           [.] malloc
    267	 *   10.00%     perf  perf           [.] cmd_record
    268	 */
    269	struct result expected[] = {
    270		{ 0, 2000, "perf", "perf",     "main" },
    271		{ 0, 1000, "bash", "[kernel]", "page_fault" },
    272		{ 0, 1000, "bash", "bash",     "main" },
    273		{ 0, 1000, "bash", "bash",     "xmalloc" },
    274		{ 0, 1000, "perf", "[kernel]", "page_fault" },
    275		{ 0, 1000, "perf", "[kernel]", "schedule" },
    276		{ 0, 1000, "perf", "libc",     "free" },
    277		{ 0, 1000, "perf", "libc",     "malloc" },
    278		{ 0, 1000, "perf", "perf",     "cmd_record" },
    279	};
    280
    281	symbol_conf.use_callchain = false;
    282	symbol_conf.cumulate_callchain = false;
    283	evsel__reset_sample_bit(evsel, CALLCHAIN);
    284
    285	setup_sorting(NULL);
    286	callchain_register_param(&callchain_param);
    287
    288	err = add_hist_entries(hists, machine);
    289	if (err < 0)
    290		goto out;
    291
    292	err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
    293
    294out:
    295	del_hist_entries(hists);
    296	reset_output_field();
    297	return err;
    298}
    299
    300/* callchain + NO children */
    301static int test2(struct evsel *evsel, struct machine *machine)
    302{
    303	int err;
    304	struct hists *hists = evsel__hists(evsel);
    305	/*
    306	 * expected output:
    307	 *
    308	 * Overhead  Command  Shared Object          Symbol
    309	 * ========  =======  =============  ==============
    310	 *   20.00%     perf  perf           [.] main
    311	 *              |
    312	 *              --- main
    313	 *
    314	 *   10.00%     bash  [kernel]       [k] page_fault
    315	 *              |
    316	 *              --- page_fault
    317	 *                  malloc
    318	 *                  main
    319	 *
    320	 *   10.00%     bash  bash           [.] main
    321	 *              |
    322	 *              --- main
    323	 *
    324	 *   10.00%     bash  bash           [.] xmalloc
    325	 *              |
    326	 *              --- xmalloc
    327	 *                  malloc
    328	 *                  xmalloc     <--- NOTE: there's a cycle
    329	 *                  malloc
    330	 *                  xmalloc
    331	 *                  main
    332	 *
    333	 *   10.00%     perf  [kernel]       [k] page_fault
    334	 *              |
    335	 *              --- page_fault
    336	 *                  sys_perf_event_open
    337	 *                  run_command
    338	 *                  main
    339	 *
    340	 *   10.00%     perf  [kernel]       [k] schedule
    341	 *              |
    342	 *              --- schedule
    343	 *                  run_command
    344	 *                  main
    345	 *
    346	 *   10.00%     perf  libc           [.] free
    347	 *              |
    348	 *              --- free
    349	 *                  cmd_record
    350	 *                  run_command
    351	 *                  main
    352	 *
    353	 *   10.00%     perf  libc           [.] malloc
    354	 *              |
    355	 *              --- malloc
    356	 *                  cmd_record
    357	 *                  run_command
    358	 *                  main
    359	 *
    360	 *   10.00%     perf  perf           [.] cmd_record
    361	 *              |
    362	 *              --- cmd_record
    363	 *                  run_command
    364	 *                  main
    365	 *
    366	 */
    367	struct result expected[] = {
    368		{ 0, 2000, "perf", "perf",     "main" },
    369		{ 0, 1000, "bash", "[kernel]", "page_fault" },
    370		{ 0, 1000, "bash", "bash",     "main" },
    371		{ 0, 1000, "bash", "bash",     "xmalloc" },
    372		{ 0, 1000, "perf", "[kernel]", "page_fault" },
    373		{ 0, 1000, "perf", "[kernel]", "schedule" },
    374		{ 0, 1000, "perf", "libc",     "free" },
    375		{ 0, 1000, "perf", "libc",     "malloc" },
    376		{ 0, 1000, "perf", "perf",     "cmd_record" },
    377	};
    378	struct callchain_result expected_callchain[] = {
    379		{
    380			1, {	{ "perf",     "main" }, },
    381		},
    382		{
    383			3, {	{ "[kernel]", "page_fault" },
    384				{ "libc",     "malloc" },
    385				{ "bash",     "main" }, },
    386		},
    387		{
    388			1, {	{ "bash",     "main" }, },
    389		},
    390		{
    391			6, {	{ "bash",     "xmalloc" },
    392				{ "libc",     "malloc" },
    393				{ "bash",     "xmalloc" },
    394				{ "libc",     "malloc" },
    395				{ "bash",     "xmalloc" },
    396				{ "bash",     "main" }, },
    397		},
    398		{
    399			4, {	{ "[kernel]", "page_fault" },
    400				{ "[kernel]", "sys_perf_event_open" },
    401				{ "perf",     "run_command" },
    402				{ "perf",     "main" }, },
    403		},
    404		{
    405			3, {	{ "[kernel]", "schedule" },
    406				{ "perf",     "run_command" },
    407				{ "perf",     "main" }, },
    408		},
    409		{
    410			4, {	{ "libc",     "free" },
    411				{ "perf",     "cmd_record" },
    412				{ "perf",     "run_command" },
    413				{ "perf",     "main" }, },
    414		},
    415		{
    416			4, {	{ "libc",     "malloc" },
    417				{ "perf",     "cmd_record" },
    418				{ "perf",     "run_command" },
    419				{ "perf",     "main" }, },
    420		},
    421		{
    422			3, {	{ "perf",     "cmd_record" },
    423				{ "perf",     "run_command" },
    424				{ "perf",     "main" }, },
    425		},
    426	};
    427
    428	symbol_conf.use_callchain = true;
    429	symbol_conf.cumulate_callchain = false;
    430	evsel__set_sample_bit(evsel, CALLCHAIN);
    431
    432	setup_sorting(NULL);
    433	callchain_register_param(&callchain_param);
    434
    435	err = add_hist_entries(hists, machine);
    436	if (err < 0)
    437		goto out;
    438
    439	err = do_test(hists, expected, ARRAY_SIZE(expected),
    440		      expected_callchain, ARRAY_SIZE(expected_callchain));
    441
    442out:
    443	del_hist_entries(hists);
    444	reset_output_field();
    445	return err;
    446}
    447
    448/* NO callchain + children */
    449static int test3(struct evsel *evsel, struct machine *machine)
    450{
    451	int err;
    452	struct hists *hists = evsel__hists(evsel);
    453	/*
    454	 * expected output:
    455	 *
    456	 * Children      Self  Command  Shared Object                   Symbol
    457	 * ========  ========  =======  =============  =======================
    458	 *   70.00%    20.00%     perf  perf           [.] main
    459	 *   50.00%     0.00%     perf  perf           [.] run_command
    460	 *   30.00%    10.00%     bash  bash           [.] main
    461	 *   30.00%    10.00%     perf  perf           [.] cmd_record
    462	 *   20.00%     0.00%     bash  libc           [.] malloc
    463	 *   10.00%    10.00%     bash  [kernel]       [k] page_fault
    464	 *   10.00%    10.00%     bash  bash           [.] xmalloc
    465	 *   10.00%    10.00%     perf  [kernel]       [k] page_fault
    466	 *   10.00%    10.00%     perf  libc           [.] malloc
    467	 *   10.00%    10.00%     perf  [kernel]       [k] schedule
    468	 *   10.00%    10.00%     perf  libc           [.] free
    469	 *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
    470	 */
    471	struct result expected[] = {
    472		{ 7000, 2000, "perf", "perf",     "main" },
    473		{ 5000,    0, "perf", "perf",     "run_command" },
    474		{ 3000, 1000, "bash", "bash",     "main" },
    475		{ 3000, 1000, "perf", "perf",     "cmd_record" },
    476		{ 2000,    0, "bash", "libc",     "malloc" },
    477		{ 1000, 1000, "bash", "[kernel]", "page_fault" },
    478		{ 1000, 1000, "bash", "bash",     "xmalloc" },
    479		{ 1000, 1000, "perf", "[kernel]", "page_fault" },
    480		{ 1000, 1000, "perf", "[kernel]", "schedule" },
    481		{ 1000, 1000, "perf", "libc",     "free" },
    482		{ 1000, 1000, "perf", "libc",     "malloc" },
    483		{ 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
    484	};
    485
    486	symbol_conf.use_callchain = false;
    487	symbol_conf.cumulate_callchain = true;
    488	evsel__reset_sample_bit(evsel, CALLCHAIN);
    489
    490	setup_sorting(NULL);
    491	callchain_register_param(&callchain_param);
    492
    493	err = add_hist_entries(hists, machine);
    494	if (err < 0)
    495		goto out;
    496
    497	err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
    498
    499out:
    500	del_hist_entries(hists);
    501	reset_output_field();
    502	return err;
    503}
    504
    505/* callchain + children */
    506static int test4(struct evsel *evsel, struct machine *machine)
    507{
    508	int err;
    509	struct hists *hists = evsel__hists(evsel);
    510	/*
    511	 * expected output:
    512	 *
    513	 * Children      Self  Command  Shared Object                   Symbol
    514	 * ========  ========  =======  =============  =======================
    515	 *   70.00%    20.00%     perf  perf           [.] main
    516	 *              |
    517	 *              --- main
    518	 *
    519	 *   50.00%     0.00%     perf  perf           [.] run_command
    520	 *              |
    521	 *              --- run_command
    522	 *                  main
    523	 *
    524	 *   30.00%    10.00%     bash  bash           [.] main
    525	 *              |
    526	 *              --- main
    527	 *
    528	 *   30.00%    10.00%     perf  perf           [.] cmd_record
    529	 *              |
    530	 *              --- cmd_record
    531	 *                  run_command
    532	 *                  main
    533	 *
    534	 *   20.00%     0.00%     bash  libc           [.] malloc
    535	 *              |
    536	 *              --- malloc
    537	 *                 |
    538	 *                 |--50.00%-- xmalloc
    539	 *                 |           main
    540	 *                  --50.00%-- main
    541	 *
    542	 *   10.00%    10.00%     bash  [kernel]       [k] page_fault
    543	 *              |
    544	 *              --- page_fault
    545	 *                  malloc
    546	 *                  main
    547	 *
    548	 *   10.00%    10.00%     bash  bash           [.] xmalloc
    549	 *              |
    550	 *              --- xmalloc
    551	 *                  malloc
    552	 *                  xmalloc     <--- NOTE: there's a cycle
    553	 *                  malloc
    554	 *                  xmalloc
    555	 *                  main
    556	 *
    557	 *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
    558	 *              |
    559	 *              --- sys_perf_event_open
    560	 *                  run_command
    561	 *                  main
    562	 *
    563	 *   10.00%    10.00%     perf  [kernel]       [k] page_fault
    564	 *              |
    565	 *              --- page_fault
    566	 *                  sys_perf_event_open
    567	 *                  run_command
    568	 *                  main
    569	 *
    570	 *   10.00%    10.00%     perf  [kernel]       [k] schedule
    571	 *              |
    572	 *              --- schedule
    573	 *                  run_command
    574	 *                  main
    575	 *
    576	 *   10.00%    10.00%     perf  libc           [.] free
    577	 *              |
    578	 *              --- free
    579	 *                  cmd_record
    580	 *                  run_command
    581	 *                  main
    582	 *
    583	 *   10.00%    10.00%     perf  libc           [.] malloc
    584	 *              |
    585	 *              --- malloc
    586	 *                  cmd_record
    587	 *                  run_command
    588	 *                  main
    589	 *
    590	 */
    591	struct result expected[] = {
    592		{ 7000, 2000, "perf", "perf",     "main" },
    593		{ 5000,    0, "perf", "perf",     "run_command" },
    594		{ 3000, 1000, "bash", "bash",     "main" },
    595		{ 3000, 1000, "perf", "perf",     "cmd_record" },
    596		{ 2000,    0, "bash", "libc",     "malloc" },
    597		{ 1000, 1000, "bash", "[kernel]", "page_fault" },
    598		{ 1000, 1000, "bash", "bash",     "xmalloc" },
    599		{ 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
    600		{ 1000, 1000, "perf", "[kernel]", "page_fault" },
    601		{ 1000, 1000, "perf", "[kernel]", "schedule" },
    602		{ 1000, 1000, "perf", "libc",     "free" },
    603		{ 1000, 1000, "perf", "libc",     "malloc" },
    604	};
    605	struct callchain_result expected_callchain[] = {
    606		{
    607			1, {	{ "perf",     "main" }, },
    608		},
    609		{
    610			2, {	{ "perf",     "run_command" },
    611				{ "perf",     "main" }, },
    612		},
    613		{
    614			1, {	{ "bash",     "main" }, },
    615		},
    616		{
    617			3, {	{ "perf",     "cmd_record" },
    618				{ "perf",     "run_command" },
    619				{ "perf",     "main" }, },
    620		},
    621		{
    622			4, {	{ "libc",     "malloc" },
    623				{ "bash",     "xmalloc" },
    624				{ "bash",     "main" },
    625				{ "bash",     "main" }, },
    626		},
    627		{
    628			3, {	{ "[kernel]", "page_fault" },
    629				{ "libc",     "malloc" },
    630				{ "bash",     "main" }, },
    631		},
    632		{
    633			6, {	{ "bash",     "xmalloc" },
    634				{ "libc",     "malloc" },
    635				{ "bash",     "xmalloc" },
    636				{ "libc",     "malloc" },
    637				{ "bash",     "xmalloc" },
    638				{ "bash",     "main" }, },
    639		},
    640		{
    641			3, {	{ "[kernel]", "sys_perf_event_open" },
    642				{ "perf",     "run_command" },
    643				{ "perf",     "main" }, },
    644		},
    645		{
    646			4, {	{ "[kernel]", "page_fault" },
    647				{ "[kernel]", "sys_perf_event_open" },
    648				{ "perf",     "run_command" },
    649				{ "perf",     "main" }, },
    650		},
    651		{
    652			3, {	{ "[kernel]", "schedule" },
    653				{ "perf",     "run_command" },
    654				{ "perf",     "main" }, },
    655		},
    656		{
    657			4, {	{ "libc",     "free" },
    658				{ "perf",     "cmd_record" },
    659				{ "perf",     "run_command" },
    660				{ "perf",     "main" }, },
    661		},
    662		{
    663			4, {	{ "libc",     "malloc" },
    664				{ "perf",     "cmd_record" },
    665				{ "perf",     "run_command" },
    666				{ "perf",     "main" }, },
    667		},
    668	};
    669
    670	symbol_conf.use_callchain = true;
    671	symbol_conf.cumulate_callchain = true;
    672	evsel__set_sample_bit(evsel, CALLCHAIN);
    673
    674	setup_sorting(NULL);
    675
    676	callchain_param = callchain_param_default;
    677	callchain_register_param(&callchain_param);
    678
    679	err = add_hist_entries(hists, machine);
    680	if (err < 0)
    681		goto out;
    682
    683	err = do_test(hists, expected, ARRAY_SIZE(expected),
    684		      expected_callchain, ARRAY_SIZE(expected_callchain));
    685
    686out:
    687	del_hist_entries(hists);
    688	reset_output_field();
    689	return err;
    690}
    691
    692static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
    693{
    694	int err = TEST_FAIL;
    695	struct machines machines;
    696	struct machine *machine;
    697	struct evsel *evsel;
    698	struct evlist *evlist = evlist__new();
    699	size_t i;
    700	test_fn_t testcases[] = {
    701		test1,
    702		test2,
    703		test3,
    704		test4,
    705	};
    706
    707	TEST_ASSERT_VAL("No memory", evlist);
    708
    709	err = parse_events(evlist, "cpu-clock", NULL);
    710	if (err)
    711		goto out;
    712	err = TEST_FAIL;
    713
    714	machines__init(&machines);
    715
    716	/* setup threads/dso/map/symbols also */
    717	machine = setup_fake_machine(&machines);
    718	if (!machine)
    719		goto out;
    720
    721	if (verbose > 1)
    722		machine__fprintf(machine, stderr);
    723
    724	evsel = evlist__first(evlist);
    725
    726	for (i = 0; i < ARRAY_SIZE(testcases); i++) {
    727		err = testcases[i](evsel, machine);
    728		if (err < 0)
    729			break;
    730	}
    731
    732out:
    733	/* tear down everything */
    734	evlist__delete(evlist);
    735	machines__exit(&machines);
    736
    737	return err;
    738}
    739
    740DEFINE_SUITE("Cumulate child hist entries", hists_cumulate);