All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] perf timechart io mode
@ 2014-06-10 15:04 Stanislav Fomichev
  2014-06-10 15:04 ` [PATCH 1/3] perf timechart: implement IO mode Stanislav Fomichev
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-10 15:04 UTC (permalink / raw)
  To: acme, namhyung, artagnon, jolsa; +Cc: linux-kernel

This patchset adds IO mode: instead of process time we record io syscalls
and then draw timechart of writes/reads/tx/rx/polls.

v2:
  - separated start_time fix into distinct commit
  - separated --io-xyz options into distinct commit
  - fixed 'error' shadowing
  - initialized variables in declaration when possible
  - removed assert usage
  - fprintf -> pr_err
  - removed wrongly placed __maybe_unused

Stanislav Fomichev (3):
  perf timechart: implement IO mode
  perf timechart: conditionally update start_time on fork
  perf timechart: add more options to IO mode

 tools/perf/Documentation/perf-timechart.txt |  34 +-
 tools/perf/builtin-timechart.c              | 654 +++++++++++++++++++++++++++-
 tools/perf/util/svghelper.c                 |  98 ++++-
 tools/perf/util/svghelper.h                 |   6 +-
 4 files changed, 767 insertions(+), 25 deletions(-)

-- 
1.8.3.2


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

* [PATCH 1/3] perf timechart: implement IO mode
  2014-06-10 15:04 [PATCH v2 0/3] perf timechart io mode Stanislav Fomichev
@ 2014-06-10 15:04 ` Stanislav Fomichev
  2014-06-12  0:59   ` Namhyung Kim
  2014-06-10 15:04 ` [PATCH 2/3] perf timechart: conditionally update start_time on fork Stanislav Fomichev
  2014-06-10 15:04 ` [PATCH 3/3] perf timechart: add more options to IO mode Stanislav Fomichev
  2 siblings, 1 reply; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-10 15:04 UTC (permalink / raw)
  To: acme, namhyung, artagnon, jolsa; +Cc: linux-kernel

In IO mode timechart shows any disk/network activity.

Signed-off-by: Stanislav Fomichev <stfomichev@yandex-team.ru>
---
 tools/perf/Documentation/perf-timechart.txt |  25 +-
 tools/perf/builtin-timechart.c              | 607 +++++++++++++++++++++++++++-
 tools/perf/util/svghelper.c                 |  98 ++++-
 tools/perf/util/svghelper.h                 |   6 +-
 4 files changed, 712 insertions(+), 24 deletions(-)

diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 5e0f986dff38..ec6b46c7bca0 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -15,10 +15,20 @@ DESCRIPTION
 There are two variants of perf timechart:
 
   'perf timechart record <command>' to record the system level events
-  of an arbitrary workload.
+  of an arbitrary workload. By default timechart records only scheduler
+  and CPU events (task switches, running times, CPU power states, etc),
+  but it's possible to record IO (disk, network) activity using -I argument.
 
   'perf timechart' to turn a trace into a Scalable Vector Graphics file,
-  that can be viewed with popular SVG viewers such as 'Inkscape'.
+  that can be viewed with popular SVG viewers such as 'Inkscape'. Depending
+  on the events in the perf.data file, timechart will contain scheduler/cpu
+  events or IO events.
+
+  In IO mode, every bar has two charts: upper and lower.
+  Upper bar shows incoming events (disk reads, ingress network packets).
+  Lower bar shows outgoing events (disk writes, egress network packets).
+  There are also poll bars which show how much time application spent
+  in poll/epoll/select syscalls.
 
 TIMECHART OPTIONS
 -----------------
@@ -63,6 +73,9 @@ RECORD OPTIONS
 -T::
 --tasks-only::
         Record only tasks-related events
+-I::
+--io-only::
+        Record only io-related events
 -g::
 --callchain::
         Do call-graph (stack chain/backtrace) recording
@@ -87,6 +100,14 @@ Record system-wide timechart:
 
   $ perf timechart --highlight gcc
 
+Record system-wide IO events:
+
+  $ perf timechart record -I
+
+  then generate timechart:
+
+  $ perf timechart
+
 SEE ALSO
 --------
 linkperf:perf-record[1]
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 74db2568b867..447ef0a77f85 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -60,10 +60,14 @@ struct timechart {
 				tasks_only,
 				with_backtrace,
 				topology;
+	/* IO related settings */
+	u64			io_events;
+	bool			io_only;
 };
 
 struct per_pidcomm;
 struct cpu_sample;
+struct io_sample;
 
 /*
  * Datastructure layout:
@@ -84,6 +88,7 @@ struct per_pid {
 	u64		start_time;
 	u64		end_time;
 	u64		total_time;
+	u64		total_bytes;
 	int		display;
 
 	struct per_pidcomm *all;
@@ -97,6 +102,8 @@ struct per_pidcomm {
 	u64		start_time;
 	u64		end_time;
 	u64		total_time;
+	u64		max_bytes;
+	u64		total_bytes;
 
 	int		Y;
 	int		display;
@@ -107,6 +114,7 @@ struct per_pidcomm {
 	char		*comm;
 
 	struct cpu_sample *samples;
+	struct io_sample  *io_samples;
 };
 
 struct sample_wrapper {
@@ -131,6 +139,27 @@ struct cpu_sample {
 	const char *backtrace;
 };
 
+enum {
+	IOTYPE_READ,
+	IOTYPE_WRITE,
+	IOTYPE_SYNC,
+	IOTYPE_TX,
+	IOTYPE_RX,
+	IOTYPE_POLL,
+};
+
+struct io_sample {
+	struct io_sample *next;
+
+	u64 start_time;
+	u64 end_time;
+	u64 bytes;
+	int type;
+	int fd;
+	int err;
+	int merges;
+};
+
 #define CSTATE 1
 #define PSTATE 2
 
@@ -682,6 +711,212 @@ static void end_sample_processing(struct timechart *tchart)
 	}
 }
 
+static int pid_begin_io_sample(struct timechart *tchart, int pid, int type,
+			       u64 start, int fd)
+{
+	struct per_pid *p = find_create_pid(tchart, pid);
+	struct per_pidcomm *c = p->current;
+	struct io_sample *sample;
+	struct io_sample *prev;
+
+	if (!c) {
+		c = zalloc(sizeof(*c));
+		if (!c)
+			return -ENOMEM;
+		p->current = c;
+		c->next = p->all;
+		p->all = c;
+	}
+
+	prev = c->io_samples;
+
+	if (prev && prev->start_time && !prev->end_time) {
+		pr_err("Invalid previous event (duplicate start)!\n");
+		return -1;
+	}
+
+	sample = zalloc(sizeof(*sample));
+	if (!sample)
+		return -ENOMEM;
+	sample->start_time = start;
+	sample->type = type;
+	sample->fd = fd;
+	sample->next = c->io_samples;
+	c->io_samples = sample;
+
+	if (c->start_time == 0 || c->start_time > start)
+		c->start_time = start;
+
+	return 0;
+}
+
+static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
+			     u64 end, long ret)
+{
+	struct per_pid *p = find_create_pid(tchart, pid);
+	struct per_pidcomm *c = p->current;
+	struct io_sample *sample;
+
+	if (!c) {
+		pr_err("Invalid pidcomm!\n");
+		return -1;
+	}
+
+	sample = c->io_samples;
+
+	if (!sample) /* skip partially captured events */
+		return 0;
+
+	if (c->io_samples->end_time) {
+		pr_err("Invalid previous event (non-zero)!\n");
+		return -1;
+	}
+
+	if (c->io_samples->type != type) {
+		pr_err("Invalid previous event (type)!\n");
+		return -1;
+	}
+
+	sample->end_time = end;
+
+	if (ret < 0) {
+		sample->err = ret;
+	} else if (type == IOTYPE_READ || type == IOTYPE_WRITE ||
+		   type == IOTYPE_TX || type == IOTYPE_RX) {
+
+		if ((u64)ret > c->max_bytes)
+			c->max_bytes = ret;
+
+		c->total_bytes += ret;
+		p->total_bytes += ret;
+		sample->bytes = ret;
+	}
+
+	tchart->io_events++;
+
+	return 0;
+}
+
+static int
+process_enter_read(struct timechart *tchart,
+		   struct perf_evsel *evsel,
+		   struct perf_sample *sample)
+{
+	long fd = perf_evsel__intval(evsel, sample, "fd");
+	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ,
+				   sample->time, fd);
+}
+
+static int
+process_exit_read(struct timechart *tchart,
+		  struct perf_evsel *evsel,
+		  struct perf_sample *sample)
+{
+	long ret = perf_evsel__intval(evsel, sample, "ret");
+	return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ,
+				 sample->time, ret);
+}
+
+static int
+process_enter_write(struct timechart *tchart,
+		    struct perf_evsel *evsel,
+		    struct perf_sample *sample)
+{
+	long fd = perf_evsel__intval(evsel, sample, "fd");
+	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE,
+				   sample->time, fd);
+}
+
+static int
+process_exit_write(struct timechart *tchart,
+		   struct perf_evsel *evsel,
+		   struct perf_sample *sample)
+{
+	long ret = perf_evsel__intval(evsel, sample, "ret");
+	return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE,
+				 sample->time, ret);
+}
+
+static int
+process_enter_sync(struct timechart *tchart,
+		   struct perf_evsel *evsel,
+		   struct perf_sample *sample)
+{
+	long fd = perf_evsel__intval(evsel, sample, "fd");
+	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC,
+				   sample->time, fd);
+}
+
+static int
+process_exit_sync(struct timechart *tchart,
+		  struct perf_evsel *evsel,
+		  struct perf_sample *sample)
+{
+	long ret = perf_evsel__intval(evsel, sample, "ret");
+	return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC,
+				 sample->time, ret);
+}
+
+static int
+process_enter_tx(struct timechart *tchart,
+		 struct perf_evsel *evsel,
+		 struct perf_sample *sample)
+{
+	long fd = perf_evsel__intval(evsel, sample, "fd");
+	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX,
+				   sample->time, fd);
+}
+
+static int
+process_exit_tx(struct timechart *tchart,
+		struct perf_evsel *evsel,
+		struct perf_sample *sample)
+{
+	long ret = perf_evsel__intval(evsel, sample, "ret");
+	return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX,
+				 sample->time, ret);
+}
+
+static int
+process_enter_rx(struct timechart *tchart,
+		 struct perf_evsel *evsel,
+		 struct perf_sample *sample)
+{
+	long fd = perf_evsel__intval(evsel, sample, "fd");
+	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX,
+				   sample->time, fd);
+}
+
+static int
+process_exit_rx(struct timechart *tchart,
+		struct perf_evsel *evsel,
+		struct perf_sample *sample)
+{
+	long ret = perf_evsel__intval(evsel, sample, "ret");
+	return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX,
+				 sample->time, ret);
+}
+
+static int
+process_enter_poll(struct timechart *tchart,
+		   struct perf_evsel *evsel,
+		   struct perf_sample *sample)
+{
+	long fd = perf_evsel__intval(evsel, sample, "fd");
+	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL,
+				   sample->time, fd);
+}
+
+static int
+process_exit_poll(struct timechart *tchart,
+		  struct perf_evsel *evsel,
+		  struct perf_sample *sample)
+{
+	long ret = perf_evsel__intval(evsel, sample, "ret");
+	return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL,
+				 sample->time, ret);
+}
+
 /*
  * Sort the pid datastructure
  */
@@ -852,6 +1087,117 @@ static void draw_cpu_usage(struct timechart *tchart)
 	}
 }
 
+static void draw_io_bars(struct timechart *tchart)
+{
+	const char *suf;
+	double bytes;
+	char comm[256];
+	struct per_pid *p;
+	struct per_pidcomm *c;
+	struct io_sample *sample;
+	int Y = 1;
+
+	p = tchart->all_data;
+	while (p) {
+		c = p->all;
+		while (c) {
+			if (!c->display) {
+				c->Y = 0;
+				c = c->next;
+				continue;
+			}
+
+			svg_box(Y, c->start_time, c->end_time, "process3");
+			sample = c->io_samples;
+			for (sample = c->io_samples; sample; sample = sample->next) {
+				double h = (double)sample->bytes / c->max_bytes;
+
+				if (sample->err)
+					h = 1;
+
+				if (sample->type == IOTYPE_SYNC)
+					svg_fbox(Y,
+						sample->start_time,
+						sample->end_time,
+						1,
+						sample->err ? "error" : "sync",
+						sample->fd,
+						sample->err,
+						sample->merges);
+				else if (sample->type == IOTYPE_POLL)
+					svg_fbox(Y,
+						sample->start_time,
+						sample->end_time,
+						1,
+						sample->err ? "error" : "poll",
+						sample->fd,
+						sample->err,
+						sample->merges);
+				else if (sample->type == IOTYPE_READ)
+					svg_ubox(Y,
+						sample->start_time,
+						sample->end_time,
+						h,
+						sample->err ? "error" : "disk",
+						sample->fd,
+						sample->err,
+						sample->merges);
+				else if (sample->type == IOTYPE_WRITE)
+					svg_lbox(Y,
+						sample->start_time,
+						sample->end_time,
+						h,
+						sample->err ? "error" : "disk",
+						sample->fd,
+						sample->err,
+						sample->merges);
+				else if (sample->type == IOTYPE_RX)
+					svg_ubox(Y,
+						sample->start_time,
+						sample->end_time,
+						h,
+						sample->err ? "error" : "net",
+						sample->fd,
+						sample->err,
+						sample->merges);
+				else if (sample->type == IOTYPE_TX)
+					svg_lbox(Y,
+						sample->start_time,
+						sample->end_time,
+						h,
+						sample->err ? "error" : "net",
+						sample->fd,
+						sample->err,
+						sample->merges);
+			}
+
+			suf = "";
+			bytes = c->total_bytes;
+			if (bytes > 1024) {
+				bytes = bytes / 1024;
+				suf = "K";
+			}
+			if (bytes > 1024) {
+				bytes = bytes / 1024;
+				suf = "M";
+			}
+			if (bytes > 1024) {
+				bytes = bytes / 1024;
+				suf = "G";
+			}
+
+
+			sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf);
+			svg_text(Y, c->start_time, comm);
+
+			c->Y = Y;
+			Y++;
+			c = c->next;
+		}
+		p = p->next;
+	}
+}
+
 static void draw_process_bars(struct timechart *tchart)
 {
 	struct per_pid *p;
@@ -987,9 +1333,6 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
 	struct per_pidcomm *c;
 	int count = 0;
 
-	if (process_filter)
-		return determine_display_tasks_filtered(tchart);
-
 	p = tchart->all_data;
 	while (p) {
 		p->display = 0;
@@ -1025,15 +1368,46 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
 	return count;
 }
 
+static int determine_display_io_tasks(struct timechart *timechart, u64 threshold)
+{
+	struct per_pid *p;
+	struct per_pidcomm *c;
+	int count = 0;
+
+	p = timechart->all_data;
+	while (p) {
+		/* no exit marker, task kept running to the end */
+		if (p->end_time == 0)
+			p->end_time = timechart->last_time;
+
+		c = p->all;
 
+		while (c) {
+			c->display = 0;
 
+			if (c->total_bytes >= threshold) {
+				c->display = 1;
+				count++;
+			}
+
+			if (c->end_time == 0)
+				c->end_time = timechart->last_time;
+
+			c = c->next;
+		}
+		p = p->next;
+	}
+	return count;
+}
+
+#define BYTES_THRESH (1 * 1024 * 1024)
 #define TIME_THRESH 10000000
 
 static void write_svg_file(struct timechart *tchart, const char *filename)
 {
 	u64 i;
 	int count;
-	int thresh = TIME_THRESH;
+	int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH;
 
 	if (tchart->power_only)
 		tchart->proc_num = 0;
@@ -1041,28 +1415,43 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
 	/* We'd like to show at least proc_num tasks;
 	 * be less picky if we have fewer */
 	do {
-		count = determine_display_tasks(tchart, thresh);
+		if (process_filter)
+			count = determine_display_tasks_filtered(tchart);
+		else if (tchart->io_events)
+			count = determine_display_io_tasks(tchart, thresh);
+		else
+			count = determine_display_tasks(tchart, thresh);
 		thresh /= 10;
 	} while (!process_filter && thresh && count < tchart->proc_num);
 
 	if (!tchart->proc_num)
 		count = 0;
 
-	open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
+	if (tchart->io_events) {
+		open_svg(filename, 0, count, tchart->first_time, tchart->last_time);
+
+		svg_time_grid(0.5);
+		svg_io_legenda();
 
-	svg_time_grid();
-	svg_legenda();
+		draw_io_bars(tchart);
+	} else {
+		open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
 
-	for (i = 0; i < tchart->numcpus; i++)
-		svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
+		svg_time_grid(0);
 
-	draw_cpu_usage(tchart);
-	if (tchart->proc_num)
-		draw_process_bars(tchart);
-	if (!tchart->tasks_only)
-		draw_c_p_states(tchart);
-	if (tchart->proc_num)
-		draw_wakeups(tchart);
+		svg_legenda();
+
+		for (i = 0; i < tchart->numcpus; i++)
+			svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
+
+		draw_cpu_usage(tchart);
+		if (tchart->proc_num)
+			draw_process_bars(tchart);
+		if (!tchart->tasks_only)
+			draw_c_p_states(tchart);
+		if (tchart->proc_num)
+			draw_wakeups(tchart);
+	}
 
 	svg_close();
 }
@@ -1110,6 +1499,56 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
 		{ "power:power_end",		process_sample_power_end },
 		{ "power:power_frequency",	process_sample_power_frequency },
 #endif
+
+		{ "syscalls:sys_enter_read",		process_enter_read },
+		{ "syscalls:sys_enter_pread64",		process_enter_read },
+		{ "syscalls:sys_enter_readv",		process_enter_read },
+		{ "syscalls:sys_enter_preadv",		process_enter_read },
+		{ "syscalls:sys_enter_write",		process_enter_write },
+		{ "syscalls:sys_enter_pwrite64",	process_enter_write },
+		{ "syscalls:sys_enter_writev",		process_enter_write },
+		{ "syscalls:sys_enter_pwritev",		process_enter_write },
+		{ "syscalls:sys_enter_sync",		process_enter_sync },
+		{ "syscalls:sys_enter_sync_file_range",	process_enter_sync },
+		{ "syscalls:sys_enter_fsync",		process_enter_sync },
+		{ "syscalls:sys_enter_msync",		process_enter_sync },
+		{ "syscalls:sys_enter_recvfrom",	process_enter_rx },
+		{ "syscalls:sys_enter_recvmmsg",	process_enter_rx },
+		{ "syscalls:sys_enter_recvmsg",		process_enter_rx },
+		{ "syscalls:sys_enter_sendto",		process_enter_tx },
+		{ "syscalls:sys_enter_sendmsg",		process_enter_tx },
+		{ "syscalls:sys_enter_sendmmsg",	process_enter_tx },
+		{ "syscalls:sys_enter_epoll_pwait",	process_enter_poll },
+		{ "syscalls:sys_enter_epoll_wait",	process_enter_poll },
+		{ "syscalls:sys_enter_poll",		process_enter_poll },
+		{ "syscalls:sys_enter_ppoll",		process_enter_poll },
+		{ "syscalls:sys_enter_pselect6",	process_enter_poll },
+		{ "syscalls:sys_enter_select",		process_enter_poll },
+
+		{ "syscalls:sys_exit_read",		process_exit_read },
+		{ "syscalls:sys_exit_pread64",		process_exit_read },
+		{ "syscalls:sys_exit_readv",		process_exit_read },
+		{ "syscalls:sys_exit_preadv",		process_exit_read },
+		{ "syscalls:sys_exit_write",		process_exit_write },
+		{ "syscalls:sys_exit_pwrite64",		process_exit_write },
+		{ "syscalls:sys_exit_writev",		process_exit_write },
+		{ "syscalls:sys_exit_pwritev",		process_exit_write },
+		{ "syscalls:sys_exit_sync",		process_exit_sync },
+		{ "syscalls:sys_exit_sync_file_range",	process_exit_sync },
+		{ "syscalls:sys_exit_fsync",		process_exit_sync },
+		{ "syscalls:sys_exit_msync",		process_exit_sync },
+		{ "syscalls:sys_exit_recvfrom",		process_exit_rx },
+		{ "syscalls:sys_exit_recvmmsg",		process_exit_rx },
+		{ "syscalls:sys_exit_recvmsg",		process_exit_rx },
+		{ "syscalls:sys_exit_sendto",		process_exit_tx },
+		{ "syscalls:sys_exit_sendmsg",		process_exit_tx },
+		{ "syscalls:sys_exit_sendmmsg",		process_exit_tx },
+		{ "syscalls:sys_exit_epoll_pwait",	process_exit_poll },
+		{ "syscalls:sys_exit_epoll_wait",	process_exit_poll },
+		{ "syscalls:sys_exit_poll",		process_exit_poll },
+		{ "syscalls:sys_exit_ppoll",		process_exit_poll },
+		{ "syscalls:sys_exit_pselect6",		process_exit_poll },
+		{ "syscalls:sys_exit_select",		process_exit_poll },
 	};
 	struct perf_data_file file = {
 		.path = input_name,
@@ -1154,6 +1593,133 @@ out_delete:
 	return ret;
 }
 
+static int timechart__io_record(int argc, const char **argv)
+{
+	unsigned int rec_argc, i;
+	const char **rec_argv;
+	const char **p;
+	char *filter = NULL;
+
+	const char * const common_args[] = {
+		"record", "-a", "-R", "-c", "1",
+	};
+	unsigned int common_args_nr = ARRAY_SIZE(common_args);
+
+	const char * const disk_events[] = {
+		"syscalls:sys_enter_read",
+		"syscalls:sys_enter_pread64",
+		"syscalls:sys_enter_readv",
+		"syscalls:sys_enter_preadv",
+		"syscalls:sys_enter_write",
+		"syscalls:sys_enter_pwrite64",
+		"syscalls:sys_enter_writev",
+		"syscalls:sys_enter_pwritev",
+		"syscalls:sys_enter_sync",
+		"syscalls:sys_enter_sync_file_range",
+		"syscalls:sys_enter_fsync",
+		"syscalls:sys_enter_msync",
+
+		"syscalls:sys_exit_read",
+		"syscalls:sys_exit_pread64",
+		"syscalls:sys_exit_readv",
+		"syscalls:sys_exit_preadv",
+		"syscalls:sys_exit_write",
+		"syscalls:sys_exit_pwrite64",
+		"syscalls:sys_exit_writev",
+		"syscalls:sys_exit_pwritev",
+		"syscalls:sys_exit_sync",
+		"syscalls:sys_exit_sync_file_range",
+		"syscalls:sys_exit_fsync",
+		"syscalls:sys_exit_msync",
+	};
+	unsigned int disk_events_nr = ARRAY_SIZE(disk_events);
+
+	const char * const net_events[] = {
+		"syscalls:sys_enter_recvfrom",
+		"syscalls:sys_enter_recvmmsg",
+		"syscalls:sys_enter_recvmsg",
+		"syscalls:sys_enter_sendto",
+		"syscalls:sys_enter_sendmsg",
+		"syscalls:sys_enter_sendmmsg",
+
+		"syscalls:sys_exit_recvfrom",
+		"syscalls:sys_exit_recvmmsg",
+		"syscalls:sys_exit_recvmsg",
+		"syscalls:sys_exit_sendto",
+		"syscalls:sys_exit_sendmsg",
+		"syscalls:sys_exit_sendmmsg",
+	};
+	unsigned int net_events_nr = ARRAY_SIZE(net_events);
+
+	const char * const poll_events[] = {
+		"syscalls:sys_enter_epoll_pwait",
+		"syscalls:sys_enter_epoll_wait",
+		"syscalls:sys_enter_poll",
+		"syscalls:sys_enter_ppoll",
+		"syscalls:sys_enter_pselect6",
+		"syscalls:sys_enter_select",
+
+		"syscalls:sys_exit_epoll_pwait",
+		"syscalls:sys_exit_epoll_wait",
+		"syscalls:sys_exit_poll",
+		"syscalls:sys_exit_ppoll",
+		"syscalls:sys_exit_pselect6",
+		"syscalls:sys_exit_select",
+	};
+	unsigned int poll_events_nr = ARRAY_SIZE(poll_events);
+
+	rec_argc = common_args_nr +
+		disk_events_nr * 4 +
+		net_events_nr * 4 +
+		poll_events_nr * 4 +
+		argc;
+	rec_argv = calloc(rec_argc + 1, sizeof(char *));
+
+	if (rec_argv == NULL)
+		return -ENOMEM;
+
+	if (asprintf(&filter, "common_pid != %d", getpid()) < 0)
+		return -ENOMEM;
+
+	p = rec_argv;
+	for (i = 0; i < common_args_nr; i++)
+		*p++ = strdup(common_args[i]);
+
+	for (i = 0; i < disk_events_nr; i++) {
+		if (!is_valid_tracepoint(disk_events[i]))
+			continue;
+
+		*p++ = "-e";
+		*p++ = strdup(disk_events[i]);
+		*p++ = "--filter";
+		*p++ = filter;
+	}
+	for (i = 0; i < net_events_nr; i++) {
+		if (!is_valid_tracepoint(net_events[i]))
+			continue;
+
+		*p++ = "-e";
+		*p++ = strdup(net_events[i]);
+		*p++ = "--filter";
+		*p++ = filter;
+	}
+	for (i = 0; i < poll_events_nr; i++) {
+		if (!is_valid_tracepoint(poll_events[i]))
+			continue;
+
+		*p++ = "-e";
+		*p++ = strdup(poll_events[i]);
+		*p++ = "--filter";
+		*p++ = filter;
+	}
+
+	for (i = 0; i < (unsigned int)argc; i++)
+		*p++ = argv[i];
+
+	return cmd_record(rec_argc, rec_argv, NULL);
+}
+
+
 static int timechart__record(struct timechart *tchart, int argc, const char **argv)
 {
 	unsigned int rec_argc, i, j;
@@ -1314,6 +1880,8 @@ int cmd_timechart(int argc, const char **argv,
 	OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
 	OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
 		    "output processes data only"),
+	OPT_BOOLEAN('I', "io-only", &tchart.io_only,
+		    "record only IO data"),
 	OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
 	OPT_END()
 	};
@@ -1340,7 +1908,10 @@ int cmd_timechart(int argc, const char **argv,
 			return -1;
 		}
 
-		return timechart__record(&tchart, argc, argv);
+		if (tchart.io_only)
+			return timechart__io_record(argc, argv);
+		else
+			return timechart__record(&tchart, argc, argv);
 	} else if (argc)
 		usage_with_options(timechart_usage, timechart_options);
 
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 6a0a13d07a28..e1b1231ea342 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -30,6 +30,7 @@ static u64 turbo_frequency, max_freq;
 
 #define SLOT_MULT 30.0
 #define SLOT_HEIGHT 25.0
+#define SLOT_HALF (SLOT_HEIGHT / 2)
 
 int svg_page_width = 1000;
 u64 svg_highlight;
@@ -114,8 +115,14 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
 	fprintf(svgfile, "      rect          { stroke-width: 1; }\n");
 	fprintf(svgfile, "      rect.process  { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1;   stroke:rgb(  0,  0,  0); } \n");
 	fprintf(svgfile, "      rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
+	fprintf(svgfile, "      rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
 	fprintf(svgfile, "      rect.sample   { fill:rgb(  0,  0,255); fill-opacity:0.8; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
 	fprintf(svgfile, "      rect.sample_hi{ fill:rgb(255,128,  0); fill-opacity:0.8; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
+	fprintf(svgfile, "      rect.error    { fill:rgb(255,  0,  0); fill-opacity:0.5; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
+	fprintf(svgfile, "      rect.net      { fill:rgb(  0,128,  0); fill-opacity:0.5; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
+	fprintf(svgfile, "      rect.disk     { fill:rgb(  0,  0,255); fill-opacity:0.5; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
+	fprintf(svgfile, "      rect.sync     { fill:rgb(128,128,  0); fill-opacity:0.5; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
+	fprintf(svgfile, "      rect.poll     { fill:rgb(  0,128,128); fill-opacity:0.2; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
 	fprintf(svgfile, "      rect.blocked  { fill:rgb(255,  0,  0); fill-opacity:0.5; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
 	fprintf(svgfile, "      rect.waiting  { fill:rgb(224,214,  0); fill-opacity:0.8; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
 	fprintf(svgfile, "      rect.WAITING  { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
@@ -132,6 +139,75 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
 	fprintf(svgfile, "    ]]>\n   </style>\n</defs>\n");
 }
 
+static double normalize_height(double height)
+{
+	if (height < 0.25)
+		return 0.25;
+	else if (height < 0.50)
+		return 0.50;
+	else if (height < 0.75)
+		return 0.75;
+	else
+		return 0.100;
+}
+
+void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
+{
+	double w = time2pixels(end) - time2pixels(start);
+	height = normalize_height(height);
+
+	if (!svgfile)
+		return;
+
+	fprintf(svgfile, "<g>\n");
+	fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
+	fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
+		time2pixels(start),
+		w,
+		Yslot * SLOT_MULT,
+		SLOT_HALF * height,
+		type);
+	fprintf(svgfile, "</g>\n");
+}
+
+void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
+{
+	double w = time2pixels(end) - time2pixels(start);
+	height = normalize_height(height);
+
+	if (!svgfile)
+		return;
+
+	fprintf(svgfile, "<g>\n");
+	fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
+	fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
+		time2pixels(start),
+		w,
+		Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height,
+		SLOT_HALF * height,
+		type);
+	fprintf(svgfile, "</g>\n");
+}
+
+void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
+{
+	double w = time2pixels(end) - time2pixels(start);
+	height = normalize_height(height);
+
+	if (!svgfile)
+		return;
+
+	fprintf(svgfile, "<g>\n");
+	fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
+	fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
+		time2pixels(start),
+		w,
+		Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height,
+		SLOT_HEIGHT * height,
+		type);
+	fprintf(svgfile, "</g>\n");
+}
+
 void svg_box(int Yslot, u64 start, u64 end, const char *type)
 {
 	if (!svgfile)
@@ -543,6 +619,20 @@ static void svg_legenda_box(int X, const char *text, const char *style)
 		X + boxsize + 5, boxsize, 0.8 * boxsize, text);
 }
 
+void svg_io_legenda(void)
+{
+	if (!svgfile)
+		return;
+
+	fprintf(svgfile, "<g>\n");
+	svg_legenda_box(0,	"Disk", "disk");
+	svg_legenda_box(100,	"Network", "net");
+	svg_legenda_box(200,	"Sync", "sync");
+	svg_legenda_box(300,	"Poll", "poll");
+	svg_legenda_box(400,	"Error", "error");
+	fprintf(svgfile, "</g>\n");
+}
+
 void svg_legenda(void)
 {
 	if (!svgfile)
@@ -559,7 +649,7 @@ void svg_legenda(void)
 	fprintf(svgfile, "</g>\n");
 }
 
-void svg_time_grid(void)
+void svg_time_grid(double min_thickness)
 {
 	u64 i;
 
@@ -579,8 +669,10 @@ void svg_time_grid(void)
 			color = 128;
 		}
 
-		fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
-			time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
+		if (thickness >= min_thickness)
+			fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
+				time2pixels(i), SLOT_MULT/2, time2pixels(i),
+				total_height, color, color, color, thickness);
 
 		i += 10000000;
 	}
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index e3aff5332e30..9292a5291445 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -4,6 +4,9 @@
 #include <linux/types.h>
 
 extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
+extern void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
+extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
+extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
 extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
 extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
 extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
@@ -16,7 +19,8 @@ extern void svg_cstate(int cpu, u64 start, u64 end, int type);
 extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
 
 
-extern void svg_time_grid(void);
+extern void svg_time_grid(double min_thickness);
+extern void svg_io_legenda(void);
 extern void svg_legenda(void);
 extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
 extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
-- 
1.8.3.2


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

* [PATCH 2/3] perf timechart: conditionally update start_time on fork
  2014-06-10 15:04 [PATCH v2 0/3] perf timechart io mode Stanislav Fomichev
  2014-06-10 15:04 ` [PATCH 1/3] perf timechart: implement IO mode Stanislav Fomichev
