summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/parse-events.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r--tools/perf/util/parse-events.c388
1 files changed, 258 insertions, 130 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4af5bd59cfd..41982c373fa 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,6 +1,8 @@
#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"
@@ -10,11 +12,6 @@
#include "header.h"
#include "debugfs.h"
-int nr_counters;
-
-struct perf_event_attr attrs[MAX_COUNTERS];
-char *filters[MAX_COUNTERS];
-
struct event_symbol {
u8 type;
u64 config;
@@ -34,34 +31,36 @@ char debugfs_path[MAXPATHLEN];
#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(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", "" },
-
- { 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", "" },
+ { 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", "" },
+
+ { 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_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_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
-static const char *hw_event_names[] = {
+static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
"cycles",
"instructions",
"cache-references",
@@ -69,11 +68,13 @@ static const char *hw_event_names[] = {
"branches",
"branch-misses",
"bus-cycles",
+ "stalled-cycles-frontend",
+ "stalled-cycles-backend",
};
-static const char *sw_event_names[] = {
- "cpu-clock-msecs",
- "task-clock-msecs",
+static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
+ "cpu-clock",
+ "task-clock",
"page-faults",
"context-switches",
"CPU-migrations",
@@ -266,10 +267,35 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
return name;
}
-const char *event_name(int counter)
+const char *event_type(int type)
{
- u64 config = attrs[counter].config;
- int type = attrs[counter].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 (evsel->name)
+ return evsel->name;
return __event_name(type, config);
}
@@ -279,13 +305,13 @@ const char *__event_name(int type, u64 config)
static char buf[32];
if (type == PERF_TYPE_RAW) {
- sprintf(buf, "raw 0x%llx", config);
+ sprintf(buf, "raw 0x%" PRIx64, config);
return buf;
}
switch (type) {
case PERF_TYPE_HARDWARE:
- if (config < PERF_COUNT_HW_MAX)
+ if (config < PERF_COUNT_HW_MAX && hw_event_names[config])
return hw_event_names[config];
return "unknown-hardware";
@@ -311,7 +337,7 @@ const char *__event_name(int type, u64 config)
}
case PERF_TYPE_SOFTWARE:
- if (config < PERF_COUNT_SW_MAX)
+ if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
return sw_event_names[config];
return "unknown-software";
@@ -434,7 +460,7 @@ parse_single_tracepoint_event(char *sys_name,
id = atoll(id_buf);
attr->config = id;
attr->type = PERF_TYPE_TRACEPOINT;
- *strp = evt_name + evt_length;
+ *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
attr->sample_type |= PERF_SAMPLE_RAW;
attr->sample_type |= PERF_SAMPLE_TIME;
@@ -449,8 +475,8 @@ parse_single_tracepoint_event(char *sys_name,
/* sys + ':' + event + ':' + flags*/
#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
static enum event_result
-parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
- char *flags)
+parse_multiple_tracepoint_event(const struct option *opt, char *sys_name,
+ const char *evt_exp, char *flags)
{
char evt_path[MAXPATHLEN];
struct dirent *evt_ent;
@@ -483,19 +509,19 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
if (len < 0)
return EVT_FAILED;
- if (parse_events(NULL, event_opt, 0))
+ if (parse_events(opt, event_opt, 0))
return EVT_FAILED;
}
return EVT_HANDLED_ALL;
}
-
-static enum event_result parse_tracepoint_event(const char **strp,
- struct perf_event_attr *attr)
+static enum event_result
+parse_tracepoint_event(const struct option *opt, const char **strp,
+ struct perf_event_attr *attr)
{
const char *evt_name;
- char *flags;
+ char *flags = NULL, *comma_loc;
char sys_name[MAX_EVENT_LENGTH];
unsigned int sys_length, evt_length;
@@ -514,6 +540,11 @@ static enum event_result parse_tracepoint_event(const char **strp,
sys_name[sys_length] = '\0';
evt_name = evt_name + 1;
+ comma_loc = strchr(evt_name, ',');
+ if (comma_loc) {
+ /* take the event name up to the comma */
+ evt_name = strndup(evt_name, comma_loc - evt_name);
+ }
flags = strchr(evt_name, ':');
if (flags) {
/* split it out: */
@@ -524,14 +555,14 @@ static enum event_result parse_tracepoint_event(const char **strp,
evt_length = strlen(evt_name);
if (evt_length >= MAX_EVENT_LENGTH)
return EVT_FAILED;
-
if (strpbrk(evt_name, "*?")) {
- *strp = evt_name + evt_length;
- return parse_multiple_tracepoint_event(sys_name, evt_name,
+ *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
+ return parse_multiple_tracepoint_event(opt, sys_name, evt_name,
flags);
- } else
+ } else {
return parse_single_tracepoint_event(sys_name, evt_name,
evt_length, attr, strp);
+ }
}
static enum event_result
@@ -621,13 +652,15 @@ static int check_events(const char *str, unsigned int i)
int n;
n = strlen(event_symbols[i].symbol);
- if (!strncmp(str, event_symbols[i].symbol, n))
+ if (!strncasecmp(str, event_symbols[i].symbol, n))
return n;
n = strlen(event_symbols[i].alias);
- if (n)
- if (!strncmp(str, event_symbols[i].alias, n))
+ if (n) {
+ if (!strncasecmp(str, event_symbols[i].alias, n))
return n;
+ }
+
return 0;
}
@@ -691,15 +724,22 @@ parse_numeric_event(const char **strp, struct perf_event_attr *attr)
return EVT_FAILED;
}
-static enum event_result
+static int
parse_event_modifier(const char **strp, struct perf_event_attr *attr)
{
const char *str = *strp;
int exclude = 0;
int eu = 0, ek = 0, eh = 0, precise = 0;
- if (*str++ != ':')
+ if (!*str)
return 0;
+
+ if (*str == ',')
+ return 0;
+
+ if (*str++ != ':')
+ return -1;
+
while (*str) {
if (*str == 'u') {
if (!exclude)
@@ -720,14 +760,16 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
++str;
}
- if (str >= *strp + 2) {
- *strp = str;
- attr->exclude_user = eu;
- attr->exclude_kernel = ek;
- attr->exclude_hv = eh;
- attr->precise_ip = precise;
- return 1;
- }
+ if (str < *strp + 2)
+ return -1;
+
+ *strp = str;
+
+ attr->exclude_user = eu;
+ attr->exclude_kernel = ek;
+ attr->exclude_hv = eh;
+ attr->precise_ip = precise;
+
return 0;
}
@@ -736,11 +778,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
* Symbolic names are (almost) exactly matched.
*/
static enum event_result
-parse_event_symbols(const char **str, struct perf_event_attr *attr)
+parse_event_symbols(const struct option *opt, const char **str,
+ struct perf_event_attr *attr)
{
enum event_result ret;
- ret = parse_tracepoint_event(str, attr);
+ ret = parse_tracepoint_event(opt, str, attr);
if (ret != EVT_FAILED)
goto modifier;
@@ -769,52 +812,27 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
return EVT_FAILED;
modifier:
- parse_event_modifier(str, attr);
-
- return ret;
-}
-
-static int store_event_type(const char *orgname)
-{
- char filename[PATH_MAX], *c;
- FILE *file;
- int id, n;
+ if (parse_event_modifier(str, attr) < 0) {
+ fprintf(stderr, "invalid event modifier: '%s'\n", *str);
+ fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
- sprintf(filename, "%s/", debugfs_path);
- strncat(filename, orgname, strlen(orgname));
- strcat(filename, "/id");
-
- c = strchr(filename, ':');
- if (c)
- *c = '/';
-
- file = fopen(filename, "r");
- if (!file)
- return 0;
- n = fscanf(file, "%i", &id);
- fclose(file);
- if (n < 1) {
- pr_err("cannot store event ID\n");
- return -EINVAL;
+ return EVT_FAILED;
}
- return perf_header__push_event(id, orgname);
+
+ return ret;
}
-int parse_events(const struct option *opt __used, const char *str, int unset __used)
+int parse_events(const struct option *opt, const char *str, int unset __used)
{
+ struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
struct perf_event_attr attr;
enum event_result ret;
-
- if (strchr(str, ':'))
- if (store_event_type(str) < 0)
- return -1;
+ const char *ostr;
for (;;) {
- if (nr_counters == MAX_COUNTERS)
- return -1;
-
+ ostr = str;
memset(&attr, 0, sizeof(attr));
- ret = parse_event_symbols(&str, &attr);
+ ret = parse_event_symbols(opt, &str, &attr);
if (ret == EVT_FAILED)
return -1;
@@ -822,8 +840,16 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
return -1;
if (ret != EVT_HANDLED_ALL) {
- attrs[nr_counters] = attr;
- nr_counters++;
+ struct perf_evsel *evsel;
+ evsel = perf_evsel__new(&attr, evlist->nr_entries);
+ if (evsel == NULL)
+ return -1;
+ perf_evlist__add(evlist, evsel);
+
+ evsel->name = calloc(str - ostr + 1, 1);
+ if (!evsel->name)
+ return -1;
+ strncpy(evsel->name, ostr, str - ostr);
}
if (*str == 0)
@@ -837,24 +863,26 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
return 0;
}
-int parse_filter(const struct option *opt __used, const char *str,
+int parse_filter(const struct option *opt, const char *str,
int unset __used)
{
- int i = nr_counters - 1;
- int len = strlen(str);
+ struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
+ struct perf_evsel *last = NULL;
+
+ if (evlist->nr_entries > 0)
+ last = list_entry(evlist->entries.prev, struct perf_evsel, node);
- if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
+ if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
fprintf(stderr,
"-F option should follow a -e tracepoint option\n");
return -1;
}
- filters[i] = malloc(len + 1);
- if (!filters[i]) {
+ last->filter = strdup(str);
+ if (last->filter == NULL) {
fprintf(stderr, "not enough memory to hold filter string\n");
return -1;
}
- strcpy(filters[i], str);
return 0;
}
@@ -872,7 +900,7 @@ static const char * const event_type_descriptors[] = {
* Print the events from <debugfs_mount_point>/tracing/events
*/
-static void print_tracepoint_events(void)
+void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
{
DIR *sys_dir, *evt_dir;
struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
@@ -887,6 +915,9 @@ static void print_tracepoint_events(void)
return;
for_each_subsystem(sys_dir, sys_dirent, sys_next) {
+ if (subsys_glob != NULL &&
+ !strglobmatch(sys_dirent.d_name, subsys_glob))
+ continue;
snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
sys_dirent.d_name);
@@ -895,9 +926,13 @@ static void print_tracepoint_events(void)
continue;
for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
+ if (event_glob != NULL &&
+ !strglobmatch(evt_dirent.d_name, event_glob))
+ continue;
+
snprintf(evt_path, MAXPATHLEN, "%s:%s",
sys_dirent.d_name, evt_dirent.d_name);
- printf(" %-42s [%s]\n", evt_path,
+ printf(" %-50s [%s]\n", evt_path,
event_type_descriptors[PERF_TYPE_TRACEPOINT]);
}
closedir(evt_dir);
@@ -906,34 +941,71 @@ static void print_tracepoint_events(void)
}
/*
- * Print the help text for the event symbols:
+ * Check whether event is in <debugfs_mount_point>/tracing/events
*/
-void print_events(void)
+
+int is_valid_tracepoint(const char *event_string)
{
- struct event_symbol *syms = event_symbols;
- unsigned int i, type, op, prev_type = -1;
- char name[40];
+ DIR *sys_dir, *evt_dir;
+ struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
+ char evt_path[MAXPATHLEN];
+ char dir_path[MAXPATHLEN];
- printf("\n");
- printf("List of pre-defined events (to be used in -e):\n");
+ if (debugfs_valid_mountpoint(debugfs_path))
+ return 0;
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
- type = syms->type;
+ sys_dir = opendir(debugfs_path);
+ if (!sys_dir)
+ return 0;
- if (type != prev_type)
- printf("\n");
+ for_each_subsystem(sys_dir, sys_dirent, sys_next) {
+
+ snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_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",
+ sys_dirent.d_name, evt_dirent.d_name);
+ if (!strcmp(evt_path, event_string)) {
+ closedir(evt_dir);
+ closedir(sys_dir);
+ return 1;
+ }
+ }
+ closedir(evt_dir);
+ }
+ closedir(sys_dir);
+ return 0;
+}
+
+void print_events_type(u8 type)
+{
+ struct event_symbol *syms = event_symbols;
+ unsigned int i;
+ char name[64];
+
+ for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
+ if (type != syms->type)
+ continue;
if (strlen(syms->alias))
- sprintf(name, "%s OR %s", syms->symbol, syms->alias);
+ snprintf(name, sizeof(name), "%s OR %s",
+ syms->symbol, syms->alias);
else
- strcpy(name, syms->symbol);
- printf(" %-42s [%s]\n", name,
- event_type_descriptors[type]);
+ snprintf(name, sizeof(name), "%s", syms->symbol);
- prev_type = type;
+ printf(" %-50s [%s]\n", name,
+ event_type_descriptors[type]);
}
+}
+
+int print_hwcache_events(const char *event_glob)
+{
+ unsigned int type, op, i, printed = 0;
- printf("\n");
for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
/* skip invalid cache type */
@@ -941,25 +1013,81 @@ void print_events(void)
continue;
for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
- printf(" %-42s [%s]\n",
- event_cache_name(type, op, i),
+ char *name = event_cache_name(type, op, i);
+
+ if (event_glob != NULL && !strglobmatch(name, event_glob))
+ continue;
+
+ printf(" %-50s [%s]\n", name,
event_type_descriptors[PERF_TYPE_HW_CACHE]);
+ ++printed;
}
}
}
+ return printed;
+}
+
+#define MAX_NAME_LEN 100
+
+/*
+ * Print the help text for the event symbols:
+ */
+void print_events(const char *event_glob)
+{
+ unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
+ struct event_symbol *syms = event_symbols;
+ char name[MAX_NAME_LEN];
+
+ printf("\n");
+ printf("List of pre-defined events (to be used in -e):\n");
+
+ for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
+ type = syms->type;
+
+ if (type != prev_type && printed) {
+ printf("\n");
+ printed = 0;
+ ntypes_printed++;
+ }
+
+ if (event_glob != NULL &&
+ !(strglobmatch(syms->symbol, event_glob) ||
+ (syms->alias && strglobmatch(syms->alias, event_glob))))
+ continue;
+
+ if (strlen(syms->alias))
+ snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
+ else
+ strncpy(name, syms->symbol, MAX_NAME_LEN);
+ printf(" %-50s [%s]\n", name,
+ event_type_descriptors[type]);
+
+ prev_type = type;
+ ++printed;
+ }
+
+ if (ntypes_printed) {
+ printed = 0;
+ printf("\n");
+ }
+ print_hwcache_events(event_glob);
+
+ if (event_glob != NULL)
+ return;
+
printf("\n");
- printf(" %-42s [%s]\n",
+ printf(" %-50s [%s]\n",
"rNNN (see 'perf list --help' on how to encode it)",
event_type_descriptors[PERF_TYPE_RAW]);
printf("\n");
- printf(" %-42s [%s]\n",
+ printf(" %-50s [%s]\n",
"mem:<addr>[:access]",
event_type_descriptors[PERF_TYPE_BREAKPOINT]);
printf("\n");
- print_tracepoint_events();
+ print_tracepoint_events(NULL, NULL);
exit(129);
}