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>
This commit is contained in:
Ian Rogers 2024-04-09 23:42:04 -07:00 committed by Arnaldo Carvalho de Melo
parent 83acca9f90
commit f649ed80f3
5 changed files with 97 additions and 99 deletions

View file

@ -181,7 +181,7 @@ struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso
* at the end of the list of duplicates.
*/
if (!dso || (dso == this))
return this; /* Find matching dso */
return dso__get(this); /* Find matching dso */
/*
* The core kernel DSOs may have duplicated long name.
* In this case, the short name should be different.
@ -253,15 +253,20 @@ static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, struct d
if (cmp_short) {
list_for_each_entry(pos, &dsos->head, node)
if (__dso__cmp_short_name(name, id, pos) == 0)
return pos;
return dso__get(pos);
return NULL;
}
return __dsos__findnew_by_longname_id(&dsos->root, name, id);
}
struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
{
return __dsos__find_id(dsos, name, NULL, cmp_short);
struct dso *res;
down_read(&dsos->lock);
res = __dsos__find_id(dsos, name, NULL, cmp_short);
up_read(&dsos->lock);
return res;
}
static void dso__set_basename(struct dso *dso)
@ -303,8 +308,6 @@ static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, struct
if (dso != NULL) {
__dsos__add(dsos, dso);
dso__set_basename(dso);
/* Put dso here because __dsos_add already got it */
dso__put(dso);
}
return dso;
}
@ -328,7 +331,7 @@ struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id
{
struct dso *dso;
down_write(&dsos->lock);
dso = dso__get(__dsos__findnew_id(dsos, name, id));
dso = __dsos__findnew_id(dsos, name, id);
up_write(&dsos->lock);
return dso;
}
@ -374,3 +377,59 @@ int __dsos__hit_all(struct dsos *dsos)
return 0;
}
struct dso *dsos__findnew_module_dso(struct dsos *dsos,
struct machine *machine,
struct kmod_path *m,
const char *filename)
{
struct dso *dso;
down_write(&dsos->lock);
dso = __dsos__find_id(dsos, m->name, NULL, /*cmp_short=*/true);
if (!dso) {
dso = __dsos__addnew(dsos, m->name);
if (dso == NULL)
goto out_unlock;
dso__set_module_info(dso, m, machine);
dso__set_long_name(dso, strdup(filename), true);
dso->kernel = DSO_SPACE__KERNEL;
}
out_unlock:
up_write(&dsos->lock);
return dso;
}
struct dso *dsos__find_kernel_dso(struct dsos *dsos)
{
struct dso *dso, *res = NULL;
down_read(&dsos->lock);
list_for_each_entry(dso, &dsos->head, node) {
/*
* The cpumode passed to is_kernel_module is not the cpumode of
* *this* event. If we insist on passing correct cpumode to
* is_kernel_module, we should record the cpumode when we adding
* this dso to the linked list.
*
* However we don't really need passing correct cpumode. We
* know the correct cpumode must be kernel mode (if not, we
* should not link it onto kernel_dsos list).
*
* Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.
* is_kernel_module() treats it as a kernel cpumode.
*/
if (!dso->kernel ||
is_kernel_module(dso->long_name,
PERF_RECORD_MISC_CPUMODE_UNKNOWN))
continue;
res = dso__get(dso);
break;
}
up_read(&dsos->lock);
return res;
}

View file

@ -10,6 +10,8 @@
struct dso;
struct dso_id;
struct kmod_path;
struct machine;
/*
* DSOs are put into both a list for fast iteration and rbtree for fast
@ -33,7 +35,7 @@ void dsos__exit(struct dsos *dsos);
void __dsos__add(struct dsos *dsos, struct dso *dso);
void dsos__add(struct dsos *dsos, struct dso *dso);
struct dso *__dsos__addnew(struct dsos *dsos, const char *name);
struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short);
struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short);
struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id);
@ -48,4 +50,9 @@ size_t __dsos__fprintf(struct dsos *dsos, FILE *fp);
int __dsos__hit_all(struct dsos *dsos);
struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine,
struct kmod_path *m, const char *filename);
struct dso *dsos__find_kernel_dso(struct dsos *dsos);
#endif /* __PERF_DSOS */

View file

@ -646,31 +646,6 @@ int machine__process_lost_samples_event(struct machine *machine __maybe_unused,
return 0;
}
static struct dso *machine__findnew_module_dso(struct machine *machine,
struct kmod_path *m,
const char *filename)
{
struct dso *dso;
down_write(&machine->dsos.lock);
dso = __dsos__find(&machine->dsos, m->name, true);
if (!dso) {
dso = __dsos__addnew(&machine->dsos, m->name);
if (dso == NULL)
goto out_unlock;
dso__set_module_info(dso, m, machine);
dso__set_long_name(dso, strdup(filename), true);
dso->kernel = DSO_SPACE__KERNEL;
}
dso__get(dso);
out_unlock:
up_write(&machine->dsos.lock);
return dso;
}
int machine__process_aux_event(struct machine *machine __maybe_unused,
union perf_event *event)
{
@ -854,7 +829,7 @@ static struct map *machine__addnew_module_map(struct machine *machine, u64 start
if (kmod_path__parse_name(&m, filename))
return NULL;
dso = machine__findnew_module_dso(machine, &m, filename);
dso = dsos__findnew_module_dso(&machine->dsos, machine, &m, filename);
if (dso == NULL)
goto out;
@ -1663,40 +1638,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
* Should be there already, from the build-id table in
* the header.
*/
struct dso *kernel = NULL;
struct dso *dso;
down_read(&machine->dsos.lock);
list_for_each_entry(dso, &machine->dsos.head, node) {
/*
* The cpumode passed to is_kernel_module is not the
* cpumode of *this* event. If we insist on passing
* correct cpumode to is_kernel_module, we should
* record the cpumode when we adding this dso to the
* linked list.
*
* However we don't really need passing correct
* cpumode. We know the correct cpumode must be kernel
* mode (if not, we should not link it onto kernel_dsos
* list).
*
* Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.
* is_kernel_module() treats it as a kernel cpumode.
*/
if (!dso->kernel ||
is_kernel_module(dso->long_name,
PERF_RECORD_MISC_CPUMODE_UNKNOWN))
continue;
kernel = dso__get(dso);
break;
}
up_read(&machine->dsos.lock);
struct dso *kernel = dsos__find_kernel_dso(&machine->dsos);
if (kernel == NULL)
kernel = machine__findnew_dso(machine, machine->mmap_name);

View file

@ -196,9 +196,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
* reading the header will have the build ID set and all future mmaps will
* have it missing.
*/
down_read(&machine->dsos.lock);
header_bid_dso = __dsos__find(&machine->dsos, filename, false);
up_read(&machine->dsos.lock);
header_bid_dso = dsos__find(&machine->dsos, filename, false);
if (header_bid_dso && header_bid_dso->header_build_id) {
dso__set_build_id(dso, &header_bid_dso->bid);
dso->header_build_id = 1;

View file

@ -133,8 +133,6 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s
if (dso != NULL) {
__dsos__add(&machine->dsos, dso);
dso__set_long_name(dso, long_name, false);
/* Put dso here because __dsos_add already got it */
dso__put(dso);
}
return dso;
@ -252,17 +250,15 @@ static struct dso *__machine__findnew_compat(struct machine *machine,
const char *file_name;
struct dso *dso;
dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true);
dso = dsos__find(&machine->dsos, vdso_file->dso_name, true);
if (dso)
goto out;
return dso;
file_name = vdso__get_compat_file(vdso_file);
if (!file_name)
goto out;
return NULL;
dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name);
out:
return dso;
return __machine__addnew_vdso(machine, vdso_file->dso_name, file_name);
}
static int __machine__findnew_vdso_compat(struct machine *machine,
@ -308,21 +304,21 @@ static struct dso *machine__find_vdso(struct machine *machine,
dso_type = machine__thread_dso_type(machine, thread);
switch (dso_type) {
case DSO__TYPE_32BIT:
dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true);
dso = dsos__find(&machine->dsos, DSO__NAME_VDSO32, true);
if (!dso) {
dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO,
true);
dso = dsos__find(&machine->dsos, DSO__NAME_VDSO,
true);
if (dso && dso_type != dso__type(dso, machine))
dso = NULL;
}
break;
case DSO__TYPE_X32BIT:
dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true);
dso = dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true);
break;
case DSO__TYPE_64BIT:
case DSO__TYPE_UNKNOWN:
default:
dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
break;
}
@ -334,37 +330,33 @@ struct dso *machine__findnew_vdso(struct machine *machine,
{
struct vdso_info *vdso_info;
struct dso *dso = NULL;
char *file;
down_write(&machine->dsos.lock);
if (!machine->vdso_info)
machine->vdso_info = vdso_info__new();
vdso_info = machine->vdso_info;
if (!vdso_info)
goto out_unlock;
return NULL;
dso = machine__find_vdso(machine, thread);
if (dso)
goto out_unlock;
return dso;
#if BITS_PER_LONG == 64
if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso))
goto out_unlock;
return dso;
#endif
dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
if (!dso) {
char *file;
dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
if (dso)
return dso;
file = get_file(&vdso_info->vdso);
if (file)
dso = __machine__addnew_vdso(machine, DSO__NAME_VDSO, file);
}
file = get_file(&vdso_info->vdso);
if (!file)
return NULL;
out_unlock:
dso__get(dso);
up_write(&machine->dsos.lock);
return dso;
return __machine__addnew_vdso(machine, DSO__NAME_VDSO, file);
}
bool dso__is_vdso(struct dso *dso)