aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-timechart.c
diff options
context:
space:
mode:
authorStanislav Fomichev <stfomichev@yandex-team.ru>2014-07-08 12:03:41 -0400
committerJiri Olsa <jolsa@kernel.org>2014-07-09 18:22:54 -0400
commitb97b59b93d10a54022afb06d5725d7aa55d98dd7 (patch)
tree8ded0d1011a71fc526b1d2d1a63005950669d81d /tools/perf/builtin-timechart.c
parentf8dda74fb4139f026571b46d8d17f67e75aa157c (diff)
perf timechart: Implement IO mode
Currently, timechart records only scheduler and CPU events (task switches, running times, CPU power states, etc); this commit adds IO mode which makes it possible to record IO (disk, network) activity. In this mode perf timechart will generate SVG with IO charts (writes, reads, tx, rx, polls). Signed-off-by: Stanislav Fomichev <stfomichev@yandex-team.ru> Acked-by: Namhyung Kim <namhyung@kernel.org> Link: http://lkml.kernel.org/n/1404835423-23098-3-git-send-email-stfomichev@yandex-team.ru Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r--tools/perf/builtin-timechart.c620
1 files changed, 602 insertions, 18 deletions
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
65struct per_pidcomm; 68struct per_pidcomm;
66struct cpu_sample; 69struct cpu_sample;
70struct 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
112struct sample_wrapper { 120struct sample_wrapper {
@@ -131,6 +139,27 @@ struct cpu_sample {
131 const char *backtrace; 139 const char *backtrace;
132}; 140};
133 141
142enum {
143 IOTYPE_READ,
144 IOTYPE_WRITE,
145 IOTYPE_SYNC,
146 IOTYPE_TX,
147 IOTYPE_RX,
148 IOTYPE_POLL,
149};
150
151struct 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
714static 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
759static 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
807static int
808process_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
817static int
818process_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
827static int
828process_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
837static int
838process_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
847static int
848process_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
857static int
858process_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
867static int
868process_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
877static int
878process_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
887static int
888process_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
897static int
898process_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
907static int
908process_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
917static int
918process_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
1097static 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
855static void draw_process_bars(struct timechart *tchart) 1208static 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
1378static 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
1032static void write_svg_file(struct timechart *tchart, const char *filename) 1413static 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
1603static 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
1157static int timechart__record(struct timechart *tchart, int argc, const char **argv) 1736static 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