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