Merge branch 'misc.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / tools / perf / util / header.c
index aa1e425..1c7414f 100644 (file)
@@ -49,6 +49,7 @@
 #include "cputopo.h"
 #include "bpf-event.h"
 #include "clockid.h"
+#include "pmu-hybrid.h"
 
 #include <linux/ctype.h>
 #include <internal/lib.h>
@@ -277,7 +278,7 @@ static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize)
        if (ret)
                return ret;
 
-       set = bitmap_alloc(size);
+       set = bitmap_zalloc(size);
        if (!set)
                return -ENOMEM;
 
@@ -777,7 +778,7 @@ static int write_pmu_mappings(struct feat_fd *ff,
 static int write_group_desc(struct feat_fd *ff,
                            struct evlist *evlist)
 {
-       u32 nr_groups = evlist->nr_groups;
+       u32 nr_groups = evlist->core.nr_groups;
        struct evsel *evsel;
        int ret;
 
@@ -788,7 +789,7 @@ static int write_group_desc(struct feat_fd *ff,
        evlist__for_each_entry(evlist, evsel) {
                if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) {
                        const char *name = evsel->group_name ?: "{anon_group}";
-                       u32 leader_idx = evsel->idx;
+                       u32 leader_idx = evsel->core.idx;
                        u32 nr_members = evsel->core.nr_members;
 
                        ret = do_write_string(ff, name);
@@ -932,6 +933,40 @@ static int write_clock_data(struct feat_fd *ff,
        return do_write(ff, data64, sizeof(*data64));
 }
 
+static int write_hybrid_topology(struct feat_fd *ff,
+                                struct evlist *evlist __maybe_unused)
+{
+       struct hybrid_topology *tp;
+       int ret;
+       u32 i;
+
+       tp = hybrid_topology__new();
+       if (!tp)
+               return -ENOENT;
+
+       ret = do_write(ff, &tp->nr, sizeof(u32));
+       if (ret < 0)
+               goto err;
+
+       for (i = 0; i < tp->nr; i++) {
+               struct hybrid_topology_node *n = &tp->nodes[i];
+
+               ret = do_write_string(ff, n->pmu_name);
+               if (ret < 0)
+                       goto err;
+
+               ret = do_write_string(ff, n->cpus);
+               if (ret < 0)
+                       goto err;
+       }
+
+       ret = 0;
+
+err:
+       hybrid_topology__delete(tp);
+       return ret;
+}
+
 static int write_dir_format(struct feat_fd *ff,
                            struct evlist *evlist __maybe_unused)
 {
@@ -1249,7 +1284,7 @@ static int memory_node__read(struct memory_node *n, unsigned long idx)
 
        dir = opendir(path);
        if (!dir) {
-               pr_warning("failed: cant' open memory sysfs data\n");
+               pr_warning("failed: can't open memory sysfs data\n");
                return -1;
        }
 
@@ -1259,7 +1294,7 @@ static int memory_node__read(struct memory_node *n, unsigned long idx)
 
        size++;
 
-       n->set = bitmap_alloc(size);
+       n->set = bitmap_zalloc(size);
        if (!n->set) {
                closedir(dir);
                return -ENOMEM;
@@ -1425,18 +1460,14 @@ static int write_compressed(struct feat_fd *ff __maybe_unused,
        return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len));
 }
 
-static int write_cpu_pmu_caps(struct feat_fd *ff,
-                             struct evlist *evlist __maybe_unused)
+static int write_per_cpu_pmu_caps(struct feat_fd *ff, struct perf_pmu *pmu,
+                                 bool write_pmu)
 {
-       struct perf_pmu *cpu_pmu = perf_pmu__find("cpu");
        struct perf_pmu_caps *caps = NULL;
        int nr_caps;
        int ret;
 
-       if (!cpu_pmu)
-               return -ENOENT;
-
-       nr_caps = perf_pmu__caps_parse(cpu_pmu);
+       nr_caps = perf_pmu__caps_parse(pmu);
        if (nr_caps < 0)
                return nr_caps;
 
@@ -1444,7 +1475,7 @@ static int write_cpu_pmu_caps(struct feat_fd *ff,
        if (ret < 0)
                return ret;
 
-       list_for_each_entry(caps, &cpu_pmu->caps, list) {
+       list_for_each_entry(caps, &pmu->caps, list) {
                ret = do_write_string(ff, caps->name);
                if (ret < 0)
                        return ret;
@@ -1454,9 +1485,49 @@ static int write_cpu_pmu_caps(struct feat_fd *ff,
                        return ret;
        }
 
+       if (write_pmu) {
+               ret = do_write_string(ff, pmu->name);
+               if (ret < 0)
+                       return ret;
+       }
+
        return ret;
 }
 
+static int write_cpu_pmu_caps(struct feat_fd *ff,
+                             struct evlist *evlist __maybe_unused)
+{
+       struct perf_pmu *cpu_pmu = perf_pmu__find("cpu");
+
+       if (!cpu_pmu)
+               return -ENOENT;
+
+       return write_per_cpu_pmu_caps(ff, cpu_pmu, false);
+}
+
+static int write_hybrid_cpu_pmu_caps(struct feat_fd *ff,
+                                    struct evlist *evlist __maybe_unused)
+{
+       struct perf_pmu *pmu;
+       u32 nr_pmu = perf_pmu__hybrid_pmu_num();
+       int ret;
+
+       if (nr_pmu == 0)
+               return -ENOENT;
+
+       ret = do_write(ff, &nr_pmu, sizeof(nr_pmu));
+       if (ret < 0)
+               return ret;
+
+       perf_pmu__for_each_hybrid_pmu(pmu) {
+               ret = write_per_cpu_pmu_caps(ff, pmu, true);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static void print_hostname(struct feat_fd *ff, FILE *fp)
 {
        fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
@@ -1623,6 +1694,18 @@ static void print_clock_data(struct feat_fd *ff, FILE *fp)
                    clockid_name(clockid));
 }
 
+static void print_hybrid_topology(struct feat_fd *ff, FILE *fp)
+{
+       int i;
+       struct hybrid_node *n;
+
+       fprintf(fp, "# hybrid cpu system:\n");
+       for (i = 0; i < ff->ph->env.nr_hybrid_nodes; i++) {
+               n = &ff->ph->env.hybrid_nodes[i];
+               fprintf(fp, "# %s cpu list : %s\n", n->pmu_name, n->cpus);
+       }
+}
+
 static void print_dir_format(struct feat_fd *ff, FILE *fp)
 {
        struct perf_session *session;
@@ -1761,7 +1844,7 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
                msz = sz;
 
        for (i = 0, evsel = events; i < nre; evsel++, i++) {
-               evsel->idx = i;
+               evsel->core.idx = i;
 
                /*
                 * must read entire on-file attr struct to
@@ -1916,18 +1999,28 @@ static void print_compressed(struct feat_fd *ff, FILE *fp)
                ff->ph->env.comp_level, ff->ph->env.comp_ratio);
 }
 
-static void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
+static void print_per_cpu_pmu_caps(FILE *fp, int nr_caps, char *cpu_pmu_caps,
+                                  char *pmu_name)
 {
-       const char *delimiter = "# cpu pmu capabilities: ";
-       u32 nr_caps = ff->ph->env.nr_cpu_pmu_caps;
-       char *str;
+       const char *delimiter;
+       char *str, buf[128];
 
        if (!nr_caps) {
-               fprintf(fp, "# cpu pmu capabilities: not available\n");
+               if (!pmu_name)
+                       fprintf(fp, "# cpu pmu capabilities: not available\n");
+               else
+                       fprintf(fp, "# %s pmu capabilities: not available\n", pmu_name);
                return;
        }
 
-       str = ff->ph->env.cpu_pmu_caps;
+       if (!pmu_name)
+               scnprintf(buf, sizeof(buf), "# cpu pmu capabilities: ");
+       else
+               scnprintf(buf, sizeof(buf), "# %s pmu capabilities: ", pmu_name);
+
+       delimiter = buf;
+
+       str = cpu_pmu_caps;
        while (nr_caps--) {
                fprintf(fp, "%s%s", delimiter, str);
                delimiter = ", ";
@@ -1937,6 +2030,24 @@ static void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
        fprintf(fp, "\n");
 }
 
+static void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
+{
+       print_per_cpu_pmu_caps(fp, ff->ph->env.nr_cpu_pmu_caps,
+                              ff->ph->env.cpu_pmu_caps, NULL);
+}
+
+static void print_hybrid_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
+{
+       struct hybrid_cpc_node *n;
+
+       for (int i = 0; i < ff->ph->env.nr_hybrid_cpc_nodes; i++) {
+               n = &ff->ph->env.hybrid_cpc_nodes[i];
+               print_per_cpu_pmu_caps(fp, n->nr_cpu_pmu_caps,
+                                      n->cpu_pmu_caps,
+                                      n->pmu_name);
+       }
+}
+
 static void print_pmu_mappings(struct feat_fd *ff, FILE *fp)
 {
        const char *delimiter = "# pmu mappings: ";
@@ -2268,7 +2379,7 @@ static struct evsel *evlist__find_by_index(struct evlist *evlist, int idx)
        struct evsel *evsel;
 
        evlist__for_each_entry(evlist, evsel) {
-               if (evsel->idx == idx)
+               if (evsel->core.idx == idx)
                        return evsel;
        }
 
@@ -2282,7 +2393,7 @@ static void evlist__set_event_name(struct evlist *evlist, struct evsel *event)
        if (!event->name)
                return;
 
-       evsel = evlist__find_by_index(evlist, event->idx);
+       evsel = evlist__find_by_index(evlist, event->core.idx);
        if (!evsel)
                return;
 
@@ -2624,12 +2735,12 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused)
         * Rebuild group relationship based on the group_desc
         */
        session = container_of(ff->ph, struct perf_session, header);
-       session->evlist->nr_groups = nr_groups;
+       session->evlist->core.nr_groups = nr_groups;
 
        i = nr = 0;
        evlist__for_each_entry(session->evlist, evsel) {
-               if (evsel->idx == (int) desc[i].leader_idx) {
-                       evsel->leader = evsel;
+               if (evsel->core.idx == (int) desc[i].leader_idx) {
+                       evsel__set_leader(evsel, evsel);
                        /* {anon_group} is a dummy name */
                        if (strcmp(desc[i].name, "{anon_group}")) {
                                evsel->group_name = desc[i].name;
@@ -2647,7 +2758,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused)
                        i++;
                } else if (nr) {
                        /* This is a group member */
-                       evsel->leader = leader;
+                       evsel__set_leader(evsel, leader);
 
                        nr--;
                }
@@ -2849,6 +2960,46 @@ static int process_clock_data(struct feat_fd *ff,
        return 0;
 }
 
+static int process_hybrid_topology(struct feat_fd *ff,
+                                  void *data __maybe_unused)
+{
+       struct hybrid_node *nodes, *n;
+       u32 nr, i;
+
+       /* nr nodes */
+       if (do_read_u32(ff, &nr))
+               return -1;
+
+       nodes = zalloc(sizeof(*nodes) * nr);
+       if (!nodes)
+               return -ENOMEM;
+
+       for (i = 0; i < nr; i++) {
+               n = &nodes[i];
+
+               n->pmu_name = do_read_string(ff);
+               if (!n->pmu_name)
+                       goto error;
+
+               n->cpus = do_read_string(ff);
+               if (!n->cpus)
+                       goto error;
+       }
+
+       ff->ph->env.nr_hybrid_nodes = nr;
+       ff->ph->env.hybrid_nodes = nodes;
+       return 0;
+
+error:
+       for (i = 0; i < nr; i++) {
+               free(nodes[i].pmu_name);
+               free(nodes[i].cpus);
+       }
+
+       free(nodes);
+       return -1;
+}
+
 static int process_dir_format(struct feat_fd *ff,
                              void *_data __maybe_unused)
 {
@@ -3002,8 +3153,9 @@ static int process_compressed(struct feat_fd *ff,
        return 0;
 }
 
-static int process_cpu_pmu_caps(struct feat_fd *ff,
-                               void *data __maybe_unused)
+static int process_per_cpu_pmu_caps(struct feat_fd *ff, int *nr_cpu_pmu_caps,
+                                   char **cpu_pmu_caps,
+                                   unsigned int *max_branches)
 {
        char *name, *value;
        struct strbuf sb;
@@ -3017,7 +3169,7 @@ static int process_cpu_pmu_caps(struct feat_fd *ff,
                return 0;
        }
 
-       ff->ph->env.nr_cpu_pmu_caps = nr_caps;
+       *nr_cpu_pmu_caps = nr_caps;
 
        if (strbuf_init(&sb, 128) < 0)
                return -1;
@@ -3039,12 +3191,12 @@ static int process_cpu_pmu_caps(struct feat_fd *ff,
                        goto free_value;
 
                if (!strcmp(name, "branches"))
-                       ff->ph->env.max_branches = atoi(value);
+                       *max_branches = atoi(value);
 
                free(value);
                free(name);
        }
-       ff->ph->env.cpu_pmu_caps = strbuf_detach(&sb, NULL);
+       *cpu_pmu_caps = strbuf_detach(&sb, NULL);
        return 0;
 
 free_value:
@@ -3056,6 +3208,63 @@ error:
        return -1;
 }
 
+static int process_cpu_pmu_caps(struct feat_fd *ff,
+                               void *data __maybe_unused)
+{
+       return process_per_cpu_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps,
+                                       &ff->ph->env.cpu_pmu_caps,
+                                       &ff->ph->env.max_branches);
+}
+
+static int process_hybrid_cpu_pmu_caps(struct feat_fd *ff,
+                                      void *data __maybe_unused)
+{
+       struct hybrid_cpc_node *nodes;
+       u32 nr_pmu, i;
+       int ret;
+
+       if (do_read_u32(ff, &nr_pmu))
+               return -1;
+
+       if (!nr_pmu) {
+               pr_debug("hybrid cpu pmu capabilities not available\n");
+               return 0;
+       }
+
+       nodes = zalloc(sizeof(*nodes) * nr_pmu);
+       if (!nodes)
+               return -ENOMEM;
+
+       for (i = 0; i < nr_pmu; i++) {
+               struct hybrid_cpc_node *n = &nodes[i];
+
+               ret = process_per_cpu_pmu_caps(ff, &n->nr_cpu_pmu_caps,
+                                              &n->cpu_pmu_caps,
+                                              &n->max_branches);
+               if (ret)
+                       goto err;
+
+               n->pmu_name = do_read_string(ff);
+               if (!n->pmu_name) {
+                       ret = -1;
+                       goto err;
+               }
+       }
+
+       ff->ph->env.nr_hybrid_cpc_nodes = nr_pmu;
+       ff->ph->env.hybrid_cpc_nodes = nodes;
+       return 0;
+
+err:
+       for (i = 0; i < nr_pmu; i++) {
+               free(nodes[i].cpu_pmu_caps);
+               free(nodes[i].pmu_name);
+       }
+
+       free(nodes);
+       return ret;
+}
+
 #define FEAT_OPR(n, func, __full_only) \
        [HEADER_##n] = {                                        \
                .name       = __stringify(n),                   \
@@ -3117,6 +3326,8 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
        FEAT_OPR(COMPRESSED,    compressed,     false),
        FEAT_OPR(CPU_PMU_CAPS,  cpu_pmu_caps,   false),
        FEAT_OPR(CLOCK_DATA,    clock_data,     false),
+       FEAT_OPN(HYBRID_TOPOLOGY,       hybrid_topology,        true),
+       FEAT_OPR(HYBRID_CPU_PMU_CAPS,   hybrid_cpu_pmu_caps,    false),
 };
 
 struct header_print_data {
@@ -3654,10 +3865,10 @@ static int perf_file_section__process(struct perf_file_section *section,
 static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
                                       struct perf_header *ph,
                                       struct perf_data* data,
-                                      bool repipe)
+                                      bool repipe, int repipe_fd)
 {
        struct feat_fd ff = {
-               .fd = STDOUT_FILENO,
+               .fd = repipe_fd,
                .ph = ph,
        };
        ssize_t ret;
@@ -3680,13 +3891,13 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
        return 0;
 }
 
-static int perf_header__read_pipe(struct perf_session *session)
+static int perf_header__read_pipe(struct perf_session *session, int repipe_fd)
 {
        struct perf_header *header = &session->header;
        struct perf_pipe_file_header f_header;
 
        if (perf_file_header__read_pipe(&f_header, header, session->data,
-                                       session->repipe) < 0) {
+                                       session->repipe, repipe_fd) < 0) {
                pr_debug("incompatible file format\n");
                return -EINVAL;
        }
@@ -3784,7 +3995,7 @@ static int evlist__prepare_tracepoint_events(struct evlist *evlist, struct tep_h
        return 0;
 }
 
-int perf_session__read_header(struct perf_session *session)
+int perf_session__read_header(struct perf_session *session, int repipe_fd)
 {
        struct perf_data *data = session->data;
        struct perf_header *header = &session->header;
@@ -3805,7 +4016,7 @@ int perf_session__read_header(struct perf_session *session)
         * We can read 'pipe' data event from regular file,
         * check for the pipe header regardless of source.
         */
-       err = perf_header__read_pipe(session);
+       err = perf_header__read_pipe(session, repipe_fd);
        if (!err || perf_data__is_pipe(data)) {
                data->is_pipe = true;
                return err;
@@ -3814,6 +4025,11 @@ int perf_session__read_header(struct perf_session *session)
        if (perf_file_header__read(&f_header, header, fd) < 0)
                return -EINVAL;
 
+       if (header->needs_swap && data->in_place_update) {
+               pr_err("In-place update not supported when byte-swapping is required\n");
+               return -EINVAL;
+       }
+
        /*
         * Sanity check that perf.data was written cleanly; data size is
         * initialized to 0 and updated only if the on_exit function is run.