mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Namhyung Kim <namhyung@kernel.org>
To: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Ingo Molnar <mingo@kernel.org>,
	Peter Zijlstra <a.p.zijlstra@chello.nl>,
	Jiri Olsa <jolsa@redhat.com>, LKML <linux-kernel@vger.kernel.org>,
	David Ahern <dsahern@gmail.com>,
	Stephane Eranian <eranian@google.com>,
	Adrian Hunter <adrian.hunter@intel.com>,
	Andi Kleen <andi@firstfloor.org>,
	Frederic Weisbecker <fweisbec@gmail.com>
Subject: [PATCH 15/37] perf tools: Introduce machine__find*_thread_time()
Date: Wed, 24 Dec 2014 16:15:11 +0900	[thread overview]
Message-ID: <1419405333-27952-16-git-send-email-namhyung@kernel.org> (raw)
In-Reply-To: <1419405333-27952-1-git-send-email-namhyung@kernel.org>

With multi-file data storage is enabled, it needs to search thread
based on sample time since sample processing is done after other
(task, comm and mmap) events are processed.  This can be a problem if
a session is very long and pid is recycled - in that case it'll only
see the last one.

So keep thread start time in it, and search thread based on the time.
This patch introduces machine__find{,new}_thread_time() function for
this.  It'll first search current thread rbtree and then dead thread
tree and list.  If it couldn't find anyone, it'll create a new thread.

The sample timestamp of 0 means that this is called from synthesized
event so just use current rbtree.  The timestamp will be -1 if sample
didn't record the timestamp so will see current threads automatically.

