#include "../../../include/linux/hw_breakpoint.h"#include "util.h"#include "../perf.h"#include "evlist.h"#include "evsel.h"#include "parse-options.h"#include "parse-events.h"#include "exec_cmd.h"#include "string.h"#include "symbol.h"#include "cache.h"#include "header.h"#include "debugfs.h"#include "parse-events-flex.h"#include "pmu.h" #define MAX_NAME_LEN 100 struct event_symbol { u8 type; u64 config; const char *symbol; const char *alias;}; #ifdef PARSER_DEBUGextern int parse_events_debug;#endifint parse_events_parse(struct list_head *list, int *idx); #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x static struct event_symbol event_symbols[] = { { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" }, { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" }, { CHW(INSTRUCTIONS), "instructions", "" }, { CHW(CACHE_REFERENCES), "cache-references", "" }, { CHW(CACHE_MISSES), "cache-misses", "" }, { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, { CHW(BRANCH_MISSES), "branch-misses", "" }, { CHW(BUS_CYCLES), "bus-cycles", "" }, { CHW(REF_CPU_CYCLES), "ref-cycles", "" }, { CSW(CPU_CLOCK), "cpu-clock", "" }, { CSW(TASK_CLOCK), "task-clock", "" }, { CSW(PAGE_FAULTS), "page-faults", "faults" }, { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, { CSW(EMULATION_FAULTS), "emulation-faults", "" },}; #define __PERF_EVENT_FIELD(config, name) \ ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) #define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW)#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG)#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) static const char *sw_event_names[PERF_COUNT_SW_MAX] = { "cpu-clock", "task-clock", "page-faults", "context-switches", "CPU-migrations", "minor-faults", "major-faults", "alignment-faults", "emulation-faults",}; #define MAX_ALIASES 8 static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = { { "L1-dcache", "l1-d", "l1d", "L1-data", }, { "L1-icache", "l1-i", "l1i", "L1-instruction", }, { "LLC", "L2", }, { "dTLB", "d-tlb", "Data-TLB", }, { "iTLB", "i-tlb", "Instruction-TLB", }, { "branch", "branches", "bpu", "btb", "bpc", }, { "node", },}; static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = { { "load", "loads", "read", }, { "store", "stores", "write", }, { "prefetch", "prefetches", "speculative-read", "speculative-load", },}; static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] [MAX_ALIASES] = { { "refs", "Reference", "ops", "access", }, { "misses", "miss", },}; #define C(x) PERF_COUNT_HW_CACHE_##x#define CACHE_READ (1 << C(OP_READ))#define CACHE_WRITE (1 << C(OP_WRITE))#define CACHE_PREFETCH (1 << C(OP_PREFETCH))#define COP(x) (1 << x) /* * cache operartion stat * L1I : Read and prefetch only * ITLB and BPU : Read-only */static unsigned long hw_cache_stat[C(MAX)] = { [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), [C(ITLB)] = (CACHE_READ), [C(BPU)] = (CACHE_READ), [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),}; #define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ if (sys_dirent.d_type == DT_DIR && \ (strcmp(sys_dirent.d_name, ".")) && \ (strcmp(sys_dirent.d_name, ".."))) static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir){ char evt_path[MAXPATHLEN]; int fd; snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, sys_dir->d_name, evt_dir->d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) return -EINVAL; close(fd); return 0;} #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ if (evt_dirent.d_type == DT_DIR && \ (strcmp(evt_dirent.d_name, ".")) && \ (strcmp(evt_dirent.d_name, "..")) && \ (!tp_event_has_id(&sys_dirent, &evt_dirent))) #define MAX_EVENT_LENGTH 512 struct tracepoint_path *tracepoint_id_to_path(u64 config){ struct tracepoint_path *path = NULL; DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char id_buf[24]; int fd; u64 id; char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; if (debugfs_valid_mountpoint(tracing_events_path)) return NULL; sys_dir = opendir(tracing_events_path); if (!sys_dir) return NULL; for_each_subsystem(sys_dir, sys_dirent, sys_next) { snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) continue; for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dirent.d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) continue; if (read(fd, id_buf, sizeof(id_buf)) < 0) { close(fd); continue; } close(fd); id = atoll(id_buf); if (id == config) { closedir(evt_dir); closedir(sys_dir); path = zalloc(sizeof(*path)); path->system = malloc(MAX_EVENT_LENGTH); if (!path->system) { free(path); return NULL; } path->name = malloc(MAX_EVENT_LENGTH); if (!path->name) { free(path->system); free(path); return NULL; } strncpy(path->system, sys_dirent.d_name, MAX_EVENT_LENGTH); strncpy(path->name, evt_dirent.d_name, MAX_EVENT_LENGTH); return path; } } closedir(evt_dir); } closedir(sys_dir); return NULL;} #define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)static const char *tracepoint_id_to_name(u64 config){ static char buf[TP_PATH_LEN]; struct tracepoint_path *path; path = tracepoint_id_to_path(config); if (path) { snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name); free(path->name); free(path->system); free(path); } else snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown"); return buf;} static int is_cache_op_valid(u8 cache_type, u8 cache_op){ if (hw_cache_stat[cache_type] & COP(cache_op)) return 1; /* valid */ else return 0; /* invalid */} static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result){ static char name[50]; if (cache_result) { sprintf(name, "%s-%s-%s", hw_cache[cache_type][0], hw_cache_op[cache_op][0], hw_cache_result[cache_result][0]); } else { sprintf(name, "%s-%s", hw_cache[cache_type][0], hw_cache_op[cache_op][1]); } return name;} const char *event_type(int type){ switch (type) { case PERF_TYPE_HARDWARE: return "hardware"; case PERF_TYPE_SOFTWARE: return "software"; case PERF_TYPE_TRACEPOINT: return "tracepoint"; case PERF_TYPE_HW_CACHE: return "hardware-cache"; default: break; } return "unknown";} const char *event_name(struct perf_evsel *evsel){ u64 config = evsel->attr.config; int type = evsel->attr.type; if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) { /* * XXX minimal fix, see comment on perf_evsen__name, this static buffer * will go away together with event_name in the next devel cycle. */ static char bf[128]; perf_evsel__name(evsel, bf, sizeof(bf)); return bf; } if (evsel->name) return evsel->name; return __event_name(type, config);} const char *__event_name(int type, u64 config){ static char buf[32]; if (type == PERF_TYPE_RAW) { sprintf(buf, "raw 0x%" PRIx64, config); return buf; } switch (type) { case PERF_TYPE_HARDWARE: return __perf_evsel__hw_name(config); case PERF_TYPE_HW_CACHE: { u8 cache_type, cache_op, cache_result; cache_type = (config >> 0) & 0xff; if (cache_type > PERF_COUNT_HW_CACHE_MAX) return "unknown-ext-hardware-cache-type"; cache_op = (config >> 8) & 0xff; if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX) return "unknown-ext-hardware-cache-op"; cache_result = (config >> 16) & 0xff; if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) return "unknown-ext-hardware-cache-result"; if (!is_cache_op_valid(cache_type, cache_op)) return "invalid-cache"; return event_cache_name(cache_type, cache_op, cache_result); } case PERF_TYPE_SOFTWARE: if (config < PERF_COUNT_SW_MAX && sw_event_names[config]) return sw_event_names[config]; return "unknown-software"; case PERF_TYPE_TRACEPOINT: return tracepoint_id_to_name(config); default: break; } return "unknown";} static int add_event(struct list_head **_list, int *idx, struct perf_event_attr *attr, char *name){ struct perf_evsel *evsel; struct list_head *list = *_list; if (!list) { list = malloc(sizeof(*list)); if (!list) return -ENOMEM; INIT_LIST_HEAD(list); } event_attr_init(attr); evsel = perf_evsel__new(attr, (*idx)++); if (!evsel) { free(list); return -ENOMEM; } evsel->name = strdup(name); list_add_tail(&evsel->node, list); *_list = list; return 0;} static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size){ int i, j; int n, longest = -1; for (i = 0; i < size; i++) { for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { n = strlen(names[i][j]); if (n > longest && !strncasecmp(str, names[i][j], n)) longest = n; } if (longest > 0) return i; } return -1;} int parse_events_add_cache(struct list_head **list, int *idx, char *type, char *op_result1, char *op_result2){ struct perf_event_attr attr; char name[MAX_NAME_LEN]; int cache_type = -1, cache_op = -1, cache_result = -1; char *op_result[2] = { op_result1, op_result2 }; int i, n; /* * No fallback - if we cannot get a clear cache type * then bail out: */ cache_type = parse_aliases(type, hw_cache, PERF_COUNT_HW_CACHE_MAX); if (cache_type == -1) return -EINVAL; n = snprintf(name, MAX_NAME_LEN, "%s", type); for (i = 0; (i < 2) && (op_result[i]); i++) { char *str = op_result[i]; snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); if (cache_op == -1) { cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); if (cache_op >= 0) { if (!is_cache_op_valid(cache_type, cache_op)) return -EINVAL; continue; } } if (cache_result == -1) { cache_result = parse_aliases(str, hw_cache_result, PERF_COUNT_HW_CACHE_RESULT_MAX); if (cache_result >= 0) continue; } } /* * Fall back to reads: */ if (cache_op == -1) cache_op = PERF_COUNT_HW_CACHE_OP_READ; /* * Fall back to accesses: */ if (cache_result == -1) cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; memset(&attr, 0, sizeof(attr)); attr.config = cache_type | (cache_op << 8) | (cache_result << 16); attr.type = PERF_TYPE_HW_CACHE; return add_event(list, idx, &attr, name);} static int add_tracepoint(struct list_head **list, int *idx, char *sys_name, char *evt_name){ struct perf_event_attr attr; char name[MAX_NAME_LEN]; char evt_path[MAXPATHLEN]; char id_buf[4]; u64 id; int fd; snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, sys_name, evt_name); fd = open(evt_path, O_RDONLY); if (fd < 0) return -1; if (read(fd, id_buf, sizeof(id_buf)) < 0) { close(fd); return -1; } close(fd); id = atoll(id_buf); memset(&attr, 0, sizeof(attr)); attr.config = id; attr.type = PERF_TYPE_TRACEPOINT; attr.sample_type |= PERF_SAMPLE_RAW; attr.sample_type |= PERF_SAMPLE_TIME; attr.sample_type |= PERF_SAMPLE_CPU; attr.sample_period = 1; snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); return add_event(list, idx, &attr, name);} static int add_tracepoint_multi(struct list_head **list, int *idx, char *sys_name, char *evt_name){Lines 1–500 of 1117. Load more
#include "../../../include/linux/hw_breakpoint.h" #include "util.h" #include "../perf.h" #include "evlist.h" #include "evsel.h" #include "parse-options.h" #include "parse-events.h" #include "exec_cmd.h" #include "string.h" #include "symbol.h" #include "cache.h" #include "header.h" #include "debugfs.h" #include "parse-events-flex.h" #include "pmu.h" #define MAX_NAME_LEN 100 struct event_symbol { u8 type; u64 config; const char *symbol; const char *alias; }; #ifdef PARSER_DEBUG extern int parse_events_debug; #endif int parse_events_parse(struct list_head *list, int *idx); #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x static struct event_symbol event_symbols[] = { { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" }, { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" }, { CHW(INSTRUCTIONS), "instructions", "" }, { CHW(CACHE_REFERENCES), "cache-references", "" }, { CHW(CACHE_MISSES), "cache-misses", "" }, { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, { CHW(BRANCH_MISSES), "branch-misses", "" }, { CHW(BUS_CYCLES), "bus-cycles", "" }, { CHW(REF_CPU_CYCLES), "ref-cycles", "" }, { CSW(CPU_CLOCK), "cpu-clock", "" }, { CSW(TASK_CLOCK), "task-clock", "" }, { CSW(PAGE_FAULTS), "page-faults", "faults" }, { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, { CSW(EMULATION_FAULTS), "emulation-faults", "" }, }; #define __PERF_EVENT_FIELD(config, name) \ ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) #define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) #define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) static const char *sw_event_names[PERF_COUNT_SW_MAX] = { "cpu-clock", "task-clock", "page-faults", "context-switches", "CPU-migrations", "minor-faults", "major-faults", "alignment-faults", "emulation-faults", }; #define MAX_ALIASES 8 static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = { { "L1-dcache", "l1-d", "l1d", "L1-data", }, { "L1-icache", "l1-i", "l1i", "L1-instruction", }, { "LLC", "L2", }, { "dTLB", "d-tlb", "Data-TLB", }, { "iTLB", "i-tlb", "Instruction-TLB", }, { "branch", "branches", "bpu", "btb", "bpc", }, { "node", }, }; static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = { { "load", "loads", "read", }, { "store", "stores", "write", }, { "prefetch", "prefetches", "speculative-read", "speculative-load", }, }; static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] [MAX_ALIASES] = { { "refs", "Reference", "ops", "access", }, { "misses", "miss", }, }; #define C(x) PERF_COUNT_HW_CACHE_##x #define CACHE_READ (1 << C(OP_READ)) #define CACHE_WRITE (1 << C(OP_WRITE)) #define CACHE_PREFETCH (1 << C(OP_PREFETCH)) #define COP(x) (1 << x) /* * cache operartion stat * L1I : Read and prefetch only * ITLB and BPU : Read-only */ static unsigned long hw_cache_stat[C(MAX)] = { [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), [C(ITLB)] = (CACHE_READ), [C(BPU)] = (CACHE_READ), [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), }; #define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ if (sys_dirent.d_type == DT_DIR && \ (strcmp(sys_dirent.d_name, ".")) && \ (strcmp(sys_dirent.d_name, ".."))) static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) { char evt_path[MAXPATHLEN]; int fd; snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, sys_dir->d_name, evt_dir->d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) return -EINVAL; close(fd); return 0; } #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ if (evt_dirent.d_type == DT_DIR && \ (strcmp(evt_dirent.d_name, ".")) && \ (strcmp(evt_dirent.d_name, "..")) && \ (!tp_event_has_id(&sys_dirent, &evt_dirent))) #define MAX_EVENT_LENGTH 512 struct tracepoint_path *tracepoint_id_to_path(u64 config) { struct tracepoint_path *path = NULL; DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char id_buf[24]; int fd; u64 id; char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; if (debugfs_valid_mountpoint(tracing_events_path)) return NULL; sys_dir = opendir(tracing_events_path); if (!sys_dir) return NULL; for_each_subsystem(sys_dir, sys_dirent, sys_next) { snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) continue; for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dirent.d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) continue; if (read(fd, id_buf, sizeof(id_buf)) < 0) { close(fd); continue; } close(fd); id = atoll(id_buf); if (id == config) { closedir(evt_dir); closedir(sys_dir); path = zalloc(sizeof(*path)); path->system = malloc(MAX_EVENT_LENGTH); if (!path->system) { free(path); return NULL; } path->name = malloc(MAX_EVENT_LENGTH); if (!path->name) { free(path->system); free(path); return NULL; } strncpy(path->system, sys_dirent.d_name, MAX_EVENT_LENGTH); strncpy(path->name, evt_dirent.d_name, MAX_EVENT_LENGTH); return path; } } closedir(evt_dir); } closedir(sys_dir); return NULL; } #define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1) static const char *tracepoint_id_to_name(u64 config) { static char buf[TP_PATH_LEN]; struct tracepoint_path *path; path = tracepoint_id_to_path(config); if (path) { snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name); free(path->name); free(path->system); free(path); } else snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown"); return buf; } static int is_cache_op_valid(u8 cache_type, u8 cache_op) { if (hw_cache_stat[cache_type] & COP(cache_op)) return 1; /* valid */ else return 0; /* invalid */ } static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) { static char name[50]; if (cache_result) { sprintf(name, "%s-%s-%s", hw_cache[cache_type][0], hw_cache_op[cache_op][0], hw_cache_result[cache_result][0]); } else { sprintf(name, "%s-%s", hw_cache[cache_type][0], hw_cache_op[cache_op][1]); } return name; } const char *event_type(int type) { switch (type) { case PERF_TYPE_HARDWARE: return "hardware"; case PERF_TYPE_SOFTWARE: return "software"; case PERF_TYPE_TRACEPOINT: return "tracepoint"; case PERF_TYPE_HW_CACHE: return "hardware-cache"; default: break; } return "unknown"; } const char *event_name(struct perf_evsel *evsel) { u64 config = evsel->attr.config; int type = evsel->attr.type; if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) { /* * XXX minimal fix, see comment on perf_evsen__name, this static buffer * will go away together with event_name in the next devel cycle. */ static char bf[128]; perf_evsel__name(evsel, bf, sizeof(bf)); return bf; } if (evsel->name) return evsel->name; return __event_name(type, config); } const char *__event_name(int type, u64 config) { static char buf[32]; if (type == PERF_TYPE_RAW) { sprintf(buf, "raw 0x%" PRIx64, config); return buf; } switch (type) { case PERF_TYPE_HARDWARE: return __perf_evsel__hw_name(config); case PERF_TYPE_HW_CACHE: { u8 cache_type, cache_op, cache_result; cache_type = (config >> 0) & 0xff; if (cache_type > PERF_COUNT_HW_CACHE_MAX) return "unknown-ext-hardware-cache-type"; cache_op = (config >> 8) & 0xff; if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX) return "unknown-ext-hardware-cache-op"; cache_result = (config >> 16) & 0xff; if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) return "unknown-ext-hardware-cache-result"; if (!is_cache_op_valid(cache_type, cache_op)) return "invalid-cache"; return event_cache_name(cache_type, cache_op, cache_result); } case PERF_TYPE_SOFTWARE: if (config < PERF_COUNT_SW_MAX && sw_event_names[config]) return sw_event_names[config]; return "unknown-software"; case PERF_TYPE_TRACEPOINT: return tracepoint_id_to_name(config); default: break; } return "unknown"; } static int add_event(struct list_head **_list, int *idx, struct perf_event_attr *attr, char *name) { struct perf_evsel *evsel; struct list_head *list = *_list; if (!list) { list = malloc(sizeof(*list)); if (!list) return -ENOMEM; INIT_LIST_HEAD(list); } event_attr_init(attr); evsel = perf_evsel__new(attr, (*idx)++); if (!evsel) { free(list); return -ENOMEM; } evsel->name = strdup(name); list_add_tail(&evsel->node, list); *_list = list; return 0; } static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size) { int i, j; int n, longest = -1; for (i = 0; i < size; i++) { for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { n = strlen(names[i][j]); if (n > longest && !strncasecmp(str, names[i][j], n)) longest = n; } if (longest > 0) return i; } return -1; } int parse_events_add_cache(struct list_head **list, int *idx, char *type, char *op_result1, char *op_result2) { struct perf_event_attr attr; char name[MAX_NAME_LEN]; int cache_type = -1, cache_op = -1, cache_result = -1; char *op_result[2] = { op_result1, op_result2 }; int i, n; /* * No fallback - if we cannot get a clear cache type * then bail out: */ cache_type = parse_aliases(type, hw_cache, PERF_COUNT_HW_CACHE_MAX); if (cache_type == -1) return -EINVAL; n = snprintf(name, MAX_NAME_LEN, "%s", type); for (i = 0; (i < 2) && (op_result[i]); i++) { char *str = op_result[i]; snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); if (cache_op == -1) { cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); if (cache_op >= 0) { if (!is_cache_op_valid(cache_type, cache_op)) return -EINVAL; continue; } } if (cache_result == -1) { cache_result = parse_aliases(str, hw_cache_result, PERF_COUNT_HW_CACHE_RESULT_MAX); if (cache_result >= 0) continue; } } /* * Fall back to reads: */ if (cache_op == -1) cache_op = PERF_COUNT_HW_CACHE_OP_READ; /* * Fall back to accesses: */ if (cache_result == -1) cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; memset(&attr, 0, sizeof(attr)); attr.config = cache_type | (cache_op << 8) | (cache_result << 16); attr.type = PERF_TYPE_HW_CACHE; return add_event(list, idx, &attr, name); } static int add_tracepoint(struct list_head **list, int *idx, char *sys_name, char *evt_name) { struct perf_event_attr attr; char name[MAX_NAME_LEN]; char evt_path[MAXPATHLEN]; char id_buf[4]; u64 id; int fd; snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, sys_name, evt_name); fd = open(evt_path, O_RDONLY); if (fd < 0) return -1; if (read(fd, id_buf, sizeof(id_buf)) < 0) { close(fd); return -1; } close(fd); id = atoll(id_buf); memset(&attr, 0, sizeof(attr)); attr.config = id; attr.type = PERF_TYPE_TRACEPOINT; attr.sample_type |= PERF_SAMPLE_RAW; attr.sample_type |= PERF_SAMPLE_TIME; attr.sample_type |= PERF_SAMPLE_CPU; attr.sample_period = 1; snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); return add_event(list, idx, &attr, name); } static int add_tracepoint_multi(struct list_head **list, int *idx, char *sys_name, char *evt_name) {