Merge tag 'perf-urgent-for-mingo-4.18-20180625' of git://git.kernel.org/pub/scm/linux...
authorIngo Molnar <mingo@kernel.org>
Tue, 26 Jun 2018 06:37:57 +0000 (08:37 +0200)
committerIngo Molnar <mingo@kernel.org>
Tue, 26 Jun 2018 06:37:57 +0000 (08:37 +0200)
Pull perf/urgent fixes from Arnaldo Carvalho de Melo:

perf bench: (Jiri Olsa):

- Fix NUMA report output code handling of less than 1s runtimes.

perf script: (Ravi Bangoria)

- Add missing output fields in a 'perf script -h' hint.

- Fix crash because of missing evsel->priv.

- Fix crash caused by accessing feat_ops[HEADER_LAST_FEATURE], which
  is just a end of features header marker.

perf stat: (Thomas Richter)

- Remove duplicate event counting

perf test:

- Wire parsing error handling in 'parse events' test (Jiri Olsa)

- Fix 'session topology' test on s/390 (Thomas Richter)

eBPF: (Yonghong Song)

- Fix a clang 7.0 compilation error when building perf linking
  with libclang

intel-pt: (Adrian Hunter)

- Fix packet decoding of CYC packets.

Copies of kernel files: (Arnaldo Carvalho de Melo)

- Synchronize drm/drm.h UAPI

- Update x86's syscall_64.tbl, adding support for 'io_pgetevents' and 'rseq'
  in 'perf trace'.

- Update powerpc uapi/asm/unistd.h, adding support for the 'rseq' syscall.

- Update if_link.h and bpf.h, no effect on tool features.

PowerPC: (Sandipan Das)

- Fix crash if callchain is empty.

s/390: (Thomas Richter)

- Support random socked_id assignment in the perf header.

- Support s390 random socket_id assignment in perf.data file.

- Make PMU alias definitions taken from sysfs and JSON files comparable
  by normalizing them wrt spaces and newlines.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
16 files changed:
tools/arch/powerpc/include/uapi/asm/unistd.h
tools/include/uapi/drm/drm.h
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/if_link.h
tools/perf/arch/powerpc/util/skip-callchain-idx.c
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
tools/perf/bench/numa.c
tools/perf/builtin-annotate.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/tests/parse-events.c
tools/perf/tests/topology.c
tools/perf/util/c++/clang.cpp
tools/perf/util/header.c
tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c
tools/perf/util/pmu.c

index 389c36f..ac5ba55 100644 (file)
 #define __NR_pkey_alloc                384
 #define __NR_pkey_free         385
 #define __NR_pkey_mprotect     386
+#define __NR_rseq              387
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
index 6fdff59..9c660e1 100644 (file)
@@ -680,6 +680,13 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_ATOMIC  3
 
+/**
+ * DRM_CLIENT_CAP_ASPECT_RATIO
+ *
+ * If set to 1, the DRM core will provide aspect ratio information in modes.
+ */
+#define DRM_CLIENT_CAP_ASPECT_RATIO    4
+
 /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
        __u64 capability;
