From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Alan Maguire <alan.maguire@oracle.com>
Cc: Jiri Olsa <jolsa@kernel.org>,
Clark Williams <williams@redhat.com>,
dwarves@vger.kernel.org, bpf@vger.kernel.org,
Andrii Nakryiko <andrii@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Arnaldo Carvalho de Melo <acme@redhat.com>,
Eduard Zingerman <eddyz87@gmail.com>,
Aaron Merey <amerey@redhat.com>
Subject: [PATCH 16/31] dwarf_loader: Skip libdw__lock when elfutils is built thread-safe
Date: Wed, 29 Jul 2026 16:07:16 -0300 [thread overview]
Message-ID: <20260729190733.72876-17-acme@kernel.org> (raw)
In-Reply-To: <20260729190733.72876-1-acme@kernel.org>
From: Arnaldo Carvalho de Melo <acme@redhat.com>
pahole serializes dwarf_getlocation(), dwarf_decl_file(), and
__dwarf_getlocations() calls behind libdw__lock because libdw's
internal caches (tsearch trees) are not thread-safe by default.
This mutex was added in commits 1caed1c443d4 ("Add a lock around
dwarf_decl_file() and dwarf_decl_line() calls") and 65b7fd68ccbb
("Use libdw__lock for dwarf_getlocation(s)") to work around
concurrency bugs in libdw.
Since then, elfutils has fixed the underlying issues:
- 0.194: eu_tsearch with proper locking (ec21fbb47)
- 0.194: rwlock replaced with __atomic builtins (680eb3021)
- 0.195: additional last_abbrev_offset protection (8fa2cd1d3)
When elfutils is compiled with --enable-thread-safety it defines
_ELFUTILS_THREAD_SAFE in <elfutils/version.h>. Use this to skip
the pahole-side mutex entirely, eliminating the serialization
overhead.
Profiling shows pthread_rwlock_tryrdlock + unlock from libdw's
internal locking accounts for ~15.6% of serial encoding time.
That overhead also disappears when elfutils is built thread-safe
(rwlock replaced with lock-free atomics in 0.194).
Before (serial, elfutils without --enable-thread-safety):
15.6% in pthread_rwlock_{tryrdlock,unlock} (libdw internal)
Plus serialization from pahole's libdw__lock mutex
After (serial, elfutils with --enable-thread-safety):
Both overheads eliminated
Cc: Alan Maguire <alan.maguire@oracle.com>
Cc: Eduard Zingerman <eddyz87@gmail.com>
Cc: Aaron Merey <amerey@redhat.com>
Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
dwarf_loader.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/dwarf_loader.c b/dwarf_loader.c
index ce0bead0e76e1876..759883cad3fce693 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -57,7 +57,25 @@
#define EM_RISCV 243
#endif
+/*
+ * libdw internal caches (tsearch trees for locations, decl file/line, etc.)
+ * are not thread-safe unless elfutils was compiled with --enable-thread-safety.
+ * When that option is active, elfutils >= 0.194 uses eu_tsearch with proper
+ * locking and >= 0.194 also replaces the abbrev rwlock with __atomic builtins,
+ * eliminating the overhead that rwlock_tryrdlock imposed even in serial mode.
+ *
+ * _ELFUTILS_THREAD_SAFE is defined in <elfutils/version.h> when the library
+ * was built thread-safe. When present we skip our own mutex; when absent we
+ * serialize the racy calls ourselves.
+ */
+#ifdef _ELFUTILS_THREAD_SAFE
+static inline void libdw__lock_lock(void) { }
+static inline void libdw__lock_unlock(void) { }
+#else
static pthread_mutex_t libdw__lock = PTHREAD_MUTEX_INITIALIZER;
+static inline void libdw__lock_lock(void) { pthread_mutex_lock(&libdw__lock); }
+static inline void libdw__lock_unlock(void) { pthread_mutex_unlock(&libdw__lock); }
+#endif
static uint32_t hashtags__bits = 12;
static uint32_t max_hashtags__bits = 21;
@@ -453,11 +471,7 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen)
int ret = 1;
if (dwarf_attr(die, DW_AT_location, &attr) != NULL) {
- /* use libdw__lock as dwarf_getlocation(s) has concurrency
- * issues when libdw is not compiled with experimental
- * --enable-thread-safety
- */
- pthread_mutex_lock(&libdw__lock);
+ libdw__lock_lock();
if (dwarf_getlocation(&attr, expr, exprlen) == 0) {
/* DW_OP_addrx needs additional lookup for real addr. */
if (*exprlen != 0 && expr[0]->atom == DW_OP_addrx) {
@@ -471,7 +485,7 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen)
}
ret = 0;
}
- pthread_mutex_unlock(&libdw__lock);
+ libdw__lock_unlock();
}
return ret;
@@ -516,7 +530,7 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die)
tag->attributes = NULL;
if (cu->extra_dbg_info) {
- pthread_mutex_lock(&libdw__lock);
+ libdw__lock_lock();
int32_t decl_line;
const char *decl_file = dwarf_decl_file(die);
@@ -531,7 +545,7 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die)
dwarf_decl_line(die, &decl_line);
dtag->decl_line = decl_line;
- pthread_mutex_unlock(&libdw__lock);
+ libdw__lock_unlock();
}
INIT_LIST_HEAD(&tag->node);
@@ -1470,7 +1484,7 @@ static void parameter__decode_location(Dwarf_Attribute *attr, struct conf_load *
ptrdiff_t offset = 0;
int loc_num = -1;
- pthread_mutex_lock(&libdw__lock);
+ libdw__lock_lock();
while ((offset = __dwarf_getlocations(attr, offset, &base, &start, &end, &expr, &exprlen)) > 0) {
bool had_stack_value;
@@ -1515,7 +1529,7 @@ static void parameter__decode_location(Dwarf_Attribute *attr, struct conf_load *
break;
}
}
- pthread_mutex_unlock(&libdw__lock);
+ libdw__lock_unlock();
parameter__finish_piece_decode(parm, die, conf, cu);
}
--
2.55.0
next prev parent reply other threads:[~2026-07-29 19:08 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-29 19:07 [PATCHES 00/31] pahole: Bug fixes and small improvements Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 01/31] cmake: Update minimum required version from 3.5 to 3.10 Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 02/31] Fix -Wsign-compare warnings across the codebase Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 03/31] btf_encoder: Fix interior pointer free and missing NULL check Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 04/31] dwarves: Fix missing list head initialization in type__clone_members Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 05/31] pahole: Fix instance memory leak on early returns in prototype__stdio_fprintf_value Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 06/31] ctf_loader, libctf: Fix error path resource leaks Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 07/31] dwarves: Don't search for holes before member byte sizes are cached Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 08/31] dwarf_loader: Allocate type_dcu via dwarf_cu__new to fix dangling stack pointer Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 09/31] dwarf_loader: Fix annotation failure leaks in variable and typedef creation Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 10/31] btf_encoder: Use btf_encoder__tag_type() for all type ID computations Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 11/31] pahole: Fix --errno typo that decrements instead of negating Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 12/31] dwarves: Fix heap buffer overflow in languages__parse realloc Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 13/31] btf_encoder: Fix early cleanup crashes in btf_encoder__new/delete Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 14/31] btf_encoder, libctf: Add elf_strptr NULL checks and fix kfunc bounds Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 15/31] dwarf_loader: Fix --fixup_silly_bitfields condition check Arnaldo Carvalho de Melo
2026-07-29 19:07 ` Arnaldo Carvalho de Melo [this message]
2026-07-29 19:07 ` [PATCH 17/31] dwarf_loader: Fix data race in tag__init() decl_file string cache Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 18/31] pahole: Fix parse_btf_features("all") being a silent no-op Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 19/31] dwarves: Fix variable shadowing in __cus__find_struct_by_name() Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 20/31] dutil: Add exec_objcopy() shell-injection-safe helper Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 21/31] btf_encoder: Fall back to objcopy when llvm-objcopy is not available Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 22/31] dwarf_loader, btf_loader: Replace stale FIXME/XXX comments with explanations Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 23/31] pahole: Skip inline expansions during BTF encoding Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 24/31] pahole: Use fseek for seekable files in --prettify and --seek_bytes Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 25/31] pahole: Guard pipe_seek() against negative offsets Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 26/31] gobuffer: Remove 5 dead functions found via coverage analysis Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 27/31] dwarves: Remove 6 " Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 28/31] pfunct, dwarves_fprintf: Mark file-local functions as static Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 29/31] btf_encoder: Fix multi-dimensional array encoding Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 30/31] btf_loader: Fix multi-dimensional array loading Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 31/31] btfdiff: Remove --flat_arrays now that pahole encodes multi dim arrays in BTF Arnaldo Carvalho de Melo
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=20260729190733.72876-17-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=alan.maguire@oracle.com \
--cc=amerey@redhat.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=dwarves@vger.kernel.org \
--cc=eddyz87@gmail.com \
--cc=jolsa@kernel.org \
--cc=williams@redhat.com \
--cc=yonghong.song@linux.dev \
/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