[PATCH v13 12/21] perf dsos: Use read lock fast path in dsos__findnew_id()
From: Ian Rogers
Date: Fri Nov 13 2026 - 16:12:20 EST
In dsos__findnew_id(), try finding the DSO under the read lock first and
only acquire the write lock when a new DSO must be inserted or an
existing DSO needs its ID updated (checked via dso__needs_improve_id()).
Prioritize build IDs over inode fields in __dso_id__cmp(),
dso__needs_improve_id(), and __dso__improve_id() so an existing DSO with
a defined build ID is not updated with inode metadata.
Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
tools/perf/util/dso.c | 55 +++++++++++++++++++++++++++---------------
tools/perf/util/dso.h | 1 +
tools/perf/util/dsos.c | 10 ++++++++
3 files changed, 47 insertions(+), 19 deletions(-)
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index f0e02062c09c..f736a94a53a9 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1649,6 +1649,11 @@ static void dso__set_long_name_id(struct dso *dso, const char *name, bool name_a
static int __dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
{
+ if (build_id__is_defined(&a->build_id) && build_id__is_defined(&b->build_id)) {
+ if (a->build_id.size != b->build_id.size)
+ return a->build_id.size < b->build_id.size ? -1 : 1;
+ return memcmp(a->build_id.data, b->build_id.data, a->build_id.size);
+ }
if (a->mmap2_valid && b->mmap2_valid) {
if (a->maj > b->maj) return -1;
if (a->maj < b->maj) return 1;
@@ -1663,11 +1668,6 @@ static int __dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
if (a->ino_generation > b->ino_generation) return -1;
if (a->ino_generation < b->ino_generation) return 1;
}
- if (build_id__is_defined(&a->build_id) && build_id__is_defined(&b->build_id)) {
- if (a->build_id.size != b->build_id.size)
- return a->build_id.size < b->build_id.size ? -1 : 1;
- return memcmp(a->build_id.data, b->build_id.data, a->build_id.size);
- }
return 0;
}
@@ -1685,6 +1685,20 @@ const struct dso_id dso_id_empty = {
}
};
+bool dso__needs_improve_id(const struct dso *dso, const struct dso_id *id)
+{
+ const struct dso_id *dso_id = dso__id_const(dso);
+
+ if (!id || build_id__is_defined(&dso_id->build_id))
+ return false;
+
+ if (build_id__is_defined(&id->build_id))
+ return true;
+
+ return (id->mmap2_valid && !dso_id->mmap2_valid) ||
+ (id->mmap2_ino_generation_valid && !dso_id->mmap2_ino_generation_valid);
+}
+
void __dso__improve_id(struct dso *dso, const struct dso_id *id)
{
struct dsos *dsos = dso__dsos(dso);
@@ -1692,22 +1706,25 @@ void __dso__improve_id(struct dso *dso, const struct dso_id *id)
bool changed = false;
/* dsos write lock held by caller. */
+ if (!id || build_id__is_defined(&dso_id->build_id))
+ return;
- if (id->mmap2_valid && !dso_id->mmap2_valid) {
- dso_id->maj = id->maj;
- dso_id->min = id->min;
- dso_id->ino = id->ino;
- dso_id->mmap2_valid = true;
- changed = true;
- }
- if (id->mmap2_ino_generation_valid && !dso_id->mmap2_ino_generation_valid) {
- dso_id->ino_generation = id->ino_generation;
- dso_id->mmap2_ino_generation_valid = true;
- changed = true;
- }
- if (build_id__is_defined(&id->build_id) && !build_id__is_defined(&dso_id->build_id)) {
+ if (build_id__is_defined(&id->build_id)) {
dso_id->build_id = id->build_id;
changed = true;
+ } else {
+ if (id->mmap2_valid && !dso_id->mmap2_valid) {
+ dso_id->maj = id->maj;
+ dso_id->min = id->min;
+ dso_id->ino = id->ino;
+ dso_id->mmap2_valid = true;
+ changed = true;
+ }
+ if (id->mmap2_ino_generation_valid && !dso_id->mmap2_ino_generation_valid) {
+ dso_id->ino_generation = id->ino_generation;
+ dso_id->mmap2_ino_generation_valid = true;
+ changed = true;
+ }
}
if (changed && dsos)
dsos->sorted = false;
@@ -1715,7 +1732,7 @@ void __dso__improve_id(struct dso *dso, const struct dso_id *id)
int dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
{
- if (a == &dso_id_empty || b == &dso_id_empty) {
+ if (!a || !b || a == &dso_id_empty || b == &dso_id_empty) {
/* There is no valid data to compare so the comparison always returns identical. */
return 0;
}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index e8cd13c101a6..bb887d10a9ee 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -802,6 +802,7 @@ void dso__delete(struct dso *dso);
int dso__cmp_id(struct dso *a, struct dso *b);
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated);
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated);
+bool dso__needs_improve_id(const struct dso *dso, const struct dso_id *id);
void __dso__improve_id(struct dso *dso, const struct dso_id *id);
int dso__name_len(const struct dso *dso);
diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c
index a7f6a98acbaf..4ff38cb5e2cb 100644
--- a/tools/perf/util/dsos.c
+++ b/tools/perf/util/dsos.c
@@ -349,6 +349,16 @@ static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name, const
struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, const struct dso_id *id)
{
struct dso *dso;
+
+ down_read(&dsos->lock);
+ dso = __dsos__find_id(dsos, name, id, false, /*write_locked=*/false);
+ if (dso && !dso__needs_improve_id(dso, id)) {
+ up_read(&dsos->lock);
+ return dso;
+ }
+ up_read(&dsos->lock);
+ dso__put(dso);
+
down_write(&dsos->lock);
dso = __dsos__findnew_id(dsos, name, id);
up_write(&dsos->lock);
--
2.56.1.703.gf848ed807c-goog