@ 2014-06-10 15:04 ` Stanislav Fomichev
  2014-06-10 15:04 ` [PATCH 3/3] perf timechart: add more options to IO mode Stanislav Fomichev
  2 siblings, 0 replies; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-10 15:04 UTC (permalink / raw)
  To: acme, namhyung, artagnon, jolsa; +Cc: linux-kernel

We don't need to overwrite current task start_time on fork, so update it
only if it's zero.

Signed-off-by: Stanislav Fomichev <stfomichev@yandex-team.ru>
---
 tools/perf/builtin-timechart.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 447ef0a77f85..6941da0cb302 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -242,7 +242,7 @@ static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
 		pid_set_comm(tchart, pid, pp->current->comm);
 
 	p->start_time = timestamp;
-	if (p->current) {
+	if (p->current && !p->current->start_time) {
 		p->current->start_time = timestamp;
 		p->current->state_since = timestamp;
 	}
-- 
1.8.3.2


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

* [PATCH 3/3] perf timechart: add more options to IO mode
  2014-06-10 15:04 [PATCH v2 0/3] perf timechart io mode Stanislav Fomichev
  2014-06-10 15:04 ` [PATCH 1/3] perf timechart: implement IO mode Stanislav Fomichev
  2014-06-10 15:04 ` [PATCH 2/3] perf timechart: conditionally update start_time on fork Stanislav Fomichev
@ 2014-06-10 15:04 ` Stanislav Fomichev
  2014-06-12  1:03   ` Namhyung Kim
  2 siblings, 1 reply; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-10 15:04 UTC (permalink / raw)
  To: acme, namhyung, artagnon, jolsa; +Cc: linux-kernel

--io-skip-eagain - don't show EAGAIN errors
--io-min-time    - make small io bursts visible
--io-merge-dist  - merge adjacent events

Signed-off-by: Stanislav Fomichev <stfomichev@yandex-team.ru>
---
 tools/perf/Documentation/perf-timechart.txt |  9 ++++++
 tools/perf/builtin-timechart.c              | 49 +++++++++++++++++++++++++++--
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index ec6b46c7bca0..62c29656ad95 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -64,6 +64,15 @@ TIMECHART OPTIONS
 	duration or tasks with given name. If number is given it's interpreted
 	as number of nanoseconds. If non-numeric string is given it's
 	interpreted as task name.
+--io-skip-eagain::
+	Don't draw EAGAIN IO events.
+--io-min-time::
+	Draw small events as if they lasted min-time. Useful when you need
+	to see very small and fast IO. Default value is 1ms.
+--io-merge-dist::
+	Merge events that are merge-dist nanoseconds apart.
+	Reduces number of figures on the SVG and makes it more render-friendly.
+	Default value is 1us.
 
 RECORD OPTIONS
 --------------
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 6941da0cb302..c818b35e3290 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -62,7 +62,10 @@ struct timechart {
 				topology;
 	/* IO related settings */
 	u64			io_events;
-	bool			io_only;
+	bool			io_only,
+				skip_eagain;
+	u64			min_time,
+				merge_dist;
 };
 
 struct per_pidcomm;
@@ -755,7 +758,7 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
 {
 	struct per_pid *p = find_create_pid(tchart, pid);
 	struct per_pidcomm *c = p->current;
-	struct io_sample *sample;
+	struct io_sample *sample, *prev;
 
 	if (!c) {
 		pr_err("Invalid pidcomm!\n");
@@ -778,6 +781,18 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
 	}
 
 	sample->end_time = end;
+	prev = sample->next;
+
+	/* we want to be able to see small and fast transfers, so make them
+	 * at least min_time long, but don't overlap them */
+	if (sample->end_time - sample->start_time < tchart->min_time)
+		sample->end_time = sample->start_time + tchart->min_time;
+	if (prev && sample->start_time < prev->end_time) {
+		if (prev->err) /* try to make errors more visible */
+			sample->start_time = prev->end_time;
+		else
+			prev->end_time = sample->start_time;
+	}
 
 	if (ret < 0) {
 		sample->err = ret;
@@ -792,6 +807,24 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
 		sample->bytes = ret;
 	}
 
+	/* merge two requests to make svg smaller and render-friendly */
+	if (prev &&
+	    prev->type == sample->type &&
+	    prev->err == sample->err &&
+	    prev->fd == sample->fd &&
+	    prev->end_time + tchart->merge_dist >= sample->start_time) {
+
+		sample->bytes += prev->bytes;
+		sample->merges += prev->merges + 1;
+
+		sample->start_time = prev->start_time;
+		sample->next = prev->next;
+		free(prev);
+
+		if (!sample->err && sample->bytes > c->max_bytes)
+			c->max_bytes = sample->bytes;
+	}
+
 	tchart->io_events++;
 
 	return 0;
@@ -1112,6 +1145,10 @@ static void draw_io_bars(struct timechart *tchart)
 			for (sample = c->io_samples; sample; sample = sample->next) {
 				double h = (double)sample->bytes / c->max_bytes;
 
+				if (tchart->skip_eagain &&
+				    sample->err == -EAGAIN)
+					continue;
+
 				if (sample->err)
 					h = 1;
 
@@ -1848,6 +1885,8 @@ int cmd_timechart(int argc, const char **argv,
 			.ordered_samples = true,
 		},
 		.proc_num = 15,
+		.min_time = 1000000,
+		.merge_dist = 1000,
 	};
 	const char *output_name = "output.svg";
 	const struct option timechart_options[] = {
@@ -1869,6 +1908,12 @@ int cmd_timechart(int argc, const char **argv,
 		    "min. number of tasks to print"),
 	OPT_BOOLEAN('t', "topology", &tchart.topology,
 		    "sort CPUs according to topology"),
+	OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain,
+		    "skip EAGAIN errors"),
+	OPT_U64(0, "io-min-time", &tchart.min_time,
+		"all IO faster than min-time will visually appear longer"),
+	OPT_U64(0, "io-merge-dist", &tchart.merge_dist,
+		"merge events that are merge-dist us apart"),
 	OPT_END()
 	};
 	const char * const timechart_usage[] = {
-- 
1.8.3.2


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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-10 15:04 ` [PATCH 1/3] perf timechart: implement IO mode Stanislav Fomichev
@ 2014-06-12  0:59   ` Namhyung Kim
  2014-06-16  6:08     ` Stanislav Fomichev
  0 siblings, 1 reply; 15+ messages in thread
From: Namhyung Kim @ 2014-06-12  0:59 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: acme, artagnon, jolsa, linux-kernel

Hi Stanislav,

On Tue, 10 Jun 2014 19:04:52 +0400, Stanislav Fomichev wrote:
> In IO mode timechart shows any disk/network activity.

[SNIP]
> +Record system-wide IO events:
> +
> +  $ perf timechart record -I

I got a segfault here:

  Core was generated by `perf timechart record -I'.
  Program terminated with signal 11, Segmentation fault.
  #0  parse_options_step (ctx=ctx@entry=0x7fff6dcd8ef0, 
      options=options@entry=0x587de0, usagestr=usagestr@entry=0x588900)
      at util/parse-options.c:353
  353			if (*arg != '-' || !arg[1]) {
  Missing separate debuginfos, use: debuginfo-install glibc-2.17-9.fc20.x86_64 nss-softokn-freebl-3.15-1.fc20.x86_64 numactl-libs-2.0.7-6.fc17.x86_64
  (gdb) bt
  #0  parse_options_step (ctx=ctx@entry=0x7fff6dcd8ef0, options=options@entry=
      0x587de0, usagestr=usagestr@entry=0x588900) at util/parse-options.c:353
  #1  0x0000000000465cf4 in parse_options_subcommand (argc=argc@entry=197, 
      argv=argv@entry=0x13fd6d0, options=options@entry=0x587de0, 
      subcommands=subcommands@entry=0x0, usagestr=usagestr@entry=0x588900, 
      flags=flags@entry=2) at util/parse-options.c:462
  #2  0x0000000000465f54 in parse_options (argc=argc@entry=197, argv=argv@entry=
      0x13fd6d0, options=options@entry=0x587de0, usagestr=usagestr@entry=
      0x588900, flags=flags@entry=2) at util/parse-options.c:492
  #3  0x0000000000429ef8 in cmd_record (argc=argc@entry=197, argv=argv@entry=
      0x13fd6d0, prefix=prefix@entry=0x0) at builtin-record.c:894
  #4  0x0000000000434c59 in timechart__io_record (argv=0x7fff6dcdc270, argc=0)
      at builtin-timechart.c:1756
  #5  cmd_timechart (argc=0, argv=0x7fff6dcdc270, prefix=<optimized out>)
      at builtin-timechart.c:1957
  #6  0x000000000041b603 in run_builtin (p=p@entry=0x7fa230, argc=argc@entry=3, 
      argv=argv@entry=0x7fff6dcdc270) at perf.c:319
  #7  0x000000000041ae82 in handle_internal_command (argv=0x7fff6dcdc270, argc=3)
      at perf.c:376
  #8  run_argv (argv=0x7fff6dcdc060, argcp=0x7fff6dcdc06c) at perf.c:420
  #9  main (argc=3, argv=0x7fff6dcdc270) at perf.c:534


