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

perf dsos: Tidy reference counting and locking

Move more functionality into dsos.c generally from machine.c, renaming
functions to match their new usage.

The find function is made to always "get" before returning a dso.

Reduce the scope of locks in vdso to match the locking paradigm.

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-3-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
f649ed80 83acca9f

+97 -99
+66 -7
tools/perf/util/dsos.c
··· 181 181 * at the end of the list of duplicates. 182 182 */ 183 183 if (!dso || (dso == this)) 184 - return this; /* Find matching dso */ 184 + return dso__get(this); /* Find matching dso */ 185 185 /* 186 186 * The core kernel DSOs may have duplicated long name. 187 187 * In this case, the short name should be different. ··· 253 253 if (cmp_short) { 254 254 list_for_each_entry(pos, &dsos->head, node) 255 255 if (__dso__cmp_short_name(name, id, pos) == 0) 256 - return pos; 256 + return dso__get(pos); 257 257 return NULL; 258 258 } 259 259 return __dsos__findnew_by_longname_id(&dsos->root, name, id); 260 260 } 261 261 262 - struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) 262 + struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) 263 263 { 264 - return __dsos__find_id(dsos, name, NULL, cmp_short); 264 + struct dso *res; 265 + 266 + down_read(&dsos->lock); 267 + res = __dsos__find_id(dsos, name, NULL, cmp_short); 268 + up_read(&dsos->lock); 269 + return res; 265 270 } 266 271 267 272 static void dso__set_basename(struct dso *dso) ··· 308 303 if (dso != NULL) { 309 304 __dsos__add(dsos, dso); 310 305 dso__set_basename(dso); 311 - /* Put dso here because __dsos_add already got it */ 312 - dso__put(dso); 313 306 } 314 307 return dso; 315 308 } ··· 331 328 { 332 329 struct dso *dso; 333 330 down_write(&dsos->lock); 334 - dso = dso__get(__dsos__findnew_id(dsos, name, id)); 331 + dso = __dsos__findnew_id(dsos, name, id); 335 332 up_write(&dsos->lock); 336 333 return dso; 337 334 } ··· 376 373 pos->hit = true; 377 374 378 375 return 0; 376 + } 377 + 378 + struct dso *dsos__findnew_module_dso(struct dsos *dsos, 379 + struct machine *machine, 380 + struct kmod_path *m, 381 + const char *filename) 382 + { 383 + struct dso *dso; 384 + 385 + down_write(&dsos->lock); 386 + 387 + dso = __dsos__find_id(dsos, m->name, NULL, /*cmp_short=*/true); 388 + if (!dso) { 389 + dso = __dsos__addnew(dsos, m->name); 390 + if (dso == NULL) 391 + goto out_unlock; 392 + 393 + dso__set_module_info(dso, m, machine); 394 + dso__set_long_name(dso, strdup(filename), true); 395 + dso->kernel = DSO_SPACE__KERNEL; 396 + } 397 + 398 + out_unlock: 399 + up_write(&dsos->lock); 400 + return dso; 401 + } 402 + 403 + struct dso *dsos__find_kernel_dso(struct dsos *dsos) 404 + { 405 + struct dso *dso, *res = NULL; 406 + 407 + down_read(&dsos->lock); 408 + list_for_each_entry(dso, &dsos->head, node) { 409 + /* 410 + * The cpumode passed to is_kernel_module is not the cpumode of 411 + * *this* event. If we insist on passing correct cpumode to 412 + * is_kernel_module, we should record the cpumode when we adding 413 + * this dso to the linked list. 414 + * 415 + * However we don't really need passing correct cpumode. We 416 + * know the correct cpumode must be kernel mode (if not, we 417 + * should not link it onto kernel_dsos list). 418 + * 419 + * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. 420 + * is_kernel_module() treats it as a kernel cpumode. 421 + */ 422 + if (!dso->kernel || 423 + is_kernel_module(dso->long_name, 424 + PERF_RECORD_MISC_CPUMODE_UNKNOWN)) 425 + continue; 426 + 427 + res = dso__get(dso); 428 + break; 429 + } 430 + up_read(&dsos->lock); 431 + return res; 379 432 }
+8 -1
tools/perf/util/dsos.h
··· 10 10 11 11 struct dso; 12 12 struct dso_id; 13 + struct kmod_path; 14 + struct machine; 13 15 14 16 /* 15 17 * DSOs are put into both a list for fast iteration and rbtree for fast ··· 35 33 void __dsos__add(struct dsos *dsos, struct dso *dso); 36 34 void dsos__add(struct dsos *dsos, struct dso *dso); 37 35 struct dso *__dsos__addnew(struct dsos *dsos, const char *name); 38 - struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); 36 + struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); 39 37 40 38 struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id); 41 39 ··· 49 47 size_t __dsos__fprintf(struct dsos *dsos, FILE *fp); 50 48 51 49 int __dsos__hit_all(struct dsos *dsos); 50 + 51 + struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine, 52 + struct kmod_path *m, const char *filename); 53 + 54 + struct dso *dsos__find_kernel_dso(struct dsos *dsos); 52 55 53 56 #endif /* __PERF_DSOS */
+2 -60
tools/perf/util/machine.c
··· 646 646 return 0; 647 647 } 648 648 649 - static struct dso *machine__findnew_module_dso(struct machine *machine, 650 - struct kmod_path *m, 651 - const char *filename) 652 - { 653 - struct dso *dso; 654 - 655 - down_write(&machine->dsos.lock); 656 - 657 - dso = __dsos__find(&machine->dsos, m->name, true); 658 - if (!dso) { 659 - dso = __dsos__addnew(&machine->dsos, m->name); 660 - if (dso == NULL) 661 - goto out_unlock; 662 - 663 - dso__set_module_info(dso, m, machine); 664 - dso__set_long_name(dso, strdup(filename), true); 665 - dso->kernel = DSO_SPACE__KERNEL; 666 - } 667 - 668 - dso__get(dso); 669 - out_unlock: 670 - up_write(&machine->dsos.lock); 671 - return dso; 672 - } 673 - 674 649 int machine__process_aux_event(struct machine *machine __maybe_unused, 675 650 union perf_event *event) 676 651 { ··· 829 854 if (kmod_path__parse_name(&m, filename)) 830 855 return NULL; 831 856 832 - dso = machine__findnew_module_dso(machine, &m, filename); 857 + dso = dsos__findnew_module_dso(&machine->dsos, machine, &m, filename); 833 858 if (dso == NULL) 834 859 goto out; 835 860 ··· 1638 1663 * Should be there already, from the build-id table in 1639 1664 * the header. 1640 1665 */ 1641 - struct dso *kernel = NULL; 1642 - struct dso *dso; 1643 - 1644 - down_read(&machine->dsos.lock); 1645 - 1646 - list_for_each_entry(dso, &machine->dsos.head, node) { 1647 - 1648 - /* 1649 - * The cpumode passed to is_kernel_module is not the 1650 - * cpumode of *this* event. If we insist on passing 1651 - * correct cpumode to is_kernel_module, we should 1652 - * record the cpumode when we adding this dso to the 1653 - * linked list. 1654 - * 1655 - * However we don't really need passing correct 1656 - * cpumode. We know the correct cpumode must be kernel 1657 - * mode (if not, we should not link it onto kernel_dsos 1658 - * list). 1659 - * 1660 - * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. 1661 - * is_kernel_module() treats it as a kernel cpumode. 1662 - */ 1663 - 1664 - if (!dso->kernel || 1665 - is_kernel_module(dso->long_name, 1666 - PERF_RECORD_MISC_CPUMODE_UNKNOWN)) 1667 - continue; 1668 - 1669 - 1670 - kernel = dso__get(dso); 1671 - break; 1672 - } 1673 - 1674 - up_read(&machine->dsos.lock); 1666 + struct dso *kernel = dsos__find_kernel_dso(&machine->dsos); 1675 1667 1676 1668 if (kernel == NULL) 1677 1669 kernel = machine__findnew_dso(machine, machine->mmap_name);
+1 -3
tools/perf/util/map.c
··· 196 196 * reading the header will have the build ID set and all future mmaps will 197 197 * have it missing. 198 198 */ 199 - down_read(&machine->dsos.lock); 200 - header_bid_dso = __dsos__find(&machine->dsos, filename, false); 201 - up_read(&machine->dsos.lock); 199 + header_bid_dso = dsos__find(&machine->dsos, filename, false); 202 200 if (header_bid_dso && header_bid_dso->header_build_id) { 203 201 dso__set_build_id(dso, &header_bid_dso->bid); 204 202 dso->header_build_id = 1;
+20 -28
tools/perf/util/vdso.c
··· 133 133 if (dso != NULL) { 134 134 __dsos__add(&machine->dsos, dso); 135 135 dso__set_long_name(dso, long_name, false); 136 - /* Put dso here because __dsos_add already got it */ 137 - dso__put(dso); 138 136 } 139 137 140 138 return dso; ··· 250 252 const char *file_name; 251 253 struct dso *dso; 252 254 253 - dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true); 255 + dso = dsos__find(&machine->dsos, vdso_file->dso_name, true); 254 256 if (dso) 255 - goto out; 257 + return dso; 256 258 257 259 file_name = vdso__get_compat_file(vdso_file); 258 260 if (!file_name) 259 - goto out; 261 + return NULL; 260 262 261 - dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name); 262 - out: 263 - return dso; 263 + return __machine__addnew_vdso(machine, vdso_file->dso_name, file_name); 264 264 } 265 265 266 266 static int __machine__findnew_vdso_compat(struct machine *machine, ··· 304 308 dso_type = machine__thread_dso_type(machine, thread); 305 309 switch (dso_type) { 306 310 case DSO__TYPE_32BIT: 307 - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); 311 + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); 308 312 if (!dso) { 309 - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, 310 - true); 313 + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, 314 + true); 311 315 if (dso && dso_type != dso__type(dso, machine)) 312 316 dso = NULL; 313 317 } 314 318 break; 315 319 case DSO__TYPE_X32BIT: 316 - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); 320 + dso = dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); 317 321 break; 318 322 case DSO__TYPE_64BIT: 319 323 case DSO__TYPE_UNKNOWN: 320 324 default: 321 - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); 325 + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true); 322 326 break; 323 327 } 324 328 ··· 330 334 { 331 335 struct vdso_info *vdso_info; 332 336 struct dso *dso = NULL; 337 + char *file; 333 338 334 - down_write(&machine->dsos.lock); 335 339 if (!machine->vdso_info) 336 340 machine->vdso_info = vdso_info__new(); 337 341 338 342 vdso_info = machine->vdso_info; 339 343 if (!vdso_info) 340 - goto out_unlock; 344 + return NULL; 341 345 342 346 dso = machine__find_vdso(machine, thread); 343 347 if (dso) 344 - goto out_unlock; 348 + return dso; 345 349 346 350 #if BITS_PER_LONG == 64 347 351 if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) 348 - goto out_unlock; 352 + return dso; 349 353 #endif 350 354 351 - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); 352 - if (!dso) { 353 - char *file; 355 + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true); 356 + if (dso) 357 + return dso; 354 358 355 - file = get_file(&vdso_info->vdso); 356 - if (file) 357 - dso = __machine__addnew_vdso(machine, DSO__NAME_VDSO, file); 358 - } 359 + file = get_file(&vdso_info->vdso); 360 + if (!file) 361 + return NULL; 359 362 360 - out_unlock: 361 - dso__get(dso); 362 - up_write(&machine->dsos.lock); 363 - return dso; 363 + return __machine__addnew_vdso(machine, DSO__NAME_VDSO, file); 364 364 } 365 365 366 366 bool dso__is_vdso(struct dso *dso)