public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC,PATCH] perf tool: Refactoring IO data files code
@ 2011-11-18 13:46 Jiri Olsa
  2011-11-18 13:46 ` [PATCH 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
                   ` (6 more replies)
  0 siblings, 7 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-18 13:46 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel

Hi,

based on following discussion:
http://marc.info/?l=linux-kernel&m=131731212425421&w=2
http://marc.info/?l=linux-kernel&m=131736842010972&w=2

I made some changes to have event memory mapping and input/output
data code in one place. The reason was to make the change for
multiple event data files at least possible ;)

This patchset is marked as RFC since it's quite big change
and I expect some better design might come up.

However, patches 1 and 2 are not big deal, since they are
just small (not so related) changes.

Patches 3-4 are the main change of the patchset.

1/5 perf tool: Fix session host_nachine retrieval
2/5 perf tool: Initialize events IDs in a single function
3/5 perf tool: Introducing perf_mmap object
4/5 perf tool: Introducing perf_data object
5/5 perf tool: Putting mmap support to perf_data object

I did some overall testing of all the changed command,
and so far so good. Just hit issue with 'diff' command,
but this one seems not to work even without my changes.

Also the current perf python binsing code is broken
wit missing dependencies so I could not test my
changes there.

thanks for comments,
jirka
---
 tools/perf/Makefile               |    4 +
 tools/perf/builtin-annotate.c     |    3 +-
 tools/perf/builtin-buildid-list.c |    4 +-
 tools/perf/builtin-diff.c         |    6 +-
 tools/perf/builtin-evlist.c       |    3 +-
 tools/perf/builtin-inject.c       |    9 +-
 tools/perf/builtin-kmem.c         |   18 +-
 tools/perf/builtin-lock.c         |    3 +-
 tools/perf/builtin-record.c       |  206 ++++++++-----------------
 tools/perf/builtin-report.c       |    7 +-
 tools/perf/builtin-sched.c        |    6 +-
 tools/perf/builtin-script.c       |    3 +-
 tools/perf/builtin-test.c         |   17 ++-
 tools/perf/builtin-timechart.c    |    7 +-
 tools/perf/builtin-top.c          |   52 ++++---
 tools/perf/perf.h                 |   26 ---
 tools/perf/util/data.c            |  303 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/data.h            |   78 ++++++++++
 tools/perf/util/event.c           |   14 +-
 tools/perf/util/evlist.c          |  268 +++------------------------------
 tools/perf/util/evlist.h          |    8 +-
 tools/perf/util/evsel.h           |    4 +-
 tools/perf/util/header.c          |   35 +++--
 tools/perf/util/header.h          |    6 +-
 tools/perf/util/mmap.c            |  138 +++++++++++++++++
 tools/perf/util/mmap.h            |   48 ++++++
 tools/perf/util/python.c          |   23 ++-
 tools/perf/util/session.c         |  115 +++++---------
 tools/perf/util/session.h         |   38 ++++--
 29 files changed, 855 insertions(+), 597 deletions(-)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/5] perf tool: Fix session host_nachine retrieval
  2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