It was because, as I said, my system doesn't have pread64 syscall.. you
missed to decrease rec_argc when skipping invalid events. :)


> +
> +  then generate timechart:
> +
> +  $ perf timechart

After fixing the problem, I could run timechart and generate an
output.svg file.  But it doesn't show any IO activity.. process info was
there in grey boxes (rect.process3) but no color boxes.  I also tried
recording with ping and dd, but the result was same.  I suspect it's
because of some mis-calculation of position or size of the boxes.

Thanks,
Namhyung

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

* Re: [PATCH 3/3] perf timechart: add more options to IO mode
  2014-06-10 15:04 ` [PATCH 3/3] perf timechart: add more options to IO mode Stanislav Fomichev
@ 2014-06-12  1:03   ` Namhyung Kim
  2014-06-16  6:15     ` Stanislav Fomichev
  0 siblings, 1 reply; 15+ messages in thread
From: Namhyung Kim @ 2014-06-12  1:03 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: acme, artagnon, jolsa, linux-kernel

On Tue, 10 Jun 2014 19:04:54 +0400, Stanislav Fomichev wrote:
> --io-skip-eagain - don't show EAGAIN errors
> --io-min-time    - make small io bursts visible
> --io-merge-dist  - merge adjacent events
>
> Signed-off-by: Stanislav Fomichev <stfomichev@yandex-team.ru>
> ---
>  tools/perf/Documentation/perf-timechart.txt |  9 ++++++
>  tools/perf/builtin-timechart.c              | 49 +++++++++++++++++++++++++++--
>  2 files changed, 56 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
> index ec6b46c7bca0..62c29656ad95 100644
> --- a/tools/perf/Documentation/perf-timechart.txt
> +++ b/tools/perf/Documentation/perf-timechart.txt
> @@ -64,6 +64,15 @@ TIMECHART OPTIONS
>  	duration or tasks with given name. If number is given it's interpreted
>  	as number of nanoseconds. If non-numeric string is given it's
>  	interpreted as task name.
> +--io-skip-eagain::
> +	Don't draw EAGAIN IO events.
> +--io-min-time::
> +	Draw small events as if they lasted min-time. Useful when you need
> +	to see very small and fast IO. Default value is 1ms.

It's in nano-second unit, right?  If so, it's very unconvenient for user
to specify.  Maybe we could support to parse unit (s, ms, us, ...) also.


> +--io-merge-dist::
> +	Merge events that are merge-dist nanoseconds apart.
> +	Reduces number of figures on the SVG and makes it more render-friendly.
> +	Default value is 1us.

Ditto.

Thanks,
Namhyung

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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-12  0:59   ` Namhyung Kim
@ 2014-06-16  6:08     ` Stanislav Fomichev
  2014-06-18  0:31       ` Namhyung Kim
  0 siblings, 1 reply; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-16  6:08 UTC (permalink / raw)
  To: Namhyung Kim; +Cc: acme, artagnon, jolsa, linux-kernel

