Commit 028c63b5 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

  - Fix perf.data size reporting in 'perf record' in no-buildid mode (He Kuang)

Infrastructure changes:

  - Protect accesses the DSO rbtrees/lists with a rw lock and reference
    count struct dso instances (Arnaldo Carvalho de Melo)

  - Export dynamic symbols used by traceevent plugins (He Kuang)

  - Add libtrace-dynamic-list file to libtraceevent's .gitignore (He Kuang)

  - Refactor shadow stats code in 'perf stat', prep work for further
    patchkits (Jiri Olsa)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents a3d86542 d3a7c489
TRACEEVENT-CFLAGS TRACEEVENT-CFLAGS
libtraceevent-dynamic-list
...@@ -23,6 +23,7 @@ endef ...@@ -23,6 +23,7 @@ endef
# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. # Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
$(call allow-override,CC,$(CROSS_COMPILE)gcc) $(call allow-override,CC,$(CROSS_COMPILE)gcc)
$(call allow-override,AR,$(CROSS_COMPILE)ar) $(call allow-override,AR,$(CROSS_COMPILE)ar)
$(call allow-override,NM,$(CROSS_COMPILE)nm)
EXT = -std=gnu99 EXT = -std=gnu99
INSTALL = install INSTALL = install
...@@ -157,8 +158,9 @@ PLUGINS_IN := $(PLUGINS:.so=-in.o) ...@@ -157,8 +158,9 @@ PLUGINS_IN := $(PLUGINS:.so=-in.o)
TE_IN := $(OUTPUT)libtraceevent-in.o TE_IN := $(OUTPUT)libtraceevent-in.o
LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE))
DYNAMIC_LIST_FILE := $(OUTPUT)libtraceevent-dynamic-list
CMD_TARGETS = $(LIB_FILE) $(PLUGINS) CMD_TARGETS = $(LIB_FILE) $(PLUGINS) $(DYNAMIC_LIST_FILE)
TARGETS = $(CMD_TARGETS) TARGETS = $(CMD_TARGETS)
...@@ -175,6 +177,9 @@ $(OUTPUT)libtraceevent.so: $(TE_IN) ...@@ -175,6 +177,9 @@ $(OUTPUT)libtraceevent.so: $(TE_IN)
$(OUTPUT)libtraceevent.a: $(TE_IN) $(OUTPUT)libtraceevent.a: $(TE_IN)
$(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
$(OUTPUT)libtraceevent-dynamic-list: $(PLUGINS)
$(QUIET_GEN)$(call do_generate_dynamic_list_file, $(PLUGINS), $@)
plugins: $(PLUGINS) plugins: $(PLUGINS)
__plugin_obj = $(notdir $@) __plugin_obj = $(notdir $@)
...@@ -244,6 +249,13 @@ define do_install_plugins ...@@ -244,6 +249,13 @@ define do_install_plugins
done done
endef endef
define do_generate_dynamic_list_file
(echo '{'; \
$(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u; \
echo '};'; \
) > $2
endef
install_lib: all_cmd install_plugins install_lib: all_cmd install_plugins
$(call QUIET_INSTALL, $(LIB_FILE)) \ $(call QUIET_INSTALL, $(LIB_FILE)) \
$(call do_install,$(LIB_FILE),$(libdir_SQ)) $(call do_install,$(LIB_FILE),$(libdir_SQ))
......
...@@ -173,6 +173,9 @@ endif ...@@ -173,6 +173,9 @@ endif
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
export LIBTRACEEVENT export LIBTRACEEVENT
LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
LDFLAGS += -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST)
LIBAPI = $(LIB_PATH)libapi.a LIBAPI = $(LIB_PATH)libapi.a
export LIBAPI export LIBAPI
...@@ -278,7 +281,7 @@ build := -f $(srctree)/tools/build/Makefile.build dir=. obj ...@@ -278,7 +281,7 @@ build := -f $(srctree)/tools/build/Makefile.build dir=. obj
$(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE $(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE
$(Q)$(MAKE) $(build)=perf $(Q)$(MAKE) $(build)=perf
$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@ $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@
$(GTK_IN): FORCE $(GTK_IN): FORCE
...@@ -373,7 +376,13 @@ $(LIB_FILE): $(LIBPERF_IN) ...@@ -373,7 +376,13 @@ $(LIB_FILE): $(LIBPERF_IN)
LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ)
$(LIBTRACEEVENT): FORCE $(LIBTRACEEVENT): FORCE
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a plugins $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a
libtraceevent_plugins: FORCE
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins
$(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent-dynamic-list
$(LIBTRACEEVENT)-clean: $(LIBTRACEEVENT)-clean:
$(call QUIET_CLEAN, libtraceevent) $(call QUIET_CLEAN, libtraceevent)
...@@ -555,4 +564,5 @@ FORCE: ...@@ -555,4 +564,5 @@ FORCE:
.PHONY: all install clean config-clean strip install-gtk .PHONY: all install clean config-clean strip install-gtk
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE single_dep .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE single_dep
.PHONY: libtraceevent_plugins
...@@ -345,12 +345,9 @@ static int process_buildids(struct record *rec) ...@@ -345,12 +345,9 @@ static int process_buildids(struct record *rec)
struct perf_data_file *file = &rec->file; struct perf_data_file *file = &rec->file;
struct perf_session *session = rec->session; struct perf_session *session = rec->session;
u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); if (file->size == 0)
if (size == 0)
return 0; return 0;
file->size = size;
/* /*
* During this process, it'll load kernel map and replace the * During this process, it'll load kernel map and replace the
* dso->long_name to a real pathname it found. In this case * dso->long_name to a real pathname it found. In this case
...@@ -719,6 +716,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -719,6 +716,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
if (!err && !file->is_pipe) { if (!err && !file->is_pipe) {
rec->session->header.data_size += rec->bytes_written; rec->session->header.data_size += rec->bytes_written;
file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
if (!rec->no_buildid) { if (!rec->no_buildid) {
process_buildids(rec); process_buildids(rec);
......
This diff is collapsed.
...@@ -166,7 +166,7 @@ int test__dso_data(void) ...@@ -166,7 +166,7 @@ int test__dso_data(void)
free(buf); free(buf);
} }
dso__delete(dso); dso__put(dso);
unlink(file); unlink(file);
return 0; return 0;
} }
...@@ -226,7 +226,7 @@ static void dsos__delete(int cnt) ...@@ -226,7 +226,7 @@ static void dsos__delete(int cnt)
struct dso *dso = dsos[i]; struct dso *dso = dsos[i];
unlink(dso->name); unlink(dso->name);
dso__delete(dso); dso__put(dso);
} }
free(dsos); free(dsos);
......
...@@ -134,11 +134,15 @@ struct machine *setup_fake_machine(struct machines *machines) ...@@ -134,11 +134,15 @@ struct machine *setup_fake_machine(struct machines *machines)
sym = symbol__new(fsym->start, fsym->length, sym = symbol__new(fsym->start, fsym->length,
STB_GLOBAL, fsym->name); STB_GLOBAL, fsym->name);
if (sym == NULL) if (sym == NULL) {
dso__put(dso);
goto out; goto out;
}
symbols__insert(&dso->symbols[MAP__FUNCTION], sym); symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
} }
dso__put(dso);
} }
return machine; return machine;
......
...@@ -68,6 +68,7 @@ libperf-y += rblist.o ...@@ -68,6 +68,7 @@ libperf-y += rblist.o
libperf-y += intlist.o libperf-y += intlist.o
libperf-y += vdso.o libperf-y += vdso.o
libperf-y += stat.o libperf-y += stat.o
libperf-y += stat-shadow.o
libperf-y += record.o libperf-y += record.o
libperf-y += srcline.o libperf-y += srcline.o
libperf-y += data.o libperf-y += data.o
......
...@@ -889,8 +889,8 @@ struct dso *machine__findnew_kernel(struct machine *machine, const char *name, ...@@ -889,8 +889,8 @@ struct dso *machine__findnew_kernel(struct machine *machine, const char *name,
* Either one of the dso or name parameter must be non-NULL or the * Either one of the dso or name parameter must be non-NULL or the
* function will not work. * function will not work.
*/ */
static struct dso *dso__findlink_by_longname(struct rb_root *root, static struct dso *__dso__findlink_by_longname(struct rb_root *root,
struct dso *dso, const char *name) struct dso *dso, const char *name)
{ {
struct rb_node **p = &root->rb_node; struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL; struct rb_node *parent = NULL;
...@@ -937,10 +937,10 @@ static struct dso *dso__findlink_by_longname(struct rb_root *root, ...@@ -937,10 +937,10 @@ static struct dso *dso__findlink_by_longname(struct rb_root *root,
return NULL; return NULL;
} }
static inline struct dso * static inline struct dso *__dso__find_by_longname(struct rb_root *root,
dso__find_by_longname(const struct rb_root *root, const char *name) const char *name)
{ {
return dso__findlink_by_longname((struct rb_root *)root, NULL, name); return __dso__findlink_by_longname(root, NULL, name);
} }
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
...@@ -1049,6 +1049,7 @@ struct dso *dso__new(const char *name) ...@@ -1049,6 +1049,7 @@ struct dso *dso__new(const char *name)
INIT_LIST_HEAD(&dso->node); INIT_LIST_HEAD(&dso->node);
INIT_LIST_HEAD(&dso->data.open_entry); INIT_LIST_HEAD(&dso->data.open_entry);
pthread_mutex_init(&dso->lock, NULL); pthread_mutex_init(&dso->lock, NULL);
atomic_set(&dso->refcnt, 1);
} }
return dso; return dso;
...@@ -1083,6 +1084,19 @@ void dso__delete(struct dso *dso) ...@@ -1083,6 +1084,19 @@ void dso__delete(struct dso *dso)
free(dso); free(dso);
} }
struct dso *dso__get(struct dso *dso)
{
if (dso)
atomic_inc(&dso->refcnt);
return dso;
}
void dso__put(struct dso *dso)
{
if (dso && atomic_dec_and_test(&dso->refcnt))
dso__delete(dso);
}
void dso__set_build_id(struct dso *dso, void *build_id) void dso__set_build_id(struct dso *dso, void *build_id)
{ {
memcpy(dso->build_id, build_id, sizeof(dso->build_id)); memcpy(dso->build_id, build_id, sizeof(dso->build_id));
...@@ -1149,14 +1163,41 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) ...@@ -1149,14 +1163,41 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
return have_build_id; return have_build_id;
} }
void dsos__add(struct dsos *dsos, struct dso *dso) void __dsos__add(struct dsos *dsos, struct dso *dso)
{ {
list_add_tail(&dso->node, &dsos->head); list_add_tail(&dso->node, &dsos->head);
dso__findlink_by_longname(&dsos->root, dso, NULL); __dso__findlink_by_longname(&dsos->root, dso, NULL);
/*
* It is now in the linked list, grab a reference, then garbage collect
* this when needing memory, by looking at LRU dso instances in the
* list with atomic_read(&dso->refcnt) == 1, i.e. no references
* anywhere besides the one for the list, do, under a lock for the
* list: remove it from the list, then a dso__put(), that probably will
* be the last and will then call dso__delete(), end of life.
*
* That, or at the end of the 'struct machine' lifetime, when all
* 'struct dso' instances will be removed from the list, in
* dsos__exit(), if they have no other reference from some other data
* structure.
*
* E.g.: after processing a 'perf.data' file and storing references
* to objects instantiated while processing events, we will have
* references to the 'thread', 'map', 'dso' structs all from 'struct
* hist_entry' instances, but we may not need anything not referenced,
* so we might as well call machines__exit()/machines__delete() and
* garbage collect it.
*/
dso__get(dso);
} }
struct dso *dsos__find(const struct dsos *dsos, const char *name, void dsos__add(struct dsos *dsos, struct dso *dso)
bool cmp_short) {
pthread_rwlock_wrlock(&dsos->lock);
__dsos__add(dsos, dso);
pthread_rwlock_unlock(&dsos->lock);
}
struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
{ {
struct dso *pos; struct dso *pos;
...@@ -1166,15 +1207,24 @@ struct dso *dsos__find(const struct dsos *dsos, const char *name, ...@@ -1166,15 +1207,24 @@ struct dso *dsos__find(const struct dsos *dsos, const char *name,
return pos; return pos;
return NULL; return NULL;
} }
return dso__find_by_longname(&dsos->root, name); return __dso__find_by_longname(&dsos->root, name);
} }
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 *dso;
pthread_rwlock_rdlock(&dsos->lock);
dso = __dsos__find(dsos, name, cmp_short);
pthread_rwlock_unlock(&dsos->lock);
return dso;
}
struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
{ {
struct dso *dso = dso__new(name); struct dso *dso = dso__new(name);
if (dso != NULL) { if (dso != NULL) {
dsos__add(dsos, dso); __dsos__add(dsos, dso);
dso__set_basename(dso); dso__set_basename(dso);
} }
return dso; return dso;
...@@ -1182,9 +1232,18 @@ struct dso *dsos__addnew(struct dsos *dsos, const char *name) ...@@ -1182,9 +1232,18 @@ struct dso *dsos__addnew(struct dsos *dsos, const char *name)
struct dso *__dsos__findnew(struct dsos *dsos, const char *name) struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
{ {
struct dso *dso = dsos__find(dsos, name, false); struct dso *dso = __dsos__find(dsos, name, false);
return dso ? dso : __dsos__addnew(dsos, name);
}
return dso ? dso : dsos__addnew(dsos, name); struct dso *dsos__findnew(struct dsos *dsos, const char *name)
{
struct dso *dso;
pthread_rwlock_wrlock(&dsos->lock);
dso = dso__get(__dsos__findnew(dsos, name));
pthread_rwlock_unlock(&dsos->lock);
return dso;
} }
size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
......
#ifndef __PERF_DSO #ifndef __PERF_DSO
#define __PERF_DSO #define __PERF_DSO
#include <linux/atomic.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <stdbool.h> #include <stdbool.h>
#include <pthread.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include "map.h" #include "map.h"
...@@ -124,6 +126,7 @@ struct dso_cache { ...@@ -124,6 +126,7 @@ struct dso_cache {
struct dsos { struct dsos {
struct list_head head; struct list_head head;
struct rb_root root; /* rbtree root sorted by long name */ struct rb_root root; /* rbtree root sorted by long name */
pthread_rwlock_t lock;
}; };
struct auxtrace_cache; struct auxtrace_cache;
...@@ -177,7 +180,7 @@ struct dso { ...@@ -177,7 +180,7 @@ struct dso {
void *priv; void *priv;
u64 db_id; u64 db_id;
}; };
atomic_t refcnt;
char name[0]; char name[0];
}; };
...@@ -204,6 +207,17 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated); ...@@ -204,6 +207,17 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated);
int dso__name_len(const struct dso *dso); int dso__name_len(const struct dso *dso);
struct dso *dso__get(struct dso *dso);
void dso__put(struct dso *dso);
static inline void __dso__zput(struct dso **dso)
{
dso__put(*dso);
*dso = NULL;
}
#define dso__zput(dso) __dso__zput(&dso)
bool dso__loaded(const struct dso *dso, enum map_type type); bool dso__loaded(const struct dso *dso, enum map_type type);
bool dso__sorted_by_name(const struct dso *dso, enum map_type type); bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
...@@ -297,11 +311,13 @@ struct map *dso__new_map(const char *name); ...@@ -297,11 +311,13 @@ struct map *dso__new_map(const char *name);
struct dso *machine__findnew_kernel(struct machine *machine, const char *name, struct dso *machine__findnew_kernel(struct machine *machine, const char *name,
const char *short_name, int dso_type); const char *short_name, int dso_type);
void __dsos__add(struct dsos *dsos, struct dso *dso);
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__addnew(struct dsos *dsos, const char *name);
struct dso *dsos__find(const struct dsos *dsos, const char *name, struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short);
bool cmp_short); struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short);
struct dso *__dsos__findnew(struct dsos *dsos, const char *name); struct dso *__dsos__findnew(struct dsos *dsos, const char *name);
struct dso *dsos__findnew(struct dsos *dsos, const char *name);
bool __dsos__read_build_ids(struct list_head *head, bool with_hits); bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
......
...@@ -1277,6 +1277,7 @@ static int __event_process_build_id(struct build_id_event *bev, ...@@ -1277,6 +1277,7 @@ static int __event_process_build_id(struct build_id_event *bev,
sbuild_id); sbuild_id);
pr_debug("build id event received for %s: %s\n", pr_debug("build id event received for %s: %s\n",
dso->long_name, sbuild_id); dso->long_name, sbuild_id);
dso__put(dso);
} }
err = 0; err = 0;
......
...@@ -20,6 +20,7 @@ static void dsos__init(struct dsos *dsos) ...@@ -20,6 +20,7 @@ static void dsos__init(struct dsos *dsos)
{ {
INIT_LIST_HEAD(&dsos->head); INIT_LIST_HEAD(&dsos->head);
dsos->root = RB_ROOT; dsos->root = RB_ROOT;
pthread_rwlock_init(&dsos->lock, NULL);
} }
int machine__init(struct machine *machine, const char *root_dir, pid_t pid) int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
...@@ -81,15 +82,25 @@ struct machine *machine__new_host(void) ...@@ -81,15 +82,25 @@ struct machine *machine__new_host(void)
return NULL; return NULL;
} }
static void dsos__delete(struct dsos *dsos) static void dsos__purge(struct dsos *dsos)
{ {
struct dso *pos, *n; struct dso *pos, *n;
pthread_rwlock_wrlock(&dsos->lock);
list_for_each_entry_safe(pos, n, &dsos->head, node) { list_for_each_entry_safe(pos, n, &dsos->head, node) {
RB_CLEAR_NODE(&pos->rb_node); RB_CLEAR_NODE(&pos->rb_node);
list_del(&pos->node); list_del_init(&pos->node);
dso__delete(pos); dso__put(pos);
} }
pthread_rwlock_unlock(&dsos->lock);
}
static void dsos__exit(struct dsos *dsos)
{
dsos__purge(dsos);
pthread_rwlock_destroy(&dsos->lock);
} }
void machine__delete_threads(struct machine *machine) void machine__delete_threads(struct machine *machine)
...@@ -110,7 +121,7 @@ void machine__delete_threads(struct machine *machine) ...@@ -110,7 +121,7 @@ void machine__delete_threads(struct machine *machine)
void machine__exit(struct machine *machine) void machine__exit(struct machine *machine)
{ {
map_groups__exit(&machine->kmaps); map_groups__exit(&machine->kmaps);
dsos__delete(&machine->dsos); dsos__exit(&machine->dsos);
machine__exit_vdso(machine); machine__exit_vdso(machine);
zfree(&machine->root_dir); zfree(&machine->root_dir);
zfree(&machine->current_tid); zfree(&machine->current_tid);
...@@ -490,17 +501,19 @@ int machine__process_lost_samples_event(struct machine *machine __maybe_unused, ...@@ -490,17 +501,19 @@ int machine__process_lost_samples_event(struct machine *machine __maybe_unused,
return 0; return 0;
} }
static struct dso* static struct dso *machine__findnew_module_dso(struct machine *machine,
machine__module_dso(struct machine *machine, struct kmod_path *m, struct kmod_path *m,
const char *filename) const char *filename)
{ {
struct dso *dso; struct dso *dso;
dso = dsos__find(&machine->dsos, m->name, true); pthread_rwlock_wrlock(&machine->dsos.lock);
dso = __dsos__find(&machine->dsos, m->name, true);
if (!dso) { if (!dso) {
dso = dsos__addnew(&machine->dsos, m->name); dso = __dsos__addnew(&machine->dsos, m->name);
if (dso == NULL) if (dso == NULL)
return NULL; goto out_unlock;
if (machine__is_host(machine)) if (machine__is_host(machine))
dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
...@@ -515,6 +528,9 @@ machine__module_dso(struct machine *machine, struct kmod_path *m, ...@@ -515,6 +528,9 @@ machine__module_dso(struct machine *machine, struct kmod_path *m,
dso__set_long_name(dso, strdup(filename), true); dso__set_long_name(dso, strdup(filename), true);
} }
dso__get(dso);
out_unlock:
pthread_rwlock_unlock(&machine->dsos.lock);
return dso; return dso;
} }
...@@ -534,8 +550,8 @@ int machine__process_itrace_start_event(struct machine *machine __maybe_unused, ...@@ -534,8 +550,8 @@ int machine__process_itrace_start_event(struct machine *machine __maybe_unused,
return 0; return 0;
} }
struct map *machine__new_module(struct machine *machine, u64 start, struct map *machine__findnew_module_map(struct machine *machine, u64 start,
const char *filename) const char *filename)
{ {
struct map *map = NULL; struct map *map = NULL;
struct dso *dso; struct dso *dso;
...@@ -549,7 +565,7 @@ struct map *machine__new_module(struct machine *machine, u64 start, ...@@ -549,7 +565,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
if (map) if (map)
goto out; goto out;
dso = machine__module_dso(machine, &m, filename); dso = machine__findnew_module_dso(machine, &m, filename);
if (dso == NULL) if (dso == NULL)
goto out; goto out;
...@@ -1017,7 +1033,7 @@ static int machine__create_module(void *arg, const char *name, u64 start) ...@@ -1017,7 +1033,7 @@ static int machine__create_module(void *arg, const char *name, u64 start)
struct machine *machine = arg; struct machine *machine = arg;
struct map *map; struct map *map;
map = machine__new_module(machine, start, name); map = machine__findnew_module_map(machine, start, name);
if (map == NULL) if (map == NULL)
return -1; return -1;
...@@ -1140,8 +1156,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine, ...@@ -1140,8 +1156,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
strlen(kmmap_prefix) - 1) == 0; strlen(kmmap_prefix) - 1) == 0;
if (event->mmap.filename[0] == '/' || if (event->mmap.filename[0] == '/' ||
(!is_kernel_mmap && event->mmap.filename[0] == '[')) { (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
map = machine__new_module(machine, event->mmap.start, map = machine__findnew_module_map(machine, event->mmap.start,
event->mmap.filename); event->mmap.filename);
if (map == NULL) if (map == NULL)
goto out_problem; goto out_problem;
...@@ -1156,6 +1172,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine, ...@@ -1156,6 +1172,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
struct dso *kernel = NULL; struct dso *kernel = NULL;
struct dso *dso; struct dso *dso;
pthread_rwlock_rdlock(&machine->dsos.lock);
list_for_each_entry(dso, &machine->dsos.head, node) { list_for_each_entry(dso, &machine->dsos.head, node) {
/* /*
...@@ -1184,14 +1202,18 @@ static int machine__process_kernel_mmap_event(struct machine *machine, ...@@ -1184,14 +1202,18 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
break; break;
} }
pthread_rwlock_unlock(&machine->dsos.lock);
if (kernel == NULL) if (kernel == NULL)
kernel = machine__findnew_dso(machine, kmmap_prefix); kernel = machine__findnew_dso(machine, kmmap_prefix);
if (kernel == NULL) if (kernel == NULL)
goto out_problem; goto out_problem;
kernel->kernel = kernel_type; kernel->kernel = kernel_type;
if (__machine__create_kernel_maps(machine, kernel) < 0) if (__machine__create_kernel_maps(machine, kernel) < 0) {
dso__put(kernel);
goto out_problem; goto out_problem;
}
if (strstr(kernel->long_name, "vmlinux")) if (strstr(kernel->long_name, "vmlinux"))
dso__set_short_name(kernel, "[kernel.vmlinux]", false); dso__set_short_name(kernel, "[kernel.vmlinux]", false);
...@@ -1948,5 +1970,5 @@ int machine__get_kernel_start(struct machine *machine) ...@@ -1948,5 +1970,5 @@ int machine__get_kernel_start(struct machine *machine)
struct dso *machine__findnew_dso(struct machine *machine, const char *filename) struct dso *machine__findnew_dso(struct machine *machine, const char *filename)
{ {
return __dsos__findnew(&machine->dsos, filename); return dsos__findnew(&machine->dsos, filename);
} }
...@@ -189,8 +189,8 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *machine, ...@@ -189,8 +189,8 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *machine,
filter); filter);
} }
struct map *machine__new_module(struct machine *machine, u64 start, struct map *machine__findnew_module_map(struct machine *machine, u64 start,
const char *filename); const char *filename);
int machine__load_kallsyms(struct machine *machine, const char *filename, int machine__load_kallsyms(struct machine *machine, const char *filename,
enum map_type type, symbol_filter_t filter); enum map_type type, symbol_filter_t filter);
......
...@@ -132,7 +132,7 @@ void map__init(struct map *map, enum map_type type, ...@@ -132,7 +132,7 @@ void map__init(struct map *map, enum map_type type,
map->end = end; map->end = end;
map->pgoff = pgoff; map->pgoff = pgoff;
map->reloc = 0; map->reloc = 0;
map->dso = dso; map->dso = dso__get(dso);
map->map_ip = map__map_ip; map->map_ip = map__map_ip;
map->unmap_ip = map__unmap_ip; map->unmap_ip = map__unmap_ip;
RB_CLEAR_NODE(&map->rb_node); RB_CLEAR_NODE(&map->rb_node);
...@@ -198,6 +198,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, ...@@ -198,6 +198,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
if (type != MAP__FUNCTION) if (type != MAP__FUNCTION)
dso__set_loaded(dso, map->type); dso__set_loaded(dso, map->type);
} }
dso__put(dso);
} }
return map; return map;
out_delete: out_delete:
...@@ -224,9 +225,15 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type) ...@@ -224,9 +225,15 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
return map; return map;
} }
void map__delete(struct map *map) static void map__exit(struct map *map)
{ {
BUG_ON(!RB_EMPTY_NODE(&map->rb_node)); BUG_ON(!RB_EMPTY_NODE(&map->rb_node));
dso__zput(map->dso);
}
void map__delete(struct map *map)
{
map__exit(map);
free(map); free(map);
} }
......
...@@ -168,7 +168,7 @@ static struct map *kernel_get_module_map(const char *module) ...@@ -168,7 +168,7 @@ static struct map *kernel_get_module_map(const char *module)
/* A file path -- this is an offline module */ /* A file path -- this is an offline module */
if (module && strchr(module, '/')) if (module && strchr(module, '/'))
return machine__new_module(host_machine, 0, module); return machine__findnew_module_map(host_machine, 0, module);
if (!module) if (!module)
module = "kernel"; module = "kernel";
......
...@@ -130,7 +130,7 @@ struct debuginfo *debuginfo__new(const char *path) ...@@ -130,7 +130,7 @@ struct debuginfo *debuginfo__new(const char *path)
continue; continue;
dinfo = __debuginfo__new(buf); dinfo = __debuginfo__new(buf);
} }
dso__delete(dso); dso__put(dso);
out: out:
/* if failed to open all distro debuginfo, open given binary */ /* if failed to open all distro debuginfo, open given binary */
......
This diff is collapsed.
#include <math.h> #include <math.h>
#include "stat.h" #include "stat.h"
#include "evsel.h"
void update_stats(struct stats *stats, u64 val) void update_stats(struct stats *stats, u64 val)
{ {
...@@ -61,3 +61,36 @@ double rel_stddev_stats(double stddev, double avg) ...@@ -61,3 +61,36 @@ double rel_stddev_stats(double stddev, double avg)
return pct; return pct;
} }
bool __perf_evsel_stat__is(struct perf_evsel *evsel,
enum perf_stat_evsel_id id)
{
struct perf_stat *ps = evsel->priv;
return ps->id == id;
}
#define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
ID(NONE, x),
ID(CYCLES_IN_TX, cpu/cycles-t/),
ID(TRANSACTION_START, cpu/tx-start/),
ID(ELISION_START, cpu/el-start/),
ID(CYCLES_IN_TX_CP, cpu/cycles-ct/),
};
#undef ID
void perf_stat_evsel_id_init(struct perf_evsel *evsel)
{
struct perf_stat *ps = evsel->priv;
int i;
/* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) {
if (!strcmp(perf_evsel__name(evsel), id_str[i])) {
ps->id = i;
break;
}
}
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define __PERF_STATS_H #define __PERF_STATS_H
#include <linux/types.h> #include <linux/types.h>
#include <stdio.h>
struct stats struct stats
{ {
...@@ -9,6 +10,27 @@ struct stats ...@@ -9,6 +10,27 @@ struct stats
u64 max, min; u64 max, min;
}; };
enum perf_stat_evsel_id {
PERF_STAT_EVSEL_ID__NONE = 0,
PERF_STAT_EVSEL_ID__CYCLES_IN_TX,
PERF_STAT_EVSEL_ID__TRANSACTION_START,
PERF_STAT_EVSEL_ID__ELISION_START,
PERF_STAT_EVSEL_ID__CYCLES_IN_TX_CP,
PERF_STAT_EVSEL_ID__MAX,
};
struct perf_stat {
struct stats res_stats[3];
enum perf_stat_evsel_id id;
};
enum aggr_mode {
AGGR_NONE,
AGGR_GLOBAL,
AGGR_SOCKET,
AGGR_CORE,
};
void update_stats(struct stats *stats, u64 val); void update_stats(struct stats *stats, u64 val);
double avg_stats(struct stats *stats); double avg_stats(struct stats *stats);
double stddev_stats(struct stats *stats); double stddev_stats(struct stats *stats);
...@@ -22,4 +44,22 @@ static inline void init_stats(struct stats *stats) ...@@ -22,4 +44,22 @@ static inline void init_stats(struct stats *stats)
stats->min = (u64) -1; stats->min = (u64) -1;
stats->max = 0; stats->max = 0;
} }
struct perf_evsel;
bool __perf_evsel_stat__is(struct perf_evsel *evsel,
enum perf_stat_evsel_id id);
#define perf_stat_evsel__is(evsel, id) \
__perf_evsel_stat__is(evsel, PERF_STAT_EVSEL_ID__ ## id)
void perf_stat_evsel_id_init(struct perf_evsel *evsel);
extern struct stats walltime_nsecs_stats;
void perf_stat__reset_shadow_stats(void);
void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
int cpu);
void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
double avg, int cpu, enum aggr_mode aggr);
#endif #endif
...@@ -1016,7 +1016,7 @@ int dso__load_sym(struct dso *dso, struct map *map, ...@@ -1016,7 +1016,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
curr_map = map__new2(start, curr_dso, curr_map = map__new2(start, curr_dso,
map->type); map->type);
if (curr_map == NULL) { if (curr_map == NULL) {
dso__delete(curr_dso); dso__put(curr_dso);
goto out_elf_end; goto out_elf_end;
} }
if (adjust_kernel_syms) { if (adjust_kernel_syms) {
......
...@@ -786,7 +786,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, ...@@ -786,7 +786,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
curr_map = map__new2(pos->start, ndso, map->type); curr_map = map__new2(pos->start, ndso, map->type);
if (curr_map == NULL) { if (curr_map == NULL) {
dso__delete(ndso); dso__put(ndso);
return -1; return -1;
} }
...@@ -1364,7 +1364,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, ...@@ -1364,7 +1364,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
/* /*
* kernel modules know their symtab type - it's set when * kernel modules know their symtab type - it's set when
* creating a module dso in machine__new_module(). * creating a module dso in machine__findnew_module_map().
*/ */
return kmod && dso->symtab_type == type; return kmod && dso->symtab_type == type;
......
...@@ -120,14 +120,14 @@ void machine__exit_vdso(struct machine *machine) ...@@ -120,14 +120,14 @@ void machine__exit_vdso(struct machine *machine)
zfree(&machine->vdso_info); zfree(&machine->vdso_info);
} }
static struct dso *machine__addnew_vdso(struct machine *machine, const char *short_name, static struct dso *__machine__addnew_vdso(struct machine *machine, const char *short_name,
const char *long_name) const char *long_name)
{ {
struct dso *dso; struct dso *dso;
dso = dso__new(short_name); dso = dso__new(short_name);
if (dso != NULL) { if (dso != NULL) {
dsos__add(&machine->dsos, dso); __dsos__add(&machine->dsos, dso);
dso__set_long_name(dso, long_name, false); dso__set_long_name(dso, long_name, false);
} }
...@@ -230,27 +230,31 @@ static const char *vdso__get_compat_file(struct vdso_file *vdso_file) ...@@ -230,27 +230,31 @@ static const char *vdso__get_compat_file(struct vdso_file *vdso_file)
return vdso_file->temp_file_name; return vdso_file->temp_file_name;
} }
static struct dso *vdso__findnew_compat(struct machine *machine, static struct dso *__machine__findnew_compat(struct machine *machine,
struct vdso_file *vdso_file) struct vdso_file *vdso_file)
{ {
const char *file_name; const char *file_name;
struct dso *dso; struct dso *dso;
dso = dsos__find(&machine->dsos, vdso_file->dso_name, true); pthread_rwlock_wrlock(&machine->dsos.lock);
dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true);
if (dso) if (dso)
return dso; goto out_unlock;
file_name = vdso__get_compat_file(vdso_file); file_name = vdso__get_compat_file(vdso_file);
if (!file_name) if (!file_name)
return NULL; goto out_unlock;
return machine__addnew_vdso(machine, vdso_file->dso_name, file_name); dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name);
out_unlock:
pthread_rwlock_unlock(&machine->dsos.lock);
return dso;
} }
static int machine__findnew_vdso_compat(struct machine *machine, static int __machine__findnew_vdso_compat(struct machine *machine,
struct thread *thread, struct thread *thread,
struct vdso_info *vdso_info, struct vdso_info *vdso_info,
struct dso **dso) struct dso **dso)
{ {
enum dso_type dso_type; enum dso_type dso_type;
...@@ -267,10 +271,10 @@ static int machine__findnew_vdso_compat(struct machine *machine, ...@@ -267,10 +271,10 @@ static int machine__findnew_vdso_compat(struct machine *machine,
switch (dso_type) { switch (dso_type) {
case DSO__TYPE_32BIT: case DSO__TYPE_32BIT:
*dso = vdso__findnew_compat(machine, &vdso_info->vdso32); *dso = __machine__findnew_compat(machine, &vdso_info->vdso32);
return 1; return 1;
case DSO__TYPE_X32BIT: case DSO__TYPE_X32BIT:
*dso = vdso__findnew_compat(machine, &vdso_info->vdsox32); *dso = __machine__findnew_compat(machine, &vdso_info->vdsox32);
return 1; return 1;
case DSO__TYPE_UNKNOWN: case DSO__TYPE_UNKNOWN:
case DSO__TYPE_64BIT: case DSO__TYPE_64BIT:
...@@ -285,31 +289,33 @@ struct dso *machine__findnew_vdso(struct machine *machine, ...@@ -285,31 +289,33 @@ struct dso *machine__findnew_vdso(struct machine *machine,
struct thread *thread __maybe_unused) struct thread *thread __maybe_unused)
{ {
struct vdso_info *vdso_info; struct vdso_info *vdso_info;
struct dso *dso; struct dso *dso = NULL;
pthread_rwlock_wrlock(&machine->dsos.lock);
if (!machine->vdso_info) if (!machine->vdso_info)
machine->vdso_info = vdso_info__new(); machine->vdso_info = vdso_info__new();
vdso_info = machine->vdso_info; vdso_info = machine->vdso_info;
if (!vdso_info) if (!vdso_info)
return NULL; goto out_unlock;
#if BITS_PER_LONG == 64 #if BITS_PER_LONG == 64
if (machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso))
return dso; goto out_unlock;
#endif #endif
dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true); dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
if (!dso) { if (!dso) {
char *file; char *file;
file = get_file(&vdso_info->vdso); file = get_file(&vdso_info->vdso);
if (!file) if (file)
return NULL; dso = __machine__addnew_vdso(machine, DSO__NAME_VDSO, file);
dso = machine__addnew_vdso(machine, DSO__NAME_VDSO, file);
} }
out_unlock:
dso__get(dso);
pthread_rwlock_unlock(&machine->dsos.lock);
return dso; return dso;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment