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_filter.c (9811B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include "util/debug.h"
      3#include "util/map.h"
      4#include "util/symbol.h"
      5#include "util/sort.h"
      6#include "util/evsel.h"
      7#include "util/event.h"
      8#include "util/evlist.h"
      9#include "util/machine.h"
     10#include "util/parse-events.h"
     11#include "tests/tests.h"
     12#include "tests/hists_common.h"
     13#include <linux/kernel.h>
     14
     15struct sample {
     16	u32 pid;
     17	u64 ip;
     18	struct thread *thread;
     19	struct map *map;
     20	struct symbol *sym;
     21	int socket;
     22};
     23
     24/* For the numbers, see hists_common.c */
     25static struct sample fake_samples[] = {
     26	/* perf [kernel] schedule() */
     27	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, .socket = 0 },
     28	/* perf [perf]   main() */
     29	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, .socket = 0 },
     30	/* perf [libc]   malloc() */
     31	{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, .socket = 0 },
     32	/* perf [perf]   main() */
     33	{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, .socket = 0 }, /* will be merged */
     34	/* perf [perf]   cmd_record() */
     35	{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, .socket = 1 },
     36	/* perf [kernel] page_fault() */
     37	{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 1 },
     38	/* bash [bash]   main() */
     39	{ .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_MAIN, .socket = 2 },
     40	/* bash [bash]   xmalloc() */
     41	{ .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_XMALLOC, .socket = 2 },
     42	/* bash [libc]   malloc() */
     43	{ .pid = FAKE_PID_BASH,  .ip = FAKE_IP_LIBC_MALLOC, .socket = 3 },
     44	/* bash [kernel] page_fault() */
     45	{ .pid = FAKE_PID_BASH,  .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 3 },
     46};
     47
     48static int add_hist_entries(struct evlist *evlist,
     49			    struct machine *machine)
     50{
     51	struct evsel *evsel;
     52	struct addr_location al;
     53	struct perf_sample sample = { .period = 100, };
     54	size_t i;
     55
     56	/*
     57	 * each evsel will have 10 samples but the 4th sample
     58	 * (perf [perf] main) will be collapsed to an existing entry
     59	 * so total 9 entries will be in the tree.
     60	 */
     61	evlist__for_each_entry(evlist, evsel) {
     62		for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
     63			struct hist_entry_iter iter = {
     64				.evsel = evsel,
     65				.sample = &sample,
     66				.ops = &hist_iter_normal,
     67				.hide_unresolved = false,
     68			};
     69			struct hists *hists = evsel__hists(evsel);
     70
     71			/* make sure it has no filter at first */
     72			hists->thread_filter = NULL;
     73			hists->dso_filter = NULL;
     74			hists->symbol_filter_str = NULL;
     75
     76			sample.cpumode = PERF_RECORD_MISC_USER;
     77			sample.pid = fake_samples[i].pid;
     78			sample.tid = fake_samples[i].pid;
     79			sample.ip = fake_samples[i].ip;
     80
     81			if (machine__resolve(machine, &al, &sample) < 0)
     82				goto out;
     83
     84			al.socket = fake_samples[i].socket;
     85			if (hist_entry_iter__add(&iter, &al,
     86						 sysctl_perf_event_max_stack, NULL) < 0) {
     87				addr_location__put(&al);
     88				goto out;
     89			}
     90
     91			fake_samples[i].thread = al.thread;
     92			fake_samples[i].map = al.map;
     93			fake_samples[i].sym = al.sym;
     94		}
     95	}
     96
     97	return 0;
     98
     99out:
    100	pr_debug("Not enough memory for adding a hist entry\n");
    101	return TEST_FAIL;
    102}
    103
    104static int test__hists_filter(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
    105{
    106	int err = TEST_FAIL;
    107	struct machines machines;
    108	struct machine *machine;
    109	struct evsel *evsel;
    110	struct evlist *evlist = evlist__new();
    111
    112	TEST_ASSERT_VAL("No memory", evlist);
    113
    114	err = parse_events(evlist, "cpu-clock", NULL);
    115	if (err)
    116		goto out;
    117	err = parse_events(evlist, "task-clock", NULL);
    118	if (err)
    119		goto out;
    120	err = TEST_FAIL;
    121
    122	/* default sort order (comm,dso,sym) will be used */
    123	if (setup_sorting(NULL) < 0)
    124		goto out;
    125
    126	machines__init(&machines);
    127
    128	/* setup threads/dso/map/symbols also */
    129	machine = setup_fake_machine(&machines);
    130	if (!machine)
    131		goto out;
    132
    133	if (verbose > 1)
    134		machine__fprintf(machine, stderr);
    135
    136	/* process sample events */
    137	err = add_hist_entries(evlist, machine);
    138	if (err < 0)
    139		goto out;
    140
    141	evlist__for_each_entry(evlist, evsel) {
    142		struct hists *hists = evsel__hists(evsel);
    143
    144		hists__collapse_resort(hists, NULL);
    145		evsel__output_resort(evsel, NULL);
    146
    147		if (verbose > 2) {
    148			pr_info("Normal histogram\n");
    149			print_hists_out(hists);
    150		}
    151
    152		TEST_ASSERT_VAL("Invalid nr samples",
    153				hists->stats.nr_samples == 10);
    154		TEST_ASSERT_VAL("Invalid nr hist entries",
    155				hists->nr_entries == 9);
    156		TEST_ASSERT_VAL("Invalid total period",
    157				hists->stats.total_period == 1000);
    158		TEST_ASSERT_VAL("Unmatched nr samples",
    159				hists->stats.nr_samples ==
    160				hists->stats.nr_non_filtered_samples);
    161		TEST_ASSERT_VAL("Unmatched nr hist entries",
    162				hists->nr_entries == hists->nr_non_filtered_entries);
    163		TEST_ASSERT_VAL("Unmatched total period",
    164				hists->stats.total_period ==
    165				hists->stats.total_non_filtered_period);
    166
    167		/* now applying thread filter for 'bash' */
    168		hists->thread_filter = fake_samples[9].thread;
    169		hists__filter_by_thread(hists);
    170
    171		if (verbose > 2) {
    172			pr_info("Histogram for thread filter\n");
    173			print_hists_out(hists);
    174		}
    175
    176		/* normal stats should be invariant */
    177		TEST_ASSERT_VAL("Invalid nr samples",
    178				hists->stats.nr_samples == 10);
    179		TEST_ASSERT_VAL("Invalid nr hist entries",
    180				hists->nr_entries == 9);
    181		TEST_ASSERT_VAL("Invalid total period",
    182				hists->stats.total_period == 1000);
    183
    184		/* but filter stats are changed */
    185		TEST_ASSERT_VAL("Unmatched nr samples for thread filter",
    186				hists->stats.nr_non_filtered_samples == 4);
    187		TEST_ASSERT_VAL("Unmatched nr hist entries for thread filter",
    188				hists->nr_non_filtered_entries == 4);
    189		TEST_ASSERT_VAL("Unmatched total period for thread filter",
    190				hists->stats.total_non_filtered_period == 400);
    191
    192		/* remove thread filter first */
    193		hists->thread_filter = NULL;
    194		hists__filter_by_thread(hists);
    195
    196		/* now applying dso filter for 'kernel' */
    197		hists->dso_filter = fake_samples[0].map->dso;
    198		hists__filter_by_dso(hists);
    199
    200		if (verbose > 2) {
    201			pr_info("Histogram for dso filter\n");
    202			print_hists_out(hists);
    203		}
    204
    205		/* normal stats should be invariant */
    206		TEST_ASSERT_VAL("Invalid nr samples",
    207				hists->stats.nr_samples == 10);
    208		TEST_ASSERT_VAL("Invalid nr hist entries",
    209				hists->nr_entries == 9);
    210		TEST_ASSERT_VAL("Invalid total period",
    211				hists->stats.total_period == 1000);
    212
    213		/* but filter stats are changed */
    214		TEST_ASSERT_VAL("Unmatched nr samples for dso filter",
    215				hists->stats.nr_non_filtered_samples == 3);
    216		TEST_ASSERT_VAL("Unmatched nr hist entries for dso filter",
    217				hists->nr_non_filtered_entries == 3);
    218		TEST_ASSERT_VAL("Unmatched total period for dso filter",
    219				hists->stats.total_non_filtered_period == 300);
    220
    221		/* remove dso filter first */
    222		hists->dso_filter = NULL;
    223		hists__filter_by_dso(hists);
    224
    225		/*
    226		 * now applying symbol filter for 'main'.  Also note that
    227		 * there's 3 samples that have 'main' symbol but the 4th
    228		 * entry of fake_samples was collapsed already so it won't
    229		 * be counted as a separate entry but the sample count and
    230		 * total period will be remained.
    231		 */
    232		hists->symbol_filter_str = "main";
    233		hists__filter_by_symbol(hists);
    234
    235		if (verbose > 2) {
    236			pr_info("Histogram for symbol filter\n");
    237			print_hists_out(hists);
    238		}
    239
    240		/* normal stats should be invariant */
    241		TEST_ASSERT_VAL("Invalid nr samples",
    242				hists->stats.nr_samples == 10);
    243		TEST_ASSERT_VAL("Invalid nr hist entries",
    244				hists->nr_entries == 9);
    245		TEST_ASSERT_VAL("Invalid total period",
    246				hists->stats.total_period == 1000);
    247
    248		/* but filter stats are changed */
    249		TEST_ASSERT_VAL("Unmatched nr samples for symbol filter",
    250				hists->stats.nr_non_filtered_samples == 3);
    251		TEST_ASSERT_VAL("Unmatched nr hist entries for symbol filter",
    252				hists->nr_non_filtered_entries == 2);
    253		TEST_ASSERT_VAL("Unmatched total period for symbol filter",
    254				hists->stats.total_non_filtered_period == 300);
    255
    256		/* remove symbol filter first */
    257		hists->symbol_filter_str = NULL;
    258		hists__filter_by_symbol(hists);
    259
    260		/* now applying socket filters */
    261		hists->socket_filter = 2;
    262		hists__filter_by_socket(hists);
    263
    264		if (verbose > 2) {
    265			pr_info("Histogram for socket filters\n");
    266			print_hists_out(hists);
    267		}
    268
    269		/* normal stats should be invariant */
    270		TEST_ASSERT_VAL("Invalid nr samples",
    271				hists->stats.nr_samples == 10);
    272		TEST_ASSERT_VAL("Invalid nr hist entries",
    273				hists->nr_entries == 9);
    274		TEST_ASSERT_VAL("Invalid total period",
    275				hists->stats.total_period == 1000);
    276
    277		/* but filter stats are changed */
    278		TEST_ASSERT_VAL("Unmatched nr samples for socket filter",
    279				hists->stats.nr_non_filtered_samples == 2);
    280		TEST_ASSERT_VAL("Unmatched nr hist entries for socket filter",
    281				hists->nr_non_filtered_entries == 2);
    282		TEST_ASSERT_VAL("Unmatched total period for socket filter",
    283				hists->stats.total_non_filtered_period == 200);
    284
    285		/* remove socket filter first */
    286		hists->socket_filter = -1;
    287		hists__filter_by_socket(hists);
    288
    289		/* now applying all filters at once. */
    290		hists->thread_filter = fake_samples[1].thread;
    291		hists->dso_filter = fake_samples[1].map->dso;
    292		hists__filter_by_thread(hists);
    293		hists__filter_by_dso(hists);
    294
    295		if (verbose > 2) {
    296			pr_info("Histogram for all filters\n");
    297			print_hists_out(hists);
    298		}
    299
    300		/* normal stats should be invariant */
    301		TEST_ASSERT_VAL("Invalid nr samples",
    302				hists->stats.nr_samples == 10);
    303		TEST_ASSERT_VAL("Invalid nr hist entries",
    304				hists->nr_entries == 9);
    305		TEST_ASSERT_VAL("Invalid total period",
    306				hists->stats.total_period == 1000);
    307
    308		/* but filter stats are changed */
    309		TEST_ASSERT_VAL("Unmatched nr samples for all filter",
    310				hists->stats.nr_non_filtered_samples == 2);
    311		TEST_ASSERT_VAL("Unmatched nr hist entries for all filter",
    312				hists->nr_non_filtered_entries == 1);
    313		TEST_ASSERT_VAL("Unmatched total period for all filter",
    314				hists->stats.total_non_filtered_period == 200);
    315	}
    316
    317
    318	err = TEST_OK;
    319
    320out:
    321	/* tear down everything */
    322	evlist__delete(evlist);
    323	reset_output_field();
    324	machines__exit(&machines);
    325
    326	return err;
    327}
    328
    329DEFINE_SUITE("Filter hist entries", hists_filter);