> It was because, as I said, my system doesn't have pread64 syscall.. you
> missed to decrease rec_argc when skipping invalid events. :)
Thanks, missed that!

> After fixing the problem, I could run timechart and generate an
> output.svg file.  But it doesn't show any IO activity.. process info was
> there in grey boxes (rect.process3) but no color boxes.  I also tried
> recording with ping and dd, but the result was same.  I suspect it's
> because of some mis-calculation of position or size of the boxes.
Did you try it with all patches applied? Because if you have really fast
IO you can miss it (unless you applied perf timechart: add more options
to IO mode).
Can you somehow share your perf.data with me? I'll check what's going
on.

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

* Re: [PATCH 3/3] perf timechart: add more options to IO mode
  2014-06-12  1:03   ` Namhyung Kim
@ 2014-06-16  6:15     ` Stanislav Fomichev
  2014-06-18  0:33       ` Namhyung Kim
  0 siblings, 1 reply; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-16  6:15 UTC (permalink / raw)
  To: Namhyung Kim; +Cc: acme, artagnon, jolsa, linux-kernel

> It's in nano-second unit, right?  If so, it's very unconvenient for user
> to specify.  Maybe we could support to parse unit (s, ms, us, ...) also.
Yes, it's nano-second. I didn't want to limit it to ms, because I
still want to be able to specify ns. I think it's a good idea to support
parsing units. Can I use OPT_CALLBACK or there is a better way to do that
(I couldn't find any similar conversions in perf)?

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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-16  6:08     ` Stanislav Fomichev
@ 2014-06-18  0:31       ` Namhyung Kim
  2014-06-18  9:00         ` Stanislav Fomichev
  0 siblings, 1 reply; 15+ messages in thread
