Skip to content

Commit 3f4ac23

Browse files
captain5050acmel
authored andcommitted
perf dsos: Switch backing storage to array from rbtree/list
DSOs were held on a list for fast iteration and in an rbtree for fast finds. Switch to using a lazily sorted array where iteration is just iterating through the array and binary searches are the same complexity as searching the rbtree. The find may need to sort the array first which does increase the complexity, but add operations have lower complexity and overall the complexity should remain about the same. The set name operations on the dso just records that the array is no longer sorted, avoiding complexity in rebalancing the rbtree. Tighter locking discipline is enforced to avoid the array being resorted while long and short names or ids are changed. The array is smaller in size, replacing 6 pointers with 2, and so even with extra allocated space in the array, the array may be 50% unoccupied, the memory saving should be at least 2x. Committer testing: On a previous version of this patchset we were getting a lot of warnings about deleting a DSO still on a list, now it is ok: root@x1:~# perf probe -l root@x1:~# perf probe finish_task_switch Added new event: probe:finish_task_switch (on finish_task_switch) You can now use it in all perf tools, such as: perf record -e probe:finish_task_switch -aR sleep 1 root@x1:~# perf probe -l probe:finish_task_switch (on finish_task_switch@kernel/sched/core.c) root@x1:~# perf trace -e probe:finish_task_switch/max-stack=8/ --max-events=1 0.000 migration/0/19 probe:finish_task_switch(__probe_ip: -1894408688) finish_task_switch.isra.0 ([kernel.kallsyms]) __schedule ([kernel.kallsyms]) schedule ([kernel.kallsyms]) smpboot_thread_fn ([kernel.kallsyms]) kthread ([kernel.kallsyms]) ret_from_fork ([kernel.kallsyms]) ret_from_fork_asm ([kernel.kallsyms]) root@x1:~# root@x1:~# perf probe -d probe:* Removed event: probe:finish_task_switch root@x1:~# perf probe -l root@x1:~# I also ran the full 'perf test' suite after applying this one, no regressions. Signed-off-by: Ian Rogers <irogers@google.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Cc: Ben Gainey <ben.gainey@arm.com> Cc: Changbin Du <changbin.du@huawei.com> Cc: Chengen Du <chengen.du@canonical.com> Cc: Colin Ian King <colin.i.king@gmail.com> Cc: Dima Kogan <dima@secretsauce.net> Cc: Ilkka Koskinen <ilkka@os.amperecomputing.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@arm.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: K Prateek Nayak <kprateek.nayak@amd.com> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linux.dev> Cc: Li Dong <lidong@vivo.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Paran Lee <p4ranlee@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Song Liu <song@kernel.org> Cc: Sun Haiyong <sunhaiyong@loongson.cn> Cc: Thomas Richter <tmricht@linux.ibm.com> Cc: Tiezhu Yang <yangtiezhu@loongson.cn> Cc: Yanteng Si <siyanteng@loongson.cn> Cc: zhaimingbing <zhaimingbing@cmss.chinamobile.com> Link: https://lore.kernel.org/r/20240504213803.218974-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 77a70f8 commit 3f4ac23

4 files changed

Lines changed: 177 additions & 109 deletions

File tree

tools/perf/util/dso.c

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,35 +1241,35 @@ struct dso *machine__findnew_kernel(struct machine *machine, const char *name,
12411241
return dso;
12421242
}
12431243

1244-
static void dso__set_long_name_id(struct dso *dso, const char *name, struct dso_id *id, bool name_allocated)
1244+
static void dso__set_long_name_id(struct dso *dso, const char *name, bool name_allocated)
12451245
{
1246-
struct rb_root *root = dso->root;
1246+
struct dsos *dsos = dso->dsos;
12471247

12481248
if (name == NULL)
12491249
return;
12501250

1251-
if (dso->long_name_allocated)
1252-
free((char *)dso->long_name);
1253-
1254-
if (root) {
1255-
rb_erase(&dso->rb_node, root);
1251+
if (dsos) {
12561252
/*
1257-
* __dsos__findnew_link_by_longname_id() isn't guaranteed to
1258-
* add it back, so a clean removal is required here.
1253+
* Need to avoid re-sorting the dsos breaking by non-atomically
1254+
* renaming the dso.
12591255
*/
1260-
RB_CLEAR_NODE(&dso->rb_node);
1261-
dso->root = NULL;
1256+
down_write(&dsos->lock);
12621257
}
12631258

1259+
if (dso->long_name_allocated)
1260+
free((char *)dso->long_name);
1261+
12641262
dso->long_name = name;
12651263
dso->long_name_len = strlen(name);
12661264
dso->long_name_allocated = name_allocated;
12671265

1268-
if (root)
1269-
__dsos__findnew_link_by_longname_id(root, dso, NULL, id);
1266+
if (dsos) {
1267+
dsos->sorted = false;
1268+
up_write(&dsos->lock);
1269+
}
12701270
}
12711271

1272-
static int __dso_id__cmp(struct dso_id *a, struct dso_id *b)
1272+
static int __dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
12731273
{
12741274
if (a->maj > b->maj) return -1;
12751275
if (a->maj < b->maj) return 1;
@@ -1297,23 +1297,30 @@ static int __dso_id__cmp(struct dso_id *a, struct dso_id *b)
12971297
return 0;
12981298
}
12991299

1300-
bool dso_id__empty(struct dso_id *id)
1300+
bool dso_id__empty(const struct dso_id *id)
13011301
{
13021302
if (!id)
13031303
return true;
13041304

13051305
return !id->maj && !id->min && !id->ino && !id->ino_generation;
13061306
}
13071307

1308-
void dso__inject_id(struct dso *dso, struct dso_id *id)
1308+
void __dso__inject_id(struct dso *dso, struct dso_id *id)
13091309
{
1310+
struct dsos *dsos = dso->dsos;
1311+
1312+
/* dsos write lock held by caller. */
1313+
13101314
dso->id.maj = id->maj;
13111315
dso->id.min = id->min;
13121316
dso->id.ino = id->ino;
13131317
dso->id.ino_generation = id->ino_generation;
1318+
1319+
if (dsos)
1320+
dsos->sorted = false;
13141321
}
13151322

1316-
int dso_id__cmp(struct dso_id *a, struct dso_id *b)
1323+
int dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
13171324
{
13181325
/*
13191326
* The second is always dso->id, so zeroes if not set, assume passing
@@ -1332,20 +1339,34 @@ int dso__cmp_id(struct dso *a, struct dso *b)
13321339

13331340
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
13341341
{
1335-
dso__set_long_name_id(dso, name, NULL, name_allocated);
1342+
dso__set_long_name_id(dso, name, name_allocated);
13361343
}
13371344

13381345
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
13391346
{
1347+
struct dsos *dsos = dso->dsos;
1348+
13401349
if (name == NULL)
13411350
return;
13421351

1352+
if (dsos) {
1353+
/*
1354+
* Need to avoid re-sorting the dsos breaking by non-atomically
1355+
* renaming the dso.
1356+
*/
1357+
down_write(&dsos->lock);
1358+
}
13431359
if (dso->short_name_allocated)
13441360
free((char *)dso->short_name);
13451361

13461362
dso->short_name = name;
13471363
dso->short_name_len = strlen(name);
13481364
dso->short_name_allocated = name_allocated;
1365+
1366+
if (dsos) {
1367+
dsos->sorted = false;
1368+
up_write(&dsos->lock);
1369+
}
13491370
}
13501371

13511372
int dso__name_len(const struct dso *dso)
@@ -1381,7 +1402,7 @@ struct dso *dso__new_id(const char *name, struct dso_id *id)
13811402
strcpy(dso->name, name);
13821403
if (id)
13831404
dso->id = *id;
1384-
dso__set_long_name_id(dso, dso->name, id, false);
1405+
dso__set_long_name_id(dso, dso->name, false);
13851406
dso__set_short_name(dso, dso->name, false);
13861407
dso->symbols = RB_ROOT_CACHED;
13871408
dso->symbol_names = NULL;
@@ -1406,9 +1427,6 @@ struct dso *dso__new_id(const char *name, struct dso_id *id)
14061427
dso->is_kmod = 0;
14071428
dso->needs_swap = DSO_SWAP__UNSET;
14081429
dso->comp = COMP_ID__NONE;
1409-
RB_CLEAR_NODE(&dso->rb_node);
1410-
dso->root = NULL;
1411-
INIT_LIST_HEAD(&dso->node);
14121430
INIT_LIST_HEAD(&dso->data.open_entry);
14131431
mutex_init(&dso->lock);
14141432
refcount_set(&dso->refcnt, 1);
@@ -1424,9 +1442,8 @@ struct dso *dso__new(const char *name)
14241442

14251443
void dso__delete(struct dso *dso)
14261444
{
1427-
if (!RB_EMPTY_NODE(&dso->rb_node))
1428-
pr_err("DSO %s is still in rbtree when being deleted!\n",
1429-
dso->long_name);
1445+
if (dso->dsos)
1446+
pr_err("DSO %s is still in rbtree when being deleted!\n", dso->long_name);
14301447

14311448
/* free inlines first, as they reference symbols */
14321449
inlines__tree_delete(&dso->inlined_nodes);

tools/perf/util/dso.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,7 @@ struct auxtrace_cache;
146146

147147
struct dso {
148148
struct mutex lock;
149-
struct list_head node;
150-
struct rb_node rb_node; /* rbtree node sorted by long name */
151-
struct rb_root *root; /* root of rbtree that rb_node is in */
149+
struct dsos *dsos;
152150
struct rb_root_cached symbols;
153151
struct symbol **symbol_names;
154152
size_t symbol_names_len;
@@ -238,8 +236,8 @@ static inline void dso__set_loaded(struct dso *dso)
238236
dso->loaded = true;
239237
}
240238

241-
int dso_id__cmp(struct dso_id *a, struct dso_id *b);
242-
bool dso_id__empty(struct dso_id *id);
239+
int dso_id__cmp(const struct dso_id *a, const struct dso_id *b);
240+
bool dso_id__empty(const struct dso_id *id);
243241

244242
struct dso *dso__new_id(const char *name, struct dso_id *id);
245243
struct dso *dso__new(const char *name);
@@ -248,7 +246,7 @@ void dso__delete(struct dso *dso);
248246
int dso__cmp_id(struct dso *a, struct dso *b);
249247
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated);
250248
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated);
251-
void dso__inject_id(struct dso *dso, struct dso_id *id);
249+
void __dso__inject_id(struct dso *dso, struct dso_id *id);
252250

253251
int dso__name_len(const struct dso *dso);
254252

0 commit comments

Comments
 (0)