Merge branch 'perf/urgent' into perf/core, to resolve a conflict
authorIngo Molnar <mingo@kernel.org>
Wed, 16 Sep 2015 07:19:56 +0000 (09:19 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 16 Sep 2015 07:19:56 +0000 (09:19 +0200)
Conflicts:
tools/perf/ui/browsers/hists.c

Signed-off-by: Ingo Molnar <mingo@kernel.org>
1  2 
tools/perf/ui/browsers/hists.c
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/parse-events.c

@@@ -1261,7 -1261,6 +1261,7 @@@ static int hists__browser_title(struct 
        int printed;
        const struct dso *dso = hists->dso_filter;
        const struct thread *thread = hists->thread_filter;
 +      int socket_id = hists->socket_filter;
        unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
        u64 nr_events = hists->stats.total_period;
        struct perf_evsel *evsel = hists_to_evsel(hists);
        if (dso)
                printed += scnprintf(bf + printed, size - printed,
                                    ", DSO: %s", dso->short_name);
 +      if (socket_id > -1)
 +              printed += scnprintf(bf + printed, size - printed,
 +                                  ", Processor Socket: %d", socket_id);
        if (!is_report_browser(hbt)) {
                struct perf_top *top = hbt->arg;
  
@@@ -1429,7 -1425,6 +1429,7 @@@ struct popup_action 
        struct thread           *thread;
        struct dso              *dso;
        struct map_symbol       ms;
 +      int                     socket;
  
        int (*fn)(struct hist_browser *browser, struct popup_action *act);
  };
@@@ -1442,7 -1437,7 +1442,7 @@@ do_annotate(struct hist_browser *browse
        struct hist_entry *he;
        int err;
  
 -      if (!objdump_path && perf_session_env__lookup_objdump(browser->env))
 +      if (!objdump_path && perf_env__lookup_objdump(browser->env))
                return 0;
  
        notes = symbol__annotation(act->ms.sym);
@@@ -1677,41 -1672,6 +1677,41 @@@ add_exit_opt(struct hist_browser *brows
        return 1;
  }
  
 +static int
 +do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
 +{
 +      if (browser->hists->socket_filter > -1) {
 +              pstack__remove(browser->pstack, &browser->hists->socket_filter);
 +              browser->hists->socket_filter = -1;
 +              perf_hpp__set_elide(HISTC_SOCKET, false);
 +      } else {
 +              browser->hists->socket_filter = act->socket;
 +              perf_hpp__set_elide(HISTC_SOCKET, true);
 +              pstack__push(browser->pstack, &browser->hists->socket_filter);
 +      }
 +
 +      hists__filter_by_socket(browser->hists);
 +      hist_browser__reset(browser);
 +      return 0;
 +}
 +
 +static int
 +add_socket_opt(struct hist_browser *browser, struct popup_action *act,
 +             char **optstr, int socket_id)
 +{
 +      if (socket_id < 0)
 +              return 0;
 +
 +      if (asprintf(optstr, "Zoom %s Processor Socket %d",
 +                   (browser->hists->socket_filter > -1) ? "out of" : "into",
 +                   socket_id) < 0)
 +              return 0;
 +
 +      act->socket = socket_id;
 +      act->fn = do_zoom_socket;
 +      return 1;
 +}
 +
  static void hist_browser__update_nr_entries(struct hist_browser *hb)
  {
        u64 nr_entries = 0;
@@@ -1765,7 -1725,6 +1765,7 @@@ static int perf_evsel__hists_browse(str
        "E             Expand all callchains\n"                         \
        "F             Toggle percentage of filtered entries\n"         \
        "H             Display column headers\n"                        \
 +      "S             Zoom into current Processor Socket\n"            \
  
        /* help messages are sorted by lexical order of the hotkey */
        const char report_help[] = HIST_BROWSER_HELP_COMMON
                hist_browser__update_nr_entries(browser);
        }
  
 -      browser->pstack = pstack__new(2);
 +      browser->pstack = pstack__new(3);
        if (browser->pstack == NULL)
                goto out;
  
                struct thread *thread = NULL;
                struct dso *dso = NULL;
                int choice = 0;
 +              int socked_id = -1;
  
                nr_options = 0;
  
                if (browser->he_selection != NULL) {
                        thread = hist_browser__selected_thread(browser);
                        dso = browser->selection->map ? browser->selection->map->dso : NULL;
 +                      socked_id = browser->he_selection->socket;
                }
                switch (key) {
                case K_TAB:
                        actions->thread = thread;
                        do_zoom_thread(browser, actions);
                        continue;
 +              case 'S':
 +                      actions->socket = socked_id;
 +                      do_zoom_socket(browser, actions);
 +                      continue;
                case '/':
                        if (ui_browser__input_window("Symbol to show",
                                        "Please enter the name of symbol you want to see",
                                 * Ditto for thread below.
                                 */
                                do_zoom_dso(browser, actions);
 -                      }
 -                      if (top == &browser->hists->thread_filter)
 +                      } else if (top == &browser->hists->thread_filter) {
                                do_zoom_thread(browser, actions);
 +                      } else if (top == &browser->hists->socket_filter) {
 +                              do_zoom_socket(browser, actions);
 +                      }
                        continue;
                }
                case 'q':
@@@ -2017,16 -1968,24 +2017,26 @@@ skip_annotation
                                          &options[nr_options], dso);
                nr_options += add_map_opt(browser, &actions[nr_options],
                                          &options[nr_options],
-                                         browser->selection->map);
+                                         browser->selection ?
+                                               browser->selection->map : NULL);
 -
 +              nr_options += add_socket_opt(browser, &actions[nr_options],
 +                                           &options[nr_options],
 +                                           socked_id);
                /* perf script support */
                if (browser->he_selection) {
                        nr_options += add_script_opt(browser,
                                                     &actions[nr_options],
                                                     &options[nr_options],
                                                     thread, NULL);
+                       /*
+                        * Note that browser->selection != NULL
+                        * when browser->he_selection is not NULL,
+                        * so we don't need to check browser->selection
+                        * before fetching browser->selection->sym like what
+                        * we do before fetching browser->selection->map.
+                        *
+                        * See hist_browser__show_entry.
+                        */
                        nr_options += add_script_opt(browser,
                                                     &actions[nr_options],
                                                     &options[nr_options],
diff --combined tools/perf/util/evlist.c
@@@ -25,7 -25,6 +25,7 @@@
  #include <linux/bitops.h>
  #include <linux/hash.h>
  #include <linux/log2.h>
 +#include <linux/err.h>
  
  static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx);
  static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx);
@@@ -125,6 -124,33 +125,33 @@@ void perf_evlist__delete(struct perf_ev
        free(evlist);
  }
  
+ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
+                                         struct perf_evsel *evsel)
+ {
+       /*
+        * We already have cpus for evsel (via PMU sysfs) so
+        * keep it, if there's no target cpu list defined.
+        */
+       if (!evsel->own_cpus || evlist->has_user_cpus) {
+               cpu_map__put(evsel->cpus);
+               evsel->cpus = cpu_map__get(evlist->cpus);
+       } else if (evsel->cpus != evsel->own_cpus) {
+               cpu_map__put(evsel->cpus);
+               evsel->cpus = cpu_map__get(evsel->own_cpus);
+       }
+       thread_map__put(evsel->threads);
+       evsel->threads = thread_map__get(evlist->threads);
+ }
+ static void perf_evlist__propagate_maps(struct perf_evlist *evlist)
+ {
+       struct perf_evsel *evsel;
+       evlist__for_each(evlist, evsel)
+               __perf_evlist__propagate_maps(evlist, evsel);
+ }
  void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
  {
        entry->evlist = evlist;
  
        if (!evlist->nr_entries++)
                perf_evlist__set_id_pos(evlist);
+       __perf_evlist__propagate_maps(evlist, entry);
  }
  
  void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
-                                  struct list_head *list,
-                                  int nr_entries)
+                                  struct list_head *list)
  {
-       bool set_id_pos = !evlist->nr_entries;
+       struct perf_evsel *evsel, *temp;
  
-       list_splice_tail(list, &evlist->entries);
-       evlist->nr_entries += nr_entries;
-       if (set_id_pos)
-               perf_evlist__set_id_pos(evlist);
+       __evlist__for_each_safe(list, temp, evsel) {
+               list_del_init(&evsel->node);
+               perf_evlist__add(evlist, evsel);
+       }
  }
  
  void __perf_evlist__set_leader(struct list_head *list)