From: Namhyung Kim @ 2014-06-18  0:31 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: acme, artagnon, jolsa, linux-kernel

Hi Stanislav,

On Mon, 16 Jun 2014 10:08:04 +0400, Stanislav Fomichev wrote:
>> It was because, as I said, my system doesn't have pread64 syscall.. you
>> missed to decrease rec_argc when skipping invalid events. :)
> Thanks, missed that!
>
>> After fixing the problem, I could run timechart and generate an
>> output.svg file.  But it doesn't show any IO activity.. process info was
>> there in grey boxes (rect.process3) but no color boxes.  I also tried
>> recording with ping and dd, but the result was same.  I suspect it's
>> because of some mis-calculation of position or size of the boxes.
> Did you try it with all patches applied? Because if you have really fast
> IO you can miss it (unless you applied perf timechart: add more options
> to IO mode).

I applied all your three patches.

  $ git log --oneline -3
  ddba809264f7 perf timechart: add more options to IO mode
  81cc94085210 perf timechart: conditionally update start_time on fork
  6aea1951c072 perf timechart: implement IO mode

  $ perf --version
  perf version 3.15.rc4.gddba809

  $ perf timechart record -I dd if=/dev/zero of=xxx bs=4k count=10k
  10240+0 records in
  10240+0 records out
  41943040 bytes (42 MB) copied, 0.0533579 s, 786 MB/s
  [ perf record: Woken up 16 times to write data ]
  [ perf record: Captured and wrote 4.209 MB perf.data (~183881 samples) ]

  $ perf timechart
  Written 0.1 seconds of trace to output.svg


