linux/tools/perf/tests/hists_filter.c
<<
>>
Prefs
   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
 104int test__hists_filter(struct test *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_events[PERF_RECORD_SAMPLE] == 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_events[PERF_RECORD_SAMPLE] ==
 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_events[PERF_RECORD_SAMPLE] == 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_events[PERF_RECORD_SAMPLE] == 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_events[PERF_RECORD_SAMPLE] == 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_events[PERF_RECORD_SAMPLE] == 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_events[PERF_RECORD_SAMPLE] == 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