index e0b0678..59b19b6 100644 (file)
@@ -2630,7 +2630,7 @@ struct bpf_fib_lookup {
        union {
                /* inputs to lookup */
                __u8    tos;            /* AF_INET  */
-               __be32  flowlabel;      /* AF_INET6 */
+               __be32  flowinfo;       /* AF_INET6, flow_label + priority */
 
                /* output: metric of fib result (IPv4/IPv6 only) */
                __u32   rt_metric;
index 68699f6..cf01b68 100644 (file)
@@ -333,6 +333,7 @@ enum {
        IFLA_BRPORT_BCAST_FLOOD,
        IFLA_BRPORT_GROUP_FWD_MASK,
        IFLA_BRPORT_NEIGH_SUPPRESS,
+       IFLA_BRPORT_ISOLATED,
        __IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
@@ -516,6 +517,7 @@ enum {
        IFLA_VXLAN_COLLECT_METADATA,
        IFLA_VXLAN_LABEL,
        IFLA_VXLAN_GPE,
+       IFLA_VXLAN_TTL_INHERIT,
        __IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
index 3598b8b..ef5d59a 100644 (file)
@@ -243,7 +243,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
        u64 ip;
        u64 skip_slot = -1;
 
-       if (chain->nr < 3)
+       if (!chain || chain->nr < 3)
                return skip_slot;
 
        ip = chain->ips[2];
index 4dfe426..f0b1709 100644 (file)
 330    common  pkey_alloc              __x64_sys_pkey_alloc
 331    common  pkey_free               __x64_sys_pkey_free
 332    common  statx                   __x64_sys_statx
+333    common  io_pgetevents           __x64_sys_io_pgetevents
+334    common  rseq                    __x64_sys_rseq
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index 63eb490..4419551 100644 (file)
@@ -1098,7 +1098,7 @@ static void *worker_thread(void *__tdata)
        u8 *global_data;
        u8 *process_data;
        u8 *thread_data;
-       u64 bytes_done;
+       u64 bytes_done, secs;
        long work_done;
        u32 l;
        struct rusage rusage;
@@ -1254,7 +1254,8 @@ static void *worker_thread(void *__tdata)
        timersub(&stop, &start0, &diff);
        td->runtime_ns = diff.tv_sec * NSEC_PER_SEC;
        td->runtime_ns += diff.tv_usec * NSEC_PER_USEC;
-       td->speed_gbs = bytes_done / (td->runtime_ns / NSEC_PER_SEC) / 1e9;
+       secs = td->runtime_ns / NSEC_PER_SEC;
+       td->speed_gbs = secs ? bytes_done / secs / 1e9 : 0;
 
        getrusage(RUSAGE_THREAD, &rusage);
        td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC;
index 5eb22cc..8180319 100644 (file)
@@ -283,6 +283,15 @@ out_put:
        return ret;
 }
 
+static int process_feature_event(struct perf_tool *tool,
+                                union perf_event *event,
+                                struct perf_session *session)
+{
+       if (event->feat.feat_id < HEADER_LAST_FEATURE)
+               return perf_event__process_feature(tool, event, session);
+       return 0;
+}
+
 static int hist_entry__tty_annotate(struct hist_entry *he,
                                    struct perf_evsel *evsel,
                                    struct perf_annotate *ann)
@@ -471,7 +480,7 @@ int cmd_annotate(int argc, const char **argv)
                        .attr   = perf_event__process_attr,
                        .build_id = perf_event__process_build_id,
                        .tracing_data   = perf_event__process_tracing_data,
-                       .feature        = perf_event__process_feature,
+                       .feature        = process_feature_event,
                        .ordered_events = true,
                        .ordering_requires_timestamps = true,
                },
index cdb5b69..c04dc7b 100644 (file)
@@ -217,7 +217,8 @@ static int process_feature_event(struct perf_tool *tool,
        }
 
        /*
-        * All features are received, we can force the
+        * (feat_id = HEADER_LAST_FEATURE) is the end marker which
+        * means all features are received, now we can force the
         * group if needed.
         */
        setup_forced_leader(rep, session->evlist);
index a31d708..568ddfa 100644 (file)
@@ -1834,6 +1834,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
        struct perf_evlist *evlist;
        struct perf_evsel *evsel, *pos;
        int err;
+       static struct perf_evsel_script *es;
 
        err = perf_event__process_attr(tool, event, pevlist);
        if (err)
@@ -1842,6 +1843,19 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
        evlist = *pevlist;
        evsel = perf_evlist__last(*pevlist);
 
+       if (!evsel->priv) {
+               if (scr->per_event_dump) {
+                       evsel->priv = perf_evsel_script__new(evsel,
+                                               scr->session->data);
+               } else {
+                       es = zalloc(sizeof(*es));
+                       if (!es)
+                               return -ENOMEM;
+                       es->fp = stdout;
+                       evsel->priv = es;
+               }
+       }
+
        if (evsel->attr.type >= PERF_TYPE_MAX &&
            evsel->attr.type != PERF_TYPE_SYNTH)
                return 0;
@@ -3030,6 +3044,15 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
        return set_maps(script);
 }
 
+static int process_feature_event(struct perf_tool *tool,
+                                union perf_event *event,
+                                struct perf_session *session)
+{
+       if (event->feat.feat_id < HEADER_LAST_FEATURE)
+               return perf_event__process_feature(tool, event, session);
+       return 0;
+}
+
 #ifdef HAVE_AUXTRACE_SUPPORT
 static int perf_script__process_auxtrace_info(struct perf_tool *tool,
                                              union perf_event *event,
@@ -3074,7 +3097,7 @@ int cmd_script(int argc, const char **argv)
                        .attr            = process_attr,
                        .event_update   = perf_event__process_event_update,
                        .tracing_data    = perf_event__process_tracing_data,
-                       .feature         = perf_event__process_feature,
+                       .feature         = process_feature_event,
                        .build_id        = perf_event__process_build_id,
                        .id_index        = perf_event__process_id_index,
                        .auxtrace_info   = perf_script__process_auxtrace_info,
@@ -3125,8 +3148,9 @@ int cmd_script(int argc, const char **argv)
                     "+field to add and -field to remove."
                     "Valid types: hw,sw,trace,raw,synth. "
                     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
-                    "addr,symoff,period,iregs,uregs,brstack,brstacksym,flags,"
-                    "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr",
+                    "addr,symoff,srcline,period,iregs,uregs,brstack,"
+                    "brstacksym,flags,bpf-output,brstackinsn,brstackoff,"
+                    "callindent,insn,insnlen,synth,phys_addr,metric,misc",
                     parse_output_fields),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                    "system-wide collection from all CPUs"),
