|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* pfmlib_perf_pmu.c: support for perf_events event table
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (c) 2009 Google, Inc
|
|
Packit |
577717 |
* Contributed by Stephane Eranian <eranian@google.com>
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit |
577717 |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit |
577717 |
* in the Software without restriction, including without limitation the rights
|
|
Packit |
577717 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit |
577717 |
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
Packit |
577717 |
* subject to the following conditions:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The above copyright notice and this permission notice shall be included in all
|
|
Packit |
577717 |
* copies or substantial portions of the Software.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
Packit |
577717 |
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit |
577717 |
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit |
577717 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit |
577717 |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
Packit |
577717 |
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#include <sys/types.h>
|
|
Packit |
577717 |
#include <string.h>
|
|
Packit |
577717 |
#include <stdlib.h>
|
|
Packit |
577717 |
#include <stdio.h>
|
|
Packit |
577717 |
#include <unistd.h>
|
|
Packit |
577717 |
#include <dirent.h>
|
|
Packit |
577717 |
#include <fcntl.h>
|
|
Packit |
577717 |
#include <limits.h>
|
|
Packit |
577717 |
#ifdef __linux__
|
|
Packit |
577717 |
#include <sys/syscall.h> /* for openat() */
|
|
Packit |
577717 |
#include <sys/param.h>
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* looks like several distributions do not have
|
|
Packit |
577717 |
* the latest libc with openat support, so disable
|
|
Packit |
577717 |
* for now
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#undef HAS_OPENAT
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "pfmlib_priv.h"
|
|
Packit |
577717 |
#include "pfmlib_perf_event_priv.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PERF_MAX_UMASKS 8
|
|
Packit |
577717 |
|
|
Packit |
577717 |
typedef struct {
|
|
Packit |
577717 |
const char *uname; /* unit mask name */
|
|
Packit |
577717 |
const char *udesc; /* unit mask desc */
|
|
Packit |
577717 |
uint64_t uid; /* unit mask id */
|
|
Packit |
577717 |
int uflags; /* umask options */
|
|
Packit |
577717 |
int grpid; /* group identifier */
|
|
Packit |
577717 |
} perf_umask_t;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
typedef struct {
|
|
Packit |
577717 |
const char *name; /* name */
|
|
Packit |
577717 |
const char *desc; /* description */
|
|
Packit |
577717 |
const char *equiv; /* event is aliased to */
|
|
Packit |
577717 |
uint64_t id; /* perf_hw_id or equivalent */
|
|
Packit |
577717 |
int modmsk; /* modifiers bitmask */
|
|
Packit |
577717 |
int type; /* perf_type_id */
|
|
Packit |
577717 |
int numasks; /* number of unit masls */
|
|
Packit |
577717 |
int ngrp; /* number of umasks groups */
|
|
Packit |
577717 |
unsigned long umask_ovfl_idx; /* base index of overflow unit masks */
|
|
Packit |
577717 |
perf_umask_t umasks[PERF_MAX_UMASKS];/* first unit masks */
|
|
Packit |
577717 |
} perf_event_t;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* umask options: uflags
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#define PERF_FL_DEFAULT 0x1 /* umask is default for group */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PERF_INVAL_OVFL_IDX ((unsigned long)-1)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PCL_EVT(f, t, m) \
|
|
Packit |
577717 |
{ .name = #f, \
|
|
Packit |
577717 |
.id = (f), \
|
|
Packit |
577717 |
.type = (t), \
|
|
Packit |
577717 |
.desc = #f, \
|
|
Packit |
577717 |
.equiv = NULL, \
|
|
Packit |
577717 |
.numasks = 0, \
|
|
Packit |
577717 |
.modmsk = (m), \
|
|
Packit |
577717 |
.ngrp = 0, \
|
|
Packit |
577717 |
.umask_ovfl_idx = PERF_INVAL_OVFL_IDX,\
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PCL_EVTA(f, t, m, a) \
|
|
Packit |
577717 |
{ .name = #f, \
|
|
Packit |
577717 |
.id = a, \
|
|
Packit |
577717 |
.type = t, \
|
|
Packit |
577717 |
.desc = #a, \
|
|
Packit |
577717 |
.equiv = #a, \
|
|
Packit |
577717 |
.numasks = 0, \
|
|
Packit |
577717 |
.modmsk = m, \
|
|
Packit |
577717 |
.ngrp = 0, \
|
|
Packit |
577717 |
.umask_ovfl_idx = PERF_INVAL_OVFL_IDX,\
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PCL_EVT_HW(n) PCL_EVT(PERF_COUNT_HW_##n, PERF_TYPE_HARDWARE, PERF_ATTR_HW)
|
|
Packit |
577717 |
#define PCL_EVT_SW(n) PCL_EVT(PERF_COUNT_SW_##n, PERF_TYPE_SOFTWARE, PERF_ATTR_SW)
|
|
Packit |
577717 |
#define PCL_EVT_AHW(n, a) PCL_EVTA(n, PERF_TYPE_HARDWARE, PERF_ATTR_HW, PERF_COUNT_HW_##a)
|
|
Packit |
577717 |
#define PCL_EVT_ASW(n, a) PCL_EVTA(n, PERF_TYPE_SOFTWARE, PERF_ATTR_SW, PERF_COUNT_SW_##a)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifndef MAXPATHLEN
|
|
Packit |
577717 |
#define MAXPATHLEN 1024
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
static char debugfs_mnt[MAXPATHLEN];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PERF_ATTR_HW 0
|
|
Packit |
577717 |
#define PERF_ATTR_SW 0
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "events/perf_events.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define perf_nevents (perf_event_support.pme_count)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static perf_event_t *perf_pe = perf_static_events;
|
|
Packit |
577717 |
static perf_event_t *perf_pe_free, *perf_pe_end;
|
|
Packit |
577717 |
static perf_umask_t *perf_um, *perf_um_free, *perf_um_end;
|
|
Packit |
577717 |
static int perf_pe_count, perf_um_count;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline int
|
|
Packit |
577717 |
pfm_perf_pmu_supported_plm(void *this)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_pmu_t *pmu;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pmu = pfmlib_get_pmu_by_type(PFM_PMU_TYPE_CORE);
|
|
Packit |
577717 |
if (!pmu) {
|
|
Packit |
577717 |
DPRINT("no core CPU PMU, going with default\n");
|
|
Packit |
577717 |
pmu = this;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
DPRINT("guessing plm from %s PMU plm=0x%x\n", pmu->name, pmu->supported_plm);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return pmu->supported_plm;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline unsigned long
|
|
Packit |
577717 |
perf_get_ovfl_umask_idx(perf_umask_t *um)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return um - perf_um;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline perf_umask_t *
|
|
Packit |
577717 |
perf_get_ovfl_umask(int pidx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return perf_um+perf_pe[pidx].umask_ovfl_idx;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline perf_umask_t *
|
|
Packit |
577717 |
perf_attridx2um(int idx, int attr_idx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_umask_t *um;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (attr_idx < PERF_MAX_UMASKS) {
|
|
Packit |
577717 |
um = &perf_pe[idx].umasks[attr_idx];
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
um = perf_get_ovfl_umask(idx);
|
|
Packit |
577717 |
um += attr_idx - PERF_MAX_UMASKS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return um;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* figure out the mount point of the debugfs filesystem
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* returns -1 if none is found
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
get_debugfs_mnt(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
FILE *fp;
|
|
Packit |
577717 |
char *buffer = NULL;
|
|
Packit |
577717 |
size_t len = 0;
|
|
Packit |
577717 |
char *q, *mnt, *fs;
|
|
Packit |
577717 |
int res = -1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fp = fopen("/proc/mounts", "r");
|
|
Packit |
577717 |
if (!fp)
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
while(pfmlib_getl(&buffer, &len, fp) != -1) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
q = strchr(buffer, ' ');
|
|
Packit |
577717 |
if (!q)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
mnt = ++q;
|
|
Packit |
577717 |
q = strchr(q, ' ');
|
|
Packit |
577717 |
if (!q)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
*q = '\0';
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fs = ++q;
|
|
Packit |
577717 |
q = strchr(q, ' ');
|
|
Packit |
577717 |
if (!q)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
*q = '\0';
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!strcmp(fs, "debugfs")) {
|
|
Packit |
577717 |
strncpy(debugfs_mnt, mnt, MAXPATHLEN);
|
|
Packit |
577717 |
debugfs_mnt[MAXPATHLEN-1]= '\0';
|
|
Packit |
577717 |
res = 0;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (buffer)
|
|
Packit |
577717 |
free(buffer);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fclose(fp);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return res;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PERF_ALLOC_EVENT_COUNT (512)
|
|
Packit |
577717 |
#define PERF_ALLOC_UMASK_COUNT (1024)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* clone static event table into a dynamic
|
|
Packit |
577717 |
* event table
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Used for tracepoints
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static perf_event_t *
|
|
Packit |
577717 |
perf_table_clone(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_event_t *addr;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perf_pe_count = perf_nevents + PERF_ALLOC_EVENT_COUNT;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
addr = calloc(perf_pe_count, sizeof(perf_event_t));
|
|
Packit |
577717 |
if (addr) {
|
|
Packit |
577717 |
memcpy(addr, perf_static_events, perf_nevents * sizeof(perf_event_t));
|
|
Packit |
577717 |
perf_pe_free = addr + perf_nevents;
|
|
Packit |
577717 |
perf_pe_end = perf_pe_free + PERF_ALLOC_EVENT_COUNT;
|
|
Packit |
577717 |
perf_pe = addr;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return addr;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* allocate space for one new event in event table
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* returns NULL if out-of-memory
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* may realloc existing table if necessary for growth
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static perf_event_t *
|
|
Packit |
577717 |
perf_table_alloc_event(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_event_t *new_pe;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
retry:
|
|
Packit |
577717 |
if (perf_pe_free < perf_pe_end)
|
|
Packit |
577717 |
return perf_pe_free++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perf_pe_count += PERF_ALLOC_EVENT_COUNT;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
new_pe = realloc(perf_pe, perf_pe_count * sizeof(perf_event_t));
|
|
Packit |
577717 |
if (!new_pe)
|
|
Packit |
577717 |
return NULL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perf_pe_free = new_pe + (perf_pe_free - perf_pe);
|
|
Packit |
577717 |
perf_pe_end = perf_pe_free + PERF_ALLOC_EVENT_COUNT;
|
|
Packit |
577717 |
perf_pe = new_pe;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
goto retry;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* allocate space for overflow new unit masks
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Each event can hold up to PERF_MAX_UMASKS.
|
|
Packit |
577717 |
* But gievn we can dynamically add events
|
|
Packit |
577717 |
* which may have more unit masks, then we
|
|
Packit |
577717 |
* put them into a separate overflow unit
|
|
Packit |
577717 |
* masks, table which can grow on demand.
|
|
Packit |
577717 |
* In that case the first PERF_MAX_UMASKS
|
|
Packit |
577717 |
* are in the event, the rest in the overflow
|
|
Packit |
577717 |
* table at index pointed to by event->umask_ovfl_idx
|
|
Packit |
577717 |
* All unit masks for an event are contiguous in the
|
|
Packit |
577717 |
* overflow table.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static perf_umask_t *
|
|
Packit |
577717 |
perf_table_alloc_umask(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_umask_t *new_um;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
retry:
|
|
Packit |
577717 |
if (perf_um_free < perf_um_end)
|
|
Packit |
577717 |
return perf_um_free++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perf_um_count += PERF_ALLOC_UMASK_COUNT;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
new_um = realloc(perf_um, perf_um_count * sizeof(*new_um));
|
|
Packit |
577717 |
if (!new_um)
|
|
Packit |
577717 |
return NULL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perf_um_free = new_um + (perf_um_free - perf_um);
|
|
Packit |
577717 |
perf_um_end = perf_um_free + PERF_ALLOC_UMASK_COUNT;
|
|
Packit |
577717 |
perf_um = new_um;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
goto retry;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef __GNUC__
|
|
Packit |
577717 |
#define POTENTIALLY_UNUSED __attribute__((unused))
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
gen_tracepoint_table(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
DIR *dir1, *dir2;
|
|
Packit |
577717 |
struct dirent *d1, *d2;
|
|
Packit |
577717 |
perf_event_t *p;
|
|
Packit |
577717 |
perf_umask_t *um;
|
|
Packit |
577717 |
char d2path[MAXPATHLEN];
|
|
Packit |
577717 |
char idpath[MAXPATHLEN];
|
|
Packit |
577717 |
char id_str[32];
|
|
Packit |
577717 |
uint64_t id;
|
|
Packit |
577717 |
int fd, err;
|
|
Packit |
577717 |
int POTENTIALLY_UNUSED dir2_fd;
|
|
Packit |
577717 |
int reuse_event = 0;
|
|
Packit |
577717 |
int numasks;
|
|
Packit |
577717 |
char *tracepoint_name;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
err = get_debugfs_mnt();
|
|
Packit |
577717 |
if (err == -1)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
strncat(debugfs_mnt, "/tracing/events", MAXPATHLEN-1);
|
|
Packit |
577717 |
debugfs_mnt[MAXPATHLEN-1]= '\0';
|
|
Packit |
577717 |
|
|
Packit |
577717 |
dir1 = opendir(debugfs_mnt);
|
|
Packit |
577717 |
if (!dir1)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
p = perf_table_clone();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
err = 0;
|
|
Packit |
577717 |
while((d1 = readdir(dir1)) && err >= 0) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!strcmp(d1->d_name, "."))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!strcmp(d1->d_name, ".."))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
snprintf(d2path, MAXPATHLEN, "%s/%s", debugfs_mnt, d1->d_name);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* fails if d2path is not a directory */
|
|
Packit |
577717 |
dir2 = opendir(d2path);
|
|
Packit |
577717 |
if (!dir2)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
dir2_fd = dirfd(dir2);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* if a subdir did not fit our expected
|
|
Packit |
577717 |
* tracepoint format, then we reuse the
|
|
Packit |
577717 |
* allocated space (with have no free)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (!reuse_event)
|
|
Packit |
577717 |
p = perf_table_alloc_event();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!p)
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (p)
|
|
Packit |
577717 |
p->name = tracepoint_name = strdup(d1->d_name);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!(p && p->name)) {
|
|
Packit |
577717 |
closedir(dir2);
|
|
Packit |
577717 |
err = -1;
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
p->desc = "tracepoint";
|
|
Packit |
577717 |
p->id = -1;
|
|
Packit |
577717 |
p->type = PERF_TYPE_TRACEPOINT;
|
|
Packit |
577717 |
p->umask_ovfl_idx = PERF_INVAL_OVFL_IDX;
|
|
Packit |
577717 |
p->modmsk = 0,
|
|
Packit |
577717 |
p->ngrp = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
numasks = 0;
|
|
Packit |
577717 |
reuse_event = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
while((d2 = readdir(dir2))) {
|
|
Packit |
577717 |
if (!strcmp(d2->d_name, "."))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!strcmp(d2->d_name, ".."))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef HAS_OPENAT
|
|
Packit |
577717 |
snprintf(idpath, MAXPATHLEN, "%s/id", d2->d_name);
|
|
Packit |
577717 |
fd = openat(dir2_fd, idpath, O_RDONLY);
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
snprintf(idpath, MAXPATHLEN, "%s/%s/id", d2path, d2->d_name);
|
|
Packit |
577717 |
fd = open(idpath, O_RDONLY);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
if (fd == -1)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
err = read(fd, id_str, sizeof(id_str));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
close(fd);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (err < 0)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
id = strtoull(id_str, NULL, 0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (numasks < PERF_MAX_UMASKS)
|
|
Packit |
577717 |
um = p->umasks+numasks;
|
|
Packit |
577717 |
else {
|
|
Packit |
577717 |
um = perf_table_alloc_umask();
|
|
Packit |
577717 |
if (numasks == PERF_MAX_UMASKS)
|
|
Packit |
577717 |
p->umask_ovfl_idx = perf_get_ovfl_umask_idx(um);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!um) {
|
|
Packit |
577717 |
err = -1;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* tracepoint have no event codes
|
|
Packit |
577717 |
* the code is in the unit masks
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
p->id = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
um->uname = strdup(d2->d_name);
|
|
Packit |
577717 |
if (!um->uname) {
|
|
Packit |
577717 |
err = -1;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
um->udesc = um->uname;
|
|
Packit |
577717 |
um->uid = id;
|
|
Packit |
577717 |
um->grpid = 0;
|
|
Packit |
577717 |
DPRINT("idpath=%s:%s id=%"PRIu64"\n", p->name, um->uname, id);
|
|
Packit |
577717 |
numasks++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
p->numasks = numasks;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
closedir(dir2);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* directory was not pointing
|
|
Packit |
577717 |
* to a tree structure we know about
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (!numasks) {
|
|
Packit |
577717 |
free(tracepoint_name);
|
|
Packit |
577717 |
reuse_event =1;
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* update total number of events
|
|
Packit |
577717 |
* only when no error is reported
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (err >= 0)
|
|
Packit |
577717 |
perf_nevents++;
|
|
Packit |
577717 |
reuse_event = 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
closedir(dir1);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_detect(void *this)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#ifdef __linux__
|
|
Packit |
577717 |
/* ought to find a better way of detecting PERF */
|
|
Packit |
577717 |
#define PERF_OLD_PROC_FILE "/proc/sys/kernel/perf_counter_paranoid"
|
|
Packit |
577717 |
#define PERF_PROC_FILE "/proc/sys/kernel/perf_event_paranoid"
|
|
Packit |
577717 |
return !(access(PERF_PROC_FILE, F_OK)
|
|
Packit |
577717 |
&& access(PERF_OLD_PROC_FILE, F_OK)) ? PFM_SUCCESS: PFM_ERR_NOTSUPP;
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
return PFM_SUCCESS;
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_init(void *this)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_pmu_t *pmu = this;
|
|
Packit |
577717 |
perf_pe = perf_static_events;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* we force the value of pme_count by hand because
|
|
Packit |
577717 |
* the library could be initialized mutltiple times
|
|
Packit |
577717 |
* due to pfm_terminate() and thus we need to start
|
|
Packit |
577717 |
* from the default count
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
perf_event_support.pme_count = PME_PERF_EVENT_COUNT;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* must dynamically add tracepoints */
|
|
Packit |
577717 |
gen_tracepoint_table();
|
|
Packit |
577717 |
/* dynamically patch supported plm based on CORE PMU plm */
|
|
Packit |
577717 |
pmu->supported_plm = pfm_perf_pmu_supported_plm(pmu);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFM_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_get_event_first(void *this)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_get_event_next(void *this, int idx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (idx < 0 || idx >= (perf_nevents-1))
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return idx+1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_add_defaults(pfmlib_event_desc_t *e, unsigned int msk, uint64_t *umask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_event_t *ent;
|
|
Packit |
577717 |
perf_umask_t *um;
|
|
Packit |
577717 |
int i, j, k, added;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
k = e->nattrs;
|
|
Packit |
577717 |
ent = perf_pe+e->event;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; msk; msk >>=1, i++) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!(msk & 0x1))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
added = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(j=0; j < ent->numasks; j++) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (j < PERF_MAX_UMASKS) {
|
|
Packit |
577717 |
um = &perf_pe[e->event].umasks[j];
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
um = perf_get_ovfl_umask(e->event);
|
|
Packit |
577717 |
um += j - PERF_MAX_UMASKS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (um->grpid != i)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (um->uflags & PERF_FL_DEFAULT) {
|
|
Packit |
577717 |
DPRINT("added default %s for group %d\n", um->uname, i);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
*umask |= um->uid;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
e->attrs[k].id = j;
|
|
Packit |
577717 |
e->attrs[k].ival = 0;
|
|
Packit |
577717 |
k++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
added++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (!added) {
|
|
Packit |
577717 |
DPRINT("no default found for event %s unit mask group %d\n", ent->name, i);
|
|
Packit |
577717 |
return PFM_ERR_UMASK;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
e->nattrs = k;
|
|
Packit |
577717 |
return PFM_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfmlib_perf_encode_tp(pfmlib_event_desc_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_umask_t *um;
|
|
Packit |
577717 |
pfmlib_event_attr_info_t *a;
|
|
Packit |
577717 |
int i, nu = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
e->fstr[0] = '\0';
|
|
Packit |
577717 |
e->count = 1;
|
|
Packit |
577717 |
evt_strcat(e->fstr, "%s", perf_pe[e->event].name);
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* look for tracepoints
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for(i=0; i < e->nattrs; i++) {
|
|
Packit |
577717 |
a = attr(e, i);
|
|
Packit |
577717 |
if (a->ctrl != PFM_ATTR_CTRL_PMU)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (a->type == PFM_ATTR_UMASK) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* tracepoint unit masks cannot be combined
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (++nu > 1)
|
|
Packit |
577717 |
return PFM_ERR_FEATCOMB;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (a->idx < PERF_MAX_UMASKS) {
|
|
Packit |
577717 |
e->codes[0] = perf_pe[e->event].umasks[a->idx].uid;
|
|
Packit |
577717 |
evt_strcat(e->fstr, ":%s", perf_pe[e->event].umasks[a->idx].uname);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
um = perf_get_ovfl_umask(e->event);
|
|
Packit |
577717 |
e->codes[0] = um[a->idx - PERF_MAX_UMASKS].uid;
|
|
Packit |
577717 |
evt_strcat(e->fstr, ":%s", um[a->idx - PERF_MAX_UMASKS].uname);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
} else
|
|
Packit |
577717 |
return PFM_ERR_ATTR;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFM_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfmlib_perf_encode_hw_cache(pfmlib_event_desc_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_event_attr_info_t *a;
|
|
Packit |
577717 |
perf_event_t *ent;
|
|
Packit |
577717 |
unsigned int msk, grpmsk;
|
|
Packit |
577717 |
uint64_t umask = 0;
|
|
Packit |
577717 |
int i, ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
grpmsk = (1 << perf_pe[e->event].ngrp)-1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ent = perf_pe + e->event;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
e->codes[0] = ent->id;
|
|
Packit |
577717 |
e->count = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
e->fstr[0] = '\0';
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < e->nattrs; i++) {
|
|
Packit |
577717 |
a = attr(e, i);
|
|
Packit |
577717 |
if (a->ctrl != PFM_ATTR_CTRL_PMU)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
if (a->type == PFM_ATTR_UMASK) {
|
|
Packit |
577717 |
e->codes[0] |= ent->umasks[a->idx].uid;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
msk = 1 << ent->umasks[a->idx].grpid;
|
|
Packit |
577717 |
/* umask cannot be combined in each group */
|
|
Packit |
577717 |
if ((grpmsk & msk) == 0)
|
|
Packit |
577717 |
return PFM_ERR_UMASK;
|
|
Packit |
577717 |
grpmsk &= ~msk;
|
|
Packit |
577717 |
} else
|
|
Packit |
577717 |
return PFM_ERR_ATTR; /* no mod, no raw umask */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* check for missing default umasks */
|
|
Packit |
577717 |
if (grpmsk) {
|
|
Packit |
577717 |
ret = pfm_perf_add_defaults(e, grpmsk, &umask);
|
|
Packit |
577717 |
if (ret != PFM_SUCCESS)
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
e->codes[0] |= umask;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* reorder all the attributes such that the fstr appears always
|
|
Packit |
577717 |
* the same regardless of how the attributes were submitted.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* cannot sort attr until after we have added the default umasks
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
evt_strcat(e->fstr, "%s", ent->name);
|
|
Packit |
577717 |
pfmlib_sort_attr(e);
|
|
Packit |
577717 |
for(i=0; i < e->nattrs; i++) {
|
|
Packit |
577717 |
a = attr(e, i);
|
|
Packit |
577717 |
if (a->ctrl != PFM_ATTR_CTRL_PMU)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
if (a->type == PFM_ATTR_UMASK)
|
|
Packit |
577717 |
evt_strcat(e->fstr, ":%s", ent->umasks[a->idx].uname);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFM_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_get_encoding(void *this, pfmlib_event_desc_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
switch(perf_pe[e->event].type) {
|
|
Packit |
577717 |
case PERF_TYPE_TRACEPOINT:
|
|
Packit |
577717 |
ret = pfmlib_perf_encode_tp(e);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PERF_TYPE_HW_CACHE:
|
|
Packit |
577717 |
ret = pfmlib_perf_encode_hw_cache(e);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PERF_TYPE_HARDWARE:
|
|
Packit |
577717 |
case PERF_TYPE_SOFTWARE:
|
|
Packit |
577717 |
ret = PFM_SUCCESS;
|
|
Packit |
577717 |
e->codes[0] = perf_pe[e->event].id;
|
|
Packit |
577717 |
e->count = 1;
|
|
Packit |
577717 |
e->fstr[0] = '\0';
|
|
Packit |
577717 |
evt_strcat(e->fstr, "%s", perf_pe[e->event].name);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
DPRINT("unsupported event type=%d\n", perf_pe[e->event].type);
|
|
Packit |
577717 |
return PFM_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_get_perf_encoding(void *this, pfmlib_event_desc_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct perf_event_attr *attr;
|
|
Packit |
577717 |
int ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
switch(perf_pe[e->event].type) {
|
|
Packit |
577717 |
case PERF_TYPE_TRACEPOINT:
|
|
Packit |
577717 |
ret = pfmlib_perf_encode_tp(e);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PERF_TYPE_HW_CACHE:
|
|
Packit |
577717 |
ret = pfmlib_perf_encode_hw_cache(e);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PERF_TYPE_HARDWARE:
|
|
Packit |
577717 |
case PERF_TYPE_SOFTWARE:
|
|
Packit |
577717 |
ret = PFM_SUCCESS;
|
|
Packit |
577717 |
e->codes[0] = perf_pe[e->event].id;
|
|
Packit |
577717 |
e->count = 1;
|
|
Packit |
577717 |
e->fstr[0] = '\0';
|
|
Packit |
577717 |
evt_strcat(e->fstr, "%s", perf_pe[e->event].name);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
DPRINT("unsupported event type=%d\n", perf_pe[e->event].type);
|
|
Packit |
577717 |
return PFM_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
attr = e->os_data;
|
|
Packit |
577717 |
attr->type = perf_pe[e->event].type;
|
|
Packit |
577717 |
attr->config = e->codes[0];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_event_is_valid(void *this, int idx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return idx >= 0 && idx < perf_nevents;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_get_event_attr_info(void *this, int idx, int attr_idx, pfmlib_event_attr_info_t *info)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_umask_t *um;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* only supports umasks, modifiers handled at OS layer */
|
|
Packit |
577717 |
um = perf_attridx2um(idx, attr_idx);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
info->name = um->uname;
|
|
Packit |
577717 |
info->desc = um->udesc;
|
|
Packit |
577717 |
info->equiv= NULL;
|
|
Packit |
577717 |
info->code = um->uid;
|
|
Packit |
577717 |
info->type = PFM_ATTR_UMASK;
|
|
Packit |
577717 |
info->ctrl = PFM_ATTR_CTRL_PMU;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
info->is_precise = 0;
|
|
Packit |
577717 |
info->is_dfl = 0;
|
|
Packit |
577717 |
info->idx = attr_idx;
|
|
Packit |
577717 |
info->dfl_val64 = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFM_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_get_event_info(void *this, int idx, pfm_event_info_t *info)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_pmu_t *pmu = this;
|
|
Packit |
577717 |
info->name = perf_pe[idx].name;
|
|
Packit |
577717 |
info->desc = perf_pe[idx].desc;
|
|
Packit |
577717 |
info->code = perf_pe[idx].id;
|
|
Packit |
577717 |
info->equiv = perf_pe[idx].equiv;
|
|
Packit |
577717 |
info->idx = idx;
|
|
Packit |
577717 |
info->pmu = pmu->pmu;
|
|
Packit |
577717 |
info->is_precise = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* unit masks + modifiers */
|
|
Packit |
577717 |
info->nattrs = perf_pe[idx].numasks;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFM_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_perf_terminate(void *this)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perf_event_t *p;
|
|
Packit |
577717 |
int i, j;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!(perf_pe && perf_um))
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* free tracepoints name + unit mask names
|
|
Packit |
577717 |
* which are dynamically allocated
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (i=0; i < perf_nevents; i++) {
|
|
Packit |
577717 |
p = &perf_pe[i];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (p->type != PERF_TYPE_TRACEPOINT)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* cast to keep compiler happy, we are
|
|
Packit |
577717 |
* freeing the dynamically allocated clone
|
|
Packit |
577717 |
* table, not the static one. We do not want
|
|
Packit |
577717 |
* to create a specific data type
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
free((void *)p->name);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* first PERF_MAX_UMASKS are pre-allocated
|
|
Packit |
577717 |
* the rest is in a separate dynamic table
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (j=0; j < p->numasks; j++) {
|
|
Packit |
577717 |
if (j == PERF_MAX_UMASKS)
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
free((void *)p->umasks[j].uname);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* perf_pe is systematically allocated
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
free(perf_pe);
|
|
Packit |
577717 |
perf_pe = NULL;
|
|
Packit |
577717 |
perf_pe_free = perf_pe_end = NULL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perf_um) {
|
|
Packit |
577717 |
int n;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* free the dynamic umasks' uname
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
n = perf_um_free - perf_um;
|
|
Packit |
577717 |
for(i=0; i < n; i++) {
|
|
Packit |
577717 |
free((void *)(perf_um[i].uname));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
free(perf_um);
|
|
Packit |
577717 |
perf_um = NULL;
|
|
Packit |
577717 |
perf_um_free = perf_um_end = NULL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_perf_validate_table(void *this, FILE *fp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
const char *name = perf_event_support.name;
|
|
Packit |
577717 |
perf_umask_t *um;
|
|
Packit |
577717 |
int i, j;
|
|
Packit |
577717 |
int error = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < perf_event_support.pme_count; i++) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!perf_pe[i].name) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: :: no name (prev event was %s)\n", name, i,
|
|
Packit |
577717 |
i > 1 ? perf_pe[i-1].name : "??");
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!perf_pe[i].desc) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s :: no description\n", name, i, perf_pe[i].name);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perf_pe[i].type < PERF_TYPE_HARDWARE || perf_pe[i].type >= PERF_TYPE_MAX) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s :: invalid type\n", name, i, perf_pe[i].name);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perf_pe[i].numasks > PERF_MAX_UMASKS && perf_pe[i].umask_ovfl_idx == PERF_INVAL_OVFL_IDX) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s :: numasks too big (<%d)\n", name, i, perf_pe[i].name, PERF_MAX_UMASKS);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perf_pe[i].numasks < PERF_MAX_UMASKS && perf_pe[i].umask_ovfl_idx != PERF_INVAL_OVFL_IDX) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s :: overflow umask idx defined but not needed (<%d)\n", name, i, perf_pe[i].name, PERF_MAX_UMASKS);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perf_pe[i].numasks && perf_pe[i].ngrp == 0) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s :: ngrp cannot be zero\n", name, i, perf_pe[i].name);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perf_pe[i].numasks == 0 && perf_pe[i].ngrp) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s :: ngrp must be zero\n", name, i, perf_pe[i].name);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(j = 0; j < perf_pe[i].numasks; j++) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (j < PERF_MAX_UMASKS){
|
|
Packit |
577717 |
um = perf_pe[i].umasks+j;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
um = perf_get_ovfl_umask(i);
|
|
Packit |
577717 |
um += j - PERF_MAX_UMASKS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (!um->uname) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s umask%d :: no name\n", name, i, perf_pe[i].name, j);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!um->udesc) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d:%s umask%d: %s :: no description\n", name, i, perf_pe[i].name, j, um->uname);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perf_pe[i].ngrp && um->grpid >= perf_pe[i].ngrp) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s umask%d: %s :: invalid grpid %d (must be < %d)\n", name, i, perf_pe[i].name, j, um->uname, um->grpid, perf_pe[i].ngrp);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* check for excess unit masks */
|
|
Packit |
577717 |
for(; j < PERF_MAX_UMASKS; j++) {
|
|
Packit |
577717 |
if (perf_pe[i].umasks[j].uname || perf_pe[i].umasks[j].udesc) {
|
|
Packit |
577717 |
fprintf(fp, "pmu: %s event%d: %s :: numasks (%d) invalid more events exists\n", name, i, perf_pe[i].name, perf_pe[i].numasks);
|
|
Packit |
577717 |
error++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return error ? PFM_ERR_INVAL : PFM_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static unsigned int
|
|
Packit |
577717 |
pfm_perf_get_event_nattrs(void *this, int idx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return perf_pe[idx].numasks;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* this function tries to figure out what the underlying core PMU
|
|
Packit |
577717 |
* priv level masks are. It looks for a TYPE_CORE PMU and uses the
|
|
Packit |
577717 |
* first event to determine supported priv level masks.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* remove attrs which are in conflicts (or duplicated) with os layer
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_perf_perf_validate_pattrs(void *this, pfmlib_event_desc_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_pmu_t *pmu = this;
|
|
Packit |
577717 |
int i, compact, type;
|
|
Packit |
577717 |
int plm = pmu->supported_plm;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (i = 0; i < e->npattrs; i++) {
|
|
Packit |
577717 |
compact = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* umasks never conflict */
|
|
Packit |
577717 |
if (e->pattrs[i].type == PFM_ATTR_UMASK)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (e->pattrs[i].ctrl != PFM_ATTR_CTRL_PERF_EVENT)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* only PERF_TYPE_HARDWARE/HW_CACHE may have
|
|
Packit |
577717 |
* precise mode or hypervisor mode
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* there is no way to know for sure for those events
|
|
Packit |
577717 |
* so we allow the modifiers and leave it to the kernel
|
|
Packit |
577717 |
* to decide
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
type = perf_pe[e->event].type;
|
|
Packit |
577717 |
if (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) {
|
|
Packit |
577717 |
/* no hypervisor mode */
|
|
Packit |
577717 |
if (e->pattrs[i].idx == PERF_ATTR_H && !(plm & PFM_PLMH))
|
|
Packit |
577717 |
compact = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* no user mode */
|
|
Packit |
577717 |
if (e->pattrs[i].idx == PERF_ATTR_U && !(plm & PFM_PLM3))
|
|
Packit |
577717 |
compact = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* no kernel mode */
|
|
Packit |
577717 |
if (e->pattrs[i].idx == PERF_ATTR_K && !(plm & PFM_PLM0))
|
|
Packit |
577717 |
compact = 1;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
if (e->pattrs[i].idx == PERF_ATTR_PR)
|
|
Packit |
577717 |
compact = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* no hypervisor mode */
|
|
Packit |
577717 |
if (e->pattrs[i].idx == PERF_ATTR_H)
|
|
Packit |
577717 |
compact = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (compact) {
|
|
Packit |
577717 |
pfmlib_compact_pattrs(e, i);
|
|
Packit |
577717 |
i--;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfmlib_pmu_t perf_event_support={
|
|
Packit |
577717 |
.desc = "perf_events generic PMU",
|
|
Packit |
577717 |
.name = "perf",
|
|
Packit |
577717 |
.pmu = PFM_PMU_PERF_EVENT,
|
|
Packit |
577717 |
.pme_count = PME_PERF_EVENT_COUNT,
|
|
Packit |
577717 |
.type = PFM_PMU_TYPE_OS_GENERIC,
|
|
Packit |
577717 |
.max_encoding = 1,
|
|
Packit |
577717 |
.supported_plm = PERF_PLM_ALL,
|
|
Packit |
577717 |
.pmu_detect = pfm_perf_detect,
|
|
Packit |
577717 |
.pmu_init = pfm_perf_init,
|
|
Packit |
577717 |
.pmu_terminate = pfm_perf_terminate,
|
|
Packit |
577717 |
.get_event_encoding[PFM_OS_NONE] = pfm_perf_get_encoding,
|
|
Packit |
577717 |
PFMLIB_ENCODE_PERF(pfm_perf_get_perf_encoding),
|
|
Packit |
577717 |
.get_event_first = pfm_perf_get_event_first,
|
|
Packit |
577717 |
.get_event_next = pfm_perf_get_event_next,
|
|
Packit |
577717 |
.event_is_valid = pfm_perf_event_is_valid,
|
|
Packit |
577717 |
.get_event_info = pfm_perf_get_event_info,
|
|
Packit |
577717 |
.get_event_attr_info = pfm_perf_get_event_attr_info,
|
|
Packit |
577717 |
.validate_table = pfm_perf_validate_table,
|
|
Packit |
577717 |
.get_event_nattrs = pfm_perf_get_event_nattrs,
|
|
Packit |
577717 |
PFMLIB_VALID_PERF_PATTRS(pfm_perf_perf_validate_pattrs),
|
|
Packit |
577717 |
};
|