@@@ -211,7 -238,7 +239,7 @@@ static int perf_evlist__add_attrs(struc
                list_add_tail(&evsel->node, &head);
        }
  
-       perf_evlist__splice_list_tail(evlist, &head, nr_attrs);
+       perf_evlist__splice_list_tail(evlist, &head);
  
        return 0;
  
@@@ -266,7 -293,7 +294,7 @@@ int perf_evlist__add_newtp(struct perf_
  {
        struct perf_evsel *evsel = perf_evsel__newtp(sys, name);
  
 -      if (evsel == NULL)
 +      if (IS_ERR(evsel))
                return -1;
  
        evsel->handler = handler;
@@@ -1104,71 -1131,56 +1132,56 @@@ int perf_evlist__mmap(struct perf_evlis
        return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
  }
  
- static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
-                                      bool has_user_cpus)
- {
-       struct perf_evsel *evsel;
-       evlist__for_each(evlist, evsel) {
-               /*
-                * We already have cpus for evsel (via PMU sysfs) so
-                * keep it, if there's no target cpu list defined.
-                */
-               if (evsel->cpus && has_user_cpus)
-                       cpu_map__put(evsel->cpus);
-               if (!evsel->cpus || has_user_cpus)
-                       evsel->cpus = cpu_map__get(evlist->cpus);
-               evsel->threads = thread_map__get(evlist->threads);
-               if ((evlist->cpus && !evsel->cpus) ||
-                   (evlist->threads && !evsel->threads))
-                       return -ENOMEM;
-       }
-       return 0;
- }
  int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
  {
-       evlist->threads = thread_map__new_str(target->pid, target->tid,
-                                             target->uid);
+       struct cpu_map *cpus;
+       struct thread_map *threads;
+       threads = thread_map__new_str(target->pid, target->tid, target->uid);
  
-       if (evlist->threads == NULL)
+       if (!threads)
                return -1;
  
        if (target__uses_dummy_map(target))
-               evlist->cpus = cpu_map__dummy_new();
+               cpus = cpu_map__dummy_new();
        else
-               evlist->cpus = cpu_map__new(target->cpu_list);
+               cpus = cpu_map__new(target->cpu_list);
  
-       if (evlist->cpus == NULL)
+       if (!cpus)
                goto out_delete_threads;
  
-       return perf_evlist__propagate_maps(evlist, !!target->cpu_list);
+       evlist->has_user_cpus = !!target->cpu_list;
+       perf_evlist__set_maps(evlist, cpus, threads);
+       return 0;
  
  out_delete_threads:
-       thread_map__put(evlist->threads);
-       evlist->threads = NULL;
+       thread_map__put(threads);
        return -1;
  }
  
- int perf_evlist__set_maps(struct perf_evlist *evlist,
-                         struct cpu_map *cpus,
-                         struct thread_map *threads)
+ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus,
+                          struct thread_map *threads)
  {
-       if (evlist->cpus)
+       /*
+        * Allow for the possibility that one or another of the maps isn't being
+        * changed i.e. don't put it.  Note we are assuming the maps that are
+        * being applied are brand new and evlist is taking ownership of the
+        * original reference count of 1.  If that is not the case it is up to
+        * the caller to increase the reference count.
+        */
+       if (cpus != evlist->cpus) {
                cpu_map__put(evlist->cpus);
+               evlist->cpus = cpus;
+       }
  
-       evlist->cpus = cpus;
-       if (evlist->threads)
+       if (threads != evlist->threads) {
                thread_map__put(evlist->threads);
+               evlist->threads = threads;
+       }
  
-       evlist->threads = threads;
-       return perf_evlist__propagate_maps(evlist, false);
+       perf_evlist__propagate_maps(evlist);
  }
  
  int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel)
