Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/lib/perf/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 13 kB image not shown  

Quelle  evsel.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <perf/evsel.h>
#include <perf/cpumap.h>
#include <perf/threadmap.h>
#include <linux/hash.h>
#include <linux/list.h>
#include <internal/evsel.h>
#include <linux/zalloc.h>
#include <stdlib.h>
#include <internal/xyarray.h>
#include <internal/cpumap.h>
#include <internal/mmap.h>
#include <internal/threadmap.h>
#include <internal/lib.h>
#include <linux/string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <asm/bug.h>

void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
        int idx)
{
 INIT_LIST_HEAD(&evsel->node);
 INIT_LIST_HEAD(&evsel->per_stream_periods);
 evsel->attr = *attr;
 evsel->idx  = idx;
 evsel->leader = evsel;
}

struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)
{
 struct perf_evsel *evsel = zalloc(sizeof(*evsel));

 if (evsel != NULL)
  perf_evsel__init(evsel, attr, 0);

 return evsel;
}

void perf_evsel__exit(struct perf_evsel *evsel)
{
 assert(evsel->fd == NULL);  /* If not fds were not closed. */
 assert(evsel->mmap == NULL); /* If not munmap wasn't called. */
 assert(evsel->sample_id == NULL); /* If not free_id wasn't called. */
 perf_cpu_map__put(evsel->cpus);
 perf_cpu_map__put(evsel->pmu_cpus);
 perf_thread_map__put(evsel->threads);
}

void perf_evsel__delete(struct perf_evsel *evsel)
{
 perf_evsel__exit(evsel);
 free(evsel);
}

#define FD(_evsel, _cpu_map_idx, _thread)    \
 ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
#define MMAP(_evsel, _cpu_map_idx, _thread)    \
 (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
        : NULL)

int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
{
 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));

 if (evsel->fd) {
  int idx, thread;

  for (idx = 0; idx < ncpus; idx++) {
   for (thread = 0; thread < nthreads; thread++) {
    int *fd = FD(evsel, idx, thread);

    if (fd)
     *fd = -1;
   }
  }
 }

 return evsel->fd != NULL ? 0 : -ENOMEM;
}

static int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads)
{
 evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap));

 return evsel->mmap != NULL ? 0 : -ENOMEM;
}

static int
sys_perf_event_open(struct perf_event_attr *attr,
      pid_t pid, struct perf_cpu cpu, int group_fd,
      unsigned long flags)
{
 return syscall(__NR_perf_event_open, attr, pid, cpu.cpu, group_fd, flags);
}

static int get_group_fd(struct perf_evsel *evsel, int cpu_map_idx, int thread, int *group_fd)
{
 struct perf_evsel *leader = evsel->leader;
 int *fd;

 if (evsel == leader) {
  *group_fd = -1;
  return 0;
 }

 /*
 * Leader must be already processed/open,
 * if not it's a bug.
 */

 if (!leader->fd)
  return -ENOTCONN;

 fd = FD(leader, cpu_map_idx, thread);
 if (fd == NULL || *fd == -1)
  return -EBADF;

 *group_fd = *fd;

 return 0;
}

int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
       struct perf_thread_map *threads)
{
 struct perf_cpu cpu;
 int idx, thread, err = 0;

 if (cpus == NULL) {
  static struct perf_cpu_map *empty_cpu_map;

  if (empty_cpu_map == NULL) {
   empty_cpu_map = perf_cpu_map__new_any_cpu();
   if (empty_cpu_map == NULL)
    return -ENOMEM;
  }

  cpus = empty_cpu_map;
 }

 if (threads == NULL) {
  static struct perf_thread_map *empty_thread_map;

  if (empty_thread_map == NULL) {
   empty_thread_map = perf_thread_map__new_dummy();
   if (empty_thread_map == NULL)
    return -ENOMEM;
  }

  threads = empty_thread_map;
 }

 if (evsel->fd == NULL &&
     perf_evsel__alloc_fd(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0)
  return -ENOMEM;

 perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
  for (thread = 0; thread < threads->nr; thread++) {
   int fd, group_fd, *evsel_fd;

   evsel_fd = FD(evsel, idx, thread);
   if (evsel_fd == NULL) {
    err = -EINVAL;
    goto out;
   }

   err = get_group_fd(evsel, idx, thread, &group_fd);
   if (err < 0)
    goto out;

   fd = sys_perf_event_open(&evsel->attr,
       threads->map[thread].pid,
       cpu, group_fd, 0);

   if (fd < 0) {
    err = -errno;
    goto out;
   }

   *evsel_fd = fd;
  }
 }
out:
 if (err)
  perf_evsel__close(evsel);

 return err;
}