@ 2011-11-18 13:46 ` Jiri Olsa
  2011-11-18 14:24   ` Arnaldo Carvalho de Melo
  2011-11-18 13:46 ` [PATCH 2/5] perf tool: Initialize events IDs in a single function Jiri Olsa
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 19+ messages in thread
From: Jiri Olsa @ 2011-11-18 13:46 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

The host_machine is statically included inside perf_session struct
so it is always present.

Changing function:
'perf_session__find_host_machine' to 'perf_session__host_machine'

Removing NULL checking code after this function, since it is not needed.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-inject.c |    6 +-----
 tools/perf/builtin-kmem.c   |   12 +++++-------
 tools/perf/builtin-record.c |    6 +-----
 tools/perf/builtin-top.c    |    4 ++--
 tools/perf/util/event.c     |   14 +++++---------
 tools/perf/util/session.h   |    6 +++---
 6 files changed, 17 insertions(+), 31 deletions(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 8dfc12b..3c5eb3a 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -111,11 +111,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
 		return -1;
 	}
 
-	machine = perf_session__find_host_machine(session);
-	if (machine == NULL) {
-		pr_err("Can't find machine for session\n");
-		return -1;
-	}
+	machine = perf_session__host_machine(session);
 
 	if (self->kernel)
 		misc = PERF_RECORD_MISC_KERNEL;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 225e963..2ca8206 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -342,7 +342,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 			   int n_lines, int is_caller)
 {
 	struct rb_node *next;
-	struct machine *machine;
 
 	printf("%.102s\n", graph_dotted_line);
 	printf(" %-34s |",  is_caller ? "Callsite": "Alloc Ptr");
@@ -351,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 
 	next = rb_first(root);
 
-	machine = perf_session__find_host_machine(session);
-	if (!machine) {
-		pr_err("__print_result: couldn't find kernel information\n");
-		return;
-	}
 	while (next && n_lines--) {
 		struct alloc_stat *data = rb_entry(next, struct alloc_stat,
 						   node);
@@ -366,8 +360,12 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 
 		if (is_caller) {
 			addr = data->call_site;
-			if (!raw_ip)
+			if (!raw_ip) {
+				struct machine *machine;
+
+				machine = perf_session__host_machine(session);
 				sym = machine__find_kernel_function(machine, addr, &map, NULL);
+			}
 		} else
 			addr = data->ptr;
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6ab58cc..1132e70 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -662,11 +662,7 @@ static int __cmd_record(int argc, const char **argv)
 		}
 	}
 
-	machine = perf_session__find_host_machine(session);
-	if (!machine) {
-		pr_err("Couldn't find native kernel information.\n");
-		return -1;
-	}
+	machine = perf_session__host_machine(session);
 
 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
 						 session, machine, "_text");
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9cdedb..8e02027 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -692,13 +692,13 @@ static void perf_event__process_sample(const union perf_event *event,
 		++top.us_samples;
 		if (top.hide_user_symbols)
 			return;
-		machine = perf_session__find_host_machine(session);
+		machine = perf_session__host_machine(session);
 		break;
 	case PERF_RECORD_MISC_KERNEL:
 		++top.kernel_samples;
 		if (top.hide_kernel_symbols)
 			return;
-		machine = perf_session__find_host_machine(session);
+		machine = perf_session__host_machine(session);
 		break;
 	case PERF_RECORD_MISC_GUEST_KERNEL:
 		++top.guest_kernel_samples;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 437f8ca..35817fa 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -589,12 +589,12 @@ int perf_event__process_mmap(union perf_event *event,
 		return 0;
 	}
 
-	machine = perf_session__find_host_machine(session);
-	if (machine == NULL)
-		goto out_problem;
 	thread = perf_session__findnew(session, event->mmap.pid);
 	if (thread == NULL)
 		goto out_problem;
+
+	machine = perf_session__host_machine(session);
+
 	map = map__new(&machine->user_dsos, event->mmap.start,
 			event->mmap.len, event->mmap.pgoff,
 			event->mmap.pid, event->mmap.filename,
@@ -672,15 +672,11 @@ void thread__find_addr_map(struct thread *self,
 
 	if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
 		al->level = 'k';
-		machine = perf_session__find_host_machine(session);
-		if (machine == NULL) {
-			al->map = NULL;
-			return;
-		}
+		machine = perf_session__host_machine(session);
 		mg = &machine->kmaps;
 	} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
 		al->level = '.';
-		machine = perf_session__find_host_machine(session);
+		machine = perf_session__host_machine(session);
 	} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
 		al->level = 'g';
 		machine = perf_session__find_machine(session, pid);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 6e393c9..a81d666 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -121,7 +121,7 @@ void perf_session__update_sample_type(struct perf_session *self);
 void perf_session__remove_thread(struct perf_session *self, struct thread *th);
 
 static inline
-struct machine *perf_session__find_host_machine(struct perf_session *self)
+struct machine *perf_session__host_machine(struct perf_session *self)
 {
 	return &self->host_machine;
 }
@@ -130,7 +130,7 @@ static inline
 struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
 {
 	if (pid == HOST_KERNEL_ID)
-		return &self->host_machine;
+		return perf_session__host_machine(self);
 	return machines__find(&self->machines, pid);
 }
 
@@ -138,7 +138,7 @@ static inline
 struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
 {
 	if (pid == HOST_KERNEL_ID)
-		return &self->host_machine;
+		return perf_session__host_machine(self);
 	return machines__findnew(&self->machines, pid);
 }
 
-- 
1.7.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/5] perf tool: Initialize events IDs in a single function
  2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
  2011-11-18 13:46 ` [PATCH 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
@ 2011-11-18 13:46 ` Jiri Olsa
  2011-11-18 14:22   ` Arnaldo Carvalho de Melo
  2011-11-18 13:46 ` [PATCH 3/5] perf tool: Introducing perf_mmap object Jiri Olsa
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 19+ messages in thread
From: Jiri Olsa @ 2011-11-18 13:46 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Currently events' IDs initialization is scattered among the
code. Adding function 'perf_evlist__init_ids' to allocate
and retrive events' IDs in one place.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/evlist.c |   50 +++++++++++++++++++++++++++++----------------
 1 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index fbb4b4a..0f715d0 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -326,10 +326,6 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
 					if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
 						goto out_unmap;
 				}
-
-				if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-				    perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
-					goto out_unmap;
 			}
 		}
 	}
@@ -366,10 +362,6 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
 				if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
 					goto out_unmap;
 			}
-
-			if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-			    perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
-				goto out_unmap;
 		}
 	}
 
@@ -385,6 +377,33 @@ out_unmap:
 	return -1;
 }
 
+static int perf_evlist__init_ids(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+	struct thread_map *threads = evlist->threads;
+	struct cpu_map *cpus = evlist->cpus;
+	int cpu, thread;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (!(evsel->attr.read_format & PERF_FORMAT_ID))
+			continue;
+
+		if ((!evsel->sample_id) &&
+		    perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
+			return -ENOMEM;
+
+		for (cpu = 0; cpu < cpus->nr; cpu++)
+			for (thread = 0; thread < threads->nr; thread++) {
+				int fd = FD(evsel, cpu, thread);
+				if (perf_evlist__id_add_fd(evlist, evsel,
+							   cpu, thread, fd))
+					return -EINVAL;
+			}
+	}
+
+	return 0;
+}
+
 /** perf_evlist__mmap - Create per cpu maps to receive events
  *
  * @evlist - list of events
@@ -403,10 +422,8 @@ out_unmap:
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 {
 	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-	int mask = pages * page_size - 1;
-	struct perf_evsel *evsel;
+	int mask = pages * page_size - 1, ret;
 	const struct cpu_map *cpus = evlist->cpus;
-	const struct thread_map *threads = evlist->threads;
 	int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
 
 	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
@@ -418,14 +435,11 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 	evlist->overwrite = overwrite;
 	evlist->mmap_len = (pages + 1) * page_size;
 
-	list_for_each_entry(evsel, &evlist->entries, node) {
-		if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-		    evsel->sample_id == NULL &&
-		    perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
-			return -ENOMEM;
-	}
+	ret = perf_evlist__init_ids(evlist);
+	if (ret)
+		return ret;
 
-	if (evlist->cpus->map[0] == -1)
+	if (cpus->map[0] == -1)
 		return perf_evlist__mmap_per_thread(evlist, prot, mask);
 
 	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
-- 
1.7.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/5] perf tool: Introducing perf_mmap object
  2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
  2011-11-18 13:46 ` [PATCH 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
  2011-11-18 13:46 ` [PATCH 2/5] perf tool: Initialize events IDs in a single function Jiri Olsa
@ 2011-11-18 13:46 ` Jiri Olsa
  2011-11-18 14:37   ` Arnaldo Carvalho de Melo
  2011-11-18 13:46 ` [PATCH 4/5] perf tool: Introducing perf_data object Jiri Olsa
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 19+ messages in thread
From: Jiri Olsa @ 2011-11-18 13:46 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Adding perf_mmap object to handle event memory maps.

All the memory map related functions originally scatered through
the whole code arenow place in perf_mmap object.

To map and unmap perf_mmap:
	perf_mmap__open
	perf_mmap__close

For reading events via callback:
	perf_mmap__process

For reading events directly:
	perf_mmap__read

following helpers were moved in from perf.h:
	perf_mmap__read_head
	perf_mmap__write_tail

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile         |    2 +
 tools/perf/builtin-record.c |   57 ++++-------------
 tools/perf/builtin-test.c   |    6 ++-
 tools/perf/builtin-top.c    |   19 ++++--
 tools/perf/perf.h           |   26 --------
 tools/perf/util/evlist.c    |  117 +++++++-----------------------------
 tools/perf/util/evlist.h    |    2 +-
 tools/perf/util/mmap.c      |  138 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/mmap.h      |   45 ++++++++++++++
 9 files changed, 239 insertions(+), 173 deletions(-)
 create mode 100644 tools/perf/util/mmap.c
 create mode 100644 tools/perf/util/mmap.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index b98e307..0158b66 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -274,6 +274,7 @@ LIB_H += util/xyarray.h
 LIB_H += util/header.h
 LIB_H += util/help.h
 LIB_H += util/session.h
+LIB_H += util/mmap.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
@@ -337,6 +338,7 @@ LIB_OBJS += $(OUTPUT)util/debug.o
 LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
+LIB_OBJS += $(OUTPUT)util/mmap.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 1132e70..89b3dc2 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -25,6 +25,7 @@
 #include "util/symbol.h"
 #include "util/cpumap.h"
 #include "util/thread_map.h"
+#include "util/mmap.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -65,7 +66,6 @@ static bool			no_buildid			=  false;
 static bool			no_buildid_cache		=  false;
 static struct perf_evlist	*evsel_list;
 
-static long			samples				=      0;
 static u64			bytes_written			=      0;
 
 static int			file_new			=      1;
@@ -103,39 +103,6 @@ static int process_synthesized_event(union perf_event *event,
 	return 0;
 }
 
-static void mmap_read(struct perf_mmap *md)
-{
-	unsigned int head = perf_mmap__read_head(md);
-	unsigned int old = md->prev;
-	unsigned char *data = md->base + page_size;
-	unsigned long size;
-	void *buf;
-
-	if (old == head)
-		return;
-
-	samples++;
-
-	size = head - old;
-
-	if ((old & md->mask) + size != (head & md->mask)) {
-		buf = &data[old & md->mask];
-		size = md->mask + 1 - (old & md->mask);
-		old += size;
-
-		write_output(buf, size);
-	}
-
-	buf = &data[old & md->mask];
-	size = head - old;
-	old += size;
-
-	write_output(buf, size);
-
-	md->prev = old;
-	perf_mmap__write_tail(md, old);
-}
-
 static volatile int done = 0;
 static volatile int signr = -1;
 static volatile int child_finished = 0;
@@ -442,17 +409,25 @@ static struct perf_event_header finished_round_event = {
 	.type = PERF_RECORD_FINISHED_ROUND,
 };
 
-static void mmap_read_all(void)
+static void mmap_read(struct perf_mmap *m __used, void *buf, unsigned long size)
+{
+	write_output(buf, size);
+}
+
+static int mmap_read_all(void)
 {
-	int i;
+	int i, ret = 0;
 
 	for (i = 0; i < evsel_list->nr_mmaps; i++) {
-		if (evsel_list->mmap[i].base)
-			mmap_read(&evsel_list->mmap[i]);
+		struct perf_mmap *m = &evsel_list->mmap[i];
+		if (m->base)
+			ret += perf_mmap__process(m, mmap_read);
 	}
 
 	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
 		write_output(&finished_round_event, sizeof(finished_round_event));
+
+	return ret;
 }
 
 static int __cmd_record(int argc, const char **argv)
@@ -712,11 +687,7 @@ static int __cmd_record(int argc, const char **argv)
 		close(go_pipe[1]);
 
 	for (;;) {
-		int hits = samples;
-
-		mmap_read_all();
-
-		if (hits == samples) {
+		if (!mmap_read_all()) {
 			if (done)
 				break;
 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 831d1ba..feb3218 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -12,6 +12,7 @@
 #include "util/parse-events.h"
 #include "util/symbol.h"
 #include "util/thread_map.h"
+#include "util/mmap.h"
 #include "../../include/linux/hw_breakpoint.h"
 
 static long page_size;
@@ -476,6 +477,7 @@ static int test__basic_mmap(void)
 		     expected_nr_events[nsyscalls], i, j;
 	struct perf_evsel *evsels[nsyscalls], *evsel;
 	int sample_size = __perf_evsel__sample_size(attr.sample_type);
+	struct perf_mmap *md;
 
 	for (i = 0; i < nsyscalls; ++i) {
 		char name[64];
@@ -551,7 +553,9 @@ static int test__basic_mmap(void)
 			++foo;
 		}
 
-	while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
+	md = &evlist->mmap[0];
+
+	while ((event = perf_mmap__read(md)) != NULL) {
 		struct perf_sample sample;
 
 		if (event->header.type != PERF_RECORD_SAMPLE) {
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8e02027..032f70d 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -38,6 +38,7 @@
 #include "util/cpumap.h"
 #include "util/xyarray.h"
 #include "util/sort.h"
+#include "util/mmap.h"
 
 #include "util/debug.h"
 
@@ -804,14 +805,16 @@ static void perf_event__process_sample(const union perf_event *event,
 	return;
 }
 
-static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
+static void session_mmap_read(struct perf_session *self,
+			      struct perf_mmap *md)
 {
-	struct perf_sample sample;
-	struct perf_evsel *evsel;
 	union perf_event *event;
-	int ret;
 
-	while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
+	while ((event = perf_mmap__read(md)) != NULL) {
+		struct perf_sample sample;
+		struct perf_evsel *evsel;
+		int ret;
+
 		ret = perf_session__parse_sample(self, event, &sample);
 		if (ret) {
 			pr_err("Can't parse sample, err = %d\n", ret);
@@ -835,8 +838,10 @@ static void perf_session__mmap_read(struct perf_session *self)
 {
 	int i;
 
-	for (i = 0; i < top.evlist->nr_mmaps; i++)
-		perf_session__mmap_read_idx(self, i);
+	for (i = 0; i < top.evlist->nr_mmaps; i++) {
+		struct perf_mmap *md = &top.evlist->mmap[i];
+		session_mmap_read(self, md);
+	}
 }
 
 static void start_counters(struct perf_evlist *evlist)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 914c895..d79efbb 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -104,32 +104,6 @@ void get_term_dimensions(struct winsize *ws);
 #include "util/types.h"
 #include <stdbool.h>
 
-struct perf_mmap {
-	void			*base;
-	int			mask;
-	unsigned int		prev;
-};
-
-static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
-{
-	struct perf_event_mmap_page *pc = mm->base;
-	int head = pc->data_head;
-	rmb();
-	return head;
-}
-
-static inline void perf_mmap__write_tail(struct perf_mmap *md,
-					 unsigned long tail)
-{
-	struct perf_event_mmap_page *pc = md->base;
-
-	/*
-	 * ensure all reads are done before we write the tail out.
-	 */
-	/* mb(); */
-	pc->data_tail = tail;
-}
-
 /*
  * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
  * counters in the current task.
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 0f715d0..2237833 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -12,6 +12,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "util.h"
+#include "mmap.h"
 
 #include <sys/mman.h>
 
@@ -200,82 +201,14 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
 	return NULL;
 }
 
-union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
-{
-	/* XXX Move this to perf.c, making it generally available */
-	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-	struct perf_mmap *md = &evlist->mmap[idx];
-	unsigned int head = perf_mmap__read_head(md);
-	unsigned int old = md->prev;
-	unsigned char *data = md->base + page_size;
-	union perf_event *event = NULL;
-
-	if (evlist->overwrite) {
-		/*
-		 * If we're further behind than half the buffer, there's a chance
-		 * the writer will bite our tail and mess up the samples under us.
-		 *
-		 * If we somehow ended up ahead of the head, we got messed up.
-		 *
-		 * In either case, truncate and restart at head.
-		 */
-		int diff = head - old;
-		if (diff > md->mask / 2 || diff < 0) {
-			fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
-
-			/*
-			 * head points to a known good entry, start there.
-			 */
-			old = head;
-		}
-	}
-
-	if (old != head) {
-		size_t size;
-
-		event = (union perf_event *)&data[old & md->mask];
-		size = event->header.size;
-
-		/*
-		 * Event straddles the mmap boundary -- header should always
-		 * be inside due to u64 alignment of output.
-		 */
-		if ((old & md->mask) + size != ((old + size) & md->mask)) {
-			unsigned int offset = old;
-			unsigned int len = min(sizeof(*event), size), cpy;
-			void *dst = &evlist->event_copy;
-
-			do {
-				cpy = min(md->mask + 1 - (offset & md->mask), len);
-				memcpy(dst, &data[offset & md->mask], cpy);
-				offset += cpy;
-				dst += cpy;
-				len -= cpy;
-			} while (len);
-
-			event = &evlist->event_copy;
-		}
-
-		old += size;
-	}
-
-	md->prev = old;
-
-	if (!evlist->overwrite)
-		perf_mmap__write_tail(md, old);
-
-	return event;
-}
-
 void perf_evlist__munmap(struct perf_evlist *evlist)
 {
 	int i;
 
 	for (i = 0; i < evlist->nr_mmaps; i++) {
-		if (evlist->mmap[i].base != NULL) {
-			munmap(evlist->mmap[i].base, evlist->mmap_len);
-			evlist->mmap[i].base = NULL;
-		}
+		struct perf_mmap *m = &evlist->mmap[i];
+		if (m->base != NULL)
+			perf_mmap__close(m);
 	}
 
 	free(evlist->mmap);
@@ -292,20 +225,18 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 }
 
 static int __perf_evlist__mmap(struct perf_evlist *evlist,
-			       int idx, int prot, int mask, int fd)
+			       int idx, int fd)
 {
-	evlist->mmap[idx].prev = 0;
-	evlist->mmap[idx].mask = mask;
-	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
-				      MAP_SHARED, fd, 0);
-	if (evlist->mmap[idx].base == MAP_FAILED)
+	struct perf_mmap *m = &evlist->mmap[idx];
+
+	if (perf_mmap__open(m, fd, evlist->overwrite, evlist->pages))
 		return -1;
 
 	perf_evlist__add_pollfd(evlist, fd);
 	return 0;
 }
 
-static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
+static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel;
 	int cpu, thread;
@@ -320,7 +251,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
 				if (output == -1) {
 					output = fd;
 					if (__perf_evlist__mmap(evlist, cpu,
-								prot, mask, output) < 0)
+								output) < 0)
 						goto out_unmap;
 				} else {
 					if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
@@ -334,15 +265,14 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
 
 out_unmap:
 	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		if (evlist->mmap[cpu].base != NULL) {
-			munmap(evlist->mmap[cpu].base, evlist->mmap_len);
-			evlist->mmap[cpu].base = NULL;
-		}
+		struct perf_mmap *m = &evlist->mmap[cpu];
+		if (m->base != NULL)
+			perf_mmap__close(m);
 	}
 	return -1;
 }
 
-static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
+static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel;
 	int thread;
@@ -356,7 +286,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
 			if (output == -1) {
 				output = fd;
 				if (__perf_evlist__mmap(evlist, thread,
-							prot, mask, output) < 0)
+							output) < 0)
 					goto out_unmap;
 			} else {
 				if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
@@ -369,10 +299,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
 
 out_unmap:
 	for (thread = 0; thread < evlist->threads->nr; thread++) {
-		if (evlist->mmap[thread].base != NULL) {
-			munmap(evlist->mmap[thread].base, evlist->mmap_len);
-			evlist->mmap[thread].base = NULL;
-		}
+		struct perf_mmap *m = &evlist->mmap[thread];
+		if (m->base != NULL)
+			perf_mmap__close(m);
 	}
 	return -1;
 }
@@ -421,10 +350,8 @@ static int perf_evlist__init_ids(struct perf_evlist *evlist)
  */
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 {
-	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-	int mask = pages * page_size - 1, ret;
 	const struct cpu_map *cpus = evlist->cpus;
-	int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
+	int ret;
 
 	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
 		return -ENOMEM;
@@ -433,16 +360,16 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 		return -ENOMEM;
 
 	evlist->overwrite = overwrite;
-	evlist->mmap_len = (pages + 1) * page_size;
+	evlist->pages = pages;
 
 	ret = perf_evlist__init_ids(evlist);
 	if (ret)
 		return ret;
 
 	if (cpus->map[0] == -1)
-		return perf_evlist__mmap_per_thread(evlist, prot, mask);
+		return perf_evlist__mmap_per_thread(evlist);
 
-	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
+	return perf_evlist__mmap_per_cpu(evlist);
 }
 
 int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 1779ffe..3784273 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -18,7 +18,7 @@ struct perf_evlist {
 	int		 nr_entries;
 	int		 nr_fds;
 	int		 nr_mmaps;
-	int		 mmap_len;
+	int		 pages;
 	bool		 overwrite;
 	union perf_event event_copy;
 	struct perf_mmap *mmap;
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
new file mode 100644
index 0000000..45e62a2
--- /dev/null
+++ b/tools/perf/util/mmap.c
@@ -0,0 +1,138 @@
+#include <string.h>
+#include <stdio.h>
+#include "mmap.h"
+
+int perf_mmap__open(struct perf_mmap *m, int fd, bool overwrite, int pages)
+{
+	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
+	int mask, len, prot;
+	void *base;
+
+	mask = pages * page_size - 1;
+	len  = (pages + 1) * page_size;
+	prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
+
+	base = mmap(NULL, len, prot, MAP_SHARED, fd, 0);
+	if (base == MAP_FAILED)
+		return -1;
+
+	memset(m, 0, sizeof(*m));
+	m->mask = mask;
+	m->len  = len;
+	m->base = base;
+	m->fd   = fd;
+	m->owrt = overwrite;
+	return 0;
+}
+
+int perf_mmap__close(struct perf_mmap *m)
+{
+	int ret = munmap(m->base, m->len);
+
+	memset(m, 0x0, sizeof(*m));
+	return ret;
+}
+
+int perf_mmap__process(struct perf_mmap *md, perf_mmap_process_t process)
+{
+	unsigned int head, old, page_size = sysconf(_SC_PAGE_SIZE);
+	unsigned char *data = md->base + page_size;
+	unsigned long size;
+	void *buf;
+
+	head = perf_mmap__read_head(md);
+	old  = md->prev;
+
+	if (old == head)
+		return 0;
+
+	size = head - old;
+
+	if ((old & md->mask) + size != (head & md->mask)) {
+		buf = &data[old & md->mask];
+		size = md->mask + 1 - (old & md->mask);
+		old += size;
+
+		process(md, buf, size);
+	}
+
+	buf = &data[old & md->mask];
+	size = head - old;
+	old += size;
+
+	process(md, buf, size);
+
+	md->prev = old;
+	perf_mmap__write_tail(md, old);
+	return 1;
+}
+
+union perf_event *perf_mmap__read(struct perf_mmap *md)
+{
+	unsigned int head, old, page_size = sysconf(_SC_PAGE_SIZE);
+	unsigned char *data = md->base + page_size;
+	union perf_event *event = NULL;
+
+	head = perf_mmap__read_head(md);
+	old = md->prev;
+
+	if (md->owrt) {
+		/*
+		 * If we're further behind than half the buffer, there's
+		 * a chance the writer will bite our tail and mess up the
+		 * samples under us.
+		 *
+		 * If we somehow ended up ahead of the head, we got messed up.
+		 *
+		 * In either case, truncate and restart at head.
+		 */
+		int diff = head - old;
+		if (diff > md->mask / 2 || diff < 0) {
+			fprintf(stderr, "WARNING: failed to keep up "
+					"with mmap data.\n");
+
+			/*
+			 * head points to a known good entry, start there.
+			 */
+			old = head;
+		}
+	}
+
+	if (old != head) {
+		size_t size;
+
+		event = (union perf_event *)&data[old & md->mask];
+		size = event->header.size;
+
+		/*
+		 * Event straddles the mmap boundary -- header should always
+		 * be inside due to u64 alignment of output.
+		 */
+		if ((old & md->mask) + size != ((old + size) & md->mask)) {
+			unsigned int offset = old;
+			unsigned int len = min(sizeof(*event), size), cpy;
+			static union perf_event event_copy;
+			void *dst = &event_copy;
+
+			do {
+				cpy = min(md->mask + 1 - (offset & md->mask),
+					  len);
+				memcpy(dst, &data[offset & md->mask], cpy);
+				offset += cpy;
+				dst += cpy;
+				len -= cpy;
+			} while (len);
+
+			event = &event_copy;
+		}
+
+		old += size;
+	}
+
+	md->prev = old;
+
+	if (!md->owrt)
+		perf_mmap__write_tail(md, old);
+
+	return event;
+}
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
new file mode 100644
index 0000000..24cf88f
--- /dev/null
+++ b/tools/perf/util/mmap.h
@@ -0,0 +1,45 @@
+#ifndef __PERF_MMAP_H
+#define __PERF_MMAP_H
+
+#include <sys/mman.h>
+#include "event.h"
+#include "../perf.h"
+
+struct perf_mmap {
+	void  *base;
+	int   mask;
+	u_int prev;
+	int   len;
+	int   fd;
+	bool  owrt;
+};
+
+typedef void (*perf_mmap_process_t)(struct perf_mmap *m,
+				    void *buf, unsigned long size);
+
+int perf_mmap__open(struct perf_mmap *m, int fd, bool overwrite, int pages);
+int perf_mmap__close(struct perf_mmap *m);
+int perf_mmap__process(struct perf_mmap *m, perf_mmap_process_t process);
+union perf_event *perf_mmap__read(struct perf_mmap *md);
+
+static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
+{
+	struct perf_event_mmap_page *pc = mm->base;
+	int head = pc->data_head;
+	rmb();
+	return head;
+}
+
+static inline void perf_mmap__write_tail(struct perf_mmap *md,
+					 unsigned long tail)
+{
+	struct perf_event_mmap_page *pc = md->base;
+
+	/*
+	 * ensure all reads are done before we write the tail out.
+	 */
+	/* mb(); */
+	pc->data_tail = tail;
+}
+
+#endif /* __PERF_MMAP_H */
-- 
1.7.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 4/5] perf tool: Introducing perf_data object
  2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
                   ` (2 preceding siblings ...)
  2011-11-18 13:46 ` [PATCH 3/5] perf tool: Introducing perf_mmap object Jiri Olsa
@ 2011-11-18 13:46 ` Jiri Olsa
  2011-11-18 13:46 ` [PATCH 5/5] perf tool: Putting mmap support to " Jiri Olsa
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-18 13:46 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Adding perf_data object to handle input/output data files.
The objective is to have this functionality centralized
and ready for supporting multiple event data streams.

All the input/output file related functions originally scatered
through the whole code are now placed in perf_mmap object.

To open/close data file:
	perf_data__open
	perf_data__close

Plus several helper functions:
	perf_data__is_pipe
	perf_data__is_ro
	perf_data__is_new
	perf_data__size

The perf_data object handles input/output file open/create processing,
plus check for pipe intput/output.

The perf_session object was modified to contains perf_data. Thus for
perf_session users the change is almost invisible apart from newly
defined open mode enums:

	PERF_DATA_NONE
	PERF_DATA_READ
	PERF_DATA_WRITE_TRUNC
	PERF_DATA_WRITE_APPEND

The PERF_DATA_NONE serves for 'top' session, where no storage
is needed. The rest is selfexplanatory.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile               |    2 +
 tools/perf/builtin-annotate.c     |    3 +-
 tools/perf/builtin-buildid-list.c |    4 +-
 tools/perf/builtin-diff.c         |    6 +-
 tools/perf/builtin-evlist.c       |    3 +-
 tools/perf/builtin-inject.c       |    3 +-
 tools/perf/builtin-kmem.c         |    6 +-
 tools/perf/builtin-lock.c         |    3 +-
 tools/perf/builtin-record.c       |  134 ++++++++-----------------
 tools/perf/builtin-report.c       |    7 +-
 tools/perf/builtin-sched.c        |    6 +-
 tools/perf/builtin-script.c       |    3 +-
 tools/perf/builtin-timechart.c    |    7 +-
 tools/perf/builtin-top.c          |   12 +--
 tools/perf/util/data.c            |  203 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/data.h            |   65 ++++++++++++
 tools/perf/util/header.c          |   35 ++++---
 tools/perf/util/header.h          |    6 +-
 tools/perf/util/session.c         |  115 ++++++++--------------
 tools/perf/util/session.h         |   26 ++++--
 20 files changed, 429 insertions(+), 220 deletions(-)
 create mode 100644 tools/perf/util/data.c
 create mode 100644 tools/perf/util/data.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0158b66..a11ec3d 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -275,6 +275,7 @@ LIB_H += util/header.h
 LIB_H += util/help.h
 LIB_H += util/session.h
 LIB_H += util/mmap.h
+LIB_H += util/data.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
@@ -339,6 +340,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
 LIB_OBJS += $(OUTPUT)util/mmap.o
+LIB_OBJS += $(OUTPUT)util/data.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 46b4c24..cbaa8be 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -183,7 +183,8 @@ static int __cmd_annotate(void)
 	struct perf_evsel *pos;
 	u64 total_nr_samples;
 
-	session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, force,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index cb690a6..0f26866 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -43,8 +43,8 @@ static int perf_session__list_build_ids(void)
 {
 	struct perf_session *session;
 
-	session = perf_session__new(input_name, O_RDONLY, force, false,
-				    &build_id__mark_dso_hit_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, force,
+				    false, &build_id__mark_dso_hit_ops);
 	if (session == NULL)
 		return -1;
 
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index b39f3a1..093d5bf 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -145,8 +145,10 @@ static int __cmd_diff(void)
 	int ret, i;
 	struct perf_session *session[2];
 
-	session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops);
-	session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
+	session[0] = perf_session__new(input_old, PERF_DATA_READ, force,
+				       false, &event_ops);
+	session[1] = perf_session__new(input_new, PERF_DATA_READ, force,
+				       false, &event_ops);
 	if (session[0] == NULL || session[1] == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 4c5e9e0..87a6662 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -22,7 +22,8 @@ static int __cmd_evlist(void)
 	struct perf_session *session;
 	struct perf_evsel *pos;
 
-	session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
+	session = perf_session__new(input_name, PERF_DATA_READ,
+				    false, false, NULL);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 3c5eb3a..38a88ca 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -205,7 +205,8 @@ static int __cmd_inject(void)
 		inject_ops.tracing_data	= perf_event__repipe_tracing_data;
 	}
 
-	session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    true, &inject_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 2ca8206..1a80840 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -480,8 +480,10 @@ static void sort_result(void)
 static int __cmd_kmem(void)
 {
 	int err = -EINVAL;
-	struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-							 0, false, &event_ops);
+	struct perf_session *session;
+
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 899080a..af2c923 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -871,7 +871,8 @@ static struct perf_event_ops eops = {
 
 static int read_events(void)
 {
-	session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &eops);
 	if (!session)
 		die("Initializing perf session failed\n");
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 89b3dc2..4b0cf7c 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -31,11 +31,6 @@
 #include <sched.h>
 #include <sys/mman.h>
 
-enum write_mode_t {
-	WRITE_FORCE,
-	WRITE_APPEND
-};
-
 static u64			user_interval			= ULLONG_MAX;
 static u64			default_interval		=      0;
 
@@ -43,8 +38,6 @@ static unsigned int		page_size;
 static unsigned int		mmap_pages			= UINT_MAX;
 static unsigned int		user_freq 			= UINT_MAX;
 static int			freq				=   1000;
-static int			output;
-static int			pipe_output			=      0;
 static const char		*output_name			= NULL;
 static bool			group				=  false;
 static int			realtime_prio			=      0;
@@ -56,7 +49,7 @@ static pid_t			target_pid			=     -1;
 static pid_t			target_tid			=     -1;
 static pid_t			child_pid			=     -1;
 static bool			no_inherit			=  false;
-static enum write_mode_t	write_mode			= WRITE_FORCE;
+static enum perf_data_mode	write_mode			=  PERF_DATA_WRITE_TRUNC;
 static bool			call_graph			=  false;
 static bool			inherit_stat			=  false;
 static bool			no_samples			=  false;
@@ -68,7 +61,6 @@ static struct perf_evlist	*evsel_list;
 
 static u64			bytes_written			=      0;
 
-static int			file_new			=      1;
 static off_t			post_processing_offset;
 
 static struct perf_session	*session;
@@ -80,10 +72,10 @@ static void advance_output(size_t size)
 	bytes_written += size;
 }
 
-static void write_output(void *buf, size_t size)
+static void write_output(int fd, void *buf, size_t size)
 {
 	while (size) {
-		int ret = write(output, buf, size);
+		int ret = write(fd, buf, size);
 
 		if (ret < 0)
 			die("failed to write");
@@ -97,9 +89,10 @@ static void write_output(void *buf, size_t size)
 
 static int process_synthesized_event(union perf_event *event,
 				     struct perf_sample *sample __used,
-				     struct perf_session *self __used)
+				     struct perf_session *self)
 {
-	write_output(event, event->header.size);
+	int fd = perf_session__fd(self);
+	write_output(fd, event, event->header.size);
 	return 0;
 }
 
@@ -328,7 +321,7 @@ try_again:
 	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
 
-	if (file_new)
+	if (perf_session__is_new(session))
 		session->evlist = evlist;
 	else {
 		if (!perf_evlist__equal(session->evlist, evlist)) {
@@ -342,12 +335,11 @@ try_again:
 
 static int process_buildids(void)
 {
-	u64 size = lseek(output, 0, SEEK_CUR);
+	u64 size = lseek(perf_session__fd(session), 0, SEEK_CUR);
 
 	if (size == 0)
 		return 0;
 
-	session->fd = output;
 	return __perf_session__process_events(session, post_processing_offset,
 					      size - post_processing_offset,
 					      size, &build_id__mark_dso_hit_ops);
@@ -355,22 +347,23 @@ static int process_buildids(void)
 
 static void atexit_header(void)
 {
-	if (!pipe_output) {
+	if (!perf_session__is_pipe(session)) {
 		session->header.data_size += bytes_written;
 
 		if (!no_buildid)
 			process_buildids();
-		perf_session__write_header(session, evsel_list, output, true);
+		perf_session__write_header(session, evsel_list, true);
 		perf_session__delete(session);
 		perf_evlist__delete(evsel_list);
 		symbol__exit();
 	}
 }
 
-static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
+static void perf_event__synthesize_guest_os(struct machine *machine,
+					    void *__data)
 {
 	int err;
-	struct perf_session *psession = data;
+	struct perf_session *psession = __data;
 
 	if (machine__is_host(machine))
 		return;
@@ -411,7 +404,8 @@ static struct perf_event_header finished_round_event = {
 
 static void mmap_read(struct perf_mmap *m __used, void *buf, unsigned long size)
 {
-	write_output(buf, size);
+	int fd = perf_session__fd(session);
+	write_output(fd, buf, size);
 }
 
 static int mmap_read_all(void)
@@ -420,26 +414,25 @@ static int mmap_read_all(void)
 
 	for (i = 0; i < evsel_list->nr_mmaps; i++) {
 		struct perf_mmap *m = &evsel_list->mmap[i];
-		if (m->base)
-			ret += perf_mmap__process(m, mmap_read);
+		ret += perf_mmap__process(m, mmap_read);
 	}
 
-	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
-		write_output(&finished_round_event, sizeof(finished_round_event));
+	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) {
+		int fd = perf_session__fd(session);
+		write_output(fd, &finished_round_event,
+			     sizeof(finished_round_event));
+	}
 
 	return ret;
 }
 
 static int __cmd_record(int argc, const char **argv)
 {
-	struct stat st;
-	int flags;
-	int err;
+	struct machine *machine;
 	unsigned long waking = 0;
-	int child_ready_pipe[2], go_pipe[2];
+	int child_ready_pipe[2], go_pipe[2], err;
 	const bool forks = argc > 0;
 	char buf;
-	struct machine *machine;
 
 	progname = argv[0];
 
@@ -455,45 +448,8 @@ static int __cmd_record(int argc, const char **argv)
 		exit(-1);
 	}
 
-	if (!output_name) {
-		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
-			pipe_output = 1;
-		else
-			output_name = "perf.data";
-	}
-	if (output_name) {
-		if (!strcmp(output_name, "-"))
-			pipe_output = 1;
-		else if (!stat(output_name, &st) && st.st_size) {
-			if (write_mode == WRITE_FORCE) {
-				char oldname[PATH_MAX];
-				snprintf(oldname, sizeof(oldname), "%s.old",
-					 output_name);
-				unlink(oldname);
-				rename(output_name, oldname);
-			}
-		} else if (write_mode == WRITE_APPEND) {
-			write_mode = WRITE_FORCE;
-		}
-	}
-
-	flags = O_CREAT|O_RDWR;
-	if (write_mode == WRITE_APPEND)
-		file_new = 0;
-	else
-		flags |= O_TRUNC;
-
-	if (pipe_output)
-		output = STDOUT_FILENO;
-	else
-		output = open(output_name, flags, S_IRUSR | S_IWUSR);
-	if (output < 0) {
-		perror("failed to create output file");
-		exit(-1);
-	}
-
-	session = perf_session__new(output_name, O_WRONLY,
-				    write_mode == WRITE_FORCE, false, NULL);
+	session = perf_session__new(output_name, write_mode,
+				    false, false, NULL);
 	if (session == NULL) {
 		pr_err("Not enough memory for reading perf file header\n");
 		return -1;
@@ -502,8 +458,8 @@ static int __cmd_record(int argc, const char **argv)
 	if (!no_buildid)
 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
 
-	if (!file_new) {
-		err = perf_session__read_header(session, output);
+	if (!perf_session__is_new(session)) {
+		err = perf_session__read_header(session);
 		if (err < 0)
 			goto out_delete_session;
 	}
@@ -536,7 +492,7 @@ static int __cmd_record(int argc, const char **argv)
 		}
 
 		if (!child_pid) {
-			if (pipe_output)
+			if (perf_session__is_pipe(session))
 				dup2(2, 1);
 			close(child_ready_pipe[0]);
 			close(go_pipe[1]);
@@ -589,32 +545,31 @@ static int __cmd_record(int argc, const char **argv)
 	 */
 	atexit(atexit_header);
 
-	if (pipe_output) {
-		err = perf_header__write_pipe(output);
+	if (perf_session__is_pipe(session)) {
+		err = perf_header__write_pipe(perf_session__fd(session));
 		if (err < 0)
-			return err;
-	} else if (file_new) {
-		err = perf_session__write_header(session, evsel_list,
-						 output, false);
+			goto out_delete_session;
+	} else if (perf_session__is_new(session)) {
+		err = perf_session__write_header(session, evsel_list, false);
 		if (err < 0)
-			return err;
+			goto out_delete_session;
 	}
 
-	post_processing_offset = lseek(output, 0, SEEK_CUR);
+	post_processing_offset = lseek(perf_session__fd(session), 0, SEEK_CUR);
 
-	if (pipe_output) {
+	if (perf_session__is_pipe(session)) {
 		err = perf_session__synthesize_attrs(session,
 						     process_synthesized_event);
 		if (err < 0) {
 			pr_err("Couldn't synthesize attrs.\n");
-			return err;
+			goto out_delete_session;
 		}
 
 		err = perf_event__synthesize_event_types(process_synthesized_event,
 							 session);
 		if (err < 0) {
 			pr_err("Couldn't synthesize event_types.\n");
-			return err;
+			goto out_delete_session;
 		}
 
 		if (have_tracepoints(&evsel_list->entries)) {
@@ -626,12 +581,12 @@ static int __cmd_record(int argc, const char **argv)
 			 * return this more properly and also
 			 * propagate errors that now are calling die()
 			 */
-			err = perf_event__synthesize_tracing_data(output, evsel_list,
+			err = perf_event__synthesize_tracing_data(evsel_list,
 								  process_synthesized_event,
 								  session);
 			if (err <= 0) {
 				pr_err("Couldn't record tracing data.\n");
-				return err;
+				goto out_delete_session;
 			}
 			advance_output(err);
 		}
@@ -699,7 +654,7 @@ static int __cmd_record(int argc, const char **argv)
 	}
 
 	if (quiet || signr == SIGUSR1)
-		return 0;
+		goto out_delete_session;
 
 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
 
@@ -804,9 +759,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 				" You need to choose between -f and -A");
 		usage_with_options(record_usage, record_options);
 	} else if (append_file) {
-		write_mode = WRITE_APPEND;
+		write_mode = PERF_DATA_WRITE_APPEND;
 	} else {
-		write_mode = WRITE_FORCE;
+		write_mode = PERF_DATA_WRITE_TRUNC;
 	}
 
 	if (nr_cgroups && !system_wide) {
@@ -851,9 +806,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 			goto out_free_fd;
 	}
 
-	if (perf_evlist__alloc_pollfd(evsel_list) < 0)
-		goto out_free_fd;
-
 	if (user_interval != ULLONG_MAX)
 		default_interval = user_interval;
 	if (user_freq != UINT_MAX)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4d7c834..5a98b8e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -35,7 +35,7 @@
 
 #include <linux/bitmap.h>
 
-static char		const *input_name = "perf.data";
+static char		const *input_name;
 
 static bool		force, use_tui, use_stdio;
 static bool		hide_unresolved;
@@ -264,7 +264,8 @@ static int __cmd_report(void)
 
 	signal(SIGINT, sig_handler);
 
-	session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, force,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
@@ -514,7 +515,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
 	if (inverted_callchain)
 		callchain_param.order = ORDER_CALLER;
 
-	if (strcmp(input_name, "-") != 0)
+	if (input_name && strcmp(input_name, "-") != 0)
 		setup_browser(true);
 	else
 		use_browser = 0;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 5177964..266333c 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1640,8 +1640,10 @@ static struct perf_event_ops event_ops = {
 static void read_events(bool destroy, struct perf_session **psession)
 {
 	int err = -EINVAL;
-	struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-							 0, false, &event_ops);
+	struct perf_session *session;
+
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		die("No Memory");
 
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 2f62a29..89ae663 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1261,7 +1261,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
 	if (!script_name)
 		setup_pager();
 
-	session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index aa26f4d..e3f4951 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -984,10 +984,11 @@ static struct perf_event_ops event_ops = {
 
 static int __cmd_timechart(void)
 {
-	struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-							 0, false, &event_ops);
-	int ret = -EINVAL;
+	struct perf_session *session;
+	int ret = EINVAL;
 
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 032f70d..e86d728 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -959,11 +959,9 @@ static int __cmd_top(void)
 {
 	pthread_t thread;
 	int ret;
-	/*
-	 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
-	 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
-	 */
-	top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
+
+	top.session = perf_session__new(NULL, PERF_DATA_NONE, false,
+					false, NULL);
 	if (top.session == NULL)
 		return -ENOMEM;
 
@@ -1248,10 +1246,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
 		pos->attr.sample_period = default_interval;
 	}
 
-	if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
-	    perf_evlist__alloc_mmap(top.evlist) < 0)
-		goto out_free_fd;
-
 	top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
 
 	symbol_conf.priv_size = sizeof(struct annotation);
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
new file mode 100644
index 0000000..c025d0f
--- /dev/null
+++ b/tools/perf/util/data.c
@@ -0,0 +1,203 @@
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <errno.h>
+
+#include "data.h"
+#include "util.h"
+#include "cpumap.h"
+#include "thread_map.h"
+#include "evsel.h"
+
+static bool pipe_is_fd(int fd)
+{
+	struct stat st;
+	return !fstat(fd, &st) && S_ISFIFO(st.st_mode);
+}
+
+static int pipe_get_fd(int mode)
+{
+	if (mode == PERF_DATA_READ)
+		return STDIN_FILENO;
+	return STDOUT_FILENO;
+}
+
+static bool pipe_chk(const char *name, int mode)
+{
+	int fd = pipe_get_fd(mode);
+
+	if (!name && pipe_is_fd(fd))
+		return true;
+
+	if (name && !strcmp(name, "-"))
+		return true;
+
+	return false;
+}
+
+static int pipe_data(struct perf_data *data)
+{
+	struct perf_data_file *file = &data->header;
+
+	memset(file, 0, sizeof(*file));
+	file->fd = pipe_get_fd(data->mode);
+	return 0;
+}
+
+static int file_chk_read(struct perf_data *data,
+			 struct stat *st, char *name)
+{
+	if (!data->force &&
+	    st->st_uid && (st->st_uid != geteuid())) {
+		pr_err("file %s not owned by current user or root\n",
+		       name);
+		return -1;
+	}
+
+	if (!st->st_size) {
+		pr_info("zero-sized file (%s), nothing to do!\n",
+			name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int file_open(struct perf_data *data, char *name)
+{
+	int flags = 0, fd;
+	int mode = data->mode;
+
+	switch (mode) {
+	case PERF_DATA_READ:
+		flags = O_RDONLY;
+		break;
+	case PERF_DATA_WRITE_TRUNC:
+		flags = O_TRUNC;
+	/* falling through intentionally */
+	case PERF_DATA_WRITE_APPEND:
+		flags |= O_CREAT|O_RDWR;
+		break;
+	default:
+		return -1;
+	};
+
+	fd = open(name, flags, S_IRUSR | S_IWUSR);
+	if (fd < 0)
+		perror("failed to create output file");
+
+	return fd;
+}
+
+static int file_backup(char *name)
+{
+	char oldname[PATH_MAX];
+	int ret;
+
+	snprintf(oldname, sizeof(oldname), "%s.old",
+		 name);
+
+	ret = unlink(oldname);
+	if (ret)
+		return ret;
+
+	ret = rename(name, oldname);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int data_file__open(struct perf_data *data,
+			   struct perf_data_file *file,
+			   char *name)
+{
+	struct stat st;
+	int fd, mode = data->mode;
+	bool exists;
+
+	exists = (!stat(name, &st) && st.st_size);
+
+	/* make the file backup if needed */
+	if (exists && (mode == PERF_DATA_WRITE_TRUNC)) {
+		int ret = file_backup(name);
+		if (ret)
+			return ret;
+	}
+
+	/* nothing to append to, change mode */
+	if (!exists &&
+	    (mode == PERF_DATA_WRITE_APPEND))
+		mode = PERF_DATA_WRITE_TRUNC;
+
+	data->mode = mode;
+	memset(file, 0, sizeof(*file));
+
+	/* read sanity checks */
+	if (mode == PERF_DATA_READ) {
+		if (!exists) {
+			pr_err("failed to open %s: does not exist\n", name);
+			return -EINVAL;
+		}
+		if (file_chk_read(data, &st, name))
+			return -1;
+		file->size = st.st_size;
+	}
+
+	fd = file_open(data, name);
+	if (fd < 0)
+		return errno;
+
+	file->name = name;
+	file->fd = fd;
+
+	list_add_tail(&file->list, &data->files);
+	return 0;
+}
+
+static void data_file__close(struct perf_data *data __used,
+			     struct perf_data_file *file)
+{
+	close(file->fd);
+}
+
+int perf_data__open(struct perf_data *data, const char *name,
+		    int mode, bool force)
+{
+	bool is_pipe;
+
+	memset(data, 0, sizeof(*data));
+	data->mode = mode;
+	INIT_LIST_HEAD(&data->files);
+
+	if (mode == PERF_DATA_NONE)
+		return 0;
+
+	is_pipe = pipe_chk(name, mode);
+	if (!is_pipe && !name)
+		name = "perf.data";
+
+	data->force   = force;
+	data->is_pipe = is_pipe;
+
+	if (is_pipe)
+		return pipe_data(data);
+
+	return data_file__open(data, &data->header, (char *) name);
+}
+
+void perf_data__close(struct perf_data *data)
+{
+	struct perf_data_file *file;
+
+	if (!data->is_pipe)
+		return;
+
+	list_for_each_entry(file, &data->files, list)
+		data_file__close(data, file);
+}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
new file mode 100644
index 0000000..3103f7a
--- /dev/null
+++ b/tools/perf/util/data.h
@@ -0,0 +1,65 @@
+#ifndef __PERF_DATA_H
+#define __PERF_DATA_H
+
+#include <stdbool.h>
+#include <linux/list.h>
+#include "mmap.h"
+#include "evlist.h"
+
+enum perf_data_mode {
+	PERF_DATA_NONE,
+	PERF_DATA_READ,
+	PERF_DATA_WRITE_TRUNC,
+	PERF_DATA_WRITE_APPEND,
+};
+
+struct perf_data_file {
+	int fd;
+	off_t size;
+	char *name;
+
+	struct list_head list;
+};
+
+struct perf_data {
+	struct perf_data_file header;
+
+	bool is_pipe;
+	int  mode;
+	bool force;
+
+	struct list_head files;
+};
+
+int perf_data__open(struct perf_data *data, const char *name,
+		    int mode, bool force);
+void perf_data__close(struct perf_data *data);
+
+#define PERF_DATA__NONE(__data) \
+	perf_data__open(&__data, NULL, PERF_DATA_NONE, false);
+
+static inline int perf_data__is_pipe(struct perf_data *data)
+{
+	return data->is_pipe;
+}
+
+static inline int perf_data__is_ro(struct perf_data *data)
+{
+	return data->mode == PERF_DATA_READ;
+}
+
+static inline int perf_data__is_new(struct perf_data *data)
+{
+	return data->mode == PERF_DATA_WRITE_TRUNC;
+}
+
+static inline off_t perf_data__size(struct perf_data *data)
+{
+	return data->header.size;
+}
+
+static inline int perf_data__fd(struct perf_data *data)
+{
+	return data->header.fd;
+}
+#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index bcd05d0..f1580c8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1123,7 +1123,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
 {
 	struct header_print_data hd;
 	struct perf_header *header = &session->header;
-	int fd = session->fd;
+	int fd = perf_session__fd(session);
 	hd.fp = fp;
 	hd.full = full;
 
@@ -1525,13 +1525,13 @@ int perf_header__write_pipe(int fd)
 
 int perf_session__write_header(struct perf_session *session,
 			       struct perf_evlist *evlist,
-			       int fd, bool at_exit)
+			       bool at_exit)
 {
 	struct perf_file_header f_header;
 	struct perf_file_attr   f_attr;
 	struct perf_header *header = &session->header;
 	struct perf_evsel *attr, *pair = NULL;
-	int err;
+	int err, fd = perf_session__fd(session);
 
 	lseek(fd, sizeof(f_header), SEEK_SET);
 
@@ -1960,10 +1960,11 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
 	return 0;
 }
 
-static int perf_header__read_pipe(struct perf_session *session, int fd)
+static int perf_header__read_pipe(struct perf_session *session)
 {
 	struct perf_header *header = &session->header;
 	struct perf_pipe_file_header f_header;
+	int fd = perf_session__fd(session);
 
 	if (perf_file_header__read_pipe(&f_header, header, fd,
 					session->repipe) < 0) {
@@ -1971,25 +1972,24 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
 		return -EINVAL;
 	}
 
-	session->fd = fd;
-
 	return 0;
 }
 
-int perf_session__read_header(struct perf_session *session, int fd)
+int perf_session__read_header(struct perf_session *session)
 {
 	struct perf_header *header = &session->header;
 	struct perf_file_header	f_header;
 	struct perf_file_attr	f_attr;
 	u64			f_id;
 	int nr_attrs, nr_ids, i, j;
+	int fd = perf_session__fd(session);
 
 	session->evlist = perf_evlist__new(NULL, NULL);
 	if (session->evlist == NULL)
 		return -ENOMEM;
 
-	if (session->fd_pipe)
-		return perf_header__read_pipe(session, fd);
+	if (perf_session__is_pipe(session))
+		return perf_header__read_pipe(session);
 
 	if (perf_file_header__read(&f_header, header, fd) < 0) {
 		pr_debug("incompatible file format\n");
@@ -2213,14 +2213,14 @@ int perf_event__process_event_type(union perf_event *event,
 	return 0;
 }
 
-int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
-					 perf_event__handler_t process,
-				   struct perf_session *session __unused)
+int perf_event__synthesize_tracing_data(struct perf_evlist *evlist,
+					perf_event__handler_t process,
+					struct perf_session *session)
 {
 	union perf_event ev;
 	struct tracing_data *tdata;
 	ssize_t size = 0, aligned_size = 0, padding;
-	int err __used = 0;
+	int fd = perf_session__fd(session);
 
 	/*
 	 * We are going to store the size of the data followed
@@ -2263,18 +2263,19 @@ int perf_event__process_tracing_data(union perf_event *event,
 				     struct perf_session *session)
 {
 	ssize_t size_read, padding, size = event->tracing_data.size;
-	off_t offset = lseek(session->fd, 0, SEEK_CUR);
+	int fd = perf_session__fd(session);
+	off_t offset = lseek(fd, 0, SEEK_CUR);
 	char buf[BUFSIZ];
 
 	/* setup for reading amidst mmap */
-	lseek(session->fd, offset + sizeof(struct tracing_data_event),
+	lseek(fd, offset + sizeof(struct tracing_data_event),
 	      SEEK_SET);
 
-	size_read = trace_report(session->fd, session->repipe);
+	size_read = trace_report(fd, session->repipe);
 
 	padding = ALIGN(size_read, sizeof(u64)) - size_read;
 
-	if (read(session->fd, buf, padding) < 0)
+	if (read(fd, buf, padding) < 0)
 		die("reading input file");
 	if (session->repipe) {
 		int retw = write(STDOUT_FILENO, buf, padding);
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 3d5a742..63b56ba 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -69,10 +69,10 @@ struct perf_header {
 
 struct perf_evlist;
 
-int perf_session__read_header(struct perf_session *session, int fd);
+int perf_session__read_header(struct perf_session *session);
 int perf_session__write_header(struct perf_session *session,
 			       struct perf_evlist *evlist,
-			       int fd, bool at_exit);
+			       bool at_exit);
 int perf_header__write_pipe(int fd);
 
 int perf_header__push_event(u64 id, const char *name);
@@ -111,7 +111,7 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
 int perf_event__process_event_type(union perf_event *event,
 				   struct perf_session *session);
 
-int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
+int perf_event__synthesize_tracing_data(struct perf_evlist *evlist,
 					perf_event__handler_t process,
 					struct perf_session *session);
 int perf_event__process_tracing_data(union perf_event *event,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 85c1e6b7..219ce32 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -13,69 +13,26 @@
 #include "sort.h"
 #include "util.h"
 #include "cpumap.h"
+#include "data.h"
 
-static int perf_session__open(struct perf_session *self, bool force)
+static int perf_session__open(struct perf_session *self)
 {
-	struct stat input_stat;
-
-	if (!strcmp(self->filename, "-")) {
-		self->fd_pipe = true;
-		self->fd = STDIN_FILENO;
-
-		if (perf_session__read_header(self, self->fd) < 0)
-			pr_err("incompatible file format");
-
-		return 0;
-	}
-
-	self->fd = open(self->filename, O_RDONLY);
-	if (self->fd < 0) {
-		int err = errno;
-
-		pr_err("failed to open %s: %s", self->filename, strerror(err));
-		if (err == ENOENT && !strcmp(self->filename, "perf.data"))
-			pr_err("  (try 'perf record' first)");
-		pr_err("\n");
-		return -errno;
-	}
-
-	if (fstat(self->fd, &input_stat) < 0)
-		goto out_close;
-
-	if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-		pr_err("file %s not owned by current user or root\n",
-		       self->filename);
-		goto out_close;
-	}
-
-	if (!input_stat.st_size) {
-		pr_info("zero-sized file (%s), nothing to do!\n",
-			self->filename);
-		goto out_close;
-	}
-
-	if (perf_session__read_header(self, self->fd) < 0) {
+	if (perf_session__read_header(self) < 0) {
 		pr_err("incompatible file format");
-		goto out_close;
+		return -1;
 	}
 
 	if (!perf_evlist__valid_sample_type(self->evlist)) {
 		pr_err("non matching sample_type");
-		goto out_close;
+		return -1;
 	}
 
 	if (!perf_evlist__valid_sample_id_all(self->evlist)) {
 		pr_err("non matching sample_id_all");
-		goto out_close;
+		return -1;
 	}
 
-	self->size = input_stat.st_size;
 	return 0;
-
-out_close:
-	close(self->fd);
-	self->fd = -1;
-	return -1;
 }
 
 static void perf_session__id_header_size(struct perf_session *session)
@@ -128,17 +85,15 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
 	machines__destroy_guest_kernel_maps(&self->machines);
 }
 
-struct perf_session *perf_session__new(const char *filename, int mode,
-				       bool force, bool repipe,
-				       struct perf_event_ops *ops)
+struct perf_session *perf_session__new(const char *name, int mode, bool force,
+				       bool repipe, struct perf_event_ops *ops)
 {
-	size_t len = filename ? strlen(filename) + 1 : 0;
-	struct perf_session *self = zalloc(sizeof(*self) + len);
+	struct perf_session *self;
 
-	if (self == NULL)
-		goto out;
+	self = zalloc(sizeof(*self));
+	if (!self)
+		return NULL;
 
-	memcpy(self->filename, filename, len);
 	self->threads = RB_ROOT;
 	INIT_LIST_HEAD(&self->dead_threads);
 	self->last_match = NULL;
@@ -158,17 +113,20 @@ struct perf_session *perf_session__new(const char *filename, int mode,
 	INIT_LIST_HEAD(&self->ordered_samples.to_free);
 	machine__init(&self->host_machine, "", HOST_KERNEL_ID);
 
-	if (mode == O_RDONLY) {
-		if (perf_session__open(self, force) < 0)
-			goto out_delete;
+	if (perf_data__open(&self->data, name, mode, force))
+		goto out_delete_session;
+
+	if (perf_data__is_ro(&self->data)) {
+		if (perf_session__open(self) < 0)
+			goto out_close_data;
 		perf_session__update_sample_type(self);
-	} else if (mode == O_WRONLY) {
+	} else {
 		/*
 		 * In O_RDONLY mode this will be performed when reading the
 		 * kernel MMAP event, in perf_event__process_mmap().
 		 */
 		if (perf_session__create_kernel_maps(self) < 0)
-			goto out_delete;
+			goto out_close_data;
 	}
 
 	if (ops && ops->ordering_requires_timestamps &&
@@ -177,9 +135,12 @@ struct perf_session *perf_session__new(const char *filename, int mode,
 		ops->ordered_samples = false;
 	}
 
-out:
 	return self;
-out_delete:
+
+out_close_data:
+	perf_data__close(&self->data);
+
+out_delete_session:
 	perf_session__delete(self);
 	return NULL;
 }
@@ -213,7 +174,7 @@ void perf_session__delete(struct perf_session *self)
 	perf_session__delete_dead_threads(self);
 	perf_session__delete_threads(self);
 	machine__exit(&self->host_machine);
-	close(self->fd);
+	perf_data__close(&self->data);
 	free(self);
 }
 
@@ -814,6 +775,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
 static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
 					    struct perf_event_ops *ops, u64 file_offset)
 {
+	int fd = perf_session__fd(session);
+
 	dump_event(session, event, file_offset, NULL);
 
 	/* These events are processed right away */
@@ -824,7 +787,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
 		return ops->event_type(event, session);
 	case PERF_RECORD_HEADER_TRACING_DATA:
 		/* setup for reading amidst mmap */
-		lseek(session->fd, file_offset, SEEK_SET);
+		lseek(fd, file_offset, SEEK_SET);
 		return ops->tracing_data(event, session);
 	case PERF_RECORD_HEADER_BUILD_ID:
 		return ops->build_id(event, session);
@@ -942,12 +905,13 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
 	u64 head;
 	int err;
 	void *p;
+	int fd = perf_session__fd(self);
 
 	perf_event_ops__fill_defaults(ops);
 
 	head = 0;
 more:
-	err = readn(self->fd, &event, sizeof(struct perf_event_header));
+	err = readn(fd, &event, sizeof(struct perf_event_header));
 	if (err <= 0) {
 		if (err == 0)
 			goto done;
@@ -967,7 +931,7 @@ more:
 	p += sizeof(struct perf_event_header);
 
 	if (size - sizeof(struct perf_event_header)) {
-		err = readn(self->fd, p, size - sizeof(struct perf_event_header));
+		err = readn(fd, p, size - sizeof(struct perf_event_header));
 		if (err <= 0) {
 			if (err == 0) {
 				pr_err("unexpected end of event stream\n");
@@ -1042,6 +1006,7 @@ int __perf_session__process_events(struct perf_session *session,
 	char *buf, *mmaps[8];
 	union perf_event *event;
 	uint32_t size;
+	int fd = perf_session__fd(session);
 
 	perf_event_ops__fill_defaults(ops);
 
@@ -1070,7 +1035,7 @@ int __perf_session__process_events(struct perf_session *session,
 		mmap_flags = MAP_PRIVATE;
 	}
 remap:
-	buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
+	buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd,
 		   file_offset);
 	if (buf == MAP_FAILED) {
 		pr_err("failed to mmap file\n");
@@ -1142,11 +1107,12 @@ int perf_session__process_events(struct perf_session *self,
 	if (perf_session__register_idle_thread(self) == NULL)
 		return -ENOMEM;
 
-	if (!self->fd_pipe)
+	if (!perf_session__is_pipe(self))
 		err = __perf_session__process_events(self,
-						     self->header.data_offset,
-						     self->header.data_size,
-						     self->size, ops);
+					     self->header.data_offset,
+					     self->header.data_size,
+					     perf_data__size(&self->data),
+					     ops);
 	else
 		err = __perf_session__process_pipe_events(self, ops);
 
@@ -1354,11 +1320,12 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
 {
 	struct stat st;
 	int ret;
+	int fd = perf_session__fd(session);
 
 	if (session == NULL || fp == NULL)
 		return;
 
-	ret = fstat(session->fd, &st);
+	ret = fstat(fd, &st);
 	if (ret == -1)
 		return;
 
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index a81d666..cbc37f3 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -6,6 +6,7 @@
 #include "header.h"
 #include "symbol.h"
 #include "thread.h"
+#include "data.h"
 #include <linux/rbtree.h>
 #include "../../../include/linux/perf_event.h"
 
@@ -28,7 +29,7 @@ struct ordered_samples {
 
 struct perf_session {
 	struct perf_header	header;
-	unsigned long		size;
+	struct perf_data	data;
 	unsigned long		mmap_window;
 	struct rb_root		threads;
 	struct list_head	dead_threads;
@@ -45,8 +46,6 @@ struct perf_session {
 	struct hists		hists;
 	u64			sample_type;
 	int			sample_size;
-	int			fd;
-	bool			fd_pipe;
 	bool			repipe;
 	bool			sample_id_all;
 	u16			id_hdr_size;
@@ -54,7 +53,6 @@ struct perf_session {
 	char			*cwd;
 	struct ordered_samples	ordered_samples;
 	struct callchain_cursor	callchain_cursor;
-	char			filename[0];
 };
 
 struct perf_evsel;
@@ -88,9 +86,8 @@ struct perf_event_ops {
 	bool		ordering_requires_timestamps;
 };
 
-struct perf_session *perf_session__new(const char *filename, int mode,
-				       bool force, bool repipe,
-				       struct perf_event_ops *ops);
+struct perf_session *perf_session__new(const char *name, int mode, bool force,
+				       bool repipe, struct perf_event_ops *ops);
 void perf_session__delete(struct perf_session *self);
 
 void perf_event_header__bswap(struct perf_event_header *self);
@@ -179,4 +176,19 @@ int perf_session__cpu_bitmap(struct perf_session *session,
 			     const char *cpu_list, unsigned long *cpu_bitmap);
 
 void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
+
+static inline bool perf_session__is_new(struct perf_session *self)
+{
+	return perf_data__is_new(&self->data);
+}
+
+static inline int perf_session__fd(struct perf_session *self)
+{
+	return perf_data__fd(&self->data);
+}
+
+static inline int perf_session__is_pipe(struct perf_session *self)
+{
+	return perf_data__is_pipe(&self->data);
+}
 #endif /* __PERF_SESSION_H */
-- 
1.7.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 5/5] perf tool: Putting mmap support to perf_data object
  2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
                   ` (3 preceding siblings ...)
  2011-11-18 13:46 ` [PATCH 4/5] perf tool: Introducing perf_data object Jiri Olsa
@ 2011-11-18 13:46 ` Jiri Olsa
  2011-11-18 14:14 ` [RFC,PATCH] perf tool: Refactoring IO data files code Arnaldo Carvalho de Melo
  2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
  6 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-18 13:46 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Adding event memory maps management under the perf_data
object. The objective is to have this functionality
centralized and dont mix this functionality into event
list.

New function 'perf_data__mmap' is added into perf_data. It prepares
allocates/prepares both perf_mmap and pollfd structures, and does
the actuall mmap-ing.

Each perf_mmap now contains perf_data_file structure,
to have memory map connected directly with the storage.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-record.c |   29 +++++--
 tools/perf/builtin-test.c   |   13 +++-
 tools/perf/builtin-top.c    |   21 ++++--
 tools/perf/util/data.c      |  100 ++++++++++++++++++++++++
 tools/perf/util/data.h      |   13 +++
 tools/perf/util/evlist.c    |  181 ++-----------------------------------------
 tools/perf/util/evlist.h    |    8 +--
 tools/perf/util/evsel.h     |    4 +-
 tools/perf/util/mmap.h      |    3 +
 tools/perf/util/python.c    |   23 ++++--
 tools/perf/util/session.h   |    6 ++
 11 files changed, 192 insertions(+), 209 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4b0cf7c..24bce09 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -318,8 +318,9 @@ try_again:
 		exit(-1);
 	}
 
-	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
-		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
+	if (perf_evlist__init_ids(evlist))
+		die("failed to init sample IDs %d (%s)\n",
+		    errno, strerror(errno));
 
 	if (perf_session__is_new(session))
 		session->evlist = evlist;
@@ -402,18 +403,18 @@ static struct perf_event_header finished_round_event = {
 	.type = PERF_RECORD_FINISHED_ROUND,
 };
 
-static void mmap_read(struct perf_mmap *m __used, void *buf, unsigned long size)
+static void mmap_read(struct perf_mmap *m, void *buf, unsigned long size)
 {
-	int fd = perf_session__fd(session);
+	int fd = perf_data__fd_file(m->file);
 	write_output(fd, buf, size);
 }
 
-static int mmap_read_all(void)
+static int mmap_read_all(struct perf_data *data)
 {
 	int i, ret = 0;
 
-	for (i = 0; i < evsel_list->nr_mmaps; i++) {
-		struct perf_mmap *m = &evsel_list->mmap[i];
+	for (i = 0; i < data->nr_mmaps; i++) {
+		struct perf_mmap *m = &data->mmaps[i];
 		ret += perf_mmap__process(m, mmap_read);
 	}
 
@@ -540,6 +541,13 @@ static int __cmd_record(int argc, const char **argv)
 
 	open_counters(evsel_list);
 
+	if (perf_data__mmap(perf_session__data(session),
+			    evsel_list, mmap_pages, false) < 0) {
+		pr_err("Failed to mmap with %d (%s)\n",
+		       errno, strerror(errno));
+		goto out_delete_session;
+	}
+
 	/*
 	 * perf_session__delete(session) will be called at atexit_header()
 	 */
@@ -642,10 +650,13 @@ static int __cmd_record(int argc, const char **argv)
 		close(go_pipe[1]);
 
 	for (;;) {
-		if (!mmap_read_all()) {
+		struct perf_data *data = perf_session__data(session);
+
+		if (!mmap_read_all(data)) {
+
 			if (done)
 				break;
-			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
+			err = poll(data->fds, data->nr_fds, -1);
 			waking++;
 		}
 
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index feb3218..d9b2cf3 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -478,6 +478,9 @@ static int test__basic_mmap(void)
 	struct perf_evsel *evsels[nsyscalls], *evsel;
 	int sample_size = __perf_evsel__sample_size(attr.sample_type);
 	struct perf_mmap *md;
+	struct perf_data data;
+
+	PERF_DATA__NONE(data);
 
 	for (i = 0; i < nsyscalls; ++i) {
 		char name[64];
@@ -541,7 +544,11 @@ static int test__basic_mmap(void)
 		}
 	}
 
-	if (perf_evlist__mmap(evlist, 128, true) < 0) {
+	err = perf_evlist__init_ids(evlist);
+	if (err)
+		goto out_close_fd;
+
+	if (perf_data__mmap(&data, evlist, 128, true)) {
 		pr_debug("failed to mmap events: %d (%s)\n", errno,
 			 strerror(errno));
 		goto out_close_fd;
@@ -553,7 +560,7 @@ static int test__basic_mmap(void)
 			++foo;
 		}
 
-	md = &evlist->mmap[0];
+	md = &data.mmaps[0];
 
 	while ((event = perf_mmap__read(md)) != NULL) {
 		struct perf_sample sample;
@@ -591,7 +598,7 @@ static int test__basic_mmap(void)
 
 	err = 0;
 out_munmap:
-	perf_evlist__munmap(evlist);
+	perf_data__close(&data);
 out_close_fd:
 	for (i = 0; i < nsyscalls; ++i)
 		perf_evsel__close_fd(evsels[i], 1, threads->nr);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e86d728..fcb1762 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -836,15 +836,16 @@ static void session_mmap_read(struct perf_session *self,
 
 static void perf_session__mmap_read(struct perf_session *self)
 {
+	struct perf_data *data = perf_session__data(self);
 	int i;
 
-	for (i = 0; i < top.evlist->nr_mmaps; i++) {
-		struct perf_mmap *md = &top.evlist->mmap[i];
+	for (i = 0; i < data->nr_mmaps; i++) {
+		struct perf_mmap *md = &data->mmaps[i];
 		session_mmap_read(self, md);
 	}
 }
 
-static void start_counters(struct perf_evlist *evlist)
+static void start_counters(struct perf_data *data, struct perf_evlist *evlist)
 {
 	struct perf_evsel *counter, *first;
 
@@ -925,7 +926,10 @@ try_again:
 		}
 	}
 
-	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
+	if (perf_evlist__init_ids(evlist))
+		goto out_err;
+
+	if (perf_data__mmap(data, evlist, mmap_pages, false) < 0) {
 		ui__warning("Failed to mmap with %d (%s)\n",
 			    errno, strerror(errno));
 		goto out_err;
@@ -957,6 +961,7 @@ static int setup_sample_type(void)
 
 static int __cmd_top(void)
 {
+	struct perf_data *data;
 	pthread_t thread;
 	int ret;
 
@@ -975,12 +980,14 @@ static int __cmd_top(void)
 	else
 		perf_event__synthesize_threads(perf_event__process, top.session);
 
-	start_counters(top.evlist);
+	data = perf_session__data(top.session);
+
+	start_counters(data, top.evlist);
 	top.session->evlist = top.evlist;
 	perf_session__update_sample_type(top.session);
 
 	/* Wait for a minimal set of events before starting the snapshot */
-	poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
+	poll(data->fds, data->nr_fds, 100);
 
 	perf_session__mmap_read(top.session);
 
@@ -1006,7 +1013,7 @@ static int __cmd_top(void)
 		perf_session__mmap_read(top.session);
 
 		if (hits == top.samples)
-			ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
+			ret = poll(data->fds, data->nr_fds, 100);
 	}
 
 out_delete:
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index c025d0f..86ce18dd 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -201,3 +201,103 @@ void perf_data__close(struct perf_data *data)
 	list_for_each_entry(file, &data->files, list)
 		data_file__close(data, file);
 }
+
+static int data_file__ass_mmap(struct perf_data *data, struct perf_mmap *m)
+{
+	/*
+	 * Currently we have only one file to store data to.
+	 * In future we might open a file here and redirected perf_mmap
+	 * data into it.
+	 */
+	m->file = &data->header;
+	return 0;
+}
+
+static struct perf_mmap *data_mmap__new(struct perf_data *data)
+{
+	struct perf_mmap *m, *mmaps;
+	int nr = data->nr_mmaps;
+
+	mmaps = realloc(data->mmaps, (nr + 1) * sizeof(struct perf_mmap));
+	if (!mmaps)
+		return NULL;
+
+	data->nr_mmaps++;
+	data->mmaps = mmaps;
+
+	m = &data->mmaps[nr];
+	memset(m, 0, sizeof(*m));
+	return m;
+}
+
+static int data_fd__new(struct perf_data *data, int fd)
+{
+	struct pollfd *p, *fds;
+	int nr = data->nr_fds;
+
+	fds = realloc(data->fds, (nr + 1) * sizeof(struct perf_mmap));
+	if (!fds)
+		return -ENOMEM;
+
+	fcntl(fd, F_SETFL, O_NONBLOCK);
+
+	data->nr_fds++;
+	data->fds = fds;
+
+	p = &data->fds[nr];
+	p->fd = fd;
+	p->events = POLLIN;
+	return 0;
+}
+
+int perf_data__mmap(struct perf_data *data,
+		    struct perf_evlist *evlist,
+		    int pages, bool overwrite)
+{
+	bool cpu_bond = evlist->cpus->map[0] != -1;
+	struct perf_evsel *evsel;
+	int cpu, thread, ret, i;
+
+	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+		struct perf_mmap *m = NULL;
+
+		for (thread = 0; thread < evlist->threads->nr; thread++) {
+			list_for_each_entry(evsel, &evlist->entries, node) {
+				int fd = PERF_EVSEL_FD(evsel, cpu, thread);
+
+				if (!m || !(cpu_bond && thread)) {
+					m = data_mmap__new(data);
+					if (!m) {
+						ret = -ENOMEM;
+						goto cleanup;
+					}
+
+					ret = -EINVAL;
+					if (perf_mmap__open(m, fd, overwrite,
+							    pages))
+						goto cleanup;
+
+					if (data_file__ass_mmap(data, m))
+						goto cleanup;
+
+				} else {
+					ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
+					      m->fd);
+				}
+
+				if (data_fd__new(data, fd))
+					return -ENOMEM;
+			}
+		}
+	}
+
+	return 0;
+
+ cleanup:
+	for (i = 0; i < data->nr_mmaps; i++) {
+		struct perf_mmap *m = &data->mmaps[i];
+		perf_mmap__close(m);
+	}
+
+	return ret;
+}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 3103f7a..148e175 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -28,12 +28,20 @@ struct perf_data {
 	int  mode;
 	bool force;
 
+	struct perf_mmap *mmaps;
+	struct pollfd *fds;
+	int nr_mmaps;
+	int nr_fds;
+
 	struct list_head files;
 };
 
 int perf_data__open(struct perf_data *data, const char *name,
 		    int mode, bool force);
 void perf_data__close(struct perf_data *data);
+int perf_data__mmap(struct perf_data *data,
+		    struct perf_evlist *evlist,
+		    int pages, bool overwrite);
 
 #define PERF_DATA__NONE(__data) \
 	perf_data__open(&__data, NULL, PERF_DATA_NONE, false);
@@ -62,4 +70,9 @@ static inline int perf_data__fd(struct perf_data *data)
 {
 	return data->header.fd;
 }
+
+static inline int perf_data__fd_file(struct perf_data_file *file)
+{
+	return file->fd;
+}
 #endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 2237833..21e3e0f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,7 +19,6 @@
 #include <linux/bitops.h>
 #include <linux/hash.h>
 
-#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
 
 void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
@@ -56,18 +55,9 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
 	evlist->nr_entries = 0;
 }
 
-void perf_evlist__exit(struct perf_evlist *evlist)
-{
-	free(evlist->mmap);
-	free(evlist->pollfd);
-	evlist->mmap = NULL;
-	evlist->pollfd = NULL;
-}
-
 void perf_evlist__delete(struct perf_evlist *evlist)
 {
 	perf_evlist__purge(evlist);
-	perf_evlist__exit(evlist);
 	free(evlist);
 }
 
@@ -109,7 +99,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)
 	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
 		list_for_each_entry(pos, &evlist->entries, node) {
 			for (thread = 0; thread < evlist->threads->nr; thread++)
-				ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
+				ioctl(PERF_EVSEL_FD(pos, cpu, thread),
+				      PERF_EVENT_IOC_DISABLE);
 		}
 	}
 }
@@ -122,26 +113,12 @@ void perf_evlist__enable(struct perf_evlist *evlist)
 	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
 		list_for_each_entry(pos, &evlist->entries, node) {
 			for (thread = 0; thread < evlist->threads->nr; thread++)
-				ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
+				ioctl(PERF_EVSEL_FD(pos, cpu, thread),
+				      PERF_EVENT_IOC_ENABLE);
 		}
 	}
 }
 
-int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
-{
-	int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
-	evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
-	return evlist->pollfd != NULL ? 0 : -ENOMEM;
-}
-
-void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
-{
-	fcntl(fd, F_SETFL, O_NONBLOCK);
-	evlist->pollfd[evlist->nr_fds].fd = fd;
-	evlist->pollfd[evlist->nr_fds].events = POLLIN;
-	evlist->nr_fds++;
-}
-
 static void perf_evlist__id_hash(struct perf_evlist *evlist,
 				 struct perf_evsel *evsel,
 				 int cpu, int thread, u64 id)
@@ -201,112 +178,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
 	return NULL;
 }
 
-void perf_evlist__munmap(struct perf_evlist *evlist)
-{
-	int i;
-
-	for (i = 0; i < evlist->nr_mmaps; i++) {
-		struct perf_mmap *m = &evlist->mmap[i];
-		if (m->base != NULL)
-			perf_mmap__close(m);
-	}
-
-	free(evlist->mmap);
-	evlist->mmap = NULL;
-}
-
-int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
-{
-	evlist->nr_mmaps = evlist->cpus->nr;
-	if (evlist->cpus->map[0] == -1)
-		evlist->nr_mmaps = evlist->threads->nr;
-	evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
-	return evlist->mmap != NULL ? 0 : -ENOMEM;
-}
-
-static int __perf_evlist__mmap(struct perf_evlist *evlist,
-			       int idx, int fd)
-{
-	struct perf_mmap *m = &evlist->mmap[idx];
-
-	if (perf_mmap__open(m, fd, evlist->overwrite, evlist->pages))
-		return -1;
-
-	perf_evlist__add_pollfd(evlist, fd);
-	return 0;
-}
-
-static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-	int cpu, thread;
-
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		int output = -1;
-
-		for (thread = 0; thread < evlist->threads->nr; thread++) {
-			list_for_each_entry(evsel, &evlist->entries, node) {
-				int fd = FD(evsel, cpu, thread);
-
-				if (output == -1) {
-					output = fd;
-					if (__perf_evlist__mmap(evlist, cpu,
-								output) < 0)
-						goto out_unmap;
-				} else {
-					if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
-						goto out_unmap;
-				}
-			}
-		}
-	}
-
-	return 0;
-
-out_unmap:
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		struct perf_mmap *m = &evlist->mmap[cpu];
-		if (m->base != NULL)
-			perf_mmap__close(m);
-	}
-	return -1;
-}
-
-static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-	int thread;
-
-	for (thread = 0; thread < evlist->threads->nr; thread++) {
-		int output = -1;
-
-		list_for_each_entry(evsel, &evlist->entries, node) {
-			int fd = FD(evsel, 0, thread);
-
-			if (output == -1) {
-				output = fd;
-				if (__perf_evlist__mmap(evlist, thread,
-							output) < 0)
-					goto out_unmap;
-			} else {
-				if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
-					goto out_unmap;
-			}
-		}
-	}
-
-	return 0;
-
-out_unmap:
-	for (thread = 0; thread < evlist->threads->nr; thread++) {
-		struct perf_mmap *m = &evlist->mmap[thread];
-		if (m->base != NULL)
-			perf_mmap__close(m);
-	}
-	return -1;
-}
-
-static int perf_evlist__init_ids(struct perf_evlist *evlist)
+int perf_evlist__init_ids(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel;
 	struct thread_map *threads = evlist->threads;
@@ -323,7 +195,7 @@ static int perf_evlist__init_ids(struct perf_evlist *evlist)
 
 		for (cpu = 0; cpu < cpus->nr; cpu++)
 			for (thread = 0; thread < threads->nr; thread++) {
-				int fd = FD(evsel, cpu, thread);
+				int fd = PERF_EVSEL_FD(evsel, cpu, thread);
 				if (perf_evlist__id_add_fd(evlist, evsel,
 							   cpu, thread, fd))
 					return -EINVAL;
@@ -333,45 +205,6 @@ static int perf_evlist__init_ids(struct perf_evlist *evlist)
 	return 0;
 }
 
-/** perf_evlist__mmap - Create per cpu maps to receive events
- *
- * @evlist - list of events
- * @pages - map length in pages
- * @overwrite - overwrite older events?
- *
- * If overwrite is false the user needs to signal event consuption using:
- *
- *	struct perf_mmap *m = &evlist->mmap[cpu];
- *	unsigned int head = perf_mmap__read_head(m);
- *
- *	perf_mmap__write_tail(m, head)
- *
- * Using perf_evlist__read_on_cpu does this automatically.
- */
-int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
-{
-	const struct cpu_map *cpus = evlist->cpus;
-	int ret;
-
-	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
-		return -ENOMEM;
-
-	if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
-		return -ENOMEM;
-
-	evlist->overwrite = overwrite;
-	evlist->pages = pages;
-
-	ret = perf_evlist__init_ids(evlist);
-	if (ret)
-		return ret;
-
-	if (cpus->map[0] == -1)
-		return perf_evlist__mmap_per_thread(evlist);
-
-	return perf_evlist__mmap_per_cpu(evlist);
-}
-
 int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
 			     pid_t target_tid, const char *cpu_list)
 {
@@ -420,7 +253,7 @@ int perf_evlist__set_filters(struct perf_evlist *evlist)
 			continue;
 		for (cpu = 0; cpu < cpus->nr; cpu++) {
 			for (thread = 0; thread < threads->nr; thread++) {
-				fd = FD(evsel, cpu, thread);
+				fd = PERF_EVSEL_FD(evsel, cpu, thread);
 				err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
 				if (err)
 					return err;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 3784273..b187efb 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -16,13 +16,6 @@ struct perf_evlist {
 	struct list_head entries;
 	struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
 	int		 nr_entries;
-	int		 nr_fds;
-	int		 nr_mmaps;
-	int		 pages;
-	bool		 overwrite;
-	union perf_event event_copy;
-	struct perf_mmap *mmap;
-	struct pollfd	 *pollfd;
 	struct thread_map *threads;
 	struct cpu_map	  *cpus;
 	struct perf_evsel *selected;
@@ -74,6 +67,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
 			     pid_t target_tid, const char *cpu_list);
 void perf_evlist__delete_maps(struct perf_evlist *evlist);
 int perf_evlist__set_filters(struct perf_evlist *evlist);
+int perf_evlist__init_ids(struct perf_evlist *evlist);
 
 u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b1d15e6..14e1864 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -8,7 +8,9 @@
 #include "xyarray.h"
 #include "cgroup.h"
 #include "hist.h"
- 
+
+#define PERF_EVSEL_FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
+
 struct perf_counts_values {
 	union {
 		struct {
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
index 24cf88f..1152135 100644
--- a/tools/perf/util/mmap.h
+++ b/tools/perf/util/mmap.h
@@ -4,6 +4,7 @@
 #include <sys/mman.h>
 #include "event.h"
 #include "../perf.h"
+#include "data.h"
 
 struct perf_mmap {
 	void  *base;
@@ -12,6 +13,8 @@ struct perf_mmap {
 	int   len;
 	int   fd;
 	bool  owrt;
+
+	struct perf_data_file *file;
 };
 
 typedef void (*perf_mmap_process_t)(struct perf_mmap *m,
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9dd47a4..263a7b5 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -7,6 +7,7 @@
 #include "event.h"
 #include "cpumap.h"
 #include "thread_map.h"
+#include "data.h"
 
 /* Define PyVarObject_HEAD_INIT for python 2.5 */
 #ifndef PyVarObject_HEAD_INIT
@@ -598,7 +599,6 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
 
 static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
 {
-	perf_evsel__exit(&pevsel->evsel);
 	pevsel->ob_type->tp_free((PyObject*)pevsel);
 }
 
@@ -668,6 +668,7 @@ static int pyrf_evsel__setup_types(void)
 struct pyrf_evlist {
 	PyObject_HEAD
 
+	struct perf_data data;
 	struct perf_evlist evlist;
 };
 
@@ -684,12 +685,12 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
 	threads = ((struct pyrf_thread_map *)pthreads)->threads;
 	cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
 	perf_evlist__init(&pevlist->evlist, cpus, threads);
+	PERF_DATA__NONE(pevlist->data);
 	return 0;
 }
 
 static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
 {
-	perf_evlist__exit(&pevlist->evlist);
 	pevlist->ob_type->tp_free((PyObject*)pevlist);
 }
 
@@ -697,6 +698,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 				   PyObject *args, PyObject *kwargs)
 {
 	struct perf_evlist *evlist = &pevlist->evlist;
+	struct perf_data *data = &pevlist->data;
 	static char *kwlist[] = { "pages", "overwrite", NULL };
 	int pages = 128, overwrite = false;
 
@@ -704,7 +706,12 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 					 &pages, &overwrite))
 		return NULL;
 
-	if (perf_evlist__mmap(evlist, pages, overwrite) < 0) {
+	if (perf_evlist__init_ids(evlist)) {
+		PyErr_SetFromErrno(PyExc_OSError);
+		return NULL;
+	}
+
+	if (perf_data__mmap(data, evlist, pages, overwrite) < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
 	}
@@ -716,14 +723,14 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
 				   PyObject *args, PyObject *kwargs)
 {
-	struct perf_evlist *evlist = &pevlist->evlist;
+	struct perf_data *data = &pevlist->data;
 	static char *kwlist[] = { "timeout", NULL };
 	int timeout = -1, n;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
 		return NULL;
 
-	n = poll(evlist->pollfd, evlist->nr_fds, timeout);
+	n = poll(data->fds, data->nr_fds, timeout);
 	if (n < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
@@ -735,13 +742,13 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
 static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
 					 PyObject *args __used, PyObject *kwargs __used)
 {
-	struct perf_evlist *evlist = &pevlist->evlist;
+	struct perf_data *data = &pevlist->data;
         PyObject *list = PyList_New(0);
 	int i;
 
-	for (i = 0; i < evlist->nr_fds; ++i) {
+	for (i = 0; i < data->nr_fds; ++i) {
 		PyObject *file;
-		FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
+		FILE *fp = fdopen(data->fds[i].fd, "r");
 
 		if (fp == NULL)
 			goto free_list;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index cbc37f3..1c5e0e8 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -191,4 +191,10 @@ static inline int perf_session__is_pipe(struct perf_session *self)
 {
 	return perf_data__is_pipe(&self->data);
 }
+
+static inline struct perf_data *perf_session__data(struct perf_session *self)
+{
+	return &self->data;
+}
+
 #endif /* __PERF_SESSION_H */
-- 
1.7.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [RFC,PATCH] perf tool: Refactoring IO data files code
  2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
                   ` (4 preceding siblings ...)
  2011-11-18 13:46 ` [PATCH 5/5] perf tool: Putting mmap support to " Jiri Olsa
@ 2011-11-18 14:14 ` Arnaldo Carvalho de Melo
  2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
  6 siblings, 0 replies; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-11-18 14:14 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, linux-kernel

Em Fri, Nov 18, 2011 at 02:46:40PM +0100, Jiri Olsa escreveu:
> Hi,
> 
> based on following discussion:
> http://marc.info/?l=linux-kernel&m=131731212425421&w=2
> http://marc.info/?l=linux-kernel&m=131736842010972&w=2
> 
> I made some changes to have event memory mapping and input/output
> data code in one place. The reason was to make the change for
> multiple event data files at least possible ;)
> 
> This patchset is marked as RFC since it's quite big change
> and I expect some better design might come up.
> 
> However, patches 1 and 2 are not big deal, since they are
> just small (not so related) changes.
> 
> Patches 3-4 are the main change of the patchset.
> 
> 1/5 perf tool: Fix session host_nachine retrieval
> 2/5 perf tool: Initialize events IDs in a single function
> 3/5 perf tool: Introducing perf_mmap object
> 4/5 perf tool: Introducing perf_data object
> 5/5 perf tool: Putting mmap support to perf_data object

Reading those patches now.
 
> I did some overall testing of all the changed command,
> and so far so good. Just hit issue with 'diff' command,
> but this one seems not to work even without my changes.

Yeah, it needs more work to properly suport multi-event perf.data files.
 
> Also the current perf python binsing code is broken
> wit missing dependencies so I could not test my
> changes there.

Which ones? I fixed some and posted to my perf/urgent branch, waiting
for Ingo to merge.

- Arnaldo

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/5] perf tool: Initialize events IDs in a single function
  2011-11-18 13:46 ` [PATCH 2/5] perf tool: Initialize events IDs in a single function Jiri Olsa
@ 2011-11-18 14:22   ` Arnaldo Carvalho de Melo
  2011-11-20  1:36     ` Jiri Olsa
  0 siblings, 1 reply; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-11-18 14:22 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, linux-kernel

Em Fri, Nov 18, 2011 at 02:46:42PM +0100, Jiri Olsa escreveu:
> Currently events' IDs initialization is scattered among the
> code. Adding function 'perf_evlist__init_ids' to allocate
> and retrive events' IDs in one place.

I'm ok with this one, will merge it in my perf/core branch together with
a fix for a bug I noticed in the original code and that remains with
your changes: consider what happens if we do a second perf_evlist__mmap,
we will call perf_evlist__id_add_fd again and thus bump evsel->ids++
over nr_threads * nr_cpus, overflowing it.

- Arnaldo

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] perf tool: Fix session host_nachine retrieval
  2011-11-18 13:46 ` [PATCH 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
@ 2011-11-18 14:24   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-11-18 14:24 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, linux-kernel

Em Fri, Nov 18, 2011 at 02:46:41PM +0100, Jiri Olsa escreveu:
> The host_machine is statically included inside perf_session struct
> so it is always present.
> 
> Changing function:
> 'perf_session__find_host_machine' to 'perf_session__host_machine'
> 
> Removing NULL checking code after this function, since it is not needed.

I'm working on finding the machine in perf_session__process_events and
then passing it to the perf_event_ops methods, will fold this in there.
 
> Signed-off-by: Jiri Olsa <jolsa@redhat.com>
> ---
>  tools/perf/builtin-inject.c |    6 +-----
>  tools/perf/builtin-kmem.c   |   12 +++++-------
>  tools/perf/builtin-record.c |    6 +-----
>  tools/perf/builtin-top.c    |    4 ++--
>  tools/perf/util/event.c     |   14 +++++---------
>  tools/perf/util/session.h   |    6 +++---
>  6 files changed, 17 insertions(+), 31 deletions(-)
> 
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index 8dfc12b..3c5eb3a 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -111,11 +111,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
>  		return -1;
>  	}
>  
> -	machine = perf_session__find_host_machine(session);
> -	if (machine == NULL) {
> -		pr_err("Can't find machine for session\n");
> -		return -1;
> -	}
> +	machine = perf_session__host_machine(session);
>  
>  	if (self->kernel)
>  		misc = PERF_RECORD_MISC_KERNEL;
> diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
> index 225e963..2ca8206 100644
> --- a/tools/perf/builtin-kmem.c
> +++ b/tools/perf/builtin-kmem.c
> @@ -342,7 +342,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
>  			   int n_lines, int is_caller)
>  {
>  	struct rb_node *next;
> -	struct machine *machine;
>  
>  	printf("%.102s\n", graph_dotted_line);
>  	printf(" %-34s |",  is_caller ? "Callsite": "Alloc Ptr");
> @@ -351,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
>  
>  	next = rb_first(root);
>  
> -	machine = perf_session__find_host_machine(session);
> -	if (!machine) {
> -		pr_err("__print_result: couldn't find kernel information\n");
> -		return;
> -	}
>  	while (next && n_lines--) {
>  		struct alloc_stat *data = rb_entry(next, struct alloc_stat,
>  						   node);
> @@ -366,8 +360,12 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
>  
>  		if (is_caller) {
>  			addr = data->call_site;
> -			if (!raw_ip)
> +			if (!raw_ip) {
> +				struct machine *machine;
> +
> +				machine = perf_session__host_machine(session);
>  				sym = machine__find_kernel_function(machine, addr, &map, NULL);
> +			}
>  		} else
>  			addr = data->ptr;
>  
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 6ab58cc..1132e70 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -662,11 +662,7 @@ static int __cmd_record(int argc, const char **argv)
>  		}
>  	}
>  
> -	machine = perf_session__find_host_machine(session);
> -	if (!machine) {
> -		pr_err("Couldn't find native kernel information.\n");
> -		return -1;
> -	}
> +	machine = perf_session__host_machine(session);
>  
>  	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
>  						 session, machine, "_text");
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index c9cdedb..8e02027 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -692,13 +692,13 @@ static void perf_event__process_sample(const union perf_event *event,
>  		++top.us_samples;
>  		if (top.hide_user_symbols)
>  			return;
> -		machine = perf_session__find_host_machine(session);
> +		machine = perf_session__host_machine(session);
>  		break;
>  	case PERF_RECORD_MISC_KERNEL:
>  		++top.kernel_samples;
>  		if (top.hide_kernel_symbols)
>  			return;
> -		machine = perf_session__find_host_machine(session);
> +		machine = perf_session__host_machine(session);
>  		break;
>  	case PERF_RECORD_MISC_GUEST_KERNEL:
>  		++top.guest_kernel_samples;
> diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
> index 437f8ca..35817fa 100644
> --- a/tools/perf/util/event.c
> +++ b/tools/perf/util/event.c
> @@ -589,12 +589,12 @@ int perf_event__process_mmap(union perf_event *event,
>  		return 0;
>  	}
>  
> -	machine = perf_session__find_host_machine(session);
> -	if (machine == NULL)
> -		goto out_problem;
>  	thread = perf_session__findnew(session, event->mmap.pid);
>  	if (thread == NULL)
>  		goto out_problem;
> +
> +	machine = perf_session__host_machine(session);
> +
>  	map = map__new(&machine->user_dsos, event->mmap.start,
>  			event->mmap.len, event->mmap.pgoff,
>  			event->mmap.pid, event->mmap.filename,
> @@ -672,15 +672,11 @@ void thread__find_addr_map(struct thread *self,
>  
>  	if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
>  		al->level = 'k';
> -		machine = perf_session__find_host_machine(session);
> -		if (machine == NULL) {
> -			al->map = NULL;
> -			return;
> -		}
> +		machine = perf_session__host_machine(session);
>  		mg = &machine->kmaps;
>  	} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
>  		al->level = '.';
> -		machine = perf_session__find_host_machine(session);
> +		machine = perf_session__host_machine(session);
>  	} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
>  		al->level = 'g';
>  		machine = perf_session__find_machine(session, pid);
> diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
> index 6e393c9..a81d666 100644
> --- a/tools/perf/util/session.h
> +++ b/tools/perf/util/session.h
> @@ -121,7 +121,7 @@ void perf_session__update_sample_type(struct perf_session *self);
>  void perf_session__remove_thread(struct perf_session *self, struct thread *th);
>  
>  static inline
> -struct machine *perf_session__find_host_machine(struct perf_session *self)
> +struct machine *perf_session__host_machine(struct perf_session *self)
>  {
>  	return &self->host_machine;
>  }
> @@ -130,7 +130,7 @@ static inline
>  struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
>  {
>  	if (pid == HOST_KERNEL_ID)
> -		return &self->host_machine;
> +		return perf_session__host_machine(self);
>  	return machines__find(&self->machines, pid);
>  }
>  
> @@ -138,7 +138,7 @@ static inline
>  struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
>  {
>  	if (pid == HOST_KERNEL_ID)
> -		return &self->host_machine;
> +		return perf_session__host_machine(self);
>  	return machines__findnew(&self->machines, pid);
>  }
>  
> -- 
> 1.7.4

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/5] perf tool: Introducing perf_mmap object
  2011-11-18 13:46 ` [PATCH 3/5] perf tool: Introducing perf_mmap object Jiri Olsa
@ 2011-11-18 14:37   ` Arnaldo Carvalho de Melo
  2011-11-20  1:39     ` Jiri Olsa
  0 siblings, 1 reply; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-11-18 14:37 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, linux-kernel

Em Fri, Nov 18, 2011 at 02:46:43PM +0100, Jiri Olsa escreveu:
> +++ b/tools/perf/builtin-test.c
> @@ -476,6 +477,7 @@ static int test__basic_mmap(void)
>  		     expected_nr_events[nsyscalls], i, j;
>  	struct perf_evsel *evsels[nsyscalls], *evsel;
>  	int sample_size = __perf_evsel__sample_size(attr.sample_type);
> +	struct perf_mmap *md;
>  
>  	for (i = 0; i < nsyscalls; ++i) {
>  		char name[64];
> @@ -551,7 +553,9 @@ static int test__basic_mmap(void)
>  			++foo;
>  		}
>  
> -	while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
> +	md = &evlist->mmap[0];
> +
> +	while ((event = perf_mmap__read(md)) != NULL) {
>  		struct perf_sample sample;
>  
>  		if (event->header.type != PERF_RECORD_SAMPLE) {

Please keep perf_evlist__mmap_read() as just a wrapper for the above
operation, that way you reduce the patch size by not touching the
functions that use perf_evlist__mmap_read().

Later, if we think this is the right thing to do, i.e. to open code it
like you're doing above, we can elliminate it, but I think its better to
keep it as perf_evlist__mmap_read(evlist, 0) as it uses just one line
instead of the 4 above :-)

> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index 8e02027..032f70d 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -38,6 +38,7 @@
>  #include "util/cpumap.h"
>  #include "util/xyarray.h"
>  #include "util/sort.h"
> +#include "util/mmap.h"
>  
>  #include "util/debug.h"
>  
> @@ -804,14 +805,16 @@ static void perf_event__process_sample(const union perf_event *event,
>  	return;
>  }
>  
> -static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
> +static void session_mmap_read(struct perf_session *self,
> +			      struct perf_mmap *md)
>  {
> -	struct perf_sample sample;
> -	struct perf_evsel *evsel;
>  	union perf_event *event;
> -	int ret;
>  
> -	while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
> +	while ((event = perf_mmap__read(md)) != NULL) {
> +		struct perf_sample sample;
> +		struct perf_evsel *evsel;
> +		int ret;
> +

Ditto, all the above is not needed, just keep perf_evlist__mmap_read()

>  		ret = perf_session__parse_sample(self, event, &sample);
>  		if (ret) {
>  			pr_err("Can't parse sample, err = %d\n", ret);
> @@ -835,8 +838,10 @@ static void perf_session__mmap_read(struct perf_session *self)
>  {
>  	int i;
>  
> -	for (i = 0; i < top.evlist->nr_mmaps; i++)
> -		perf_session__mmap_read_idx(self, i);
> +	for (i = 0; i < top.evlist->nr_mmaps; i++) {
> +		struct perf_mmap *md = &top.evlist->mmap[i];
> +		session_mmap_read(self, md);
> +	}

ditto

>  }
>  
>  static void start_counters(struct perf_evlist *evlist)
> diff --git a/tools/perf/perf.h b/tools/perf/perf.h
> index 914c895..d79efbb 100644
> --- a/tools/perf/perf.h
> +++ b/tools/perf/perf.h
> @@ -104,32 +104,6 @@ void get_term_dimensions(struct winsize *ws);
>  #include "util/types.h"
>  #include <stdbool.h>
>  
> -struct perf_mmap {
> -	void			*base;
> -	int			mask;
> -	unsigned int		prev;
> -};
> -
> -static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
> -{
> -	struct perf_event_mmap_page *pc = mm->base;
> -	int head = pc->data_head;
> -	rmb();
> -	return head;
> -}
> -
> -static inline void perf_mmap__write_tail(struct perf_mmap *md,
> -					 unsigned long tail)
> -{
> -	struct perf_event_mmap_page *pc = md->base;
> -
> -	/*
> -	 * ensure all reads are done before we write the tail out.
> -	 */
> -	/* mb(); */
> -	pc->data_tail = tail;
> -}
> -

Ok, the above just moved to tools/perf/util/mmap.c, I guess, reading
on...

>  /*
>   * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
>   * counters in the current task.
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 0f715d0..2237833 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -12,6 +12,7 @@
>  #include "evlist.h"
>  #include "evsel.h"
>  #include "util.h"
> +#include "mmap.h"
>  
>  #include <sys/mman.h>
>  
> @@ -200,82 +201,14 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
>  	return NULL;
>  }
>  
> -union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
> -{
> -	/* XXX Move this to perf.c, making it generally available */
> -	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
> -	struct perf_mmap *md = &evlist->mmap[idx];
> -	unsigned int head = perf_mmap__read_head(md);
> -	unsigned int old = md->prev;
> -	unsigned char *data = md->base + page_size;
> -	union perf_event *event = NULL;

Just keep this as a simple wrapper to the functions moved to the
perf_mmap__ class

> -
> -	if (evlist->overwrite) {
> -		/*
> -		 * If we're further behind than half the buffer, there's a chance
> -		 * the writer will bite our tail and mess up the samples under us.
> -		 *
> -		 * If we somehow ended up ahead of the head, we got messed up.
> -		 *
> -		 * In either case, truncate and restart at head.
> -		 */
> -		int diff = head - old;
> -		if (diff > md->mask / 2 || diff < 0) {
> -			fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
> -
> -			/*
> -			 * head points to a known good entry, start there.
> -			 */
> -			old = head;
> -		}
> -	}
> -
> -	if (old != head) {
> -		size_t size;
> -
> -		event = (union perf_event *)&data[old & md->mask];
> -		size = event->header.size;
> -
> -		/*
> -		 * Event straddles the mmap boundary -- header should always
> -		 * be inside due to u64 alignment of output.
> -		 */
> -		if ((old & md->mask) + size != ((old + size) & md->mask)) {
> -			unsigned int offset = old;
> -			unsigned int len = min(sizeof(*event), size), cpy;
> -			void *dst = &evlist->event_copy;
> -
> -			do {
> -				cpy = min(md->mask + 1 - (offset & md->mask), len);
> -				memcpy(dst, &data[offset & md->mask], cpy);
> -				offset += cpy;
> -				dst += cpy;
> -				len -= cpy;
> -			} while (len);
> -
> -			event = &evlist->event_copy;
> -		}
> -
> -		old += size;
> -	}
> -
> -	md->prev = old;
> -
> -	if (!evlist->overwrite)
> -		perf_mmap__write_tail(md, old);
> -
> -	return event;
> -}
> -
>  void perf_evlist__munmap(struct perf_evlist *evlist)
>  {
>  	int i;
>  
>  	for (i = 0; i < evlist->nr_mmaps; i++) {
> -		if (evlist->mmap[i].base != NULL) {
> -			munmap(evlist->mmap[i].base, evlist->mmap_len);
> -			evlist->mmap[i].base = NULL;
> -		}
> +		struct perf_mmap *m = &evlist->mmap[i];
> +		if (m->base != NULL)
> +			perf_mmap__close(m);

Wouldn't it be perf_mmap__munmap() ? 

>  	}
>  
>  	free(evlist->mmap);
> @@ -292,20 +225,18 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
>  }
>  
>  static int __perf_evlist__mmap(struct perf_evlist *evlist,
> -			       int idx, int prot, int mask, int fd)
> +			       int idx, int fd)
>  {
> -	evlist->mmap[idx].prev = 0;
> -	evlist->mmap[idx].mask = mask;
> -	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
> -				      MAP_SHARED, fd, 0);
> -	if (evlist->mmap[idx].base == MAP_FAILED)
> +	struct perf_mmap *m = &evlist->mmap[idx];
> +
> +	if (perf_mmap__open(m, fd, evlist->overwrite, evlist->pages))

And here perf_mmap__mmap or at least perf_mmap__map and the other
perf_mmap__unmap?

>  		return -1;
>  
>  	perf_evlist__add_pollfd(evlist, fd);
>  	return 0;
>  }
>  
> -static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
> +static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist)
>  {
>  	struct perf_evsel *evsel;
>  	int cpu, thread;
> @@ -320,7 +251,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
>  				if (output == -1) {
>  					output = fd;
>  					if (__perf_evlist__mmap(evlist, cpu,
> -								prot, mask, output) < 0)
> +								output) < 0)
>  						goto out_unmap;
>  				} else {
>  					if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
> @@ -334,15 +265,14 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
>  
>  out_unmap:
>  	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
> -		if (evlist->mmap[cpu].base != NULL) {
> -			munmap(evlist->mmap[cpu].base, evlist->mmap_len);
> -			evlist->mmap[cpu].base = NULL;
> -		}
> +		struct perf_mmap *m = &evlist->mmap[cpu];
> +		if (m->base != NULL)
> +			perf_mmap__close(m);

ditto

>  	}
>  	return -1;
>  }
>  
> -static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
> +static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist)
>  {
>  	struct perf_evsel *evsel;
>  	int thread;
> @@ -356,7 +286,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
>  			if (output == -1) {
>  				output = fd;
>  				if (__perf_evlist__mmap(evlist, thread,
> -							prot, mask, output) < 0)
> +							output) < 0)
>  					goto out_unmap;
>  			} else {
>  				if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
> @@ -369,10 +299,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
>  
>  out_unmap:
>  	for (thread = 0; thread < evlist->threads->nr; thread++) {
> -		if (evlist->mmap[thread].base != NULL) {
> -			munmap(evlist->mmap[thread].base, evlist->mmap_len);
> -			evlist->mmap[thread].base = NULL;
> -		}
> +		struct perf_mmap *m = &evlist->mmap[thread];
> +		if (m->base != NULL)
> +			perf_mmap__close(m);
>  	}
>  	return -1;
>  }
> @@ -421,10 +350,8 @@ static int perf_evlist__init_ids(struct perf_evlist *evlist)
>   */
>  int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
>  {
> -	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
> -	int mask = pages * page_size - 1, ret;
>  	const struct cpu_map *cpus = evlist->cpus;
> -	int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
> +	int ret;
>  
>  	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
>  		return -ENOMEM;
> @@ -433,16 +360,16 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
>  		return -ENOMEM;
>  
>  	evlist->overwrite = overwrite;
> -	evlist->mmap_len = (pages + 1) * page_size;
> +	evlist->pages = pages;
>  
>  	ret = perf_evlist__init_ids(evlist);
>  	if (ret)
>  		return ret;
>  
>  	if (cpus->map[0] == -1)
> -		return perf_evlist__mmap_per_thread(evlist, prot, mask);
> +		return perf_evlist__mmap_per_thread(evlist);
>  
> -	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
> +	return perf_evlist__mmap_per_cpu(evlist);
>  }
>  
>  int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index 1779ffe..3784273 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -18,7 +18,7 @@ struct perf_evlist {
>  	int		 nr_entries;
>  	int		 nr_fds;
>  	int		 nr_mmaps;
> -	int		 mmap_len;
> +	int		 pages;
>  	bool		 overwrite;
>  	union perf_event event_copy;
>  	struct perf_mmap *mmap;
> diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
> new file mode 100644
> index 0000000..45e62a2
> --- /dev/null
> +++ b/tools/perf/util/mmap.c
> @@ -0,0 +1,138 @@
> +#include <string.h>
> +#include <stdio.h>
> +#include "mmap.h"
> +
> +int perf_mmap__open(struct perf_mmap *m, int fd, bool overwrite, int pages)
> +{
> +	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
> +	int mask, len, prot;
> +	void *base;
> +
> +	mask = pages * page_size - 1;
> +	len  = (pages + 1) * page_size;
> +	prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
> +
> +	base = mmap(NULL, len, prot, MAP_SHARED, fd, 0);
> +	if (base == MAP_FAILED)
> +		return -1;
> +
> +	memset(m, 0, sizeof(*m));
> +	m->mask = mask;
> +	m->len  = len;
> +	m->base = base;
> +	m->fd   = fd;
> +	m->owrt = overwrite;
> +	return 0;
> +}
> +
> +int perf_mmap__close(struct perf_mmap *m)
> +{
> +	int ret = munmap(m->base, m->len);
> +
> +	memset(m, 0x0, sizeof(*m));
> +	return ret;
> +}
> +
> +int perf_mmap__process(struct perf_mmap *md, perf_mmap_process_t process)
> +{
> +	unsigned int head, old, page_size = sysconf(_SC_PAGE_SIZE);
> +	unsigned char *data = md->base + page_size;
> +	unsigned long size;
> +	void *buf;
> +
> +	head = perf_mmap__read_head(md);
> +	old  = md->prev;
> +
> +	if (old == head)
> +		return 0;
> +
> +	size = head - old;
> +
> +	if ((old & md->mask) + size != (head & md->mask)) {
> +		buf = &data[old & md->mask];
> +		size = md->mask + 1 - (old & md->mask);
> +		old += size;
> +
> +		process(md, buf, size);
> +	}
> +
> +	buf = &data[old & md->mask];
> +	size = head - old;
> +	old += size;
> +
> +	process(md, buf, size);
> +
> +	md->prev = old;
> +	perf_mmap__write_tail(md, old);
> +	return 1;
> +}
> +
> +union perf_event *perf_mmap__read(struct perf_mmap *md)
> +{
> +	unsigned int head, old, page_size = sysconf(_SC_PAGE_SIZE);
> +	unsigned char *data = md->base + page_size;
> +	union perf_event *event = NULL;
> +
> +	head = perf_mmap__read_head(md);
> +	old = md->prev;
> +
> +	if (md->owrt) {
> +		/*
> +		 * If we're further behind than half the buffer, there's
> +		 * a chance the writer will bite our tail and mess up the
> +		 * samples under us.
> +		 *
> +		 * If we somehow ended up ahead of the head, we got messed up.
> +		 *
> +		 * In either case, truncate and restart at head.
> +		 */
> +		int diff = head - old;
> +		if (diff > md->mask / 2 || diff < 0) {
> +			fprintf(stderr, "WARNING: failed to keep up "
> +					"with mmap data.\n");
> +
> +			/*
> +			 * head points to a known good entry, start there.
> +			 */
> +			old = head;
> +		}
> +	}
> +
> +	if (old != head) {
> +		size_t size;
> +
> +		event = (union perf_event *)&data[old & md->mask];
> +		size = event->header.size;
> +
> +		/*
> +		 * Event straddles the mmap boundary -- header should always
> +		 * be inside due to u64 alignment of output.
> +		 */
> +		if ((old & md->mask) + size != ((old + size) & md->mask)) {
> +			unsigned int offset = old;
> +			unsigned int len = min(sizeof(*event), size), cpy;
> +			static union perf_event event_copy;
> +			void *dst = &event_copy;
> +
> +			do {
> +				cpy = min(md->mask + 1 - (offset & md->mask),
> +					  len);
> +				memcpy(dst, &data[offset & md->mask], cpy);
> +				offset += cpy;
> +				dst += cpy;
> +				len -= cpy;
> +			} while (len);
> +
> +			event = &event_copy;
> +		}
> +
> +		old += size;
> +	}
> +
> +	md->prev = old;
> +
> +	if (!md->owrt)
> +		perf_mmap__write_tail(md, old);
> +
> +	return event;
> +}
> diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
> new file mode 100644
> index 0000000..24cf88f
> --- /dev/null
> +++ b/tools/perf/util/mmap.h
> @@ -0,0 +1,45 @@
> +#ifndef __PERF_MMAP_H
> +#define __PERF_MMAP_H
> +
> +#include <sys/mman.h>
> +#include "event.h"
> +#include "../perf.h"
> +
> +struct perf_mmap {
> +	void  *base;
> +	int   mask;
> +	u_int prev;
> +	int   len;
> +	int   fd;
> +	bool  owrt;
> +};
> +
> +typedef void (*perf_mmap_process_t)(struct perf_mmap *m,
> +				    void *buf, unsigned long size);
> +
> +int perf_mmap__open(struct perf_mmap *m, int fd, bool overwrite, int pages);
> +int perf_mmap__close(struct perf_mmap *m);
> +int perf_mmap__process(struct perf_mmap *m, perf_mmap_process_t process);
> +union perf_event *perf_mmap__read(struct perf_mmap *md);
> +
> +static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
> +{
> +	struct perf_event_mmap_page *pc = mm->base;
> +	int head = pc->data_head;
> +	rmb();
> +	return head;
> +}
> +
> +static inline void perf_mmap__write_tail(struct perf_mmap *md,
> +					 unsigned long tail)
> +{
> +	struct perf_event_mmap_page *pc = md->base;
> +
> +	/*
> +	 * ensure all reads are done before we write the tail out.
> +	 */
> +	/* mb(); */
> +	pc->data_tail = tail;
> +}
> +
> +#endif /* __PERF_MMAP_H */
> -- 
> 1.7.4

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/5] perf tool: Initialize events IDs in a single function
  2011-11-20  1:36     ` Jiri Olsa
@ 2011-11-20  1:03       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2011-11-20  1:03 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: a.p.zijlstra, mingo, paulus, linux-kernel

Em Sat, Nov 19, 2011 at 08:36:21PM -0500, Jiri Olsa escreveu:
> On Fri, Nov 18, 2011 at 12:22:55PM -0200, Arnaldo Carvalho de Melo wrote:
> > Em Fri, Nov 18, 2011 at 02:46:42PM +0100, Jiri Olsa escreveu:
> > > Currently events' IDs initialization is scattered among the
> > > code. Adding function 'perf_evlist__init_ids' to allocate
> > > and retrive events' IDs in one place.

> > I'm ok with this one, will merge it in my perf/core branch together with
> > a fix for a bug I noticed in the original code and that remains with
> > your changes: consider what happens if we do a second perf_evlist__mmap,
> > we will call perf_evlist__id_add_fd again and thus bump evsel->ids++
> > over nr_threads * nr_cpus, overflowing it.

> is there a valid scenario for this function to be called more than once?
> I'd think that just ensuring this is called once is enough

I don't know, I just don't want to preclude that, crystal balls are not
that reliable :-)

- Arnaldo

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/5] perf tool: Initialize events IDs in a single function
  2011-11-18 14:22   ` Arnaldo Carvalho de Melo
@ 2011-11-20  1:36     ` Jiri Olsa
  2011-11-20  1:03       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  1:36 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: a.p.zijlstra, mingo, paulus, linux-kernel

On Fri, Nov 18, 2011 at 12:22:55PM -0200, Arnaldo Carvalho de Melo wrote:
> Em Fri, Nov 18, 2011 at 02:46:42PM +0100, Jiri Olsa escreveu:
> > Currently events' IDs initialization is scattered among the
> > code. Adding function 'perf_evlist__init_ids' to allocate
> > and retrive events' IDs in one place.
> 
> I'm ok with this one, will merge it in my perf/core branch together with
> a fix for a bug I noticed in the original code and that remains with
> your changes: consider what happens if we do a second perf_evlist__mmap,
> we will call perf_evlist__id_add_fd again and thus bump evsel->ids++
> over nr_threads * nr_cpus, overflowing it.

is there a valid scenario for this function to be called more than once?
I'd think that just ensuring this is called once is enough

jirka

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/5] perf tool: Introducing perf_mmap object
  2011-11-18 14:37   ` Arnaldo Carvalho de Melo
@ 2011-11-20  1:39     ` Jiri Olsa
  0 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  1:39 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: a.p.zijlstra, mingo, paulus, linux-kernel

On Fri, Nov 18, 2011 at 12:37:40PM -0200, Arnaldo Carvalho de Melo wrote:
> Em Fri, Nov 18, 2011 at 02:46:43PM +0100, Jiri Olsa escreveu:
> > +++ b/tools/perf/builtin-test.c
> > @@ -476,6 +477,7 @@ static int test__basic_mmap(void)
> >  		     expected_nr_events[nsyscalls], i, j;
> >  	struct perf_evsel *evsels[nsyscalls], *evsel;
> >  	int sample_size = __perf_evsel__sample_size(attr.sample_type);
> > +	struct perf_mmap *md;
> >  
> >  	for (i = 0; i < nsyscalls; ++i) {
> >  		char name[64];
> > @@ -551,7 +553,9 @@ static int test__basic_mmap(void)
> >  			++foo;
> >  		}
> >  
> > -	while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
> > +	md = &evlist->mmap[0];
> > +
> > +	while ((event = perf_mmap__read(md)) != NULL) {
> >  		struct perf_sample sample;
> >  
> >  		if (event->header.type != PERF_RECORD_SAMPLE) {
> 
> Please keep perf_evlist__mmap_read() as just a wrapper for the above
> operation, that way you reduce the patch size by not touching the
> functions that use perf_evlist__mmap_read().
> 
> Later, if we think this is the right thing to do, i.e. to open code it
> like you're doing above, we can elliminate it, but I think its better to
> keep it as perf_evlist__mmap_read(evlist, 0) as it uses just one line
> instead of the 4 above :-)

right, I'll sent v2 shortly

> 
> > diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> > index 8e02027..032f70d 100644
> > --- a/tools/perf/builtin-top.c
> > +++ b/tools/perf/builtin-top.c
> > @@ -38,6 +38,7 @@

SNIP

> >  void perf_evlist__munmap(struct perf_evlist *evlist)
> >  {
> >  	int i;
> >  
> >  	for (i = 0; i < evlist->nr_mmaps; i++) {
> > -		if (evlist->mmap[i].base != NULL) {
> > -			munmap(evlist->mmap[i].base, evlist->mmap_len);
> > -			evlist->mmap[i].base = NULL;
> > -		}
> > +		struct perf_mmap *m = &evlist->mmap[i];
> > +		if (m->base != NULL)
> > +			perf_mmap__close(m);
> 
> Wouldn't it be perf_mmap__munmap() ? 
> 
> >  	}
> >  
> >  	free(evlist->mmap);
> > @@ -292,20 +225,18 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
> >  }
> >  
> >  static int __perf_evlist__mmap(struct perf_evlist *evlist,
> > -			       int idx, int prot, int mask, int fd)
> > +			       int idx, int fd)
> >  {
> > -	evlist->mmap[idx].prev = 0;
> > -	evlist->mmap[idx].mask = mask;
> > -	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
> > -				      MAP_SHARED, fd, 0);
> > -	if (evlist->mmap[idx].base == MAP_FAILED)
> > +	struct perf_mmap *m = &evlist->mmap[idx];
> > +
> > +	if (perf_mmap__open(m, fd, evlist->overwrite, evlist->pages))
> 
> And here perf_mmap__mmap or at least perf_mmap__map and the other
> perf_mmap__unmap?

not sure, perf_mmap__open and perf_mmap__close actually does map/umap..
maybe we can rename them ;)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC,PATCHv2] perf tool: Refactoring IO data files code
  2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
                   ` (5 preceding siblings ...)
  2011-11-18 14:14 ` [RFC,PATCH] perf tool: Refactoring IO data files code Arnaldo Carvalho de Melo
@ 2011-11-20  2:03 ` Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
                     ` (4 more replies)
  6 siblings, 5 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  2:03 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel

Hi,

based on following discussion:
http://marc.info/?l=linux-kernel&m=131731212425421&w=2
http://marc.info/?l=linux-kernel&m=131736842010972&w=2

I made some changes to have event memory mapping and input/output
data code in one place. The reason was to make the change for
multiple event data files at least possible ;)

This patchset is marked as RFC since it's quite big change
and I expect some better design might come up.

However, patches 1 and 2 are not big deal, since they are
just small (not so related) changes.

Patches 3-4 are the main change of the patchset.

1/5 perf tool: Fix session host_nachine retrieval
2/5 perf tool: Initialize events IDs in a single function
3/5 perf tool: Introducing perf_mmap object
4/5 perf tool: Introducing perf_data object
5/5 perf tool: Putting mmap support to perf_data object

I did some overall testing of all the changed command,
and so far so good. Just hit issue with 'diff' command,
but this one seems not to work even without my changes.

Also the current perf python binsing code is broken
wit missing dependencies so I could not test my
changes there.

v2 changes:
  - 3/5 kept the perf_evlist__mmap_read function as a wrapper
    around perf_mmap__read
  - 4/5 removed unlink call from file_backup, because it's not
    needed when followed with rename

thanks for comments,
jirka

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCHv2 1/5] perf tool: Fix session host_nachine retrieval
  2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
@ 2011-11-20  2:03   ` Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 2/5] perf tool: Initialize events IDs in a single function Jiri Olsa
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  2:03 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

The host_machine is statically included inside perf_session struct
so it is always present.

Changing function:
'perf_session__find_host_machine' to 'perf_session__host_machine'

Removing NULL checking code after this function, since it is not needed.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-inject.c |    6 +-----
 tools/perf/builtin-kmem.c   |   12 +++++-------
 tools/perf/builtin-record.c |    6 +-----
 tools/perf/builtin-top.c    |    4 ++--
 tools/perf/util/event.c     |   14 +++++---------
 tools/perf/util/session.h   |    6 +++---
 6 files changed, 17 insertions(+), 31 deletions(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 8dfc12b..3c5eb3a 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -111,11 +111,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
 		return -1;
 	}
 
-	machine = perf_session__find_host_machine(session);
-	if (machine == NULL) {
-		pr_err("Can't find machine for session\n");
-		return -1;
-	}
+	machine = perf_session__host_machine(session);
 
 	if (self->kernel)
 		misc = PERF_RECORD_MISC_KERNEL;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 225e963..2ca8206 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -342,7 +342,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 			   int n_lines, int is_caller)
 {
 	struct rb_node *next;
-	struct machine *machine;
 
 	printf("%.102s\n", graph_dotted_line);
 	printf(" %-34s |",  is_caller ? "Callsite": "Alloc Ptr");
@@ -351,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 
 	next = rb_first(root);
 
-	machine = perf_session__find_host_machine(session);
-	if (!machine) {
-		pr_err("__print_result: couldn't find kernel information\n");
-		return;
-	}
 	while (next && n_lines--) {
 		struct alloc_stat *data = rb_entry(next, struct alloc_stat,
 						   node);
@@ -366,8 +360,12 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 
 		if (is_caller) {
 			addr = data->call_site;
-			if (!raw_ip)
+			if (!raw_ip) {
+				struct machine *machine;
+
+				machine = perf_session__host_machine(session);
 				sym = machine__find_kernel_function(machine, addr, &map, NULL);
+			}
 		} else
 			addr = data->ptr;
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6ab58cc..1132e70 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -662,11 +662,7 @@ static int __cmd_record(int argc, const char **argv)
 		}
 	}
 
-	machine = perf_session__find_host_machine(session);
-	if (!machine) {
-		pr_err("Couldn't find native kernel information.\n");
-		return -1;
-	}
+	machine = perf_session__host_machine(session);
 
 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
 						 session, machine, "_text");
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9cdedb..8e02027 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -692,13 +692,13 @@ static void perf_event__process_sample(const union perf_event *event,
 		++top.us_samples;
 		if (top.hide_user_symbols)
 			return;
-		machine = perf_session__find_host_machine(session);
+		machine = perf_session__host_machine(session);
 		break;
 	case PERF_RECORD_MISC_KERNEL:
 		++top.kernel_samples;
 		if (top.hide_kernel_symbols)
 			return;
-		machine = perf_session__find_host_machine(session);
+		machine = perf_session__host_machine(session);
 		break;
 	case PERF_RECORD_MISC_GUEST_KERNEL:
 		++top.guest_kernel_samples;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 437f8ca..35817fa 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -589,12 +589,12 @@ int perf_event__process_mmap(union perf_event *event,
 		return 0;
 	}
 
-	machine = perf_session__find_host_machine(session);
-	if (machine == NULL)
-		goto out_problem;
 	thread = perf_session__findnew(session, event->mmap.pid);
 	if (thread == NULL)
 		goto out_problem;
+
+	machine = perf_session__host_machine(session);
+
 	map = map__new(&machine->user_dsos, event->mmap.start,
 			event->mmap.len, event->mmap.pgoff,
 			event->mmap.pid, event->mmap.filename,
@@ -672,15 +672,11 @@ void thread__find_addr_map(struct thread *self,
 
 	if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
 		al->level = 'k';
-		machine = perf_session__find_host_machine(session);
-		if (machine == NULL) {
-			al->map = NULL;
-			return;
-		}
+		machine = perf_session__host_machine(session);
 		mg = &machine->kmaps;
 	} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
 		al->level = '.';
-		machine = perf_session__find_host_machine(session);
+		machine = perf_session__host_machine(session);
 	} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
 		al->level = 'g';
 		machine = perf_session__find_machine(session, pid);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 6e393c9..a81d666 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -121,7 +121,7 @@ void perf_session__update_sample_type(struct perf_session *self);
 void perf_session__remove_thread(struct perf_session *self, struct thread *th);
 
 static inline
-struct machine *perf_session__find_host_machine(struct perf_session *self)
+struct machine *perf_session__host_machine(struct perf_session *self)
 {
 	return &self->host_machine;
 }
@@ -130,7 +130,7 @@ static inline
 struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
 {
 	if (pid == HOST_KERNEL_ID)
-		return &self->host_machine;
+		return perf_session__host_machine(self);
 	return machines__find(&self->machines, pid);
 }
 
@@ -138,7 +138,7 @@ static inline
 struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
 {
 	if (pid == HOST_KERNEL_ID)
-		return &self->host_machine;
+		return perf_session__host_machine(self);
 	return machines__findnew(&self->machines, pid);
 }
 
-- 
1.7.6.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCHv2 2/5] perf tool: Initialize events IDs in a single function
  2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
@ 2011-11-20  2:03   ` Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 3/5] perf tool: Introducing perf_mmap object Jiri Olsa
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  2:03 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Currently events' IDs initialization is scattered among the
code. Adding function 'perf_evlist__init_ids' to allocate
and retrive events' IDs in one place.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/util/evlist.c |   50 +++++++++++++++++++++++++++++----------------
 1 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index fbb4b4a..0f715d0 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -326,10 +326,6 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
 					if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
 						goto out_unmap;
 				}
-
-				if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-				    perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
-					goto out_unmap;
 			}
 		}
 	}
@@ -366,10 +362,6 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
 				if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
 					goto out_unmap;
 			}
-
-			if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-			    perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
-				goto out_unmap;
 		}
 	}
 
@@ -385,6 +377,33 @@ out_unmap:
 	return -1;
 }
 
+static int perf_evlist__init_ids(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+	struct thread_map *threads = evlist->threads;
+	struct cpu_map *cpus = evlist->cpus;
+	int cpu, thread;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (!(evsel->attr.read_format & PERF_FORMAT_ID))
+			continue;
+
+		if ((!evsel->sample_id) &&
+		    perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
+			return -ENOMEM;
+
+		for (cpu = 0; cpu < cpus->nr; cpu++)
+			for (thread = 0; thread < threads->nr; thread++) {
+				int fd = FD(evsel, cpu, thread);
+				if (perf_evlist__id_add_fd(evlist, evsel,
+							   cpu, thread, fd))
+					return -EINVAL;
+			}
+	}
+
+	return 0;
+}
+
 /** perf_evlist__mmap - Create per cpu maps to receive events
  *
  * @evlist - list of events
@@ -403,10 +422,8 @@ out_unmap:
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 {
 	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-	int mask = pages * page_size - 1;
-	struct perf_evsel *evsel;
+	int mask = pages * page_size - 1, ret;
 	const struct cpu_map *cpus = evlist->cpus;
-	const struct thread_map *threads = evlist->threads;
 	int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
 
 	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
@@ -418,14 +435,11 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 	evlist->overwrite = overwrite;
 	evlist->mmap_len = (pages + 1) * page_size;
 
-	list_for_each_entry(evsel, &evlist->entries, node) {
-		if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-		    evsel->sample_id == NULL &&
-		    perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
-			return -ENOMEM;
-	}
+	ret = perf_evlist__init_ids(evlist);
+	if (ret)
+		return ret;
 
-	if (evlist->cpus->map[0] == -1)
+	if (cpus->map[0] == -1)
 		return perf_evlist__mmap_per_thread(evlist, prot, mask);
 
 	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
-- 
1.7.6.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCHv2 3/5] perf tool: Introducing perf_mmap object
  2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 2/5] perf tool: Initialize events IDs in a single function Jiri Olsa
@ 2011-11-20  2:03   ` Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 4/5] perf tool: Introducing perf_data object Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 5/5] perf tool: Putting mmap support to " Jiri Olsa
  4 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  2:03 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Adding perf_mmap object to handle event memory maps.

All the memory map related functions originally scatered through
the whole code arenow place in perf_mmap object.

To map and unmap perf_mmap:
        perf_mmap__open
        perf_mmap__close

For reading events via callback:
        perf_mmap__process

For reading events directly:
        perf_mmap__read

following helpers were moved in from perf.h:
        perf_mmap__read_head
        perf_mmap__write_tail

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile         |    2 +
 tools/perf/builtin-record.c |   57 ++++-------------
 tools/perf/perf.h           |   26 --------
 tools/perf/util/evlist.c    |  116 ++++++++----------------------------
 tools/perf/util/evlist.h    |    2 +-
 tools/perf/util/mmap.c      |  138 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/mmap.h      |   45 ++++++++++++++
 7 files changed, 225 insertions(+), 161 deletions(-)
 create mode 100644 tools/perf/util/mmap.c
 create mode 100644 tools/perf/util/mmap.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index b98e307..0158b66 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -274,6 +274,7 @@ LIB_H += util/xyarray.h
 LIB_H += util/header.h
 LIB_H += util/help.h
 LIB_H += util/session.h
+LIB_H += util/mmap.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
@@ -337,6 +338,7 @@ LIB_OBJS += $(OUTPUT)util/debug.o
 LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
+LIB_OBJS += $(OUTPUT)util/mmap.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 1132e70..89b3dc2 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -25,6 +25,7 @@
 #include "util/symbol.h"
 #include "util/cpumap.h"
 #include "util/thread_map.h"
+#include "util/mmap.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -65,7 +66,6 @@ static bool			no_buildid			=  false;
 static bool			no_buildid_cache		=  false;
 static struct perf_evlist	*evsel_list;
 
-static long			samples				=      0;
 static u64			bytes_written			=      0;
 
 static int			file_new			=      1;
@@ -103,39 +103,6 @@ static int process_synthesized_event(union perf_event *event,
 	return 0;
 }
 
-static void mmap_read(struct perf_mmap *md)
-{
-	unsigned int head = perf_mmap__read_head(md);
-	unsigned int old = md->prev;
-	unsigned char *data = md->base + page_size;
-	unsigned long size;
-	void *buf;
-
-	if (old == head)
-		return;
-
-	samples++;
-
-	size = head - old;
-
-	if ((old & md->mask) + size != (head & md->mask)) {
-		buf = &data[old & md->mask];
-		size = md->mask + 1 - (old & md->mask);
-		old += size;
-
-		write_output(buf, size);
-	}
-
-	buf = &data[old & md->mask];
-	size = head - old;
-	old += size;
-
-	write_output(buf, size);
-
-	md->prev = old;
-	perf_mmap__write_tail(md, old);
-}
-
 static volatile int done = 0;
 static volatile int signr = -1;
 static volatile int child_finished = 0;
@@ -442,17 +409,25 @@ static struct perf_event_header finished_round_event = {
 	.type = PERF_RECORD_FINISHED_ROUND,
 };
 
-static void mmap_read_all(void)
+static void mmap_read(struct perf_mmap *m __used, void *buf, unsigned long size)
+{
+	write_output(buf, size);
+}
+
+static int mmap_read_all(void)
 {
-	int i;
+	int i, ret = 0;
 
 	for (i = 0; i < evsel_list->nr_mmaps; i++) {
-		if (evsel_list->mmap[i].base)
-			mmap_read(&evsel_list->mmap[i]);
+		struct perf_mmap *m = &evsel_list->mmap[i];
+		if (m->base)
+			ret += perf_mmap__process(m, mmap_read);
 	}
 
 	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
 		write_output(&finished_round_event, sizeof(finished_round_event));
+
+	return ret;
 }
 
 static int __cmd_record(int argc, const char **argv)
@@ -712,11 +687,7 @@ static int __cmd_record(int argc, const char **argv)
 		close(go_pipe[1]);
 
 	for (;;) {
-		int hits = samples;
-
-		mmap_read_all();
-
-		if (hits == samples) {
+		if (!mmap_read_all()) {
 			if (done)
 				break;
 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 914c895..d79efbb 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -104,32 +104,6 @@ void get_term_dimensions(struct winsize *ws);
 #include "util/types.h"
 #include <stdbool.h>
 
-struct perf_mmap {
-	void			*base;
-	int			mask;
-	unsigned int		prev;
-};
-
-static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
-{
-	struct perf_event_mmap_page *pc = mm->base;
-	int head = pc->data_head;
-	rmb();
-	return head;
-}
-
-static inline void perf_mmap__write_tail(struct perf_mmap *md,
-					 unsigned long tail)
-{
-	struct perf_event_mmap_page *pc = md->base;
-
-	/*
-	 * ensure all reads are done before we write the tail out.
-	 */
-	/* mb(); */
-	pc->data_tail = tail;
-}
-
 /*
  * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
  * counters in the current task.
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 0f715d0..7dd64dd 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -12,6 +12,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "util.h"
+#include "mmap.h"
 
 #include <sys/mman.h>
 
@@ -202,69 +203,9 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
 
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
 {
-	/* XXX Move this to perf.c, making it generally available */
-	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-	struct perf_mmap *md = &evlist->mmap[idx];
-	unsigned int head = perf_mmap__read_head(md);
-	unsigned int old = md->prev;
-	unsigned char *data = md->base + page_size;
-	union perf_event *event = NULL;
-
-	if (evlist->overwrite) {
-		/*
-		 * If we're further behind than half the buffer, there's a chance
-		 * the writer will bite our tail and mess up the samples under us.
-		 *
-		 * If we somehow ended up ahead of the head, we got messed up.
-		 *
-		 * In either case, truncate and restart at head.
-		 */
-		int diff = head - old;
-		if (diff > md->mask / 2 || diff < 0) {
-			fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
-
-			/*
-			 * head points to a known good entry, start there.
-			 */
-			old = head;
-		}
-	}
-
-	if (old != head) {
-		size_t size;
-
-		event = (union perf_event *)&data[old & md->mask];
-		size = event->header.size;
-
-		/*
-		 * Event straddles the mmap boundary -- header should always
-		 * be inside due to u64 alignment of output.
-		 */
-		if ((old & md->mask) + size != ((old + size) & md->mask)) {
-			unsigned int offset = old;
-			unsigned int len = min(sizeof(*event), size), cpy;
-			void *dst = &evlist->event_copy;
-
-			do {
-				cpy = min(md->mask + 1 - (offset & md->mask), len);
-				memcpy(dst, &data[offset & md->mask], cpy);
-				offset += cpy;
-				dst += cpy;
-				len -= cpy;
-			} while (len);
-
-			event = &evlist->event_copy;
-		}
-
-		old += size;
-	}
-
-	md->prev = old;
-
-	if (!evlist->overwrite)
-		perf_mmap__write_tail(md, old);
-
-	return event;
+	struct perf_mmap *md;
+	md = &evlist->mmap[idx];
+	return perf_mmap__read(md);
 }
 
 void perf_evlist__munmap(struct perf_evlist *evlist)
@@ -272,10 +213,9 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
 	int i;
 
 	for (i = 0; i < evlist->nr_mmaps; i++) {
-		if (evlist->mmap[i].base != NULL) {
-			munmap(evlist->mmap[i].base, evlist->mmap_len);
-			evlist->mmap[i].base = NULL;
-		}
+		struct perf_mmap *m = &evlist->mmap[i];
+		if (m->base != NULL)
+			perf_mmap__close(m);
 	}
 
 	free(evlist->mmap);
@@ -292,20 +232,18 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 }
 
 static int __perf_evlist__mmap(struct perf_evlist *evlist,
-			       int idx, int prot, int mask, int fd)
+			       int idx, int fd)
 {
-	evlist->mmap[idx].prev = 0;
-	evlist->mmap[idx].mask = mask;
-	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
-				      MAP_SHARED, fd, 0);
-	if (evlist->mmap[idx].base == MAP_FAILED)
+	struct perf_mmap *m = &evlist->mmap[idx];
+
+	if (perf_mmap__open(m, fd, evlist->overwrite, evlist->pages))
 		return -1;
 
 	perf_evlist__add_pollfd(evlist, fd);
 	return 0;
 }
 
-static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
+static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel;
 	int cpu, thread;
@@ -320,7 +258,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
 				if (output == -1) {
 					output = fd;
 					if (__perf_evlist__mmap(evlist, cpu,
-								prot, mask, output) < 0)
+								output) < 0)
 						goto out_unmap;
 				} else {
 					if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
@@ -334,15 +272,14 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
 
 out_unmap:
 	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		if (evlist->mmap[cpu].base != NULL) {
-			munmap(evlist->mmap[cpu].base, evlist->mmap_len);
-			evlist->mmap[cpu].base = NULL;
-		}
+		struct perf_mmap *m = &evlist->mmap[cpu];
+		if (m->base != NULL)
+			perf_mmap__close(m);
 	}
 	return -1;
 }
 
-static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
+static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel;
 	int thread;
@@ -356,7 +293,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
 			if (output == -1) {
 				output = fd;
 				if (__perf_evlist__mmap(evlist, thread,
-							prot, mask, output) < 0)
+							output) < 0)
 					goto out_unmap;
 			} else {
 				if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
@@ -369,10 +306,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
 
 out_unmap:
 	for (thread = 0; thread < evlist->threads->nr; thread++) {
-		if (evlist->mmap[thread].base != NULL) {
-			munmap(evlist->mmap[thread].base, evlist->mmap_len);
-			evlist->mmap[thread].base = NULL;
-		}
+		struct perf_mmap *m = &evlist->mmap[thread];
+		if (m->base != NULL)
+			perf_mmap__close(m);
 	}
 	return -1;
 }
@@ -421,10 +357,8 @@ static int perf_evlist__init_ids(struct perf_evlist *evlist)
  */
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 {
-	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-	int mask = pages * page_size - 1, ret;
 	const struct cpu_map *cpus = evlist->cpus;
-	int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
+	int ret;
 
 	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
 		return -ENOMEM;
@@ -433,16 +367,16 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
 		return -ENOMEM;
 
 	evlist->overwrite = overwrite;
-	evlist->mmap_len = (pages + 1) * page_size;
+	evlist->pages = pages;
 
 	ret = perf_evlist__init_ids(evlist);
 	if (ret)
 		return ret;
 
 	if (cpus->map[0] == -1)
-		return perf_evlist__mmap_per_thread(evlist, prot, mask);
+		return perf_evlist__mmap_per_thread(evlist);
 
-	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
+	return perf_evlist__mmap_per_cpu(evlist);
 }
 
 int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 1779ffe..3784273 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -18,7 +18,7 @@ struct perf_evlist {
 	int		 nr_entries;
 	int		 nr_fds;
 	int		 nr_mmaps;
-	int		 mmap_len;
+	int		 pages;
 	bool		 overwrite;
 	union perf_event event_copy;
 	struct perf_mmap *mmap;
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
new file mode 100644
index 0000000..45e62a2
--- /dev/null
+++ b/tools/perf/util/mmap.c
@@ -0,0 +1,138 @@
+#include <string.h>
+#include <stdio.h>
+#include "mmap.h"
+
+int perf_mmap__open(struct perf_mmap *m, int fd, bool overwrite, int pages)
+{
+	unsigned int page_size = sysconf(_SC_PAGE_SIZE);
+	int mask, len, prot;
+	void *base;
+
+	mask = pages * page_size - 1;
+	len  = (pages + 1) * page_size;
+	prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
+
+	base = mmap(NULL, len, prot, MAP_SHARED, fd, 0);
+	if (base == MAP_FAILED)
+		return -1;
+
+	memset(m, 0, sizeof(*m));
+	m->mask = mask;
+	m->len  = len;
+	m->base = base;
+	m->fd   = fd;
+	m->owrt = overwrite;
+	return 0;
+}
+
+int perf_mmap__close(struct perf_mmap *m)
+{
+	int ret = munmap(m->base, m->len);
+
+	memset(m, 0x0, sizeof(*m));
+	return ret;
+}
+
+int perf_mmap__process(struct perf_mmap *md, perf_mmap_process_t process)
+{
+	unsigned int head, old, page_size = sysconf(_SC_PAGE_SIZE);
+	unsigned char *data = md->base + page_size;
+	unsigned long size;
+	void *buf;
+
+	head = perf_mmap__read_head(md);
+	old  = md->prev;
+
+	if (old == head)
+		return 0;
+
+	size = head - old;
+
+	if ((old & md->mask) + size != (head & md->mask)) {
+		buf = &data[old & md->mask];
+		size = md->mask + 1 - (old & md->mask);
+		old += size;
+
+		process(md, buf, size);
+	}
+
+	buf = &data[old & md->mask];
+	size = head - old;
+	old += size;
+
+	process(md, buf, size);
+
+	md->prev = old;
+	perf_mmap__write_tail(md, old);
+	return 1;
+}
+
+union perf_event *perf_mmap__read(struct perf_mmap *md)
+{
+	unsigned int head, old, page_size = sysconf(_SC_PAGE_SIZE);
+	unsigned char *data = md->base + page_size;
+	union perf_event *event = NULL;
+
+	head = perf_mmap__read_head(md);
+	old = md->prev;
+
+	if (md->owrt) {
+		/*
+		 * If we're further behind than half the buffer, there's
+		 * a chance the writer will bite our tail and mess up the
+		 * samples under us.
+		 *
+		 * If we somehow ended up ahead of the head, we got messed up.
+		 *
+		 * In either case, truncate and restart at head.
+		 */
+		int diff = head - old;
+		if (diff > md->mask / 2 || diff < 0) {
+			fprintf(stderr, "WARNING: failed to keep up "
+					"with mmap data.\n");
+
+			/*
+			 * head points to a known good entry, start there.
+			 */
+			old = head;
+		}
+	}
+
+	if (old != head) {
+		size_t size;
+
+		event = (union perf_event *)&data[old & md->mask];
+		size = event->header.size;
+
+		/*
+		 * Event straddles the mmap boundary -- header should always
+		 * be inside due to u64 alignment of output.
+		 */
+		if ((old & md->mask) + size != ((old + size) & md->mask)) {
+			unsigned int offset = old;
+			unsigned int len = min(sizeof(*event), size), cpy;
+			static union perf_event event_copy;
+			void *dst = &event_copy;
+
+			do {
+				cpy = min(md->mask + 1 - (offset & md->mask),
+					  len);
+				memcpy(dst, &data[offset & md->mask], cpy);
+				offset += cpy;
+				dst += cpy;
+				len -= cpy;
+			} while (len);
+
+			event = &event_copy;
+		}
+
+		old += size;
+	}
+
+	md->prev = old;
+
+	if (!md->owrt)
+		perf_mmap__write_tail(md, old);
+
+	return event;
+}
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
new file mode 100644
index 0000000..24cf88f
--- /dev/null
+++ b/tools/perf/util/mmap.h
@@ -0,0 +1,45 @@
+#ifndef __PERF_MMAP_H
+#define __PERF_MMAP_H
+
+#include <sys/mman.h>
+#include "event.h"
+#include "../perf.h"
+
+struct perf_mmap {
+	void  *base;
+	int   mask;
+	u_int prev;
+	int   len;
+	int   fd;
+	bool  owrt;
+};
+
+typedef void (*perf_mmap_process_t)(struct perf_mmap *m,
+				    void *buf, unsigned long size);
+
+int perf_mmap__open(struct perf_mmap *m, int fd, bool overwrite, int pages);
+int perf_mmap__close(struct perf_mmap *m);
+int perf_mmap__process(struct perf_mmap *m, perf_mmap_process_t process);
+union perf_event *perf_mmap__read(struct perf_mmap *md);
+
+static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
+{
+	struct perf_event_mmap_page *pc = mm->base;
+	int head = pc->data_head;
+	rmb();
+	return head;
+}
+
+static inline void perf_mmap__write_tail(struct perf_mmap *md,
+					 unsigned long tail)
+{
+	struct perf_event_mmap_page *pc = md->base;
+
+	/*
+	 * ensure all reads are done before we write the tail out.
+	 */
+	/* mb(); */
+	pc->data_tail = tail;
+}
+
+#endif /* __PERF_MMAP_H */
-- 
1.7.6.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCHv2 4/5] perf tool: Introducing perf_data object
  2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
                     ` (2 preceding siblings ...)
  2011-11-20  2:03   ` [PATCHv2 3/5] perf tool: Introducing perf_mmap object Jiri Olsa
@ 2011-11-20  2:03   ` Jiri Olsa
  2011-11-20  2:03   ` [PATCHv2 5/5] perf tool: Putting mmap support to " Jiri Olsa
  4 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  2:03 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Adding perf_data object to handle input/output data files.
The objective is to have this functionality centralized
and ready for supporting multiple event data streams.

All the input/output file related functions originally scatered
through the whole code are now placed in perf_mmap object.

To open/close data file:
        perf_data__open
        perf_data__close

Plus several helper functions:
        perf_data__is_pipe
        perf_data__is_ro
        perf_data__is_new
        perf_data__size

The perf_data object handles input/output file open/create processing,
plus check for pipe intput/output.

The perf_session object was modified to contains perf_data. Thus for
perf_session users the change is almost invisible apart from newly
defined open mode enums:

        PERF_DATA_NONE
        PERF_DATA_READ
        PERF_DATA_WRITE_TRUNC
        PERF_DATA_WRITE_APPEND

The PERF_DATA_NONE serves for 'top' session, where no storage
is needed. The rest is selfexplanatory.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/Makefile               |    2 +
 tools/perf/builtin-annotate.c     |    3 +-
 tools/perf/builtin-buildid-list.c |    4 +-
 tools/perf/builtin-diff.c         |    6 +-
 tools/perf/builtin-evlist.c       |    3 +-
 tools/perf/builtin-inject.c       |    3 +-
 tools/perf/builtin-kmem.c         |    6 +-
 tools/perf/builtin-lock.c         |    3 +-
 tools/perf/builtin-record.c       |  134 ++++++++-----------------
 tools/perf/builtin-report.c       |    7 +-
 tools/perf/builtin-sched.c        |    6 +-
 tools/perf/builtin-script.c       |    3 +-
 tools/perf/builtin-timechart.c    |    7 +-
 tools/perf/builtin-top.c          |   12 +--
 tools/perf/util/data.c            |  199 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/data.h            |   65 ++++++++++++
 tools/perf/util/header.c          |   35 ++++---
 tools/perf/util/header.h          |    6 +-
 tools/perf/util/session.c         |  115 ++++++++--------------
 tools/perf/util/session.h         |   26 ++++--
 20 files changed, 425 insertions(+), 220 deletions(-)
 create mode 100644 tools/perf/util/data.c
 create mode 100644 tools/perf/util/data.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0158b66..a11ec3d 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -275,6 +275,7 @@ LIB_H += util/header.h
 LIB_H += util/help.h
 LIB_H += util/session.h
 LIB_H += util/mmap.h
+LIB_H += util/data.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
@@ -339,6 +340,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
 LIB_OBJS += $(OUTPUT)util/mmap.o
+LIB_OBJS += $(OUTPUT)util/data.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 46b4c24..cbaa8be 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -183,7 +183,8 @@ static int __cmd_annotate(void)
 	struct perf_evsel *pos;
 	u64 total_nr_samples;
 
-	session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, force,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index cb690a6..0f26866 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -43,8 +43,8 @@ static int perf_session__list_build_ids(void)
 {
 	struct perf_session *session;
 
-	session = perf_session__new(input_name, O_RDONLY, force, false,
-				    &build_id__mark_dso_hit_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, force,
+				    false, &build_id__mark_dso_hit_ops);
 	if (session == NULL)
 		return -1;
 
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index b39f3a1..093d5bf 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -145,8 +145,10 @@ static int __cmd_diff(void)
 	int ret, i;
 	struct perf_session *session[2];
 
-	session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops);
-	session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
+	session[0] = perf_session__new(input_old, PERF_DATA_READ, force,
+				       false, &event_ops);
+	session[1] = perf_session__new(input_new, PERF_DATA_READ, force,
+				       false, &event_ops);
 	if (session[0] == NULL || session[1] == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 4c5e9e0..87a6662 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -22,7 +22,8 @@ static int __cmd_evlist(void)
 	struct perf_session *session;
 	struct perf_evsel *pos;
 
-	session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
+	session = perf_session__new(input_name, PERF_DATA_READ,
+				    false, false, NULL);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 3c5eb3a..38a88ca 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -205,7 +205,8 @@ static int __cmd_inject(void)
 		inject_ops.tracing_data	= perf_event__repipe_tracing_data;
 	}
 
-	session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    true, &inject_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 2ca8206..1a80840 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -480,8 +480,10 @@ static void sort_result(void)
 static int __cmd_kmem(void)
 {
 	int err = -EINVAL;
-	struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-							 0, false, &event_ops);
+	struct perf_session *session;
+
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 899080a..af2c923 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -871,7 +871,8 @@ static struct perf_event_ops eops = {
 
 static int read_events(void)
 {
-	session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &eops);
 	if (!session)
 		die("Initializing perf session failed\n");
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 89b3dc2..8765ae0 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -31,11 +31,6 @@
 #include <sched.h>
 #include <sys/mman.h>
 
-enum write_mode_t {
-	WRITE_FORCE,
-	WRITE_APPEND
-};
-
 static u64			user_interval			= ULLONG_MAX;
 static u64			default_interval		=      0;
 
@@ -43,8 +38,6 @@ static unsigned int		page_size;
 static unsigned int		mmap_pages			= UINT_MAX;
 static unsigned int		user_freq 			= UINT_MAX;
 static int			freq				=   1000;
-static int			output;
-static int			pipe_output			=      0;
 static const char		*output_name			= NULL;
 static bool			group				=  false;
 static int			realtime_prio			=      0;
@@ -56,7 +49,7 @@ static pid_t			target_pid			=     -1;
 static pid_t			target_tid			=     -1;
 static pid_t			child_pid			=     -1;
 static bool			no_inherit			=  false;
-static enum write_mode_t	write_mode			= WRITE_FORCE;
+static enum perf_data_mode	write_mode			=  PERF_DATA_WRITE_TRUNC;
 static bool			call_graph			=  false;
 static bool			inherit_stat			=  false;
 static bool			no_samples			=  false;
@@ -68,7 +61,6 @@ static struct perf_evlist	*evsel_list;
 
 static u64			bytes_written			=      0;
 
-static int			file_new			=      1;
 static off_t			post_processing_offset;
 
 static struct perf_session	*session;
@@ -80,10 +72,10 @@ static void advance_output(size_t size)
 	bytes_written += size;
 }
 
-static void write_output(void *buf, size_t size)
+static void write_output(int fd, void *buf, size_t size)
 {
 	while (size) {
-		int ret = write(output, buf, size);
+		int ret = write(fd, buf, size);
 
 		if (ret < 0)
 			die("failed to write");
@@ -97,9 +89,10 @@ static void write_output(void *buf, size_t size)
 
 static int process_synthesized_event(union perf_event *event,
 				     struct perf_sample *sample __used,
-				     struct perf_session *self __used)
+				     struct perf_session *self)
 {
-	write_output(event, event->header.size);
+	int fd = perf_session__fd(self);
+	write_output(fd, event, event->header.size);
 	return 0;
 }
 
@@ -328,7 +321,7 @@ try_again:
 	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
 
-	if (file_new)
+	if (perf_session__is_new(session))
 		session->evlist = evlist;
 	else {
 		if (!perf_evlist__equal(session->evlist, evlist)) {
@@ -342,12 +335,11 @@ try_again:
 
 static int process_buildids(void)
 {
-	u64 size = lseek(output, 0, SEEK_CUR);
+	u64 size = lseek(perf_session__fd(session), 0, SEEK_CUR);
 
 	if (size == 0)
 		return 0;
 
-	session->fd = output;
 	return __perf_session__process_events(session, post_processing_offset,
 					      size - post_processing_offset,
 					      size, &build_id__mark_dso_hit_ops);
@@ -355,22 +347,23 @@ static int process_buildids(void)
 
 static void atexit_header(void)
 {
-	if (!pipe_output) {
+	if (!perf_session__is_pipe(session)) {
 		session->header.data_size += bytes_written;
 
 		if (!no_buildid)
 			process_buildids();
-		perf_session__write_header(session, evsel_list, output, true);
+		perf_session__write_header(session, evsel_list, true);
 		perf_session__delete(session);
 		perf_evlist__delete(evsel_list);
 		symbol__exit();
 	}
 }
 
-static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
+static void perf_event__synthesize_guest_os(struct machine *machine,
+					    void *__data)
 {
 	int err;
-	struct perf_session *psession = data;
+	struct perf_session *psession = __data;
 
 	if (machine__is_host(machine))
 		return;
@@ -411,7 +404,8 @@ static struct perf_event_header finished_round_event = {
 
 static void mmap_read(struct perf_mmap *m __used, void *buf, unsigned long size)
 {
-	write_output(buf, size);
+	int fd = perf_session__fd(session);
+	write_output(fd, buf, size);
 }
 
 static int mmap_read_all(void)
@@ -420,26 +414,25 @@ static int mmap_read_all(void)
 
 	for (i = 0; i < evsel_list->nr_mmaps; i++) {
 		struct perf_mmap *m = &evsel_list->mmap[i];
-		if (m->base)
-			ret += perf_mmap__process(m, mmap_read);
+		ret += perf_mmap__process(m, mmap_read);
 	}
 
-	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
-		write_output(&finished_round_event, sizeof(finished_round_event));
+	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) {
+		int fd = perf_session__fd(session);
+		write_output(fd, &finished_round_event,
+			     sizeof(finished_round_event));
+	}
 
 	return ret;
 }
 
 static int __cmd_record(int argc, const char **argv)
 {
-	struct stat st;
-	int flags;
-	int err;
+	struct machine *machine;
 	unsigned long waking = 0;
-	int child_ready_pipe[2], go_pipe[2];
+	int child_ready_pipe[2], go_pipe[2], err = 0;
 	const bool forks = argc > 0;
 	char buf;
-	struct machine *machine;
 
 	progname = argv[0];
 
@@ -455,45 +448,8 @@ static int __cmd_record(int argc, const char **argv)
 		exit(-1);
 	}
 
-	if (!output_name) {
-		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
-			pipe_output = 1;
-		else
-			output_name = "perf.data";
-	}
-	if (output_name) {
-		if (!strcmp(output_name, "-"))
-			pipe_output = 1;
-		else if (!stat(output_name, &st) && st.st_size) {
-			if (write_mode == WRITE_FORCE) {
-				char oldname[PATH_MAX];
-				snprintf(oldname, sizeof(oldname), "%s.old",
-					 output_name);
-				unlink(oldname);
-				rename(output_name, oldname);
-			}
-		} else if (write_mode == WRITE_APPEND) {
-			write_mode = WRITE_FORCE;
-		}
-	}
-
-	flags = O_CREAT|O_RDWR;
-	if (write_mode == WRITE_APPEND)
-		file_new = 0;
-	else
-		flags |= O_TRUNC;
-
-	if (pipe_output)
-		output = STDOUT_FILENO;
-	else
-		output = open(output_name, flags, S_IRUSR | S_IWUSR);
-	if (output < 0) {
-		perror("failed to create output file");
-		exit(-1);
-	}
-
-	session = perf_session__new(output_name, O_WRONLY,
-				    write_mode == WRITE_FORCE, false, NULL);
+	session = perf_session__new(output_name, write_mode,
+				    false, false, NULL);
 	if (session == NULL) {
 		pr_err("Not enough memory for reading perf file header\n");
 		return -1;
@@ -502,8 +458,8 @@ static int __cmd_record(int argc, const char **argv)
 	if (!no_buildid)
 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
 
-	if (!file_new) {
-		err = perf_session__read_header(session, output);
+	if (!perf_session__is_new(session)) {
+		err = perf_session__read_header(session);
 		if (err < 0)
 			goto out_delete_session;
 	}
@@ -536,7 +492,7 @@ static int __cmd_record(int argc, const char **argv)
 		}
 
 		if (!child_pid) {
-			if (pipe_output)
+			if (perf_session__is_pipe(session))
 				dup2(2, 1);
 			close(child_ready_pipe[0]);
 			close(go_pipe[1]);
@@ -589,32 +545,31 @@ static int __cmd_record(int argc, const char **argv)
 	 */
 	atexit(atexit_header);
 
-	if (pipe_output) {
-		err = perf_header__write_pipe(output);
+	if (perf_session__is_pipe(session)) {
+		err = perf_header__write_pipe(perf_session__fd(session));
 		if (err < 0)
-			return err;
-	} else if (file_new) {
-		err = perf_session__write_header(session, evsel_list,
-						 output, false);
+			goto out_delete_session;
+	} else if (perf_session__is_new(session)) {
+		err = perf_session__write_header(session, evsel_list, false);
 		if (err < 0)
-			return err;
+			goto out_delete_session;
 	}
 
-	post_processing_offset = lseek(output, 0, SEEK_CUR);
+	post_processing_offset = lseek(perf_session__fd(session), 0, SEEK_CUR);
 
-	if (pipe_output) {
+	if (perf_session__is_pipe(session)) {
 		err = perf_session__synthesize_attrs(session,
 						     process_synthesized_event);
 		if (err < 0) {
 			pr_err("Couldn't synthesize attrs.\n");
-			return err;
+			goto out_delete_session;
 		}
 
 		err = perf_event__synthesize_event_types(process_synthesized_event,
 							 session);
 		if (err < 0) {
 			pr_err("Couldn't synthesize event_types.\n");
-			return err;
+			goto out_delete_session;
 		}
 
 		if (have_tracepoints(&evsel_list->entries)) {
@@ -626,12 +581,12 @@ static int __cmd_record(int argc, const char **argv)
 			 * return this more properly and also
 			 * propagate errors that now are calling die()
 			 */
-			err = perf_event__synthesize_tracing_data(output, evsel_list,
+			err = perf_event__synthesize_tracing_data(evsel_list,
 								  process_synthesized_event,
 								  session);
 			if (err <= 0) {
 				pr_err("Couldn't record tracing data.\n");
-				return err;
+				goto out_delete_session;
 			}
 			advance_output(err);
 		}
@@ -699,7 +654,7 @@ static int __cmd_record(int argc, const char **argv)
 	}
 
 	if (quiet || signr == SIGUSR1)
-		return 0;
+		goto out_delete_session;
 
 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
 
@@ -804,9 +759,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 				" You need to choose between -f and -A");
 		usage_with_options(record_usage, record_options);
 	} else if (append_file) {
-		write_mode = WRITE_APPEND;
+		write_mode = PERF_DATA_WRITE_APPEND;
 	} else {
-		write_mode = WRITE_FORCE;
+		write_mode = PERF_DATA_WRITE_TRUNC;
 	}
 
 	if (nr_cgroups && !system_wide) {
@@ -851,9 +806,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 			goto out_free_fd;
 	}
 
-	if (perf_evlist__alloc_pollfd(evsel_list) < 0)
-		goto out_free_fd;
-
 	if (user_interval != ULLONG_MAX)
 		default_interval = user_interval;
 	if (user_freq != UINT_MAX)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4d7c834..5a98b8e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -35,7 +35,7 @@
 
 #include <linux/bitmap.h>
 
-static char		const *input_name = "perf.data";
+static char		const *input_name;
 
 static bool		force, use_tui, use_stdio;
 static bool		hide_unresolved;
@@ -264,7 +264,8 @@ static int __cmd_report(void)
 
 	signal(SIGINT, sig_handler);
 
-	session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, force,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
@@ -514,7 +515,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
 	if (inverted_callchain)
 		callchain_param.order = ORDER_CALLER;
 
-	if (strcmp(input_name, "-") != 0)
+	if (input_name && strcmp(input_name, "-") != 0)
 		setup_browser(true);
 	else
 		use_browser = 0;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 5177964..266333c 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1640,8 +1640,10 @@ static struct perf_event_ops event_ops = {
 static void read_events(bool destroy, struct perf_session **psession)
 {
 	int err = -EINVAL;
-	struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-							 0, false, &event_ops);
+	struct perf_session *session;
+
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		die("No Memory");
 
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 2f62a29..89ae663 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1261,7 +1261,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
 	if (!script_name)
 		setup_pager();
 
-	session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index aa26f4d..e3f4951 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -984,10 +984,11 @@ static struct perf_event_ops event_ops = {
 
 static int __cmd_timechart(void)
 {
-	struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-							 0, false, &event_ops);
-	int ret = -EINVAL;
+	struct perf_session *session;
+	int ret = EINVAL;
 
+	session = perf_session__new(input_name, PERF_DATA_READ, false,
+				    false, &event_ops);
 	if (session == NULL)
 		return -ENOMEM;
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8e02027..bc3a21b 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -954,11 +954,9 @@ static int __cmd_top(void)
 {
 	pthread_t thread;
 	int ret;
-	/*
-	 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
-	 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
-	 */
-	top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
+
+	top.session = perf_session__new(NULL, PERF_DATA_NONE, false,
+					false, NULL);
 	if (top.session == NULL)
 		return -ENOMEM;
 
@@ -1243,10 +1241,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
 		pos->attr.sample_period = default_interval;
 	}
 
-	if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
-	    perf_evlist__alloc_mmap(top.evlist) < 0)
-		goto out_free_fd;
-
 	top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
 
 	symbol_conf.priv_size = sizeof(struct annotation);
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
new file mode 100644
index 0000000..52ee306
--- /dev/null
+++ b/tools/perf/util/data.c
@@ -0,0 +1,199 @@
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <errno.h>
+
+#include "data.h"
+#include "util.h"
+#include "cpumap.h"
+#include "thread_map.h"
+#include "evsel.h"
+
+static bool pipe_is_fd(int fd)
+{
+	struct stat st;
+	return !fstat(fd, &st) && S_ISFIFO(st.st_mode);
+}
+
+static int pipe_get_fd(int mode)
+{
+	if (mode == PERF_DATA_READ)
+		return STDIN_FILENO;
+	return STDOUT_FILENO;
+}
+
+static bool pipe_chk(const char *name, int mode)
+{
+	int fd = pipe_get_fd(mode);
+
+	if (!name && pipe_is_fd(fd))
+		return true;
+
+	if (name && !strcmp(name, "-"))
+		return true;
+
+	return false;
+}
+
+static int pipe_data(struct perf_data *data)
+{
+	struct perf_data_file *file = &data->header;
+
+	memset(file, 0, sizeof(*file));
+	file->fd = pipe_get_fd(data->mode);
+	return 0;
+}
+
+static int file_chk_read(struct perf_data *data,
+			 struct stat *st, char *name)
+{
+	if (!data->force &&
+	    st->st_uid && (st->st_uid != geteuid())) {
+		pr_err("file %s not owned by current user or root\n",
+		       name);
+		return -1;
+	}
+
+	if (!st->st_size) {
+		pr_info("zero-sized file (%s), nothing to do!\n",
+			name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int file_open(struct perf_data *data, char *name)
+{
+	int flags = 0, fd;
+	int mode = data->mode;
+
+	switch (mode) {
+	case PERF_DATA_READ:
+		flags = O_RDONLY;
+		break;
+	case PERF_DATA_WRITE_TRUNC:
+		flags = O_TRUNC;
+	/* falling through intentionally */
+	case PERF_DATA_WRITE_APPEND:
+		flags |= O_CREAT|O_RDWR;
+		break;
+	default:
+		return -1;
+	};
+
+	fd = open(name, flags, S_IRUSR | S_IWUSR);
+	if (fd < 0)
+		perror("failed to create output file");
+
+	return fd;
+}
+
+static int file_backup(char *name)
+{
+	char oldname[PATH_MAX];
+	int ret;
+
+	snprintf(oldname, sizeof(oldname), "%s.old",
+		 name);
+
+	ret = rename(name, oldname);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int data_file__open(struct perf_data *data,
+			   struct perf_data_file *file,
+			   char *name)
+{
+	struct stat st;
+	int fd, mode = data->mode;
+	bool exists;
+
+	exists = (!stat(name, &st) && st.st_size);
+
+	/* make the file backup if needed */
+	if (exists && (mode == PERF_DATA_WRITE_TRUNC)) {
+		int ret = file_backup(name);
+		if (ret)
+			return ret;
+	}
+
+	/* nothing to append to, change mode */
+	if (!exists &&
+	    (mode == PERF_DATA_WRITE_APPEND))
+		mode = PERF_DATA_WRITE_TRUNC;
+
+	data->mode = mode;
+	memset(file, 0, sizeof(*file));
+
+	/* read sanity checks */
+	if (mode == PERF_DATA_READ) {
+		if (!exists) {
+			pr_err("failed to open %s: does not exist\n", name);
+			return -EINVAL;
+		}
+		if (file_chk_read(data, &st, name))
+			return -1;
+		file->size = st.st_size;
+	}
+
+	fd = file_open(data, name);
+	if (fd < 0)
+		return errno;
+
+	file->name = name;
+	file->fd = fd;
+
+	list_add_tail(&file->list, &data->files);
+	return 0;
+}
+
+static void data_file__close(struct perf_data *data __used,
+			     struct perf_data_file *file)
+{
+	close(file->fd);
+}
+
+int perf_data__open(struct perf_data *data, const char *name,
+		    int mode, bool force)
+{
+	bool is_pipe;
+
+	memset(data, 0, sizeof(*data));
+	data->mode = mode;
+	INIT_LIST_HEAD(&data->files);
+
+	if (mode == PERF_DATA_NONE)
+		return 0;
+
+	is_pipe = pipe_chk(name, mode);
+	if (!is_pipe && !name)
+		name = "perf.data";
+
+	data->force   = force;
+	data->is_pipe = is_pipe;
+
+	if (is_pipe)
+		return pipe_data(data);
+
+	return data_file__open(data, &data->header, (char *) name);
+}
+
+void perf_data__close(struct perf_data *data)
+{
+	struct perf_data_file *file;
+
+	if (!data->is_pipe)
+		return;
+
+	list_for_each_entry(file, &data->files, list)
+		data_file__close(data, file);
+}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
new file mode 100644
index 0000000..3103f7a
--- /dev/null
+++ b/tools/perf/util/data.h
@@ -0,0 +1,65 @@
+#ifndef __PERF_DATA_H
+#define __PERF_DATA_H
+
+#include <stdbool.h>
+#include <linux/list.h>
+#include "mmap.h"
+#include "evlist.h"
+
+enum perf_data_mode {
+	PERF_DATA_NONE,
+	PERF_DATA_READ,
+	PERF_DATA_WRITE_TRUNC,
+	PERF_DATA_WRITE_APPEND,
+};
+
+struct perf_data_file {
+	int fd;
+	off_t size;
+	char *name;
+
+	struct list_head list;
+};
+
+struct perf_data {
+	struct perf_data_file header;
+
+	bool is_pipe;
+	int  mode;
+	bool force;
+
+	struct list_head files;
+};
+
+int perf_data__open(struct perf_data *data, const char *name,
+		    int mode, bool force);
+void perf_data__close(struct perf_data *data);
+
+#define PERF_DATA__NONE(__data) \
+	perf_data__open(&__data, NULL, PERF_DATA_NONE, false);
+
+static inline int perf_data__is_pipe(struct perf_data *data)
+{
+	return data->is_pipe;
+}
+
+static inline int perf_data__is_ro(struct perf_data *data)
+{
+	return data->mode == PERF_DATA_READ;
+}
+
+static inline int perf_data__is_new(struct perf_data *data)
+{
+	return data->mode == PERF_DATA_WRITE_TRUNC;
+}
+
+static inline off_t perf_data__size(struct perf_data *data)
+{
+	return data->header.size;
+}
+
+static inline int perf_data__fd(struct perf_data *data)
+{
+	return data->header.fd;
+}
+#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index bcd05d0..f1580c8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1123,7 +1123,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
 {
 	struct header_print_data hd;
 	struct perf_header *header = &session->header;
-	int fd = session->fd;
+	int fd = perf_session__fd(session);
 	hd.fp = fp;
 	hd.full = full;
 
@@ -1525,13 +1525,13 @@ int perf_header__write_pipe(int fd)
 
 int perf_session__write_header(struct perf_session *session,
 			       struct perf_evlist *evlist,
-			       int fd, bool at_exit)
+			       bool at_exit)
 {
 	struct perf_file_header f_header;
 	struct perf_file_attr   f_attr;
 	struct perf_header *header = &session->header;
 	struct perf_evsel *attr, *pair = NULL;
-	int err;
+	int err, fd = perf_session__fd(session);
 
 	lseek(fd, sizeof(f_header), SEEK_SET);
 
@@ -1960,10 +1960,11 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
 	return 0;
 }
 
-static int perf_header__read_pipe(struct perf_session *session, int fd)
+static int perf_header__read_pipe(struct perf_session *session)
 {
 	struct perf_header *header = &session->header;
 	struct perf_pipe_file_header f_header;
+	int fd = perf_session__fd(session);
 
 	if (perf_file_header__read_pipe(&f_header, header, fd,
 					session->repipe) < 0) {
@@ -1971,25 +1972,24 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
 		return -EINVAL;
 	}
 
-	session->fd = fd;
-
 	return 0;
 }
 
-int perf_session__read_header(struct perf_session *session, int fd)
+int perf_session__read_header(struct perf_session *session)
 {
 	struct perf_header *header = &session->header;
 	struct perf_file_header	f_header;
 	struct perf_file_attr	f_attr;
 	u64			f_id;
 	int nr_attrs, nr_ids, i, j;
+	int fd = perf_session__fd(session);
 
 	session->evlist = perf_evlist__new(NULL, NULL);
 	if (session->evlist == NULL)
 		return -ENOMEM;
 
-	if (session->fd_pipe)
-		return perf_header__read_pipe(session, fd);
+	if (perf_session__is_pipe(session))
+		return perf_header__read_pipe(session);
 
 	if (perf_file_header__read(&f_header, header, fd) < 0) {
 		pr_debug("incompatible file format\n");
@@ -2213,14 +2213,14 @@ int perf_event__process_event_type(union perf_event *event,
 	return 0;
 }
 
-int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
-					 perf_event__handler_t process,
-				   struct perf_session *session __unused)
+int perf_event__synthesize_tracing_data(struct perf_evlist *evlist,
+					perf_event__handler_t process,
+					struct perf_session *session)
 {
 	union perf_event ev;
 	struct tracing_data *tdata;
 	ssize_t size = 0, aligned_size = 0, padding;
-	int err __used = 0;
+	int fd = perf_session__fd(session);
 
 	/*
 	 * We are going to store the size of the data followed
@@ -2263,18 +2263,19 @@ int perf_event__process_tracing_data(union perf_event *event,
 				     struct perf_session *session)
 {
 	ssize_t size_read, padding, size = event->tracing_data.size;
-	off_t offset = lseek(session->fd, 0, SEEK_CUR);
+	int fd = perf_session__fd(session);
+	off_t offset = lseek(fd, 0, SEEK_CUR);
 	char buf[BUFSIZ];
 
 	/* setup for reading amidst mmap */
-	lseek(session->fd, offset + sizeof(struct tracing_data_event),
+	lseek(fd, offset + sizeof(struct tracing_data_event),
 	      SEEK_SET);
 
-	size_read = trace_report(session->fd, session->repipe);
+	size_read = trace_report(fd, session->repipe);
 
 	padding = ALIGN(size_read, sizeof(u64)) - size_read;
 
-	if (read(session->fd, buf, padding) < 0)
+	if (read(fd, buf, padding) < 0)
 		die("reading input file");
 	if (session->repipe) {
 		int retw = write(STDOUT_FILENO, buf, padding);
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 3d5a742..63b56ba 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -69,10 +69,10 @@ struct perf_header {
 
 struct perf_evlist;
 
-int perf_session__read_header(struct perf_session *session, int fd);
+int perf_session__read_header(struct perf_session *session);
 int perf_session__write_header(struct perf_session *session,
 			       struct perf_evlist *evlist,
-			       int fd, bool at_exit);
+			       bool at_exit);
 int perf_header__write_pipe(int fd);
 
 int perf_header__push_event(u64 id, const char *name);
@@ -111,7 +111,7 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
 int perf_event__process_event_type(union perf_event *event,
 				   struct perf_session *session);
 
-int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
+int perf_event__synthesize_tracing_data(struct perf_evlist *evlist,
 					perf_event__handler_t process,
 					struct perf_session *session);
 int perf_event__process_tracing_data(union perf_event *event,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 85c1e6b7..219ce32 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -13,69 +13,26 @@
 #include "sort.h"
 #include "util.h"
 #include "cpumap.h"
+#include "data.h"
 
-static int perf_session__open(struct perf_session *self, bool force)
+static int perf_session__open(struct perf_session *self)
 {
-	struct stat input_stat;
-
-	if (!strcmp(self->filename, "-")) {
-		self->fd_pipe = true;
-		self->fd = STDIN_FILENO;
-
-		if (perf_session__read_header(self, self->fd) < 0)
-			pr_err("incompatible file format");
-
-		return 0;
-	}
-
-	self->fd = open(self->filename, O_RDONLY);
-	if (self->fd < 0) {
-		int err = errno;
-
-		pr_err("failed to open %s: %s", self->filename, strerror(err));
-		if (err == ENOENT && !strcmp(self->filename, "perf.data"))
-			pr_err("  (try 'perf record' first)");
-		pr_err("\n");
-		return -errno;
-	}
-
-	if (fstat(self->fd, &input_stat) < 0)
-		goto out_close;
-
-	if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
-		pr_err("file %s not owned by current user or root\n",
-		       self->filename);
-		goto out_close;
-	}
-
-	if (!input_stat.st_size) {
-		pr_info("zero-sized file (%s), nothing to do!\n",
-			self->filename);
-		goto out_close;
-	}
-
-	if (perf_session__read_header(self, self->fd) < 0) {
+	if (perf_session__read_header(self) < 0) {
 		pr_err("incompatible file format");
-		goto out_close;
+		return -1;
 	}
 
 	if (!perf_evlist__valid_sample_type(self->evlist)) {
 		pr_err("non matching sample_type");
-		goto out_close;
+		return -1;
 	}
 
 	if (!perf_evlist__valid_sample_id_all(self->evlist)) {
 		pr_err("non matching sample_id_all");
-		goto out_close;
+		return -1;
 	}
 
-	self->size = input_stat.st_size;
 	return 0;
-
-out_close:
-	close(self->fd);
-	self->fd = -1;
-	return -1;
 }
 
 static void perf_session__id_header_size(struct perf_session *session)
@@ -128,17 +85,15 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
 	machines__destroy_guest_kernel_maps(&self->machines);
 }
 
-struct perf_session *perf_session__new(const char *filename, int mode,
-				       bool force, bool repipe,
-				       struct perf_event_ops *ops)
+struct perf_session *perf_session__new(const char *name, int mode, bool force,
+				       bool repipe, struct perf_event_ops *ops)
 {
-	size_t len = filename ? strlen(filename) + 1 : 0;
-	struct perf_session *self = zalloc(sizeof(*self) + len);
+	struct perf_session *self;
 
-	if (self == NULL)
-		goto out;
+	self = zalloc(sizeof(*self));
+	if (!self)
+		return NULL;
 
-	memcpy(self->filename, filename, len);
 	self->threads = RB_ROOT;
 	INIT_LIST_HEAD(&self->dead_threads);
 	self->last_match = NULL;
@@ -158,17 +113,20 @@ struct perf_session *perf_session__new(const char *filename, int mode,
 	INIT_LIST_HEAD(&self->ordered_samples.to_free);
 	machine__init(&self->host_machine, "", HOST_KERNEL_ID);
 
-	if (mode == O_RDONLY) {
-		if (perf_session__open(self, force) < 0)
-			goto out_delete;
+	if (perf_data__open(&self->data, name, mode, force))
+		goto out_delete_session;
+
+	if (perf_data__is_ro(&self->data)) {
+		if (perf_session__open(self) < 0)
+			goto out_close_data;
 		perf_session__update_sample_type(self);
-	} else if (mode == O_WRONLY) {
+	} else {
 		/*
 		 * In O_RDONLY mode this will be performed when reading the
 		 * kernel MMAP event, in perf_event__process_mmap().
 		 */
 		if (perf_session__create_kernel_maps(self) < 0)
-			goto out_delete;
+			goto out_close_data;
 	}
 
 	if (ops && ops->ordering_requires_timestamps &&
@@ -177,9 +135,12 @@ struct perf_session *perf_session__new(const char *filename, int mode,
 		ops->ordered_samples = false;
 	}
 
-out:
 	return self;
-out_delete:
+
+out_close_data:
+	perf_data__close(&self->data);
+
+out_delete_session:
 	perf_session__delete(self);
 	return NULL;
 }
@@ -213,7 +174,7 @@ void perf_session__delete(struct perf_session *self)
 	perf_session__delete_dead_threads(self);
 	perf_session__delete_threads(self);
 	machine__exit(&self->host_machine);
-	close(self->fd);
+	perf_data__close(&self->data);
 	free(self);
 }
 
@@ -814,6 +775,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
 static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
 					    struct perf_event_ops *ops, u64 file_offset)
 {
+	int fd = perf_session__fd(session);
+
 	dump_event(session, event, file_offset, NULL);
 
 	/* These events are processed right away */
@@ -824,7 +787,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
 		return ops->event_type(event, session);
 	case PERF_RECORD_HEADER_TRACING_DATA:
 		/* setup for reading amidst mmap */
-		lseek(session->fd, file_offset, SEEK_SET);
+		lseek(fd, file_offset, SEEK_SET);
 		return ops->tracing_data(event, session);
 	case PERF_RECORD_HEADER_BUILD_ID:
 		return ops->build_id(event, session);
@@ -942,12 +905,13 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
 	u64 head;
 	int err;
 	void *p;
+	int fd = perf_session__fd(self);
 
 	perf_event_ops__fill_defaults(ops);
 
 	head = 0;
 more:
-	err = readn(self->fd, &event, sizeof(struct perf_event_header));
+	err = readn(fd, &event, sizeof(struct perf_event_header));
 	if (err <= 0) {
 		if (err == 0)
 			goto done;
@@ -967,7 +931,7 @@ more:
 	p += sizeof(struct perf_event_header);
 
 	if (size - sizeof(struct perf_event_header)) {
-		err = readn(self->fd, p, size - sizeof(struct perf_event_header));
+		err = readn(fd, p, size - sizeof(struct perf_event_header));
 		if (err <= 0) {
 			if (err == 0) {
 				pr_err("unexpected end of event stream\n");
@@ -1042,6 +1006,7 @@ int __perf_session__process_events(struct perf_session *session,
 	char *buf, *mmaps[8];
 	union perf_event *event;
 	uint32_t size;
+	int fd = perf_session__fd(session);
 
 	perf_event_ops__fill_defaults(ops);
 
@@ -1070,7 +1035,7 @@ int __perf_session__process_events(struct perf_session *session,
 		mmap_flags = MAP_PRIVATE;
 	}
 remap:
-	buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
+	buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd,
 		   file_offset);
 	if (buf == MAP_FAILED) {
 		pr_err("failed to mmap file\n");
@@ -1142,11 +1107,12 @@ int perf_session__process_events(struct perf_session *self,
 	if (perf_session__register_idle_thread(self) == NULL)
 		return -ENOMEM;
 
-	if (!self->fd_pipe)
+	if (!perf_session__is_pipe(self))
 		err = __perf_session__process_events(self,
-						     self->header.data_offset,
-						     self->header.data_size,
-						     self->size, ops);
+					     self->header.data_offset,
+					     self->header.data_size,
+					     perf_data__size(&self->data),
+					     ops);
 	else
 		err = __perf_session__process_pipe_events(self, ops);
 
@@ -1354,11 +1320,12 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
 {
 	struct stat st;
 	int ret;
+	int fd = perf_session__fd(session);
 
 	if (session == NULL || fp == NULL)
 		return;
 
-	ret = fstat(session->fd, &st);
+	ret = fstat(fd, &st);
 	if (ret == -1)
 		return;
 
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index a81d666..cbc37f3 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -6,6 +6,7 @@
 #include "header.h"
 #include "symbol.h"
 #include "thread.h"
+#include "data.h"
 #include <linux/rbtree.h>
 #include "../../../include/linux/perf_event.h"
 
@@ -28,7 +29,7 @@ struct ordered_samples {
 
 struct perf_session {
 	struct perf_header	header;
-	unsigned long		size;
+	struct perf_data	data;
 	unsigned long		mmap_window;
 	struct rb_root		threads;
 	struct list_head	dead_threads;
@@ -45,8 +46,6 @@ struct perf_session {
 	struct hists		hists;
 	u64			sample_type;
 	int			sample_size;
-	int			fd;
-	bool			fd_pipe;
 	bool			repipe;
 	bool			sample_id_all;
 	u16			id_hdr_size;
@@ -54,7 +53,6 @@ struct perf_session {
 	char			*cwd;
 	struct ordered_samples	ordered_samples;
 	struct callchain_cursor	callchain_cursor;
-	char			filename[0];
 };
 
 struct perf_evsel;
@@ -88,9 +86,8 @@ struct perf_event_ops {
 	bool		ordering_requires_timestamps;
 };
 
-struct perf_session *perf_session__new(const char *filename, int mode,
-				       bool force, bool repipe,
-				       struct perf_event_ops *ops);
+struct perf_session *perf_session__new(const char *name, int mode, bool force,
+				       bool repipe, struct perf_event_ops *ops);
 void perf_session__delete(struct perf_session *self);
 
 void perf_event_header__bswap(struct perf_event_header *self);
@@ -179,4 +176,19 @@ int perf_session__cpu_bitmap(struct perf_session *session,
 			     const char *cpu_list, unsigned long *cpu_bitmap);
 
 void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
+
+static inline bool perf_session__is_new(struct perf_session *self)
+{
+	return perf_data__is_new(&self->data);
+}
+
+static inline int perf_session__fd(struct perf_session *self)
+{
+	return perf_data__fd(&self->data);
+}
+
+static inline int perf_session__is_pipe(struct perf_session *self)
+{
+	return perf_data__is_pipe(&self->data);
+}
 #endif /* __PERF_SESSION_H */
-- 
1.7.6.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCHv2 5/5] perf tool: Putting mmap support to perf_data object
  2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
                     ` (3 preceding siblings ...)
  2011-11-20  2:03   ` [PATCHv2 4/5] perf tool: Introducing perf_data object Jiri Olsa
@ 2011-11-20  2:03   ` Jiri Olsa
  4 siblings, 0 replies; 19+ messages in thread
From: Jiri Olsa @ 2011-11-20  2:03 UTC (permalink / raw)
  To: acme, a.p.zijlstra, mingo, paulus; +Cc: linux-kernel, Jiri Olsa

Adding event memory maps management under the perf_data
object. The objective is to have this functionality
centralized and dont mix this functionality into event
list.

New function 'perf_data__mmap' is added into perf_data. It prepares
allocates/prepares both perf_mmap and pollfd structures, and does
the actuall mmap-ing.

Each perf_mmap now contains perf_data_file structure,
to have memory map connected directly with the storage.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
---
 tools/perf/builtin-record.c |   29 +++++--
 tools/perf/builtin-test.c   |   14 +++-
 tools/perf/builtin-top.c    |   26 ++++--
 tools/perf/util/data.c      |  107 ++++++++++++++++++++++++
 tools/perf/util/data.h      |   15 ++++
 tools/perf/util/evlist.c    |  188 ++-----------------------------------------
 tools/perf/util/evlist.h    |   10 +--
 tools/perf/util/evsel.h     |    4 +-
 tools/perf/util/mmap.h      |    3 +
 tools/perf/util/python.c    |   23 ++++--
 tools/perf/util/session.h   |    6 ++
 11 files changed, 205 insertions(+), 220 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8765ae0..a6cb29f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -318,8 +318,9 @@ try_again:
 		exit(-1);
 	}
 
-	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
-		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
+	if (perf_evlist__init_ids(evlist))
+		die("failed to init sample IDs %d (%s)\n",
+		    errno, strerror(errno));
 
 	if (perf_session__is_new(session))
 		session->evlist = evlist;
@@ -402,18 +403,18 @@ static struct perf_event_header finished_round_event = {
 	.type = PERF_RECORD_FINISHED_ROUND,
 };
 
-static void mmap_read(struct perf_mmap *m __used, void *buf, unsigned long size)
+static void mmap_read(struct perf_mmap *m, void *buf, unsigned long size)
 {
-	int fd = perf_session__fd(session);
+	int fd = perf_data__fd_file(m->file);
 	write_output(fd, buf, size);
 }
 
-static int mmap_read_all(void)
+static int mmap_read_all(struct perf_data *data)
 {
 	int i, ret = 0;
 
-	for (i = 0; i < evsel_list->nr_mmaps; i++) {
-		struct perf_mmap *m = &evsel_list->mmap[i];
+	for (i = 0; i < data->nr_mmaps; i++) {
+		struct perf_mmap *m = &data->mmaps[i];
 		ret += perf_mmap__process(m, mmap_read);
 	}
 
@@ -540,6 +541,13 @@ static int __cmd_record(int argc, const char **argv)
 
 	open_counters(evsel_list);
 
+	if (perf_data__mmap(perf_session__data(session),
+			    evsel_list, mmap_pages, false) < 0) {
+		pr_err("Failed to mmap with %d (%s)\n",
+		       errno, strerror(errno));
+		goto out_delete_session;
+	}
+
 	/*
 	 * perf_session__delete(session) will be called at atexit_header()
 	 */
@@ -642,10 +650,13 @@ static int __cmd_record(int argc, const char **argv)
 		close(go_pipe[1]);
 
 	for (;;) {
-		if (!mmap_read_all()) {
+		struct perf_data *data = perf_session__data(session);
+
+		if (!mmap_read_all(data)) {
+
 			if (done)
 				break;
-			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
+			err = poll(data->fds, data->nr_fds, -1);
 			waking++;
 		}
 
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 831d1ba..eafeb67 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -12,6 +12,7 @@
 #include "util/parse-events.h"
 #include "util/symbol.h"
 #include "util/thread_map.h"
+#include "util/data.h"
 #include "../../include/linux/hw_breakpoint.h"
 
 static long page_size;
@@ -476,6 +477,9 @@ static int test__basic_mmap(void)
 		     expected_nr_events[nsyscalls], i, j;
 	struct perf_evsel *evsels[nsyscalls], *evsel;
 	int sample_size = __perf_evsel__sample_size(attr.sample_type);
+	struct perf_data data;
+
+	PERF_DATA__NONE(data);
 
 	for (i = 0; i < nsyscalls; ++i) {
 		char name[64];
@@ -539,7 +543,11 @@ static int test__basic_mmap(void)
 		}
 	}
 
-	if (perf_evlist__mmap(evlist, 128, true) < 0) {
+	err = perf_evlist__init_ids(evlist);
+	if (err)
+		goto out_close_fd;
+
+	if (perf_data__mmap(&data, evlist, 128, true)) {
 		pr_debug("failed to mmap events: %d (%s)\n", errno,
 			 strerror(errno));
 		goto out_close_fd;
@@ -551,7 +559,7 @@ static int test__basic_mmap(void)
 			++foo;
 		}
 
-	while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
+	while ((event = perf_data__mmap_read(&data, 0)) != NULL) {
 		struct perf_sample sample;
 
 		if (event->header.type != PERF_RECORD_SAMPLE) {
@@ -587,7 +595,7 @@ static int test__basic_mmap(void)
 
 	err = 0;
 out_munmap:
-	perf_evlist__munmap(evlist);
+	perf_data__close(&data);
 out_close_fd:
 	for (i = 0; i < nsyscalls; ++i)
 		perf_evsel__close_fd(evsels[i], 1, threads->nr);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index bc3a21b..1d42473 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -804,14 +804,15 @@ static void perf_event__process_sample(const union perf_event *event,
 	return;
 }
 
-static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
+static void perf_session__mmap_read_idx(struct perf_session *self,
+					struct perf_data *data, int idx)
 {
 	struct perf_sample sample;
 	struct perf_evsel *evsel;
 	union perf_event *event;
 	int ret;
 
-	while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
+	while ((event = perf_data__mmap_read(data, idx)) != NULL) {
 		ret = perf_session__parse_sample(self, event, &sample);
 		if (ret) {
 			pr_err("Can't parse sample, err = %d\n", ret);
@@ -833,13 +834,14 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
 
 static void perf_session__mmap_read(struct perf_session *self)
 {
+	struct perf_data *data = perf_session__data(self);
 	int i;
 
-	for (i = 0; i < top.evlist->nr_mmaps; i++)
-		perf_session__mmap_read_idx(self, i);
+	for (i = 0; i < data->nr_mmaps; i++)
+		perf_session__mmap_read_idx(self, data, i);
 }
 
-static void start_counters(struct perf_evlist *evlist)
+static void start_counters(struct perf_data *data, struct perf_evlist *evlist)
 {
 	struct perf_evsel *counter, *first;
 
@@ -920,7 +922,10 @@ try_again:
 		}
 	}
 
-	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
+	if (perf_evlist__init_ids(evlist))
+		goto out_err;
+
+	if (perf_data__mmap(data, evlist, mmap_pages, false) < 0) {
 		ui__warning("Failed to mmap with %d (%s)\n",
 			    errno, strerror(errno));
 		goto out_err;
@@ -952,6 +957,7 @@ static int setup_sample_type(void)
 
 static int __cmd_top(void)
 {
+	struct perf_data *data;
 	pthread_t thread;
 	int ret;
 
@@ -970,12 +976,14 @@ static int __cmd_top(void)
 	else
 		perf_event__synthesize_threads(perf_event__process, top.session);
 
-	start_counters(top.evlist);
+	data = perf_session__data(top.session);
+
+	start_counters(data, top.evlist);
 	top.session->evlist = top.evlist;
 	perf_session__update_sample_type(top.session);
 
 	/* Wait for a minimal set of events before starting the snapshot */
-	poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
+	poll(data->fds, data->nr_fds, 100);
 
 	perf_session__mmap_read(top.session);
 
@@ -1001,7 +1009,7 @@ static int __cmd_top(void)
 		perf_session__mmap_read(top.session);
 
 		if (hits == top.samples)
-			ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
+			ret = poll(data->fds, data->nr_fds, 100);
 	}
 
 out_delete:
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 52ee306..6864c2c 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -197,3 +197,110 @@ void perf_data__close(struct perf_data *data)
 	list_for_each_entry(file, &data->files, list)
 		data_file__close(data, file);
 }
+
+static int data_file__ass_mmap(struct perf_data *data, struct perf_mmap *m)
+{
+	/*
+	 * Currently we have only one file to store data to.
+	 * In future we might open a file here and redirected perf_mmap
+	 * data into it.
+	 */
+	m->file = &data->header;
+	return 0;
+}
+
+static struct perf_mmap *data_mmap__new(struct perf_data *data)
+{
+	struct perf_mmap *m, *mmaps;
+	int nr = data->nr_mmaps;
+
+	mmaps = realloc(data->mmaps, (nr + 1) * sizeof(struct perf_mmap));
+	if (!mmaps)
+		return NULL;
+
+	data->nr_mmaps++;
+	data->mmaps = mmaps;
+
+	m = &data->mmaps[nr];
+	memset(m, 0, sizeof(*m));
+	return m;
+}
+
+static int data_fd__new(struct perf_data *data, int fd)
+{
+	struct pollfd *p, *fds;
+	int nr = data->nr_fds;
+
+	fds = realloc(data->fds, (nr + 1) * sizeof(struct perf_mmap));
+	if (!fds)
+		return -ENOMEM;
+
+	fcntl(fd, F_SETFL, O_NONBLOCK);
+
+	data->nr_fds++;
+	data->fds = fds;
+
+	p = &data->fds[nr];
+	p->fd = fd;
+	p->events = POLLIN;
+	return 0;
+}
+
+int perf_data__mmap(struct perf_data *data,
+		    struct perf_evlist *evlist,
+		    int pages, bool overwrite)
+{
+	bool cpu_bond = evlist->cpus->map[0] != -1;
+	struct perf_evsel *evsel;
+	int cpu, thread, ret, i;
+
+	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+		struct perf_mmap *m = NULL;
+
+		for (thread = 0; thread < evlist->threads->nr; thread++) {
+			list_for_each_entry(evsel, &evlist->entries, node) {
+				int fd = PERF_EVSEL_FD(evsel, cpu, thread);
+
+				if (!m || !(cpu_bond && thread)) {
+					m = data_mmap__new(data);
+					if (!m) {
+						ret = -ENOMEM;
+						goto cleanup;
+					}
+
+					ret = -EINVAL;
+					if (perf_mmap__open(m, fd, overwrite,
+							    pages))
+						goto cleanup;
+
+					if (data_file__ass_mmap(data, m))
+						goto cleanup;
+
+				} else {
+					ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
+					      m->fd);
+				}
+
+				if (data_fd__new(data, fd))
+					return -ENOMEM;
+			}
+		}
+	}
+
+	return 0;
+
+ cleanup:
+	for (i = 0; i < data->nr_mmaps; i++) {
+		struct perf_mmap *m = &data->mmaps[i];
+		perf_mmap__close(m);
+	}
+
+	return ret;
+}
+
+union perf_event *perf_data__mmap_read(struct perf_data *data, int idx)
+{
+	struct perf_mmap *md;
+	md = &data->mmaps[idx];
+	return perf_mmap__read(md);
+}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 3103f7a..ca2e6a5 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -28,12 +28,22 @@ struct perf_data {
 	int  mode;
 	bool force;
 
+	struct perf_mmap *mmaps;
+	struct pollfd *fds;
+	int nr_mmaps;
+	int nr_fds;
+
 	struct list_head files;
 };
 
 int perf_data__open(struct perf_data *data, const char *name,
 		    int mode, bool force);
 void perf_data__close(struct perf_data *data);
+int perf_data__mmap(struct perf_data *data,
+		    struct perf_evlist *evlist,
+		    int pages, bool overwrite);
+union perf_event *perf_data__mmap_read(struct perf_data *data,
+				       int idx);
 
 #define PERF_DATA__NONE(__data) \
 	perf_data__open(&__data, NULL, PERF_DATA_NONE, false);
@@ -62,4 +72,9 @@ static inline int perf_data__fd(struct perf_data *data)
 {
 	return data->header.fd;
 }
+
+static inline int perf_data__fd_file(struct perf_data_file *file)
+{
+	return file->fd;
+}
 #endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 7dd64dd..21e3e0f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,7 +19,6 @@
 #include <linux/bitops.h>
 #include <linux/hash.h>
 
-#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
 
 void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
@@ -56,18 +55,9 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
 	evlist->nr_entries = 0;
 }
 
-void perf_evlist__exit(struct perf_evlist *evlist)
-{
-	free(evlist->mmap);
-	free(evlist->pollfd);
-	evlist->mmap = NULL;
-	evlist->pollfd = NULL;
-}
-
 void perf_evlist__delete(struct perf_evlist *evlist)
 {
 	perf_evlist__purge(evlist);
-	perf_evlist__exit(evlist);
 	free(evlist);
 }
 
@@ -109,7 +99,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)
 	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
 		list_for_each_entry(pos, &evlist->entries, node) {
 			for (thread = 0; thread < evlist->threads->nr; thread++)
-				ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
+				ioctl(PERF_EVSEL_FD(pos, cpu, thread),
+				      PERF_EVENT_IOC_DISABLE);
 		}
 	}
 }
@@ -122,26 +113,12 @@ void perf_evlist__enable(struct perf_evlist *evlist)
 	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
 		list_for_each_entry(pos, &evlist->entries, node) {
 			for (thread = 0; thread < evlist->threads->nr; thread++)
-				ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
+				ioctl(PERF_EVSEL_FD(pos, cpu, thread),
+				      PERF_EVENT_IOC_ENABLE);
 		}
 	}
 }
 
-int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
-{
-	int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
-	evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
-	return evlist->pollfd != NULL ? 0 : -ENOMEM;
-}
-
-void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
-{
-	fcntl(fd, F_SETFL, O_NONBLOCK);
-	evlist->pollfd[evlist->nr_fds].fd = fd;
-	evlist->pollfd[evlist->nr_fds].events = POLLIN;
-	evlist->nr_fds++;
-}
-
 static void perf_evlist__id_hash(struct perf_evlist *evlist,
 				 struct perf_evsel *evsel,
 				 int cpu, int thread, u64 id)
@@ -201,119 +178,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
 	return NULL;
 }
 
-union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
-{
-	struct perf_mmap *md;
-	md = &evlist->mmap[idx];
-	return perf_mmap__read(md);
-}
-
-void perf_evlist__munmap(struct perf_evlist *evlist)
-{
-	int i;
-
-	for (i = 0; i < evlist->nr_mmaps; i++) {
-		struct perf_mmap *m = &evlist->mmap[i];
-		if (m->base != NULL)
-			perf_mmap__close(m);
-	}
-
-	free(evlist->mmap);
-	evlist->mmap = NULL;
-}
-
-int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
-{
-	evlist->nr_mmaps = evlist->cpus->nr;
-	if (evlist->cpus->map[0] == -1)
-		evlist->nr_mmaps = evlist->threads->nr;
-	evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
-	return evlist->mmap != NULL ? 0 : -ENOMEM;
-}
-
-static int __perf_evlist__mmap(struct perf_evlist *evlist,
-			       int idx, int fd)
-{
-	struct perf_mmap *m = &evlist->mmap[idx];
-
-	if (perf_mmap__open(m, fd, evlist->overwrite, evlist->pages))
-		return -1;
-
-	perf_evlist__add_pollfd(evlist, fd);
-	return 0;
-}
-
-static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-	int cpu, thread;
-
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		int output = -1;
-
-		for (thread = 0; thread < evlist->threads->nr; thread++) {
-			list_for_each_entry(evsel, &evlist->entries, node) {
-				int fd = FD(evsel, cpu, thread);
-
-				if (output == -1) {
-					output = fd;
-					if (__perf_evlist__mmap(evlist, cpu,
-								output) < 0)
-						goto out_unmap;
-				} else {
-					if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
-						goto out_unmap;
-				}
-			}
-		}
-	}
-
-	return 0;
-
-out_unmap:
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		struct perf_mmap *m = &evlist->mmap[cpu];
-		if (m->base != NULL)
-			perf_mmap__close(m);
-	}
-	return -1;
-}
-
-static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist)
-{
-	struct perf_evsel *evsel;
-	int thread;
-
-	for (thread = 0; thread < evlist->threads->nr; thread++) {
-		int output = -1;
-
-		list_for_each_entry(evsel, &evlist->entries, node) {
-			int fd = FD(evsel, 0, thread);
-
-			if (output == -1) {
-				output = fd;
-				if (__perf_evlist__mmap(evlist, thread,
-							output) < 0)
-					goto out_unmap;
-			} else {
-				if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
-					goto out_unmap;
-			}
-		}
-	}
-
-	return 0;
-
-out_unmap:
-	for (thread = 0; thread < evlist->threads->nr; thread++) {
-		struct perf_mmap *m = &evlist->mmap[thread];
-		if (m->base != NULL)
-			perf_mmap__close(m);
-	}
-	return -1;
-}
-
-static int perf_evlist__init_ids(struct perf_evlist *evlist)
+int perf_evlist__init_ids(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel;
 	struct thread_map *threads = evlist->threads;
@@ -330,7 +195,7 @@ static int perf_evlist__init_ids(struct perf_evlist *evlist)
 
 		for (cpu = 0; cpu < cpus->nr; cpu++)
 			for (thread = 0; thread < threads->nr; thread++) {
-				int fd = FD(evsel, cpu, thread);
+				int fd = PERF_EVSEL_FD(evsel, cpu, thread);
 				if (perf_evlist__id_add_fd(evlist, evsel,
 							   cpu, thread, fd))
 					return -EINVAL;
@@ -340,45 +205,6 @@ static int perf_evlist__init_ids(struct perf_evlist *evlist)
 	return 0;
 }
 
-/** perf_evlist__mmap - Create per cpu maps to receive events
- *
- * @evlist - list of events
- * @pages - map length in pages
- * @overwrite - overwrite older events?
- *
- * If overwrite is false the user needs to signal event consuption using:
- *
- *	struct perf_mmap *m = &evlist->mmap[cpu];
- *	unsigned int head = perf_mmap__read_head(m);
- *
- *	perf_mmap__write_tail(m, head)
- *
- * Using perf_evlist__read_on_cpu does this automatically.
- */
-int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
-{
-	const struct cpu_map *cpus = evlist->cpus;
-	int ret;
-
-	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
-		return -ENOMEM;
-
-	if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
-		return -ENOMEM;
-
-	evlist->overwrite = overwrite;
-	evlist->pages = pages;
-
-	ret = perf_evlist__init_ids(evlist);
-	if (ret)
-		return ret;
-
-	if (cpus->map[0] == -1)
-		return perf_evlist__mmap_per_thread(evlist);
-
-	return perf_evlist__mmap_per_cpu(evlist);
-}
-
 int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
 			     pid_t target_tid, const char *cpu_list)
 {
@@ -427,7 +253,7 @@ int perf_evlist__set_filters(struct perf_evlist *evlist)
 			continue;
 		for (cpu = 0; cpu < cpus->nr; cpu++) {
 			for (thread = 0; thread < threads->nr; thread++) {
-				fd = FD(evsel, cpu, thread);
+				fd = PERF_EVSEL_FD(evsel, cpu, thread);
 				err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
 				if (err)
 					return err;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 3784273..9de0d39 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -16,13 +16,6 @@ struct perf_evlist {
 	struct list_head entries;
 	struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
 	int		 nr_entries;
-	int		 nr_fds;
-	int		 nr_mmaps;
-	int		 pages;
-	bool		 overwrite;
-	union perf_event event_copy;
-	struct perf_mmap *mmap;
-	struct pollfd	 *pollfd;
 	struct thread_map *threads;
 	struct cpu_map	  *cpus;
 	struct perf_evsel *selected;
@@ -48,8 +41,6 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
 
 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
 
-union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
-
 int perf_evlist__open(struct perf_evlist *evlist, bool group);
 
 int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
@@ -74,6 +65,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
 			     pid_t target_tid, const char *cpu_list);
 void perf_evlist__delete_maps(struct perf_evlist *evlist);
 int perf_evlist__set_filters(struct perf_evlist *evlist);
+int perf_evlist__init_ids(struct perf_evlist *evlist);
 
 u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b1d15e6..14e1864 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -8,7 +8,9 @@
 #include "xyarray.h"
 #include "cgroup.h"
 #include "hist.h"
- 
+
+#define PERF_EVSEL_FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
+
 struct perf_counts_values {
 	union {
 		struct {
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
index 24cf88f..1152135 100644
--- a/tools/perf/util/mmap.h
+++ b/tools/perf/util/mmap.h
@@ -4,6 +4,7 @@
 #include <sys/mman.h>
 #include "event.h"
 #include "../perf.h"
+#include "data.h"
 
 struct perf_mmap {
 	void  *base;
@@ -12,6 +13,8 @@ struct perf_mmap {
 	int   len;
 	int   fd;
 	bool  owrt;
+
+	struct perf_data_file *file;
 };
 
 typedef void (*perf_mmap_process_t)(struct perf_mmap *m,
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9dd47a4..263a7b5 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -7,6 +7,7 @@
 #include "event.h"
 #include "cpumap.h"
 #include "thread_map.h"
+#include "data.h"
 
 /* Define PyVarObject_HEAD_INIT for python 2.5 */
 #ifndef PyVarObject_HEAD_INIT
@@ -598,7 +599,6 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
 
 static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
 {
-	perf_evsel__exit(&pevsel->evsel);
 	pevsel->ob_type->tp_free((PyObject*)pevsel);
 }
 
@@ -668,6 +668,7 @@ static int pyrf_evsel__setup_types(void)
 struct pyrf_evlist {
 	PyObject_HEAD
 
+	struct perf_data data;
 	struct perf_evlist evlist;
 };
 
@@ -684,12 +685,12 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
 	threads = ((struct pyrf_thread_map *)pthreads)->threads;
 	cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
 	perf_evlist__init(&pevlist->evlist, cpus, threads);
+	PERF_DATA__NONE(pevlist->data);
 	return 0;
 }
 
 static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
 {
-	perf_evlist__exit(&pevlist->evlist);
 	pevlist->ob_type->tp_free((PyObject*)pevlist);
 }
 
@@ -697,6 +698,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 				   PyObject *args, PyObject *kwargs)
 {
 	struct perf_evlist *evlist = &pevlist->evlist;
+	struct perf_data *data = &pevlist->data;
 	static char *kwlist[] = { "pages", "overwrite", NULL };
 	int pages = 128, overwrite = false;
 
@@ -704,7 +706,12 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 					 &pages, &overwrite))
 		return NULL;
 
-	if (perf_evlist__mmap(evlist, pages, overwrite) < 0) {
+	if (perf_evlist__init_ids(evlist)) {
+		PyErr_SetFromErrno(PyExc_OSError);
+		return NULL;
+	}
+
+	if (perf_data__mmap(data, evlist, pages, overwrite) < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
 	}
@@ -716,14 +723,14 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
 				   PyObject *args, PyObject *kwargs)
 {
-	struct perf_evlist *evlist = &pevlist->evlist;
+	struct perf_data *data = &pevlist->data;
 	static char *kwlist[] = { "timeout", NULL };
 	int timeout = -1, n;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
 		return NULL;
 
-	n = poll(evlist->pollfd, evlist->nr_fds, timeout);
+	n = poll(data->fds, data->nr_fds, timeout);
 	if (n < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
@@ -735,13 +742,13 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
 static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
 					 PyObject *args __used, PyObject *kwargs __used)
 {
-	struct perf_evlist *evlist = &pevlist->evlist;
+	struct perf_data *data = &pevlist->data;
         PyObject *list = PyList_New(0);
 	int i;
 
-	for (i = 0; i < evlist->nr_fds; ++i) {
+	for (i = 0; i < data->nr_fds; ++i) {
 		PyObject *file;
-		FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
+		FILE *fp = fdopen(data->fds[i].fd, "r");
 
 		if (fp == NULL)
 			goto free_list;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index cbc37f3..1c5e0e8 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -191,4 +191,10 @@ static inline int perf_session__is_pipe(struct perf_session *self)
 {
 	return perf_data__is_pipe(&self->data);
 }
+
+static inline struct perf_data *perf_session__data(struct perf_session *self)
+{
+	return &self->data;
+}
+
 #endif /* __PERF_SESSION_H */
-- 
1.7.6.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2011-11-20  1:04 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-18 13:46 [RFC,PATCH] perf tool: Refactoring IO data files code Jiri Olsa
2011-11-18 13:46 ` [PATCH 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
2011-11-18 14:24   ` Arnaldo Carvalho de Melo
2011-11-18 13:46 ` [PATCH 2/5] perf tool: Initialize events IDs in a single function Jiri Olsa
2011-11-18 14:22   ` Arnaldo Carvalho de Melo
2011-11-20  1:36     ` Jiri Olsa
2011-11-20  1:03       ` Arnaldo Carvalho de Melo
2011-11-18 13:46 ` [PATCH 3/5] perf tool: Introducing perf_mmap object Jiri Olsa
2011-11-18 14:37   ` Arnaldo Carvalho de Melo
2011-11-20  1:39     ` Jiri Olsa
2011-11-18 13:46 ` [PATCH 4/5] perf tool: Introducing perf_data object Jiri Olsa
2011-11-18 13:46 ` [PATCH 5/5] perf tool: Putting mmap support to " Jiri Olsa
2011-11-18 14:14 ` [RFC,PATCH] perf tool: Refactoring IO data files code Arnaldo Carvalho de Melo
2011-11-20  2:03 ` [RFC,PATCHv2] " Jiri Olsa
2011-11-20  2:03   ` [PATCHv2 1/5] perf tool: Fix session host_nachine retrieval Jiri Olsa
2011-11-20  2:03   ` [PATCHv2 2/5] perf tool: Initialize events IDs in a single function Jiri Olsa
2011-11-20  2:03   ` [PATCHv2 3/5] perf tool: Introducing perf_mmap object Jiri Olsa
2011-11-20  2:03   ` [PATCHv2 4/5] perf tool: Introducing perf_data object Jiri Olsa
2011-11-20  2:03   ` [PATCHv2 5/5] perf tool: Putting mmap support to " Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox