aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2015-03-02 20:21:35 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-03-02 22:17:08 -0500
commitf3b623b8490af7a9b819cbcf2d99ab4597ece94b (patch)
tree13926b268a431ab99d8518b0b9c9d4c7c124c188 /tools/perf/util
parent2ed11312eb19506c027e7cac039994ad42a9cb2c (diff)
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.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/build-id.c5
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/machine.c44
-rw-r--r--tools/perf/util/machine.h1
-rw-r--r--tools/perf/util/session.c6
-rw-r--r--tools/perf/util/thread.c14
-rw-r--r--tools/perf/util/thread.h13
8 files changed, 56 insertions, 31 deletions
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index ffdc338df925..a19674666b4e 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -61,8 +61,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
61 61
62 if (thread) { 62 if (thread) {
63 rb_erase(&thread->rb_node, &machine->threads); 63 rb_erase(&thread->rb_node, &machine->threads);
64 machine->last_match = NULL; 64 if (machine->last_match == thread)
65 thread__delete(thread); 65 thread__zput(machine->last_match);
66 thread__put(thread);
66 } 67 }
67 68
68 return 0; 69 return 0;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 70b48a65064c..95f5ab707b74 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -355,6 +355,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
355 callchain_init(he->callchain); 355 callchain_init(he->callchain);
356 356
357 INIT_LIST_HEAD(&he->pairs.node); 357 INIT_LIST_HEAD(&he->pairs.node);
358 thread__get(he->thread);
358 } 359 }
359 360
360 return he; 361 return he;
@@ -941,6 +942,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
941 942
942void hist_entry__delete(struct hist_entry *he) 943void hist_entry__delete(struct hist_entry *he)
943{ 944{
945 thread__zput(he->thread);
944 zfree(&he->branch_info); 946 zfree(&he->branch_info);
945 zfree(&he->mem_info); 947 zfree(&he->mem_info);
946 zfree(&he->stat_acc); 948 zfree(&he->stat_acc);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2b690d028907..e988c9fcd1bc 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -60,7 +60,7 @@ struct hists {
60 struct rb_root entries_collapsed; 60 struct rb_root entries_collapsed;
61 u64 nr_entries; 61 u64 nr_entries;
62 u64 nr_non_filtered_entries; 62 u64 nr_non_filtered_entries;
63 const struct thread *thread_filter; 63 struct thread *thread_filter;
64 const struct dso *dso_filter; 64 const struct dso *dso_filter;
65 const char *uid_filter_str; 65 const char *uid_filter_str;
66 const char *symbol_filter_str; 66 const char *symbol_filter_str;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 9e0f60a7e7b3..24f8c978cfd4 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -14,6 +14,8 @@
14#include "unwind.h" 14#include "unwind.h"
15#include "linux/hash.h" 15#include "linux/hash.h"
16 16
17static void machine__remove_thread(struct machine *machine, struct thread *th);
18
17static void dsos__init(struct dsos *dsos) 19static void dsos__init(struct dsos *dsos)
18{ 20{
19 INIT_LIST_HEAD(&dsos->head); 21 INIT_LIST_HEAD(&dsos->head);
@@ -89,16 +91,6 @@ static void dsos__delete(struct dsos *dsos)
89 } 91 }
90} 92}
91 93
92void machine__delete_dead_threads(struct machine *machine)
93{
94 struct thread *n, *t;
95
96 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
97 list_del(&t->node);
98 thread__delete(t);
99 }
100}
101
102void machine__delete_threads(struct machine *machine) 94void machine__delete_threads(struct machine *machine)
103{ 95{
104 struct rb_node *nd = rb_first(&machine->threads); 96 struct rb_node *nd = rb_first(&machine->threads);
@@ -106,9 +98,8 @@ void machine__delete_threads(struct machine *machine)
106 while (nd) { 98 while (nd) {
107 struct thread *t = rb_entry(nd, struct thread, rb_node); 99 struct thread *t = rb_entry(nd, struct thread, rb_node);
108 100
109 rb_erase(&t->rb_node, &machine->threads);
110 nd = rb_next(nd); 101 nd = rb_next(nd);
111 thread__delete(t); 102 machine__remove_thread(machine, t);
112 } 103 }
113} 104}
114 105
@@ -361,9 +352,13 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
361 * the full rbtree: 352 * the full rbtree:
362 */ 353 */
363 th = machine->last_match; 354 th = machine->last_match;
364 if (th && th->tid == tid) { 355 if (th != NULL) {
365 machine__update_thread_pid(machine, th, pid); 356 if (th->tid == tid) {
366 return th; 357 machine__update_thread_pid(machine, th, pid);
358 return th;
359 }
360
361 thread__zput(machine->last_match);
367 } 362 }
368 363
369 while (*p != NULL) { 364 while (*p != NULL) {
@@ -371,7 +366,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
371 th = rb_entry(parent, struct thread, rb_node); 366 th = rb_entry(parent, struct thread, rb_node);
372 367
373 if (th->tid == tid) { 368 if (th->tid == tid) {
374 machine->last_match = th; 369 machine->last_match = thread__get(th);
375 machine__update_thread_pid(machine, th, pid); 370 machine__update_thread_pid(machine, th, pid);
376 return th; 371 return th;
377 } 372 }
@@ -403,8 +398,11 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
403 thread__delete(th); 398 thread__delete(th);
404 return NULL; 399 return NULL;
405 } 400 }
406 401 /*
407 machine->last_match = th; 402 * It is now in the rbtree, get a ref
403 */
404 thread__get(th);
405 machine->last_match = thread__get(th);
408 } 406 }
409 407
410 return th; 408 return th;
@@ -1238,13 +1236,17 @@ out_problem:
1238 1236
1239static void machine__remove_thread(struct machine *machine, struct thread *th) 1237static void machine__remove_thread(struct machine *machine, struct thread *th)
1240{ 1238{
1241 machine->last_match = NULL; 1239 if (machine->last_match == th)
1240 thread__zput(machine->last_match);
1241
1242 rb_erase(&th->rb_node, &machine->threads); 1242 rb_erase(&th->rb_node, &machine->threads);
1243 /* 1243 /*
1244 * We may have references to this thread, for instance in some hist_entry 1244 * Move it first to the dead_threads list, then drop the reference,
1245 * instances, so just move them to a separate list. 1245 * if this is the last reference, then the thread__delete destructor
1246 * will be called and we will remove it from the dead_threads list.
1246 */ 1247 */
1247 list_add_tail(&th->node, &machine->dead_threads); 1248 list_add_tail(&th->node, &machine->dead_threads);
1249 thread__put(th);
1248} 1250}
1249 1251
1250int machine__process_fork_event(struct machine *machine, union perf_event *event, 1252int machine__process_fork_event(struct machine *machine, union perf_event *event,
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index e8b7779a0a3f..e2faf3b47e7b 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -118,7 +118,6 @@ void machines__set_comm_exec(struct machines *machines, bool comm_exec);
118struct machine *machine__new_host(void); 118struct machine *machine__new_host(void);
119int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 119int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
120void machine__exit(struct machine *machine); 120void machine__exit(struct machine *machine);
121void machine__delete_dead_threads(struct machine *machine);
122void machine__delete_threads(struct machine *machine); 121void machine__delete_threads(struct machine *machine);
123void machine__delete(struct machine *machine); 122void machine__delete(struct machine *machine);
124 123
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index e4f166981ff0..ed4e5cf2bd9d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -138,11 +138,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
138 return NULL; 138 return NULL;
139} 139}
140 140
141static void perf_session__delete_dead_threads(struct perf_session *session)
142{
143 machine__delete_dead_threads(&session->machines.host);
144}
145
146static void perf_session__delete_threads(struct perf_session *session) 141static void perf_session__delete_threads(struct perf_session *session)
147{ 142{
148 machine__delete_threads(&session->machines.host); 143 machine__delete_threads(&session->machines.host);
@@ -167,7 +162,6 @@ static void perf_session_env__delete(struct perf_session_env *env)
167void perf_session__delete(struct perf_session *session) 162void perf_session__delete(struct perf_session *session)
168{ 163{
169 perf_session__destroy_kernel_maps(session); 164 perf_session__destroy_kernel_maps(session);
170 perf_session__delete_dead_threads(session);
171 perf_session__delete_threads(session); 165 perf_session__delete_threads(session);
172 perf_session_env__delete(&session->header.env); 166 perf_session_env__delete(&session->header.env);
173 machines__exit(&session->machines); 167 machines__exit(&session->machines);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 9ebc8b1f9be5..a5dbba95107f 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -82,6 +82,20 @@ void thread__delete(struct thread *thread)
82 free(thread); 82 free(thread);
83} 83}
84 84
85struct thread *thread__get(struct thread *thread)
86{
87 ++thread->refcnt;
88 return thread;
89}
90
91void thread__put(struct thread *thread)
92{
93 if (thread && --thread->refcnt == 0) {
94 list_del_init(&thread->node);
95 thread__delete(thread);
96 }
97}
98
85struct comm *thread__comm(const struct thread *thread) 99struct comm *thread__comm(const struct thread *thread)
86{ 100{
87 if (list_empty(&thread->comm_list)) 101 if (list_empty(&thread->comm_list))
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 160fd066a7d1..783b6688d2f7 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -20,6 +20,7 @@ struct thread {
20 pid_t tid; 20 pid_t tid;
21 pid_t ppid; 21 pid_t ppid;
22 int cpu; 22 int cpu;
23 int refcnt;
23 char shortname[3]; 24 char shortname[3];
24 bool comm_set; 25 bool comm_set;
25 bool dead; /* if set thread has exited */ 26 bool dead; /* if set thread has exited */
@@ -37,6 +38,18 @@ struct comm;
37struct thread *thread__new(pid_t pid, pid_t tid); 38struct thread *thread__new(pid_t pid, pid_t tid);
38int thread__init_map_groups(struct thread *thread, struct machine *machine); 39int thread__init_map_groups(struct thread *thread, struct machine *machine);
39void thread__delete(struct thread *thread); 40void thread__delete(struct thread *thread);
41
42struct thread *thread__get(struct thread *thread);
43void thread__put(struct thread *thread);
44
45static inline void __thread__zput(struct thread **thread)
46{
47 thread__put(*thread);
48 *thread = NULL;
49}
50
51#define thread__zput(thread) __thread__zput(&thread)
52
40static inline void thread__exited(struct thread *thread) 53static inline void thread__exited(struct thread *thread)
41{ 54{
42 thread->dead = true; 55 thread->dead = true;