Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf dsos: Switch more loops to dsos__for_each_dso()

Switch loops within dsos.c, add a version that isn't locked. Switch
some unlocked loops to hold the read lock.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Anne Macedo <retpolanne@posteo.net>
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: 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: Markus Elfring <Markus.Elfring@web.de>
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: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Song Liu <song@kernel.org>
Cc: Sun Haiyong <sunhaiyong@loongson.cn>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Cc: Yanteng Si <siyanteng@loongson.cn>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Cc: zhaimingbing <zhaimingbing@cmss.chinamobile.com>
Link: https://lore.kernel.org/r/20240410064214.2755936-6-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
0ffc8fca 1d6eff93

+185 -113
+1 -1
tools/perf/util/build-id.c
··· 964 964 965 965 static bool machine__read_build_ids(struct machine *machine, bool with_hits) 966 966 { 967 - return __dsos__read_build_ids(&machine->dsos, with_hits); 967 + return dsos__read_build_ids(&machine->dsos, with_hits); 968 968 } 969 969 970 970 bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
+176 -104
tools/perf/util/dsos.c
··· 41 41 exit_rwsem(&dsos->lock); 42 42 } 43 43 44 - bool __dsos__read_build_ids(struct dsos *dsos, bool with_hits) 44 + 45 + static int __dsos__for_each_dso(struct dsos *dsos, 46 + int (*cb)(struct dso *dso, void *data), 47 + void *data) 45 48 { 46 - struct list_head *head = &dsos->head; 47 - bool have_build_id = false; 48 - struct dso *pos; 49 + struct dso *dso; 50 + 51 + list_for_each_entry(dso, &dsos->head, node) { 52 + int err; 53 + 54 + err = cb(dso, data); 55 + if (err) 56 + return err; 57 + } 58 + return 0; 59 + } 60 + 61 + struct dsos__read_build_ids_cb_args { 62 + bool with_hits; 63 + bool have_build_id; 64 + }; 65 + 66 + static int dsos__read_build_ids_cb(struct dso *dso, void *data) 67 + { 68 + struct dsos__read_build_ids_cb_args *args = data; 49 69 struct nscookie nsc; 50 70 51 - list_for_each_entry(pos, head, node) { 52 - if (with_hits && !pos->hit && !dso__is_vdso(pos)) 53 - continue; 54 - if (pos->has_build_id) { 55 - have_build_id = true; 56 - continue; 57 - } 58 - nsinfo__mountns_enter(pos->nsinfo, &nsc); 59 - if (filename__read_build_id(pos->long_name, &pos->bid) > 0) { 60 - have_build_id = true; 61 - pos->has_build_id = true; 62 - } else if (errno == ENOENT && pos->nsinfo) { 63 - char *new_name = dso__filename_with_chroot(pos, pos->long_name); 64 - 65 - if (new_name && filename__read_build_id(new_name, 66 - &pos->bid) > 0) { 67 - have_build_id = true; 68 - pos->has_build_id = true; 69 - } 70 - free(new_name); 71 - } 72 - nsinfo__mountns_exit(&nsc); 71 + if (args->with_hits && !dso->hit && !dso__is_vdso(dso)) 72 + return 0; 73 + if (dso->has_build_id) { 74 + args->have_build_id = true; 75 + return 0; 73 76 } 77 + nsinfo__mountns_enter(dso->nsinfo, &nsc); 78 + if (filename__read_build_id(dso->long_name, &dso->bid) > 0) { 79 + args->have_build_id = true; 80 + dso->has_build_id = true; 81 + } else if (errno == ENOENT && dso->nsinfo) { 82 + char *new_name = dso__filename_with_chroot(dso, dso->long_name); 74 83 75 - return have_build_id; 84 + if (new_name && filename__read_build_id(new_name, &dso->bid) > 0) { 85 + args->have_build_id = true; 86 + dso->has_build_id = true; 87 + } 88 + free(new_name); 89 + } 90 + nsinfo__mountns_exit(&nsc); 91 + return 0; 92 + } 93 + 94 + bool dsos__read_build_ids(struct dsos *dsos, bool with_hits) 95 + { 96 + struct dsos__read_build_ids_cb_args args = { 97 + .with_hits = with_hits, 98 + .have_build_id = false, 99 + }; 100 + 101 + dsos__for_each_dso(dsos, dsos__read_build_ids_cb, &args); 102 + return args.have_build_id; 76 103 } 77 104 78 105 static int __dso__cmp_long_name(const char *long_name, struct dso_id *id, struct dso *b) ··· 132 105 133 106 if (!name) 134 107 name = dso->long_name; 108 + 135 109 /* 136 110 * Find node with the matching name 137 111 */ ··· 213 185 return __dsos__findnew_link_by_longname_id(root, NULL, name, id); 214 186 } 215 187 188 + struct dsos__find_id_cb_args { 189 + const char *name; 190 + struct dso_id *id; 191 + struct dso *res; 192 + }; 193 + 194 + static int dsos__find_id_cb(struct dso *dso, void *data) 195 + { 196 + struct dsos__find_id_cb_args *args = data; 197 + 198 + if (__dso__cmp_short_name(args->name, args->id, dso) == 0) { 199 + args->res = dso__get(dso); 200 + return 1; 201 + } 202 + return 0; 203 + 204 + } 205 + 216 206 static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, struct dso_id *id, bool cmp_short) 217 207 { 218 - struct dso *pos; 208 + struct dso *res; 219 209 220 210 if (cmp_short) { 221 - list_for_each_entry(pos, &dsos->head, node) 222 - if (__dso__cmp_short_name(name, id, pos) == 0) 223 - return dso__get(pos); 224 - return NULL; 211 + struct dsos__find_id_cb_args args = { 212 + .name = name, 213 + .id = id, 214 + .res = NULL, 215 + }; 216 + 217 + __dsos__for_each_dso(dsos, dsos__find_id_cb, &args); 218 + return args.res; 225 219 } 226 - return __dsos__findnew_by_longname_id(&dsos->root, name, id); 220 + res = __dsos__findnew_by_longname_id(&dsos->root, name, id); 221 + return res; 227 222 } 228 223 229 224 struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) ··· 326 275 return dso; 327 276 } 328 277 329 - size_t __dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, 330 - bool (skip)(struct dso *dso, int parm), int parm) 278 + struct dsos__fprintf_buildid_cb_args { 279 + FILE *fp; 280 + bool (*skip)(struct dso *dso, int parm); 281 + int parm; 282 + size_t ret; 283 + }; 284 + 285 + static int dsos__fprintf_buildid_cb(struct dso *dso, void *data) 331 286 { 332 - struct list_head *head = &dsos->head; 333 - struct dso *pos; 334 - size_t ret = 0; 287 + struct dsos__fprintf_buildid_cb_args *args = data; 288 + char sbuild_id[SBUILD_ID_SIZE]; 335 289 336 - list_for_each_entry(pos, head, node) { 337 - char sbuild_id[SBUILD_ID_SIZE]; 338 - 339 - if (skip && skip(pos, parm)) 340 - continue; 341 - build_id__sprintf(&pos->bid, sbuild_id); 342 - ret += fprintf(fp, "%-40s %s\n", sbuild_id, pos->long_name); 343 - } 344 - return ret; 345 - } 346 - 347 - size_t __dsos__fprintf(struct dsos *dsos, FILE *fp) 348 - { 349 - struct list_head *head = &dsos->head; 350 - struct dso *pos; 351 - size_t ret = 0; 352 - 353 - list_for_each_entry(pos, head, node) { 354 - ret += dso__fprintf(pos, fp); 355 - } 356 - 357 - return ret; 358 - } 359 - 360 - int __dsos__hit_all(struct dsos *dsos) 361 - { 362 - struct list_head *head = &dsos->head; 363 - struct dso *pos; 364 - 365 - list_for_each_entry(pos, head, node) 366 - pos->hit = true; 367 - 290 + if (args->skip && args->skip(dso, args->parm)) 291 + return 0; 292 + build_id__sprintf(&dso->bid, sbuild_id); 293 + args->ret += fprintf(args->fp, "%-40s %s\n", sbuild_id, dso->long_name); 368 294 return 0; 295 + } 296 + 297 + size_t dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, 298 + bool (*skip)(struct dso *dso, int parm), int parm) 299 + { 300 + struct dsos__fprintf_buildid_cb_args args = { 301 + .fp = fp, 302 + .skip = skip, 303 + .parm = parm, 304 + .ret = 0, 305 + }; 306 + 307 + dsos__for_each_dso(dsos, dsos__fprintf_buildid_cb, &args); 308 + return args.ret; 309 + } 310 + 311 + struct dsos__fprintf_cb_args { 312 + FILE *fp; 313 + size_t ret; 314 + }; 315 + 316 + static int dsos__fprintf_cb(struct dso *dso, void *data) 317 + { 318 + struct dsos__fprintf_cb_args *args = data; 319 + 320 + args->ret += dso__fprintf(dso, args->fp); 321 + return 0; 322 + } 323 + 324 + size_t dsos__fprintf(struct dsos *dsos, FILE *fp) 325 + { 326 + struct dsos__fprintf_cb_args args = { 327 + .fp = fp, 328 + .ret = 0, 329 + }; 330 + 331 + dsos__for_each_dso(dsos, dsos__fprintf_cb, &args); 332 + return args.ret; 333 + } 334 + 335 + static int dsos__hit_all_cb(struct dso *dso, void *data __maybe_unused) 336 + { 337 + dso->hit = true; 338 + return 0; 339 + } 340 + 341 + int dsos__hit_all(struct dsos *dsos) 342 + { 343 + return dsos__for_each_dso(dsos, dsos__hit_all_cb, NULL); 369 344 } 370 345 371 346 struct dso *dsos__findnew_module_dso(struct dsos *dsos, ··· 419 342 return dso; 420 343 } 421 344 345 + static int dsos__find_kernel_dso_cb(struct dso *dso, void *data) 346 + { 347 + struct dso **res = data; 348 + /* 349 + * The cpumode passed to is_kernel_module is not the cpumode of *this* 350 + * event. If we insist on passing correct cpumode to is_kernel_module, 351 + * we should record the cpumode when we adding this dso to the linked 352 + * list. 353 + * 354 + * However we don't really need passing correct cpumode. We know the 355 + * correct cpumode must be kernel mode (if not, we should not link it 356 + * onto kernel_dsos list). 357 + * 358 + * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. 359 + * is_kernel_module() treats it as a kernel cpumode. 360 + */ 361 + if (!dso->kernel || 362 + is_kernel_module(dso->long_name, PERF_RECORD_MISC_CPUMODE_UNKNOWN)) 363 + return 0; 364 + 365 + *res = dso__get(dso); 366 + return 1; 367 + } 368 + 422 369 struct dso *dsos__find_kernel_dso(struct dsos *dsos) 423 370 { 424 - struct dso *dso, *res = NULL; 371 + struct dso *res = NULL; 425 372 426 - down_read(&dsos->lock); 427 - list_for_each_entry(dso, &dsos->head, node) { 428 - /* 429 - * The cpumode passed to is_kernel_module is not the cpumode of 430 - * *this* event. If we insist on passing correct cpumode to 431 - * is_kernel_module, we should record the cpumode when we adding 432 - * this dso to the linked list. 433 - * 434 - * However we don't really need passing correct cpumode. We 435 - * know the correct cpumode must be kernel mode (if not, we 436 - * should not link it onto kernel_dsos list). 437 - * 438 - * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. 439 - * is_kernel_module() treats it as a kernel cpumode. 440 - */ 441 - if (!dso->kernel || 442 - is_kernel_module(dso->long_name, 443 - PERF_RECORD_MISC_CPUMODE_UNKNOWN)) 444 - continue; 445 - 446 - res = dso__get(dso); 447 - break; 448 - } 449 - up_read(&dsos->lock); 373 + dsos__for_each_dso(dsos, dsos__find_kernel_dso_cb, &res); 450 374 return res; 451 375 } 452 376 453 377 int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data) 454 378 { 455 - struct dso *dso; 379 + int err; 456 380 457 381 down_read(&dsos->lock); 458 - list_for_each_entry(dso, &dsos->head, node) { 459 - int err; 460 - 461 - err = cb(dso, data); 462 - if (err) 463 - return err; 464 - } 382 + err = __dsos__for_each_dso(dsos, cb, data); 465 383 up_read(&dsos->lock); 466 - return 0; 384 + return err; 467 385 }
+4 -4
tools/perf/util/dsos.h
··· 33 33 34 34 struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id); 35 35 36 - bool __dsos__read_build_ids(struct dsos *dsos, bool with_hits); 36 + bool dsos__read_build_ids(struct dsos *dsos, bool with_hits); 37 37 38 38 struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso *dso, 39 39 const char *name, struct dso_id *id); 40 40 41 - size_t __dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, 41 + size_t dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, 42 42 bool (skip)(struct dso *dso, int parm), int parm); 43 - size_t __dsos__fprintf(struct dsos *dsos, FILE *fp); 43 + size_t dsos__fprintf(struct dsos *dsos, FILE *fp); 44 44 45 - int __dsos__hit_all(struct dsos *dsos); 45 + int dsos__hit_all(struct dsos *dsos); 46 46 47 47 struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine, 48 48 struct kmod_path *m, const char *filename);
+4 -4
tools/perf/util/machine.c
··· 853 853 size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) 854 854 { 855 855 struct rb_node *nd; 856 - size_t ret = __dsos__fprintf(&machines->host.dsos, fp); 856 + size_t ret = dsos__fprintf(&machines->host.dsos, fp); 857 857 858 858 for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 859 859 struct machine *pos = rb_entry(nd, struct machine, rb_node); 860 - ret += __dsos__fprintf(&pos->dsos, fp); 860 + ret += dsos__fprintf(&pos->dsos, fp); 861 861 } 862 862 863 863 return ret; ··· 866 866 size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, 867 867 bool (skip)(struct dso *dso, int parm), int parm) 868 868 { 869 - return __dsos__fprintf_buildid(&m->dsos, fp, skip, parm); 869 + return dsos__fprintf_buildid(&m->dsos, fp, skip, parm); 870 870 } 871 871 872 872 size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, ··· 3232 3232 3233 3233 int machine__hit_all_dsos(struct machine *machine) 3234 3234 { 3235 - return __dsos__hit_all(&machine->dsos); 3235 + return dsos__hit_all(&machine->dsos); 3236 3236 }