> Can you somehow share your perf.data with me? I'll check what's going
> on.

https://git.kernel.org/cgit/linux/kernel/git/namhyung/linux-perf.git/plain/tools/perf/perf.timechart.data?h=perf/tmp

Thanks,
Namhyung

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

* Re: [PATCH 3/3] perf timechart: add more options to IO mode
  2014-06-16  6:15     ` Stanislav Fomichev
@ 2014-06-18  0:33       ` Namhyung Kim
  0 siblings, 0 replies; 15+ messages in thread
From: Namhyung Kim @ 2014-06-18  0:33 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: acme, artagnon, jolsa, linux-kernel

On Mon, 16 Jun 2014 10:15:22 +0400, Stanislav Fomichev wrote:
>> It's in nano-second unit, right?  If so, it's very unconvenient for user
>> to specify.  Maybe we could support to parse unit (s, ms, us, ...) also.
> Yes, it's nano-second. I didn't want to limit it to ms, because I
> still want to be able to specify ns. I think it's a good idea to support
> parsing units. Can I use OPT_CALLBACK or there is a better way to do that
> (I couldn't find any similar conversions in perf)?

Please use OPT_CALLBACK.

Thanks,
Namhyung

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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-18  0:31       ` Namhyung Kim
@ 2014-06-18  9:00         ` Stanislav Fomichev
  2014-06-19  0:30           ` Namhyung Kim
  0 siblings, 1 reply; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-18  9:00 UTC (permalink / raw)
  To: Namhyung Kim; +Cc: acme, artagnon, jolsa, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 583 bytes --]

> > Can you somehow share your perf.data with me? I'll check what's going
> > on.
> 
> https://git.kernel.org/cgit/linux/kernel/git/namhyung/linux-perf.git/plain/tools/perf/perf.timechart.data?h=perf/tmp
Hm, I don't see any issue with your data, I can see dd disk io and firefox polls.
I attached output.png, but it has some artifacts (I used imagemagick to convert
it); if I use Inkscape to view SVG, I don't see any artifacts (maybe
there is a problem, but another one).

Do you get different picture (empty process bars) if you run it on your side?
If you do, then I'm puzzled...

[-- Attachment #2: output.png --]
[-- Type: image/png, Size: 29193 bytes --]

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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-18  9:00         ` Stanislav Fomichev
@ 2014-06-19  0:30           ` Namhyung Kim
  2014-06-19  9:58             ` Stanislav Fomichev
  0 siblings, 1 reply; 15+ messages in thread
From: Namhyung Kim @ 2014-06-19  0:30 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: acme, artagnon, jolsa, linux-kernel

Hi Stanislav,

On Wed, 18 Jun 2014 13:00:34 +0400, Stanislav Fomichev wrote:
>> > Can you somehow share your perf.data with me? I'll check what's going
>> > on.
>> 
>> https://git.kernel.org/cgit/linux/kernel/git/namhyung/linux-perf.git/plain/tools/perf/perf.timechart.data?h=perf/tmp
> Hm, I don't see any issue with your data, I can see dd disk io and firefox polls.
> I attached output.png, but it has some artifacts (I used imagemagick to convert
> it); if I use Inkscape to view SVG, I don't see any artifacts (maybe
> there is a problem, but another one).
>
> Do you get different picture (empty process bars) if you run it on your side?
> If you do, then I'm puzzled...

