root/tools/perf/arch/arm64/util/arm-spe.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. arm_spe_info_priv_size
  2. arm_spe_info_fill
  3. arm_spe_recording_options
  4. arm_spe_reference
  5. arm_spe_recording_free
  6. arm_spe_read_finish
  7. arm_spe_recording_init
  8. arm_spe_pmu_default_config

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Arm Statistical Profiling Extensions (SPE) support
   4  * Copyright (c) 2017-2018, Arm Ltd.
   5  */
   6 
   7 #include <linux/kernel.h>
   8 #include <linux/types.h>
   9 #include <linux/bitops.h>
  10 #include <linux/log2.h>
  11 #include <linux/zalloc.h>
  12 #include <time.h>
  13 
  14 #include "../../util/cpumap.h"
  15 #include "../../util/event.h"
  16 #include "../../util/evsel.h"
  17 #include "../../util/evlist.h"
  18 #include "../../util/session.h"
  19 #include <internal/lib.h> // page_size
  20 #include "../../util/pmu.h"
  21 #include "../../util/debug.h"
  22 #include "../../util/auxtrace.h"
  23 #include "../../util/record.h"
  24 #include "../../util/arm-spe.h"
  25 
  26 #define KiB(x) ((x) * 1024)
  27 #define MiB(x) ((x) * 1024 * 1024)
  28 
  29 struct arm_spe_recording {
  30         struct auxtrace_record          itr;
  31         struct perf_pmu                 *arm_spe_pmu;
  32         struct evlist           *evlist;
  33 };
  34 
  35 static size_t
  36 arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused,
  37                        struct evlist *evlist __maybe_unused)
  38 {
  39         return ARM_SPE_AUXTRACE_PRIV_SIZE;
  40 }
  41 
  42 static int arm_spe_info_fill(struct auxtrace_record *itr,
  43                              struct perf_session *session,
  44                              struct perf_record_auxtrace_info *auxtrace_info,
  45                              size_t priv_size)
  46 {
  47         struct arm_spe_recording *sper =
  48                         container_of(itr, struct arm_spe_recording, itr);
  49         struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
  50 
  51         if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE)
  52                 return -EINVAL;
  53 
  54         if (!session->evlist->core.nr_mmaps)
  55                 return -EINVAL;
  56 
  57         auxtrace_info->type = PERF_AUXTRACE_ARM_SPE;
  58         auxtrace_info->priv[ARM_SPE_PMU_TYPE] = arm_spe_pmu->type;
  59 
  60         return 0;
  61 }
  62 
  63 static int arm_spe_recording_options(struct auxtrace_record *itr,
  64                                      struct evlist *evlist,
  65                                      struct record_opts *opts)
  66 {
  67         struct arm_spe_recording *sper =
  68                         container_of(itr, struct arm_spe_recording, itr);
  69         struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
  70         struct evsel *evsel, *arm_spe_evsel = NULL;
  71         bool privileged = perf_event_paranoid_check(-1);
  72         struct evsel *tracking_evsel;
  73         int err;
  74 
  75         sper->evlist = evlist;
  76 
  77         evlist__for_each_entry(evlist, evsel) {
  78                 if (evsel->core.attr.type == arm_spe_pmu->type) {
  79                         if (arm_spe_evsel) {
  80                                 pr_err("There may be only one " ARM_SPE_PMU_NAME "x event\n");
  81                                 return -EINVAL;
  82                         }
  83                         evsel->core.attr.freq = 0;
  84                         evsel->core.attr.sample_period = 1;
  85                         arm_spe_evsel = evsel;
  86                         opts->full_auxtrace = true;
  87                 }
  88         }
  89 
  90         if (!opts->full_auxtrace)
  91                 return 0;
  92 
  93         /* We are in full trace mode but '-m,xyz' wasn't specified */
  94         if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
  95                 if (privileged) {
  96                         opts->auxtrace_mmap_pages = MiB(4) / page_size;
  97                 } else {
  98                         opts->auxtrace_mmap_pages = KiB(128) / page_size;
  99                         if (opts->mmap_pages == UINT_MAX)
 100                                 opts->mmap_pages = KiB(256) / page_size;
 101                 }
 102         }
 103 
 104         /* Validate auxtrace_mmap_pages */
 105         if (opts->auxtrace_mmap_pages) {
 106                 size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
 107                 size_t min_sz = KiB(8);
 108 
 109                 if (sz < min_sz || !is_power_of_2(sz)) {
 110                         pr_err("Invalid mmap size for ARM SPE: must be at least %zuKiB and a power of 2\n",
 111                                min_sz / 1024);
 112                         return -EINVAL;
 113                 }
 114         }
 115 
 116 
 117         /*
 118          * To obtain the auxtrace buffer file descriptor, the auxtrace event
 119          * must come first.
 120          */
 121         perf_evlist__to_front(evlist, arm_spe_evsel);
 122 
 123         perf_evsel__set_sample_bit(arm_spe_evsel, CPU);
 124         perf_evsel__set_sample_bit(arm_spe_evsel, TIME);
 125         perf_evsel__set_sample_bit(arm_spe_evsel, TID);
 126 
 127         /* Add dummy event to keep tracking */
 128         err = parse_events(evlist, "dummy:u", NULL);
 129         if (err)
 130                 return err;
 131 
 132         tracking_evsel = evlist__last(evlist);
 133         perf_evlist__set_tracking_event(evlist, tracking_evsel);
 134 
 135         tracking_evsel->core.attr.freq = 0;
 136         tracking_evsel->core.attr.sample_period = 1;
 137         perf_evsel__set_sample_bit(tracking_evsel, TIME);
 138         perf_evsel__set_sample_bit(tracking_evsel, CPU);
 139         perf_evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK);
 140 
 141         return 0;
 142 }
 143 
 144 static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused)
 145 {
 146         struct timespec ts;
 147 
 148         clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
 149 
 150         return ts.tv_sec ^ ts.tv_nsec;
 151 }
 152 
 153 static void arm_spe_recording_free(struct auxtrace_record *itr)
 154 {
 155         struct arm_spe_recording *sper =
 156                         container_of(itr, struct arm_spe_recording, itr);
 157 
 158         free(sper);
 159 }
 160 
 161 static int arm_spe_read_finish(struct auxtrace_record *itr, int idx)
 162 {
 163         struct arm_spe_recording *sper =
 164                         container_of(itr, struct arm_spe_recording, itr);
 165         struct evsel *evsel;
 166 
 167         evlist__for_each_entry(sper->evlist, evsel) {
 168                 if (evsel->core.attr.type == sper->arm_spe_pmu->type) {
 169                         if (evsel->disabled)
 170                                 return 0;
 171                         return perf_evlist__enable_event_idx(sper->evlist,
 172                                                              evsel, idx);
 173                 }
 174         }
 175         return -EINVAL;
 176 }
 177 
 178 struct auxtrace_record *arm_spe_recording_init(int *err,
 179                                                struct perf_pmu *arm_spe_pmu)
 180 {
 181         struct arm_spe_recording *sper;
 182 
 183         if (!arm_spe_pmu) {
 184                 *err = -ENODEV;
 185                 return NULL;
 186         }
 187 
 188         sper = zalloc(sizeof(struct arm_spe_recording));
 189         if (!sper) {
 190                 *err = -ENOMEM;
 191                 return NULL;
 192         }
 193 
 194         sper->arm_spe_pmu = arm_spe_pmu;
 195         sper->itr.recording_options = arm_spe_recording_options;
 196         sper->itr.info_priv_size = arm_spe_info_priv_size;
 197         sper->itr.info_fill = arm_spe_info_fill;
 198         sper->itr.free = arm_spe_recording_free;
 199         sper->itr.reference = arm_spe_reference;
 200         sper->itr.read_finish = arm_spe_read_finish;
 201         sper->itr.alignment = 0;
 202 
 203         *err = 0;
 204         return &sper->itr;
 205 }
 206 
 207 struct perf_event_attr
 208 *arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu)
 209 {
 210         struct perf_event_attr *attr;
 211 
 212         attr = zalloc(sizeof(struct perf_event_attr));
 213         if (!attr) {
 214                 pr_err("arm_spe default config cannot allocate a perf_event_attr\n");
 215                 return NULL;
 216         }
 217 
 218         /*
 219          * If kernel driver doesn't advertise a minimum,
 220          * use max allowable by PMSIDR_EL1.INTERVAL
 221          */
 222         if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu",
 223                                   &attr->sample_period) != 1) {
 224                 pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n");
 225                 attr->sample_period = 4096;
 226         }
 227 
 228         arm_spe_pmu->selectable = true;
 229         arm_spe_pmu->is_uncore = false;
 230 
 231         return attr;
 232 }

/* [<][>][^][v][top][bottom][index][help] */