aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-07-16 07:48:13 -0400
committerIngo Molnar <mingo@kernel.org>2014-07-16 07:48:13 -0400
commitff2ebe46e15bd49d52b9c2f3fc77f3a9d94eac7b (patch)
tree87a4ec640a5cec0b09135c5340815e2674beb19e
parentf4aa84fc2a1c3a1ae1b81e434e8cde1c5f98a6b4 (diff)
parentd243144af0b52fc5164a0823194f29a5979e236c (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core
Pull perf/core improvements and fixes from Jiri Olsa: * Add IO mode into timechart command (Stanislav Fomichev) Signed-off-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/perf/Documentation/perf-timechart.txt38
-rw-r--r--tools/perf/builtin-timechart.c693
-rw-r--r--tools/perf/util/svghelper.c168
-rw-r--r--tools/perf/util/svghelper.h6
4 files changed, 845 insertions, 60 deletions
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 5e0f986dff38..df98d1c82688 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -15,10 +15,20 @@ DESCRIPTION
15There are two variants of perf timechart: 15There are two variants of perf timechart:
16 16
17 'perf timechart record <command>' to record the system level events 17 'perf timechart record <command>' to record the system level events
18 of an arbitrary workload. 18 of an arbitrary workload. By default timechart records only scheduler
19 and CPU events (task switches, running times, CPU power states, etc),
20 but it's possible to record IO (disk, network) activity using -I argument.
19 21
20 'perf timechart' to turn a trace into a Scalable Vector Graphics file, 22 'perf timechart' to turn a trace into a Scalable Vector Graphics file,
21 that can be viewed with popular SVG viewers such as 'Inkscape'. 23 that can be viewed with popular SVG viewers such as 'Inkscape'. Depending
24 on the events in the perf.data file, timechart will contain scheduler/cpu
25 events or IO events.
26
27 In IO mode, every bar has two charts: upper and lower.
28 Upper bar shows incoming events (disk reads, ingress network packets).
29 Lower bar shows outgoing events (disk writes, egress network packets).
30 There are also poll bars which show how much time application spent
31 in poll/epoll/select syscalls.
22 32
23TIMECHART OPTIONS 33TIMECHART OPTIONS
24----------------- 34-----------------
@@ -54,6 +64,19 @@ TIMECHART OPTIONS
54 duration or tasks with given name. If number is given it's interpreted 64 duration or tasks with given name. If number is given it's interpreted
55 as number of nanoseconds. If non-numeric string is given it's 65 as number of nanoseconds. If non-numeric string is given it's
56 interpreted as task name. 66 interpreted as task name.
67--io-skip-eagain::
68 Don't draw EAGAIN IO events.
69--io-min-time=<nsecs>::
70 Draw small events as if they lasted min-time. Useful when you need
71 to see very small and fast IO. It's possible to specify ms or us
72 suffix to specify time in milliseconds or microseconds.
73 Default value is 1ms.
74--io-merge-dist=<nsecs>::
75 Merge events that are merge-dist nanoseconds apart.
76 Reduces number of figures on the SVG and makes it more render-friendly.
77 It's possible to specify ms or us suffix to specify time in
78 milliseconds or microseconds.
79 Default value is 1us.
57 80
58RECORD OPTIONS 81RECORD OPTIONS
59-------------- 82--------------
@@ -63,6 +86,9 @@ RECORD OPTIONS
63-T:: 86-T::
64--tasks-only:: 87--tasks-only::
65 Record only tasks-related events 88 Record only tasks-related events
89-I::
90--io-only::
91 Record only io-related events
66-g:: 92-g::
67--callchain:: 93--callchain::
68 Do call-graph (stack chain/backtrace) recording 94 Do call-graph (stack chain/backtrace) recording
@@ -87,6 +113,14 @@ Record system-wide timechart:
87 113
88 $ perf timechart --highlight gcc 114 $ perf timechart --highlight gcc
89 115
116Record system-wide IO events:
117
118 $ perf timechart record -I
119
120 then generate timechart:
121
122 $ perf timechart
123
90SEE ALSO 124SEE ALSO
91-------- 125--------
92linkperf:perf-record[1] 126linkperf:perf-record[1]
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 74db2568b867..04c9c53becad 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -60,10 +60,17 @@ struct timechart {
60 tasks_only, 60 tasks_only,
61 with_backtrace, 61 with_backtrace,
62 topology; 62 topology;
63 /* IO related settings */
64 u64 io_events;
65 bool io_only,
66 skip_eagain;
67 u64 min_time,
68 merge_dist;
63}; 69};
64 70
65struct per_pidcomm; 71struct per_pidcomm;
66struct cpu_sample; 72struct cpu_sample;
73struct io_sample;
67 74
68/* 75/*
69 * Datastructure layout: 76 * Datastructure layout:
@@ -84,6 +91,7 @@ struct per_pid {
84 u64 start_time; 91 u64 start_time;
85 u64 end_time; 92 u64 end_time;
86 u64 total_time; 93 u64 total_time;
94 u64 total_bytes;
87 int display; 95 int display;
88 96
89 struct per_pidcomm *all; 97 struct per_pidcomm *all;
@@ -97,6 +105,8 @@ struct per_pidcomm {
97 u64 start_time; 105 u64 start_time;
98 u64 end_time; 106 u64 end_time;
99 u64 total_time; 107 u64 total_time;
108 u64 max_bytes;
109 u64 total_bytes;
100 110
101 int Y; 111 int Y;
102 int display; 112 int display;
@@ -107,6 +117,7 @@ struct per_pidcomm {
107 char *comm; 117 char *comm;
108 118
109 struct cpu_sample *samples; 119 struct cpu_sample *samples;
120 struct io_sample *io_samples;
110}; 121};
111 122
112struct sample_wrapper { 123struct sample_wrapper {
@@ -131,6 +142,27 @@ struct cpu_sample {
131 const char *backtrace; 142 const char *backtrace;
132}; 143};
133 144
145enum {
146 IOTYPE_READ,
147 IOTYPE_WRITE,
148 IOTYPE_SYNC,
149 IOTYPE_TX,
150 IOTYPE_RX,
151 IOTYPE_POLL,
152};
153
154struct io_sample {
155 struct io_sample *next;
156
157 u64 start_time;
158 u64 end_time;
159 u64 bytes;
160 int type;
161 int fd;
162 int err;
163 int merges;
164};
165
134#define CSTATE 1 166#define CSTATE 1
135#define PSTATE 2 167#define PSTATE 2
136 168
@@ -213,7 +245,7 @@ static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
213 pid_set_comm(tchart, pid, pp->current->comm); 245 pid_set_comm(tchart, pid, pp->current->comm);
214 246
215 p->start_time = timestamp; 247 p->start_time = timestamp;
216 if (p->current) { 248 if (p->current && !p->current->start_time) {
217 p->current->start_time = timestamp; 249 p->current->start_time = timestamp;
218 p->current->state_since = timestamp; 250 p->current->state_since = timestamp;
219 } 251 }
@@ -682,6 +714,249 @@ static void end_sample_processing(struct timechart *tchart)
682 } 714 }
683} 715}
684 716
717static int pid_begin_io_sample(struct timechart *tchart, int pid, int type,
718 u64 start, int fd)
719{
720 struct per_pid *p = find_create_pid(tchart, pid);
721 struct per_pidcomm *c = p->current;
722 struct io_sample *sample;
723 struct io_sample *prev;
724
725 if (!c) {
726 c = zalloc(sizeof(*c));
727 if (!c)
728 return -ENOMEM;
729 p->current = c;
730 c->next = p->all;
731 p->all = c;
732 }
733
734 prev = c->io_samples;
735
736 if (prev && prev->start_time && !prev->end_time) {
737 pr_warning("Skip invalid start event: "
738 "previous event already started!\n");
739
740 /* remove previous event that has been started,
741 * we are not sure we will ever get an end for it */
742 c->io_samples = prev->next;
743 free(prev);
744 return 0;
745 }
746
747 sample = zalloc(sizeof(*sample));
748 if (!sample)
749 return -ENOMEM;
750 sample->start_time = start;
751 sample->type = type;
752 sample->fd = fd;
753 sample->next = c->io_samples;
754 c->io_samples = sample;
755
756 if (c->start_time == 0 || c->start_time > start)
757 c->start_time = start;
758
759 return 0;
760}
761
762static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
763 u64 end, long ret)
764{
765 struct per_pid *p = find_create_pid(tchart, pid);
766 struct per_pidcomm *c = p->current;
767 struct io_sample *sample, *prev;
768
769 if (!c) {
770 pr_warning("Invalid pidcomm!\n");
771 return -1;
772 }
773
774 sample = c->io_samples;
775
776 if (!sample) /* skip partially captured events */
777 return 0;
778
779 if (sample->end_time) {
780 pr_warning("Skip invalid end event: "
781 "previous event already ended!\n");
782 return 0;
783 }
784
785 if (sample->type != type) {
786 pr_warning("Skip invalid end event: invalid event type!\n");
787 return 0;
788 }
789
790 sample->end_time = end;
791 prev = sample->next;
792
793 /* we want to be able to see small and fast transfers, so make them
794 * at least min_time long, but don't overlap them */
795 if (sample->end_time - sample->start_time < tchart->min_time)
796 sample->end_time = sample->start_time + tchart->min_time;
797 if (prev && sample->start_time < prev->end_time) {
798 if (prev->err) /* try to make errors more visible */
799 sample->start_time = prev->end_time;
800 else
801 prev->end_time = sample->start_time;
802 }
803
804 if (ret < 0) {
805 sample->err = ret;
806 } else if (type == IOTYPE_READ || type == IOTYPE_WRITE ||
807 type == IOTYPE_TX || type == IOTYPE_RX) {
808
809 if ((u64)ret > c->max_bytes)
810 c->max_bytes = ret;
811
812 c->total_bytes += ret;
813 p->total_bytes += ret;
814 sample->bytes = ret;
815 }
816
817 /* merge two requests to make svg smaller and render-friendly */
818 if (prev &&
819 prev->type == sample->type &&
820 prev->err == sample->err &&
821 prev->fd == sample->fd &&
822 prev->end_time + tchart->merge_dist >= sample->start_time) {
823
824 sample->bytes += prev->bytes;
825 sample->merges += prev->merges + 1;
826
827 sample->start_time = prev->start_time;
828 sample->next = prev->next;
829 free(prev);
830
831 if (!sample->err && sample->bytes > c->max_bytes)
832 c->max_bytes = sample->bytes;
833 }
834
835 tchart->io_events++;
836
837 return 0;
838}
839
840static int
841process_enter_read(struct timechart *tchart,
842 struct perf_evsel *evsel,
843 struct perf_sample *sample)
844{
845 long fd = perf_evsel__intval(evsel, sample, "fd");
846 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ,
847 sample->time, fd);
848}
849
850static int
851process_exit_read(struct timechart *tchart,
852 struct perf_evsel *evsel,
853 struct perf_sample *sample)
854{
855 long ret = perf_evsel__intval(evsel, sample, "ret");
856 return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ,
857 sample->time, ret);
858}
859
860static int
861process_enter_write(struct timechart *tchart,
862 struct perf_evsel *evsel,
863 struct perf_sample *sample)
864{
865 long fd = perf_evsel__intval(evsel, sample, "fd");
866 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE,
867 sample->time, fd);
868}
869
870static int
871process_exit_write(struct timechart *tchart,
872 struct perf_evsel *evsel,
873 struct perf_sample *sample)
874{
875 long ret = perf_evsel__intval(evsel, sample, "ret");
876 return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE,
877 sample->time, ret);
878}
879
880static int
881process_enter_sync(struct timechart *tchart,
882 struct perf_evsel *evsel,
883 struct perf_sample *sample)
884{
885 long fd = perf_evsel__intval(evsel, sample, "fd");
886 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC,
887 sample->time, fd);
888}
889
890static int
891process_exit_sync(struct timechart *tchart,
892 struct perf_evsel *evsel,
893 struct perf_sample *sample)
894{
895 long ret = perf_evsel__intval(evsel, sample, "ret");
896 return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC,
897 sample->time, ret);
898}
899
900static int
901process_enter_tx(struct timechart *tchart,
902 struct perf_evsel *evsel,
903 struct perf_sample *sample)
904{
905 long fd = perf_evsel__intval(evsel, sample, "fd");
906 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX,
907 sample->time, fd);
908}
909
910static int
911process_exit_tx(struct timechart *tchart,
912 struct perf_evsel *evsel,
913 struct perf_sample *sample)
914{
915 long ret = perf_evsel__intval(evsel, sample, "ret");
916 return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX,
917 sample->time, ret);
918}
919
920static int
921process_enter_rx(struct timechart *tchart,
922 struct perf_evsel *evsel,
923 struct perf_sample *sample)
924{
925 long fd = perf_evsel__intval(evsel, sample, "fd");
926 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX,
927 sample->time, fd);
928}
929
930static int
931process_exit_rx(struct timechart *tchart,
932 struct perf_evsel *evsel,
933 struct perf_sample *sample)
934{
935 long ret = perf_evsel__intval(evsel, sample, "ret");
936 return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX,
937 sample->time, ret);
938}
939
940static int
941process_enter_poll(struct timechart *tchart,
942 struct perf_evsel *evsel,
943 struct perf_sample *sample)
944{
945 long fd = perf_evsel__intval(evsel, sample, "fd");
946 return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL,
947 sample->time, fd);
948}
949
950static int
951process_exit_poll(struct timechart *tchart,
952 struct perf_evsel *evsel,
953 struct perf_sample *sample)
954{
955 long ret = perf_evsel__intval(evsel, sample, "ret");
956 return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL,
957 sample->time, ret);
958}
959
685/* 960/*
686 * Sort the pid datastructure 961 * Sort the pid datastructure
687 */ 962 */
@@ -852,6 +1127,121 @@ static void draw_cpu_usage(struct timechart *tchart)
852 } 1127 }
853} 1128}
854 1129
1130static void draw_io_bars(struct timechart *tchart)
1131{
1132 const char *suf;
1133 double bytes;
1134 char comm[256];
1135 struct per_pid *p;
1136 struct per_pidcomm *c;
1137 struct io_sample *sample;
1138 int Y = 1;
1139
1140 p = tchart->all_data;
1141 while (p) {
1142 c = p->all;
1143 while (c) {
1144 if (!c->display) {
1145 c->Y = 0;
1146 c = c->next;
1147 continue;
1148 }
1149
1150 svg_box(Y, c->start_time, c->end_time, "process3");
1151 sample = c->io_samples;
1152 for (sample = c->io_samples; sample; sample = sample->next) {
1153 double h = (double)sample->bytes / c->max_bytes;
1154
1155 if (tchart->skip_eagain &&
1156 sample->err == -EAGAIN)
1157 continue;
1158
1159 if (sample->err)
1160 h = 1;
1161
1162 if (sample->type == IOTYPE_SYNC)
1163 svg_fbox(Y,
1164 sample->start_time,
1165 sample->end_time,
1166 1,
1167 sample->err ? "error" : "sync",
1168 sample->fd,
1169 sample->err,
1170 sample->merges);
1171 else if (sample->type == IOTYPE_POLL)
1172 svg_fbox(Y,
1173 sample->start_time,
1174 sample->end_time,
1175 1,
1176 sample->err ? "error" : "poll",
1177 sample->fd,
1178 sample->err,
1179 sample->merges);
1180 else if (sample->type == IOTYPE_READ)
1181 svg_ubox(Y,
1182 sample->start_time,
1183 sample->end_time,
1184 h,
1185 sample->err ? "error" : "disk",
1186 sample->fd,
1187 sample->err,
1188 sample->merges);
1189 else if (sample->type == IOTYPE_WRITE)
1190 svg_lbox(Y,
1191 sample->start_time,
1192 sample->end_time,
1193 h,
1194 sample->err ? "error" : "disk",
1195 sample->fd,
1196 sample->err,
1197 sample->merges);
1198 else if (sample->type == IOTYPE_RX)
1199 svg_ubox(Y,
1200 sample->start_time,
1201 sample->end_time,
1202 h,
1203 sample->err ? "error" : "net",
1204 sample->fd,
1205 sample->err,
1206 sample->merges);
1207 else if (sample->type == IOTYPE_TX)
1208 svg_lbox(Y,
1209 sample->start_time,
1210 sample->end_time,
1211 h,
1212 sample->err ? "error" : "net",
1213 sample->fd,
1214 sample->err,
1215 sample->merges);
1216 }
1217
1218 suf = "";
1219 bytes = c->total_bytes;
1220 if (bytes > 1024) {
1221 bytes = bytes / 1024;
1222 suf = "K";
1223 }
1224 if (bytes > 1024) {
1225 bytes = bytes / 1024;
1226 suf = "M";
1227 }
1228 if (bytes > 1024) {
1229 bytes = bytes / 1024;
1230 suf = "G";
1231 }
1232
1233
1234 sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf);
1235 svg_text(Y, c->start_time, comm);
1236
1237 c->Y = Y;
1238 Y++;
1239 c = c->next;
1240 }
1241 p = p->next;
1242 }
1243}
1244
855static void draw_process_bars(struct timechart *tchart) 1245static void draw_process_bars(struct timechart *tchart)
856{ 1246{
857 struct per_pid *p; 1247 struct per_pid *p;
@@ -987,9 +1377,6 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
987 struct per_pidcomm *c; 1377 struct per_pidcomm *c;
988 int count = 0; 1378 int count = 0;
989 1379
990 if (process_filter)
991 return determine_display_tasks_filtered(tchart);
992
993 p = tchart->all_data; 1380 p = tchart->all_data;
994 while (p) { 1381 while (p) {
995 p->display = 0; 1382 p->display = 0;
@@ -1025,15 +1412,46 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold)
1025 return count; 1412 return count;
1026} 1413}
1027 1414
1415static int determine_display_io_tasks(struct timechart *timechart, u64 threshold)
1416{
1417 struct per_pid *p;
1418 struct per_pidcomm *c;
1419 int count = 0;
1420
1421 p = timechart->all_data;
1422 while (p) {
1423 /* no exit marker, task kept running to the end */
1424 if (p->end_time == 0)
1425 p->end_time = timechart->last_time;
1028 1426
1427 c = p->all;
1029 1428
1429 while (c) {
1430 c->display = 0;
1431
1432 if (c->total_bytes >= threshold) {
1433 c->display = 1;
1434 count++;
1435 }
1436
1437 if (c->end_time == 0)
1438 c->end_time = timechart->last_time;
1439
1440 c = c->next;
1441 }
1442 p = p->next;
1443 }
1444 return count;
1445}
1446
1447#define BYTES_THRESH (1 * 1024 * 1024)
1030#define TIME_THRESH 10000000 1448#define TIME_THRESH 10000000
1031 1449
1032static void write_svg_file(struct timechart *tchart, const char *filename) 1450static void write_svg_file(struct timechart *tchart, const char *filename)
1033{ 1451{
1034 u64 i; 1452 u64 i;
1035 int count; 1453 int count;
1036 int thresh = TIME_THRESH; 1454 int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH;
1037 1455
1038 if (tchart->power_only) 1456 if (tchart->power_only)
1039 tchart->proc_num = 0; 1457 tchart->proc_num = 0;
@@ -1041,28 +1459,43 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
1041 /* We'd like to show at least proc_num tasks; 1459 /* We'd like to show at least proc_num tasks;
1042 * be less picky if we have fewer */ 1460 * be less picky if we have fewer */
1043 do { 1461 do {
1044 count = determine_display_tasks(tchart, thresh); 1462 if (process_filter)
1463 count = determine_display_tasks_filtered(tchart);
1464 else if (tchart->io_events)
1465 count = determine_display_io_tasks(tchart, thresh);
1466 else
1467 count = determine_display_tasks(tchart, thresh);
1045 thresh /= 10; 1468 thresh /= 10;
1046 } while (!process_filter && thresh && count < tchart->proc_num); 1469 } while (!process_filter && thresh && count < tchart->proc_num);
1047 1470
1048 if (!tchart->proc_num) 1471 if (!tchart->proc_num)
1049 count = 0; 1472 count = 0;
1050 1473
1051 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); 1474 if (tchart->io_events) {
1475 open_svg(filename, 0, count, tchart->first_time, tchart->last_time);
1052 1476
1053 svg_time_grid(); 1477 svg_time_grid(0.5);
1054 svg_legenda(); 1478 svg_io_legenda();
1479
1480 draw_io_bars(tchart);
1481 } else {
1482 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
1055 1483
1056 for (i = 0; i < tchart->numcpus; i++) 1484 svg_time_grid(0);
1057 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1058 1485
1059 draw_cpu_usage(tchart); 1486 svg_legenda();
1060 if (tchart->proc_num) 1487
1061 draw_process_bars(tchart); 1488 for (i = 0; i < tchart->numcpus; i++)
1062 if (!tchart->tasks_only) 1489 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1063 draw_c_p_states(tchart); 1490
1064 if (tchart->proc_num) 1491 draw_cpu_usage(tchart);
1065 draw_wakeups(tchart); 1492 if (tchart->proc_num)
1493 draw_process_bars(tchart);
1494 if (!tchart->tasks_only)
1495 draw_c_p_states(tchart);
1496 if (tchart->proc_num)
1497 draw_wakeups(tchart);
1498 }
1066 1499
1067 svg_close(); 1500 svg_close();
1068} 1501}
@@ -1110,6 +1543,56 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
1110 { "power:power_end", process_sample_power_end }, 1543 { "power:power_end", process_sample_power_end },
1111 { "power:power_frequency", process_sample_power_frequency }, 1544 { "power:power_frequency", process_sample_power_frequency },
1112#endif 1545#endif
1546
1547 { "syscalls:sys_enter_read", process_enter_read },
1548 { "syscalls:sys_enter_pread64", process_enter_read },
1549 { "syscalls:sys_enter_readv", process_enter_read },
1550 { "syscalls:sys_enter_preadv", process_enter_read },
1551 { "syscalls:sys_enter_write", process_enter_write },
1552 { "syscalls:sys_enter_pwrite64", process_enter_write },
1553 { "syscalls:sys_enter_writev", process_enter_write },
1554 { "syscalls:sys_enter_pwritev", process_enter_write },
1555 { "syscalls:sys_enter_sync", process_enter_sync },
1556 { "syscalls:sys_enter_sync_file_range", process_enter_sync },
1557 { "syscalls:sys_enter_fsync", process_enter_sync },
1558 { "syscalls:sys_enter_msync", process_enter_sync },
1559 { "syscalls:sys_enter_recvfrom", process_enter_rx },
1560 { "syscalls:sys_enter_recvmmsg", process_enter_rx },
1561 { "syscalls:sys_enter_recvmsg", process_enter_rx },
1562 { "syscalls:sys_enter_sendto", process_enter_tx },
1563 { "syscalls:sys_enter_sendmsg", process_enter_tx },
1564 { "syscalls:sys_enter_sendmmsg", process_enter_tx },
1565 { "syscalls:sys_enter_epoll_pwait", process_enter_poll },
1566 { "syscalls:sys_enter_epoll_wait", process_enter_poll },
1567 { "syscalls:sys_enter_poll", process_enter_poll },
1568 { "syscalls:sys_enter_ppoll", process_enter_poll },
1569 { "syscalls:sys_enter_pselect6", process_enter_poll },
1570 { "syscalls:sys_enter_select", process_enter_poll },
1571
1572 { "syscalls:sys_exit_read", process_exit_read },
1573 { "syscalls:sys_exit_pread64", process_exit_read },
1574 { "syscalls:sys_exit_readv", process_exit_read },
1575 { "syscalls:sys_exit_preadv", process_exit_read },
1576 { "syscalls:sys_exit_write", process_exit_write },
1577 { "syscalls:sys_exit_pwrite64", process_exit_write },
1578 { "syscalls:sys_exit_writev", process_exit_write },
1579 { "syscalls:sys_exit_pwritev", process_exit_write },
1580 { "syscalls:sys_exit_sync", process_exit_sync },
1581 { "syscalls:sys_exit_sync_file_range", process_exit_sync },
1582 { "syscalls:sys_exit_fsync", process_exit_sync },
1583 { "syscalls:sys_exit_msync", process_exit_sync },
1584 { "syscalls:sys_exit_recvfrom", process_exit_rx },
1585 { "syscalls:sys_exit_recvmmsg", process_exit_rx },
1586 { "syscalls:sys_exit_recvmsg", process_exit_rx },
1587 { "syscalls:sys_exit_sendto", process_exit_tx },
1588 { "syscalls:sys_exit_sendmsg", process_exit_tx },
1589 { "syscalls:sys_exit_sendmmsg", process_exit_tx },
1590 { "syscalls:sys_exit_epoll_pwait", process_exit_poll },
1591 { "syscalls:sys_exit_epoll_wait", process_exit_poll },
1592 { "syscalls:sys_exit_poll", process_exit_poll },
1593 { "syscalls:sys_exit_ppoll", process_exit_poll },
1594 { "syscalls:sys_exit_pselect6", process_exit_poll },
1595 { "syscalls:sys_exit_select", process_exit_poll },
1113 }; 1596 };
1114 struct perf_data_file file = { 1597 struct perf_data_file file = {
1115 .path = input_name, 1598 .path = input_name,
@@ -1154,6 +1637,139 @@ out_delete:
1154 return ret; 1637 return ret;
1155} 1638}
1156 1639
1640static int timechart__io_record(int argc, const char **argv)
1641{
1642 unsigned int rec_argc, i;
1643 const char **rec_argv;
1644 const char **p;
1645 char *filter = NULL;
1646
1647 const char * const common_args[] = {
1648 "record", "-a", "-R", "-c", "1",
1649 };
1650 unsigned int common_args_nr = ARRAY_SIZE(common_args);
1651
1652 const char * const disk_events[] = {
1653 "syscalls:sys_enter_read",
1654 "syscalls:sys_enter_pread64",
1655 "syscalls:sys_enter_readv",
1656 "syscalls:sys_enter_preadv",
1657 "syscalls:sys_enter_write",
1658 "syscalls:sys_enter_pwrite64",
1659 "syscalls:sys_enter_writev",
1660 "syscalls:sys_enter_pwritev",
1661 "syscalls:sys_enter_sync",
1662 "syscalls:sys_enter_sync_file_range",
1663 "syscalls:sys_enter_fsync",
1664 "syscalls:sys_enter_msync",
1665
1666 "syscalls:sys_exit_read",
1667 "syscalls:sys_exit_pread64",
1668 "syscalls:sys_exit_readv",
1669 "syscalls:sys_exit_preadv",
1670 "syscalls:sys_exit_write",
1671 "syscalls:sys_exit_pwrite64",
1672 "syscalls:sys_exit_writev",
1673 "syscalls:sys_exit_pwritev",
1674 "syscalls:sys_exit_sync",
1675 "syscalls:sys_exit_sync_file_range",
1676 "syscalls:sys_exit_fsync",
1677 "syscalls:sys_exit_msync",
1678 };
1679 unsigned int disk_events_nr = ARRAY_SIZE(disk_events);
1680
1681 const char * const net_events[] = {
1682 "syscalls:sys_enter_recvfrom",
1683 "syscalls:sys_enter_recvmmsg",
1684 "syscalls:sys_enter_recvmsg",
1685 "syscalls:sys_enter_sendto",
1686 "syscalls:sys_enter_sendmsg",
1687 "syscalls:sys_enter_sendmmsg",
1688
1689 "syscalls:sys_exit_recvfrom",
1690 "syscalls:sys_exit_recvmmsg",
1691 "syscalls:sys_exit_recvmsg",
1692 "syscalls:sys_exit_sendto",
1693 "syscalls:sys_exit_sendmsg",
1694 "syscalls:sys_exit_sendmmsg",
1695 };
1696 unsigned int net_events_nr = ARRAY_SIZE(net_events);
1697
1698 const char * const poll_events[] = {
1699 "syscalls:sys_enter_epoll_pwait",
1700 "syscalls:sys_enter_epoll_wait",
1701 "syscalls:sys_enter_poll",
1702 "syscalls:sys_enter_ppoll",
1703 "syscalls:sys_enter_pselect6",
1704 "syscalls:sys_enter_select",
1705
1706 "syscalls:sys_exit_epoll_pwait",
1707 "syscalls:sys_exit_epoll_wait",
1708 "syscalls:sys_exit_poll",
1709 "syscalls:sys_exit_ppoll",
1710 "syscalls:sys_exit_pselect6",
1711 "syscalls:sys_exit_select",
1712 };
1713 unsigned int poll_events_nr = ARRAY_SIZE(poll_events);
1714
1715 rec_argc = common_args_nr +
1716 disk_events_nr * 4 +
1717 net_events_nr * 4 +
1718 poll_events_nr * 4 +
1719 argc;
1720 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1721
1722 if (rec_argv == NULL)
1723 return -ENOMEM;
1724
1725 if (asprintf(&filter, "common_pid != %d", getpid()) < 0)
1726 return -ENOMEM;
1727
1728 p = rec_argv;
1729 for (i = 0; i < common_args_nr; i++)
1730 *p++ = strdup(common_args[i]);
1731
1732 for (i = 0; i < disk_events_nr; i++) {
1733 if (!is_valid_tracepoint(disk_events[i])) {
1734 rec_argc -= 4;
1735 continue;
1736 }
1737
1738 *p++ = "-e";
1739 *p++ = strdup(disk_events[i]);
1740 *p++ = "--filter";
1741 *p++ = filter;
1742 }
1743 for (i = 0; i < net_events_nr; i++) {
1744 if (!is_valid_tracepoint(net_events[i])) {
1745 rec_argc -= 4;
1746 continue;
1747 }
1748
1749 *p++ = "-e";
1750 *p++ = strdup(net_events[i]);
1751 *p++ = "--filter";
1752 *p++ = filter;
1753 }
1754 for (i = 0; i < poll_events_nr; i++) {
1755 if (!is_valid_tracepoint(poll_events[i])) {
1756 rec_argc -= 4;
1757 continue;
1758 }
1759
1760 *p++ = "-e";
1761 *p++ = strdup(poll_events[i]);
1762 *p++ = "--filter";
1763 *p++ = filter;
1764 }
1765
1766 for (i = 0; i < (unsigned int)argc; i++)
1767 *p++ = argv[i];
1768
1769 return cmd_record(rec_argc, rec_argv, NULL);
1770}
1771
1772
1157static int timechart__record(struct timechart *tchart, int argc, const char **argv) 1773static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1158{ 1774{
1159 unsigned int rec_argc, i, j; 1775 unsigned int rec_argc, i, j;
@@ -1270,6 +1886,30 @@ parse_highlight(const struct option *opt __maybe_unused, const char *arg,
1270 return 0; 1886 return 0;
1271} 1887}
1272 1888
1889static int
1890parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
1891{
1892 char unit = 'n';
1893 u64 *value = opt->value;
1894
1895 if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) {
1896 switch (unit) {
1897 case 'm':
1898 *value *= 1000000;
1899 break;
1900 case 'u':
1901 *value *= 1000;
1902 break;
1903 case 'n':
1904 break;
1905 default:
1906 return -1;
1907 }
1908 }
1909
1910 return 0;
1911}
1912
1273int cmd_timechart(int argc, const char **argv, 1913int cmd_timechart(int argc, const char **argv,
1274 const char *prefix __maybe_unused) 1914 const char *prefix __maybe_unused)
1275{ 1915{
@@ -1282,6 +1922,8 @@ int cmd_timechart(int argc, const char **argv,
1282 .ordered_samples = true, 1922 .ordered_samples = true,
1283 }, 1923 },
1284 .proc_num = 15, 1924 .proc_num = 15,
1925 .min_time = 1000000,
1926 .merge_dist = 1000,
1285 }; 1927 };
1286 const char *output_name = "output.svg"; 1928 const char *output_name = "output.svg";
1287 const struct option timechart_options[] = { 1929 const struct option timechart_options[] = {
@@ -1303,6 +1945,14 @@ int cmd_timechart(int argc, const char **argv,
1303 "min. number of tasks to print"), 1945 "min. number of tasks to print"),
1304 OPT_BOOLEAN('t', "topology", &tchart.topology, 1946 OPT_BOOLEAN('t', "topology", &tchart.topology,
1305 "sort CPUs according to topology"), 1947 "sort CPUs according to topology"),
1948 OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain,
1949 "skip EAGAIN errors"),
1950 OPT_CALLBACK(0, "io-min-time", &tchart.min_time, "time",
1951 "all IO faster than min-time will visually appear longer",
1952 parse_time),
1953 OPT_CALLBACK(0, "io-merge-dist", &tchart.merge_dist, "time",
1954 "merge events that are merge-dist us apart",
1955 parse_time),
1306 OPT_END() 1956 OPT_END()
1307 }; 1957 };
1308 const char * const timechart_usage[] = { 1958 const char * const timechart_usage[] = {
@@ -1314,6 +1964,8 @@ int cmd_timechart(int argc, const char **argv,
1314 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), 1964 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1315 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, 1965 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1316 "output processes data only"), 1966 "output processes data only"),
1967 OPT_BOOLEAN('I', "io-only", &tchart.io_only,
1968 "record only IO data"),
1317 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), 1969 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1318 OPT_END() 1970 OPT_END()
1319 }; 1971 };
@@ -1340,7 +1992,10 @@ int cmd_timechart(int argc, const char **argv,
1340 return -1; 1992 return -1;
1341 } 1993 }
1342 1994
1343 return timechart__record(&tchart, argc, argv); 1995 if (tchart.io_only)
1996 return timechart__io_record(argc, argv);
1997 else
1998 return timechart__record(&tchart, argc, argv);
1344 } else if (argc) 1999 } else if (argc)
1345 usage_with_options(timechart_usage, timechart_options); 2000 usage_with_options(timechart_usage, timechart_options);
1346 2001
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 6a0a13d07a28..283d3e73e2f2 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -30,6 +30,7 @@ static u64 turbo_frequency, max_freq;
30 30
31#define SLOT_MULT 30.0 31#define SLOT_MULT 30.0
32#define SLOT_HEIGHT 25.0 32#define SLOT_HEIGHT 25.0
33#define SLOT_HALF (SLOT_HEIGHT / 2)
33 34
34int svg_page_width = 1000; 35int svg_page_width = 1000;
35u64 svg_highlight; 36u64 svg_highlight;
@@ -114,8 +115,14 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
114 fprintf(svgfile, " rect { stroke-width: 1; }\n"); 115 fprintf(svgfile, " rect { stroke-width: 1; }\n");
115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 116 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 117 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
117 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
122 fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
123 fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
124 fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
125 fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
119 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 126 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
120 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 127 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 128 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
@@ -132,12 +139,81 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
132 fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); 139 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
133} 140}
134 141
142static double normalize_height(double height)
143{
144 if (height < 0.25)
145 return 0.25;
146 else if (height < 0.50)
147 return 0.50;
148 else if (height < 0.75)
149 return 0.75;
150 else
151 return 0.100;
152}
153
154void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
155{
156 double w = time2pixels(end) - time2pixels(start);
157 height = normalize_height(height);
158
159 if (!svgfile)
160 return;
161
162 fprintf(svgfile, "<g>\n");
163 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
164 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
165 time2pixels(start),
166 w,
167 Yslot * SLOT_MULT,
168 SLOT_HALF * height,
169 type);
170 fprintf(svgfile, "</g>\n");
171}
172
173void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
174{
175 double w = time2pixels(end) - time2pixels(start);
176 height = normalize_height(height);
177
178 if (!svgfile)
179 return;
180
181 fprintf(svgfile, "<g>\n");
182 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
183 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
184 time2pixels(start),
185 w,
186 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height,
187 SLOT_HALF * height,
188 type);
189 fprintf(svgfile, "</g>\n");
190}
191
192void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
193{
194 double w = time2pixels(end) - time2pixels(start);
195 height = normalize_height(height);
196
197 if (!svgfile)
198 return;
199
200 fprintf(svgfile, "<g>\n");
201 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
202 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
203 time2pixels(start),
204 w,
205 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height,
206 SLOT_HEIGHT * height,
207 type);
208 fprintf(svgfile, "</g>\n");
209}
210
135void svg_box(int Yslot, u64 start, u64 end, const char *type) 211void svg_box(int Yslot, u64 start, u64 end, const char *type)
136{ 212{
137 if (!svgfile) 213 if (!svgfile)
138 return; 214 return;
139 215
140 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 216 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
141 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 217 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
142} 218}
143 219
@@ -174,7 +250,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
174 cpu, time_to_string(end - start)); 250 cpu, time_to_string(end - start));
175 if (backtrace) 251 if (backtrace)
176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 252 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
177 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 253 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, 254 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
179 type); 255 type);
180 256
@@ -186,7 +262,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
186 text_size = round_text_size(text_size); 262 text_size = round_text_size(text_size);
187 263
188 if (text_size > MIN_TEXT_SIZE) 264 if (text_size > MIN_TEXT_SIZE)
189 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 265 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n",
190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 266 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
191 267
192 fprintf(svgfile, "</g>\n"); 268 fprintf(svgfile, "</g>\n");
@@ -202,10 +278,10 @@ static char *time_to_string(u64 duration)
202 return text; 278 return text;
203 279
204 if (duration < 1000 * 1000) { /* less than 1 msec */ 280 if (duration < 1000 * 1000) { /* less than 1 msec */
205 sprintf(text, "%4.1f us", duration / 1000.0); 281 sprintf(text, "%.1f us", duration / 1000.0);
206 return text; 282 return text;
207 } 283 }
208 sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); 284 sprintf(text, "%.1f ms", duration / 1000.0 / 1000);
209 285
210 return text; 286 return text;
211} 287}
@@ -233,14 +309,14 @@ void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
233 309
234 font_size = round_text_size(font_size); 310 font_size = round_text_size(font_size);
235 311
236 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 312 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); 313 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
238 if (backtrace) 314 if (backtrace)
239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); 315 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
240 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 316 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 317 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
242 if (font_size > MIN_TEXT_SIZE) 318 if (font_size > MIN_TEXT_SIZE)
243 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n", 319 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n",
244 font_size, text); 320 font_size, text);
245 fprintf(svgfile, "</g>\n"); 321 fprintf(svgfile, "</g>\n");
246} 322}
@@ -289,16 +365,16 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
289 365
290 fprintf(svgfile, "<g>\n"); 366 fprintf(svgfile, "<g>\n");
291 367
292 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 368 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n",
293 time2pixels(first_time), 369 time2pixels(first_time),
294 time2pixels(last_time)-time2pixels(first_time), 370 time2pixels(last_time)-time2pixels(first_time),
295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 371 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
296 372
297 sprintf(cpu_string, "CPU %i", (int)cpu); 373 sprintf(cpu_string, "CPU %i", (int)cpu);
298 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 374 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 375 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
300 376
301 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 377 fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n",
302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 378 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
303 379
304 fprintf(svgfile, "</g>\n"); 380 fprintf(svgfile, "</g>\n");
@@ -319,11 +395,11 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
319 else 395 else
320 type = "sample"; 396 type = "sample";
321 397
322 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 398 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu));
323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); 399 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
324 if (backtrace) 400 if (backtrace)
325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 401 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
326 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 402 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 403 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
328 width = time2pixels(end)-time2pixels(start); 404 width = time2pixels(end)-time2pixels(start);
329 if (width > 6) 405 if (width > 6)
@@ -332,7 +408,7 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
332 width = round_text_size(width); 408 width = round_text_size(width);
333 409
334 if (width > MIN_TEXT_SIZE) 410 if (width > MIN_TEXT_SIZE)
335 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n", 411 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n",
336 width, name); 412 width, name);
337 413
338 fprintf(svgfile, "</g>\n"); 414 fprintf(svgfile, "</g>\n");
@@ -353,7 +429,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
353 type = 6; 429 type = 6;
354 sprintf(style, "c%i", type); 430 sprintf(style, "c%i", type);
355 431
356 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", 432 fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n",
357 style, 433 style,
358 time2pixels(start), time2pixels(end)-time2pixels(start), 434 time2pixels(start), time2pixels(end)-time2pixels(start),
359 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 435 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
@@ -365,7 +441,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
365 width = round_text_size(width); 441 width = round_text_size(width);
366 442
367 if (width > MIN_TEXT_SIZE) 443 if (width > MIN_TEXT_SIZE)
368 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 444 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n",
369 time2pixels(start), cpu2y(cpu)+width, width, type); 445 time2pixels(start), cpu2y(cpu)+width, width, type);
370 446
371 fprintf(svgfile, "</g>\n"); 447 fprintf(svgfile, "</g>\n");
@@ -407,9 +483,9 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
407 if (max_freq) 483 if (max_freq)
408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 484 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 485 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
410 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", 486 fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n",
411 time2pixels(start), time2pixels(end), height, height); 487 time2pixels(start), time2pixels(end), height, height);
412 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 488 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n",
413 time2pixels(start), height+0.9, HzToHuman(freq)); 489 time2pixels(start), height+0.9, HzToHuman(freq));
414 490
415 fprintf(svgfile, "</g>\n"); 491 fprintf(svgfile, "</g>\n");
@@ -435,32 +511,32 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
435 511
436 if (row1 < row2) { 512 if (row1 < row2) {
437 if (row1) { 513 if (row1) {
438 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 514 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
439 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 515 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
440 if (desc2) 516 if (desc2)
441 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 517 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
442 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); 518 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
443 } 519 }
444 if (row2) { 520 if (row2) {
445 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 521 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
446 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); 522 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
447 if (desc1) 523 if (desc1)
448 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 524 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
449 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); 525 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
450 } 526 }
451 } else { 527 } else {
452 if (row2) { 528 if (row2) {
453 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 529 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
454 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 530 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
455 if (desc1) 531 if (desc1)
456 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 532 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
457 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); 533 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
458 } 534 }
459 if (row1) { 535 if (row1) {
460 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 536 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
461 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); 537 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
462 if (desc2) 538 if (desc2)
463 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 539 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
464 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); 540 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
465 } 541 }
466 } 542 }
@@ -468,7 +544,7 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
468 if (row2 > row1) 544 if (row2 > row1)
469 height += SLOT_HEIGHT; 545 height += SLOT_HEIGHT;
470 if (row1) 546 if (row1)
471 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 547 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
472 time2pixels(start), height); 548 time2pixels(start), height);
473 549
474 fprintf(svgfile, "</g>\n"); 550 fprintf(svgfile, "</g>\n");
@@ -488,16 +564,16 @@ void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 564 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
489 565
490 if (row1 < row2) 566 if (row1 < row2)
491 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 567 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 568 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
493 else 569 else
494 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 570 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
495 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); 571 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
496 572
497 height = row1 * SLOT_MULT; 573 height = row1 * SLOT_MULT;
498 if (row2 > row1) 574 if (row2 > row1)
499 height += SLOT_HEIGHT; 575 height += SLOT_HEIGHT;
500 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 576 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
501 time2pixels(start), height); 577 time2pixels(start), height);
502 578
503 fprintf(svgfile, "</g>\n"); 579 fprintf(svgfile, "</g>\n");
@@ -515,9 +591,9 @@ void svg_interrupt(u64 start, int row, const char *backtrace)
515 if (backtrace) 591 if (backtrace)
516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 592 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
517 593
518 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 594 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
519 time2pixels(start), row * SLOT_MULT); 595 time2pixels(start), row * SLOT_MULT);
520 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 596 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 597 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
522 598
523 fprintf(svgfile, "</g>\n"); 599 fprintf(svgfile, "</g>\n");
@@ -528,7 +604,7 @@ void svg_text(int Yslot, u64 start, const char *text)
528 if (!svgfile) 604 if (!svgfile)
529 return; 605 return;
530 606
531 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 607 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
532 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); 608 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
533} 609}
534 610
@@ -537,12 +613,26 @@ static void svg_legenda_box(int X, const char *text, const char *style)
537 double boxsize; 613 double boxsize;
538 boxsize = SLOT_HEIGHT / 2; 614 boxsize = SLOT_HEIGHT / 2;
539 615
540 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 616 fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
541 X, boxsize, boxsize, style); 617 X, boxsize, boxsize, style);
542 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n", 618 fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n",
543 X + boxsize + 5, boxsize, 0.8 * boxsize, text); 619 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
544} 620}
545 621
622void svg_io_legenda(void)
623{
624 if (!svgfile)
625 return;
626
627 fprintf(svgfile, "<g>\n");
628 svg_legenda_box(0, "Disk", "disk");
629 svg_legenda_box(100, "Network", "net");
630 svg_legenda_box(200, "Sync", "sync");
631 svg_legenda_box(300, "Poll", "poll");
632 svg_legenda_box(400, "Error", "error");
633 fprintf(svgfile, "</g>\n");
634}
635
546void svg_legenda(void) 636void svg_legenda(void)
547{ 637{
548 if (!svgfile) 638 if (!svgfile)
@@ -559,7 +649,7 @@ void svg_legenda(void)
559 fprintf(svgfile, "</g>\n"); 649 fprintf(svgfile, "</g>\n");
560} 650}
561 651
562void svg_time_grid(void) 652void svg_time_grid(double min_thickness)
563{ 653{
564 u64 i; 654 u64 i;
565 655
@@ -579,8 +669,10 @@ void svg_time_grid(void)
579 color = 128; 669 color = 128;
580 } 670 }
581 671
582 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", 672 if (thickness >= min_thickness)
583 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 673 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n",
674 time2pixels(i), SLOT_MULT/2, time2pixels(i),
675 total_height, color, color, color, thickness);
584 676
585 i += 10000000; 677 i += 10000000;
586 } 678 }
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 @@
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
8extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
9extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 10extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 11extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
9extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 12extern 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);
16extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 19extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
17 20
18 21
19extern void svg_time_grid(void); 22extern void svg_time_grid(double min_thickness);
23extern void svg_io_legenda(void);
20extern void svg_legenda(void); 24extern void svg_legenda(void);
21extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); 25extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
22extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); 26extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);