0001
0002 #include "util/debug.h"
0003 #include "util/dso.h"
0004 #include "util/event.h"
0005 #include "util/map.h"
0006 #include "util/symbol.h"
0007 #include "util/sort.h"
0008 #include "util/evsel.h"
0009 #include "util/evlist.h"
0010 #include "util/machine.h"
0011 #include "util/thread.h"
0012 #include "util/parse-events.h"
0013 #include "tests/tests.h"
0014 #include "tests/hists_common.h"
0015 #include <linux/kernel.h>
0016
0017 struct sample {
0018 u32 cpu;
0019 u32 pid;
0020 u64 ip;
0021 struct thread *thread;
0022 struct map *map;
0023 struct symbol *sym;
0024 };
0025
0026
0027 static struct sample fake_samples[] = {
0028
0029 { .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
0030
0031 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
0032
0033 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
0034
0035 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
0036
0037 { .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
0038
0039 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
0040
0041 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
0042
0043 { .cpu = 3, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
0044
0045 { .cpu = 0, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
0046
0047 { .cpu = 1, .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
0048 };
0049
0050 static int add_hist_entries(struct hists *hists, struct machine *machine)
0051 {
0052 struct addr_location al;
0053 struct evsel *evsel = hists_to_evsel(hists);
0054 struct perf_sample sample = { .period = 100, };
0055 size_t i;
0056
0057 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
0058 struct hist_entry_iter iter = {
0059 .evsel = evsel,
0060 .sample = &sample,
0061 .ops = &hist_iter_normal,
0062 .hide_unresolved = false,
0063 };
0064
0065 sample.cpumode = PERF_RECORD_MISC_USER;
0066 sample.cpu = fake_samples[i].cpu;
0067 sample.pid = fake_samples[i].pid;
0068 sample.tid = fake_samples[i].pid;
0069 sample.ip = fake_samples[i].ip;
0070
0071 if (machine__resolve(machine, &al, &sample) < 0)
0072 goto out;
0073
0074 if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
0075 NULL) < 0) {
0076 addr_location__put(&al);
0077 goto out;
0078 }
0079
0080 fake_samples[i].thread = al.thread;
0081 fake_samples[i].map = al.map;
0082 fake_samples[i].sym = al.sym;
0083 }
0084
0085 return TEST_OK;
0086
0087 out:
0088 pr_debug("Not enough memory for adding a hist entry\n");
0089 return TEST_FAIL;
0090 }
0091
0092 static void del_hist_entries(struct hists *hists)
0093 {
0094 struct hist_entry *he;
0095 struct rb_root_cached *root_in;
0096 struct rb_root_cached *root_out;
0097 struct rb_node *node;
0098
0099 if (hists__has(hists, need_collapse))
0100 root_in = &hists->entries_collapsed;
0101 else
0102 root_in = hists->entries_in;
0103
0104 root_out = &hists->entries;
0105
0106 while (!RB_EMPTY_ROOT(&root_out->rb_root)) {
0107 node = rb_first_cached(root_out);
0108
0109 he = rb_entry(node, struct hist_entry, rb_node);
0110 rb_erase_cached(node, root_out);
0111 rb_erase_cached(&he->rb_node_in, root_in);
0112 hist_entry__delete(he);
0113 }
0114 }
0115
0116 typedef int (*test_fn_t)(struct evsel *, struct machine *);
0117
0118 #define COMM(he) (thread__comm_str(he->thread))
0119 #define DSO(he) (he->ms.map->dso->short_name)
0120 #define SYM(he) (he->ms.sym->name)
0121 #define CPU(he) (he->cpu)
0122 #define PID(he) (he->thread->tid)
0123
0124
0125 static int test1(struct evsel *evsel, struct machine *machine)
0126 {
0127 int err;
0128 struct hists *hists = evsel__hists(evsel);
0129 struct hist_entry *he;
0130 struct rb_root_cached *root;
0131 struct rb_node *node;
0132
0133 field_order = NULL;
0134 sort_order = NULL;
0135
0136 setup_sorting(NULL);
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153 err = add_hist_entries(hists, machine);
0154 if (err < 0)
0155 goto out;
0156
0157 hists__collapse_resort(hists, NULL);
0158 evsel__output_resort(evsel, NULL);
0159
0160 if (verbose > 2) {
0161 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
0162 print_hists_out(hists);
0163 }
0164
0165 root = &hists->entries;
0166 node = rb_first_cached(root);
0167 he = rb_entry(node, struct hist_entry, rb_node);
0168 TEST_ASSERT_VAL("Invalid hist entry",
0169 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
0170 !strcmp(SYM(he), "main") && he->stat.period == 200);
0171
0172 node = rb_next(node);
0173 he = rb_entry(node, struct hist_entry, rb_node);
0174 TEST_ASSERT_VAL("Invalid hist entry",
0175 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
0176 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
0177
0178 node = rb_next(node);
0179 he = rb_entry(node, struct hist_entry, rb_node);
0180 TEST_ASSERT_VAL("Invalid hist entry",
0181 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
0182 !strcmp(SYM(he), "main") && he->stat.period == 100);
0183
0184 node = rb_next(node);
0185 he = rb_entry(node, struct hist_entry, rb_node);
0186 TEST_ASSERT_VAL("Invalid hist entry",
0187 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
0188 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
0189
0190 node = rb_next(node);
0191 he = rb_entry(node, struct hist_entry, rb_node);
0192 TEST_ASSERT_VAL("Invalid hist entry",
0193 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
0194 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
0195
0196 node = rb_next(node);
0197 he = rb_entry(node, struct hist_entry, rb_node);
0198 TEST_ASSERT_VAL("Invalid hist entry",
0199 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
0200 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
0201
0202 node = rb_next(node);
0203 he = rb_entry(node, struct hist_entry, rb_node);
0204 TEST_ASSERT_VAL("Invalid hist entry",
0205 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
0206 !strcmp(SYM(he), "free") && he->stat.period == 100);
0207
0208 node = rb_next(node);
0209 he = rb_entry(node, struct hist_entry, rb_node);
0210 TEST_ASSERT_VAL("Invalid hist entry",
0211 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
0212 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
0213
0214 node = rb_next(node);
0215 he = rb_entry(node, struct hist_entry, rb_node);
0216 TEST_ASSERT_VAL("Invalid hist entry",
0217 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
0218 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
0219
0220 out:
0221 del_hist_entries(hists);
0222 reset_output_field();
0223 return err;
0224 }
0225
0226
0227 static int test2(struct evsel *evsel, struct machine *machine)
0228 {
0229 int err;
0230 struct hists *hists = evsel__hists(evsel);
0231 struct hist_entry *he;
0232 struct rb_root_cached *root;
0233 struct rb_node *node;
0234
0235 field_order = "overhead,cpu";
0236 sort_order = "pid";
0237
0238 setup_sorting(NULL);
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253 err = add_hist_entries(hists, machine);
0254 if (err < 0)
0255 goto out;
0256
0257 hists__collapse_resort(hists, NULL);
0258 evsel__output_resort(evsel, NULL);
0259
0260 if (verbose > 2) {
0261 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
0262 print_hists_out(hists);
0263 }
0264
0265 root = &hists->entries;
0266 node = rb_first_cached(root);
0267 he = rb_entry(node, struct hist_entry, rb_node);
0268 TEST_ASSERT_VAL("Invalid hist entry",
0269 CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);
0270
0271 node = rb_next(node);
0272 he = rb_entry(node, struct hist_entry, rb_node);
0273 TEST_ASSERT_VAL("Invalid hist entry",
0274 CPU(he) == 0 && PID(he) == 100 && he->stat.period == 100);
0275
0276 out:
0277 del_hist_entries(hists);
0278 reset_output_field();
0279 return err;
0280 }
0281
0282
0283 static int test3(struct evsel *evsel, struct machine *machine)
0284 {
0285 int err;
0286 struct hists *hists = evsel__hists(evsel);
0287 struct hist_entry *he;
0288 struct rb_root_cached *root;
0289 struct rb_node *node;
0290
0291 field_order = "comm,overhead,dso";
0292 sort_order = NULL;
0293
0294 setup_sorting(NULL);
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307 err = add_hist_entries(hists, machine);
0308 if (err < 0)
0309 goto out;
0310
0311 hists__collapse_resort(hists, NULL);
0312 evsel__output_resort(evsel, NULL);
0313
0314 if (verbose > 2) {
0315 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
0316 print_hists_out(hists);
0317 }
0318
0319 root = &hists->entries;
0320 node = rb_first_cached(root);
0321 he = rb_entry(node, struct hist_entry, rb_node);
0322 TEST_ASSERT_VAL("Invalid hist entry",
0323 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
0324 he->stat.period == 200);
0325
0326 node = rb_next(node);
0327 he = rb_entry(node, struct hist_entry, rb_node);
0328 TEST_ASSERT_VAL("Invalid hist entry",
0329 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
0330 he->stat.period == 100);
0331
0332 node = rb_next(node);
0333 he = rb_entry(node, struct hist_entry, rb_node);
0334 TEST_ASSERT_VAL("Invalid hist entry",
0335 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
0336 he->stat.period == 300);
0337
0338 node = rb_next(node);
0339 he = rb_entry(node, struct hist_entry, rb_node);
0340 TEST_ASSERT_VAL("Invalid hist entry",
0341 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
0342 he->stat.period == 200);
0343
0344 node = rb_next(node);
0345 he = rb_entry(node, struct hist_entry, rb_node);
0346 TEST_ASSERT_VAL("Invalid hist entry",
0347 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
0348 he->stat.period == 200);
0349
0350 out:
0351 del_hist_entries(hists);
0352 reset_output_field();
0353 return err;
0354 }
0355
0356
0357 static int test4(struct evsel *evsel, struct machine *machine)
0358 {
0359 int err;
0360 struct hists *hists = evsel__hists(evsel);
0361 struct hist_entry *he;
0362 struct rb_root_cached *root;
0363 struct rb_node *node;
0364
0365 field_order = "dso,sym,comm,overhead,dso";
0366 sort_order = "sym";
0367
0368 setup_sorting(NULL);
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385 err = add_hist_entries(hists, machine);
0386 if (err < 0)
0387 goto out;
0388
0389 hists__collapse_resort(hists, NULL);
0390 evsel__output_resort(evsel, NULL);
0391
0392 if (verbose > 2) {
0393 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
0394 print_hists_out(hists);
0395 }
0396
0397 root = &hists->entries;
0398 node = rb_first_cached(root);
0399 he = rb_entry(node, struct hist_entry, rb_node);
0400 TEST_ASSERT_VAL("Invalid hist entry",
0401 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&
0402 !strcmp(COMM(he), "perf") && he->stat.period == 100);
0403
0404 node = rb_next(node);
0405 he = rb_entry(node, struct hist_entry, rb_node);
0406 TEST_ASSERT_VAL("Invalid hist entry",
0407 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "free") &&
0408 !strcmp(COMM(he), "perf") && he->stat.period == 100);
0409
0410 node = rb_next(node);
0411 he = rb_entry(node, struct hist_entry, rb_node);
0412 TEST_ASSERT_VAL("Invalid hist entry",
0413 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "main") &&
0414 !strcmp(COMM(he), "bash") && he->stat.period == 100);
0415
0416 node = rb_next(node);
0417 he = rb_entry(node, struct hist_entry, rb_node);
0418 TEST_ASSERT_VAL("Invalid hist entry",
0419 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "main") &&
0420 !strcmp(COMM(he), "perf") && he->stat.period == 200);
0421
0422 node = rb_next(node);
0423 he = rb_entry(node, struct hist_entry, rb_node);
0424 TEST_ASSERT_VAL("Invalid hist entry",
0425 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "malloc") &&
0426 !strcmp(COMM(he), "perf") && he->stat.period == 100);
0427
0428 node = rb_next(node);
0429 he = rb_entry(node, struct hist_entry, rb_node);
0430 TEST_ASSERT_VAL("Invalid hist entry",
0431 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
0432 !strcmp(COMM(he), "bash") && he->stat.period == 100);
0433
0434 node = rb_next(node);
0435 he = rb_entry(node, struct hist_entry, rb_node);
0436 TEST_ASSERT_VAL("Invalid hist entry",
0437 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
0438 !strcmp(COMM(he), "perf") && he->stat.period == 100);
0439
0440 node = rb_next(node);
0441 he = rb_entry(node, struct hist_entry, rb_node);
0442 TEST_ASSERT_VAL("Invalid hist entry",
0443 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "schedule") &&
0444 !strcmp(COMM(he), "perf") && he->stat.period == 100);
0445
0446 node = rb_next(node);
0447 he = rb_entry(node, struct hist_entry, rb_node);
0448 TEST_ASSERT_VAL("Invalid hist entry",
0449 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "xmalloc") &&
0450 !strcmp(COMM(he), "bash") && he->stat.period == 100);
0451
0452 out:
0453 del_hist_entries(hists);
0454 reset_output_field();
0455 return err;
0456 }
0457
0458
0459 static int test5(struct evsel *evsel, struct machine *machine)
0460 {
0461 int err;
0462 struct hists *hists = evsel__hists(evsel);
0463 struct hist_entry *he;
0464 struct rb_root_cached *root;
0465 struct rb_node *node;
0466
0467 field_order = "cpu,pid,comm,dso,sym";
0468 sort_order = "dso,pid";
0469
0470 setup_sorting(NULL);
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488 err = add_hist_entries(hists, machine);
0489 if (err < 0)
0490 goto out;
0491
0492 hists__collapse_resort(hists, NULL);
0493 evsel__output_resort(evsel, NULL);
0494
0495 if (verbose > 2) {
0496 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
0497 print_hists_out(hists);
0498 }
0499
0500 root = &hists->entries;
0501 node = rb_first_cached(root);
0502 he = rb_entry(node, struct hist_entry, rb_node);
0503
0504 TEST_ASSERT_VAL("Invalid hist entry",
0505 CPU(he) == 0 && PID(he) == 100 &&
0506 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
0507 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
0508
0509 node = rb_next(node);
0510 he = rb_entry(node, struct hist_entry, rb_node);
0511 TEST_ASSERT_VAL("Invalid hist entry",
0512 CPU(he) == 2 && PID(he) == 200 &&
0513 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
0514 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
0515
0516 node = rb_next(node);
0517 he = rb_entry(node, struct hist_entry, rb_node);
0518 TEST_ASSERT_VAL("Invalid hist entry",
0519 CPU(he) == 1 && PID(he) == 300 &&
0520 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
0521 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
0522
0523 node = rb_next(node);
0524 he = rb_entry(node, struct hist_entry, rb_node);
0525 TEST_ASSERT_VAL("Invalid hist entry",
0526 CPU(he) == 0 && PID(he) == 300 &&
0527 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
0528 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
0529
0530 node = rb_next(node);
0531 he = rb_entry(node, struct hist_entry, rb_node);
0532 TEST_ASSERT_VAL("Invalid hist entry",
0533 CPU(he) == 3 && PID(he) == 300 &&
0534 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
0535 !strcmp(SYM(he), "main") && he->stat.period == 100);
0536
0537 node = rb_next(node);
0538 he = rb_entry(node, struct hist_entry, rb_node);
0539 TEST_ASSERT_VAL("Invalid hist entry",
0540 CPU(he) == 1 && PID(he) == 100 &&
0541 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
0542 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
0543
0544 node = rb_next(node);
0545 he = rb_entry(node, struct hist_entry, rb_node);
0546 TEST_ASSERT_VAL("Invalid hist entry",
0547 CPU(he) == 2 && PID(he) == 100 &&
0548 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
0549 !strcmp(SYM(he), "free") && he->stat.period == 100);
0550
0551 node = rb_next(node);
0552 he = rb_entry(node, struct hist_entry, rb_node);
0553 TEST_ASSERT_VAL("Invalid hist entry",
0554 CPU(he) == 1 && PID(he) == 100 &&
0555 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
0556 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
0557
0558 node = rb_next(node);
0559 he = rb_entry(node, struct hist_entry, rb_node);
0560 TEST_ASSERT_VAL("Invalid hist entry",
0561 CPU(he) == 1 && PID(he) == 100 &&
0562 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
0563 !strcmp(SYM(he), "main") && he->stat.period == 100);
0564
0565 node = rb_next(node);
0566 he = rb_entry(node, struct hist_entry, rb_node);
0567 TEST_ASSERT_VAL("Invalid hist entry",
0568 CPU(he) == 2 && PID(he) == 200 &&
0569 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
0570 !strcmp(SYM(he), "main") && he->stat.period == 100);
0571
0572 out:
0573 del_hist_entries(hists);
0574 reset_output_field();
0575 return err;
0576 }
0577
0578 static int test__hists_output(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0579 {
0580 int err = TEST_FAIL;
0581 struct machines machines;
0582 struct machine *machine;
0583 struct evsel *evsel;
0584 struct evlist *evlist = evlist__new();
0585 size_t i;
0586 test_fn_t testcases[] = {
0587 test1,
0588 test2,
0589 test3,
0590 test4,
0591 test5,
0592 };
0593
0594 TEST_ASSERT_VAL("No memory", evlist);
0595
0596 err = parse_event(evlist, "cpu-clock");
0597 if (err)
0598 goto out;
0599 err = TEST_FAIL;
0600
0601 machines__init(&machines);
0602
0603
0604 machine = setup_fake_machine(&machines);
0605 if (!machine)
0606 goto out;
0607
0608 if (verbose > 1)
0609 machine__fprintf(machine, stderr);
0610
0611 evsel = evlist__first(evlist);
0612
0613 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
0614 err = testcases[i](evsel, machine);
0615 if (err < 0)
0616 break;
0617 }
0618
0619 out:
0620
0621 evlist__delete(evlist);
0622 machines__exit(&machines);
0623
0624 return err;
0625 }
0626
0627 DEFINE_SUITE("Sort output of hist entries", hists_output);