linux/tools/perf/tests/event-times.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/compiler.h>
   3#include <errno.h>
   4#include <inttypes.h>
   5#include <string.h>
   6#include <sys/wait.h>
   7#include "tests.h"
   8#include "evlist.h"
   9#include "evsel.h"
  10#include "util.h"
  11#include "debug.h"
  12#include "thread_map.h"
  13#include "target.h"
  14
  15static int attach__enable_on_exec(struct perf_evlist *evlist)
  16{
  17        struct perf_evsel *evsel = perf_evlist__last(evlist);
  18        struct target target = {
  19                .uid = UINT_MAX,
  20        };
  21        const char *argv[] = { "true", NULL, };
  22        char sbuf[STRERR_BUFSIZE];
  23        int err;
  24
  25        pr_debug("attaching to spawned child, enable on exec\n");
  26
  27        err = perf_evlist__create_maps(evlist, &target);
  28        if (err < 0) {
  29                pr_debug("Not enough memory to create thread/cpu maps\n");
  30                return err;
  31        }
  32
  33        err = perf_evlist__prepare_workload(evlist, &target, argv, false, NULL);
  34        if (err < 0) {
  35                pr_debug("Couldn't run the workload!\n");
  36                return err;
  37        }
  38
  39        evsel->attr.enable_on_exec = 1;
  40
  41        err = perf_evlist__open(evlist);
  42        if (err < 0) {
  43                pr_debug("perf_evlist__open: %s\n",
  44                         str_error_r(errno, sbuf, sizeof(sbuf)));
  45                return err;
  46        }
  47
  48        return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL;
  49}
  50
  51static int detach__enable_on_exec(struct perf_evlist *evlist)
  52{
  53        waitpid(evlist->workload.pid, NULL, 0);
  54        return 0;
  55}
  56
  57static int attach__current_disabled(struct perf_evlist *evlist)
  58{
  59        struct perf_evsel *evsel = perf_evlist__last(evlist);
  60        struct thread_map *threads;
  61        int err;
  62
  63        pr_debug("attaching to current thread as disabled\n");
  64
  65        threads = thread_map__new(-1, getpid(), UINT_MAX);
  66        if (threads == NULL) {
  67                pr_debug("thread_map__new\n");
  68                return -1;
  69        }
  70
  71        evsel->attr.disabled = 1;
  72
  73        err = perf_evsel__open_per_thread(evsel, threads);
  74        if (err) {
  75                pr_debug("Failed to open event cpu-clock:u\n");
  76                return err;
  77        }
  78
  79        thread_map__put(threads);
  80        return perf_evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL;
  81}
  82
  83static int attach__current_enabled(struct perf_evlist *evlist)
  84{
  85        struct perf_evsel *evsel = perf_evlist__last(evlist);
  86        struct thread_map *threads;
  87        int err;
  88
  89        pr_debug("attaching to current thread as enabled\n");
  90
  91        threads = thread_map__new(-1, getpid(), UINT_MAX);
  92        if (threads == NULL) {
  93                pr_debug("failed to call thread_map__new\n");
  94                return -1;
  95        }
  96
  97        err = perf_evsel__open_per_thread(evsel, threads);
  98
  99        thread_map__put(threads);
 100        return err == 0 ? TEST_OK : TEST_FAIL;
 101}
 102
 103static int detach__disable(struct perf_evlist *evlist)
 104{
 105        struct perf_evsel *evsel = perf_evlist__last(evlist);
 106
 107        return perf_evsel__enable(evsel);
 108}
 109
 110static int attach__cpu_disabled(struct perf_evlist *evlist)
 111{
 112        struct perf_evsel *evsel = perf_evlist__last(evlist);
 113        struct cpu_map *cpus;
 114        int err;
 115
 116        pr_debug("attaching to CPU 0 as enabled\n");
 117
 118        cpus = cpu_map__new("0");
 119        if (cpus == NULL) {
 120                pr_debug("failed to call cpu_map__new\n");
 121                return -1;
 122        }
 123
 124        evsel->attr.disabled = 1;
 125
 126        err = perf_evsel__open_per_cpu(evsel, cpus);
 127        if (err) {
 128                if (err == -EACCES)
 129                        return TEST_SKIP;
 130
 131                pr_debug("Failed to open event cpu-clock:u\n");
 132                return err;
 133        }
 134
 135        cpu_map__put(cpus);
 136        return perf_evsel__enable(evsel);
 137}
 138
 139static int attach__cpu_enabled(struct perf_evlist *evlist)
 140{
 141        struct perf_evsel *evsel = perf_evlist__last(evlist);
 142        struct cpu_map *cpus;
 143        int err;
 144
 145        pr_debug("attaching to CPU 0 as enabled\n");
 146
 147        cpus = cpu_map__new("0");
 148        if (cpus == NULL) {
 149                pr_debug("failed to call cpu_map__new\n");
 150                return -1;
 151        }
 152
 153        err = perf_evsel__open_per_cpu(evsel, cpus);
 154        if (err == -EACCES)
 155                return TEST_SKIP;
 156
 157        cpu_map__put(cpus);
 158        return err ? TEST_FAIL : TEST_OK;
 159}
 160
 161static int test_times(int (attach)(struct perf_evlist *),
 162                      int (detach)(struct perf_evlist *))
 163{
 164        struct perf_counts_values count;
 165        struct perf_evlist *evlist = NULL;
 166        struct perf_evsel *evsel;
 167        int err = -1, i;
 168
 169        evlist = perf_evlist__new();
 170        if (!evlist) {
 171                pr_debug("failed to create event list\n");
 172                goto out_err;
 173        }
 174
 175        err = parse_events(evlist, "cpu-clock:u", NULL);
 176        if (err) {
 177                pr_debug("failed to parse event cpu-clock:u\n");
 178                goto out_err;
 179        }
 180
 181        evsel = perf_evlist__last(evlist);
 182        evsel->attr.read_format |=
 183                PERF_FORMAT_TOTAL_TIME_ENABLED |
 184                PERF_FORMAT_TOTAL_TIME_RUNNING;
 185
 186        err = attach(evlist);
 187        if (err == TEST_SKIP) {
 188                pr_debug("  SKIP  : not enough rights\n");
 189                return err;
 190        }
 191
 192        TEST_ASSERT_VAL("failed to attach", !err);
 193
 194        for (i = 0; i < 100000000; i++) { }
 195
 196        TEST_ASSERT_VAL("failed to detach", !detach(evlist));
 197
 198        perf_evsel__read(evsel, 0, 0, &count);
 199
 200        err = !(count.ena == count.run);
 201
 202        pr_debug("  %s: ena %" PRIu64", run %" PRIu64"\n",
 203                 !err ? "OK    " : "FAILED",
 204                 count.ena, count.run);
 205
 206out_err:
 207        perf_evlist__delete(evlist);
 208        return !err ? TEST_OK : TEST_FAIL;
 209}
 210
 211/*
 212 * This test creates software event 'cpu-clock'
 213 * attaches it in several ways (explained below)
 214 * and checks that enabled and running times
 215 * match.
 216 */
 217int test__event_times(struct test *test __maybe_unused, int subtest __maybe_unused)
 218{
 219        int err, ret = 0;
 220
 221#define _T(attach, detach)                      \
 222        err = test_times(attach, detach);       \
 223        if (err && (ret == TEST_OK || ret == TEST_SKIP))        \
 224                ret = err;
 225
 226        /* attach on newly spawned process after exec */
 227        _T(attach__enable_on_exec,   detach__enable_on_exec)
 228        /* attach on current process as enabled */
 229        _T(attach__current_enabled,  detach__disable)
 230        /* attach on current process as disabled */
 231        _T(attach__current_disabled, detach__disable)
 232        /* attach on cpu as disabled */
 233        _T(attach__cpu_disabled,     detach__disable)
 234        /* attach on cpu as enabled */
 235        _T(attach__cpu_enabled,      detach__disable)
 236
 237#undef _T
 238        return ret;
 239}
 240