diff options
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r-- | tools/perf/builtin-timechart.c | 146 |
1 files changed, 134 insertions, 12 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 702d8fe58fbc..0a2f22261c3a 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -153,6 +153,17 @@ static struct wake_event *wake_events; | |||
153 | 153 | ||
154 | struct sample_wrapper *all_samples; | 154 | struct sample_wrapper *all_samples; |
155 | 155 | ||
156 | |||
157 | struct process_filter; | ||
158 | struct process_filter { | ||
159 | char *name; | ||
160 | int pid; | ||
161 | struct process_filter *next; | ||
162 | }; | ||
163 | |||
164 | static struct process_filter *process_filter; | ||
165 | |||
166 | |||
156 | static struct per_pid *find_create_pid(int pid) | 167 | static struct per_pid *find_create_pid(int pid) |
157 | { | 168 | { |
158 | struct per_pid *cursor = all_data; | 169 | struct per_pid *cursor = all_data; |
@@ -763,21 +774,42 @@ static void draw_wakeups(void) | |||
763 | c = p->all; | 774 | c = p->all; |
764 | while (c) { | 775 | while (c) { |
765 | if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { | 776 | if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { |
766 | if (p->pid == we->waker) { | 777 | if (p->pid == we->waker && !from) { |
767 | from = c->Y; | 778 | from = c->Y; |
768 | task_from = c->comm; | 779 | task_from = strdup(c->comm); |
769 | } | 780 | } |
770 | if (p->pid == we->wakee) { | 781 | if (p->pid == we->wakee && !to) { |
771 | to = c->Y; | 782 | to = c->Y; |
772 | task_to = c->comm; | 783 | task_to = strdup(c->comm); |
773 | } | 784 | } |
774 | } | 785 | } |
775 | c = c->next; | 786 | c = c->next; |
776 | } | 787 | } |
788 | c = p->all; | ||
789 | while (c) { | ||
790 | if (p->pid == we->waker && !from) { | ||
791 | from = c->Y; | ||
792 | task_from = strdup(c->comm); | ||
793 | } | ||
794 | if (p->pid == we->wakee && !to) { | ||
795 | to = c->Y; | ||
796 | task_to = strdup(c->comm); | ||
797 | } | ||
798 | c = c->next; | ||
799 | } | ||
777 | } | 800 | } |
778 | p = p->next; | 801 | p = p->next; |
779 | } | 802 | } |
780 | 803 | ||
804 | if (!task_from) { | ||
805 | task_from = malloc(40); | ||
806 | sprintf(task_from, "[%i]", we->waker); | ||
807 | } | ||
808 | if (!task_to) { | ||
809 | task_to = malloc(40); | ||
810 | sprintf(task_to, "[%i]", we->wakee); | ||
811 | } | ||
812 | |||
781 | if (we->waker == -1) | 813 | if (we->waker == -1) |
782 | svg_interrupt(we->time, to); | 814 | svg_interrupt(we->time, to); |
783 | else if (from && to && abs(from - to) == 1) | 815 | else if (from && to && abs(from - to) == 1) |
@@ -785,6 +817,9 @@ static void draw_wakeups(void) | |||
785 | else | 817 | else |
786 | svg_partial_wakeline(we->time, from, task_from, to, task_to); | 818 | svg_partial_wakeline(we->time, from, task_from, to, task_to); |
787 | we = we->next; | 819 | we = we->next; |
820 | |||
821 | free(task_from); | ||
822 | free(task_to); | ||
788 | } | 823 | } |
789 | } | 824 | } |
790 | 825 | ||
@@ -858,12 +893,89 @@ static void draw_process_bars(void) | |||
858 | } | 893 | } |
859 | } | 894 | } |
860 | 895 | ||
896 | static void add_process_filter(const char *string) | ||
897 | { | ||
898 | struct process_filter *filt; | ||
899 | int pid; | ||
900 | |||
901 | pid = strtoull(string, NULL, 10); | ||
902 | filt = malloc(sizeof(struct process_filter)); | ||
903 | if (!filt) | ||
904 | return; | ||
905 | |||
906 | filt->name = strdup(string); | ||
907 | filt->pid = pid; | ||
908 | filt->next = process_filter; | ||
909 | |||
910 | process_filter = filt; | ||
911 | } | ||
912 | |||
913 | static int passes_filter(struct per_pid *p, struct per_pidcomm *c) | ||
914 | { | ||
915 | struct process_filter *filt; | ||
916 | if (!process_filter) | ||
917 | return 1; | ||
918 | |||
919 | filt = process_filter; | ||
920 | while (filt) { | ||
921 | if (filt->pid && p->pid == filt->pid) | ||
922 | return 1; | ||
923 | if (strcmp(filt->name, c->comm) == 0) | ||
924 | return 1; | ||
925 | filt = filt->next; | ||
926 | } | ||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | static int determine_display_tasks_filtered(void) | ||
931 | { | ||
932 | struct per_pid *p; | ||
933 | struct per_pidcomm *c; | ||
934 | int count = 0; | ||
935 | |||
936 | p = all_data; | ||
937 | while (p) { | ||
938 | p->display = 0; | ||
939 | if (p->start_time == 1) | ||
940 | p->start_time = first_time; | ||
941 | |||
942 | /* no exit marker, task kept running to the end */ | ||
943 | if (p->end_time == 0) | ||
944 | p->end_time = last_time; | ||
945 | |||
946 | c = p->all; | ||
947 | |||
948 | while (c) { | ||
949 | c->display = 0; | ||
950 | |||
951 | if (c->start_time == 1) | ||
952 | c->start_time = first_time; | ||
953 | |||
954 | if (passes_filter(p, c)) { | ||
955 | c->display = 1; | ||
956 | p->display = 1; | ||
957 | count++; | ||
958 | } | ||
959 | |||
960 | if (c->end_time == 0) | ||
961 | c->end_time = last_time; | ||
962 | |||
963 | c = c->next; | ||
964 | } | ||
965 | p = p->next; | ||
966 | } | ||
967 | return count; | ||
968 | } | ||
969 | |||
861 | static int determine_display_tasks(u64 threshold) | 970 | static int determine_display_tasks(u64 threshold) |
862 | { | 971 | { |
863 | struct per_pid *p; | 972 | struct per_pid *p; |
864 | struct per_pidcomm *c; | 973 | struct per_pidcomm *c; |
865 | int count = 0; | 974 | int count = 0; |
866 | 975 | ||
976 | if (process_filter) | ||
977 | return determine_display_tasks_filtered(); | ||
978 | |||
867 | p = all_data; | 979 | p = all_data; |
868 | while (p) { | 980 | while (p) { |
869 | p->display = 0; | 981 | p->display = 0; |
@@ -1050,12 +1162,10 @@ more: | |||
1050 | size = event->header.size; | 1162 | size = event->header.size; |
1051 | 1163 | ||
1052 | if (!size || process_event(event) < 0) { | 1164 | if (!size || process_event(event) < 0) { |
1053 | 1165 | pr_warning("%p [%p]: skipping unknown header type: %d\n", | |
1054 | printf("%p [%p]: skipping unknown header type: %d\n", | 1166 | (void *)(offset + head), |
1055 | (void *)(offset + head), | 1167 | (void *)(long)(event->header.size), |
1056 | (void *)(long)(event->header.size), | 1168 | event->header.type); |
1057 | event->header.type); | ||
1058 | |||
1059 | /* | 1169 | /* |
1060 | * assume we lost track of the stream, check alignment, and | 1170 | * assume we lost track of the stream, check alignment, and |
1061 | * increment a single u64 in the hope to catch on again 'soon'. | 1171 | * increment a single u64 in the hope to catch on again 'soon'. |
@@ -1088,7 +1198,8 @@ done: | |||
1088 | 1198 | ||
1089 | write_svg_file(output_name); | 1199 | write_svg_file(output_name); |
1090 | 1200 | ||
1091 | printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); | 1201 | pr_info("Written %2.1f seconds of trace to %s.\n", |
1202 | (last_time - first_time) / 1000000000.0, output_name); | ||
1092 | 1203 | ||
1093 | return rc; | 1204 | return rc; |
1094 | } | 1205 | } |
@@ -1129,6 +1240,14 @@ static int __cmd_record(int argc, const char **argv) | |||
1129 | return cmd_record(i, rec_argv, NULL); | 1240 | return cmd_record(i, rec_argv, NULL); |
1130 | } | 1241 | } |
1131 | 1242 | ||
1243 | static int | ||
1244 | parse_process(const struct option *opt __used, const char *arg, int __used unset) | ||
1245 | { | ||
1246 | if (arg) | ||
1247 | add_process_filter(arg); | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1132 | static const struct option options[] = { | 1251 | static const struct option options[] = { |
1133 | OPT_STRING('i', "input", &input_name, "file", | 1252 | OPT_STRING('i', "input", &input_name, "file", |
1134 | "input file name"), | 1253 | "input file name"), |
@@ -1136,8 +1255,11 @@ static const struct option options[] = { | |||
1136 | "output file name"), | 1255 | "output file name"), |
1137 | OPT_INTEGER('w', "width", &svg_page_width, | 1256 | OPT_INTEGER('w', "width", &svg_page_width, |
1138 | "page width"), | 1257 | "page width"), |
1139 | OPT_BOOLEAN('p', "power-only", &power_only, | 1258 | OPT_BOOLEAN('P', "power-only", &power_only, |
1140 | "output power data only"), | 1259 | "output power data only"), |
1260 | OPT_CALLBACK('p', "process", NULL, "process", | ||
1261 | "process selector. Pass a pid or process name.", | ||
1262 | parse_process), | ||
1141 | OPT_END() | 1263 | OPT_END() |
1142 | }; | 1264 | }; |
1143 | 1265 | ||