perf evsel: Add evsel__clone() function
authorNamhyung Kim <namhyung@kernel.org>
Thu, 24 Sep 2020 12:44:51 +0000 (21:44 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 28 Sep 2020 11:55:48 +0000 (08:55 -0300)
The evsel__clone() is to create an exactly same evsel from same
attributes.  The function assumes the given evsel is not configured
yet so it cares fields set during event parsing.  Those fields are now
moved together as Jiri suggested.  Note that metric events will be
handled by later patch.

It will be used by perf stat to generate separate events for each
cgroup.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20200924124455.336326-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/evsel.c
tools/perf/util/evsel.h

index 2ac19a2..1cad605 100644 (file)
@@ -331,6 +331,110 @@ error_free:
        goto out;
 }
 
+static int evsel__copy_config_terms(struct evsel *dst, struct evsel *src)
+{
+       struct evsel_config_term *pos, *tmp;
+
+       list_for_each_entry(pos, &src->config_terms, list) {
+               tmp = malloc(sizeof(*tmp));
+               if (tmp == NULL)
+                       return -ENOMEM;
+
+               *tmp = *pos;
+               if (tmp->free_str) {
+                       tmp->val.str = strdup(pos->val.str);
+                       if (tmp->val.str == NULL) {
+                               free(tmp);
+                               return -ENOMEM;
+                       }
+               }
+               list_add_tail(&tmp->list, &dst->config_terms);
+       }
+       return 0;
+}
+
+/**
+ * evsel__clone - create a new evsel copied from @orig
+ * @orig: original evsel
+ *
+ * The assumption is that @orig is not configured nor opened yet.
+ * So we only care about the attributes that can be set while it's parsed.
+ */
+struct evsel *evsel__clone(struct evsel *orig)
+{
+       struct evsel *evsel;
+
+       BUG_ON(orig->core.fd);
+       BUG_ON(orig->counts);
+       BUG_ON(orig->priv);
+       BUG_ON(orig->per_pkg_mask);
+
+       /* cannot handle BPF objects for now */
+       if (orig->bpf_obj)
+               return NULL;
+
+       evsel = evsel__new(&orig->core.attr);
+       if (evsel == NULL)
+               return NULL;
+
+       evsel->core.cpus = perf_cpu_map__get(orig->core.cpus);
+       evsel->core.own_cpus = perf_cpu_map__get(orig->core.own_cpus);
+       evsel->core.threads = perf_thread_map__get(orig->core.threads);
+       evsel->core.nr_members = orig->core.nr_members;
+       evsel->core.system_wide = orig->core.system_wide;
+
+       if (orig->name) {
+               evsel->name = strdup(orig->name);
+               if (evsel->name == NULL)
+                       goto out_err;
+       }
+       if (orig->group_name) {
+               evsel->group_name = strdup(orig->group_name);
+               if (evsel->group_name == NULL)
+                       goto out_err;
+       }
+       if (orig->pmu_name) {
+               evsel->pmu_name = strdup(orig->pmu_name);
+               if (evsel->pmu_name == NULL)
+                       goto out_err;
+       }
+       if (orig->filter) {
+               evsel->filter = strdup(orig->filter);
+               if (evsel->filter == NULL)
+                       goto out_err;
+       }
+       evsel->cgrp = cgroup__get(orig->cgrp);
+       evsel->tp_format = orig->tp_format;
+       evsel->handler = orig->handler;
+       evsel->leader = orig->leader;
+
+       evsel->max_events = orig->max_events;
+       evsel->tool_event = orig->tool_event;
+       evsel->unit = orig->unit;
+       evsel->scale = orig->scale;
+       evsel->snapshot = orig->snapshot;
+       evsel->per_pkg = orig->per_pkg;
+       evsel->percore = orig->percore;
+       evsel->precise_max = orig->precise_max;
+       evsel->use_uncore_alias = orig->use_uncore_alias;
+       evsel->is_libpfm_event = orig->is_libpfm_event;
+
+       evsel->exclude_GH = orig->exclude_GH;
+       evsel->sample_read = orig->sample_read;
+       evsel->auto_merge_stats = orig->auto_merge_stats;
+       evsel->collect_stat = orig->collect_stat;
+       evsel->weak_group = orig->weak_group;
+
+       if (evsel__copy_config_terms(evsel, orig) < 0)
+               goto out_err;
+
+       return evsel;
+
+out_err:
+       evsel__delete(evsel);
+       return NULL;
+}
+
 /*
  * Returns pointer with encoded error via <linux/err.h> interface.
  */
