diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-07-16 07:48:13 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-07-16 07:48:13 -0400 |
commit | ff2ebe46e15bd49d52b9c2f3fc77f3a9d94eac7b (patch) | |
tree | 87a4ec640a5cec0b09135c5340815e2674beb19e | |
parent | f4aa84fc2a1c3a1ae1b81e434e8cde1c5f98a6b4 (diff) | |
parent | d243144af0b52fc5164a0823194f29a5979e236c (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.txt | 38 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 693 | ||||
-rw-r--r-- | tools/perf/util/svghelper.c | 168 | ||||
-rw-r--r-- | tools/perf/util/svghelper.h | 6 |
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 | |||
15 | There are two variants of perf timechart: | 15 | There 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 | ||
23 | TIMECHART OPTIONS | 33 | TIMECHART 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 | ||
58 | RECORD OPTIONS | 81 | RECORD 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 | ||
116 | Record system-wide IO events: | ||
117 | |||
118 | $ perf timechart record -I | ||
119 | |||
120 | then generate timechart: | ||
121 | |||
122 | $ perf timechart | ||
123 | |||
90 | SEE ALSO | 124 | SEE ALSO |
91 | -------- | 125 | -------- |
92 | linkperf:perf-record[1] | 126 | linkperf: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 | ||
65 | struct per_pidcomm; | 71 | struct per_pidcomm; |
66 | struct cpu_sample; | 72 | struct cpu_sample; |
73 | struct 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 | ||
112 | struct sample_wrapper { | 123 | struct sample_wrapper { |
@@ -131,6 +142,27 @@ struct cpu_sample { | |||
131 | const char *backtrace; | 142 | const char *backtrace; |
132 | }; | 143 | }; |
133 | 144 | ||
145 | enum { | ||
146 | IOTYPE_READ, | ||
147 | IOTYPE_WRITE, | ||
148 | IOTYPE_SYNC, | ||
149 | IOTYPE_TX, | ||
150 | IOTYPE_RX, | ||
151 | IOTYPE_POLL, | ||
152 | }; | ||
153 | |||
154 | struct 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 | ||
717 | static 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 | |||
762 | static 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 | |||
840 | static int | ||
841 | process_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 | |||
850 | static int | ||
851 | process_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 | |||
860 | static int | ||
861 | process_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 | |||
870 | static int | ||
871 | process_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 | |||
880 | static int | ||
881 | process_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 | |||
890 | static int | ||
891 | process_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 | |||
900 | static int | ||
901 | process_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 | |||
910 | static int | ||
911 | process_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 | |||
920 | static int | ||
921 | process_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 | |||
930 | static int | ||
931 | process_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 | |||
940 | static int | ||
941 | process_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 | |||
950 | static int | ||
951 | process_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 | ||
1130 | static 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 | |||
855 | static void draw_process_bars(struct timechart *tchart) | 1245 | static 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 | ||
1415 | static 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 | ||
1032 | static void write_svg_file(struct timechart *tchart, const char *filename) | 1450 | static 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 | ||
1640 | static 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 | |||
1157 | static int timechart__record(struct timechart *tchart, int argc, const char **argv) | 1773 | static 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 | ||
1889 | static int | ||
1890 | parse_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 | |||
1273 | int cmd_timechart(int argc, const char **argv, | 1913 | int 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 | ||
34 | int svg_page_width = 1000; | 35 | int svg_page_width = 1000; |
35 | u64 svg_highlight; | 36 | u64 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 | ||
142 | static 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 | |||
154 | void 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 | |||
173 | void 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 | |||
192 | void 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 | |||
135 | void svg_box(int Yslot, u64 start, u64 end, const char *type) | 211 | void 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 ></text></g>\n", | 517 | fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s ></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 ></text></g>\n", | 524 | fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s ></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 <</text></g>\n", | 532 | fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s <</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 <</text></g>\n", | 539 | fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s <</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 | ||
622 | void 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 | |||
546 | void svg_legenda(void) | 636 | void 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 | ||
562 | void svg_time_grid(void) | 652 | void 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 | ||
6 | extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); | 6 | extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); |
7 | extern void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); | ||
8 | extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); | ||
9 | extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); | ||
7 | extern void svg_box(int Yslot, u64 start, u64 end, const char *type); | 10 | extern void svg_box(int Yslot, u64 start, u64 end, const char *type); |
8 | extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); | 11 | extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); |
9 | extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); | 12 | 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); | |||
16 | extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); | 19 | extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); |
17 | 20 | ||
18 | 21 | ||
19 | extern void svg_time_grid(void); | 22 | extern void svg_time_grid(double min_thickness); |
23 | extern void svg_io_legenda(void); | ||
20 | extern void svg_legenda(void); | 24 | extern void svg_legenda(void); |
21 | extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); | 25 | extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); |
22 | extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); | 26 | extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); |