aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Documentation/perf-timechart.txt13
-rw-r--r--tools/perf/builtin-timechart.c75
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
68RECORD OPTIONS 81RECORD 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
68struct per_pidcomm; 71struct 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
1889static int
1890parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
1891{
1892 char unit = 'n';
1893 u64 *value = opt->value;
1894
1895 if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) {
1896 switch (unit) {
1897 case 'm':
1898 *value *= 1000000;
1899 break;
1900 case 'u':
1901 *value *= 1000;
1902 break;
1903 case 'n':
1904 break;
1905 default:
1906 return -1;
1907 }
1908 }
1909
1910 return 0;
1911}
1912
1852int cmd_timechart(int argc, const char **argv, 1913int 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[] = {