index 35e3f6d..79a860d 100644 (file)
@@ -42,65 +42,79 @@ enum perf_tool_event {
  */
 struct evsel {
        struct perf_evsel       core;
-       struct evlist   *evlist;
-       char                    *filter;
+       struct evlist           *evlist;
+       off_t                   id_offset;
+       int                     idx;
+       int                     id_pos;
+       int                     is_pos;
+       unsigned int            sample_size;
+
+       /*
+        * These fields can be set in the parse-events code or similar.
+        * Please check evsel__clone() to copy them properly so that
+        * they can be released properly.
+        */
+       struct {
+               char                    *name;
+               char                    *group_name;
+               const char              *pmu_name;
+               struct tep_event        *tp_format;
+               char                    *filter;
+               unsigned long           max_events;
+               double                  scale;
+               const char              *unit;
+               struct cgroup           *cgrp;
+               enum perf_tool_event    tool_event;
+               /* parse modifier helper */
+               int                     exclude_GH;
+               int                     sample_read;
+               bool                    snapshot;
+               bool                    per_pkg;
+               bool                    percore;
+               bool                    precise_max;
+               bool                    use_uncore_alias;
+               bool                    is_libpfm_event;
+               bool                    auto_merge_stats;
+               bool                    collect_stat;
+               bool                    weak_group;
+               int                     bpf_fd;
+               struct bpf_object       *bpf_obj;
+       };
+
+       /*
+        * metric fields are similar, but needs more care as they can have
+        * references to other metric (evsel).
+        */
+       const char *            metric_expr;
+       const char *            metric_name;
+       struct evsel            **metric_events;
+       struct evsel            *metric_leader;
+
+       void                    *handler;
        struct perf_counts      *counts;
        struct perf_counts      *prev_raw_counts;
-       int                     idx;
-       unsigned long           max_events;
        unsigned long           nr_events_printed;
-       char                    *name;
-       double                  scale;
-       const char              *unit;
-       struct tep_event        *tp_format;
-       off_t                   id_offset;
        struct perf_stat_evsel  *stats;
        void                    *priv;
        u64                     db_id;
-       struct cgroup           *cgrp;
-       void                    *handler;
-       unsigned int            sample_size;
-       int                     id_pos;
-       int                     is_pos;
-       enum perf_tool_event    tool_event;
        bool                    uniquified_name;
-       bool                    snapshot;
        bool                    supported;
        bool                    needs_swap;
        bool                    disabled;
        bool                    no_aux_samples;
        bool                    immediate;
        bool                    tracking;
-       bool                    per_pkg;
-       bool                    precise_max;
        bool                    ignore_missing_thread;
        bool                    forced_leader;
-       bool                    use_uncore_alias;
-       bool                    is_libpfm_event;
-       /* parse modifier helper */
-       int                     exclude_GH;
-       int                     sample_read;
-       unsigned long           *per_pkg_mask;
-       struct evsel            *leader;
-       char                    *group_name;
        bool                    cmdline_group_boundary;
-       struct list_head        config_terms;
-       struct bpf_object       *bpf_obj;
-       int                     bpf_fd;
-       int                     err;
-       bool                    auto_merge_stats;
        bool                    merged_stat;
-       const char *            metric_expr;
-       const char *            metric_name;
-       struct evsel            **metric_events;
-       struct evsel            *metric_leader;
-       bool                    collect_stat;
-       bool                    weak_group;
        bool                    reset_group;
        bool                    errored;
-       bool                    percore;
+       unsigned long           *per_pkg_mask;
+       struct evsel            *leader;
+       struct list_head        config_terms;
+       int                     err;
        int                     cpu_iter;
-       const char              *pmu_name;
        struct {
                evsel__sb_cb_t  *cb;
                void            *data;
@@ -169,6 +183,7 @@ static inline struct evsel *evsel__new(struct perf_event_attr *attr)
        return evsel__new_idx(attr, 0);
 }
 
+struct evsel *evsel__clone(struct evsel *orig);
 struct evsel *evsel__newtp_idx(const char *sys, const char *name, int idx);
 
 /*