Dead threads are managed in a rbtree, and if there's more than one
thread has sample tid/pid, it'll be saved in a list.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-script.c     |   5 +-
 tools/perf/tests/dwarf-unwind.c |  10 ++--
 tools/perf/tests/hists_common.c |   3 +-
 tools/perf/tests/hists_link.c   |   2 +-
 tools/perf/util/event.c         |   4 +-
 tools/perf/util/machine.c       | 109 +++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/machine.h       |   8 ++-
 tools/perf/util/thread.c        |   4 ++
 tools/perf/util/thread.h        |   1 +
 9 files changed, 132 insertions(+), 14 deletions(-)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index ce304dfd962a..85122b388d8e 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -549,8 +549,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
 				struct machine *machine)
 {
 	struct addr_location al;
-	struct thread *thread = machine__findnew_thread(machine, sample->pid,
-							sample->tid);
+	struct thread *thread = machine__findnew_thread_time(machine, sample->pid,
+							     sample->tid,
+							     sample->time);
 
 	if (thread == NULL) {
 		pr_debug("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index ab28cca2cb97..dfecd49fef90 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -13,10 +13,10 @@
 
 static int mmap_handler(struct perf_tool *tool __maybe_unused,
 			union perf_event *event,
-			struct perf_sample *sample __maybe_unused,
+			struct perf_sample *sample,
 			struct machine *machine)
 {
-	return machine__process_mmap2_event(machine, event, NULL);
+	return machine__process_mmap2_event(machine, event, sample);
 }
 
 static int init_live_machine(struct machine *machine)
@@ -61,12 +61,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
 __attribute__ ((noinline))
 static int unwind_thread(struct thread *thread)
 {
-	struct perf_sample sample;
+	struct perf_sample sample = {
+		.time = -1ULL,
+	};
 	unsigned long cnt = 0;
 	int err = -1;
 
-	memset(&sample, 0, sizeof(sample));
-
 	if (test__arch_unwind_sample(&sample, thread)) {
 		pr_debug("failed to get unwind sample\n");
 		goto out;
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index a62c09134516..86a8fdb41804 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -80,6 +80,7 @@ static struct {
 struct machine *setup_fake_machine(struct machines *machines)
 {
 	struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
+	struct perf_sample sample = { .time = -1ULL, };
 	size_t i;
 
 	if (machine == NULL) {
@@ -113,7 +114,7 @@ struct machine *setup_fake_machine(struct machines *machines)
 		strcpy(fake_mmap_event.mmap.filename,
 		       fake_mmap_info[i].filename);
 
-		machine__process_mmap_event(machine, &fake_mmap_event, NULL);
+		machine__process_mmap_event(machine, &fake_mmap_event, &sample);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index fe7cb886c23e..07f1d19b88b5 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
 	struct perf_evsel *evsel;
 	struct addr_location al;
 	struct hist_entry *he;
-	struct perf_sample sample = { .period = 1, };
+	struct perf_sample sample = { .period = 1, .time = -1ULL, };
 	size_t i = 0, k;
 
 	/*
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 6c6d044e959a..ff7594a27c73 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -825,8 +825,8 @@ int perf_event__preprocess_sample(const union perf_event *event,
 				  struct perf_sample *sample)
 {
 	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-	struct thread *thread = machine__findnew_thread(machine, sample->pid,
-							sample->tid);
+	struct thread *thread = machine__findnew_thread_time(machine, sample->pid,
+							     sample->tid, sample->time);
 
 	if (thread == NULL)
 		return -1;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 582e011adc92..2cc088d71922 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -431,6 +431,103 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 	return __machine__findnew_thread(machine, pid, tid, false);
 }
 
+static void machine__remove_thread(struct machine *machine, struct thread *th);
+
+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 *th = NULL;
+	struct rb_node **p;
+	struct rb_node *parent = NULL;
+	bool initial = timestamp == (u64)0;
+
+	curr = __machine__findnew_thread(machine, pid, tid, initial);
+	if (curr && timestamp >= curr->start_time)
+		return curr;
+
+	p = &machine->dead_threads.rb_node;
+	while (*p != NULL) {
+		parent = *p;
+		th = rb_entry(parent, struct thread, rb_node);
+
+		if (th->tid == tid) {
+			list_for_each_entry(pos, &th->node, node) {
+				if (timestamp >= pos->start_time &&
+				    pos->start_time > th->start_time) {
+					th = pos;
+					break;
+				}
+			}
+
+			if (timestamp >= th->start_time) {
+				machine__update_thread_pid(machine, th, pid);
+				return th;
+			}
+			break;
+		}
+
+		if (tid < th->tid)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	if (!create)
+		return NULL;
+
+	if (!curr)
+		return __machine__findnew_thread(machine, pid, tid, true);
+
+	new = thread__new(pid, tid);
+	if (new == NULL)
+		return NULL;
+
+	new->start_time = timestamp;
+
+	if (*p) {
+		list_for_each_entry(pos, &th->node, node) {
+			/* sort by time */
+			if (timestamp >= pos->start_time) {
+				th = pos;
+				break;
+			}
+		}
+		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);
+	}
+
+	/*
+	 * 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.
+	 */
+	if (thread__init_map_groups(new, machine)) {
+		thread__delete(new);
+		return NULL;
+	}
+
+	return new;
+}
+
+struct thread *machine__find_thread_time(struct machine *machine, pid_t pid,
+					 pid_t tid, u64 timestamp)
+{
+	return __machine__findnew_thread_time(machine, pid, tid, timestamp, false);
+}
+
+struct thread *machine__findnew_thread_time(struct machine *machine, pid_t pid,
+					    pid_t tid, u64 timestamp)
+{
+	return __machine__findnew_thread_time(machine, pid, tid, timestamp, true);
+}
+
 struct comm *machine__thread_exec_comm(struct machine *machine,
 				       struct thread *thread)
 {
@@ -1169,7 +1266,7 @@ int machine__process_mmap2_event(struct machine *machine,
 	}
 
 	thread = machine__findnew_thread(machine, event->mmap2.pid,
-					event->mmap2.tid);
+					 event->mmap2.tid);
 	if (thread == NULL)
 		goto out_problem;
 
@@ -1265,6 +1362,16 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
 		pos = rb_entry(parent, struct thread, rb_node);
 
 		if (pos->tid == th->tid) {
+			struct thread *old;
+
+			/* sort by time */
+			list_for_each_entry(old, &pos->node, node) {
+				if (th->start_time >= old->start_time) {
+					pos = old;
+					break;
+				}
+			}
+
 			list_add_tail(&th->node, &pos->node);
 			return;
 		}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 4349946a38ff..9571b6b1c5b5 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -68,8 +68,6 @@ static inline bool machine__kernel_ip(struct machine *machine, u64 ip)
 	return ip >= kernel_start;
 }
 
-struct thread *machine__find_thread(struct machine *machine, pid_t pid,
-				    pid_t tid);
 struct comm *machine__thread_exec_comm(struct machine *machine,
 				       struct thread *thread);
 
@@ -149,6 +147,12 @@ static inline bool machine__is_host(struct machine *machine)
 
 struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
 				       pid_t tid);
+struct thread *machine__find_thread(struct machine *machine, pid_t pid,
+				    pid_t tid);
+struct thread *machine__findnew_thread_time(struct machine *machine, pid_t pid,
+					    pid_t tid, u64 timestamp);
+struct thread *machine__find_thread_time(struct machine *machine, pid_t pid,
+					 pid_t tid, u64 timestamp);
 
 size_t machine__fprintf(struct machine *machine, FILE *fp);
 
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index b9c5c5d5e718..f2465f17cf16 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -128,6 +128,9 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
 
 	/* Override the default :tid entry */
 	if (!thread->comm_set) {
+		if (!thread->start_time)
+			thread->start_time = timestamp;
+
 		err = comm__override(curr, str, timestamp, exec);
 		if (err)
 			return err;
@@ -229,6 +232,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
 	}
 
 	thread->ppid = parent->tid;
+	thread->start_time = timestamp;
 	return thread__clone_map_groups(thread, parent);
 }
 
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 413f28cf689b..5c07cee3b64e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -25,6 +25,7 @@ struct thread {
 	struct list_head	comm_list;
 	int			comm_len;
 	u64			db_id;
+	u64			start_time;
 
 	void			*priv;
 	struct thread_stack	*ts;
-- 
2.1.3


  parent reply	other threads:[~2014-12-24  7:21 UTC|newest]

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-24  7:14 [RFC/PATCHSET 00/37] perf tools: Speed-up perf report by using multi thread (v1) Namhyung Kim
2014-12-24  7:14 ` [PATCH 01/37] perf tools: Set attr.task bit for a tracking event Namhyung Kim
2014-12-31 11:25   ` Jiri Olsa
2014-12-24  7:14 ` [PATCH 02/37] perf record: Use a software dummy event to track task/mmap events Namhyung Kim
2014-12-26 16:27   ` David Ahern
2014-12-27  5:28     ` Namhyung Kim
2014-12-29 12:58       ` Adrian Hunter
2014-12-30  5:51         ` Namhyung Kim
2014-12-30  9:04           ` Adrian Hunter
2014-12-24  7:14 ` [PATCH 03/37] perf tools: Use perf_data_file__fd() consistently Namhyung Kim
2014-12-26 16:30   ` David Ahern
2014-12-27  5:30     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 04/37] perf tools: Add multi file interface to perf_data_file Namhyung Kim
2014-12-25 22:08   ` Jiri Olsa
2014-12-26  1:19     ` Namhyung Kim
2014-12-31 11:26   ` Jiri Olsa
2014-12-31 14:55     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 05/37] perf tools: Create separate mmap for dummy tracking event Namhyung Kim
2014-12-25 22:08   ` Jiri Olsa
2014-12-26  1:45     ` Namhyung Kim
2014-12-25 22:09   ` Jiri Olsa
2014-12-26  1:55     ` Namhyung Kim
2014-12-26 16:51   ` David Ahern
2014-12-27  5:32     ` Namhyung Kim
2014-12-29 13:44   ` Adrian Hunter
2014-12-30  5:57     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 06/37] perf tools: Introduce perf_evlist__mmap_multi() Namhyung Kim
2014-12-24  7:15 ` [PATCH 07/37] perf tools: Do not use __perf_session__process_events() directly Namhyung Kim
2014-12-31 11:33   ` Jiri Olsa
2014-12-24  7:15 ` [PATCH 08/37] perf tools: Handle multi-file session properly Namhyung Kim
2014-12-31 12:01   ` Jiri Olsa
2014-12-31 14:53     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 09/37] perf record: Add -M/--multi option for multi file recording Namhyung Kim
2014-12-24  7:15 ` [PATCH 10/37] perf report: Skip dummy tracking event Namhyung Kim
2014-12-24  7:15 ` [PATCH 11/37] perf tools: Introduce thread__comm_time() helpers Namhyung Kim
2014-12-26 17:00   ` David Ahern
2014-12-27  5:36     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 12/37] perf tools: Add a test case for thread comm handling Namhyung Kim
2014-12-24  7:15 ` [PATCH 13/37] perf tools: Use thread__comm_time() when adding hist entries Namhyung Kim
2014-12-25 22:53   ` Jiri Olsa
2014-12-26  2:10     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 14/37] perf tools: Convert dead thread list into rbtree Namhyung Kim
2014-12-25 23:05   ` Jiri Olsa
2014-12-26  2:26     ` Namhyung Kim
2014-12-26 17:14       ` David Ahern
2014-12-27  5:42         ` Namhyung Kim
2014-12-27 15:31   ` David Ahern
2014-12-28 13:24     ` Namhyung Kim
2014-12-24  7:15 ` Namhyung Kim [this message]
2014-12-27 16:33   ` [PATCH 15/37] perf tools: Introduce machine__find*_thread_time() David Ahern
2014-12-28 14:50     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 16/37] perf tools: Add a test case for timed thread handling Namhyung Kim
2014-12-31 14:17   ` Jiri Olsa
2014-12-31 15:32     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 17/37] perf tools: Maintain map groups list in a leader thread Namhyung Kim
2014-12-24  7:15 ` [PATCH 18/37] perf tools: Remove thread when map groups initialization failed Namhyung Kim
2014-12-28  0:45   ` David Ahern
2014-12-29  7:08     ` Namhyung Kim
2014-12-24  7:15 ` [PATCH 19/37] perf tools: Introduce thread__find_addr_location_time() and friends Namhyung Kim
2014-12-24  7:15 ` [PATCH 20/37] perf tools: Add a test case for timed map groups handling Namhyung Kim
2014-12-24  7:15 ` [PATCH 21/37] perf tools: Protect dso symbol loading using a mutex Namhyung Kim
2014-12-24  7:15 ` [PATCH 22/37] perf tools: Protect dso cache tree using dso->lock Namhyung Kim
2014-12-24  7:15 ` [PATCH 23/37] perf tools: Protect dso cache fd with a mutex Namhyung Kim
2014-12-24  7:15 ` [PATCH 24/37] perf session: Pass struct events stats to event processing functions Namhyung Kim
2014-12-24  7:15 ` [PATCH 25/37] perf hists: Pass hists struct to hist_entry_iter functions Namhyung Kim
2014-12-24  7:15 ` [PATCH 26/37] perf tools: Move BUILD_ID_SIZE definition to perf.h Namhyung Kim
2014-12-24  7:15 ` [PATCH 27/37] perf report: Parallelize perf report using multi-thread Namhyung Kim
2014-12-24  7:15 ` [PATCH 28/37] perf tools: Add missing_threads rb tree Namhyung Kim
2014-12-24  7:15 ` [PATCH 29/37] perf top: Always creates thread in the current task tree Namhyung Kim
2014-12-24  7:15 ` [PATCH 30/37] perf tools: Fix progress ui to support multi thread Namhyung Kim
2014-12-24  7:15 ` [PATCH 31/37] perf record: Show total size of multi file data Namhyung Kim
2014-12-24  7:15 ` [PATCH 32/37] perf report: Add --multi-thread option and config item Namhyung Kim
2014-12-24  7:15 ` [PATCH 33/37] perf tools: Add front cache for dso data access Namhyung Kim
2014-12-24  7:15 ` [PATCH 34/37] perf tools: Convert lseek + read to pread Namhyung Kim
2014-12-24  7:15 ` [PATCH 35/37] perf callchain: Save eh/debug frame offset for dwarf unwind Namhyung Kim
2014-12-24  7:15 ` [PATCH 36/37] perf tools: Add new perf data command Namhyung Kim
2014-12-24  7:15 ` [PATCH 37/37] perf data: Implement 'split' subcommand Namhyung Kim
2014-12-24 13:51   ` Arnaldo Carvalho de Melo
2014-12-24 14:14     ` Namhyung Kim
2014-12-24 14:45       ` Arnaldo Carvalho de Melo
2014-12-26 13:59   ` Jiri Olsa
2014-12-27  5:21     ` Namhyung Kim
2014-12-26 14:02 ` [RFC/PATCHSET 00/37] perf tools: Speed-up perf report by using multi thread (v1) Jiri Olsa
2014-12-27  5:23   ` Namhyung Kim
2015-01-05 18:48 ` Andi Kleen
2015-01-06 15:50   ` Stephane Eranian
2015-01-07  7:13     ` Namhyung Kim
2015-01-07 15:14       ` Stephane Eranian
2015-01-08  5:19         ` Namhyung Kim
2015-01-07  6:58   ` Namhyung Kim
2015-01-08 14:52     ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1419405333-27952-16-git-send-email-namhyung@kernel.org \
    --to=namhyung@kernel.org \
    --cc=a.p.zijlstra@chello.nl \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=andi@firstfloor.org \
    --cc=dsahern@gmail.com \
    --cc=eranian@google.com \
    --cc=fweisbec@gmail.com \
    --cc=jolsa@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®