Hmm.. it looks like an unrelated issue.  I can see the bars in inkscape,
but still see empty grey bars in firefox.

Thanks,
Namhyung

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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-19  0:30           ` Namhyung Kim
@ 2014-06-19  9:58             ` Stanislav Fomichev
  2014-06-19 12:18               ` Stanislav Fomichev
  0 siblings, 1 reply; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-19  9:58 UTC (permalink / raw)
  To: Namhyung Kim; +Cc: acme, artagnon, jolsa, linux-kernel

> Hmm.. it looks like an unrelated issue.  I can see the bars in inkscape,
> but still see empty grey bars in firefox.
I'll try to have a look; maybe I'm writing some non-standard svg
instructions which fail on (probably) standard-compliant firefox and
work on more robust inkscape.

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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-19  9:58             ` Stanislav Fomichev
@ 2014-06-19 12:18               ` Stanislav Fomichev
  2014-06-19 12:38                 ` Namhyung Kim
  0 siblings, 1 reply; 15+ messages in thread
From: Stanislav Fomichev @ 2014-06-19 12:18 UTC (permalink / raw)
  To: Namhyung Kim; +Cc: acme, artagnon, jolsa, linux-kernel

> > Hmm.. it looks like an unrelated issue.  I can see the bars in inkscape,
> > but still see empty grey bars in firefox.
> I'll try to have a look; maybe I'm writing some non-standard svg
> instructions which fail on (probably) standard-compliant firefox and
> work on more robust inkscape.

