lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Wed, 24 Dec 2014 16:15:24 +0900 From: Namhyung Kim <namhyung@...nel.org> To: Arnaldo Carvalho de Melo <acme@...nel.org> Cc: Ingo Molnar <mingo@...nel.org>, Peter Zijlstra <a.p.zijlstra@...llo.nl>, Jiri Olsa <jolsa@...hat.com>, LKML <linux-kernel@...r.kernel.org>, David Ahern <dsahern@...il.com>, Stephane Eranian <eranian@...gle.com>, Adrian Hunter <adrian.hunter@...el.com>, Andi Kleen <andi@...stfloor.org>, Frederic Weisbecker <fweisbec@...il.com> Subject: [PATCH 28/37] perf tools: Add missing_threads rb tree Sometimes it's possible to miss certain meta events like fork/exit and in this case it can fail to find such thread in the machine's rbtree. But adding a thread to the tree is dangerous since it's now executed in multi-thread environment otherwise it'll add an overhead in order to grab a lock for every search. So adds a separate missing_threads tree and protect it with a mutex. It's expected to be accessed only if a thread is not found in a normal tree. Signed-off-by: Namhyung Kim <namhyung@...nel.org> --- tools/perf/tests/thread-lookup-time.c | 8 ++- tools/perf/util/build-id.c | 9 +++- tools/perf/util/machine.c | 91 +++++++++++++++++++++++------------ tools/perf/util/machine.h | 2 + tools/perf/util/session.c | 8 +-- tools/perf/util/thread.h | 1 + 6 files changed, 80 insertions(+), 39 deletions(-) diff --git a/tools/perf/tests/thread-lookup-time.c b/tools/perf/tests/thread-lookup-time.c index 6237ecf8caae..04cdde9329d6 100644 --- a/tools/perf/tests/thread-lookup-time.c +++ b/tools/perf/tests/thread-lookup-time.c @@ -7,7 +7,9 @@ static int thread__print_cb(struct thread *th, void *arg __maybe_unused) { printf("thread: %d, start time: %"PRIu64" %s\n", - th->tid, th->start_time, th->dead ? "(dead)" : ""); + th->tid, th->start_time, + th->dead ? "(dead)" : th->exited ? "(exited)" : + th->missing ? "(missing)" : ""); return 0; } @@ -105,6 +107,8 @@ static int lookup_with_timestamp(struct machine *machine) machine__findnew_thread_time(machine, 0, 0, 70000) == t3); machine__delete_threads(machine); + machine__delete_dead_threads(machine); + machine__delete_missing_threads(machine); return 0; } @@ -146,6 +150,8 @@ static int lookup_without_timestamp(struct machine *machine) machine__findnew_thread_time(machine, 0, 0, -1ULL) == t3); machine__delete_threads(machine); + machine__delete_dead_threads(machine); + machine__delete_missing_threads(machine); return 0; } diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 0c72680a977f..98446d089b08 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -60,7 +60,14 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, event->fork.ppid, event->fork.ptid); if (thread) { - rb_erase(&thread->rb_node, &machine->threads); + if (thread->dead) + rb_erase(&thread->rb_node, &machine->dead_threads); + else if (thread->missing) + rb_erase(&thread->rb_node, &machine->missing_threads); + else + rb_erase(&thread->rb_node, &machine->threads); + + list_del(&thread->node); machine->last_match = NULL; thread__delete(thread); } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index ffce0bcd2d9a..c7492d4fde29 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -29,6 +29,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->threads = RB_ROOT; machine->dead_threads = RB_ROOT; + machine->missing_threads = RB_ROOT; machine->last_match = NULL; machine->vdso_info = NULL; @@ -89,6 +90,19 @@ static void dsos__delete(struct dsos *dsos) } } +void machine__delete_missing_threads(struct machine *machine) +{ + struct rb_node *nd = rb_first(&machine->missing_threads); + + while (nd) { + struct thread *t = rb_entry(nd, struct thread, rb_node); + + nd = rb_next(nd); + rb_erase(&t->rb_node, &machine->missing_threads); + thread__delete(t); + } +} + void machine__delete_dead_threads(struct machine *machine) { struct rb_node *nd = rb_first(&machine->dead_threads); @@ -438,11 +452,12 @@ static struct thread *__machine__findnew_thread_time(struct machine *machine, pid_t pid, pid_t tid, u64 timestamp, bool create) { - struct thread *curr, *pos, *new; + struct thread *curr, *pos, *new = NULL; struct thread *th = NULL; struct rb_node **p; struct rb_node *parent = NULL; bool initial = timestamp == (u64)0; + static pthread_mutex_t missing_thread_lock = PTHREAD_MUTEX_INITIALIZER; curr = __machine__findnew_thread(machine, pid, tid, initial); if (curr && timestamp >= curr->start_time) @@ -475,44 +490,49 @@ static struct thread *__machine__findnew_thread_time(struct machine *machine, p = &(*p)->rb_right; } - if (!create) - return NULL; - - if (!curr) - return __machine__findnew_thread(machine, pid, tid, true); + pthread_mutex_lock(&missing_thread_lock); - new = thread__new(pid, tid); - if (new == NULL) - return NULL; + p = &machine->missing_threads.rb_node; + parent = NULL; - new->start_time = timestamp; + while (*p != NULL) { + parent = *p; + th = rb_entry(parent, struct thread, rb_node); - if (*p) { - list_for_each_entry(pos, &th->node, node) { - /* sort by time */ - if (timestamp >= pos->start_time) { - th = pos; - break; - } + if (th->tid == tid) { + pthread_mutex_unlock(&missing_thread_lock); + return th; } - list_add_tail(&new->node, &th->node); - } else { - rb_link_node(&new->rb_node, parent, p); - rb_insert_color(&new->rb_node, &machine->dead_threads); + + if (tid < th->tid) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; } + if (!create) + goto out; + + new = thread__new(pid, tid); + if (new == NULL) + goto out; + + /* missing threads are not bothered with timestamp */ + new->start_time = 0; + new->missing = true; + /* - * We have to initialize map_groups separately - * after rb tree is updated. - * - * The reason is that we call machine__findnew_thread - * within thread__init_map_groups to find the thread - * leader and that would screwed the rb tree. + * missing threads have their own map groups regardless of + * leader for the sake of simplicity. it's okay since the map + * groups has no map in it anyway. */ - if (thread__init_map_groups(new, machine)) { - thread__delete(new); - return NULL; - } + new->mg = map_groups__new(machine); + + rb_link_node(&new->rb_node, parent, p); + rb_insert_color(&new->rb_node, &machine->missing_threads); + +out: + pthread_mutex_unlock(&missing_thread_lock); return new; } @@ -1351,6 +1371,7 @@ static void machine__remove_thread(struct machine *machine, struct thread *th) machine->last_match = NULL; rb_erase(&th->rb_node, &machine->threads); + RB_CLEAR_NODE(&th->rb_node); th->dead = true; @@ -1822,6 +1843,14 @@ int machine__for_each_thread(struct machine *machine, return rc; } } + + for (nd = rb_first(&machine->missing_threads); nd; nd = rb_next(nd)) { + thread = rb_entry(nd, struct thread, rb_node); + rc = fn(thread, priv); + if (rc != 0) + return rc; + } + return rc; } diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 9571b6b1c5b5..40af1f59e360 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -31,6 +31,7 @@ struct machine { char *root_dir; struct rb_root threads; struct rb_root dead_threads; + struct rb_root missing_threads; struct thread *last_match; struct vdso_info *vdso_info; struct dsos user_dsos; @@ -116,6 +117,7 @@ void machines__set_comm_exec(struct machines *machines, bool comm_exec); struct machine *machine__new_host(void); int machine__init(struct machine *machine, const char *root_dir, pid_t pid); void machine__exit(struct machine *machine); +void machine__delete_missing_threads(struct machine *machine); void machine__delete_dead_threads(struct machine *machine); void machine__delete_threads(struct machine *machine); void machine__delete(struct machine *machine); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c1a17110ec6a..34956983ae8e 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -138,14 +138,11 @@ struct perf_session *perf_session__new(struct perf_data_file *file, 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) { machine__delete_threads(&session->machines.host); + machine__delete_dead_threads(&session->machines.host); + machine__delete_missing_threads(&session->machines.host); } static void perf_session_env__delete(struct perf_session_env *env) @@ -167,7 +164,6 @@ static void perf_session_env__delete(struct perf_session_env *env) void perf_session__delete(struct perf_session *session) { perf_session__destroy_kernel_maps(session); - perf_session__delete_dead_threads(session); perf_session__delete_threads(session); perf_session_env__delete(&session->header.env); machines__exit(&session->machines); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 0b88ca22bc3d..87188ba9465b 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -23,6 +23,7 @@ struct thread { bool comm_set; bool exited; /* if set thread has exited */ bool dead; /* thread is in dead_threads list */ + bool missing; /* thread is in missing_threads list */ struct list_head comm_list; int comm_len; u64 db_id; -- 2.1.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists