diff options
-rw-r--r-- | tools/perf/Documentation/perf-timechart.txt | 13 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 75 |
2 files changed, 86 insertions, 2 deletions
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index ec6b46c7bca0..df98d1c82688 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt | |||
@@ -64,6 +64,19 @@ TIMECHART OPTIONS | |||
64 | 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 |
65 | 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 |
66 | 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. | ||
67 | 80 | ||
68 | RECORD OPTIONS | 81 | RECORD OPTIONS |
69 | -------------- | 82 | -------------- |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 37bf1eb0755f..04c9c53becad 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -62,7 +62,10 @@ struct timechart { | |||
62 | topology; | 62 | topology; |
63 | /* IO related settings */ | 63 | /* IO related settings */ |
64 | u64 io_events; | 64 | u64 io_events; |
65 | bool io_only; | 65 | bool io_only, |
66 | skip_eagain; | ||
67 | u64 min_time, | ||
68 | merge_dist; | ||
66 | }; | 69 | }; |
67 | 70 | ||
68 | struct per_pidcomm; | 71 | struct per_pidcomm; |
@@ -761,7 +764,7 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, | |||
761 | { | 764 | { |
762 | struct per_pid *p = find_create_pid(tchart, pid); | 765 | struct per_pid *p = find_create_pid(tchart, pid); |
763 | struct per_pidcomm *c = p->current; | 766 | struct per_pidcomm *c = p->current; |
764 | struct io_sample *sample; | 767 | struct io_sample *sample, *prev; |
765 | 768 | ||
766 | if (!c) { | 769 | if (!c) { |
767 | pr_warning("Invalid pidcomm!\n"); | 770 | pr_warning("Invalid pidcomm!\n"); |
@@ -785,6 +788,18 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, | |||
785 | } | 788 | } |
786 | 789 | ||
787 | sample->end_time = end; | 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 | } | ||
788 | 803 | ||
789 | if (ret < 0) { | 804 | if (ret < 0) { |
790 | sample->err = ret; | 805 | sample->err = ret; |
@@ -799,6 +814,24 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type, | |||
799 | sample->bytes = ret; | 814 | sample->bytes = ret; |
800 | } | 815 | } |
801 | 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 | |||
802 | tchart->io_events++; | 835 | tchart->io_events++; |
803 | 836 | ||
804 | return 0; | 837 | return 0; |
@@ -1119,6 +1152,10 @@ static void draw_io_bars(struct timechart *tchart) | |||
1119 | for (sample = c->io_samples; sample; sample = sample->next) { | 1152 | for (sample = c->io_samples; sample; sample = sample->next) { |
1120 | double h = (double)sample->bytes / c->max_bytes; | 1153 | double h = (double)sample->bytes / c->max_bytes; |
1121 | 1154 | ||
1155 | if (tchart->skip_eagain && | ||
1156 | sample->err == -EAGAIN) | ||
1157 | continue; | ||
1158 | |||
1122 | if (sample->err) | 1159 | if (sample->err) |
1123 | h = 1; | 1160 | h = 1; |
1124 | 1161 | ||
@@ -1849,6 +1886,30 @@ parse_highlight(const struct option *opt __maybe_unused, const char *arg, | |||
1849 | return 0; | 1886 | return 0; |
1850 | } | 1887 | } |
1851 | 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 | |||
1852 | int cmd_timechart(int argc, const char **argv, | 1913 | int cmd_timechart(int argc, const char **argv, |
1853 | const char *prefix __maybe_unused) | 1914 | const char *prefix __maybe_unused) |
1854 | { | 1915 | { |
@@ -1861,6 +1922,8 @@ int cmd_timechart(int argc, const char **argv, | |||
1861 | .ordered_samples = true, | 1922 | .ordered_samples = true, |
1862 | }, | 1923 | }, |
1863 | .proc_num = 15, | 1924 | .proc_num = 15, |
1925 | .min_time = 1000000, | ||
1926 | .merge_dist = 1000, | ||
1864 | }; | 1927 | }; |
1865 | const char *output_name = "output.svg"; | 1928 | const char *output_name = "output.svg"; |
1866 | const struct option timechart_options[] = { | 1929 | const struct option timechart_options[] = { |
@@ -1882,6 +1945,14 @@ int cmd_timechart(int argc, const char **argv, | |||
1882 | "min. number of tasks to print"), | 1945 | "min. number of tasks to print"), |
1883 | OPT_BOOLEAN('t', "topology", &tchart.topology, | 1946 | OPT_BOOLEAN('t', "topology", &tchart.topology, |
1884 | "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), | ||
1885 | OPT_END() | 1956 | OPT_END() |
1886 | }; | 1957 | }; |
1887 | const char * const timechart_usage[] = { | 1958 | const char * const timechart_usage[] = { |