|
@@ -30,6 +30,15 @@ extern int parse_events_debug;
|
|
|
#endif
|
|
|
int parse_events_parse(void *data, void *scanner);
|
|
|
|
|
|
+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;
|
|
|
+
|
|
|
static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
|
|
|
[PERF_COUNT_HW_CPU_CYCLES] = {
|
|
|
.symbol = "cpu-cycles",
|
|
@@ -863,6 +872,113 @@ int parse_events_name(struct list_head *list, char *name)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+comp_pmu(const void *p1, const void *p2)
|
|
|
+{
|
|
|
+ struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1;
|
|
|
+ struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2;
|
|
|
+
|
|
|
+ return strcmp(pmu1->symbol, pmu2->symbol);
|
|
|
+}
|
|
|
+
|
|
|
+static void perf_pmu__parse_cleanup(void)
|
|
|
+{
|
|
|
+ if (perf_pmu_events_list_num > 0) {
|
|
|
+ struct perf_pmu_event_symbol *p;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < perf_pmu_events_list_num; i++) {
|
|
|
+ p = perf_pmu_events_list + i;
|
|
|
+ free(p->symbol);
|
|
|
+ }
|
|
|
+ free(perf_pmu_events_list);
|
|
|
+ perf_pmu_events_list = NULL;
|
|
|
+ perf_pmu_events_list_num = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#define SET_SYMBOL(str, stype) \
|
|
|
+do { \
|
|
|
+ p->symbol = str; \
|
|
|
+ if (!p->symbol) \
|
|
|
+ goto err; \
|
|
|
+ p->type = stype; \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+/*
|
|
|
+ * Read the pmu events list from sysfs
|
|
|
+ * Save it into perf_pmu_events_list
|
|
|
+ */
|
|
|
+static void perf_pmu__parse_init(void)
|
|
|
+{
|
|
|
+
|
|
|
+ struct perf_pmu *pmu = NULL;
|
|
|
+ struct perf_pmu_alias *alias;
|
|
|
+ int len = 0;
|
|
|
+
|
|
|
+ pmu = perf_pmu__find("cpu");
|
|
|
+ if ((pmu == NULL) || list_empty(&pmu->aliases)) {
|
|
|
+ perf_pmu_events_list_num = -1;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ list_for_each_entry(alias, &pmu->aliases, list) {
|
|
|
+ if (strchr(alias->name, '-'))
|
|
|
+ len++;
|
|
|
+ len++;
|
|
|
+ }
|
|
|
+ perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len);
|
|
|
+ if (!perf_pmu_events_list)
|
|
|
+ return;
|
|
|
+ perf_pmu_events_list_num = len;
|
|
|
+
|
|
|
+ len = 0;
|
|
|
+ list_for_each_entry(alias, &pmu->aliases, list) {
|
|
|
+ struct perf_pmu_event_symbol *p = perf_pmu_events_list + len;
|
|
|
+ char *tmp = strchr(alias->name, '-');
|
|
|
+
|
|
|
+ if (tmp != NULL) {
|
|
|
+ SET_SYMBOL(strndup(alias->name, tmp - alias->name),
|
|
|
+ PMU_EVENT_SYMBOL_PREFIX);
|
|
|
+ p++;
|
|
|
+ SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX);
|
|
|
+ len += 2;
|
|
|
+ } else {
|
|
|
+ SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL);
|
|
|
+ len++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ qsort(perf_pmu_events_list, len,
|
|
|
+ sizeof(struct perf_pmu_event_symbol), comp_pmu);
|
|
|
+
|
|
|
+ return;
|
|
|
+err:
|
|
|
+ perf_pmu__parse_cleanup();
|
|
|
+}
|
|
|
+
|
|
|
+enum perf_pmu_event_symbol_type
|
|
|
+perf_pmu__parse_check(const char *name)
|
|
|
+{
|
|
|
+ struct perf_pmu_event_symbol p, *r;
|
|
|
+
|
|
|
+ /* scan kernel pmu events from sysfs if needed */
|
|
|
+ if (perf_pmu_events_list_num == 0)
|
|
|
+ perf_pmu__parse_init();
|
|
|
+ /*
|
|
|
+ * name "cpu" could be prefix of cpu-cycles or cpu// events.
|
|
|
+ * cpu-cycles has been handled by hardcode.
|
|
|
+ * So it must be cpu// events, not kernel pmu event.
|
|
|
+ */
|
|
|
+ if ((perf_pmu_events_list_num <= 0) || !strcmp(name, "cpu"))
|
|
|
+ return PMU_EVENT_SYMBOL_ERR;
|
|
|
+
|
|
|
+ p.symbol = strdup(name);
|
|
|
+ r = bsearch(&p, perf_pmu_events_list,
|
|
|
+ (size_t) perf_pmu_events_list_num,
|
|
|
+ sizeof(struct perf_pmu_event_symbol), comp_pmu);
|
|
|
+ free(p.symbol);
|
|
|
+ return r ? r->type : PMU_EVENT_SYMBOL_ERR;
|
|
|
+}
|
|
|
+
|
|
|
static int parse_events__scanner(const char *str, void *data, int start_token)
|
|
|
{
|
|
|
YY_BUFFER_STATE buffer;
|
|
@@ -917,6 +1033,7 @@ int parse_events(struct perf_evlist *evlist, const char *str)
|
|
|
int ret;
|
|
|
|
|
|
ret = parse_events__scanner(str, &data, PE_START_EVENTS);
|
|
|
+ perf_pmu__parse_cleanup();
|
|
|
if (!ret) {
|
|
|
int entries = data.idx - evlist->nr_entries;
|
|
|
perf_evlist__splice_list_tail(evlist, &data.list, entries);
|