cregit-Linux how code gets into the kernel

Release 4.10 tools/perf/util/parse-events.c

Directory: tools/perf/util
#include <linux/hw_breakpoint.h>
#include <linux/err.h>
#include "util.h"
#include "../perf.h"
#include "evlist.h"
#include "evsel.h"
#include <subcmd/parse-options.h>
#include "parse-events.h"
#include <subcmd/exec-cmd.h>
#include "string.h"
#include "symbol.h"
#include "cache.h"
#include "header.h"
#include "bpf-loader.h"
#include "debug.h"
#include <api/fs/tracing_path.h>
#include "parse-events-bison.h"

#define YY_EXTRA_TYPE int
#include "parse-events-flex.h"
#include "pmu.h"
#include "thread_map.h"
#include "cpumap.h"
#include "probe-file.h"
#include "asm/bug.h"
#include "util/parse-branch-options.h"


#define MAX_NAME_LEN 100

#ifdef PARSER_DEBUG
extern int parse_events_debug;
#endif
int parse_events_parse(void *data, void *scanner);
static int get_config_terms(struct list_head *head_config,
			    struct list_head *head_terms __maybe_unused);


static struct perf_pmu_event_symbol *perf_pmu_events_list;
/*
 * The variable indicates the number of supported pmu event symbols.
 * 0 means not initialized and ready to init
 * -1 means failed to init, don't try anymore
 * >0 is the number of supported pmu event symbols
 */

static int perf_pmu_events_list_num;


struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
	[PERF_COUNT_HW_CPU_CYCLES] = {
		.symbol = "cpu-cycles",
		.alias  = "cycles",
        },
	[PERF_COUNT_HW_INSTRUCTIONS] = {
		.symbol = "instructions",
		.alias  = "",
        },
	[PERF_COUNT_HW_CACHE_REFERENCES] = {
		.symbol = "cache-references",
		.alias  = "",
        },
	[PERF_COUNT_HW_CACHE_MISSES] = {
		.symbol = "cache-misses",
		.alias  = "",
        },
	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = {
		.symbol = "branch-instructions",
		.alias  = "branches",
        },
	[PERF_COUNT_HW_BRANCH_MISSES] = {
		.symbol = "branch-misses",
		.alias  = "",
        },
	[PERF_COUNT_HW_BUS_CYCLES] = {
		.symbol = "bus-cycles",
		.alias  = "",
        },
	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = {
		.symbol = "stalled-cycles-frontend",
		.alias  = "idle-cycles-frontend",
        },
	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = {
		.symbol = "stalled-cycles-backend",
		.alias  = "idle-cycles-backend",
        },
	[PERF_COUNT_HW_REF_CPU_CYCLES] = {
		.symbol = "ref-cycles",
		.alias  = "",
        },
};


struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
	[PERF_COUNT_SW_CPU_CLOCK] = {
		.symbol = "cpu-clock",
		.alias  = "",
        },
	[PERF_COUNT_SW_TASK_CLOCK] = {
		.symbol = "task-clock",
		.alias  = "",
        },
	[PERF_COUNT_SW_PAGE_FAULTS] = {
		.symbol = "page-faults",
		.alias  = "faults",
        },
	[PERF_COUNT_SW_CONTEXT_SWITCHES] = {
		.symbol = "context-switches",
		.alias  = "cs",
        },
	[PERF_COUNT_SW_CPU_MIGRATIONS] = {
		.symbol = "cpu-migrations",
		.alias  = "migrations",
        },
	[PERF_COUNT_SW_PAGE_FAULTS_MIN] = {
		.symbol = "minor-faults",
		.alias  = "",
        },
	[PERF_COUNT_SW_PAGE_FAULTS_MAJ] = {
		.symbol = "major-faults",
		.alias  = "",
        },
	[PERF_COUNT_SW_ALIGNMENT_FAULTS] = {
		.symbol = "alignment-faults",
		.alias  = "",
        },
	[PERF_COUNT_SW_EMULATION_FAULTS] = {
		.symbol = "emulation-faults",
		.alias  = "",
        },
	[PERF_COUNT_SW_DUMMY] = {
		.symbol = "dummy",
		.alias  = "",
        },
	[PERF_COUNT_SW_BPF_OUTPUT] = {
		.symbol = "bpf-output",
		.alias  = "",
        },
};


