diff options
-rw-r--r-- | tools/perf/Documentation/perf-timechart.txt | 25 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 620 | ||||
-rw-r--r-- | tools/perf/util/svghelper.c | 98 | ||||
-rw-r--r-- | tools/perf/util/svghelper.h | 6 |
4 files changed, 725 insertions, 24 deletions
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index 5e0f986dff38..ec6b46c7bca0 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt | |||
@@ -15,10 +15,20 @@ DESCRIPTION | |||
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 | ----------------- |
@@ -63,6 +73,9 @@ RECORD OPTIONS | |||
63 | -T:: | 73 | -T:: |
64 | --tasks-only:: | 74 | --tasks-only:: |
65 | Record only tasks-related events | 75 | Record only tasks-related events |
76 | -I:: | ||
77 | --io-only:: | ||
78 | Record only io-related events | ||
66 | -g:: | 79 | -g:: |
67 | --callchain:: | 80 | --callchain:: |
68 | Do call-graph (stack chain/backtrace) recording | 81 | Do call-graph (stack chain/backtrace) recording |
@@ -87,6 +100,14 @@ Record system-wide timechart: | |||
87 | 100 | ||
88 | $ perf timechart --highlight gcc | 101 | $ perf timechart --highlight gcc |
89 | 102 | ||
103 | Record system-wide IO events: | ||
104 | |||
105 | $ perf timechart record -I | ||
106 | |||
107 | then generate timechart: | ||
108 | |||
109 | $ perf timechart | ||
110 | |||
90 | SEE ALSO | 111 | SEE ALSO |
91 | -------- | 112 | -------- |
92 | linkperf:perf-record[1] | 113 | linkperf:perf-record[1] |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 74db2568b867..4079062d25b0 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -60,10 +60,14 @@ 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; | ||
63 | }; | 66 | }; |
64 | 67 | ||
65 | struct per_pidcomm; | 68 | struct per_pidcomm; |
66 | struct cpu_sample; | 69 | struct cpu_sample; |
70 | struct io_sample; | ||
67 | 71 | ||
68 | /* | 72 | /* |
69 | * Datastructure layout: | 73 | * Datastructure layout: |
@@ -84,6 +88,7 @@ struct per_pid { | |||
84 | u64 start_time; | 88 | u64 start_time; |
85 | u64 end_time; | 89 | u64 end_time; |
86 | u64 total_time; | 90 | u64 total_time; |
91 | u64 total_bytes; | ||
87 | int display; | 92 | int display; |
88 | 93 | ||
89 | struct per_pidcomm *all; | 94 | struct per_pidcomm *all; |
@@ -97,6 +102,8 @@ struct per_pidcomm { | |||
97 | u64 start_time; | 102 | u64 start_time; |
98 | u64 end_time; | 103 | u64 end_time; |
99 | u64 total_time; | 104 | u64 total_time; |
105 | u64 max_bytes; | ||
106 | u64 total_bytes; | ||
100 | 107 | ||
101 | int Y; | 108 | int Y; |
102 | int display; | 109 | int display; |
@@ -107,6 +114,7 @@ struct per_pidcomm { | |||
107 | char *comm; | 114 | char *comm; |
108 | 115 | ||
109 | struct cpu_sample *samples; | 116 | struct cpu_sample *samples; |
117 | struct io_sample *io_samples; | ||
110 | }; | 118 | }; |
111 | 119 | ||
112 | struct sample_wrapper { | 120 | struct sample_wrapper { |
@@ -131,6 +139,27 @@ struct cpu_sample { | |||
131 | const char *backtrace; | 139 | const char *backtrace; |
132 | }; | 140 | }; |
133 | 141 | ||
142 | enum { | ||
143 | IOTYPE_READ, | ||
144 | IOTYPE_WRITE, | ||
145 | IOTYPE_SYNC, | ||
146 | IOTYPE_TX, | ||
147 | IOTYPE_RX, | ||
148 | IOTYPE_POLL, | ||
149 | }; | ||
150 | |||
151 | struct io_sample { | ||
152 | struct io_sample *next; | ||
153 | |||
154 | u64 start_time; | ||
155 | u64 end_time; | ||
156 | u64 bytes; | ||
157 | int type; | ||
158 | int fd; | ||
159 | int err; | ||
160 | int merges; | ||
161 | }; | ||
162 | |||
134 | #define CSTATE 1 | 163 | #define CSTATE 1 |
135 | #define PSTATE 2 | 164 | #define PSTATE 2 |
136 | 165 | ||
@@ -682,6 +711,219 @@ static void end_sample_processing(struct timechart *tchart) | |||
682 | } | 711 | } |
683 | } | 712 | } |
684 | 713 | ||
714 | static int pid_begin_io_sample(struct timechart *tchart, int pid, int type, | ||
715 | u64 start, int fd) | ||
716 | { | ||
717 | struct per_pid *p = find_create_pid(tchart, pid); | ||
718 | struct per_pidcomm *c = p->current; | ||
719 | struct io_sample *sample; | ||
720 | struct io_sample *prev; | ||
721 | |||
722 | if (!c) { | ||
723 | c = zalloc(sizeof(*c)); | ||
724 | if (!c) | ||
725 | return -ENOMEM; | ||
726 | p->current = c; | ||
727 | c->next = p->all; | ||
728 | p->all = c; | ||
729 | } | ||
730 | |||
731 | prev = c->io_samples; | ||
732 | |||
733 | if (prev && prev->start_time && !prev->end_time) { | ||
734 | pr_warning("Skip invalid start event: " | ||
735 | "previous event already started!\n"); | ||
736 | |||
737 | /* remove previous event that has been started, | ||
738 | * we are not sure we will ever get an end for it */ | ||
739 | c->io_samples = prev->next; | ||
740 | free(prev); | ||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | sample = zalloc(sizeof(*sample)); | ||
745 | if (!sample) | ||
746 | return -ENOMEM; | ||
747 | sample->start_time = start; | ||
748 | sample->type = type; | ||
749 | sample->fd = fd; | ||
750 | sample->next = c->io_samples; | ||
751 | c->io_samples = sample; | ||
752 | |||
753 | if (c->start_time == 0 || c->start_time > start) | ||
754 | c->start_time = start; | ||
755 | |||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int pid_end_io_sample(struct timechart *tchart, int pid, int type, | ||
760 | u64 end, long ret) | ||
761 | { | ||
762 | struct per_pid *p = find_create_pid(tchart, pid); | ||
763 | struct per_pidcomm *c = p->current; | ||
764 | struct io_sample *sample; | ||
765 | |||
766 | if (!c) { | ||
767 | pr_warning("Invalid pidcomm!\n"); | ||
768 | return -1; | ||
769 | } | ||
770 | |||
771 | sample = c->io_samples; | ||
772 | |||
773 | if (!sample) /* skip partially captured events */ | ||
774 | return 0; | ||
775 | |||
776 | if (sample->end_time) { | ||
777 | pr_warning("Skip invalid end event: " | ||
778 | "previous event already ended!\n"); | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | if (sample->type != type) { | ||
783 | pr_warning("Skip invalid end event: invalid event type!\n"); | ||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | sample->end_time = end; | ||
788 | |||
789 | if (ret < 0) { | ||
790 | sample->err = ret; | ||
791 | } else if (type == IOTYPE_READ || type == IOTYPE_WRITE || | ||
792 | type == IOTYPE_TX || type == IOTYPE_RX) { | ||
793 | |||
794 | if ((u64)ret > c->max_bytes) | ||
795 | c->max_bytes = ret; | ||
796 | |||
797 | c->total_bytes += ret; | ||
798 | p->total_bytes += ret; | ||
799 | sample->bytes = ret; | ||
800 | } | ||
801 | |||
802 | tchart->io_events++; | ||
803 | |||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | static int | ||
808 | process_enter_read(struct timechart *tchart, | ||
809 | struct perf_evsel *evsel, | ||
810 | struct perf_sample *sample) | ||
811 | { | ||
812 | long fd = perf_evsel__intval(evsel, sample, "fd"); | ||
813 | return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ, | ||
814 | sample->time, fd); | ||
815 | } | ||
816 | |||
817 | static int | ||
818 | process_exit_read(struct timechart *tchart, | ||
819 | struct perf_evsel *evsel, | ||
820 | struct perf_sample *sample) | ||
821 | { | ||
822 | long ret = perf_evsel__intval(evsel, sample, "ret"); | ||
823 | return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ, | ||
824 | sample->time, ret); | ||
825 | } | ||
826 | |||
827 | static int | ||
828 | process_enter_write(struct timechart *tchart, | ||
829 | struct perf_evsel *evsel, | ||
830 | struct perf_sample *sample) | ||
831 | { | ||
832 | long fd = perf_evsel__intval(evsel, sample, "fd"); | ||
833 | return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE, | ||
834 | sample->time, fd); | ||
835 | } | ||
836 | |||
837 | static int | ||
838 | process_exit_write(struct timechart *tchart, | ||
839 | struct perf_evsel *evsel, | ||
840 | struct perf_sample *sample) | ||
841 | { | ||
842 | long ret = perf_evsel__intval(evsel, sample, "ret"); | ||
843 | return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE, | ||
844 | sample->time, ret); | ||
845 | } | ||
846 | |||
847 | static int | ||
848 | process_enter_sync(struct timechart *tchart, | ||
849 | struct perf_evsel *evsel, | ||
850 | struct perf_sample *sample) | ||
851 | { | ||
852 | long fd = perf_evsel__intval(evsel, sample, "fd"); | ||
853 | return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC, | ||
854 | sample->time, fd); | ||
855 | } | ||
856 | |||
857 | static int | ||
858 | process_exit_sync(struct timechart *tchart, | ||
859 | struct perf_evsel *evsel, | ||
860 | struct perf_sample *sample) | ||
861 | { | ||
862 | long ret = perf_evsel__intval(evsel, sample, "ret"); | ||
863 | return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC, | ||
864 | sample->time, ret); | ||
865 | } | ||
866 | |||
867 | static int | ||
868 | process_enter_tx(struct timechart *tchart, | ||
869 | struct perf_evsel *evsel, | ||
870 | struct perf_sample *sample) | ||
871 | { | ||
872 | long fd = perf_evsel__intval(evsel, sample, "fd"); | ||
873 | return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX, | ||
874 | sample->time, fd); | ||
875 | } | ||
876 | |||
877 | static int | ||
878 | process_exit_tx(struct timechart *tchart, | ||
879 | struct perf_evsel *evsel, | ||
880 | struct perf_sample *sample) | ||
881 | { | ||
882 | long ret = perf_evsel__intval(evsel, sample, "ret"); | ||
883 | return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX, | ||
884 | sample->time, ret); | ||
885 | } | ||
886 | |||
887 | static int | ||
888 | process_enter_rx(struct timechart *tchart, | ||
889 | struct perf_evsel *evsel, | ||
890 | struct perf_sample *sample) | ||
891 | { | ||
892 | long fd = perf_evsel__intval(evsel, sample, "fd"); | ||
893 | return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX, | ||
894 | sample->time, fd); | ||
895 | } | ||
896 | |||
897 | static int | ||
898 | process_exit_rx(struct timechart *tchart, | ||
899 | struct perf_evsel *evsel, | ||
900 | struct perf_sample *sample) | ||
901 | { | ||
902 | long ret = perf_evsel__intval(evsel, sample, "ret"); | ||
903 | return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX, | ||
904 | sample->time, ret); | ||
905 | } | ||
906 | |||
907 | static int | ||
908 | process_enter_poll(struct timechart *tchart, | ||
909 | struct perf_evsel *evsel, | ||
910 | struct perf_sample *sample) | ||
911 | { | ||
912 | long fd = perf_evsel__intval(evsel, sample, "fd"); | ||
913 | return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL, | ||
914 | sample->time, fd); | ||
915 | } | ||
916 | |||
917 | static int | ||
918 | process_exit_poll(struct timechart *tchart, | ||
919 | struct perf_evsel *evsel, | ||
920 | struct perf_sample *sample) | ||
921 | { | ||
922 | long ret = perf_evsel__intval(evsel, sample, "ret"); | ||
923 | return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL, | ||
924 | sample->time, ret); | ||
925 | } | ||
926 | |||
685 | /* | 927 | /* |
686 | * Sort the pid datastructure | 928 | * Sort the pid datastructure |
687 | */ | 929 | */ |
@@ -852,6 +1094,117 @@ static void draw_cpu_usage(struct timechart *tchart) | |||
852 | } | 1094 | } |
853 | } | 1095 | } |
854 | 1096 | ||
1097 | static void draw_io_bars(struct timechart *tchart) | ||
1098 | { | ||
1099 | const char *suf; | ||
1100 | double bytes; | ||
1101 | char comm[256]; | ||
1102 | struct per_pid *p; | ||
1103 | struct per_pidcomm *c; | ||
1104 | struct io_sample *sample; | ||
1105 | int Y = 1; | ||
1106 | |||
1107 | p = tchart->all_data; | ||
1108 | while (p) { | ||
1109 | c = p->all; | ||
1110 | while (c) { | ||
1111 | if (!c->display) { | ||
1112 | c->Y = 0; | ||
1113 | c = c->next; | ||
1114 | continue; | ||
1115 | } | ||
1116 | |||
1117 | svg_box(Y, c->start_time, c->end_time, "process3"); | ||
1118 | sample = c->io_samples; | ||
1119 | for (sample = c->io_samples; sample; sample = sample->next) { | ||
1120 | double h = (double)sample->bytes / c->max_bytes; | ||
1121 | |||
1122 | if (sample->err) | ||
1123 | h = 1; | ||
1124 | |||
1125 | if (sample->type == IOTYPE_SYNC) | ||
1126 | svg_fbox(Y, | ||
1127 | sample->start_time, | ||
1128 | sample->end_time, | ||
1129 | 1, | ||
1130 | sample->err ? "error" : "sync", | ||
1131 | sample->fd, | ||
1132 | sample->err, | ||
1133 | sample->merges); | ||
1134 | else if (sample->type == IOTYPE_POLL) | ||
1135 | svg_fbox(Y, | ||
1136 | sample->start_time, | ||
1137 | sample->end_time, | ||
1138 | 1, | ||
1139 | sample->err ? "error" : "poll", | ||
1140 | sample->fd, | ||
1141 | sample->err, | ||
1142 | sample->merges); | ||
1143 | else if (sample->type == IOTYPE_READ) | ||
1144 | svg_ubox(Y, | ||
1145 | sample->start_time, | ||
1146 | sample->end_time, | ||
1147 | h, | ||
1148 | sample->err ? "error" : "disk", | ||
1149 | sample->fd, | ||
1150 | sample->err, | ||
1151 | sample->merges); | ||
1152 | else if (sample->type == IOTYPE_WRITE) | ||
1153 | svg_lbox(Y, | ||
1154 | sample->start_time, | ||
1155 | sample->end_time, | ||
1156 | h, | ||
1157 | sample->err ? "error" : "disk", | ||
1158 | sample->fd, | ||
1159 | sample->err, | ||
1160 | sample->merges); | ||
1161 | else if (sample->type == IOTYPE_RX) | ||
1162 | svg_ubox(Y, | ||
1163 | sample->start_time, | ||
1164 | sample->end_time, | ||
1165 | h, | ||
1166 | sample->err ? "error" : "net", | ||
1167 | sample->fd, | ||
1168 | sample->err, | ||
1169 | sample->merges); | ||
1170 | else if (sample->type == IOTYPE_TX) | ||
1171 | svg_lbox(Y, | ||
1172 | sample->start_time, | ||
1173 | sample->end_time, | ||
1174 | h, | ||
1175 | sample->err ? "error" : "net", | ||
1176 | sample->fd, | ||
1177 | sample->err, | ||
1178 | sample->merges); | ||
1179 | } | ||
1180 | |||
1181 | suf = ""; | ||
1182 | bytes = c->total_bytes; | ||
1183 | if (bytes > 1024) { | ||
1184 | bytes = bytes / 1024; | ||
1185 | suf = "K"; | ||
1186 | } | ||
1187 | if (bytes > 1024) { | ||
1188 | bytes = bytes / 1024; | ||
1189 | suf = "M"; | ||
1190 | } | ||
1191 | if (bytes > 1024) { | ||
1192 | bytes = bytes / 1024; | ||
1193 | suf = "G"; | ||
1194 | } | ||
1195 | |||
1196 | |||
1197 | sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf); | ||
1198 | svg_text(Y, c->start_time, comm); | ||
1199 | |||
1200 | c->Y = Y; | ||
1201 | Y++; | ||
1202 | c = c->next; | ||
1203 | } | ||
1204 | p = p->next; | ||
1205 | } | ||
1206 | } | ||
1207 | |||
855 | static void draw_process_bars(struct timechart *tchart) | 1208 | static void draw_process_bars(struct timechart *tchart) |
856 | { | 1209 | { |
857 | struct per_pid *p; | 1210 | struct per_pid *p; |
@@ -987,9 +1340,6 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold) | |||
987 | struct per_pidcomm *c; | 1340 | struct per_pidcomm *c; |
988 | int count = 0; | 1341 | int count = 0; |
989 | 1342 | ||
990 | if (process_filter) | ||
991 | return determine_display_tasks_filtered(tchart); | ||
992 | |||
993 | p = tchart->all_data; | 1343 | p = tchart->all_data; |
994 | while (p) { | 1344 | while (p) { |
995 | p->display = 0; | 1345 | p->display = 0; |
@@ -1025,15 +1375,46 @@ static int determine_display_tasks(struct timechart *tchart, u64 threshold) | |||
1025 | return count; | 1375 | return count; |
1026 | } | 1376 | } |
1027 | 1377 | ||
1378 | static int determine_display_io_tasks(struct timechart *timechart, u64 threshold) | ||
1379 | { | ||
1380 | struct per_pid *p; | ||
1381 | struct per_pidcomm *c; | ||
1382 | int count = 0; | ||
1383 | |||
1384 | p = timechart->all_data; | ||
1385 | while (p) { | ||
1386 | /* no exit marker, task kept running to the end */ | ||
1387 | if (p->end_time == 0) | ||
1388 | p->end_time = timechart->last_time; | ||
1389 | |||
1390 | c = p->all; | ||
1391 | |||
1392 | while (c) { | ||
1393 | c->display = 0; | ||
1394 | |||
1395 | if (c->total_bytes >= threshold) { | ||
1396 | c->display = 1; | ||
1397 | count++; | ||
1398 | } | ||
1028 | 1399 | ||
1400 | if (c->end_time == 0) | ||
1401 | c->end_time = timechart->last_time; | ||
1402 | |||
1403 | c = c->next; | ||
1404 | } | ||
1405 | p = p->next; | ||
1406 | } | ||
1407 | return count; | ||
1408 | } | ||
1029 | 1409 | ||
1410 | #define BYTES_THRESH (1 * 1024 * 1024) | ||
1030 | #define TIME_THRESH 10000000 | 1411 | #define TIME_THRESH 10000000 |
1031 | 1412 | ||
1032 | static void write_svg_file(struct timechart *tchart, const char *filename) | 1413 | static void write_svg_file(struct timechart *tchart, const char *filename) |
1033 | { | 1414 | { |
1034 | u64 i; | 1415 | u64 i; |
1035 | int count; | 1416 | int count; |
1036 | int thresh = TIME_THRESH; | 1417 | int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH; |
1037 | 1418 | ||
1038 | if (tchart->power_only) | 1419 | if (tchart->power_only) |
1039 | tchart->proc_num = 0; | 1420 | tchart->proc_num = 0; |
@@ -1041,28 +1422,43 @@ static void write_svg_file(struct timechart *tchart, const char *filename) | |||
1041 | /* We'd like to show at least proc_num tasks; | 1422 | /* We'd like to show at least proc_num tasks; |
1042 | * be less picky if we have fewer */ | 1423 | * be less picky if we have fewer */ |
1043 | do { | 1424 | do { |
1044 | count = determine_display_tasks(tchart, thresh); | 1425 | if (process_filter) |
1426 | count = determine_display_tasks_filtered(tchart); | ||
1427 | else if (tchart->io_events) | ||
1428 | count = determine_display_io_tasks(tchart, thresh); | ||
1429 | else | ||
1430 | count = determine_display_tasks(tchart, thresh); | ||
1045 | thresh /= 10; | 1431 | thresh /= 10; |
1046 | } while (!process_filter && thresh && count < tchart->proc_num); | 1432 | } while (!process_filter && thresh && count < tchart->proc_num); |
1047 | 1433 | ||
1048 | if (!tchart->proc_num) | 1434 | if (!tchart->proc_num) |
1049 | count = 0; | 1435 | count = 0; |
1050 | 1436 | ||
1051 | open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); | 1437 | if (tchart->io_events) { |
1438 | open_svg(filename, 0, count, tchart->first_time, tchart->last_time); | ||
1052 | 1439 | ||
1053 | svg_time_grid(); | 1440 | svg_time_grid(0.5); |
1054 | svg_legenda(); | 1441 | svg_io_legenda(); |
1055 | 1442 | ||
1056 | for (i = 0; i < tchart->numcpus; i++) | 1443 | draw_io_bars(tchart); |
1057 | svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); | 1444 | } else { |
1445 | open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); | ||
1058 | 1446 | ||
1059 | draw_cpu_usage(tchart); | 1447 | svg_time_grid(0); |
1060 | if (tchart->proc_num) | 1448 | |
1061 | draw_process_bars(tchart); | 1449 | svg_legenda(); |
1062 | if (!tchart->tasks_only) | 1450 | |
1063 | draw_c_p_states(tchart); | 1451 | for (i = 0; i < tchart->numcpus; i++) |
1064 | if (tchart->proc_num) | 1452 | svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); |
1065 | draw_wakeups(tchart); | 1453 | |
1454 | draw_cpu_usage(tchart); | ||
1455 | if (tchart->proc_num) | ||
1456 | draw_process_bars(tchart); | ||
1457 | if (!tchart->tasks_only) | ||
1458 | draw_c_p_states(tchart); | ||
1459 | if (tchart->proc_num) | ||
1460 | draw_wakeups(tchart); | ||
1461 | } | ||
1066 | 1462 | ||
1067 | svg_close(); | 1463 | svg_close(); |
1068 | } | 1464 | } |
@@ -1110,6 +1506,56 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) | |||
1110 | { "power:power_end", process_sample_power_end }, | 1506 | { "power:power_end", process_sample_power_end }, |
1111 | { "power:power_frequency", process_sample_power_frequency }, | 1507 | { "power:power_frequency", process_sample_power_frequency }, |
1112 | #endif | 1508 | #endif |
1509 | |||
1510 | { "syscalls:sys_enter_read", process_enter_read }, | ||
1511 | { "syscalls:sys_enter_pread64", process_enter_read }, | ||
1512 | { "syscalls:sys_enter_readv", process_enter_read }, | ||
1513 | { "syscalls:sys_enter_preadv", process_enter_read }, | ||
1514 | { "syscalls:sys_enter_write", process_enter_write }, | ||
1515 | { "syscalls:sys_enter_pwrite64", process_enter_write }, | ||
1516 | { "syscalls:sys_enter_writev", process_enter_write }, | ||
1517 | { "syscalls:sys_enter_pwritev", process_enter_write }, | ||
1518 | { "syscalls:sys_enter_sync", process_enter_sync }, | ||
1519 | { "syscalls:sys_enter_sync_file_range", process_enter_sync }, | ||
1520 | { "syscalls:sys_enter_fsync", process_enter_sync }, | ||
1521 | { "syscalls:sys_enter_msync", process_enter_sync }, | ||
1522 | { "syscalls:sys_enter_recvfrom", process_enter_rx }, | ||
1523 | { "syscalls:sys_enter_recvmmsg", process_enter_rx }, | ||
1524 | { "syscalls:sys_enter_recvmsg", process_enter_rx }, | ||
1525 | { "syscalls:sys_enter_sendto", process_enter_tx }, | ||
1526 | { "syscalls:sys_enter_sendmsg", process_enter_tx }, | ||
1527 | { "syscalls:sys_enter_sendmmsg", process_enter_tx }, | ||
1528 | { "syscalls:sys_enter_epoll_pwait", process_enter_poll }, | ||
1529 | { "syscalls:sys_enter_epoll_wait", process_enter_poll }, | ||
1530 | { "syscalls:sys_enter_poll", process_enter_poll }, | ||
1531 | { "syscalls:sys_enter_ppoll", process_enter_poll }, | ||
1532 | { "syscalls:sys_enter_pselect6", process_enter_poll }, | ||
1533 | { "syscalls:sys_enter_select", process_enter_poll }, | ||
1534 | |||
1535 | { "syscalls:sys_exit_read", process_exit_read }, | ||
1536 | { "syscalls:sys_exit_pread64", process_exit_read }, | ||
1537 | { "syscalls:sys_exit_readv", process_exit_read }, | ||
1538 | { "syscalls:sys_exit_preadv", process_exit_read }, | ||
1539 | { "syscalls:sys_exit_write", process_exit_write }, | ||
1540 | { "syscalls:sys_exit_pwrite64", process_exit_write }, | ||
1541 | { "syscalls:sys_exit_writev", process_exit_write }, | ||
1542 | { "syscalls:sys_exit_pwritev", process_exit_write }, | ||
1543 | { "syscalls:sys_exit_sync", process_exit_sync }, | ||
1544 | { "syscalls:sys_exit_sync_file_range", process_exit_sync }, | ||
1545 | { "syscalls:sys_exit_fsync", process_exit_sync }, | ||
1546 | { "syscalls:sys_exit_msync", process_exit_sync }, | ||
1547 | { "syscalls:sys_exit_recvfrom", process_exit_rx }, | ||
1548 | { "syscalls:sys_exit_recvmmsg", process_exit_rx }, | ||
1549 | { "syscalls:sys_exit_recvmsg", process_exit_rx }, | ||
1550 | { "syscalls:sys_exit_sendto", process_exit_tx }, | ||
1551 | { "syscalls:sys_exit_sendmsg", process_exit_tx }, | ||
1552 | { "syscalls:sys_exit_sendmmsg", process_exit_tx }, | ||
1553 | { "syscalls:sys_exit_epoll_pwait", process_exit_poll }, | ||
1554 | { "syscalls:sys_exit_epoll_wait", process_exit_poll }, | ||
1555 | { "syscalls:sys_exit_poll", process_exit_poll }, | ||
1556 | { "syscalls:sys_exit_ppoll", process_exit_poll }, | ||
1557 | { "syscalls:sys_exit_pselect6", process_exit_poll }, | ||
1558 | { "syscalls:sys_exit_select", process_exit_poll }, | ||
1113 | }; | 1559 | }; |
1114 | struct perf_data_file file = { | 1560 | struct perf_data_file file = { |
1115 | .path = input_name, | 1561 | .path = input_name, |
@@ -1154,6 +1600,139 @@ out_delete: | |||
1154 | return ret; | 1600 | return ret; |
1155 | } | 1601 | } |
1156 | 1602 | ||
1603 | static int timechart__io_record(int argc, const char **argv) | ||
1604 | { | ||
1605 | unsigned int rec_argc, i; | ||
1606 | const char **rec_argv; | ||
1607 | const char **p; | ||
1608 | char *filter = NULL; | ||
1609 | |||
1610 | const char * const common_args[] = { | ||
1611 | "record", "-a", "-R", "-c", "1", | ||
1612 | }; | ||
1613 | unsigned int common_args_nr = ARRAY_SIZE(common_args); | ||
1614 | |||
1615 | const char * const disk_events[] = { | ||
1616 | "syscalls:sys_enter_read", | ||
1617 | "syscalls:sys_enter_pread64", | ||
1618 | "syscalls:sys_enter_readv", | ||
1619 | "syscalls:sys_enter_preadv", | ||
1620 | "syscalls:sys_enter_write", | ||
1621 | "syscalls:sys_enter_pwrite64", | ||
1622 | "syscalls:sys_enter_writev", | ||
1623 | "syscalls:sys_enter_pwritev", | ||
1624 | "syscalls:sys_enter_sync", | ||
1625 | "syscalls:sys_enter_sync_file_range", | ||
1626 | "syscalls:sys_enter_fsync", | ||
1627 | "syscalls:sys_enter_msync", | ||
1628 | |||
1629 | "syscalls:sys_exit_read", | ||
1630 | "syscalls:sys_exit_pread64", | ||
1631 | "syscalls:sys_exit_readv", | ||
1632 | "syscalls:sys_exit_preadv", | ||
1633 | "syscalls:sys_exit_write", | ||
1634 | "syscalls:sys_exit_pwrite64", | ||
1635 | "syscalls:sys_exit_writev", | ||
1636 | "syscalls:sys_exit_pwritev", | ||
1637 | "syscalls:sys_exit_sync", | ||
1638 | "syscalls:sys_exit_sync_file_range", | ||
1639 | "syscalls:sys_exit_fsync", | ||
1640 | "syscalls:sys_exit_msync", | ||
1641 | }; | ||
1642 | unsigned int disk_events_nr = ARRAY_SIZE(disk_events); | ||
1643 | |||
1644 | const char * const net_events[] = { | ||
1645 | "syscalls:sys_enter_recvfrom", | ||
1646 | "syscalls:sys_enter_recvmmsg", | ||
1647 | "syscalls:sys_enter_recvmsg", | ||
1648 | "syscalls:sys_enter_sendto", | ||
1649 | "syscalls:sys_enter_sendmsg", | ||
1650 | "syscalls:sys_enter_sendmmsg", | ||
1651 | |||
1652 | "syscalls:sys_exit_recvfrom", | ||
1653 | "syscalls:sys_exit_recvmmsg", | ||
1654 | "syscalls:sys_exit_recvmsg", | ||
1655 | "syscalls:sys_exit_sendto", | ||
1656 | "syscalls:sys_exit_sendmsg", | ||
1657 | "syscalls:sys_exit_sendmmsg", | ||
1658 | }; | ||
1659 | unsigned int net_events_nr = ARRAY_SIZE(net_events); | ||
1660 | |||
1661 | const char * const poll_events[] = { | ||
1662 | "syscalls:sys_enter_epoll_pwait", | ||
1663 | "syscalls:sys_enter_epoll_wait", | ||
1664 | "syscalls:sys_enter_poll", | ||
1665 | "syscalls:sys_enter_ppoll", | ||
1666 | "syscalls:sys_enter_pselect6", | ||
1667 | "syscalls:sys_enter_select", | ||
1668 | |||
1669 | "syscalls:sys_exit_epoll_pwait", | ||
1670 | "syscalls:sys_exit_epoll_wait", | ||
1671 | "syscalls:sys_exit_poll", | ||
1672 | "syscalls:sys_exit_ppoll", | ||
1673 | "syscalls:sys_exit_pselect6", | ||
1674 | "syscalls:sys_exit_select", | ||
1675 | }; | ||
1676 | unsigned int poll_events_nr = ARRAY_SIZE(poll_events); | ||
1677 | |||
1678 | rec_argc = common_args_nr + | ||
1679 | disk_events_nr * 4 + | ||
1680 | net_events_nr * 4 + | ||
1681 | poll_events_nr * 4 + | ||
1682 | argc; | ||
1683 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | ||
1684 | |||
1685 | if (rec_argv == NULL) | ||
1686 | return -ENOMEM; | ||
1687 | |||
1688 | if (asprintf(&filter, "common_pid != %d", getpid()) < 0) | ||
1689 | return -ENOMEM; | ||
1690 | |||
1691 | p = rec_argv; | ||
1692 | for (i = 0; i < common_args_nr; i++) | ||
1693 | *p++ = strdup(common_args[i]); | ||
1694 | |||
1695 | for (i = 0; i < disk_events_nr; i++) { | ||
1696 | if (!is_valid_tracepoint(disk_events[i])) { | ||
1697 | rec_argc -= 4; | ||
1698 | continue; | ||
1699 | } | ||
1700 | |||
1701 | *p++ = "-e"; | ||
1702 | *p++ = strdup(disk_events[i]); | ||
1703 | *p++ = "--filter"; | ||
1704 | *p++ = filter; | ||
1705 | } | ||
1706 | for (i = 0; i < net_events_nr; i++) { | ||
1707 | if (!is_valid_tracepoint(net_events[i])) { | ||
1708 | rec_argc -= 4; | ||
1709 | continue; | ||
1710 | } | ||
1711 | |||
1712 | *p++ = "-e"; | ||
1713 | *p++ = strdup(net_events[i]); | ||
1714 | *p++ = "--filter"; | ||
1715 | *p++ = filter; | ||
1716 | } | ||
1717 | for (i = 0; i < poll_events_nr; i++) { | ||
1718 | if (!is_valid_tracepoint(poll_events[i])) { | ||
1719 | rec_argc -= 4; | ||
1720 | continue; | ||
1721 | } | ||
1722 | |||
1723 | *p++ = "-e"; | ||
1724 | *p++ = strdup(poll_events[i]); | ||
1725 | *p++ = "--filter"; | ||
1726 | *p++ = filter; | ||
1727 | } | ||
1728 | |||
1729 | for (i = 0; i < (unsigned int)argc; i++) | ||
1730 | *p++ = argv[i]; | ||
1731 | |||
1732 | return cmd_record(rec_argc, rec_argv, NULL); | ||
1733 | } | ||
1734 | |||
1735 | |||
1157 | static int timechart__record(struct timechart *tchart, int argc, const char **argv) | 1736 | static int timechart__record(struct timechart *tchart, int argc, const char **argv) |
1158 | { | 1737 | { |
1159 | unsigned int rec_argc, i, j; | 1738 | unsigned int rec_argc, i, j; |
@@ -1314,6 +1893,8 @@ int cmd_timechart(int argc, const char **argv, | |||
1314 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), | 1893 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), |
1315 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, | 1894 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, |
1316 | "output processes data only"), | 1895 | "output processes data only"), |
1896 | OPT_BOOLEAN('I', "io-only", &tchart.io_only, | ||
1897 | "record only IO data"), | ||
1317 | OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), | 1898 | OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), |
1318 | OPT_END() | 1899 | OPT_END() |
1319 | }; | 1900 | }; |
@@ -1340,7 +1921,10 @@ int cmd_timechart(int argc, const char **argv, | |||
1340 | return -1; | 1921 | return -1; |
1341 | } | 1922 | } |
1342 | 1923 | ||
1343 | return timechart__record(&tchart, argc, argv); | 1924 | if (tchart.io_only) |
1925 | return timechart__io_record(argc, argv); | ||
1926 | else | ||
1927 | return timechart__record(&tchart, argc, argv); | ||
1344 | } else if (argc) | 1928 | } else if (argc) |
1345 | usage_with_options(timechart_usage, timechart_options); | 1929 | usage_with_options(timechart_usage, timechart_options); |
1346 | 1930 | ||
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 27caf0f45469..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,6 +139,75 @@ 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) |
@@ -543,6 +619,20 @@ static void svg_legenda_box(int X, const char *text, const char *style) | |||
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=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.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); |