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