Found it: if I specify space before number in quotes, like in:
<rect ... height=" 3.1" ...>

Firefox doesn't want to render it, but if I remove the space before the
number (3.1), it works just fine.
I'll fix it and will resend the series with fixes.

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

* Re: [PATCH 1/3] perf timechart: implement IO mode
  2014-06-19 12:18               ` Stanislav Fomichev
@ 2014-06-19 12:38                 ` Namhyung Kim
  0 siblings, 0 replies; 15+ messages in thread
From: Namhyung Kim @ 2014-06-19 12:38 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: acme, artagnon, jolsa, linux-kernel

Hi Stanislav,

2014-06-19 (목), 16:18 +0400, Stanislav Fomichev:
> > > Hmm.. it looks like an unrelated issue.  I can see the bars in inkscape,
> > > but still see empty grey bars in firefox.
> > I'll try to have a look; maybe I'm writing some non-standard svg
> > instructions which fail on (probably) standard-compliant firefox and
> > work on more robust inkscape.
> 
> Found it: if I specify space before number in quotes, like in:
> <rect ... height=" 3.1" ...>
> 
> Firefox doesn't want to render it, but if I remove the space before the
> number (3.1), it works just fine.
> I'll fix it and will resend the series with fixes.

Nice!  I'll try to look at v3 tomorrow. :)

Thanks,
Namhyung



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

end of thread, other threads:[~2014-06-19 12:38 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-10 15:04 [PATCH v2 0/3] perf timechart io mode Stanislav Fomichev
2014-06-10 15:04 ` [PATCH 1/3] perf timechart: implement IO mode Stanislav Fomichev
2014-06-12  0:59   ` Namhyung Kim
2014-06-16  6:08     ` Stanislav Fomichev
2014-06-18  0:31       ` Namhyung Kim
2014-06-18  9:00         ` Stanislav Fomichev
2014-06-19  0:30           ` Namhyung Kim
2014-06-19  9:58             ` Stanislav Fomichev
2014-06-19 12:18               ` Stanislav Fomichev
2014-06-19 12:38                 ` Namhyung Kim
2014-06-10 15:04 ` [PATCH 2/3] perf timechart: conditionally update start_time on fork Stanislav Fomichev
2014-06-10 15:04 ` [PATCH 3/3] perf timechart: add more options to IO mode Stanislav Fomichev
2014-06-12  1:03   ` Namhyung Kim
2014-06-16  6:15     ` Stanislav Fomichev
2014-06-18  0:33       ` Namhyung Kim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.