aboutsummaryrefslogtreecommitdiffstats
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.c133
1 files changed, 111 insertions, 22 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d76aa30cb1fb..c659a3ca1283 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -6,7 +6,7 @@
6#include "parse-options.h" 6#include "parse-options.h"
7#include "parse-events.h" 7#include "parse-events.h"
8#include "exec_cmd.h" 8#include "exec_cmd.h"
9#include "linux/string.h" 9#include "string.h"
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
@@ -30,6 +30,15 @@ extern int parse_events_debug;
30#endif 30#endif
31int parse_events_parse(void *data, void *scanner); 31int parse_events_parse(void *data, void *scanner);
32 32
33static struct perf_pmu_event_symbol *perf_pmu_events_list;
34/*
35 * The variable indicates the number of supported pmu event symbols.
36 * 0 means not initialized and ready to init
37 * -1 means failed to init, don't try anymore
38 * >0 is the number of supported pmu event symbols
39 */
40static int perf_pmu_events_list_num;
41
33static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { 42static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
34 [PERF_COUNT_HW_CPU_CYCLES] = { 43 [PERF_COUNT_HW_CPU_CYCLES] = {
35 .symbol = "cpu-cycles", 44 .symbol = "cpu-cycles",
@@ -863,30 +872,111 @@ int parse_events_name(struct list_head *list, char *name)
863 return 0; 872 return 0;
864} 873}
865 874
866static int parse_events__scanner(const char *str, void *data, int start_token); 875static int
876comp_pmu(const void *p1, const void *p2)
877{
878 struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1;
879 struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2;
867 880
868static int parse_events_fixup(int ret, const char *str, void *data, 881 return strcmp(pmu1->symbol, pmu2->symbol);
869 int start_token) 882}
883
884static void perf_pmu__parse_cleanup(void)
870{ 885{
871 char *o = strdup(str); 886 if (perf_pmu_events_list_num > 0) {
872 char *s = NULL; 887 struct perf_pmu_event_symbol *p;
873 char *t = o; 888 int i;
874 char *p; 889
890 for (i = 0; i < perf_pmu_events_list_num; i++) {
891 p = perf_pmu_events_list + i;
892 free(p->symbol);
893 }
894 free(perf_pmu_events_list);
895 perf_pmu_events_list = NULL;
896 perf_pmu_events_list_num = 0;
897 }
898}
899
900#define SET_SYMBOL(str, stype) \
901do { \
902 p->symbol = str; \
903 if (!p->symbol) \
904 goto err; \
905 p->type = stype; \
906} while (0)
907
908/*
909 * Read the pmu events list from sysfs
910 * Save it into perf_pmu_events_list
911 */
912static void perf_pmu__parse_init(void)
913{
914
915 struct perf_pmu *pmu = NULL;
916 struct perf_pmu_alias *alias;
875 int len = 0; 917 int len = 0;
876 918
877 if (!o) 919 pmu = perf_pmu__find("cpu");
878 return ret; 920 if ((pmu == NULL) || list_empty(&pmu->aliases)) {
879 while ((p = strsep(&t, ",")) != NULL) { 921 perf_pmu_events_list_num = -1;
880 if (s) 922 return;
881 str_append(&s, &len, ",");
882 str_append(&s, &len, "cpu/");
883 str_append(&s, &len, p);
884 str_append(&s, &len, "/");
885 } 923 }
886 free(o); 924 list_for_each_entry(alias, &pmu->aliases, list) {
887 if (!s) 925 if (strchr(alias->name, '-'))
888 return -ENOMEM; 926 len++;
889 return parse_events__scanner(s, data, start_token); 927 len++;
928 }
929 perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len);
930 if (!perf_pmu_events_list)
931 return;
932 perf_pmu_events_list_num = len;
933
934 len = 0;
935 list_for_each_entry(alias, &pmu->aliases, list) {
936 struct perf_pmu_event_symbol *p = perf_pmu_events_list + len;
937 char *tmp = strchr(alias->name, '-');
938
939 if (tmp != NULL) {
940 SET_SYMBOL(strndup(alias->name, tmp - alias->name),
941 PMU_EVENT_SYMBOL_PREFIX);
942 p++;
943 SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX);
944 len += 2;
945 } else {
946 SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL);
947 len++;
948 }
949 }
950 qsort(perf_pmu_events_list, len,
951 sizeof(struct perf_pmu_event_symbol), comp_pmu);
952
953 return;
954err:
955 perf_pmu__parse_cleanup();
956}
957
958enum perf_pmu_event_symbol_type
959perf_pmu__parse_check(const char *name)
960{
961 struct perf_pmu_event_symbol p, *r;
962
963 /* scan kernel pmu events from sysfs if needed */
964 if (perf_pmu_events_list_num == 0)
965 perf_pmu__parse_init();
966 /*
967 * name "cpu" could be prefix of cpu-cycles or cpu// events.
968 * cpu-cycles has been handled by hardcode.
969 * So it must be cpu// events, not kernel pmu event.
970 */
971 if ((perf_pmu_events_list_num <= 0) || !strcmp(name, "cpu"))
972 return PMU_EVENT_SYMBOL_ERR;
973
974 p.symbol = strdup(name);
975 r = bsearch(&p, perf_pmu_events_list,
976 (size_t) perf_pmu_events_list_num,
977 sizeof(struct perf_pmu_event_symbol), comp_pmu);
978 free(p.symbol);
979 return r ? r->type : PMU_EVENT_SYMBOL_ERR;
890} 980}
891 981
892static int parse_events__scanner(const char *str, void *data, int start_token) 982static int parse_events__scanner(const char *str, void *data, int start_token)
@@ -909,8 +999,6 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
909 parse_events__flush_buffer(buffer, scanner); 999 parse_events__flush_buffer(buffer, scanner);
910 parse_events__delete_buffer(buffer, scanner); 1000 parse_events__delete_buffer(buffer, scanner);
911 parse_events_lex_destroy(scanner); 1001 parse_events_lex_destroy(scanner);
912 if (ret && !strchr(str, '/'))
913 ret = parse_events_fixup(ret, str, data, start_token);
914 return ret; 1002 return ret;
915} 1003}
916 1004
@@ -945,6 +1033,7 @@ int parse_events(struct perf_evlist *evlist, const char *str)
945 int ret; 1033 int ret;
946 1034
947 ret = parse_events__scanner(str, &data, PE_START_EVENTS); 1035 ret = parse_events__scanner(str, &data, PE_START_EVENTS);
1036 perf_pmu__parse_cleanup();
948 if (!ret) { 1037 if (!ret) {
949 int entries = data.idx - evlist->nr_entries; 1038 int entries = data.idx - evlist->nr_entries;
950 perf_evlist__splice_list_tail(evlist, &data.list, entries); 1039 perf_evlist__splice_list_tail(evlist, &data.list, entries);