From 4f1202c8e61478984ed2d0df616149faf84c2a7f Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 20 Sep 2009 18:13:28 +0200 Subject: perf timechart: Show the name of the waker/wakee in timechart Timechart currently shows thin green lines for sending or receiving wakeups. This patch also prints (in a very small font) the name of the process that is being woken/wakes up this process. Signed-off-by: Arjan van de Ven Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <20090920181328.68baa978@linux.intel.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-timechart.c | 11 ++++++++--- tools/perf/util/svghelper.c | 28 +++++++++++++++++++++------- tools/perf/util/svghelper.h | 2 +- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 58d737ec8f5..3f45b8b24e3 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -752,6 +752,7 @@ static void draw_wakeups(void) we = wake_events; while (we) { int from = 0, to = 0; + char *task_from = NULL, *task_to = NULL; /* locate the column of the waker and wakee */ p = all_data; @@ -760,10 +761,14 @@ static void draw_wakeups(void) c = p->all; while (c) { if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { - if (p->pid == we->waker) + if (p->pid == we->waker) { from = c->Y; - if (p->pid == we->wakee) + task_from = c->comm; + } + if (p->pid == we->wakee) { to = c->Y; + task_to = c->comm; + } } c = c->next; } @@ -776,7 +781,7 @@ static void draw_wakeups(void) else if (from && to && abs(from - to) == 1) svg_wakeline(we->time, from, to); else - svg_partial_wakeline(we->time, from, to); + svg_partial_wakeline(we->time, from, task_from, to, task_to); we = we->next; } } diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index b0fcecdf378..9f70fa8e764 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -242,7 +242,7 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq) } -void svg_partial_wakeline(u64 start, int row1, int row2) +void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2) { double height; @@ -251,21 +251,35 @@ void svg_partial_wakeline(u64 start, int row1, int row2) if (row1 < row2) { - if (row1) + if (row1) { fprintf(svgfile, "\n", time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); - - if (row2) + if (desc2) + fprintf(svgfile, "%s >\n", + time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); + } + if (row2) { fprintf(svgfile, "\n", time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); + if (desc1) + fprintf(svgfile, "%s >\n", + time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); + } } else { - if (row2) + if (row2) { fprintf(svgfile, "\n", time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); - - if (row1) + if (desc1) + fprintf(svgfile, "%s <\n", + time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); + } + if (row1) { fprintf(svgfile, "\n", time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); + if (desc2) + fprintf(svgfile, "%s <\n", + time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); + } } height = row1 * SLOT_MULT; if (row2 > row1) diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index ad79b5dc53d..8260a7e6e31 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -17,7 +17,7 @@ extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); extern void svg_time_grid(u64 start, u64 end); extern void svg_legenda(void); extern void svg_wakeline(u64 start, int row1, int row2); -extern void svg_partial_wakeline(u64 start, int row1, int row2); +extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2); extern void svg_interrupt(u64 start, int row); extern void svg_text(int Yslot, u64 start, const char *text); extern void svg_close(void); -- cgit v1.2.3 From a92fe7b3063db2caa578872fce975ff53aa56214 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 20 Sep 2009 18:13:53 +0200 Subject: perf timechart: Show the duration of scheduler delays in the SVG Given that scheduler latencies are the hot thing nowadays, show the duration of said latencies in the SVG in text form. In addition, if the latency is more than 10 msec, pick a brighter yellow color as a way to point these long delays out. Signed-off-by: Arjan van de Ven Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <20090920181353.796f4509@linux.intel.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-timechart.c | 6 ++--- tools/perf/util/svghelper.c | 56 +++++++++++++++++++++++++++++++++++++++--- tools/perf/util/svghelper.h | 3 ++- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 3f45b8b24e3..23b3f09d19a 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -827,15 +827,15 @@ static void draw_process_bars(void) continue; } - svg_box(Y, p->start_time, p->end_time, "process"); + svg_box(Y, c->start_time, c->end_time, "process"); sample = c->samples; while (sample) { if (sample->type == TYPE_RUNNING) - svg_sample(Y, sample->cpu, sample->start_time, sample->end_time, "sample"); + svg_sample(Y, sample->cpu, sample->start_time, sample->end_time); if (sample->type == TYPE_BLOCKED) svg_box(Y, sample->start_time, sample->end_time, "blocked"); if (sample->type == TYPE_WAITING) - svg_box(Y, sample->start_time, sample->end_time, "waiting"); + svg_waiting(Y, sample->start_time, sample->end_time); sample = sample->next; } diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 9f70fa8e764..52f628fe642 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -69,7 +69,8 @@ void open_svg(const char *filename, int cpus, int rows) 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.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; 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(255,255, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); + fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; 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"); fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n"); fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n"); fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n"); @@ -92,14 +93,14 @@ void svg_box(int Yslot, u64 start, u64 end, const char *type) time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); } -void svg_sample(int Yslot, int cpu, u64 start, u64 end, const char *type) +void svg_sample(int Yslot, int cpu, u64 start, u64 end) { double text_size; if (!svgfile) return; - fprintf(svgfile, "\n", - time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); + fprintf(svgfile, "\n", + time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT); text_size = (time2pixels(end)-time2pixels(start)); if (cpu > 9) @@ -112,6 +113,53 @@ void svg_sample(int Yslot, int cpu, u64 start, u64 end, const char *type) } +static char *time_to_string(u64 duration) +{ + static char text[80]; + + text[0] = 0; + + if (duration < 1000) /* less than 1 usec */ + return text; + + if (duration < 1000 * 1000) { /* less than 1 msec */ + sprintf(text, "%4.1f us", duration / 1000.0); + return text; + } + sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); + + return text; +} + +void svg_waiting(int Yslot, u64 start, u64 end) +{ + char *text; + const char *style; + double font_size; + + if (!svgfile) + return; + + style = "waiting"; + + if (end-start > 10 * 1000000) /* 10 msec */ + style = "WAITING"; + + text = time_to_string(end-start); + + font_size = 1.0 * (time2pixels(end)-time2pixels(start)) / strlen(text); + + if (font_size > 0.2) + font_size = 0.2; + + + fprintf(svgfile, "\n", + time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, style); + if (font_size > MIN_TEXT_SIZE) + fprintf(svgfile, "%s\n", + time2pixels(start), Yslot * SLOT_MULT + 2, font_size, text); +} + static char *cpu_model(void) { static char cpu_m[255]; diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index 8260a7e6e31..ed4ebcfaf49 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -5,7 +5,8 @@ extern void open_svg(const char *filename, int cpus, int rows); extern void svg_box(int Yslot, u64 start, u64 end, const char *type); -extern void svg_sample(int Yslot, int cpu, u64 start, u64 end, const char *type); +extern void svg_sample(int Yslot, int cpu, u64 start, u64 end); +extern void svg_waiting(int Yslot, u64 start, u64 end); extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); -- cgit v1.2.3 From 5094b655452dd48367fb28af74ffc76019b93dc2 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 20 Sep 2009 18:14:16 +0200 Subject: perf util: Make the timechart SVG width dynamic This patch adds a command line option for timechart that allows the user to specify the width of the SVG file. This patch also makes sure that each second of recording has at least 200 units (pixels at 96 DPI) of width. This impacts recordings longer than 5 seconds; recordings shorter than 5 second will scale up to have a width of 1000 units for the whole recording (as before). Signed-off-by: Arjan van de Ven Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <20090920181416.69570c5d@linux.intel.com> Signed-off-by: Ingo Molnar --- tools/perf/Documentation/perf-timechart.txt | 3 +++ tools/perf/builtin-timechart.c | 6 ++++-- tools/perf/util/svghelper.c | 30 +++++++++++++++++++---------- tools/perf/util/svghelper.h | 6 ++++-- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index 61e0104c627..1c2ed3090cc 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt @@ -28,6 +28,9 @@ OPTIONS -i:: --input=:: Select the input file (default: perf.data) +-w:: +--width=:: + Select the width of the SVG file (default: 1000) SEE ALSO diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 23b3f09d19a..60040639627 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -915,9 +915,9 @@ static void write_svg_file(const char *filename) if (count < 15) count = determine_display_tasks(TIME_THRESH / 10); - open_svg(filename, numcpus, count); + open_svg(filename, numcpus, count, first_time, last_time); - svg_time_grid(first_time, last_time); + svg_time_grid(); svg_legenda(); for (i = 0; i < numcpus; i++) @@ -1132,6 +1132,8 @@ static const struct option options[] = { "input file name"), OPT_STRING('o', "output", &output_name, "file", "output file name"), + OPT_INTEGER('w', "width", &svg_page_width, + "page width"), OPT_END() }; diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 52f628fe642..be1555e241b 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -25,7 +25,8 @@ static u64 turbo_frequency, max_freq; #define SLOT_MULT 30.0 #define SLOT_HEIGHT 25.0 -#define WIDTH 1000.0 + +int svg_page_width = 1000; #define MIN_TEXT_SIZE 0.001 @@ -46,21 +47,35 @@ static double time2pixels(u64 time) { double X; - X = WIDTH * (time - first_time) / (last_time - first_time); + X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time); return X; } -void open_svg(const char *filename, int cpus, int rows) +void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end) { + int new_width; svgfile = fopen(filename, "w"); if (!svgfile) { fprintf(stderr, "Cannot open %s for output\n", filename); return; } + first_time = start; + first_time = first_time / 100000000 * 100000000; + last_time = end; + + /* + * if the recording is short, we default to a width of 1000, but + * for longer recordings we want at least 200 units of width per second + */ + new_width = (last_time - first_time) / 5000000; + + if (new_width > svg_page_width) + svg_page_width = new_width; + total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; fprintf(svgfile, " \n"); - fprintf(svgfile, "\n", WIDTH, total_height); + fprintf(svgfile, "\n", svg_page_width, total_height); fprintf(svgfile, "\n