index 7d40770..6121191 100644 (file)
@@ -1309,6 +1309,11 @@ static int test__checkevent_config_cache(struct perf_evlist *evlist)
        return 0;
 }
 
+static bool test__intel_pt_valid(void)
+{
+       return !!perf_pmu__find("intel_pt");
+}
+
 static int test__intel_pt(struct perf_evlist *evlist)
 {
        struct perf_evsel *evsel = perf_evlist__first(evlist);
@@ -1375,6 +1380,7 @@ struct evlist_test {
        const char *name;
        __u32 type;
        const int id;
+       bool (*valid)(void);
        int (*check)(struct perf_evlist *evlist);
 };
 
@@ -1648,6 +1654,7 @@ static struct evlist_test test__events[] = {
        },
        {
                .name  = "intel_pt//u",
+               .valid = test__intel_pt_valid,
                .check = test__intel_pt,
                .id    = 52,
        },
@@ -1686,17 +1693,24 @@ static struct terms_test test__terms[] = {
 
 static int test_event(struct evlist_test *e)
 {
+       struct parse_events_error err = { .idx = 0, };
        struct perf_evlist *evlist;
        int ret;
 
+       if (e->valid && !e->valid()) {
+               pr_debug("... SKIP");
+               return 0;
+       }
+
        evlist = perf_evlist__new();
        if (evlist == NULL)
                return -ENOMEM;
 
-       ret = parse_events(evlist, e->name, NULL);
+       ret = parse_events(evlist, e->name, &err);
        if (ret) {
-               pr_debug("failed to parse event '%s', err %d\n",
-                        e->name, ret);
+               pr_debug("failed to parse event '%s', err %d, str '%s'\n",
+                        e->name, ret, err.str);
+               parse_events_print_error(&err, e->name);
        } else {
                ret = e->check(evlist);
        }
@@ -1714,10 +1728,11 @@ static int test_events(struct evlist_test *events, unsigned cnt)
        for (i = 0; i < cnt; i++) {
                struct evlist_test *e = &events[i];
 
-               pr_debug("running test %d '%s'\n", e->id, e->name);
+               pr_debug("running test %d '%s'", e->id, e->name);
                ret1 = test_event(e);
                if (ret1)
                        ret2 = ret1;
+               pr_debug("\n");
        }
 
        return ret2;
@@ -1799,7 +1814,7 @@ static int test_pmu_events(void)
        }
 
        while (!ret && (ent = readdir(dir))) {
-               struct evlist_test e;
+               struct evlist_test e = { .id = 0, };
                char name[2 * NAME_MAX + 1 + 12 + 3];
 
                /* Names containing . are special and cannot be used directly */
index 40e30a2..9497d02 100644 (file)
@@ -45,6 +45,7 @@ static int session_write_header(char *path)
 
        perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
        perf_header__set_feat(&session->header, HEADER_NRCPUS);
+       perf_header__set_feat(&session->header, HEADER_ARCH);
 
        session->header.data_size += DATA_SIZE;
 
index bf31cea..8951250 100644 (file)
@@ -146,8 +146,15 @@ getBPFObjectFromModule(llvm::Module *Module)
        raw_svector_ostream ostream(*Buffer);
 
        legacy::PassManager PM;
-       if (TargetMachine->addPassesToEmitFile(PM, ostream,
-                                              TargetMachine::CGFT_ObjectFile)) {
+       bool NotAdded;
+#if CLANG_VERSION_MAJOR < 7
+       NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream,
+                                                     TargetMachine::CGFT_ObjectFile);
+#else
+       NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream, nullptr,
+                                                     TargetMachine::CGFT_ObjectFile);
+#endif
+       if (NotAdded) {
                llvm::errs() << "TargetMachine can't emit a file of this type\n";
                return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);;
        }
index 540cd2d..653ff65 100644 (file)
@@ -2129,6 +2129,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
        int cpu_nr = ff->ph->env.nr_cpus_avail;
        u64 size = 0;
        struct perf_header *ph = ff->ph;
+       bool do_core_id_test = true;
 
        ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu));
        if (!ph->env.cpu)
