perf evsel: Add support for address filters
[cascardo/linux.git] / tools / perf / util / parse-events.c
index 6c913c3..33546c3 100644 (file)
@@ -904,6 +904,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
        [PARSE_EVENTS__TERM_TYPE_MAX_STACK]             = "max-stack",
        [PARSE_EVENTS__TERM_TYPE_OVERWRITE]             = "overwrite",
        [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE]           = "no-overwrite",
+       [PARSE_EVENTS__TERM_TYPE_DRV_CFG]               = "driver-config",
 };
 
 static bool config_term_shrinked;
@@ -1034,7 +1035,8 @@ static int config_term_pmu(struct perf_event_attr *attr,
                           struct parse_events_term *term,
                           struct parse_events_error *err)
 {
-       if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER)
+       if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER ||
+           term->type_term == PARSE_EVENTS__TERM_TYPE_DRV_CFG)
                /*
                 * Always succeed for sysfs terms, as we dont know
                 * at this point what type they need to have.
@@ -1134,6 +1136,9 @@ do {                                                              \
                case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
                        ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 0 : 1);
                        break;
+               case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
+                       ADD_CONFIG_TERM(DRV_CFG, drv_cfg, term->val.str);
+                       break;
                default:
                        break;
                }
@@ -1755,20 +1760,49 @@ foreach_evsel_in_last_glob(struct perf_evlist *evlist,
 static int set_filter(struct perf_evsel *evsel, const void *arg)
 {
        const char *str = arg;
+       bool found = false;
+       int nr_addr_filters = 0;
+       struct perf_pmu *pmu = NULL;
 
-       if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) {
-               fprintf(stderr,
-                       "--filter option should follow a -e tracepoint option\n");
-               return -1;
+       if (evsel == NULL)
+               goto err;
+
+       if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
+               if (perf_evsel__append_tp_filter(evsel, str) < 0) {
+                       fprintf(stderr,
+                               "not enough memory to hold filter string\n");
+                       return -1;
+               }
+
+               return 0;
        }
 
-       if (perf_evsel__append_filter(evsel, "&&", str) < 0) {
+       while ((pmu = perf_pmu__scan(pmu)) != NULL)
+               if (pmu->type == evsel->attr.type) {
+                       found = true;
+                       break;
+               }
+
+       if (found)
+               perf_pmu__scan_file(pmu, "nr_addr_filters",
+                                   "%d", &nr_addr_filters);
+
+       if (!nr_addr_filters)
+               goto err;
+
+       if (perf_evsel__append_addr_filter(evsel, str) < 0) {
                fprintf(stderr,
                        "not enough memory to hold filter string\n");
                return -1;
        }
 
        return 0;
+
+err:
+       fprintf(stderr,
+               "--filter option should follow a -e tracepoint or HW tracer option\n");
+
+       return -1;
 }
 
 int parse_filter(const struct option *opt, const char *str,
@@ -1793,7 +1827,7 @@ static int add_exclude_perf_filter(struct perf_evsel *evsel,
 
        snprintf(new_filter, sizeof(new_filter), "common_pid != %d", getpid());
 
-       if (perf_evsel__append_filter(evsel, "&&", new_filter) < 0) {
+       if (perf_evsel__append_tp_filter(evsel, new_filter) < 0) {
                fprintf(stderr,
                        "not enough memory to hold filter string\n");
                return -1;