@@@ -1388,6 -1400,8 +1401,8 @@@ void perf_evlist__close(struct perf_evl
  
  static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist)
  {
+       struct cpu_map    *cpus;
+       struct thread_map *threads;
        int err = -ENOMEM;
  
        /*
         * error, and we may not want to do that fallback to a
         * default cpu identity map :-\
         */
-       evlist->cpus = cpu_map__new(NULL);
-       if (evlist->cpus == NULL)
+       cpus = cpu_map__new(NULL);
+       if (!cpus)
                goto out;
  
-       evlist->threads = thread_map__new_dummy();
-       if (evlist->threads == NULL)
-               goto out_free_cpus;
+       threads = thread_map__new_dummy();
+       if (!threads)
+               goto out_put;
  
-       err = 0;
+       perf_evlist__set_maps(evlist, cpus, threads);
  out:
        return err;
- out_free_cpus:
-       cpu_map__put(evlist->cpus);
-       evlist->cpus = NULL;
+ out_put:
+       cpu_map__put(cpus);
        goto out;
  }
  
diff --combined tools/perf/util/evsel.c
@@@ -9,11 -9,10 +9,11 @@@
  
  #include <byteswap.h>
  #include <linux/bitops.h>
 -#include <api/fs/debugfs.h>
 +#include <api/fs/tracing_path.h>
  #include <traceevent/event-parse.h>
  #include <linux/hw_breakpoint.h>
  #include <linux/perf_event.h>
 +#include <linux/err.h>
  #include <sys/resource.h>
  #include "asm/bug.h"
  #include "callchain.h"
@@@ -226,17 -225,11 +226,17 @@@ struct perf_evsel *perf_evsel__new_idx(
        return evsel;
  }
  
 +/*
 + * Returns pointer with encoded error via <linux/err.h> interface.
 + */
  struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
  {
        struct perf_evsel *evsel = zalloc(perf_evsel__object.size);
 +      int err = -ENOMEM;
  
 -      if (evsel != NULL) {
 +      if (evsel == NULL) {
 +              goto out_err;
 +      } else {
                struct perf_event_attr attr = {
                        .type          = PERF_TYPE_TRACEPOINT,
                        .sample_type   = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
                        goto out_free;
  
                evsel->tp_format = trace_event__tp_format(sys, name);
 -              if (evsel->tp_format == NULL)
 +              if (IS_ERR(evsel->tp_format)) {
 +                      err = PTR_ERR(evsel->tp_format);
                        goto out_free;
 +              }
  
                event_attr_init(&attr);
                attr.config = evsel->tp_format->id;
  out_free:
        zfree(&evsel->name);
        free(evsel);
 -      return NULL;
 +out_err:
 +      return ERR_PTR(err);
  }
  
  const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
@@@ -1043,6 -1033,7 +1043,7 @@@ void perf_evsel__exit(struct perf_evse
        perf_evsel__free_config_terms(evsel);
        close_cgroup(evsel->cgrp);
        cpu_map__put(evsel->cpus);
+       cpu_map__put(evsel->own_cpus);
        thread_map__put(evsel->threads);
        zfree(&evsel->group_name);
        zfree(&evsel->name);
diff --combined tools/perf/util/evsel.h
@@@ -98,6 -98,7 +98,7 @@@ struct perf_evsel 
        struct cgroup_sel       *cgrp;
        void                    *handler;
        struct cpu_map          *cpus;
+       struct cpu_map          *own_cpus;
        struct thread_map       *threads;
        unsigned int            sample_size;
        int                     id_pos;
@@@ -129,6 -130,7 +130,6 @@@ union u64_swap 
  struct cpu_map;
  struct target;
  struct thread_map;
 -struct perf_evlist;
  struct record_opts;
  
  static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
@@@ -160,9 -162,6 +161,9 @@@ static inline struct perf_evsel *perf_e
  
  struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx);
  
 +/*
 + * Returns pointer with encoded error via <linux/err.h> interface.
 + */
  static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name)
  {
        return perf_evsel__newtp_idx(sys, name, 0);
diff --combined tools/perf/util/header.c
@@@ -24,6 -24,9 +24,6 @@@
  #include "build-id.h"
  #include "data.h"
  
 -static u32 header_argc;
 -static const char **header_argv;
 -
  /*
   * magic2 = "PERFILE2"
   * must be a numerical value to let the endianness
@@@ -85,9 -88,6 +85,9 @@@ int write_padded(int fd, const void *bf
        return err;
  }
  
 +#define string_size(str)                                              \
 +      (PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32))
 +
  static int do_write_string(int fd, const char *str)
  {
        u32 len, olen;
@@@ -135,6 -135,37 +135,6 @@@ static char *do_read_string(int fd, str
        return NULL;
  }
  
 -int
 -perf_header__set_cmdline(int argc, const char **argv)
 -{
 -      int i;
 -
 -      /*
 -       * If header_argv has already been set, do not override it.
 -       * This allows a command to set the cmdline, parse args and
 -       * then call another builtin function that implements a
 -       * command -- e.g, cmd_kvm calling cmd_record.
 -       */
 -      if (header_argv)
 -              return 0;
 -
 -      header_argc = (u32)argc;
 -
 -      /* do not include NULL termination */
 -      header_argv = calloc(argc, sizeof(char *));
 -      if (!header_argv)
 -              return -ENOMEM;
 -
 -      /*
 -       * must copy argv contents because it gets moved
 -       * around during option parsing
 -       */
 -      for (i = 0; i < argc ; i++)
 -              header_argv[i] = argv[i];
 -
 -      return 0;
 -}
 -
  static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
                            struct perf_evlist *evlist)
  {
@@@ -371,8 -402,8 +371,8 @@@ static int write_cmdline(int fd, struc
  {
        char buf[MAXPATHLEN];
        char proc[32];
 -      u32 i, n;
 -      int ret;
 +      u32 n;
 +      int i, ret;
  
        /*
         * actual atual path to perf binary
        buf[ret] = '\0';
  
        /* account for binary path */
 -      n = header_argc + 1;
 +      n = perf_env.nr_cmdline + 1;
  
        ret = do_write(fd, &n, sizeof(n));
        if (ret < 0)
        if (ret < 0)
                return ret;
  
 -      for (i = 0 ; i < header_argc; i++) {
 -              ret = do_write_string(fd, header_argv[i]);
 +      for (i = 0 ; i < perf_env.nr_cmdline; i++) {
 +              ret = do_write_string(fd, perf_env.cmdline_argv[i]);
                if (ret < 0)
                        return ret;
        }
        "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list"
  
  struct cpu_topo {
 +      u32 cpu_nr;
        u32 core_sib;
        u32 thread_sib;
        char **core_siblings;
@@@ -521,7 -551,7 +521,7 @@@ static struct cpu_topo *build_cpu_topol
                return NULL;
  
        tp = addr;
 -
 +      tp->cpu_nr = nr;
        addr += sizeof(*tp);
        tp->core_siblings = addr;
        addr += sz;
@@@ -544,7 -574,7 +544,7 @@@ static int write_cpu_topology(int fd, s
  {
        struct cpu_topo *tp;
        u32 i;
 -      int ret;
 +      int ret, j;
  
        tp = build_cpu_topology();
        if (!tp)
                if (ret < 0)
                        break;
        }
 +
 +      ret = perf_env__read_cpu_topology_map(&perf_env);
 +      if (ret < 0)
 +              goto done;
 +
 +      for (j = 0; j < perf_env.nr_cpus_avail; j++) {
 +              ret = do_write(fd, &perf_env.cpu[j].core_id,
 +                             sizeof(perf_env.cpu[j].core_id));
 +              if (ret < 0)
 +                      return ret;
 +              ret = do_write(fd, &perf_env.cpu[j].socket_id,
 +                             sizeof(perf_env.cpu[j].socket_id));
 +              if (ret < 0)
 +                      return ret;
 +      }
  done:
        free_cpu_topo(tp);
        return ret;
@@@ -923,7 -938,6 +923,7 @@@ static void print_cpu_topology(struct p
  {
        int nr, i;
        char *str;
 +      int cpu_nr = ph->env.nr_cpus_online;
  
        nr = ph->env.nr_sibling_cores;
        str = ph->env.sibling_cores;
                fprintf(fp, "# sibling threads : %s\n", str);
                str += strlen(str) + 1;
        }
 +
 +      if (ph->env.cpu != NULL) {
 +              for (i = 0; i < cpu_nr; i++)
 +                      fprintf(fp, "# CPU %d: Core ID %d, Socket ID %d\n", i,
 +                              ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id);
 +      } else
 +              fprintf(fp, "# Core ID and Socket ID information is not available\n");
  }
  
  static void free_event_desc(struct perf_evsel *events)
@@@ -1431,7 -1438,7 +1431,7 @@@ static int process_nrcpus(struct perf_f
        if (ph->needs_swap)
                nr = bswap_32(nr);
  
-       ph->env.nr_cpus_online = nr;
+       ph->env.nr_cpus_avail = nr;
  
        ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
        if (ph->needs_swap)
                nr = bswap_32(nr);
  
-       ph->env.nr_cpus_avail = nr;
+       ph->env.nr_cpus_online = nr;
        return 0;
  }
  
@@@ -1575,7 -1582,7 +1575,7 @@@ error
        return -1;
  }
  
 -static int process_cpu_topology(struct perf_file_section *section __maybe_unused,
 +static int process_cpu_topology(struct perf_file_section *section,
                                struct perf_header *ph, int fd,
                                void *data __maybe_unused)
  {
        u32 nr, i;
        char *str;
        struct strbuf sb;
 +      int cpu_nr = ph->env.nr_cpus_online;
 +      u64 size = 0;
 +
 +      ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu));
 +      if (!ph->env.cpu)
 +              return -1;
  
        ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
 -              return -1;
 +              goto free_cpu;
  
        if (ph->needs_swap)
                nr = bswap_32(nr);
  
        ph->env.nr_sibling_cores = nr;
 +      size += sizeof(u32);
        strbuf_init(&sb, 128);
  
        for (i = 0; i < nr; i++) {
  
                /* include a NULL character at the end */
                strbuf_add(&sb, str, strlen(str) + 1);
 +              size += string_size(str);
                free(str);
        }
        ph->env.sibling_cores = strbuf_detach(&sb, NULL);
                nr = bswap_32(nr);
  
        ph->env.nr_sibling_threads = nr;
 +      size += sizeof(u32);
  
        for (i = 0; i < nr; i++) {
                str = do_read_string(fd, ph);
  
                /* include a NULL character at the end */
                strbuf_add(&sb, str, strlen(str) + 1);
 +              size += string_size(str);
                free(str);
        }
        ph->env.sibling_threads = strbuf_detach(&sb, NULL);
 +
 +      /*
 +       * The header may be from old perf,
 +       * which doesn't include core id and socket id information.
 +       */
 +      if (section->size <= size) {
 +              zfree(&ph->env.cpu);
 +              return 0;
 +      }
 +
 +      for (i = 0; i < (u32)cpu_nr; i++) {
 +              ret = readn(fd, &nr, sizeof(nr));
 +              if (ret != sizeof(nr))
 +                      goto free_cpu;
 +
 +              if (ph->needs_swap)
 +                      nr = bswap_32(nr);
 +
 +              if (nr > (u32)cpu_nr) {
 +                      pr_debug("core_id number is too big."
 +                               "You may need to upgrade the perf tool.\n");
 +                      goto free_cpu;
 +              }
 +              ph->env.cpu[i].core_id = nr;
 +
 +              ret = readn(fd, &nr, sizeof(nr));
 +              if (ret != sizeof(nr))
 +                      goto free_cpu;
 +
 +              if (ph->needs_swap)
 +                      nr = bswap_32(nr);
 +
 +              if (nr > (u32)cpu_nr) {
 +                      pr_debug("socket_id number is too big."
 +                               "You may need to upgrade the perf tool.\n");
 +                      goto free_cpu;
 +              }
 +
 +              ph->env.cpu[i].socket_id = nr;
 +      }
 +
        return 0;
  
  error:
        strbuf_release(&sb);
 +free_cpu:
 +      zfree(&ph->env.cpu);
        return -1;
  }
  
@@@ -1783,9 -1737,6 +1783,9 @@@ static int process_pmu_mappings(struct 
                /* include a NULL character at the end */
                strbuf_add(&sb, "", 1);
  
 +              if (!strcmp(name, "msr"))
 +                      ph->env.msr_pmu_type = type;
 +
                free(name);
                pmu_num--;
        }
@@@ -2564,7 -2515,6 +2564,7 @@@ int perf_session__read_header(struct pe
                return -ENOMEM;
  
        session->evlist->env = &header->env;
 +      session->machines.host.env = &header->env;
        if (perf_data_file__is_pipe(file))
                return perf_header__read_pipe(session);
  
@@@ -1,5 -1,4 +1,5 @@@
  #include <linux/hw_breakpoint.h>
 +#include <linux/err.h>
  #include "util.h"
  #include "../perf.h"
  #include "evlist.h"
@@@ -12,7 -11,7 +12,7 @@@
  #include "cache.h"
  #include "header.h"
  #include "debug.h"
 -#include <api/fs/debugfs.h>
 +#include <api/fs/tracing_path.h>
  #include "parse-events-bison.h"
  #define YY_EXTRA_TYPE int
  #include "parse-events-flex.h"
@@@ -288,8 -287,8 +288,8 @@@ __add_event(struct list_head *list, in
        if (!evsel)
                return NULL;
  
-       if (cpus)
-               evsel->cpus = cpu_map__get(cpus);
+       evsel->cpus     = cpu_map__get(cpus);
+       evsel->own_cpus = cpu_map__get(cpus);
  
        if (name)
                evsel->name = strdup(name);
@@@ -387,52 -386,22 +387,52 @@@ int parse_events_add_cache(struct list_
        return add_event(list, idx, &attr, name, NULL);
  }
  
 +static void tracepoint_error(struct parse_events_error *error, int err,
 +                           char *sys, char *name)
 +{
 +      char help[BUFSIZ];
 +
 +      /*
 +       * We get error directly from syscall errno ( > 0),
 +       * or from encoded pointer's error ( < 0).
 +       */
 +      err = abs(err);
 +
 +      switch (err) {
 +      case EACCES:
 +              error->str = strdup("can't access trace events");
 +              break;
 +      case ENOENT:
 +              error->str = strdup("unknown tracepoint");
 +              break;
 +      default:
 +              error->str = strdup("failed to add tracepoint");
 +              break;
 +      }
 +
 +      tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name);
 +      error->help = strdup(help);
 +}
 +
  static int add_tracepoint(struct list_head *list, int *idx,
 -                        char *sys_name, char *evt_name)
 +                        char *sys_name, char *evt_name,
 +                        struct parse_events_error *error __maybe_unused)
  {
        struct perf_evsel *evsel;
  
        evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++);
 -      if (!evsel)
 -              return -ENOMEM;
 +      if (IS_ERR(evsel)) {
 +              tracepoint_error(error, PTR_ERR(evsel), sys_name, evt_name);
 +              return PTR_ERR(evsel);
 +      }
  
        list_add_tail(&evsel->node, list);
 -
        return 0;
  }
  
  static int add_tracepoint_multi_event(struct list_head *list, int *idx,
 -                                    char *sys_name, char *evt_name)
 +                                    char *sys_name, char *evt_name,
 +                                    struct parse_events_error *error)
  {
        char evt_path[MAXPATHLEN];
        struct dirent *evt_ent;
        snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
        evt_dir = opendir(evt_path);
        if (!evt_dir) {
 -              perror("Can't open event dir");
 +              tracepoint_error(error, errno, sys_name, evt_name);
                return -1;
        }
  
                if (!strglobmatch(evt_ent->d_name, evt_name))
                        continue;
  
 -              ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
 +              ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, error);
        }
  
        closedir(evt_dir);
  }
  
  static int add_tracepoint_event(struct list_head *list, int *idx,
 -                              char *sys_name, char *evt_name)
 +                              char *sys_name, char *evt_name,
 +                              struct parse_events_error *error)
  {
        return strpbrk(evt_name, "*?") ?
 -             add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
 -             add_tracepoint(list, idx, sys_name, evt_name);
 +             add_tracepoint_multi_event(list, idx, sys_name, evt_name, error) :
 +             add_tracepoint(list, idx, sys_name, evt_name, error);
  }
  
  static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
 -                                  char *sys_name, char *evt_name)
 +                                  char *sys_name, char *evt_name,
 +                                  struct parse_events_error *error)
  {
        struct dirent *events_ent;
        DIR *events_dir;
  
        events_dir = opendir(tracing_events_path);
        if (!events_dir) {
 -              perror("Can't open event dir");
 +              tracepoint_error(error, errno, sys_name, evt_name);
                return -1;
        }
  
                        continue;
  
                ret = add_tracepoint_event(list, idx, events_ent->d_name,
 -                                         evt_name);
 +                                         evt_name, error);
        }
  
        closedir(events_dir);
  }
  
  int parse_events_add_tracepoint(struct list_head *list, int *idx,
 -                              char *sys, char *event)
 +                              char *sys, char *event,
 +                              struct parse_events_error *error)
  {
        if (strpbrk(sys, "*?"))
 -              return add_tracepoint_multi_sys(list, idx, sys, event);
 +              return add_tracepoint_multi_sys(list, idx, sys, event, error);
        else
 -              return add_tracepoint_event(list, idx, sys, event);
 +              return add_tracepoint_event(list, idx, sys, event, error);
  }
  
  static int
@@@ -1174,10 -1140,9 +1174,9 @@@ int parse_events(struct perf_evlist *ev
        ret = parse_events__scanner(str, &data, PE_START_EVENTS);
        perf_pmu__parse_cleanup();
        if (!ret) {
-               int entries = data.idx - evlist->nr_entries;
                struct perf_evsel *last;
  
-               perf_evlist__splice_list_tail(evlist, &data.list, entries);
+               perf_evlist__splice_list_tail(evlist, &data.list);
                evlist->nr_groups += data.nr_groups;
                last = perf_evlist__last(evlist);
                last->cmdline_group_boundary = true;