@@ -2183,6 +2184,13 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
                return 0;
        }
 
+       /* On s390 the socket_id number is not related to the numbers of cpus.
+        * The socket_id number might be higher than the numbers of cpus.
+        * This depends on the configuration.
+        */
+       if (ph->env.arch && !strncmp(ph->env.arch, "s390", 4))
+               do_core_id_test = false;
+
        for (i = 0; i < (u32)cpu_nr; i++) {
                if (do_read_u32(ff, &nr))
                        goto free_cpu;
@@ -2192,7 +2200,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
                if (do_read_u32(ff, &nr))
                        goto free_cpu;
 
-               if (nr != (u32)-1 && nr > (u32)cpu_nr) {
+               if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) {
                        pr_debug("socket_id number is too big."
                                 "You may need to upgrade the perf tool.\n");
                        goto free_cpu;
@@ -3456,7 +3464,7 @@ int perf_event__process_feature(struct perf_tool *tool,
                pr_warning("invalid record type %d in pipe-mode\n", type);
                return 0;
        }
-       if (feat == HEADER_RESERVED || feat > HEADER_LAST_FEATURE) {
+       if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) {
                pr_warning("invalid record type %d in pipe-mode\n", type);
                return -1;
        }
index ba4c9dd..d426761 100644 (file)
@@ -366,7 +366,7 @@ static int intel_pt_get_cyc(unsigned int byte, const unsigned char *buf,
                if (len < offs)
                        return INTEL_PT_NEED_MORE_BYTES;
                byte = buf[offs++];
-               payload |= (byte >> 1) << shift;
+               payload |= ((uint64_t)byte >> 1) << shift;
        }
 
        packet->type = INTEL_PT_CYC;
index d2fb597..3ba6a17 100644 (file)
@@ -234,6 +234,74 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
        return 0;
 }
 
+static void perf_pmu_assign_str(char *name, const char *field, char **old_str,
+                               char **new_str)
+{
+       if (!*old_str)
+               goto set_new;
+
+       if (*new_str) { /* Have new string, check with old */
+               if (strcasecmp(*old_str, *new_str))
+                       pr_debug("alias %s differs in field '%s'\n",
+                                name, field);
+               zfree(old_str);
+       } else          /* Nothing new --> keep old string */
+               return;
+set_new:
+       *old_str = *new_str;
+       *new_str = NULL;
+}
+
+static void perf_pmu_update_alias(struct perf_pmu_alias *old,
+                                 struct perf_pmu_alias *newalias)
+{
+       perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc);
+       perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
+                           &newalias->long_desc);
+       perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
+       perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
+                           &newalias->metric_expr);
+       perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
+                           &newalias->metric_name);
+       perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
+       old->scale = newalias->scale;
+       old->per_pkg = newalias->per_pkg;
+       old->snapshot = newalias->snapshot;
+       memcpy(old->unit, newalias->unit, sizeof(old->unit));
+}
+
+/* Delete an alias entry. */
+static void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
+{
+       zfree(&newalias->name);
+       zfree(&newalias->desc);
+       zfree(&newalias->long_desc);
+       zfree(&newalias->topic);
+       zfree(&newalias->str);
+       zfree(&newalias->metric_expr);
+       zfree(&newalias->metric_name);
+       parse_events_terms__purge(&newalias->terms);
+       free(newalias);
+}
+
+/* Merge an alias, search in alias list. If this name is already
+ * present merge both of them to combine all information.
+ */
+static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
+                                struct list_head *alist)
+{
+       struct perf_pmu_alias *a;
+
+       list_for_each_entry(a, alist, list) {
+               if (!strcasecmp(newalias->name, a->name)) {
+                       perf_pmu_update_alias(a, newalias);
+                       perf_pmu_free_alias(newalias);
+                       return true;
+               }
+       }
+       return false;
+}
+
 static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
                                 char *desc, char *val,
                                 char *long_desc, char *topic,
@@ -241,9 +309,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
                                 char *metric_expr,
                                 char *metric_name)
 {
+       struct parse_events_term *term;
        struct perf_pmu_alias *alias;
        int ret;
        int num;
+       char newval[256];
 
        alias = malloc(sizeof(*alias));
        if (!alias)
@@ -262,6 +332,27 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
                return ret;
        }
 
+       /* Scan event and remove leading zeroes, spaces, newlines, some
+        * platforms have terms specified as
+        * event=0x0091 (read from files ../<PMU>/events/<FILE>
+        * and terms specified as event=0x91 (read from JSON files).
+        *
+        * Rebuild string to make alias->str member comparable.
+        */
+       memset(newval, 0, sizeof(newval));
+       ret = 0;
+       list_for_each_entry(term, &alias->terms, list) {
+               if (ret)
+                       ret += scnprintf(newval + ret, sizeof(newval) - ret,
+                                        ",");
+               if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
+                       ret += scnprintf(newval + ret, sizeof(newval) - ret,
+                                        "%s=%#x", term->config, term->val.num);
+               else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
+                       ret += scnprintf(newval + ret, sizeof(newval) - ret,
+                                        "%s=%s", term->config, term->val.str);
+       }
+
        alias->name = strdup(name);
        if (dir) {
                /*
@@ -285,9 +376,10 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
                snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
        }
        alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
-       alias->str = strdup(val);
+       alias->str = strdup(newval);
 
-       list_add_tail(&alias->list, list);
+       if (!perf_pmu_merge_alias(alias, list))
+               list_add_tail(&alias->list, list);
 
        return 0;
 }
@@ -303,6 +395,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
 
        buf[ret] = 0;
 
+       /* Remove trailing newline from sysfs file */
+       rtrim(buf);
+
        return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
                                     NULL, NULL, NULL);
 }