Commit d243144a authored by Stanislav Fomichev's avatar Stanislav Fomichev Committed by Jiri Olsa

perf timechart: Add more options to IO mode

--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: default avatarStanislav Fomichev <stfomichev@yandex-team.ru>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/n/1404835423-23098-5-git-send-email-stfomichev@yandex-team.ruSigned-off-by: default avatarJiri Olsa <jolsa@kernel.org>
parent 962e310a
...@@ -64,6 +64,19 @@ TIMECHART OPTIONS ...@@ -64,6 +64,19 @@ TIMECHART OPTIONS
duration or tasks with given name. If number is given it's interpreted 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 as number of nanoseconds. If non-numeric string is given it's
interpreted as task name. interpreted as task name.
--io-skip-eagain::
Don't draw EAGAIN IO events.
--io-min-time=<nsecs>::
Draw small events as if they lasted min-time. Useful when you need
to see very small and fast IO. It's possible to specify ms or us
suffix to specify time in milliseconds or microseconds.
Default value is 1ms.
--io-merge-dist=<nsecs>::
Merge events that are merge-dist nanoseconds apart.
Reduces number of figures on the SVG and makes it more render-friendly.
It's possible to specify ms or us suffix to specify time in
milliseconds or microseconds.
Default value is 1us.
RECORD OPTIONS RECORD OPTIONS
-------------- --------------
......
...@@ -62,7 +62,10 @@ struct timechart { ...@@ -62,7 +62,10 @@ struct timechart {
topology; topology;
/* IO related settings */ /* IO related settings */
u64 io_events; u64 io_events;
bool io_only; bool io_only,
skip_eagain;
u64 min_time,
merge_dist;
}; };
struct per_pidcomm; struct per_pidcomm;
...@@ -761,7 +764,7 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, ...@@ -761,7 +764,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_pid *p = find_create_pid(tchart, pid);
struct per_pidcomm *c = p->current; struct per_pidcomm *c = p->current;
struct io_sample *sample; struct io_sample *sample, *prev;
if (!c) { if (!c) {
pr_warning("Invalid pidcomm!\n"); pr_warning("Invalid pidcomm!\n");
...@@ -785,6 +788,18 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, ...@@ -785,6 +788,18 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
} }
sample->end_time = end; 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) { if (ret < 0) {
sample->err = ret; sample->err = ret;
...@@ -799,6 +814,24 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, ...@@ -799,6 +814,24 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
sample->bytes = ret; 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++; tchart->io_events++;
return 0; return 0;
...@@ -1119,6 +1152,10 @@ static void draw_io_bars(struct timechart *tchart) ...@@ -1119,6 +1152,10 @@ static void draw_io_bars(struct timechart *tchart)
for (sample = c->io_samples; sample; sample = sample->next) { for (sample = c->io_samples; sample; sample = sample->next) {
double h = (double)sample->bytes / c->max_bytes; double h = (double)sample->bytes / c->max_bytes;
if (tchart->skip_eagain &&
sample->err == -EAGAIN)
continue;
if (sample->err) if (sample->err)
h = 1; h = 1;
...@@ -1849,6 +1886,30 @@ parse_highlight(const struct option *opt __maybe_unused, const char *arg, ...@@ -1849,6 +1886,30 @@ parse_highlight(const struct option *opt __maybe_unused, const char *arg,
return 0; return 0;
} }
static int
parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
{
char unit = 'n';
u64 *value = opt->value;
if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) {
switch (unit) {
case 'm':
*value *= 1000000;
break;
case 'u':
*value *= 1000;
break;
case 'n':
break;
default:
return -1;
}
}
return 0;
}
int cmd_timechart(int argc, const char **argv, int cmd_timechart(int argc, const char **argv,
const char *prefix __maybe_unused) const char *prefix __maybe_unused)
{ {
...@@ -1861,6 +1922,8 @@ int cmd_timechart(int argc, const char **argv, ...@@ -1861,6 +1922,8 @@ int cmd_timechart(int argc, const char **argv,
.ordered_samples = true, .ordered_samples = true,
}, },
.proc_num = 15, .proc_num = 15,
.min_time = 1000000,
.merge_dist = 1000,
}; };
const char *output_name = "output.svg"; const char *output_name = "output.svg";
const struct option timechart_options[] = { const struct option timechart_options[] = {
...@@ -1882,6 +1945,14 @@ int cmd_timechart(int argc, const char **argv, ...@@ -1882,6 +1945,14 @@ int cmd_timechart(int argc, const char **argv,
"min. number of tasks to print"), "min. number of tasks to print"),
OPT_BOOLEAN('t', "topology", &tchart.topology, OPT_BOOLEAN('t', "topology", &tchart.topology,
"sort CPUs according to topology"), "sort CPUs according to topology"),
OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain,
"skip EAGAIN errors"),
OPT_CALLBACK(0, "io-min-time", &tchart.min_time, "time",
"all IO faster than min-time will visually appear longer",
parse_time),
OPT_CALLBACK(0, "io-merge-dist", &tchart.merge_dist, "time",
"merge events that are merge-dist us apart",
parse_time),
OPT_END() OPT_END()
}; };
const char * const timechart_usage[] = { const char * const timechart_usage[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment