perf tools: Reference count struct thread

We need to do that to stop accumulating entries in the dead_threads
linked list, i.e. we were keeping references to threads in struct hists
that continue to exist even after a thread exited and was removed from
the machine threads rbtree.

We still keep the dead_threads list, but just for debugging, allowing us
to iterate at any given point over the threads that still are referenced
by things like struct hist_entry.

Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: David Ahern <dsahern@gmail.com>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-3ejvfyed0r7ue61dkurzjux4@git.kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 2ed11312
...@@ -831,7 +831,7 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) ...@@ -831,7 +831,7 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
return -1; return -1;
} }
atoms->thread = thread; atoms->thread = thread__get(thread);
INIT_LIST_HEAD(&atoms->work_list); INIT_LIST_HEAD(&atoms->work_list);
__thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid); __thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid);
return 0; return 0;
......
...@@ -1741,7 +1741,10 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -1741,7 +1741,10 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
} else } else
ttrace->entry_pending = true; ttrace->entry_pending = true;
trace->current = thread; if (trace->current != thread) {
thread__put(trace->current);
trace->current = thread__get(thread);
}
return 0; return 0;
} }
...@@ -2274,6 +2277,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -2274,6 +2277,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
} }
out_disable: out_disable:
thread__zput(trace->current);
perf_evlist__disable(evlist); perf_evlist__disable(evlist);
if (!err) { if (!err) {
......
...@@ -1467,7 +1467,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1467,7 +1467,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
perf_hpp__set_user_width(symbol_conf.col_width_list_str); perf_hpp__set_user_width(symbol_conf.col_width_list_str);
while (1) { while (1) {
const struct thread *thread = NULL; struct thread *thread = NULL;
const struct dso *dso = NULL; const struct dso *dso = NULL;
int choice = 0, int choice = 0,
annotate = -2, zoom_dso = -2, zoom_thread = -2, annotate = -2, zoom_dso = -2, zoom_thread = -2,
...@@ -1754,13 +1754,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1754,13 +1754,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
pstack__remove(fstack, &browser->hists->thread_filter); pstack__remove(fstack, &browser->hists->thread_filter);
zoom_out_thread: zoom_out_thread:
ui_helpline__pop(); ui_helpline__pop();
browser->hists->thread_filter = NULL; thread__zput(browser->hists->thread_filter);
perf_hpp__set_elide(HISTC_THREAD, false); perf_hpp__set_elide(HISTC_THREAD, false);
} else { } else {
ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
thread->comm_set ? thread__comm_str(thread) : "", thread->comm_set ? thread__comm_str(thread) : "",
thread->tid); thread->tid);
browser->hists->thread_filter = thread; browser->hists->thread_filter = thread__get(thread);
perf_hpp__set_elide(HISTC_THREAD, false); perf_hpp__set_elide(HISTC_THREAD, false);
pstack__push(fstack, &browser->hists->thread_filter); pstack__push(fstack, &browser->hists->thread_filter);
} }
......
...@@ -61,8 +61,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, ...@@ -61,8 +61,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
if (thread) { if (thread) {
rb_erase(&thread->rb_node, &machine->threads); rb_erase(&thread->rb_node, &machine->threads);
machine->last_match = NULL; if (machine->last_match == thread)
thread__delete(thread); thread__zput(machine->last_match);
thread__put(thread);
} }
return 0; return 0;
......
...@@ -355,6 +355,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, ...@@ -355,6 +355,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
callchain_init(he->callchain); callchain_init(he->callchain);
INIT_LIST_HEAD(&he->pairs.node); INIT_LIST_HEAD(&he->pairs.node);
thread__get(he->thread);
} }
return he; return he;
...@@ -941,6 +942,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) ...@@ -941,6 +942,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
void hist_entry__delete(struct hist_entry *he) void hist_entry__delete(struct hist_entry *he)
{ {
thread__zput(he->thread);
zfree(&he->branch_info); zfree(&he->branch_info);
zfree(&he->mem_info); zfree(&he->mem_info);
zfree(&he->stat_acc); zfree(&he->stat_acc);
......
...@@ -60,7 +60,7 @@ struct hists { ...@@ -60,7 +60,7 @@ struct hists {
struct rb_root entries_collapsed; struct rb_root entries_collapsed;
u64 nr_entries; u64 nr_entries;
u64 nr_non_filtered_entries; u64 nr_non_filtered_entries;
const struct thread *thread_filter; struct thread *thread_filter;
const struct dso *dso_filter; const struct dso *dso_filter;
const char *uid_filter_str; const char *uid_filter_str;
const char *symbol_filter_str; const char *symbol_filter_str;
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "unwind.h" #include "unwind.h"
#include "linux/hash.h" #include "linux/hash.h"
static void machine__remove_thread(struct machine *machine, struct thread *th);
static void dsos__init(struct dsos *dsos) static void dsos__init(struct dsos *dsos)
{ {
INIT_LIST_HEAD(&dsos->head); INIT_LIST_HEAD(&dsos->head);
...@@ -89,16 +91,6 @@ static void dsos__delete(struct dsos *dsos) ...@@ -89,16 +91,6 @@ static void dsos__delete(struct dsos *dsos)
} }
} }
void machine__delete_dead_threads(struct machine *machine)
{
struct thread *n, *t;
list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
list_del(&t->node);
thread__delete(t);
}
}
void machine__delete_threads(struct machine *machine) void machine__delete_threads(struct machine *machine)
{ {
struct rb_node *nd = rb_first(&machine->threads); struct rb_node *nd = rb_first(&machine->threads);
...@@ -106,9 +98,8 @@ void machine__delete_threads(struct machine *machine) ...@@ -106,9 +98,8 @@ void machine__delete_threads(struct machine *machine)
while (nd) { while (nd) {
struct thread *t = rb_entry(nd, struct thread, rb_node); struct thread *t = rb_entry(nd, struct thread, rb_node);
rb_erase(&t->rb_node, &machine->threads);
nd = rb_next(nd); nd = rb_next(nd);
thread__delete(t); machine__remove_thread(machine, t);
} }
} }
...@@ -361,9 +352,13 @@ static struct thread *__machine__findnew_thread(struct machine *machine, ...@@ -361,9 +352,13 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
* the full rbtree: * the full rbtree:
*/ */
th = machine->last_match; th = machine->last_match;
if (th && th->tid == tid) { if (th != NULL) {
machine__update_thread_pid(machine, th, pid); if (th->tid == tid) {
return th; machine__update_thread_pid(machine, th, pid);
return th;
}
thread__zput(machine->last_match);
} }
while (*p != NULL) { while (*p != NULL) {
...@@ -371,7 +366,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, ...@@ -371,7 +366,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
th = rb_entry(parent, struct thread, rb_node); th = rb_entry(parent, struct thread, rb_node);
if (th->tid == tid) { if (th->tid == tid) {
machine->last_match = th; machine->last_match = thread__get(th);
machine__update_thread_pid(machine, th, pid); machine__update_thread_pid(machine, th, pid);
return th; return th;
} }
...@@ -403,8 +398,11 @@ static struct thread *__machine__findnew_thread(struct machine *machine, ...@@ -403,8 +398,11 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
thread__delete(th); thread__delete(th);
return NULL; return NULL;
} }
/*
machine->last_match = th; * It is now in the rbtree, get a ref
*/
thread__get(th);
machine->last_match = thread__get(th);
} }
return th; return th;
...@@ -1238,13 +1236,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event ...@@ -1238,13 +1236,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
static void machine__remove_thread(struct machine *machine, struct thread *th) static void machine__remove_thread(struct machine *machine, struct thread *th)
{ {
machine->last_match = NULL; if (machine->last_match == th)
thread__zput(machine->last_match);
rb_erase(&th->rb_node, &machine->threads); rb_erase(&th->rb_node, &machine->threads);
/* /*
* We may have references to this thread, for instance in some hist_entry * Move it first to the dead_threads list, then drop the reference,
* instances, so just move them to a separate list. * if this is the last reference, then the thread__delete destructor
* will be called and we will remove it from the dead_threads list.
*/ */
list_add_tail(&th->node, &machine->dead_threads); list_add_tail(&th->node, &machine->dead_threads);
thread__put(th);
} }
int machine__process_fork_event(struct machine *machine, union perf_event *event, int machine__process_fork_event(struct machine *machine, union perf_event *event,
......
...@@ -118,7 +118,6 @@ void machines__set_comm_exec(struct machines *machines, bool comm_exec); ...@@ -118,7 +118,6 @@ void machines__set_comm_exec(struct machines *machines, bool comm_exec);
struct machine *machine__new_host(void); struct machine *machine__new_host(void);
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);
void machine__exit(struct machine *machine); void machine__exit(struct machine *machine);
void machine__delete_dead_threads(struct machine *machine);
void machine__delete_threads(struct machine *machine); void machine__delete_threads(struct machine *machine);
void machine__delete(struct machine *machine); void machine__delete(struct machine *machine);
......
...@@ -138,11 +138,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file, ...@@ -138,11 +138,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
return NULL; return NULL;
} }
static void perf_session__delete_dead_threads(struct perf_session *session)
{
machine__delete_dead_threads(&session->machines.host);
}
static void perf_session__delete_threads(struct perf_session *session) static void perf_session__delete_threads(struct perf_session *session)
{ {
machine__delete_threads(&session->machines.host); machine__delete_threads(&session->machines.host);
...@@ -167,7 +162,6 @@ static void perf_session_env__delete(struct perf_session_env *env) ...@@ -167,7 +162,6 @@ static void perf_session_env__delete(struct perf_session_env *env)
void perf_session__delete(struct perf_session *session) void perf_session__delete(struct perf_session *session)
{ {
perf_session__destroy_kernel_maps(session); perf_session__destroy_kernel_maps(session);
perf_session__delete_dead_threads(session);
perf_session__delete_threads(session); perf_session__delete_threads(session);
perf_session_env__delete(&session->header.env); perf_session_env__delete(&session->header.env);
machines__exit(&session->machines); machines__exit(&session->machines);
......
...@@ -82,6 +82,20 @@ void thread__delete(struct thread *thread) ...@@ -82,6 +82,20 @@ void thread__delete(struct thread *thread)
free(thread); free(thread);
} }
struct thread *thread__get(struct thread *thread)
{
++thread->refcnt;
return thread;
}
void thread__put(struct thread *thread)
{
if (thread && --thread->refcnt == 0) {
list_del_init(&thread->node);
thread__delete(thread);
}
}
struct comm *thread__comm(const struct thread *thread) struct comm *thread__comm(const struct thread *thread)
{ {
if (list_empty(&thread->comm_list)) if (list_empty(&thread->comm_list))
......
...@@ -20,6 +20,7 @@ struct thread { ...@@ -20,6 +20,7 @@ struct thread {
pid_t tid; pid_t tid;
pid_t ppid; pid_t ppid;
int cpu; int cpu;
int refcnt;
char shortname[3]; char shortname[3];
bool comm_set; bool comm_set;
bool dead; /* if set thread has exited */ bool dead; /* if set thread has exited */
...@@ -37,6 +38,18 @@ struct comm; ...@@ -37,6 +38,18 @@ struct comm;
struct thread *thread__new(pid_t pid, pid_t tid); struct thread *thread__new(pid_t pid, pid_t tid);
int thread__init_map_groups(struct thread *thread, struct machine *machine); int thread__init_map_groups(struct thread *thread, struct machine *machine);
void thread__delete(struct thread *thread); void thread__delete(struct thread *thread);
struct thread *thread__get(struct thread *thread);
void thread__put(struct thread *thread);
static inline void __thread__zput(struct thread **thread)
{
thread__put(*thread);
*thread = NULL;
}
#define thread__zput(thread) __thread__zput(&thread)
static inline void thread__exited(struct thread *thread) static inline void thread__exited(struct thread *thread)
{ {
thread->dead = true; thread->dead = true;
......
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