diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/annotate.c | 23 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 5 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 61 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 1 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 3 | ||||
-rw-r--r-- | tools/perf/util/thread_map.c | 22 | ||||
-rw-r--r-- | tools/perf/util/thread_map.h | 1 |
7 files changed, 98 insertions, 18 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ea7e0de4b9c1..06cc04e5806a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -223,13 +223,19 @@ bool ins__is_call(const struct ins *ins) static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) { const char *s = strchr(ops->raw, '+'); + const char *c = strchr(ops->raw, ','); - ops->target.addr = strtoull(ops->raw, NULL, 16); + if (c++ != NULL) + ops->target.addr = strtoull(c, NULL, 16); + else + ops->target.addr = strtoull(ops->raw, NULL, 16); - if (s++ != NULL) + if (s++ != NULL) { ops->target.offset = strtoull(s, NULL, 16); - else - ops->target.offset = UINT64_MAX; + ops->target.offset_avail = true; + } else { + ops->target.offset_avail = false; + } return 0; } @@ -237,7 +243,7 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op static int jump__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { - if (!ops->target.addr) + if (!ops->target.addr || ops->target.offset < 0) return ins__raw_scnprintf(ins, bf, size, ops); return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); @@ -641,7 +647,8 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - if (addr < sym->start || addr >= sym->end) { + if ((addr < sym->start || addr >= sym->end) && + (addr != sym->end || sym->start != sym->end)) { pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, __LINE__, sym->name, sym->start, addr, sym->end); return -ERANGE; @@ -1205,9 +1212,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, if (dl == NULL) return -1; - if (dl->ops.target.offset == UINT64_MAX) + if (!disasm_line__has_offset(dl)) { dl->ops.target.offset = dl->ops.target.addr - map__rip_2objdump(map, sym->start); + dl->ops.target.offset_avail = true; + } /* kcore has no symbols, so add the call target name */ if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 87e4cadc5d27..09776b5af991 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -24,7 +24,8 @@ struct ins_operands { char *raw; char *name; u64 addr; - u64 offset; + s64 offset; + bool offset_avail; } target; union { struct { @@ -68,7 +69,7 @@ struct disasm_line { static inline bool disasm_line__has_offset(const struct disasm_line *dl) { - return dl->ops.target.offset != UINT64_MAX; + return dl->ops.target.offset_avail; } void disasm_line__free(struct disasm_line *dl); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b2365a63db45..04e536ae4d88 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -990,6 +990,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, * it overloads any global configuration. */ apply_config_terms(evsel, opts); + + evsel->ignore_missing_thread = opts->ignore_missing_thread; } static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) @@ -1419,6 +1421,33 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, return fprintf(fp, " %-32s %s\n", name, val); } +static bool ignore_missing_thread(struct perf_evsel *evsel, + struct thread_map *threads, + int thread, int err) +{ + if (!evsel->ignore_missing_thread) + return false; + + /* The system wide setup does not work with threads. */ + if (evsel->system_wide) + return false; + + /* The -ESRCH is perf event syscall errno for pid's not found. */ + if (err != -ESRCH) + return false; + + /* If there's only one thread, let it fail. */ + if (threads->nr == 1) + return false; + + if (thread_map__remove(threads, thread)) + return false; + + pr_warning("WARNING: Ignored open failure for pid %d\n", + thread_map__pid(threads, thread)); + return true; +} + static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, struct thread_map *threads) { @@ -1474,7 +1503,7 @@ retry_sample_id: for (cpu = 0; cpu < cpus->nr; cpu++) { for (thread = 0; thread < nthreads; thread++) { - int group_fd; + int fd, group_fd; if (!evsel->cgrp && !evsel->system_wide) pid = thread_map__pid(threads, thread); @@ -1484,21 +1513,37 @@ retry_open: pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", pid, cpus->map[cpu], group_fd, flags); - FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, - pid, - cpus->map[cpu], - group_fd, flags); - if (FD(evsel, cpu, thread) < 0) { + fd = sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu], + group_fd, flags); + + FD(evsel, cpu, thread) = fd; + + if (fd < 0) { err = -errno; + + if (ignore_missing_thread(evsel, threads, thread, err)) { + /* + * We just removed 1 thread, so take a step + * back on thread index and lower the upper + * nthreads limit. + */ + nthreads--; + thread--; + + /* ... and pretend like nothing have happened. */ + err = 0; + continue; + } + pr_debug2("\nsys_perf_event_open failed, error %d\n", err); goto try_fallback; } - pr_debug2(" = %d\n", FD(evsel, cpu, thread)); + pr_debug2(" = %d\n", fd); if (evsel->bpf_fd >= 0) { - int evt_fd = FD(evsel, cpu, thread); + int evt_fd = fd; int bpf_fd = evsel->bpf_fd; err = ioctl(evt_fd, diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6abb89cd27f9..06ef6f29efa1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -120,6 +120,7 @@ struct perf_evsel { bool tracking; bool per_pkg; bool precise_max; + bool ignore_missing_thread; /* parse modifier helper */ int exclude_GH; int nr_members; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index df2482b2ba45..dc93940de351 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1459,7 +1459,8 @@ int dso__load(struct dso *dso, struct map *map) * Read the build id if possible. This is required for * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work */ - if (is_regular_file(dso->long_name) && + if (!dso->has_build_id && + is_regular_file(dso->long_name) && filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) dso__set_build_id(dso, build_id); diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 40585f5b7027..f9eab200fd75 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -448,3 +448,25 @@ bool thread_map__has(struct thread_map *threads, pid_t pid) return false; } + +int thread_map__remove(struct thread_map *threads, int idx) +{ + int i; + + if (threads->nr < 1) + return -EINVAL; + + if (idx >= threads->nr) + return -EINVAL; + + /* + * Free the 'idx' item and shift the rest up. + */ + free(threads->map[idx].comm); + + for (i = idx; i < threads->nr - 1; i++) + threads->map[i] = threads->map[i + 1]; + + threads->nr--; + return 0; +} diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index bd3b971588da..ea0ef08c6303 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h @@ -58,4 +58,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread) void thread_map__read_comms(struct thread_map *threads); bool thread_map__has(struct thread_map *threads, pid_t pid); +int thread_map__remove(struct thread_map *threads, int idx); #endif /* __PERF_THREAD_MAP_H */ |