1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include "util/debug.h"
3*4882a593Smuzhiyun #include "util/dso.h"
4*4882a593Smuzhiyun #include "util/event.h"
5*4882a593Smuzhiyun #include "util/map.h"
6*4882a593Smuzhiyun #include "util/symbol.h"
7*4882a593Smuzhiyun #include "util/sort.h"
8*4882a593Smuzhiyun #include "util/evsel.h"
9*4882a593Smuzhiyun #include "util/evlist.h"
10*4882a593Smuzhiyun #include "util/machine.h"
11*4882a593Smuzhiyun #include "util/thread.h"
12*4882a593Smuzhiyun #include "util/parse-events.h"
13*4882a593Smuzhiyun #include "tests/tests.h"
14*4882a593Smuzhiyun #include "tests/hists_common.h"
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun struct sample {
18*4882a593Smuzhiyun u32 cpu;
19*4882a593Smuzhiyun u32 pid;
20*4882a593Smuzhiyun u64 ip;
21*4882a593Smuzhiyun struct thread *thread;
22*4882a593Smuzhiyun struct map *map;
23*4882a593Smuzhiyun struct symbol *sym;
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* For the numbers, see hists_common.c */
27*4882a593Smuzhiyun static struct sample fake_samples[] = {
28*4882a593Smuzhiyun /* perf [kernel] schedule() */
29*4882a593Smuzhiyun { .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
30*4882a593Smuzhiyun /* perf [perf] main() */
31*4882a593Smuzhiyun { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
32*4882a593Smuzhiyun /* perf [perf] cmd_record() */
33*4882a593Smuzhiyun { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
34*4882a593Smuzhiyun /* perf [libc] malloc() */
35*4882a593Smuzhiyun { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
36*4882a593Smuzhiyun /* perf [libc] free() */
37*4882a593Smuzhiyun { .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
38*4882a593Smuzhiyun /* perf [perf] main() */
39*4882a593Smuzhiyun { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
40*4882a593Smuzhiyun /* perf [kernel] page_fault() */
41*4882a593Smuzhiyun { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
42*4882a593Smuzhiyun /* bash [bash] main() */
43*4882a593Smuzhiyun { .cpu = 3, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
44*4882a593Smuzhiyun /* bash [bash] xmalloc() */
45*4882a593Smuzhiyun { .cpu = 0, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
46*4882a593Smuzhiyun /* bash [kernel] page_fault() */
47*4882a593Smuzhiyun { .cpu = 1, .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun
add_hist_entries(struct hists * hists,struct machine * machine)50*4882a593Smuzhiyun static int add_hist_entries(struct hists *hists, struct machine *machine)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun struct addr_location al;
53*4882a593Smuzhiyun struct evsel *evsel = hists_to_evsel(hists);
54*4882a593Smuzhiyun struct perf_sample sample = { .period = 100, };
55*4882a593Smuzhiyun size_t i;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
58*4882a593Smuzhiyun struct hist_entry_iter iter = {
59*4882a593Smuzhiyun .evsel = evsel,
60*4882a593Smuzhiyun .sample = &sample,
61*4882a593Smuzhiyun .ops = &hist_iter_normal,
62*4882a593Smuzhiyun .hide_unresolved = false,
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun sample.cpumode = PERF_RECORD_MISC_USER;
66*4882a593Smuzhiyun sample.cpu = fake_samples[i].cpu;
67*4882a593Smuzhiyun sample.pid = fake_samples[i].pid;
68*4882a593Smuzhiyun sample.tid = fake_samples[i].pid;
69*4882a593Smuzhiyun sample.ip = fake_samples[i].ip;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (machine__resolve(machine, &al, &sample) < 0)
72*4882a593Smuzhiyun goto out;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
75*4882a593Smuzhiyun NULL) < 0) {
76*4882a593Smuzhiyun addr_location__put(&al);
77*4882a593Smuzhiyun goto out;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun fake_samples[i].thread = al.thread;
81*4882a593Smuzhiyun fake_samples[i].map = al.map;
82*4882a593Smuzhiyun fake_samples[i].sym = al.sym;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun return TEST_OK;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun out:
88*4882a593Smuzhiyun pr_debug("Not enough memory for adding a hist entry\n");
89*4882a593Smuzhiyun return TEST_FAIL;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
del_hist_entries(struct hists * hists)92*4882a593Smuzhiyun static void del_hist_entries(struct hists *hists)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun struct hist_entry *he;
95*4882a593Smuzhiyun struct rb_root_cached *root_in;
96*4882a593Smuzhiyun struct rb_root_cached *root_out;
97*4882a593Smuzhiyun struct rb_node *node;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (hists__has(hists, need_collapse))
100*4882a593Smuzhiyun root_in = &hists->entries_collapsed;
101*4882a593Smuzhiyun else
102*4882a593Smuzhiyun root_in = hists->entries_in;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun root_out = &hists->entries;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun while (!RB_EMPTY_ROOT(&root_out->rb_root)) {
107*4882a593Smuzhiyun node = rb_first_cached(root_out);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
110*4882a593Smuzhiyun rb_erase_cached(node, root_out);
111*4882a593Smuzhiyun rb_erase_cached(&he->rb_node_in, root_in);
112*4882a593Smuzhiyun hist_entry__delete(he);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun typedef int (*test_fn_t)(struct evsel *, struct machine *);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #define COMM(he) (thread__comm_str(he->thread))
119*4882a593Smuzhiyun #define DSO(he) (he->ms.map->dso->short_name)
120*4882a593Smuzhiyun #define SYM(he) (he->ms.sym->name)
121*4882a593Smuzhiyun #define CPU(he) (he->cpu)
122*4882a593Smuzhiyun #define PID(he) (he->thread->tid)
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* default sort keys (no field) */
test1(struct evsel * evsel,struct machine * machine)125*4882a593Smuzhiyun static int test1(struct evsel *evsel, struct machine *machine)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun int err;
128*4882a593Smuzhiyun struct hists *hists = evsel__hists(evsel);
129*4882a593Smuzhiyun struct hist_entry *he;
130*4882a593Smuzhiyun struct rb_root_cached *root;
131*4882a593Smuzhiyun struct rb_node *node;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun field_order = NULL;
134*4882a593Smuzhiyun sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun setup_sorting(NULL);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /*
139*4882a593Smuzhiyun * expected output:
140*4882a593Smuzhiyun *
141*4882a593Smuzhiyun * Overhead Command Shared Object Symbol
142*4882a593Smuzhiyun * ======== ======= ============= ==============
143*4882a593Smuzhiyun * 20.00% perf perf [.] main
144*4882a593Smuzhiyun * 10.00% bash [kernel] [k] page_fault
145*4882a593Smuzhiyun * 10.00% bash bash [.] main
146*4882a593Smuzhiyun * 10.00% bash bash [.] xmalloc
147*4882a593Smuzhiyun * 10.00% perf [kernel] [k] page_fault
148*4882a593Smuzhiyun * 10.00% perf [kernel] [k] schedule
149*4882a593Smuzhiyun * 10.00% perf libc [.] free
150*4882a593Smuzhiyun * 10.00% perf libc [.] malloc
151*4882a593Smuzhiyun * 10.00% perf perf [.] cmd_record
152*4882a593Smuzhiyun */
153*4882a593Smuzhiyun err = add_hist_entries(hists, machine);
154*4882a593Smuzhiyun if (err < 0)
155*4882a593Smuzhiyun goto out;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun hists__collapse_resort(hists, NULL);
158*4882a593Smuzhiyun evsel__output_resort(evsel, NULL);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (verbose > 2) {
161*4882a593Smuzhiyun pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
162*4882a593Smuzhiyun print_hists_out(hists);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun root = &hists->entries;
166*4882a593Smuzhiyun node = rb_first_cached(root);
167*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
168*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
169*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
170*4882a593Smuzhiyun !strcmp(SYM(he), "main") && he->stat.period == 200);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun node = rb_next(node);
173*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
174*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
175*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
176*4882a593Smuzhiyun !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun node = rb_next(node);
179*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
180*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
181*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
182*4882a593Smuzhiyun !strcmp(SYM(he), "main") && he->stat.period == 100);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun node = rb_next(node);
185*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
186*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
187*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
188*4882a593Smuzhiyun !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun node = rb_next(node);
191*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
192*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
193*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
194*4882a593Smuzhiyun !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun node = rb_next(node);
197*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
198*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
199*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
200*4882a593Smuzhiyun !strcmp(SYM(he), "schedule") && he->stat.period == 100);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun node = rb_next(node);
203*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
204*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
205*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
206*4882a593Smuzhiyun !strcmp(SYM(he), "free") && he->stat.period == 100);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun node = rb_next(node);
209*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
210*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
211*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
212*4882a593Smuzhiyun !strcmp(SYM(he), "malloc") && he->stat.period == 100);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun node = rb_next(node);
215*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
216*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
217*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
218*4882a593Smuzhiyun !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun out:
221*4882a593Smuzhiyun del_hist_entries(hists);
222*4882a593Smuzhiyun reset_output_field();
223*4882a593Smuzhiyun return err;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* mixed fields and sort keys */
test2(struct evsel * evsel,struct machine * machine)227*4882a593Smuzhiyun static int test2(struct evsel *evsel, struct machine *machine)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun int err;
230*4882a593Smuzhiyun struct hists *hists = evsel__hists(evsel);
231*4882a593Smuzhiyun struct hist_entry *he;
232*4882a593Smuzhiyun struct rb_root_cached *root;
233*4882a593Smuzhiyun struct rb_node *node;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun field_order = "overhead,cpu";
236*4882a593Smuzhiyun sort_order = "pid";
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun setup_sorting(NULL);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /*
241*4882a593Smuzhiyun * expected output:
242*4882a593Smuzhiyun *
243*4882a593Smuzhiyun * Overhead CPU Command: Pid
244*4882a593Smuzhiyun * ======== === =============
245*4882a593Smuzhiyun * 30.00% 1 perf : 100
246*4882a593Smuzhiyun * 10.00% 0 perf : 100
247*4882a593Smuzhiyun * 10.00% 2 perf : 100
248*4882a593Smuzhiyun * 20.00% 2 perf : 200
249*4882a593Smuzhiyun * 10.00% 0 bash : 300
250*4882a593Smuzhiyun * 10.00% 1 bash : 300
251*4882a593Smuzhiyun * 10.00% 3 bash : 300
252*4882a593Smuzhiyun */
253*4882a593Smuzhiyun err = add_hist_entries(hists, machine);
254*4882a593Smuzhiyun if (err < 0)
255*4882a593Smuzhiyun goto out;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun hists__collapse_resort(hists, NULL);
258*4882a593Smuzhiyun evsel__output_resort(evsel, NULL);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (verbose > 2) {
261*4882a593Smuzhiyun pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
262*4882a593Smuzhiyun print_hists_out(hists);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun root = &hists->entries;
266*4882a593Smuzhiyun node = rb_first_cached(root);
267*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
268*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
269*4882a593Smuzhiyun CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun node = rb_next(node);
272*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
273*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
274*4882a593Smuzhiyun CPU(he) == 0 && PID(he) == 100 && he->stat.period == 100);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun out:
277*4882a593Smuzhiyun del_hist_entries(hists);
278*4882a593Smuzhiyun reset_output_field();
279*4882a593Smuzhiyun return err;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* fields only (no sort key) */
test3(struct evsel * evsel,struct machine * machine)283*4882a593Smuzhiyun static int test3(struct evsel *evsel, struct machine *machine)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun int err;
286*4882a593Smuzhiyun struct hists *hists = evsel__hists(evsel);
287*4882a593Smuzhiyun struct hist_entry *he;
288*4882a593Smuzhiyun struct rb_root_cached *root;
289*4882a593Smuzhiyun struct rb_node *node;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun field_order = "comm,overhead,dso";
292*4882a593Smuzhiyun sort_order = NULL;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun setup_sorting(NULL);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /*
297*4882a593Smuzhiyun * expected output:
298*4882a593Smuzhiyun *
299*4882a593Smuzhiyun * Command Overhead Shared Object
300*4882a593Smuzhiyun * ======= ======== =============
301*4882a593Smuzhiyun * bash 20.00% bash
302*4882a593Smuzhiyun * bash 10.00% [kernel]
303*4882a593Smuzhiyun * perf 30.00% perf
304*4882a593Smuzhiyun * perf 20.00% [kernel]
305*4882a593Smuzhiyun * perf 20.00% libc
306*4882a593Smuzhiyun */
307*4882a593Smuzhiyun err = add_hist_entries(hists, machine);
308*4882a593Smuzhiyun if (err < 0)
309*4882a593Smuzhiyun goto out;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun hists__collapse_resort(hists, NULL);
312*4882a593Smuzhiyun evsel__output_resort(evsel, NULL);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (verbose > 2) {
315*4882a593Smuzhiyun pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
316*4882a593Smuzhiyun print_hists_out(hists);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun root = &hists->entries;
320*4882a593Smuzhiyun node = rb_first_cached(root);
321*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
322*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
323*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
324*4882a593Smuzhiyun he->stat.period == 200);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun node = rb_next(node);
327*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
328*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
329*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
330*4882a593Smuzhiyun he->stat.period == 100);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun node = rb_next(node);
333*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
334*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
335*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
336*4882a593Smuzhiyun he->stat.period == 300);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun node = rb_next(node);
339*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
340*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
341*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
342*4882a593Smuzhiyun he->stat.period == 200);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun node = rb_next(node);
345*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
346*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
347*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
348*4882a593Smuzhiyun he->stat.period == 200);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun out:
351*4882a593Smuzhiyun del_hist_entries(hists);
352*4882a593Smuzhiyun reset_output_field();
353*4882a593Smuzhiyun return err;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* handle duplicate 'dso' field */
test4(struct evsel * evsel,struct machine * machine)357*4882a593Smuzhiyun static int test4(struct evsel *evsel, struct machine *machine)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun int err;
360*4882a593Smuzhiyun struct hists *hists = evsel__hists(evsel);
361*4882a593Smuzhiyun struct hist_entry *he;
362*4882a593Smuzhiyun struct rb_root_cached *root;
363*4882a593Smuzhiyun struct rb_node *node;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun field_order = "dso,sym,comm,overhead,dso";
366*4882a593Smuzhiyun sort_order = "sym";
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun setup_sorting(NULL);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /*
371*4882a593Smuzhiyun * expected output:
372*4882a593Smuzhiyun *
373*4882a593Smuzhiyun * Shared Object Symbol Command Overhead
374*4882a593Smuzhiyun * ============= ============== ======= ========
375*4882a593Smuzhiyun * perf [.] cmd_record perf 10.00%
376*4882a593Smuzhiyun * libc [.] free perf 10.00%
377*4882a593Smuzhiyun * bash [.] main bash 10.00%
378*4882a593Smuzhiyun * perf [.] main perf 20.00%
379*4882a593Smuzhiyun * libc [.] malloc perf 10.00%
380*4882a593Smuzhiyun * [kernel] [k] page_fault bash 10.00%
381*4882a593Smuzhiyun * [kernel] [k] page_fault perf 10.00%
382*4882a593Smuzhiyun * [kernel] [k] schedule perf 10.00%
383*4882a593Smuzhiyun * bash [.] xmalloc bash 10.00%
384*4882a593Smuzhiyun */
385*4882a593Smuzhiyun err = add_hist_entries(hists, machine);
386*4882a593Smuzhiyun if (err < 0)
387*4882a593Smuzhiyun goto out;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun hists__collapse_resort(hists, NULL);
390*4882a593Smuzhiyun evsel__output_resort(evsel, NULL);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun if (verbose > 2) {
393*4882a593Smuzhiyun pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
394*4882a593Smuzhiyun print_hists_out(hists);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun root = &hists->entries;
398*4882a593Smuzhiyun node = rb_first_cached(root);
399*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
400*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
401*4882a593Smuzhiyun !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&
402*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && he->stat.period == 100);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun node = rb_next(node);
405*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
406*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
407*4882a593Smuzhiyun !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "free") &&
408*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && he->stat.period == 100);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun node = rb_next(node);
411*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
412*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
413*4882a593Smuzhiyun !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "main") &&
414*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && he->stat.period == 100);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun node = rb_next(node);
417*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
418*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
419*4882a593Smuzhiyun !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "main") &&
420*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && he->stat.period == 200);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun node = rb_next(node);
423*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
424*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
425*4882a593Smuzhiyun !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "malloc") &&
426*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && he->stat.period == 100);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun node = rb_next(node);
429*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
430*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
431*4882a593Smuzhiyun !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
432*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && he->stat.period == 100);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun node = rb_next(node);
435*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
436*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
437*4882a593Smuzhiyun !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
438*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && he->stat.period == 100);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun node = rb_next(node);
441*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
442*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
443*4882a593Smuzhiyun !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "schedule") &&
444*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && he->stat.period == 100);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun node = rb_next(node);
447*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
448*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
449*4882a593Smuzhiyun !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "xmalloc") &&
450*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && he->stat.period == 100);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun out:
453*4882a593Smuzhiyun del_hist_entries(hists);
454*4882a593Smuzhiyun reset_output_field();
455*4882a593Smuzhiyun return err;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun /* full sort keys w/o overhead field */
test5(struct evsel * evsel,struct machine * machine)459*4882a593Smuzhiyun static int test5(struct evsel *evsel, struct machine *machine)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun int err;
462*4882a593Smuzhiyun struct hists *hists = evsel__hists(evsel);
463*4882a593Smuzhiyun struct hist_entry *he;
464*4882a593Smuzhiyun struct rb_root_cached *root;
465*4882a593Smuzhiyun struct rb_node *node;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun field_order = "cpu,pid,comm,dso,sym";
468*4882a593Smuzhiyun sort_order = "dso,pid";
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun setup_sorting(NULL);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun /*
473*4882a593Smuzhiyun * expected output:
474*4882a593Smuzhiyun *
475*4882a593Smuzhiyun * CPU Command: Pid Command Shared Object Symbol
476*4882a593Smuzhiyun * === ============= ======= ============= ==============
477*4882a593Smuzhiyun * 0 perf: 100 perf [kernel] [k] schedule
478*4882a593Smuzhiyun * 2 perf: 200 perf [kernel] [k] page_fault
479*4882a593Smuzhiyun * 1 bash: 300 bash [kernel] [k] page_fault
480*4882a593Smuzhiyun * 0 bash: 300 bash bash [.] xmalloc
481*4882a593Smuzhiyun * 3 bash: 300 bash bash [.] main
482*4882a593Smuzhiyun * 1 perf: 100 perf libc [.] malloc
483*4882a593Smuzhiyun * 2 perf: 100 perf libc [.] free
484*4882a593Smuzhiyun * 1 perf: 100 perf perf [.] cmd_record
485*4882a593Smuzhiyun * 1 perf: 100 perf perf [.] main
486*4882a593Smuzhiyun * 2 perf: 200 perf perf [.] main
487*4882a593Smuzhiyun */
488*4882a593Smuzhiyun err = add_hist_entries(hists, machine);
489*4882a593Smuzhiyun if (err < 0)
490*4882a593Smuzhiyun goto out;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun hists__collapse_resort(hists, NULL);
493*4882a593Smuzhiyun evsel__output_resort(evsel, NULL);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (verbose > 2) {
496*4882a593Smuzhiyun pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
497*4882a593Smuzhiyun print_hists_out(hists);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun root = &hists->entries;
501*4882a593Smuzhiyun node = rb_first_cached(root);
502*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
505*4882a593Smuzhiyun CPU(he) == 0 && PID(he) == 100 &&
506*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
507*4882a593Smuzhiyun !strcmp(SYM(he), "schedule") && he->stat.period == 100);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun node = rb_next(node);
510*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
511*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
512*4882a593Smuzhiyun CPU(he) == 2 && PID(he) == 200 &&
513*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
514*4882a593Smuzhiyun !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun node = rb_next(node);
517*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
518*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
519*4882a593Smuzhiyun CPU(he) == 1 && PID(he) == 300 &&
520*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
521*4882a593Smuzhiyun !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun node = rb_next(node);
524*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
525*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
526*4882a593Smuzhiyun CPU(he) == 0 && PID(he) == 300 &&
527*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
528*4882a593Smuzhiyun !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun node = rb_next(node);
531*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
532*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
533*4882a593Smuzhiyun CPU(he) == 3 && PID(he) == 300 &&
534*4882a593Smuzhiyun !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
535*4882a593Smuzhiyun !strcmp(SYM(he), "main") && he->stat.period == 100);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun node = rb_next(node);
538*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
539*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
540*4882a593Smuzhiyun CPU(he) == 1 && PID(he) == 100 &&
541*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
542*4882a593Smuzhiyun !strcmp(SYM(he), "malloc") && he->stat.period == 100);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun node = rb_next(node);
545*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
546*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
547*4882a593Smuzhiyun CPU(he) == 2 && PID(he) == 100 &&
548*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
549*4882a593Smuzhiyun !strcmp(SYM(he), "free") && he->stat.period == 100);
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun node = rb_next(node);
552*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
553*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
554*4882a593Smuzhiyun CPU(he) == 1 && PID(he) == 100 &&
555*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
556*4882a593Smuzhiyun !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun node = rb_next(node);
559*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
560*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
561*4882a593Smuzhiyun CPU(he) == 1 && PID(he) == 100 &&
562*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
563*4882a593Smuzhiyun !strcmp(SYM(he), "main") && he->stat.period == 100);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun node = rb_next(node);
566*4882a593Smuzhiyun he = rb_entry(node, struct hist_entry, rb_node);
567*4882a593Smuzhiyun TEST_ASSERT_VAL("Invalid hist entry",
568*4882a593Smuzhiyun CPU(he) == 2 && PID(he) == 200 &&
569*4882a593Smuzhiyun !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
570*4882a593Smuzhiyun !strcmp(SYM(he), "main") && he->stat.period == 100);
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun out:
573*4882a593Smuzhiyun del_hist_entries(hists);
574*4882a593Smuzhiyun reset_output_field();
575*4882a593Smuzhiyun return err;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
test__hists_output(struct test * test __maybe_unused,int subtest __maybe_unused)578*4882a593Smuzhiyun int test__hists_output(struct test *test __maybe_unused, int subtest __maybe_unused)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun int err = TEST_FAIL;
581*4882a593Smuzhiyun struct machines machines;
582*4882a593Smuzhiyun struct machine *machine;
583*4882a593Smuzhiyun struct evsel *evsel;
584*4882a593Smuzhiyun struct evlist *evlist = evlist__new();
585*4882a593Smuzhiyun size_t i;
586*4882a593Smuzhiyun test_fn_t testcases[] = {
587*4882a593Smuzhiyun test1,
588*4882a593Smuzhiyun test2,
589*4882a593Smuzhiyun test3,
590*4882a593Smuzhiyun test4,
591*4882a593Smuzhiyun test5,
592*4882a593Smuzhiyun };
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun TEST_ASSERT_VAL("No memory", evlist);
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun err = parse_events(evlist, "cpu-clock", NULL);
597*4882a593Smuzhiyun if (err)
598*4882a593Smuzhiyun goto out;
599*4882a593Smuzhiyun err = TEST_FAIL;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun machines__init(&machines);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun /* setup threads/dso/map/symbols also */
604*4882a593Smuzhiyun machine = setup_fake_machine(&machines);
605*4882a593Smuzhiyun if (!machine)
606*4882a593Smuzhiyun goto out;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (verbose > 1)
609*4882a593Smuzhiyun machine__fprintf(machine, stderr);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun evsel = evlist__first(evlist);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(testcases); i++) {
614*4882a593Smuzhiyun err = testcases[i](evsel, machine);
615*4882a593Smuzhiyun if (err < 0)
616*4882a593Smuzhiyun break;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun out:
620*4882a593Smuzhiyun /* tear down everything */
621*4882a593Smuzhiyun evlist__delete(evlist);
622*4882a593Smuzhiyun machines__exit(&machines);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun return err;
625*4882a593Smuzhiyun }
626