static void perf_evsel__close_fd_cpu(struct perf_evsel *evsel, int cpu_map_idx)
{
 int thread;

 for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
  int *fd = FD(evsel, cpu_map_idx, thread);

  if (fd && *fd >= 0) {
   close(*fd);
   *fd = -1;
  }
 }
}

void perf_evsel__close_fd(struct perf_evsel *evsel)
{
 for (int idx = 0; idx < xyarray__max_x(evsel->fd); idx++)
  perf_evsel__close_fd_cpu(evsel, idx);
}

void perf_evsel__free_fd(struct perf_evsel *evsel)
{
 xyarray__delete(evsel->fd);
 evsel->fd = NULL;
}

void perf_evsel__close(struct perf_evsel *evsel)
{
 if (evsel->fd == NULL)
  return;

 perf_evsel__close_fd(evsel);
 perf_evsel__free_fd(evsel);
}

void perf_evsel__close_cpu(struct perf_evsel *evsel, int cpu_map_idx)
{
 if (evsel->fd == NULL)
  return;

 perf_evsel__close_fd_cpu(evsel, cpu_map_idx);
}

void perf_evsel__munmap(struct perf_evsel *evsel)
{
 int idx, thread;

 if (evsel->fd == NULL || evsel->mmap == NULL)
  return;

 for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
  for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
   int *fd = FD(evsel, idx, thread);

   if (fd == NULL || *fd < 0)
    continue;

   perf_mmap__munmap(MMAP(evsel, idx, thread));
  }
 }

 xyarray__delete(evsel->mmap);
 evsel->mmap = NULL;
}

int perf_evsel__mmap(struct perf_evsel *evsel, int pages)
{
 int ret, idx, thread;
 struct perf_mmap_param mp = {
  .prot = PROT_READ | PROT_WRITE,
  .mask = (pages * page_size) - 1,
 };

 if (evsel->fd == NULL || evsel->mmap)
  return -EINVAL;

 if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
  return -ENOMEM;

 for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
  for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
   int *fd = FD(evsel, idx, thread);
   struct perf_mmap *map;
   struct perf_cpu cpu = perf_cpu_map__cpu(evsel->cpus, idx);

   if (fd == NULL || *fd < 0)
    continue;

   map = MMAP(evsel, idx, thread);
   perf_mmap__init(map, NULL, false, NULL);

   ret = perf_mmap__mmap(map, &mp, *fd, cpu);
   if (ret) {
    perf_evsel__munmap(evsel);
    return ret;
   }
  }
 }

 return 0;
}

void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu_map_idx, int thread)
{
 int *fd = FD(evsel, cpu_map_idx, thread);

 if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
  return NULL;

 return MMAP(evsel, cpu_map_idx, thread)->base;
}

int perf_evsel__read_size(struct perf_evsel *evsel)
{
 u64 read_format = evsel->attr.read_format;
 int entry = sizeof(u64); /* value */
 int size = 0;
 int nr = 1;

 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
  size += sizeof(u64);

 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
  size += sizeof(u64);

 if (read_format & PERF_FORMAT_ID)
  entry += sizeof(u64);

 if (read_format & PERF_FORMAT_LOST)
  entry += sizeof(u64);

 if (read_format & PERF_FORMAT_GROUP) {
  nr = evsel->nr_members;
  size += sizeof(u64);
 }

 size += entry * nr;
 return size;
}

/* This only reads values for the leader */
static int perf_evsel__read_group(struct perf_evsel *evsel, int cpu_map_idx,
      int thread, struct perf_counts_values *count)
{
 size_t size = perf_evsel__read_size(evsel);
 int *fd = FD(evsel, cpu_map_idx, thread);
 u64 read_format = evsel->attr.read_format;
 u64 *data;
 int idx = 1;

 if (fd == NULL || *fd < 0)
  return -EINVAL;

 data = calloc(1, size);
 if (data == NULL)
  return -ENOMEM;

 if (readn(*fd, data, size) <= 0) {
  free(data);
  return -errno;
 }

 /*
 * This reads only the leader event intentionally since we don't have
 * perf counts values for sibling events.
 */

 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
  count->ena = data[idx++];
 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
  count->run = data[idx++];

 /* value is always available */
 count->val = data[idx++];
 if (read_format & PERF_FORMAT_ID)
  count->id = data[idx++];
 if (read_format & PERF_FORMAT_LOST)
  count->lost = data[idx++];

 free(data);
 return 0;
}

/*
 * The perf read format is very flexible.  It needs to set the proper
 * values according to the read format.
 */

static void perf_evsel__adjust_values(struct perf_evsel *evsel, u64 *buf,
          struct perf_counts_values *count)
{
 u64 read_format = evsel->attr.read_format;
 int n = 0;