#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)


#define for_each_subsystem(sys_dir, sys_dirent)			\
	while ((sys_dirent = readdir(sys_dir)) != NULL)         \
                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; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra7098.59%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo11.41%150.00%
Total71100.00%2100.00%

#define for_each_event(sys_dirent, evt_dir, evt_dirent) \ while ((evt_dirent = readdir(evt_dir)) != NULL) \ 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_dirent, *evt_dirent; char id_buf[24]; int fd; u64 id; char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; sys_dir = opendir(tracing_events_path); if (!sys_dir) return NULL; for_each_subsystem(sys_dir, sys_dirent) { 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) { 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) { zfree(&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; }

Contributors

PersonTokensPropCommitsCommitProp
jason baronjason baron17756.19%17.69%
frederic weisbeckerfrederic weisbecker7925.08%17.69%
eric dumazeteric dumazet237.30%17.69%
arnaldo carvalho de meloarnaldo carvalho de melo175.40%538.46%
stephane eranianstephane eranian72.22%215.38%
ulrich drepperulrich drepper61.90%17.69%
peter zijlstrapeter zijlstra51.59%17.69%
julia lawalljulia lawall10.32%17.69%
Total315100.00%13100.00%


struct tracepoint_path *tracepoint_name_to_path(const char *name) { struct tracepoint_path *path = zalloc(sizeof(*path)); char *str = strchr(name, ':'); if (path == NULL || str == NULL) { free(path); return NULL; } path->system = strndup(name, str - name); path->name = strdup(str+1); if (path->system == NULL || path->name == NULL) { zfree(&path->system); zfree(&path->name); free(path); path = NULL; } return path; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim12196.80%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo43.20%150.00%
Total125100.00%2100.00%


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"; }

Contributors

PersonTokensPropCommitsCommitProp
ingo molnaringo molnar2555.56%342.86%
david aherndavid ahern817.78%114.29%
peter zijlstrapeter zijlstra715.56%114.29%
jason baronjason baron48.89%114.29%
jaswinder singh rajputjaswinder singh rajput12.22%114.29%
Total45100.00%7100.00%


static int parse_events__is_name_term(struct parse_events_term *term) { return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; }

Contributors

PersonTokensPropCommitsCommitProp
wang nanwang nan18100.00%1100.00%
Total18100.00%1100.00%


static char *get_config_name(struct list_head *head_terms) { struct parse_events_term *term; if (!head_terms) return NULL; list_for_each_entry(term, head_terms, list) if (parse_events__is_name_term(term)) return term->val.str; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
wang nanwang nan50100.00%1100.00%
Total50100.00%1100.00%


static struct perf_evsel * __add_event(struct list_head *list, int *idx, struct perf_event_attr *attr, char *name, struct cpu_map *cpus, struct list_head *config_terms) { struct perf_evsel *evsel; event_attr_init(attr); evsel = perf_evsel__new_idx(attr, (*idx)++); if (!evsel) return NULL; evsel->cpus = cpu_map__get(cpus); evsel->own_cpus = cpu_map__get(cpus); if (name) evsel->name = strdup(name); if (config_terms) list_splice(config_terms, &evsel->config_terms); list_add_tail(&evsel->node, list); return evsel; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa9374.40%440.00%
zheng yanzheng yan129.60%110.00%
adrian hunteradrian hunter97.20%110.00%
arnaldo carvalho de meloarnaldo carvalho de melo54.00%220.00%
stephane eranianstephane eranian54.00%110.00%
david aherndavid ahern10.80%110.00%
Total125100.00%10100.00%


static int add_event(struct list_head *list, int *idx, struct perf_event_attr *attr, char *name, struct list_head *config_terms) { return __add_event(list, idx, attr, name, NULL, config_terms) ? 0 : -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
zheng yanzheng yan3672.00%125.00%
jiri olsajiri olsa714.00%125.00%
stephane eranianstephane eranian510.00%125.00%
david aherndavid ahern24.00%125.00%
Total50100.00%4100.00%


static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) { int i, j; int n, longest = -1; for (i = 0; i < size; i++) { for (j = 0; j < PERF_EVSEL__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; }

Contributors

PersonTokensPropCommitsCommitProp
ingo molnaringo molnar8265.60%360.00%
paul mackerraspaul mackerras4132.80%120.00%
arnaldo carvalho de meloarnaldo carvalho de melo21.60%120.00%
Total125100.00%5100.00%

typedef int config_term_func_t(struct perf_event_attr *attr, struct parse_events_term *term, struct parse_events_error *err); static int config_term_common(struct perf_event_attr *attr, struct parse_events_term *term, struct parse_events_error *err); static int config_attr(struct perf_event_attr *attr, struct list_head *head, struct parse_events_error *err, config_term_func_t config_term);
int parse_events_add_cache(struct list_head *list, int *idx, char *type, char *op_result1, char *op_result2, struct parse_events_error *err, struct list_head *head_config) { struct perf_event_attr attr; LIST_HEAD(config_terms); char name[MAX_NAME_LEN], *config_name; 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, perf_evsel__hw_cache, PERF_COUNT_HW_CACHE_MAX); if (cache_type == -1) return -EINVAL; config_name = get_config_name(head_config); n = snprintf(name, MAX_NAME_LEN, "%s", type); for (i = 0; (i < 2) && (op_result[i]); i++) { char *str = op_result[i]; n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); if (cache_op == -1) { cache_op = parse_aliases(str, perf_evsel__hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); if (cache_op >= 0) { if (!perf_evsel__is_cache_op_valid(cache_type, cache_op)) return -EINVAL; continue; } } if (cache_result == -1) { cache_result = parse_aliases(str, perf_evsel__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; if (head_config) { if (config_attr(&attr, head_config, err, config_term_common)) return -EINVAL; if (get_config_terms(head_config, &config_terms)) return -ENOMEM; } return add_event(list, idx, &attr, config_name ? : name, &config_terms); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa13636.86%327.27%
ingo molnaringo molnar9425.47%218.18%
wang nanwang nan6617.89%19.09%
paul mackerraspaul mackerras5514.91%19.09%
jaswinder singh rajputjaswinder singh rajput112.98%19.09%
arnaldo carvalho de meloarnaldo carvalho de melo71.90%327.27%
Total369100.00%11100.00%


static void tracepoint_error(struct parse_events_error *e, int err, const char *sys, const char *name) { char help[BUFSIZ]; if (!e) return; /* * We get error directly from syscall errno ( > 0), * or from encoded pointer's error ( < 0). */ err = abs(err); switch (err) { case EACCES: e->str = strdup("can't access trace events"); break; case ENOENT: e->str = strdup("unknown tracepoint"); break; default: e->str = strdup("failed to add tracepoint"); break; } tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name); e->help = strdup(help); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa10492.86%250.00%
adrian hunteradrian hunter65.36%125.00%
wang nanwang nan21.79%125.00%
Total112100.00%4100.00%


static int add_tracepoint(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { struct perf_evsel *evsel; evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); if (IS_ERR(evsel)) { tracepoint_error(err, PTR_ERR(evsel), sys_name, evt_name); return PTR_ERR(evsel); } if (head_config) { LIST_HEAD(config_terms); if (get_config_terms(head_config, &config_terms)) return -ENOMEM; list_splice(&config_terms, &evsel->config_terms); } list_add_tail(&evsel->node, list); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa4634.59%541.67%
he kuanghe kuang4130.83%18.33%
arnaldo carvalho de meloarnaldo carvalho de melo2418.05%216.67%
jason baronjason baron1410.53%18.33%
frederic weisbeckerfrederic weisbecker53.76%18.33%
wang nanwang nan21.50%18.33%
david aherndavid ahern10.75%18.33%
Total133100.00%12100.00%


static int add_tracepoint_multi_event(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { char evt_path[MAXPATHLEN]; struct dirent *evt_ent; DIR *evt_dir; int ret = 0, found = 0; snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); evt_dir = opendir(evt_path); if (!evt_dir) { tracepoint_error(err, errno, sys_name, evt_name); return -1; } while (!ret && (evt_ent = readdir(evt_dir))) { if (!strcmp(evt_ent->d_name, ".") || !strcmp(evt_ent->d_name, "..") || !strcmp(evt_ent->d_name, "enable") || !strcmp(evt_ent->d_name, "filter")) continue; if (!strglobmatch(evt_ent->d_name, evt_name)) continue; found++; ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, err, head_config); } if (!found) { tracepoint_error(err, ENOENT, sys_name, evt_name); ret = -1; } closedir(evt_dir); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker9943.81%16.67%
jiri olsajiri olsa7432.74%746.67%
jaswinder singh rajputjaswinder singh rajput198.41%16.67%
masami hiramatsumasami hiramatsu156.64%16.67%
he kuanghe kuang73.10%16.67%
paul mackerraspaul mackerras62.65%16.67%
arnaldo carvalho de meloarnaldo carvalho de melo41.77%213.33%
wang nanwang nan20.88%16.67%
Total226100.00%15100.00%


static int add_tracepoint_event(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { return strpbrk(evt_name, "*?") ? add_tracepoint_multi_event(list, idx, sys_name, evt_name, err, head_config) : add_tracepoint(list, idx, sys_name, evt_name, err, head_config); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa6284.93%360.00%
he kuanghe kuang912.33%120.00%
wang nanwang nan22.74%120.00%
Total73100.00%5100.00%


static int add_tracepoint_multi_sys(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { struct dirent *events_ent; DIR *events_dir; int ret = 0; events_dir = opendir(tracing_events_path); if (!events_dir) { tracepoint_error(err, errno, sys_name, evt_name); return -1; } while (!ret && (events_ent = readdir(events_dir))) { if (!strcmp(events_ent->d_name, ".") || !strcmp(events_ent->d_name, "..") || !strcmp(events_ent->d_name, "enable") || !strcmp(events_ent->d_name, "header_event") || !strcmp(events_ent->d_name, "header_page")) continue; if (!strglobmatch(events_ent->d_name, sys_name)) continue; ret = add_tracepoint_event(list, idx, events_ent->d_name, evt_name, err, head_config); } closedir(events_dir); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa17895.19%466.67%
he kuanghe kuang73.74%116.67%
wang nanwang nan21.07%116.67%
Total187100.00%6100.00%

struct __add_bpf_event_param { struct parse_events_evlist *data; struct list_head *list; struct list_head *head_config; };
static int add_bpf_event(const char *group, const char *event, int fd, void *_param) { LIST_HEAD(new_evsels); struct __add_bpf_event_param *param = _param; struct parse_events_evlist *evlist = param->data; struct list_head *list = param->list; struct perf_evsel *pos; int err; pr_debug("add bpf event %s:%s and attach bpf program %d\n", group, event, fd); err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, group, event, evlist->error, param->head_config); if (err) { struct perf_evsel *evsel, *tmp; pr_debug("Failed to add BPF event %s:%s\n", group, event); list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { list_del(&evsel->node); perf_evsel__delete(evsel); } return err; } pr_debug("adding %s:%s\n", group, event); list_for_each_entry(pos, &new_evsels, node) { pr_debug("adding %s:%s to %p\n", group, event, pos); pos->bpf_fd = fd; } list_splice(&new_evsels, list); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
wang nanwang nan195100.00%4100.00%
Total195100.00%4100.00%


int parse_events_load_bpf_obj