Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+845 -60
+36 -2
tools/perf/Documentation/perf-timechart.txt
··· 15 15 There are two variants of perf timechart: 16 16 17 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 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 33 TIMECHART OPTIONS 24 34 ----------------- ··· 64 54 duration or tasks with given name. If number is given it's interpreted 65 55 as number of nanoseconds. If non-numeric string is given it's 66 56 interpreted as task name. 57 + --io-skip-eagain:: 58 + Don't draw EAGAIN IO events. 59 + --io-min-time=<nsecs>:: 60 + Draw small events as if they lasted min-time. Useful when you need 61 + to see very small and fast IO. It's possible to specify ms or us 62 + suffix to specify time in milliseconds or microseconds. 63 + Default value is 1ms. 64 + --io-merge-dist=<nsecs>:: 65 + Merge events that are merge-dist nanoseconds apart. 66 + Reduces number of figures on the SVG and makes it more render-friendly. 67 + It's possible to specify ms or us suffix to specify time in 68 + milliseconds or microseconds. 69 + Default value is 1us. 67 70 68 71 RECORD OPTIONS 69 72 -------------- ··· 86 63 -T:: 87 64 --tasks-only:: 88 65 Record only tasks-related events 66 + -I:: 67 + --io-only:: 68 + Record only io-related events 89 69 -g:: 90 70 --callchain:: 91 71 Do call-graph (stack chain/backtrace) recording ··· 112 86 then generate timechart and highlight 'gcc' tasks: 113 87 114 88 $ perf timechart --highlight gcc 89 + 90 + Record system-wide IO events: 91 + 92 + $ perf timechart record -I 93 + 94 + then generate timechart: 95 + 96 + $ perf timechart 115 97 116 98 SEE ALSO 117 99 --------
+674 -19
tools/perf/builtin-timechart.c
··· 60 60 tasks_only, 61 61 with_backtrace, 62 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 71 struct per_pidcomm; 66 72 struct cpu_sample; 73 + struct io_sample; 67 74 68 75 /* 69 76 * Datastructure layout: ··· 91 84 u64 start_time; 92 85 u64 end_time; 93 86 u64 total_time; 87 + u64 total_bytes; 94 88 int display; 95 89 96 90 struct per_pidcomm *all; ··· 105 97 u64 start_time; 106 98 u64 end_time; 107 99 u64 total_time; 100 + u64 max_bytes; 101 + u64 total_bytes; 108 102 109 103 int Y; 110 104 int display; ··· 117 107 char *comm; 118 108 119 109 struct cpu_sample *samples; 110 + struct io_sample *io_samples; 120 111 }; 121 112 122 113 struct sample_wrapper { ··· 140 129 int type; 141 130 int cpu; 142 131 const char *backtrace; 132 + }; 133 + 134 + enum { 135 + IOTYPE_READ, 136 + IOTYPE_WRITE, 137 + IOTYPE_SYNC, 138 + IOTYPE_TX, 139 + IOTYPE_RX, 140 + IOTYPE_POLL, 141 + }; 142 + 143 + struct io_sample { 144 + struct io_sample *next; 145 + 146 + u64 start_time; 147 + u64 end_time; 148 + u64 bytes; 149 + int type; 150 + int fd; 151 + int err; 152 + int merges; 143 153 }; 144 154 145 155 #define CSTATE 1 ··· 245 213 pid_set_comm(tchart, pid, pp->current->comm); 246 214 247 215 p->start_time = timestamp; 248 - if (p->current) { 216 + if (p->current && !p->current->start_time) { 249 217 p->current->start_time = timestamp; 250 218 p->current->state_since = timestamp; 251 219 } ··· 714 682 } 715 683 } 716 684 685 + static int pid_begin_io_sample(struct timechart *tchart, int pid, int type, 686 + u64 start, int fd) 687 + { 688 + struct per_pid *p = find_create_pid(tchart, pid); 689 + struct per_pidcomm *c = p->current; 690 + struct io_sample *sample; 691 + struct io_sample *prev; 692 + 693 + if (!c) { 694 + c = zalloc(sizeof(*c)); 695 + if (!c) 696 + return -ENOMEM; 697 + p->current = c; 698 + c->next = p->all; 699 + p->all = c; 700 + } 701 + 702 + prev = c->io_samples; 703 + 704 + if (prev && prev->start_time && !prev->end_time) { 705 + pr_warning("Skip invalid start event: " 706 + "previous event already started!\n"); 707 + 708 + /* remove previous event that has been started, 709 + * we are not sure we will ever get an end for it */ 710 + c->io_samples = prev->next; 711 + free(prev); 712 + return 0; 713 + } 714 + 715 + sample = zalloc(sizeof(*sample)); 716 + if (!sample) 717 + return -ENOMEM; 718 + sample->start_time = start; 719 + sample->type = type; 720 + sample->fd = fd; 721 + sample->next = c->io_samples; 722 + c->io_samples = sample; 723 + 724 + if (c->start_time == 0 || c->start_time > start) 725 + c->start_time = start; 726 + 727 + return 0; 728 + } 729 + 730 + static int pid_end_io_sample(struct timechart *tchart, int pid, int type, 731 + u64 end, long ret) 732 + { 733 + struct per_pid *p = find_create_pid(tchart, pid); 734 + struct per_pidcomm *c = p->current; 735 + struct io_sample *sample, *prev; 736 + 737 + if (!c) { 738 + pr_warning("Invalid pidcomm!\n"); 739 + return -1; 740 + } 741 + 742 + sample = c->io_samples; 743 + 744 + if (!sample) /* skip partially captured events */ 745 + return 0; 746 + 747 + if (sample->end_time) { 748 + pr_warning("Skip invalid end event: " 749 + "previous event already ended!\n"); 750 + return 0; 751 + } 752 + 753 + if (sample->type != type) { 754 + pr_warning("Skip invalid end event: invalid event type!\n"); 755 + return 0; 756 + } 757 + 758 + sample->end_time = end; 759 + prev = sample->next; 760 + 761 + /* we want to be able to see small and fast transfers, so make them 762 + * at least min_time long, but don't overlap them */ 763 + if (sample->end_time - sample->start_time < tchart->min_time) 764 + sample->end_time = sample->start_time + tchart->min_time; 765 + if (prev && sample->start_time < prev->end_time) { 766 + if (prev->err) /* try to make errors more visible */ 767 + sample->start_time = prev->end_time; 768 + else 769 + prev->end_time = sample->start_time; 770 + } 771 + 772 + if (ret < 0) { 773 + sample->err = ret; 774 + } else if (type == IOTYPE_READ || type == IOTYPE_WRITE || 775 + type == IOTYPE_TX || type == IOTYPE_RX) { 776 + 777 + if ((u64)ret > c->max_bytes) 778 + c->max_bytes = ret; 779 + 780 + c->total_bytes += ret; 781 + p->total_bytes += ret; 782 + sample->bytes = ret; 783 + } 784 + 785 + /* merge two requests to make svg smaller and render-friendly */ 786 + if (prev && 787 + prev->type == sample->type && 788 + prev->err == sample->err && 789 + prev->fd == sample->fd && 790 + prev->end_time + tchart->merge_dist >= sample->start_time) { 791 + 792 + sample->bytes += prev->bytes; 793 + sample->merges += prev->merges + 1; 794 + 795 + sample->start_time = prev->start_time; 796 + sample->next = prev->next; 797 + free(prev); 798 + 799 + if (!sample->err && sample->bytes > c->max_bytes) 800 + c->max_bytes = sample->bytes; 801 + } 802 + 803 + tchart->io_events++; 804 + 805 + return 0; 806 + } 807 + 808 + static int 809 + process_enter_read(struct timechart *tchart, 810 + struct perf_evsel *evsel, 811 + struct perf_sample *sample) 812 + { 813 + long fd = perf_evsel__intval(evsel, sample, "fd"); 814 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ, 815 + sample->time, fd); 816 + } 817 + 818 + static int 819 + process_exit_read(struct timechart *tchart, 820 + struct perf_evsel *evsel, 821 + struct perf_sample *sample) 822 + { 823 + long ret = perf_evsel__intval(evsel, sample, "ret"); 824 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ, 825 + sample->time, ret); 826 + } 827 + 828 + static int 829 + process_enter_write(struct timechart *tchart, 830 + struct perf_evsel *evsel, 831 + struct perf_sample *sample) 832 + { 833 + long fd = perf_evsel__intval(evsel, sample, "fd"); 834 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE, 835 + sample->time, fd); 836 + } 837 + 838 + static int 839 + process_exit_write(struct timechart *tchart, 840 + struct perf_evsel *evsel, 841 + struct perf_sample *sample) 842 + { 843 + long ret = perf_evsel__intval(evsel, sample, "ret"); 844 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE, 845 + sample->time, ret); 846 + } 847 + 848 + static int 849 + process_enter_sync(struct timechart *tchart, 850 + struct perf_evsel *evsel, 851 + struct perf_sample *sample) 852 + { 853 + long fd = perf_evsel__intval(evsel, sample, "fd"); 854 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC, 855 + sample->time, fd); 856 + } 857 + 858 + static int 859 + process_exit_sync(struct timechart *tchart, 860 + struct perf_evsel *evsel, 861 + struct perf_sample *sample) 862 + { 863 + long ret = perf_evsel__intval(evsel, sample, "ret"); 864 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC, 865 + sample->time, ret); 866 + } 867 + 868 + static int 869 + process_enter_tx(struct timechart *tchart, 870 + struct perf_evsel *evsel, 871 + struct perf_sample *sample) 872 + { 873 + long fd = perf_evsel__intval(evsel, sample, "fd"); 874 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX, 875 + sample->time, fd); 876 + } 877 + 878 + static int 879 + process_exit_tx(struct timechart *tchart, 880 + struct perf_evsel *evsel, 881 + struct perf_sample *sample) 882 + { 883 + long ret = perf_evsel__intval(evsel, sample, "ret"); 884 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX, 885 + sample->time, ret); 886 + } 887 + 888 + static int 889 + process_enter_rx(struct timechart *tchart, 890 + struct perf_evsel *evsel, 891 + struct perf_sample *sample) 892 + { 893 + long fd = perf_evsel__intval(evsel, sample, "fd"); 894 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX, 895 + sample->time, fd); 896 + } 897 + 898 + static int 899 + process_exit_rx(struct timechart *tchart, 900 + struct perf_evsel *evsel, 901 + struct perf_sample *sample) 902 + { 903 + long ret = perf_evsel__intval(evsel, sample, "ret"); 904 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX, 905 + sample->time, ret); 906 + } 907 + 908 + static int 909 + process_enter_poll(struct timechart *tchart, 910 + struct perf_evsel *evsel, 911 + struct perf_sample *sample) 912 + { 913 + long fd = perf_evsel__intval(evsel, sample, "fd"); 914 + return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL, 915 + sample->time, fd); 916 + } 917 + 918 + static int 919 + process_exit_poll(struct timechart *tchart, 920 + struct perf_evsel *evsel, 921 + struct perf_sample *sample) 922 + { 923 + long ret = perf_evsel__intval(evsel, sample, "ret"); 924 + return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL, 925 + sample->time, ret); 926 + } 927 + 717 928 /* 718 929 * Sort the pid datastructure 719 930 */ ··· 1127 852 } 1128 853 } 1129 854 855 + static void draw_io_bars(struct timechart *tchart) 856 + { 857 + const char *suf; 858 + double bytes; 859 + char comm[256]; 860 + struct per_pid *p; 861 + struct per_pidcomm *c; 862 + struct io_sample *sample; 863 + int Y = 1; 864 + 865 + p = tchart->all_data; 866 + while (p) { 867 + c = p->all; 868 + while (c) { 869 + if (!c->display) { 870 + c->Y = 0; 871 + c = c->next; 872 + continue; 873 + } 874 + 875 + svg_box(Y, c->start_time, c->end_time, "process3"); 876 + sample = c->io_samples; 877 + for (sample = c->io_samples; sample; sample = sample->next) { 878 + double h = (double)sample->bytes / c->max_bytes; 879 + 880 + if (tchart->skip_eagain && 881 + sample->err == -EAGAIN) 882 + continue; 883 + 884 + if (sample->err) 885 + h = 1; 886 + 887 + if (sample->type == IOTYPE_SYNC) 888 + svg_fbox(Y, 889 + sample->start_time, 890 + sample->end_time, 891 + 1, 892 + sample->err ? "error" : "sync", 893 + sample->fd, 894 + sample->err, 895 + sample->merges); 896 + else if (sample->type == IOTYPE_POLL) 897 + svg_fbox(Y, 898 + sample->start_time, 899 + sample->end_time, 900 + 1, 901 + sample->err ? "error" : "poll", 902 + sample->fd, 903 + sample->err, 904 + sample->merges); 905 + else if (sample->type == IOTYPE_READ) 906 + svg_ubox(Y, 907 + sample->start_time, 908 + sample->end_time, 909 + h, 910 + sample->err ? "error" : "disk", 911 + sample->fd, 912 + sample->err, 913 + sample->merges); 914 + else if (sample->type == IOTYPE_WRITE) 915 + svg_lbox(Y, 916 + sample->start_time, 917 + sample->end_time, 918 + h, 919 + sample->err ? "error" : "disk", 920 + sample->fd, 921 + sample->err, 922 + sample->merges); 923 + else if (sample->type == IOTYPE_RX) 924 + svg_ubox(Y, 925 + sample->start_time, 926 + sample->end_time, 927 + h, 928 + sample->err ? "error" : "net", 929 + sample->fd, 930 + sample->err, 931 + sample->merges); 932 + else if (sample->type == IOTYPE_TX) 933 + svg_lbox(Y, 934 + sample->start_time, 935 + sample->end_time, 936 + h, 937 + sample->err ? "error" : "net", 938 + sample->fd, 939 + sample->err, 940 + sample->merges); 941 + } 942 + 943 + suf = ""; 944 + bytes = c->total_bytes; 945 + if (bytes > 1024) { 946 + bytes = bytes / 1024; 947 + suf = "K"; 948 + } 949 + if (bytes > 1024) { 950 + bytes = bytes / 1024; 951 + suf = "M"; 952 + } 953 + if (bytes > 1024) { 954 + bytes = bytes / 1024; 955 + suf = "G"; 956 + } 957 + 958 + 959 + sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf); 960 + svg_text(Y, c->start_time, comm); 961 + 962 + c->Y = Y; 963 + Y++; 964 + c = c->next; 965 + } 966 + p = p->next; 967 + } 968 + } 969 + 1130 970 static void draw_process_bars(struct timechart *tchart) 1131 971 { 1132 972 struct per_pid *p; ··· 1377 987 struct per_pidcomm *c; 1378 988 int count = 0; 1379 989 1380 - if (process_filter) 1381 - return determine_display_tasks_filtered(tchart); 1382 - 1383 990 p = tchart->all_data; 1384 991 while (p) { 1385 992 p->display = 0; ··· 1412 1025 return count; 1413 1026 } 1414 1027 1028 + static int determine_display_io_tasks(struct timechart *timechart, u64 threshold) 1029 + { 1030 + struct per_pid *p; 1031 + struct per_pidcomm *c; 1032 + int count = 0; 1415 1033 1034 + p = timechart->all_data; 1035 + while (p) { 1036 + /* no exit marker, task kept running to the end */ 1037 + if (p->end_time == 0) 1038 + p->end_time = timechart->last_time; 1416 1039 1040 + c = p->all; 1041 + 1042 + while (c) { 1043 + c->display = 0; 1044 + 1045 + if (c->total_bytes >= threshold) { 1046 + c->display = 1; 1047 + count++; 1048 + } 1049 + 1050 + if (c->end_time == 0) 1051 + c->end_time = timechart->last_time; 1052 + 1053 + c = c->next; 1054 + } 1055 + p = p->next; 1056 + } 1057 + return count; 1058 + } 1059 + 1060 + #define BYTES_THRESH (1 * 1024 * 1024) 1417 1061 #define TIME_THRESH 10000000 1418 1062 1419 1063 static void write_svg_file(struct timechart *tchart, const char *filename) 1420 1064 { 1421 1065 u64 i; 1422 1066 int count; 1423 - int thresh = TIME_THRESH; 1067 + int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH; 1424 1068 1425 1069 if (tchart->power_only) 1426 1070 tchart->proc_num = 0; ··· 1459 1041 /* We'd like to show at least proc_num tasks; 1460 1042 * be less picky if we have fewer */ 1461 1043 do { 1462 - count = determine_display_tasks(tchart, thresh); 1044 + if (process_filter) 1045 + count = determine_display_tasks_filtered(tchart); 1046 + else if (tchart->io_events) 1047 + count = determine_display_io_tasks(tchart, thresh); 1048 + else 1049 + count = determine_display_tasks(tchart, thresh); 1463 1050 thresh /= 10; 1464 1051 } while (!process_filter && thresh && count < tchart->proc_num); 1465 1052 1466 1053 if (!tchart->proc_num) 1467 1054 count = 0; 1468 1055 1469 - open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); 1056 + if (tchart->io_events) { 1057 + open_svg(filename, 0, count, tchart->first_time, tchart->last_time); 1470 1058 1471 - svg_time_grid(); 1472 - svg_legenda(); 1059 + svg_time_grid(0.5); 1060 + svg_io_legenda(); 1473 1061 1474 - for (i = 0; i < tchart->numcpus; i++) 1475 - svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); 1062 + draw_io_bars(tchart); 1063 + } else { 1064 + open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); 1476 1065 1477 - draw_cpu_usage(tchart); 1478 - if (tchart->proc_num) 1479 - draw_process_bars(tchart); 1480 - if (!tchart->tasks_only) 1481 - draw_c_p_states(tchart); 1482 - if (tchart->proc_num) 1483 - draw_wakeups(tchart); 1066 + svg_time_grid(0); 1067 + 1068 + svg_legenda(); 1069 + 1070 + for (i = 0; i < tchart->numcpus; i++) 1071 + svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); 1072 + 1073 + draw_cpu_usage(tchart); 1074 + if (tchart->proc_num) 1075 + draw_process_bars(tchart); 1076 + if (!tchart->tasks_only) 1077 + draw_c_p_states(tchart); 1078 + if (tchart->proc_num) 1079 + draw_wakeups(tchart); 1080 + } 1484 1081 1485 1082 svg_close(); 1486 1083 } ··· 1543 1110 { "power:power_end", process_sample_power_end }, 1544 1111 { "power:power_frequency", process_sample_power_frequency }, 1545 1112 #endif 1113 + 1114 + { "syscalls:sys_enter_read", process_enter_read }, 1115 + { "syscalls:sys_enter_pread64", process_enter_read }, 1116 + { "syscalls:sys_enter_readv", process_enter_read }, 1117 + { "syscalls:sys_enter_preadv", process_enter_read }, 1118 + { "syscalls:sys_enter_write", process_enter_write }, 1119 + { "syscalls:sys_enter_pwrite64", process_enter_write }, 1120 + { "syscalls:sys_enter_writev", process_enter_write }, 1121 + { "syscalls:sys_enter_pwritev", process_enter_write }, 1122 + { "syscalls:sys_enter_sync", process_enter_sync }, 1123 + { "syscalls:sys_enter_sync_file_range", process_enter_sync }, 1124 + { "syscalls:sys_enter_fsync", process_enter_sync }, 1125 + { "syscalls:sys_enter_msync", process_enter_sync }, 1126 + { "syscalls:sys_enter_recvfrom", process_enter_rx }, 1127 + { "syscalls:sys_enter_recvmmsg", process_enter_rx }, 1128 + { "syscalls:sys_enter_recvmsg", process_enter_rx }, 1129 + { "syscalls:sys_enter_sendto", process_enter_tx }, 1130 + { "syscalls:sys_enter_sendmsg", process_enter_tx }, 1131 + { "syscalls:sys_enter_sendmmsg", process_enter_tx }, 1132 + { "syscalls:sys_enter_epoll_pwait", process_enter_poll }, 1133 + { "syscalls:sys_enter_epoll_wait", process_enter_poll }, 1134 + { "syscalls:sys_enter_poll", process_enter_poll }, 1135 + { "syscalls:sys_enter_ppoll", process_enter_poll }, 1136 + { "syscalls:sys_enter_pselect6", process_enter_poll }, 1137 + { "syscalls:sys_enter_select", process_enter_poll }, 1138 + 1139 + { "syscalls:sys_exit_read", process_exit_read }, 1140 + { "syscalls:sys_exit_pread64", process_exit_read }, 1141 + { "syscalls:sys_exit_readv", process_exit_read }, 1142 + { "syscalls:sys_exit_preadv", process_exit_read }, 1143 + { "syscalls:sys_exit_write", process_exit_write }, 1144 + { "syscalls:sys_exit_pwrite64", process_exit_write }, 1145 + { "syscalls:sys_exit_writev", process_exit_write }, 1146 + { "syscalls:sys_exit_pwritev", process_exit_write }, 1147 + { "syscalls:sys_exit_sync", process_exit_sync }, 1148 + { "syscalls:sys_exit_sync_file_range", process_exit_sync }, 1149 + { "syscalls:sys_exit_fsync", process_exit_sync }, 1150 + { "syscalls:sys_exit_msync", process_exit_sync }, 1151 + { "syscalls:sys_exit_recvfrom", process_exit_rx }, 1152 + { "syscalls:sys_exit_recvmmsg", process_exit_rx }, 1153 + { "syscalls:sys_exit_recvmsg", process_exit_rx }, 1154 + { "syscalls:sys_exit_sendto", process_exit_tx }, 1155 + { "syscalls:sys_exit_sendmsg", process_exit_tx }, 1156 + { "syscalls:sys_exit_sendmmsg", process_exit_tx }, 1157 + { "syscalls:sys_exit_epoll_pwait", process_exit_poll }, 1158 + { "syscalls:sys_exit_epoll_wait", process_exit_poll }, 1159 + { "syscalls:sys_exit_poll", process_exit_poll }, 1160 + { "syscalls:sys_exit_ppoll", process_exit_poll }, 1161 + { "syscalls:sys_exit_pselect6", process_exit_poll }, 1162 + { "syscalls:sys_exit_select", process_exit_poll }, 1546 1163 }; 1547 1164 struct perf_data_file file = { 1548 1165 .path = input_name, ··· 1636 1153 perf_session__delete(session); 1637 1154 return ret; 1638 1155 } 1156 + 1157 + static int timechart__io_record(int argc, const char **argv) 1158 + { 1159 + unsigned int rec_argc, i; 1160 + const char **rec_argv; 1161 + const char **p; 1162 + char *filter = NULL; 1163 + 1164 + const char * const common_args[] = { 1165 + "record", "-a", "-R", "-c", "1", 1166 + }; 1167 + unsigned int common_args_nr = ARRAY_SIZE(common_args); 1168 + 1169 + const char * const disk_events[] = { 1170 + "syscalls:sys_enter_read", 1171 + "syscalls:sys_enter_pread64", 1172 + "syscalls:sys_enter_readv", 1173 + "syscalls:sys_enter_preadv", 1174 + "syscalls:sys_enter_write", 1175 + "syscalls:sys_enter_pwrite64", 1176 + "syscalls:sys_enter_writev", 1177 + "syscalls:sys_enter_pwritev", 1178 + "syscalls:sys_enter_sync", 1179 + "syscalls:sys_enter_sync_file_range", 1180 + "syscalls:sys_enter_fsync", 1181 + "syscalls:sys_enter_msync", 1182 + 1183 + "syscalls:sys_exit_read", 1184 + "syscalls:sys_exit_pread64", 1185 + "syscalls:sys_exit_readv", 1186 + "syscalls:sys_exit_preadv", 1187 + "syscalls:sys_exit_write", 1188 + "syscalls:sys_exit_pwrite64", 1189 + "syscalls:sys_exit_writev", 1190 + "syscalls:sys_exit_pwritev", 1191 + "syscalls:sys_exit_sync", 1192 + "syscalls:sys_exit_sync_file_range", 1193 + "syscalls:sys_exit_fsync", 1194 + "syscalls:sys_exit_msync", 1195 + }; 1196 + unsigned int disk_events_nr = ARRAY_SIZE(disk_events); 1197 + 1198 + const char * const net_events[] = { 1199 + "syscalls:sys_enter_recvfrom", 1200 + "syscalls:sys_enter_recvmmsg", 1201 + "syscalls:sys_enter_recvmsg", 1202 + "syscalls:sys_enter_sendto", 1203 + "syscalls:sys_enter_sendmsg", 1204 + "syscalls:sys_enter_sendmmsg", 1205 + 1206 + "syscalls:sys_exit_recvfrom", 1207 + "syscalls:sys_exit_recvmmsg", 1208 + "syscalls:sys_exit_recvmsg", 1209 + "syscalls:sys_exit_sendto", 1210 + "syscalls:sys_exit_sendmsg", 1211 + "syscalls:sys_exit_sendmmsg", 1212 + }; 1213 + unsigned int net_events_nr = ARRAY_SIZE(net_events); 1214 + 1215 + const char * const poll_events[] = { 1216 + "syscalls:sys_enter_epoll_pwait", 1217 + "syscalls:sys_enter_epoll_wait", 1218 + "syscalls:sys_enter_poll", 1219 + "syscalls:sys_enter_ppoll", 1220 + "syscalls:sys_enter_pselect6", 1221 + "syscalls:sys_enter_select", 1222 + 1223 + "syscalls:sys_exit_epoll_pwait", 1224 + "syscalls:sys_exit_epoll_wait", 1225 + "syscalls:sys_exit_poll", 1226 + "syscalls:sys_exit_ppoll", 1227 + "syscalls:sys_exit_pselect6", 1228 + "syscalls:sys_exit_select", 1229 + }; 1230 + unsigned int poll_events_nr = ARRAY_SIZE(poll_events); 1231 + 1232 + rec_argc = common_args_nr + 1233 + disk_events_nr * 4 + 1234 + net_events_nr * 4 + 1235 + poll_events_nr * 4 + 1236 + argc; 1237 + rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1238 + 1239 + if (rec_argv == NULL) 1240 + return -ENOMEM; 1241 + 1242 + if (asprintf(&filter, "common_pid != %d", getpid()) < 0) 1243 + return -ENOMEM; 1244 + 1245 + p = rec_argv; 1246 + for (i = 0; i < common_args_nr; i++) 1247 + *p++ = strdup(common_args[i]); 1248 + 1249 + for (i = 0; i < disk_events_nr; i++) { 1250 + if (!is_valid_tracepoint(disk_events[i])) { 1251 + rec_argc -= 4; 1252 + continue; 1253 + } 1254 + 1255 + *p++ = "-e"; 1256 + *p++ = strdup(disk_events[i]); 1257 + *p++ = "--filter"; 1258 + *p++ = filter; 1259 + } 1260 + for (i = 0; i < net_events_nr; i++) { 1261 + if (!is_valid_tracepoint(net_events[i])) { 1262 + rec_argc -= 4; 1263 + continue; 1264 + } 1265 + 1266 + *p++ = "-e"; 1267 + *p++ = strdup(net_events[i]); 1268 + *p++ = "--filter"; 1269 + *p++ = filter; 1270 + } 1271 + for (i = 0; i < poll_events_nr; i++) { 1272 + if (!is_valid_tracepoint(poll_events[i])) { 1273 + rec_argc -= 4; 1274 + continue; 1275 + } 1276 + 1277 + *p++ = "-e"; 1278 + *p++ = strdup(poll_events[i]); 1279 + *p++ = "--filter"; 1280 + *p++ = filter; 1281 + } 1282 + 1283 + for (i = 0; i < (unsigned int)argc; i++) 1284 + *p++ = argv[i]; 1285 + 1286 + return cmd_record(rec_argc, rec_argv, NULL); 1287 + } 1288 + 1639 1289 1640 1290 static int timechart__record(struct timechart *tchart, int argc, const char **argv) 1641 1291 { ··· 1886 1270 return 0; 1887 1271 } 1888 1272 1273 + static int 1274 + parse_time(const struct option *opt, const char *arg, int __maybe_unused unset) 1275 + { 1276 + char unit = 'n'; 1277 + u64 *value = opt->value; 1278 + 1279 + if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) { 1280 + switch (unit) { 1281 + case 'm': 1282 + *value *= 1000000; 1283 + break; 1284 + case 'u': 1285 + *value *= 1000; 1286 + break; 1287 + case 'n': 1288 + break; 1289 + default: 1290 + return -1; 1291 + } 1292 + } 1293 + 1294 + return 0; 1295 + } 1296 + 1889 1297 int cmd_timechart(int argc, const char **argv, 1890 1298 const char *prefix __maybe_unused) 1891 1299 { ··· 1922 1282 .ordered_samples = true, 1923 1283 }, 1924 1284 .proc_num = 15, 1285 + .min_time = 1000000, 1286 + .merge_dist = 1000, 1925 1287 }; 1926 1288 const char *output_name = "output.svg"; 1927 1289 const struct option timechart_options[] = { ··· 1945 1303 "min. number of tasks to print"), 1946 1304 OPT_BOOLEAN('t', "topology", &tchart.topology, 1947 1305 "sort CPUs according to topology"), 1306 + OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain, 1307 + "skip EAGAIN errors"), 1308 + OPT_CALLBACK(0, "io-min-time", &tchart.min_time, "time", 1309 + "all IO faster than min-time will visually appear longer", 1310 + parse_time), 1311 + OPT_CALLBACK(0, "io-merge-dist", &tchart.merge_dist, "time", 1312 + "merge events that are merge-dist us apart", 1313 + parse_time), 1948 1314 OPT_END() 1949 1315 }; 1950 1316 const char * const timechart_usage[] = { ··· 1964 1314 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), 1965 1315 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, 1966 1316 "output processes data only"), 1317 + OPT_BOOLEAN('I', "io-only", &tchart.io_only, 1318 + "record only IO data"), 1967 1319 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), 1968 1320 OPT_END() 1969 1321 }; ··· 1992 1340 return -1; 1993 1341 } 1994 1342 1995 - return timechart__record(&tchart, argc, argv); 1343 + if (tchart.io_only) 1344 + return timechart__io_record(argc, argv); 1345 + else 1346 + return timechart__record(&tchart, argc, argv); 1996 1347 } else if (argc) 1997 1348 usage_with_options(timechart_usage, timechart_options); 1998 1349
+130 -38
tools/perf/util/svghelper.c
··· 30 30 31 31 #define SLOT_MULT 30.0 32 32 #define SLOT_HEIGHT 25.0 33 + #define SLOT_HALF (SLOT_HEIGHT / 2) 33 34 34 35 int svg_page_width = 1000; 35 36 u64 svg_highlight; ··· 115 114 fprintf(svgfile, " rect { stroke-width: 1; }\n"); 116 115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 117 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.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 118 118 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 119 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.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 121 + fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 122 + fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 123 + fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 124 + fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 125 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 121 126 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 122 127 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); ··· 139 132 fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); 140 133 } 141 134 135 + static double normalize_height(double height) 136 + { 137 + if (height < 0.25) 138 + return 0.25; 139 + else if (height < 0.50) 140 + return 0.50; 141 + else if (height < 0.75) 142 + return 0.75; 143 + else 144 + return 0.100; 145 + } 146 + 147 + void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges) 148 + { 149 + double w = time2pixels(end) - time2pixels(start); 150 + height = normalize_height(height); 151 + 152 + if (!svgfile) 153 + return; 154 + 155 + fprintf(svgfile, "<g>\n"); 156 + fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges); 157 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 158 + time2pixels(start), 159 + w, 160 + Yslot * SLOT_MULT, 161 + SLOT_HALF * height, 162 + type); 163 + fprintf(svgfile, "</g>\n"); 164 + } 165 + 166 + void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges) 167 + { 168 + double w = time2pixels(end) - time2pixels(start); 169 + height = normalize_height(height); 170 + 171 + if (!svgfile) 172 + return; 173 + 174 + fprintf(svgfile, "<g>\n"); 175 + fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges); 176 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 177 + time2pixels(start), 178 + w, 179 + Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height, 180 + SLOT_HALF * height, 181 + type); 182 + fprintf(svgfile, "</g>\n"); 183 + } 184 + 185 + void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges) 186 + { 187 + double w = time2pixels(end) - time2pixels(start); 188 + height = normalize_height(height); 189 + 190 + if (!svgfile) 191 + return; 192 + 193 + fprintf(svgfile, "<g>\n"); 194 + fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges); 195 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 196 + time2pixels(start), 197 + w, 198 + Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height, 199 + SLOT_HEIGHT * height, 200 + type); 201 + fprintf(svgfile, "</g>\n"); 202 + } 203 + 142 204 void svg_box(int Yslot, u64 start, u64 end, const char *type) 143 205 { 144 206 if (!svgfile) 145 207 return; 146 208 147 - fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 209 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 148 210 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 149 211 } 150 212 ··· 250 174 cpu, time_to_string(end - start)); 251 175 if (backtrace) 252 176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 253 - fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 177 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n", 254 178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, 255 179 type); 256 180 ··· 262 186 text_size = round_text_size(text_size); 263 187 264 188 if (text_size > MIN_TEXT_SIZE) 265 - fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 189 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n", 266 190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 267 191 268 192 fprintf(svgfile, "</g>\n"); ··· 278 202 return text; 279 203 280 204 if (duration < 1000 * 1000) { /* less than 1 msec */ 281 - sprintf(text, "%4.1f us", duration / 1000.0); 205 + sprintf(text, "%.1f us", duration / 1000.0); 282 206 return text; 283 207 } 284 - sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); 208 + sprintf(text, "%.1f ms", duration / 1000.0 / 1000); 285 209 286 210 return text; 287 211 } ··· 309 233 310 234 font_size = round_text_size(font_size); 311 235 312 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 236 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 313 237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); 314 238 if (backtrace) 315 239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); 316 - fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 240 + fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n", 317 241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 318 242 if (font_size > MIN_TEXT_SIZE) 319 - fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n", 243 + fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n", 320 244 font_size, text); 321 245 fprintf(svgfile, "</g>\n"); 322 246 } ··· 365 289 366 290 fprintf(svgfile, "<g>\n"); 367 291 368 - fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 292 + fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n", 369 293 time2pixels(first_time), 370 294 time2pixels(last_time)-time2pixels(first_time), 371 295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 372 296 373 297 sprintf(cpu_string, "CPU %i", (int)cpu); 374 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 298 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n", 375 299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 376 300 377 - fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 301 + fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n", 378 302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 379 303 380 304 fprintf(svgfile, "</g>\n"); ··· 395 319 else 396 320 type = "sample"; 397 321 398 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 322 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu)); 399 323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); 400 324 if (backtrace) 401 325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 402 - fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 326 + fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n", 403 327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 404 328 width = time2pixels(end)-time2pixels(start); 405 329 if (width > 6) ··· 408 332 width = round_text_size(width); 409 333 410 334 if (width > MIN_TEXT_SIZE) 411 - fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n", 335 + fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n", 412 336 width, name); 413 337 414 338 fprintf(svgfile, "</g>\n"); ··· 429 353 type = 6; 430 354 sprintf(style, "c%i", type); 431 355 432 - fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", 356 + fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n", 433 357 style, 434 358 time2pixels(start), time2pixels(end)-time2pixels(start), 435 359 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); ··· 441 365 width = round_text_size(width); 442 366 443 367 if (width > MIN_TEXT_SIZE) 444 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 368 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n", 445 369 time2pixels(start), cpu2y(cpu)+width, width, type); 446 370 447 371 fprintf(svgfile, "</g>\n"); ··· 483 407 if (max_freq) 484 408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 485 409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 486 - fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", 410 + fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n", 487 411 time2pixels(start), time2pixels(end), height, height); 488 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 412 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n", 489 413 time2pixels(start), height+0.9, HzToHuman(freq)); 490 414 491 415 fprintf(svgfile, "</g>\n"); ··· 511 435 512 436 if (row1 < row2) { 513 437 if (row1) { 514 - 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", 438 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 515 439 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 516 440 if (desc2) 517 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 441 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 518 442 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); 519 443 } 520 444 if (row2) { 521 - 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", 445 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 522 446 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); 523 447 if (desc1) 524 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 448 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 525 449 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); 526 450 } 527 451 } else { 528 452 if (row2) { 529 - 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", 453 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 530 454 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 531 455 if (desc1) 532 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 456 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 533 457 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); 534 458 } 535 459 if (row1) { 536 - 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", 460 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 537 461 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); 538 462 if (desc2) 539 - fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 463 + fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 540 464 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); 541 465 } 542 466 } ··· 544 468 if (row2 > row1) 545 469 height += SLOT_HEIGHT; 546 470 if (row1) 547 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 471 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 548 472 time2pixels(start), height); 549 473 550 474 fprintf(svgfile, "</g>\n"); ··· 564 488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 565 489 566 490 if (row1 < row2) 567 - 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", 491 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 568 492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 569 493 else 570 - 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", 494 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 571 495 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); 572 496 573 497 height = row1 * SLOT_MULT; 574 498 if (row2 > row1) 575 499 height += SLOT_HEIGHT; 576 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 500 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 577 501 time2pixels(start), height); 578 502 579 503 fprintf(svgfile, "</g>\n"); ··· 591 515 if (backtrace) 592 516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 593 517 594 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 518 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 595 519 time2pixels(start), row * SLOT_MULT); 596 - fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 520 + fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 597 521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 598 522 599 523 fprintf(svgfile, "</g>\n"); ··· 604 528 if (!svgfile) 605 529 return; 606 530 607 - fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 531 + fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n", 608 532 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); 609 533 } 610 534 ··· 613 537 double boxsize; 614 538 boxsize = SLOT_HEIGHT / 2; 615 539 616 - fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 540 + fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n", 617 541 X, boxsize, boxsize, style); 618 - fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n", 542 + fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n", 619 543 X + boxsize + 5, boxsize, 0.8 * boxsize, text); 544 + } 545 + 546 + void svg_io_legenda(void) 547 + { 548 + if (!svgfile) 549 + return; 550 + 551 + fprintf(svgfile, "<g>\n"); 552 + svg_legenda_box(0, "Disk", "disk"); 553 + svg_legenda_box(100, "Network", "net"); 554 + svg_legenda_box(200, "Sync", "sync"); 555 + svg_legenda_box(300, "Poll", "poll"); 556 + svg_legenda_box(400, "Error", "error"); 557 + fprintf(svgfile, "</g>\n"); 620 558 } 621 559 622 560 void svg_legenda(void) ··· 649 559 fprintf(svgfile, "</g>\n"); 650 560 } 651 561 652 - void svg_time_grid(void) 562 + void svg_time_grid(double min_thickness) 653 563 { 654 564 u64 i; 655 565 ··· 669 579 color = 128; 670 580 } 671 581 672 - 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", 673 - time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 582 + if (thickness >= min_thickness) 583 + fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n", 584 + time2pixels(i), SLOT_MULT/2, time2pixels(i), 585 + total_height, color, color, color, thickness); 674 586 675 587 i += 10000000; 676 588 }
+5 -1
tools/perf/util/svghelper.h
··· 4 4 #include <linux/types.h> 5 5 6 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 10 extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 8 11 extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 9 12 extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); ··· 19 16 extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 20 17 21 18 22 - extern void svg_time_grid(void); 19 + extern void svg_time_grid(double min_thickness); 20 + extern void svg_io_legenda(void); 23 21 extern void svg_legenda(void); 24 22 extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); 25 23 extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);