 count->val = buf[n++];

 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
  count->ena = buf[n++];

 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
  count->run = buf[n++];

 if (read_format & PERF_FORMAT_ID)
  count->id = buf[n++];

 if (read_format & PERF_FORMAT_LOST)
  count->lost = buf[n++];
}

int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
       struct perf_counts_values *count)
{
 size_t size = perf_evsel__read_size(evsel);
 int *fd = FD(evsel, cpu_map_idx, thread);
 u64 read_format = evsel->attr.read_format;
 struct perf_counts_values buf;

 memset(count, 0, sizeof(*count));

 if (fd == NULL || *fd < 0)
  return -EINVAL;

 if (read_format & PERF_FORMAT_GROUP)
  return perf_evsel__read_group(evsel, cpu_map_idx, thread, count);

 if (MMAP(evsel, cpu_map_idx, thread) &&
     !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
     !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
  return 0;

 if (readn(*fd, buf.values, size) <= 0)
  return -errno;

 perf_evsel__adjust_values(evsel, buf.values, count);
 return 0;
}

static int perf_evsel__ioctl(struct perf_evsel *evsel, int ioc, void *arg,
        int cpu_map_idx, int thread)
{
 int *fd = FD(evsel, cpu_map_idx, thread);

 if (fd == NULL || *fd < 0)
  return -1;

 return ioctl(*fd, ioc, arg);
}

static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
     int ioc,  void *arg,
     int cpu_map_idx)
{
 int thread;

 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
  int err = perf_evsel__ioctl(evsel, ioc, arg, cpu_map_idx, thread);

  if (err)
   return err;
 }

 return 0;
}

int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
{
 return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
}

int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread)
{
 struct perf_cpu cpu __maybe_unused;
 int idx;
 int err;

 perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
  err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
  if (err)
   return err;
 }

 return 0;
}

int perf_evsel__enable(struct perf_evsel *evsel)
{
 int i;
 int err = 0;

 for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
  err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
 return err;
}

int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
{
 return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
}

int perf_evsel__disable(struct perf_evsel *evsel)
{
 int i;
 int err = 0;

 for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
  err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
 return err;
}

int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
{
 int err = 0, i;

 for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
  err = perf_evsel__run_ioctl(evsel,
         PERF_EVENT_IOC_SET_FILTER,
         (void *)filter, i);
 return err;
}

struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
{
 return evsel->cpus;
}

struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel)
{
 return evsel->threads;
}

struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel)
{
 return &evsel->attr;
}

int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
{
 if (ncpus == 0 || nthreads == 0)
  return 0;

 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
 if (evsel->sample_id == NULL)
  return -ENOMEM;

 evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
 if (evsel->id == NULL) {
  xyarray__delete(evsel->sample_id);
  evsel->sample_id = NULL;
  return -ENOMEM;
 }

 return 0;
}

void perf_evsel__free_id(struct perf_evsel *evsel)
{
 struct perf_sample_id_period *pos, *n;

 xyarray__delete(evsel->sample_id);
 evsel->sample_id = NULL;
 zfree(&evsel->id);
 evsel->ids = 0;

 perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) {
  list_del_init(&pos->node);
  free(pos);
 }
}

bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel)
{
 return (evsel->attr.sample_type & PERF_SAMPLE_READ) &&
  (evsel->attr.sample_type & PERF_SAMPLE_TID) &&
  evsel->attr.inherit;
}

u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread)
{
 struct hlist_head *head;
 struct perf_sample_id_period *res;
 int hash;

 if (!per_thread)
  return &sid->period;

 hash = hash_32(tid, PERF_SAMPLE_ID__HLIST_BITS);
 head = &sid->periods[hash];

 hlist_for_each_entry(res, head, hnode)
  if (res->tid == tid)
   return &res->period;

 if (sid->evsel == NULL)
  return NULL;

 res = zalloc(sizeof(struct perf_sample_id_period));
 if (res == NULL)
  return NULL;

 INIT_LIST_HEAD(&res->node);
 res->tid = tid;

 list_add_tail(&res->node, &sid->evsel->per_stream_periods);
 hlist_add_head(&res->hnode, &sid->periods[hash]);

 return &res->period;
}

void perf_counts_values__scale(struct perf_counts_values *count,
          bool scale, __s8 *pscaled)
{
 s8 scaled = 0;

 if (scale) {
  if (count->run == 0) {
   scaled = -1;
   count->val = 0;
  } else if (count->run < count->ena) {
   scaled = 1;
   count->val = (u64)((double)count->val * count->ena / count->run);
  }
 }

 if (pscaled)
  *pscaled = scaled;
}

Messung V0.5
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.