linux/tools/perf/util/evsel.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
   3 *
   4 * Parts came from builtin-{top,stat,record}.c, see those files for further
   5 * copyright notes.
   6 *
   7 * Released under the GPL v2. (and only v2, not any later version)
   8 */
   9
  10#include "evsel.h"
  11#include "evlist.h"
  12#include "util.h"
  13#include "cpumap.h"
  14#include "thread_map.h"
  15
  16#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
  17
  18void perf_evsel__init(struct perf_evsel *evsel,
  19                      struct perf_event_attr *attr, int idx)
  20{
  21        evsel->idx         = idx;
  22        evsel->attr        = *attr;
  23        INIT_LIST_HEAD(&evsel->node);
  24}
  25
  26struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
  27{
  28        struct perf_evsel *evsel = zalloc(sizeof(*evsel));
  29
  30        if (evsel != NULL)
  31                perf_evsel__init(evsel, attr, idx);
  32
  33        return evsel;
  34}
  35
  36int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
  37{
  38        evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
  39        return evsel->fd != NULL ? 0 : -ENOMEM;
  40}
  41
  42int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
  43{
  44        evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
  45        if (evsel->sample_id == NULL)
  46                return -ENOMEM;
  47
  48        evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
  49        if (evsel->id == NULL) {
  50                xyarray__delete(evsel->sample_id);
  51                evsel->sample_id = NULL;
  52                return -ENOMEM;
  53        }
  54
  55        return 0;
  56}
  57
  58int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
  59{
  60        evsel->counts = zalloc((sizeof(*evsel->counts) +
  61                                (ncpus * sizeof(struct perf_counts_values))));
  62        return evsel->counts != NULL ? 0 : -ENOMEM;
  63}
  64
  65void perf_evsel__free_fd(struct perf_evsel *evsel)
  66{
  67        xyarray__delete(evsel->fd);
  68        evsel->fd = NULL;
  69}
  70
  71void perf_evsel__free_id(struct perf_evsel *evsel)
  72{
  73        xyarray__delete(evsel->sample_id);
  74        evsel->sample_id = NULL;
  75        free(evsel->id);
  76        evsel->id = NULL;
  77}
  78
  79void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
  80{
  81        int cpu, thread;
  82
  83        for (cpu = 0; cpu < ncpus; cpu++)
  84                for (thread = 0; thread < nthreads; ++thread) {
  85                        close(FD(evsel, cpu, thread));
  86                        FD(evsel, cpu, thread) = -1;
  87                }
  88}
  89
  90void perf_evsel__exit(struct perf_evsel *evsel)
  91{
  92        assert(list_empty(&evsel->node));
  93        xyarray__delete(evsel->fd);
  94        xyarray__delete(evsel->sample_id);
  95        free(evsel->id);
  96}
  97
  98void perf_evsel__delete(struct perf_evsel *evsel)
  99{
 100        perf_evsel__exit(evsel);
 101        close_cgroup(evsel->cgrp);
 102        free(evsel->name);
 103        free(evsel);
 104}
 105
 106int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
 107                              int cpu, int thread, bool scale)
 108{
 109        struct perf_counts_values count;
 110        size_t nv = scale ? 3 : 1;
 111
 112        if (FD(evsel, cpu, thread) < 0)
 113                return -EINVAL;
 114
 115        if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
 116                return -ENOMEM;
 117
 118        if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
 119                return -errno;
 120
 121        if (scale) {
 122                if (count.run == 0)
 123                        count.val = 0;
 124                else if (count.run < count.ena)
 125                        count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
 126        } else
 127                count.ena = count.run = 0;
 128
 129        evsel->counts->cpu[cpu] = count;
 130        return 0;
 131}
 132
 133int __perf_evsel__read(struct perf_evsel *evsel,
 134                       int ncpus, int nthreads, bool scale)
 135{
 136        size_t nv = scale ? 3 : 1;
 137        int cpu, thread;
 138        struct perf_counts_values *aggr = &evsel->counts->aggr, count;
 139
 140        aggr->val = aggr->ena = aggr->run = 0;
 141
 142        for (cpu = 0; cpu < ncpus; cpu++) {
 143                for (thread = 0; thread < nthreads; thread++) {
 144                        if (FD(evsel, cpu, thread) < 0)
 145                                continue;
 146
 147                        if (readn(FD(evsel, cpu, thread),
 148                                  &count, nv * sizeof(u64)) < 0)
 149                                return -errno;
 150
 151                        aggr->val += count.val;
 152                        if (scale) {
 153                                aggr->ena += count.ena;
 154                                aggr->run += count.run;
 155                        }
 156                }
 157        }
 158
 159        evsel->counts->scaled = 0;
 160        if (scale) {
 161                if (aggr->run == 0) {
 162                        evsel->counts->scaled = -1;
 163                        aggr->val = 0;
 164                        return 0;
 165                }
 166
 167                if (aggr->run < aggr->ena) {
 168                        evsel->counts->scaled = 1;
 169                        aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
 170                }
 171        } else
 172                aggr->ena = aggr->run = 0;
 173
 174        return 0;
 175}
 176
 177static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 178                              struct thread_map *threads, bool group)
 179{
 180        int cpu, thread;
 181        unsigned long flags = 0;
 182        int pid = -1;
 183
 184        if (evsel->fd == NULL &&
 185            perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
 186                return -1;
 187
 188        if (evsel->cgrp) {
 189                flags = PERF_FLAG_PID_CGROUP;
 190                pid = evsel->cgrp->fd;
 191        }
 192
 193        for (cpu = 0; cpu < cpus->nr; cpu++) {
 194                int group_fd = -1;
 195
 196                for (thread = 0; thread < threads->nr; thread++) {
 197
 198                        if (!evsel->cgrp)
 199                                pid = threads->map[thread];
 200
 201                        FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
 202                                                                     pid,
 203                                                                     cpus->map[cpu],
 204                                                                     group_fd, flags);
 205                        if (FD(evsel, cpu, thread) < 0)
 206                                goto out_close;
 207
 208                        if (group && group_fd == -1)
 209                                group_fd = FD(evsel, cpu, thread);
 210                }
 211        }
 212
 213        return 0;
 214
 215out_close:
 216        do {
 217                while (--thread >= 0) {
 218                        close(FD(evsel, cpu, thread));
 219                        FD(evsel, cpu, thread) = -1;
 220                }
 221                thread = threads->nr;
 222        } while (--cpu >= 0);
 223        return -1;
 224}
 225
 226static struct {
 227        struct cpu_map map;
 228        int cpus[1];
 229} empty_cpu_map = {
 230        .map.nr = 1,
 231        .cpus   = { -1, },
 232};
 233
 234static struct {
 235        struct thread_map map;
 236        int threads[1];
 237} empty_thread_map = {
 238        .map.nr  = 1,
 239        .threads = { -1, },
 240};
 241
 242int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 243                     struct thread_map *threads, bool group)
 244{
 245        if (cpus == NULL) {
 246                /* Work around old compiler warnings about strict aliasing */
 247                cpus = &empty_cpu_map.map;
 248        }
 249
 250        if (threads == NULL)
 251                threads = &empty_thread_map.map;
 252
 253        return __perf_evsel__open(evsel, cpus, threads, group);
 254}
 255
 256int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
 257                             struct cpu_map *cpus, bool group)
 258{
 259        return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group);
 260}
 261
 262int perf_evsel__open_per_thread(struct perf_evsel *evsel,
 263                                struct thread_map *threads, bool group)
 264{
 265        return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group);
 266}
 267
 268static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
 269                                       struct perf_sample *sample)
 270{
 271        const u64 *array = event->sample.array;
 272
 273        array += ((event->header.size -
 274                   sizeof(event->header)) / sizeof(u64)) - 1;
 275
 276        if (type & PERF_SAMPLE_CPU) {
 277                u32 *p = (u32 *)array;
 278                sample->cpu = *p;
 279                array--;
 280        }
 281
 282        if (type & PERF_SAMPLE_STREAM_ID) {
 283                sample->stream_id = *array;
 284                array--;
 285        }
 286
 287        if (type & PERF_SAMPLE_ID) {
 288                sample->id = *array;
 289                array--;
 290        }
 291
 292        if (type & PERF_SAMPLE_TIME) {
 293                sample->time = *array;
 294                array--;
 295        }
 296
 297        if (type & PERF_SAMPLE_TID) {
 298                u32 *p = (u32 *)array;
 299                sample->pid = p[0];
 300                sample->tid = p[1];
 301        }
 302
 303        return 0;
 304}
 305
 306int perf_event__parse_sample(const union perf_event *event, u64 type,
 307                             bool sample_id_all, struct perf_sample *data)
 308{
 309        const u64 *array;
 310
 311        data->cpu = data->pid = data->tid = -1;
 312        data->stream_id = data->id = data->time = -1ULL;
 313
 314        if (event->header.type != PERF_RECORD_SAMPLE) {
 315                if (!sample_id_all)
 316                        return 0;
 317                return perf_event__parse_id_sample(event, type, data);
 318        }
 319
 320        array = event->sample.array;
 321
 322        if (type & PERF_SAMPLE_IP) {
 323                data->ip = event->ip.ip;
 324                array++;
 325        }
 326
 327        if (type & PERF_SAMPLE_TID) {
 328                u32 *p = (u32 *)array;
 329                data->pid = p[0];
 330                data->tid = p[1];
 331                array++;
 332        }
 333
 334        if (type & PERF_SAMPLE_TIME) {
 335                data->time = *array;
 336                array++;
 337        }
 338
 339        if (type & PERF_SAMPLE_ADDR) {
 340                data->addr = *array;
 341                array++;
 342        }
 343
 344        data->id = -1ULL;
 345        if (type & PERF_SAMPLE_ID) {
 346                data->id = *array;
 347                array++;
 348        }
 349
 350        if (type & PERF_SAMPLE_STREAM_ID) {
 351                data->stream_id = *array;
 352                array++;
 353        }
 354
 355        if (type & PERF_SAMPLE_CPU) {
 356                u32 *p = (u32 *)array;
 357                data->cpu = *p;
 358                array++;
 359        }
 360
 361        if (type & PERF_SAMPLE_PERIOD) {
 362                data->period = *array;
 363                array++;
 364        }
 365
 366        if (type & PERF_SAMPLE_READ) {
 367                fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
 368                return -1;
 369        }
 370
 371        if (type & PERF_SAMPLE_CALLCHAIN) {
 372                data->callchain = (struct ip_callchain *)array;
 373                array += 1 + data->callchain->nr;
 374        }
 375
 376        if (type & PERF_SAMPLE_RAW) {
 377                u32 *p = (u32 *)array;
 378                data->raw_size = *p;
 379                p++;
 380                data->raw_data = p;
 381        }
 382
 383        return 0;
 384}
 385