From: Ian Rogers <irogers@google.com>
To: irogers@google.com, acme@kernel.org, adrian.hunter@intel.com,
mingo@redhat.com, namhyung@kernel.org, peterz@infradead.org
Cc: ak@linux.intel.com, alexander.shishkin@linux.intel.com,
atrajeev@linux.ibm.com, dvyukov@google.com, fzczx123@gmail.com,
james.clark@linaro.org, jolsa@kernel.org, kjain@linux.ibm.com,
krzysztof.m.lopatowski@gmail.com, leo.yan@arm.com,
lihuafei1@huawei.com, linux-kernel@vger.kernel.org,
linux-perf-users@vger.kernel.org, linux@treblig.org,
m.liska@foxlink.cz, mark.rutland@arm.com, martin.liska@hey.com,
mpetlan@redhat.com, quic_zhonhan@quicinc.com,
scclevenger@os.amperecomputing.com, sesse@google.com,
stephen.s.brennan@oracle.com, thomas.falcon@intel.com,
yangyicong@hisilicon.com
Subject: [PATCH v2 5/8] perf tools: Internal support for BUILD_ID_OFFSET
Date: Fri, 2 Oct 2026 10:38:38 -0700 [thread overview]
Message-ID: <20261002173848.3228217-6-irogers@google.com> (raw)
In-Reply-To: <20261002173848.3228217-1-irogers@google.com>
Implement user-space parsing for the new sample types in evsel,
update perf_event_attr_fprintf to display the new bits
in 'perf report -D', and update synthetic event parameter names.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-report.c | 6 +-
tools/perf/builtin-script.c | 16 +--
tools/perf/util/callchain.c | 93 ++++++++++++-----
tools/perf/util/dsos.c | 27 +++++
tools/perf/util/dsos.h | 2 +
tools/perf/util/event.c | 35 +++++--
tools/perf/util/evsel.c | 114 ++++++++++++++++++++-
tools/perf/util/evsel.h | 3 +-
tools/perf/util/evsel_fprintf.c | 9 +-
tools/perf/util/machine.c | 119 +++++++++++++++++-----
tools/perf/util/maps.c | 59 +++++++++++
tools/perf/util/maps.h | 2 +
tools/perf/util/perf_event_attr_fprintf.c | 3 +-
tools/perf/util/sample.c | 9 ++
tools/perf/util/sample.h | 28 +++++
tools/perf/util/session.c | 52 +++++++---
tools/perf/util/synthetic-events.c | 28 +++++
17 files changed, 515 insertions(+), 90 deletions(-)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 57225bc87731..0c8596cf82b5 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -382,7 +382,8 @@ static int report__setup_sample_type(struct report *rep)
session->itrace_synth_opts->add_last_branch)
sample_type |= PERF_SAMPLE_BRANCH_STACK;
- if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
+ if (!is_pipe && !(sample_type & (PERF_SAMPLE_CALLCHAIN |
+ PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET))) {
if (perf_hpp_list.parent) {
ui__error("Selected --sort parent, but no "
"callchain data. Did you call "
@@ -408,7 +409,8 @@ static int report__setup_sample_type(struct report *rep)
if (symbol_conf.cumulate_callchain) {
/* Silently ignore if callchain is missing */
- if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
+ if (!(sample_type & (PERF_SAMPLE_CALLCHAIN |
+ PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET))) {
symbol_conf.cumulate_callchain = false;
perf_hpp__cancel_cumulate(session->evlist);
}
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 99e9e0c60f14..0c93959574e5 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -498,7 +498,8 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
return -EINVAL;
if (PRINT_FIELD(IP)) {
- if (evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", PERF_OUTPUT_IP))
+ if (evsel__check_stype(evsel, PERF_SAMPLE_IP | PERF_SAMPLE_BUILD_ID_OFFSET,
+ "IP", PERF_OUTPUT_IP))
return -EINVAL;
}
@@ -515,7 +516,8 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
return -EINVAL;
if (PRINT_FIELD(SYM) &&
- !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) {
+ !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP | PERF_SAMPLE_ADDR |
+ PERF_SAMPLE_BUILD_ID_OFFSET))) {
pr_err("Display of symbols requested but neither sample IP nor "
"sample address\navailable. Hence, no addresses to convert "
"to symbols.\n");
@@ -527,7 +529,8 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
return -EINVAL;
}
if (PRINT_FIELD(DSO) &&
- !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) {
+ !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP | PERF_SAMPLE_ADDR |
+ PERF_SAMPLE_BUILD_ID_OFFSET))) {
pr_err("Display of DSO requested but no address to convert.\n");
return -EINVAL;
}
@@ -1788,7 +1791,7 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample,
unsigned int print_opts = output[type].print_ip_opts;
struct callchain_cursor *cursor = NULL;
- if (symbol_conf.use_callchain && sample->callchain) {
+ if (symbol_conf.use_callchain && (sample->callchain || sample->callchain_bids)) {
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(al->thread, cursor,
sample, NULL, NULL,
@@ -2753,7 +2756,7 @@ static void process_event(struct perf_script *script,
if (script->stitch_lbr)
thread__set_lbr_stitch_enable(al->thread, true);
- if (symbol_conf.use_callchain && sample->callchain) {
+ if (symbol_conf.use_callchain && (sample->callchain || sample->callchain_bids)) {
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(al->thread, cursor,
sample, NULL, NULL,
@@ -3000,7 +3003,7 @@ static int process_deferred_sample_event(const struct perf_tool *tool,
if (PRINT_FIELD(IP)) {
struct callchain_cursor *cursor = NULL;
- if (symbol_conf.use_callchain && sample->callchain) {
+ if (symbol_conf.use_callchain && (sample->callchain || sample->callchain_bids)) {
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(al.thread, cursor,
sample, NULL, NULL,
@@ -3082,6 +3085,7 @@ static int process_attr(const struct perf_tool *tool, union perf_event *event,
/* Enable fields for callchain entries */
if (symbol_conf.use_callchain &&
(sample_type & PERF_SAMPLE_CALLCHAIN ||
+ sample_type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET ||
sample_type & PERF_SAMPLE_BRANCH_STACK ||
(sample_type & PERF_SAMPLE_REGS_USER &&
sample_type & PERF_SAMPLE_STACK_USER))) {
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 31c675cbab63..24a229ee2ada 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1173,7 +1173,8 @@ int sample__resolve_callchain(struct perf_sample *sample,
struct addr_location *al,
int max_stack)
{
- if (sample->callchain == NULL && !symbol_conf.show_branchflag_count)
+ if (sample->callchain == NULL && sample->callchain_bids == NULL &&
+ !symbol_conf.show_branchflag_count)
return 0;
if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
@@ -1186,7 +1187,8 @@ int sample__resolve_callchain(struct perf_sample *sample,
int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
{
- if ((!symbol_conf.use_callchain || sample->callchain == NULL) &&
+ if ((!symbol_conf.use_callchain ||
+ (sample->callchain == NULL && sample->callchain_bids == NULL)) &&
!symbol_conf.show_branchflag_count)
return 0;
return callchain_append(he->callchain, get_tls_callchain_cursor(), sample->period);
@@ -1912,32 +1914,75 @@ int sample__for_each_callchain_node(struct thread *thread,
int sample__merge_deferred_callchain(struct perf_sample *sample_orig,
struct perf_sample *sample_callchain)
{
- u64 nr_orig = sample_orig->callchain->nr - 1;
- u64 nr_deferred = sample_callchain->callchain->nr;
- struct ip_callchain *callchain;
-
- if (sample_orig->merged_callchain) {
- /* Already merged. */
- return -EINVAL;
+ if (sample_orig->deferred_bid && sample_callchain->callchain_bids_nr > 0) {
+ const struct perf_sample_build_id_offset *entry =
+ &sample_callchain->callchain_bids[0];
+
+ memcpy(sample_orig->bid.deferred_storage, &entry->bid,
+ sizeof(struct perf_build_id));
+ sample_orig->bid.bid =
+ (struct perf_build_id *)sample_orig->bid.deferred_storage;
+ sample_orig->bid.offset = entry->offset;
+ if (!sample_orig->evsel ||
+ !(sample_orig->evsel->core.attr.sample_type & PERF_SAMPLE_IP))
+ sample_orig->ip = entry->offset;
+ sample_orig->deferred_bid = false;
+ }
+
+ if (sample_orig->callchain_bids_nr >= 2 &&
+ sample_callchain->callchain_bids_nr > 0) {
+ u64 nr_orig = sample_orig->callchain_bids_nr - 1;
+ u64 nr_deferred = sample_callchain->callchain_bids_nr;
+
+ if (sample_orig->callchain_bids[nr_orig - 1].offset ==
+ PERF_CONTEXT_USER_DEFERRED) {
+ struct perf_sample_build_id_offset *bids =
+ calloc(nr_orig + nr_deferred, sizeof(*bids));
+
+ if (bids == NULL)
+ return -ENOMEM;
+
+ memcpy(bids, sample_orig->callchain_bids,
+ nr_orig * sizeof(*bids));
+ memcpy(&bids[nr_orig], sample_callchain->callchain_bids,
+ nr_deferred * sizeof(*bids));
+ if (sample_orig->merged_callchain_bids)
+ free(sample_orig->callchain_bids);
+ sample_orig->callchain_bids = bids;
+ sample_orig->callchain_bids_nr = nr_orig + nr_deferred;
+ sample_orig->merged_callchain_bids = true;
+ }
}
- if (sample_orig->callchain->nr < 2) {
- sample_orig->deferred_callchain = false;
- return -EINVAL;
- }
+ if (sample_orig->callchain && sample_callchain->callchain) {
+ u64 nr_orig = sample_orig->callchain->nr - 1;
+ u64 nr_deferred = sample_callchain->callchain->nr;
+ struct ip_callchain *callchain;
- callchain = calloc(1 + nr_orig + nr_deferred, sizeof(u64));
- if (callchain == NULL)
- return -ENOMEM;
+ if (sample_orig->merged_callchain) {
+ /* Already merged. */
+ return -EINVAL;
+ }
- callchain->nr = nr_orig + nr_deferred;
- /* copy original including PERF_CONTEXT_USER_DEFERRED (but the cookie) */
- memcpy(callchain->ips, sample_orig->callchain->ips, nr_orig * sizeof(u64));
- /* copy deferred user callchains */
- memcpy(&callchain->ips[nr_orig], sample_callchain->callchain->ips,
- nr_deferred * sizeof(u64));
+ if (sample_orig->callchain->nr < 2) {
+ sample_orig->deferred_callchain = false;
+ return -EINVAL;
+ }
+
+ callchain = calloc(1 + nr_orig + nr_deferred, sizeof(u64));
+ if (callchain == NULL)
+ return -ENOMEM;
+
+ callchain->nr = nr_orig + nr_deferred;
+ /* copy original including PERF_CONTEXT_USER_DEFERRED (but the cookie) */
+ memcpy(callchain->ips, sample_orig->callchain->ips, nr_orig * sizeof(u64));
+ /* copy deferred user callchains */
+ memcpy(&callchain->ips[nr_orig], sample_callchain->callchain->ips,
+ nr_deferred * sizeof(u64));
+
+ sample_orig->merged_callchain = true;
+ sample_orig->callchain = callchain;
+ }
- sample_orig->merged_callchain = true;
- sample_orig->callchain = callchain;
return 0;
}
diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c
index e927e707abac..ae47966ff6af 100644
--- a/tools/perf/util/dsos.c
+++ b/tools/perf/util/dsos.c
@@ -294,6 +294,33 @@ struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
return res;
}
+struct dsos__find_build_id_cb_args {
+ const struct build_id *bid;
+ struct dso *res;
+};
+
+static int dsos__find_build_id_cb(struct dso *dso, void *data)
+{
+ struct dsos__find_build_id_cb_args *args = data;
+
+ if (dso__build_id_equal(dso, args->bid)) {
+ args->res = dso__get(dso);
+ return 1;
+ }
+ return 0;
+}
+
+struct dso *dsos__find_by_build_id(struct dsos *dsos, const struct build_id *bid)
+{
+ struct dsos__find_build_id_cb_args args = {
+ .bid = bid,
+ .res = NULL,
+ };
+
+ dsos__for_each_dso(dsos, dsos__find_build_id_cb, &args);
+ return args.res;
+}
+
static void dso__set_basename(struct dso *dso)
{
bool allocated = false;
diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h
index a26774950866..1b9d71c5857e 100644
--- a/tools/perf/util/dsos.h
+++ b/tools/perf/util/dsos.h
@@ -8,6 +8,7 @@
#include <linux/rbtree.h>
#include "rwsem.h"
+struct build_id;
struct dso;
struct dso_id;
struct kmod_path;
@@ -31,6 +32,7 @@ void dsos__exit(struct dsos *dsos);
int __dsos__add(struct dsos *dsos, struct dso *dso);
int dsos__add(struct dsos *dsos, struct dso *dso);
struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short);
+struct dso *dsos__find_by_build_id(struct dsos *dsos, const struct build_id *bid);
struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, const struct dso_id *id);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index cd13a0c3cb52..0483d0b25d19 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -702,7 +702,6 @@ struct map *thread__find_map(struct thread *thread, struct perf_sample *sample,
thread__zput(al->thread);
al->thread = thread__get(thread);
- al->addr = sample->ip;
al->cpumode = sample->cpumode;
al->filtered = 0;
@@ -735,15 +734,31 @@ struct map *thread__find_map(struct thread *thread, struct perf_sample *sample,
return NULL;
}
- al->map = maps__find(maps, al->addr);
- if (al->map != NULL) {
- /*
- * Kernel maps might be changed when loading symbols so loading
- * must be done prior to using kernel maps.
- */
- if (load_map)
- map__load(al->map);
- al->addr = map__map_ip(al->map, al->addr);
+
+ if (sample->bid.bid && sample->bid.bid->size > 0) {
+ struct build_id bid;
+
+ build_id__init(&bid, sample->bid.bid->data, sample->bid.bid->size);
+ al->addr = sample->bid.offset;
+ al->map = maps__find_by_build_id(maps, &bid);
+ if (al->map != NULL) {
+ if (load_map)
+ map__load(al->map);
+ /* al->addr is already a file offset */
+ }
+ } else {
+ /* When bid.bid->size == 0, bid.ip holds the fallback virtual address. */
+ al->addr = sample->bid.bid ? sample->bid.ip : sample->ip;
+ al->map = maps__find(maps, al->addr);
+ if (al->map != NULL) {
+ /*
+ * Kernel maps might be changed when loading symbols so loading
+ * must be done prior to using kernel maps.
+ */
+ if (load_map)
+ map__load(al->map);
+ al->addr = map__map_ip(al->map, al->addr);
+ }
}
return al->map;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9c5e7510f0c0..08e9e6567bed 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -3423,6 +3423,21 @@ static int __set_offcpu_sample(struct perf_sample *data)
return -EFAULT;
}
+/*
+ * Before __evsel__parse_sample() is called on a cross-endian perf.data file,
+ * perf_event__all64_swap() has already byte-swapped the entire PERF_RECORD_SAMPLE
+ * payload in 64-bit chunks. That leaves 64-bit fields (like offset, ip, cookie)
+ * in host endianness, but scrambles the 24-byte struct perf_build_id (which
+ * contains a 16-bit reserved field, a 1-byte size, and a 20-byte byte array).
+ * Undo the 64-bit chunk swap on struct perf_build_id and byte-swap its 16-bit
+ * field.
+ */
+static void perf_build_id__undo_bswap_64(struct perf_build_id *bid)
+{
+ mem_bswap_64(bid, sizeof(*bid));
+ bid->__reserved_2 = bswap_16(bid->__reserved_2);
+}
+
int __evsel__parse_sample(struct evsel *evsel, union perf_event *event,
struct perf_sample *data, bool needs_swap)
{
@@ -3450,11 +3465,23 @@ int __evsel__parse_sample(struct evsel *evsel, union perf_event *event,
data->vcpu = -1;
if (event->header.type == PERF_RECORD_CALLCHAIN_DEFERRED) {
- const u64 max_callchain_nr = UINT64_MAX / sizeof(u64);
+ if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
+ const size_t entry_sz = sizeof(struct perf_sample_build_id_offset);
+ const u64 max_nr = UINT64_MAX / entry_sz;
+ u64 nr = event->callchain_deferred.nr;
- data->callchain = (struct ip_callchain *)&event->callchain_deferred.nr;
- if (data->callchain->nr > max_callchain_nr)
- goto out_efault;
+ if (nr > max_nr)
+ goto out_efault;
+ OVERFLOW_CHECK(event->callchain_deferred.bids, nr * entry_sz, max_size);
+ data->callchain_bids = event->callchain_deferred.bids;
+ data->callchain_bids_nr = nr;
+ } else {
+ const u64 max_callchain_nr = UINT64_MAX / sizeof(u64);
+
+ data->callchain = (struct ip_callchain *)&event->callchain_deferred.nr;
+ if (data->callchain->nr > max_callchain_nr)
+ goto out_efault;
+ }
data->deferred_cookie = event->callchain_deferred.cookie;
@@ -3885,6 +3912,85 @@ int __evsel__parse_sample(struct evsel *evsel, union perf_event *event,
array = (void *)array + sz;
}
+ if (type & PERF_SAMPLE_BUILD_ID_OFFSET) {
+ const struct perf_sample_build_id_offset *entry =
+ (const struct perf_sample_build_id_offset *)array;
+
+ OVERFLOW_CHECK(array, sizeof(*entry), max_size);
+ if (evsel->core.attr.defer_callchain && entry->zero == 0 &&
+ entry->context == PERF_CONTEXT_USER_DEFERRED) {
+ data->deferred_bid = true;
+ data->deferred_callchain = true;
+ data->deferred_cookie = entry->cookie;
+ data->bid.bid = (struct perf_build_id *)&entry->bid;
+ data->bid.offset = entry->ip;
+ } else {
+ if (swapped) {
+ struct perf_build_id *bid =
+ (void *)data->bid.deferred_storage;
+
+ /*
+ * perf_event__all64_swap() already swapped the
+ * sample in 64-bit chunks, so entry->offset is
+ * already in host endianness; undo the 64-bit
+ * swap on the build ID bytes.
+ */
+ memcpy(bid, &entry->bid, sizeof(*bid));
+ perf_build_id__undo_bswap_64(bid);
+ data->bid.bid = bid;
+ } else {
+ data->bid.bid = (struct perf_build_id *)&entry->bid;
+ }
+ data->bid.offset = entry->offset;
+ }
+ if (!(type & PERF_SAMPLE_IP))
+ data->ip = data->bid.offset;
+ array += sizeof(*entry) / sizeof(u64);
+ } else {
+ data->bid.bid = NULL;
+ data->bid.offset = 0;
+ }
+
+ if (type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET) {
+ const size_t entry_sz = sizeof(struct perf_sample_build_id_offset);
+ const u64 max_callchain_nr = UINT64_MAX / entry_sz;
+
+ OVERFLOW_CHECK_u64(array);
+ sz = *array++;
+ if (sz > max_callchain_nr)
+ goto out_efault;
+
+ OVERFLOW_CHECK(array, sz * entry_sz, max_size);
+ if (evsel->core.attr.defer_callchain && sz >= 2 &&
+ array[(sz - 2) * 4 + 3] == PERF_CONTEXT_USER_DEFERRED) {
+ data->deferred_cookie = array[(sz - 1) * 4 + 3];
+ data->deferred_callchain = true;
+ }
+ if (swapped && sz > 0) {
+ struct perf_sample_build_id_offset *bids = calloc(sz, entry_sz);
+
+ if (!bids)
+ goto out_efault;
+ /*
+ * perf_event__all64_swap() already swapped each 64-bit
+ * word (including bids[i].offset); undo the 64-bit swap
+ * on each build ID.
+ */
+ memcpy(bids, array, sz * entry_sz);
+ for (u64 i = 0; i < sz; i++)
+ perf_build_id__undo_bswap_64(&bids[i].bid);
+ data->callchain_bids = bids;
+ data->merged_callchain_bids = true;
+ } else {
+ data->callchain_bids = (struct perf_sample_build_id_offset *)array;
+ }
+ data->callchain_bids_nr = sz;
+ array += sz * entry_sz / sizeof(u64);
+ } else {
+ data->callchain_bids = NULL;
+ data->callchain_bids_nr = 0;
+ }
+
if (evsel__is_offcpu_event(evsel)) {
if (__set_offcpu_sample(data))
goto out_efault;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 174f3414fd3c..d4aa0191a1fd 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -569,7 +569,8 @@ static inline bool evsel__has_callchain(const struct evsel *evsel)
* For reporting purposes, an evsel sample can have a recorded callchain
* or a callchain synthesized from AUX area data.
*/
- return evsel->core.attr.sample_type & PERF_SAMPLE_CALLCHAIN ||
+ return evsel->core.attr.sample_type & (PERF_SAMPLE_CALLCHAIN |
+ PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET) ||
evsel->synth_sample_type & PERF_SAMPLE_CALLCHAIN;
}
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index 0f7a25500a44..e91411a1ac18 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -131,7 +131,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
if (cursor == NULL)
return fprintf(fp, "<not enough memory for the callchain cursor>%s", print_oneline ? "" : "\n");
- if (sample->callchain) {
+ if (sample->callchain || sample->callchain_bids) {
callchain_cursor_commit(cursor);
while (1) {
@@ -232,8 +232,11 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
} else {
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
- if (print_ip)
- printed += fprintf(fp, "%16" PRIx64, sample->ip);
+ if (print_ip) {
+ u64 ip = sample->bid.bid ? sample->bid.offset : sample->ip;
+
+ printed += fprintf(fp, "%16" PRIx64, ip);
+ }
if (print_sym) {
printed += fprintf(fp, " ");
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 1a13253d0c7f..99dc47e95938 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -2221,7 +2221,9 @@ static int add_callchain_ip(struct thread *thread,
struct branch_flags *flags,
struct iterations *iter,
u64 branch_from,
- bool symbols)
+ bool symbols,
+ struct perf_build_id *bid,
+ u64 offset)
{
static __thread struct perf_sample sample;
struct map_symbol ms = {};
@@ -2235,6 +2237,8 @@ static int add_callchain_ip(struct thread *thread,
al.sym = NULL;
al.srcline = NULL;
sample.ip = ip;
+ sample.bid.bid = bid;
+ sample.bid.offset = offset;
if (!cpumode) {
thread__find_cpumode_addr_location(thread, &sample, symbols, &al);
} else {
@@ -2295,6 +2299,9 @@ static int add_callchain_ip(struct thread *thread,
ms.map = map__get(al.map);
ms.sym = al.sym;
+ if (bid && bid->size > 0 && al.map)
+ ip = map__unmap_ip(al.map, al.addr);
+
if (append_inlines(cursor, &ms, ip, branch, flags, nr_loop_iter,
iter_cycles, branch_from) == 0)
goto out;
@@ -2410,10 +2417,17 @@ static int lbr_callchain_add_kernel_ip(struct thread *thread,
if (callee) {
for (i = 0; i < end + 1; i++) {
+ struct perf_build_id *bid = NULL;
+ u64 offset = 0;
+
+ if (sample->callchain_bids && i < (int)sample->callchain_bids_nr) {
+ bid = &sample->callchain_bids[i].bid;
+ offset = sample->callchain_bids[i].offset;
+ }
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, chain->ips[i],
false, NULL, NULL, branch_from,
- symbols);
+ symbols, bid, offset);
if (err)
return err;
}
@@ -2421,10 +2435,17 @@ static int lbr_callchain_add_kernel_ip(struct thread *thread,
}
for (i = end; i >= 0; i--) {
+ struct perf_build_id *bid = NULL;
+ u64 offset = 0;
+
+ if (sample->callchain_bids && i < (int)sample->callchain_bids_nr) {
+ bid = &sample->callchain_bids[i].bid;
+ offset = sample->callchain_bids[i].offset;
+ }
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, chain->ips[i],
false, NULL, NULL, branch_from,
- symbols);
+ symbols, bid, offset);
if (err)
return err;
}
@@ -2507,7 +2528,7 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, ip,
true, flags, NULL,
- *branch_from, symbols);
+ *branch_from, symbols, /*bid=*/NULL, /*offset=*/0);
if (err)
return err;
@@ -2532,7 +2553,7 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, ip,
true, flags, NULL,
- *branch_from, symbols);
+ *branch_from, symbols, /*bid=*/NULL, /*offset=*/0);
if (err)
return err;
save_lbr_cursor_node(thread, cursor, i);
@@ -2547,7 +2568,7 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, ip,
true, flags, NULL,
- *branch_from, symbols);
+ *branch_from, symbols, /*bid=*/NULL, /*offset=*/0);
if (err)
return err;
save_lbr_cursor_node(thread, cursor, i);
@@ -2567,7 +2588,7 @@ static int lbr_callchain_add_lbr_ip(struct thread *thread,
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, ip,
true, flags, NULL,
- *branch_from, symbols);
+ *branch_from, symbols, /*bid=*/NULL, /*offset=*/0);
if (err)
return err;
}
@@ -2740,12 +2761,16 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
{
bool callee = (callchain_param.order == ORDER_CALLEE);
struct ip_callchain *chain = sample->callchain;
- int chain_nr = min(max_stack, (int)chain->nr), i;
+ int chain_nr, i;
struct lbr_stitch *lbr_stitch;
bool stitched_lbr = false;
u64 branch_from = 0;
int err;
+ if (!chain)
+ return 0;
+
+ chain_nr = min(max_stack, (int)chain->nr);
for (i = 0; i < chain_nr; i++) {
if (chain->ips[i] == PERF_CONTEXT_USER)
break;
@@ -2831,7 +2856,8 @@ static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread,
if (ip >= PERF_CONTEXT_MAX) {
err = add_callchain_ip(thread, cursor, parent,
root_al, cpumode, ip,
- false, NULL, NULL, 0, symbols);
+ false, NULL, NULL, 0, symbols,
+ /*bid=*/NULL, /*offset=*/0);
break;
}
}
@@ -2859,6 +2885,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
struct branch_stack *branch = sample->branch_stack;
struct branch_entry *entries = perf_sample__branch_entries(sample);
struct ip_callchain *chain = sample->callchain;
+ struct ip_callchain *alloc_chain = NULL;
int chain_nr = 0;
u8 cpumode = PERF_RECORD_MISC_USER;
int i, j, err, nr_entries, usr_idx;
@@ -2866,6 +2893,17 @@ static int thread__resolve_callchain_sample(struct thread *thread,
int first_call = 0;
u64 leaf_frame_caller;
+ if (!chain && sample->callchain_bids_nr > 0) {
+ alloc_chain = malloc(sizeof(*chain) + sample->callchain_bids_nr * sizeof(u64));
+ if (!alloc_chain)
+ return -ENOMEM;
+ alloc_chain->nr = sample->callchain_bids_nr;
+ for (i = 0; i < (int)sample->callchain_bids_nr; i++)
+ alloc_chain->ips[i] = sample->callchain_bids[i].offset;
+ chain = alloc_chain;
+ sample->callchain = alloc_chain;
+ }
+
if (chain)
chain_nr = chain->nr;
@@ -2876,8 +2914,10 @@ static int thread__resolve_callchain_sample(struct thread *thread,
root_al, max_stack,
!env ? 0 : env->max_branches,
symbols);
- if (err)
- return (err < 0) ? err : 0;
+ if (err) {
+ err = (err < 0) ? err : 0;
+ goto out;
+ }
}
/*
@@ -2940,22 +2980,26 @@ static int thread__resolve_callchain_sample(struct thread *thread,
root_al,
NULL, be[i].to,
true, &be[i].flags,
- NULL, be[i].from, symbols);
+ NULL, be[i].from, symbols,
+ /*bid=*/NULL, /*offset=*/0);
if (!err) {
err = add_callchain_ip(thread, cursor, parent, root_al,
NULL, be[i].from,
true, &be[i].flags,
- &iter[i], 0, symbols);
+ &iter[i], 0, symbols,
+ /*bid=*/NULL, /*offset=*/0);
}
if (err == -EINVAL)
break;
if (err)
- return err;
+ goto out;
}
- if (chain_nr == 0)
- return 0;
+ if (chain_nr == 0) {
+ err = 0;
+ goto out;
+ }
chain_nr -= nr;
}
@@ -2964,12 +3008,16 @@ static int thread__resolve_callchain_sample(struct thread *thread,
if (chain && callchain_param.order != ORDER_CALLEE) {
err = find_prev_cpumode(chain, thread, cursor, parent, root_al,
&cpumode, chain->nr - first_call, symbols);
- if (err)
- return (err < 0) ? err : 0;
+ if (err) {
+ err = (err < 0) ? err : 0;
+ goto out;
+ }
}
for (i = first_call, nr_entries = 0;
i < chain_nr && nr_entries < max_stack; i++) {
u64 ip;
+ struct perf_build_id *bid = NULL;
+ u64 offset = 0;
if (callchain_param.order == ORDER_CALLEE)
j = i;
@@ -2981,13 +3029,19 @@ static int thread__resolve_callchain_sample(struct thread *thread,
continue;
#endif
ip = chain->ips[j];
+ if (sample->callchain_bids && j < (int)sample->callchain_bids_nr) {
+ bid = &sample->callchain_bids[j].bid;
+ offset = sample->callchain_bids[j].offset;
+ }
if (ip < PERF_CONTEXT_MAX)
++nr_entries;
else if (callchain_param.order != ORDER_CALLEE) {
err = find_prev_cpumode(chain, thread, cursor, parent,
root_al, &cpumode, j, symbols);
- if (err)
- return (err < 0) ? err : 0;
+ if (err) {
+ err = (err < 0) ? err : 0;
+ goto out;
+ }
continue;
}
@@ -3013,21 +3067,32 @@ static int thread__resolve_callchain_sample(struct thread *thread,
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, leaf_frame_caller,
- false, NULL, NULL, 0, symbols);
- if (err)
- return (err < 0) ? err : 0;
+ false, NULL, NULL, 0, symbols,
+ /*bid=*/NULL, /*offset=*/0);
+ if (err) {
+ err = (err < 0) ? err : 0;
+ goto out;
+ }
}
}
err = add_callchain_ip(thread, cursor, parent,
root_al, &cpumode, ip,
- false, NULL, NULL, 0, symbols);
+ false, NULL, NULL, 0, symbols, bid, offset);
- if (err)
- return (err < 0) ? err : 0;
+ if (err) {
+ err = (err < 0) ? err : 0;
+ goto out;
+ }
}
- return 0;
+ err = 0;
+out:
+ if (alloc_chain) {
+ sample->callchain = NULL;
+ free(alloc_chain);
+ }
+ return err;
}
static int unwind_entry(struct unwind_entry *entry, void *arg)
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index f808df2fe77b..1e83332ea00a 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -2,8 +2,11 @@
#include <errno.h>
#include <stdlib.h>
#include <linux/zalloc.h>
+#include "build-id.h"
#include "debug.h"
#include "dso.h"
+#include "dsos.h"
+#include "machine.h"
#include "map.h"
#include "maps.h"
#include "rwsem.h"
@@ -1251,6 +1254,62 @@ static int map__strcmp_name(const void *name, const void *b)
return strcmp(name, dso__short_name(dso));
}
+struct map *maps__find_by_build_id(struct maps *maps, struct build_id *bid)
+{
+ struct map *result = NULL;
+
+ down_read(maps__lock(maps));
+ for (unsigned int i = 0, n = maps__nr_maps(maps); i < n; i++) {
+ struct map *map = maps__maps_by_address(maps)[i];
+
+ if (dso__build_id_equal(map__dso(map), bid)) {
+ result = map__get(map);
+ break;
+ }
+ }
+ up_read(maps__lock(maps));
+
+ if (!result && maps__machine(maps)) {
+ struct machine *machine = maps__machine(maps);
+ struct dso *dso = dsos__find_by_build_id(&machine->dsos, bid);
+
+ if (!dso) {
+ char sbuild_id[SBUILD_ID_SIZE];
+ char *origname;
+
+ build_id__snprintf(bid, sbuild_id, sizeof(sbuild_id));
+ origname = build_id_cache__origname(sbuild_id);
+ if (origname) {
+ struct dso_id id = { .build_id = *bid };
+
+ dso = dsos__findnew_id(&machine->dsos, origname, &id);
+ free(origname);
+ }
+ }
+ if (dso) {
+ down_write(maps__lock(maps));
+ for (unsigned int i = 0, n = maps__nr_maps(maps); i < n; i++) {
+ struct map *map = maps__maps_by_address(maps)[i];
+
+ if (dso__build_id_equal(map__dso(map), bid)) {
+ result = map__get(map);
+ break;
+ }
+ }
+ if (!result) {
+ result = map__new2(0, dso);
+ if (result && __maps__insert(maps, result)) {
+ map__put(result);
+ result = NULL;
+ }
+ }
+ up_write(maps__lock(maps));
+ dso__put(dso);
+ }
+ }
+ return result;
+}
+
struct map *maps__find_by_name(struct maps *maps, const char *name)
{
struct map *result = NULL;
diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h
index 4ec9b7453a3b..6f1791457068 100644
--- a/tools/perf/util/maps.h
+++ b/tools/perf/util/maps.h
@@ -11,6 +11,7 @@ struct ref_reloc_sym;
struct machine;
struct map;
struct maps;
+struct build_id;
#define KMAP_NAME_LEN 256
@@ -76,6 +77,7 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams);
int maps__fixup_overlap_and_insert(struct maps *maps, struct map *new);
struct map *maps__find_by_name(struct maps *maps, const char *name);
+struct map *maps__find_by_build_id(struct maps *maps, struct build_id *bid);
struct map *maps__find_next_entry(struct maps *maps, struct map *map);
diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c
index 2e8be9a357dc..dd653da923c4 100644
--- a/tools/perf/util/perf_event_attr_fprintf.c
+++ b/tools/perf/util/perf_event_attr_fprintf.c
@@ -40,7 +40,8 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
bit_name(WEIGHT), bit_name(PHYS_ADDR), bit_name(AUX),
bit_name(CGROUP), bit_name(DATA_PAGE_SIZE), bit_name(CODE_PAGE_SIZE),
- bit_name(WEIGHT_STRUCT),
+ bit_name(WEIGHT_STRUCT), bit_name(BUILD_ID_OFFSET),
+ bit_name(CALLCHAIN_BUILD_ID_OFFSET),
{ .name = NULL, }
};
#undef bit_name
diff --git a/tools/perf/util/sample.c b/tools/perf/util/sample.c
index bccc19e2aaf2..1513eda8765b 100644
--- a/tools/perf/util/sample.c
+++ b/tools/perf/util/sample.c
@@ -24,11 +24,15 @@ void perf_sample__init(struct perf_sample *sample, bool all)
if (all) {
memset(sample, 0, sizeof(*sample));
} else {
+ sample->ip = 0;
sample->evsel = NULL;
sample->user_regs = NULL;
sample->intr_regs = NULL;
sample->merged_callchain = false;
sample->callchain = NULL;
+ sample->merged_callchain_bids = false;
+ sample->callchain_bids = NULL;
+ sample->callchain_bids_nr = 0;
}
}
@@ -42,6 +46,11 @@ void perf_sample__exit(struct perf_sample *sample)
zfree(&sample->callchain);
sample->merged_callchain = false;
}
+ if (sample->merged_callchain_bids) {
+ zfree(&sample->callchain_bids);
+ sample->callchain_bids_nr = 0;
+ sample->merged_callchain_bids = false;
+ }
}
struct regs_dump *perf_sample__user_regs(struct perf_sample *sample)
diff --git a/tools/perf/util/sample.h b/tools/perf/util/sample.h
index cb4b16654876..adf2ff1bd13b 100644
--- a/tools/perf/util/sample.h
+++ b/tools/perf/util/sample.h
@@ -7,7 +7,9 @@
struct evsel;
struct machine;
+struct perf_sample_build_id_offset;
struct thread;
+struct perf_build_id;
/* number of register is bound by the number of bits in regs_dump::mask (64) */
#define PERF_SAMPLE_REGS_CACHE_SIZE (8 * sizeof(u64))
@@ -163,6 +165,22 @@ struct perf_sample {
u64 code_page_size;
/** @cgroup: The sample event PERF_SAMPLE_CGROUP value. */
u64 cgroup;
+ /** @bid: The sample event PERF_SAMPLE_BUILD_ID_OFFSET value. */
+ struct {
+ struct perf_build_id *bid;
+ union {
+ u64 offset;
+ u64 ip;
+ };
+ u64 deferred_storage[3];
+ } bid;
+ /**
+ * @callchain_bids: Build IDs for the callchain when
+ * PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET is set.
+ */
+ struct perf_sample_build_id_offset *callchain_bids;
+ /** @callchain_bids_nr: Number of entries in callchain_bids. */
+ u32 callchain_bids_nr;
/** @file_offset: Byte offset of this event in the perf.data file. */
u64 file_offset;
/** @flags: Extra flag data from auxiliary events like intel-pt. */
@@ -205,11 +223,21 @@ struct perf_sample {
* user callchain marker was encountered.
*/
bool deferred_callchain;
+ /**
+ * @deferred_bid: When processing PERF_SAMPLE_BUILD_ID_OFFSET a deferred
+ * user marker was encountered.
+ */
+ bool deferred_bid;
/**
* @merged_callchain: A synthesized merged callchain that is allocated
* and needs freeing.
*/
bool merged_callchain;
+ /**
+ * @merged_callchain_bids: A synthesized merged callchain_bids that is
+ * allocated and needs freeing.
+ */
+ bool merged_callchain_bids;
/**
* @deferred_cookie: Identifier of the deferred callchain in the later
* PERF_RECORD_CALLCHAIN_DEFERRED event.
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5e113070b3c6..d952e186dcf6 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -21,6 +21,7 @@
#include "map_symbol.h"
#include "branch.h"
+#include "build-id.h"
#include "debug.h"
#include "dwarf-regs.h"
#include "env.h"
@@ -1326,15 +1327,17 @@ static void callchain__lbr_callstack_printf(struct perf_sample *sample)
struct ip_callchain *callchain = sample->callchain;
struct branch_stack *lbr_stack = sample->branch_stack;
struct branch_entry *entries = perf_sample__branch_entries(sample);
- u64 kernel_callchain_nr = callchain->nr;
+ u64 kernel_callchain_nr = callchain ? callchain->nr : sample->callchain_bids_nr;
unsigned int i;
for (i = 0; i < kernel_callchain_nr; i++) {
- if (callchain->ips[i] == PERF_CONTEXT_USER)
+ u64 ip = callchain ? callchain->ips[i] : sample->callchain_bids[i].offset;
+
+ if (ip == PERF_CONTEXT_USER)
break;
}
- if ((i != kernel_callchain_nr) && lbr_stack->nr) {
+ if ((i != kernel_callchain_nr) && lbr_stack && lbr_stack->nr) {
u64 total_nr;
/*
* LBR callstack can only get user call chain,
@@ -1357,9 +1360,11 @@ static void callchain__lbr_callstack_printf(struct perf_sample *sample)
printf("... LBR call chain: nr:%" PRIu64 "\n", total_nr);
- for (i = 0; i < kernel_callchain_nr; i++)
- printf("..... %2d: %016" PRIx64 "\n",
- i, callchain->ips[i]);
+ for (i = 0; i < kernel_callchain_nr; i++) {
+ u64 ip = callchain ? callchain->ips[i] : sample->callchain_bids[i].offset;
+
+ printf("..... %2d: %016" PRIx64 "\n", i, ip);
+ }
printf("..... %2d: %016" PRIx64 "\n",
(int)(kernel_callchain_nr), entries[0].to);
@@ -1400,12 +1405,24 @@ static void callchain__printf(struct evsel *evsel,
if (evsel__has_branch_callstack(evsel))
callchain__lbr_callstack_printf(sample);
- printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr);
+ if (callchain) {
+ printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr);
- for (i = 0; i < callchain->nr; i++)
- printf("..... %2d: %016" PRIx64 "%s\n",
- i, callchain->ips[i],
- callchain_context_str(callchain->ips[i]));
+ for (i = 0; i < callchain->nr; i++)
+ printf("..... %2d: %016" PRIx64 "%s\n",
+ i, callchain->ips[i],
+ callchain_context_str(callchain->ips[i]));
+ } else if (sample->callchain_bids) {
+ printf("... FP chain (build ID + offset): nr:%u\n",
+ sample->callchain_bids_nr);
+
+ for (i = 0; i < sample->callchain_bids_nr; i++) {
+ u64 offset = sample->callchain_bids[i].offset;
+
+ printf("..... %2d: %016" PRIx64 "%s\n",
+ i, offset, callchain_context_str(offset));
+ }
+ }
if (sample->deferred_callchain)
printf("...... (deferred)\n");
@@ -1730,6 +1747,17 @@ static void dump_sample(struct machine *machine, union perf_event *event,
event->header.misc, sample->pid, sample->tid, sample->ip,
sample->period, sample->addr);
+ if (sample_type & PERF_SAMPLE_BUILD_ID_OFFSET) {
+ struct build_id bid;
+ char sbuild_id[SBUILD_ID_SIZE] = "";
+
+ if (sample->bid.bid) {
+ build_id__init(&bid, sample->bid.bid->data, sample->bid.bid->size);
+ build_id__snprintf(&bid, sbuild_id, sizeof(sbuild_id));
+ }
+ printf("... build_id: %s offset: %#" PRIx64 "\n", sbuild_id, sample->bid.offset);
+ }
+
if (evsel__has_callchain(evsel))
callchain__printf(evsel, sample);
@@ -1783,7 +1811,7 @@ static void dump_deferred_callchain(union perf_event *event, struct perf_sample
printf("(IP, 0x%x): %d/%d: %#" PRIx64 "\n",
event->header.misc, sample->pid, sample->tid, sample->deferred_cookie);
- if (evsel__has_callchain(evsel))
+ if (evsel__has_callchain(evsel) || sample->callchain_bids)
callchain__printf(evsel, sample);
}
diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
index 4d552150bc04..e1c04f4ee76e 100644
--- a/tools/perf/util/synthetic-events.c
+++ b/tools/perf/util/synthetic-events.c
@@ -1711,6 +1711,13 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
result += sample->aux_sample.size;
}
+ if (type & PERF_SAMPLE_BUILD_ID_OFFSET)
+ result += sizeof(struct perf_build_id) + sizeof(u64);
+
+ if (type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET)
+ result += sizeof(u64) + sample->callchain_bids_nr *
+ (sizeof(struct perf_build_id) + sizeof(u64));
+
return result;
}
@@ -1967,6 +1974,27 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
array = (void *)array + sz;
}
+ if (type & PERF_SAMPLE_BUILD_ID_OFFSET) {
+ if (sample->bid.bid) {
+ memcpy(array, sample->bid.bid, sizeof(struct perf_build_id));
+ array += sizeof(struct perf_build_id) / sizeof(u64);
+ *array++ = sample->bid.offset;
+ } else {
+ memset(array, 0, sizeof(struct perf_build_id));
+ array += sizeof(struct perf_build_id) / sizeof(u64);
+ *array++ = sample->ip;
+ }
+ }
+
+ if (type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET) {
+ *array++ = sample->callchain_bids_nr;
+ if (sample->callchain_bids && sample->callchain_bids_nr) {
+ sz = sample->callchain_bids_nr * sizeof(*sample->callchain_bids);
+ memcpy(array, sample->callchain_bids, sz);
+ array += sz / sizeof(u64);
+ }
+ }
+
return 0;
}
--
2.56.0.rc1.315.gc6ed9934b7-goog
next prev parent reply other threads:[~2026-10-02 17:39 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-24 6:19 [PATCH v1 0/5] perf: Default use of build IDs and improvements Ian Rogers
2025-04-24 6:19 ` [PATCH v1 1/5] perf build-id: Reduce size of "size" variable Ian Rogers
2025-04-24 6:19 ` [PATCH v1 2/5] perf build-id: Truncate to avoid overflowing the build_id data Ian Rogers
2025-04-24 6:19 ` [PATCH v1 3/5] perf build-id: Change sprintf functions to snprintf Ian Rogers
2025-04-24 6:19 ` [PATCH v1 4/5] perf dso: Move build_id to dso_id Ian Rogers
2025-04-24 6:19 ` [PATCH v1 5/5] perf record: Make --buildid-mmap the default Ian Rogers
2025-04-24 7:20 ` Ian Rogers
2025-04-25 14:45 ` Arnaldo Carvalho de Melo
2025-04-25 14:59 ` Arnaldo Carvalho de Melo
2025-04-25 16:03 ` Ian Rogers
2026-10-02 17:38 ` [PATCH v2 0/8] perf/core, perf/tools: Add PERF_SAMPLE_BUILD_ID_OFFSET support Ian Rogers
2026-10-02 17:38 ` [PATCH v2 1/8] perf event: Factor build_id out into its own top-level struct Ian Rogers
2026-10-02 17:38 ` [PATCH v2 2/8] perf/core: Add BUILD_ID_OFFSET to UAPI Ian Rogers
2026-10-02 17:38 ` [PATCH v2 3/8] perf/core: Implement BUILD_ID_OFFSET sample type Ian Rogers
2026-10-02 17:38 ` [PATCH v2 4/8] perf: Refactor thread map and symbol APIs to take perf_sample Ian Rogers
2026-10-02 17:38 ` Ian Rogers [this message]
2026-10-02 17:38 ` [PATCH v2 6/8] perf inject: Extend perf inject to support bid_offset conversion Ian Rogers
2026-10-02 17:38 ` [PATCH v2 7/8] perf record: Add --buildid-offset option Ian Rogers
2026-10-02 17:38 ` [PATCH v2 8/8] perf tests: Add build_id_offset test coverage Ian Rogers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261002173848.3228217-6-irogers@google.com \
--to=irogers@google.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=ak@linux.intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=atrajeev@linux.ibm.com \
--cc=dvyukov@google.com \
--cc=fzczx123@gmail.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=kjain@linux.ibm.com \
--cc=krzysztof.m.lopatowski@gmail.com \
--cc=leo.yan@arm.com \
--cc=lihuafei1@huawei.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=linux@treblig.org \
--cc=m.liska@foxlink.cz \
--cc=mark.rutland@arm.com \
--cc=martin.liska@hey.com \
--cc=mingo@redhat.com \
--cc=mpetlan@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=quic_zhonhan@quicinc.com \
--cc=scclevenger@os.amperecomputing.com \
--cc=sesse@google.com \
--cc=stephen.s.brennan@oracle.com \
--cc=thomas.falcon@intel.com \
--cc=yangyicong@hisilicon.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®