From: Ian Rogers <irogers@google.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>,
Tanushree Shah <tshah@linux.ibm.com>,
Michael Liang <mliang@purestorage.com>,
Alessio Podda <aleph.pi.gh@gmail.com>,
Shimin Guo <shimin.guo@skydio.com>,
linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v1 2/2] perf libdw: Optimize fallback logic for missing DWARF
Date: Sun, 23 Aug 2026 23:28:41 -0700 [thread overview]
Message-ID: <20260824062841.1529489-3-irogers@google.com> (raw)
In-Reply-To: <20260824062841.1529489-1-irogers@google.com>
When libdw encounters a DWARF definition it cannot accurately
un-inline or an address block natively missing structural line maps,
dwfl_module_getsrc() falls back immediately with 0. This causes perf's
addr2line_style loop to fall back to launching the cmd__addr2line()
sub-process wrapper. In environments generating massive numbers of
unmapped traces, this forces thousands of redundant `addr2line -e`
fork/execs in a polling loop.
This patch intercepts failure scenarios:
1. Returns -1 when dwfl_module_getsrc() returns NULL (meaning the DWARF
is parsed but the line mapping is natively missing).
2. Evaluates `ret < 0` in addr2line() to dynamically bypass the subprocess
fallback and return 0. This precisely acts as a failure condition,
incrementing the dso->a2l_fails counter and accurately triggering the
A2L_FAIL_LIMIT throttling without shelling out.
3. Incorporates exact error string checking for "no DWARF" to safely
abort alternative fallbacks directly within both libdw resolving and
the unwinder logic (unwind-libdw).
This preserves fallbacks if unwinder or DWARF parsing genuinely
aborts, but avoids falling back when mappings are absent.
Assisted-by: Antigravity:gemini-3.6-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/libdw.c | 11 +++++++++--
tools/perf/util/srcline.c | 2 ++
tools/perf/util/unwind-libdw.c | 15 ++++++++++++---
3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/libdw.c b/tools/perf/util/libdw.c
index f53caee980b0..7c681b03c654 100644
--- a/tools/perf/util/libdw.c
+++ b/tools/perf/util/libdw.c
@@ -186,8 +186,15 @@ int libdw__addr2line(const char *dso_name, u64 addr, char **file, unsigned int *
* between the regular ELF addr2line addresses and those to use with
* libdw.
*/
- if (!dwfl_module_getdwarf(mod, &bias))
- return 0;
+ if (!dwfl_module_getdwarf(mod, &bias)) {
+ const char *err = dwfl_errmsg(-1);
+
+ /*
+ * Abort fallbacks specifically when DWARF is completely missing,
+ * but allow alternative backends to try if parsing failed.
+ */
+ return (err && strstr(err, "no DWARF")) ? -1 : 0;
+ }
/* Find source line information for the address. */
dwline = dwfl_module_getsrc(mod, addr + bias);
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 8e954f0c860a..8283a741c018 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -176,6 +176,8 @@ static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *
}
if (ret > 0)
return ret;
+ if (ret < 0)
+ return 0;
}
return 0;
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 63a5c2253174..69d4585c870c 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -441,8 +441,17 @@ int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
}
out:
- if (err)
- pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
+ if (err) {
+ const char *msg = dwfl_errmsg(-1);
+
+ pr_debug("unwind: failed with '%s'\n", msg);
+ /*
+ * Abort fallbacks specifically when unwinding information is completely
+ * missing, but allow fallback unwinders to try if parsing simply failed.
+ */
+ if (msg && strstr(msg, "no DWARF"))
+ err = -EINVAL;
+ }
for (i = 0; i < ui->idx; i++)
map_symbol__exit(&ui->entries[i].ms);
@@ -460,6 +469,6 @@ int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
* < 0 : fatal error (e.g. -ENOMEM). Aborts unwinding entirely.
*/
if (err)
- return (err == -ENOMEM) ? -ENOMEM : (entries > 0 ? 1 : 0);
+ return (err == -ENOMEM || err == -EINVAL) ? err : (entries > 0 ? 1 : 0);
return entries;
}
--
2.55.0.766.g2966f0265a-goog
prev parent reply other threads:[~2026-08-24 6:28 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 6:28 [PATCH v1 0/2] perf libdw: Improve split-debug handling and error fallback Ian Rogers
2026-08-24 6:28 ` [PATCH v1 1/2] perf libdw: Pass dso_name explicitly to properly anchor split-debug builds Ian Rogers
2026-08-24 6:28 ` Ian Rogers [this message]
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=20260824062841.1529489-3-irogers@google.com \
--to=irogers@google.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=aleph.pi.gh@gmail.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=mliang@purestorage.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=shimin.guo@skydio.com \
--cc=tshah@linux.ibm.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