aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-timechart.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r--tools/perf/builtin-timechart.c267
1 files changed, 132 insertions, 135 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index e8a510d935e5..cb58b6605fcc 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -29,14 +29,14 @@
29#include "util/header.h" 29#include "util/header.h"
30#include "util/parse-options.h" 30#include "util/parse-options.h"
31#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/event.h"
33#include "util/data_map.h"
32#include "util/svghelper.h" 34#include "util/svghelper.h"
33 35
34static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
35static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
36 38
37 39
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
40static u64 sample_type; 40static u64 sample_type;
41 41
42static unsigned int numcpus; 42static unsigned int numcpus;
@@ -49,8 +49,6 @@ static u64 first_time, last_time;
49static int power_only; 49static int power_only;
50 50
51 51
52static struct perf_header *header;
53
54struct per_pid; 52struct per_pid;
55struct per_pidcomm; 53struct per_pidcomm;
56 54
@@ -153,6 +151,17 @@ static struct wake_event *wake_events;
153 151
154struct sample_wrapper *all_samples; 152struct sample_wrapper *all_samples;
155 153
154
155struct process_filter;
156struct process_filter {
157 char *name;
158 int pid;
159 struct process_filter *next;
160};
161
162static struct process_filter *process_filter;
163
164
156static struct per_pid *find_create_pid(int pid) 165static struct per_pid *find_create_pid(int pid)
157{ 166{
158 struct per_pid *cursor = all_data; 167 struct per_pid *cursor = all_data;
@@ -763,11 +772,11 @@ static void draw_wakeups(void)
763 c = p->all; 772 c = p->all;
764 while (c) { 773 while (c) {
765 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { 774 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
766 if (p->pid == we->waker) { 775 if (p->pid == we->waker && !from) {
767 from = c->Y; 776 from = c->Y;
768 task_from = strdup(c->comm); 777 task_from = strdup(c->comm);
769 } 778 }
770 if (p->pid == we->wakee) { 779 if (p->pid == we->wakee && !to) {
771 to = c->Y; 780 to = c->Y;
772 task_to = strdup(c->comm); 781 task_to = strdup(c->comm);
773 } 782 }
@@ -882,12 +891,89 @@ static void draw_process_bars(void)
882 } 891 }
883} 892}
884 893
894static void add_process_filter(const char *string)
895{
896 struct process_filter *filt;
897 int pid;
898
899 pid = strtoull(string, NULL, 10);
900 filt = malloc(sizeof(struct process_filter));
901 if (!filt)
902 return;
903
904 filt->name = strdup(string);
905 filt->pid = pid;
906 filt->next = process_filter;
907
908 process_filter = filt;
909}
910
911static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
912{
913 struct process_filter *filt;
914 if (!process_filter)
915 return 1;
916
917 filt = process_filter;
918 while (filt) {
919 if (filt->pid && p->pid == filt->pid)
920 return 1;
921 if (strcmp(filt->name, c->comm) == 0)
922 return 1;
923 filt = filt->next;
924 }
925 return 0;
926}
927
928static int determine_display_tasks_filtered(void)
929{
930 struct per_pid *p;
931 struct per_pidcomm *c;
932 int count = 0;
933
934 p = all_data;
935 while (p) {
936 p->display = 0;
937 if (p->start_time == 1)
938 p->start_time = first_time;
939
940 /* no exit marker, task kept running to the end */
941 if (p->end_time == 0)
942 p->end_time = last_time;
943
944 c = p->all;
945
946 while (c) {
947 c->display = 0;
948
949 if (c->start_time == 1)
950 c->start_time = first_time;
951
952 if (passes_filter(p, c)) {
953 c->display = 1;
954 p->display = 1;
955 count++;
956 }
957
958 if (c->end_time == 0)
959 c->end_time = last_time;
960
961 c = c->next;
962 }
963 p = p->next;
964 }
965 return count;
966}
967
885static int determine_display_tasks(u64 threshold) 968static int determine_display_tasks(u64 threshold)
886{ 969{
887 struct per_pid *p; 970 struct per_pid *p;
888 struct per_pidcomm *c; 971 struct per_pidcomm *c;
889 int count = 0; 972 int count = 0;
890 973
974 if (process_filter)
975 return determine_display_tasks_filtered();
976
891 p = all_data; 977 p = all_data;
892 while (p) { 978 while (p) {
893 p->display = 0; 979 p->display = 0;
@@ -957,36 +1043,6 @@ static void write_svg_file(const char *filename)
957 svg_close(); 1043 svg_close();
958} 1044}
959 1045
960static int
961process_event(event_t *event)
962{
963
964 switch (event->header.type) {
965
966 case PERF_RECORD_COMM:
967 return process_comm_event(event);
968 case PERF_RECORD_FORK:
969 return process_fork_event(event);
970 case PERF_RECORD_EXIT:
971 return process_exit_event(event);
972 case PERF_RECORD_SAMPLE:
973 return queue_sample_event(event);
974
975 /*
976 * We dont process them right now but they are fine:
977 */
978 case PERF_RECORD_MMAP:
979 case PERF_RECORD_THROTTLE:
980 case PERF_RECORD_UNTHROTTLE:
981 return 0;
982
983 default:
984 return -1;
985 }
986
987 return 0;
988}
989
990static void process_samples(void) 1046static void process_samples(void)
991{ 1047{
992 struct sample_wrapper *cursor; 1048 struct sample_wrapper *cursor;
@@ -1002,107 +1058,38 @@ static void process_samples(void)
1002 } 1058 }
1003} 1059}
1004 1060
1005 1061static int sample_type_check(u64 type)
1006static int __cmd_timechart(void)
1007{ 1062{
1008 int ret, rc = EXIT_FAILURE; 1063 sample_type = type;
1009 unsigned long offset = 0;
1010 unsigned long head, shift;
1011 struct stat statbuf;
1012 event_t *event;
1013 uint32_t size;
1014 char *buf;
1015 int input;
1016
1017 input = open(input_name, O_RDONLY);
1018 if (input < 0) {
1019 fprintf(stderr, " failed to open file: %s", input_name);
1020 if (!strcmp(input_name, "perf.data"))
1021 fprintf(stderr, " (try 'perf record' first)");
1022 fprintf(stderr, "\n");
1023 exit(-1);
1024 }
1025
1026 ret = fstat(input, &statbuf);
1027 if (ret < 0) {
1028 perror("failed to stat file");
1029 exit(-1);
1030 }
1031
1032 if (!statbuf.st_size) {
1033 fprintf(stderr, "zero-sized file, nothing to do!\n");
1034 exit(0);
1035 }
1036
1037 header = perf_header__read(input);
1038 head = header->data_offset;
1039
1040 sample_type = perf_header__sample_type(header);
1041 1064
1042 shift = page_size * (head / page_size); 1065 if (!(sample_type & PERF_SAMPLE_RAW)) {
1043 offset += shift; 1066 fprintf(stderr, "No trace samples found in the file.\n"
1044 head -= shift; 1067 "Have you used 'perf timechart record' to record it?\n");
1045 1068 return -1;
1046remap:
1047 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1048 MAP_SHARED, input, offset);
1049 if (buf == MAP_FAILED) {
1050 perror("failed to mmap file");
1051 exit(-1);
1052 }
1053
1054more:
1055 event = (event_t *)(buf + head);
1056
1057 size = event->header.size;
1058 if (!size)
1059 size = 8;
1060
1061 if (head + event->header.size >= page_size * mmap_window) {
1062 int ret2;
1063
1064 shift = page_size * (head / page_size);
1065
1066 ret2 = munmap(buf, page_size * mmap_window);
1067 assert(ret2 == 0);
1068
1069 offset += shift;
1070 head -= shift;
1071 goto remap;
1072 }
1073
1074 size = event->header.size;
1075
1076 if (!size || process_event(event) < 0) {
1077
1078 printf("%p [%p]: skipping unknown header type: %d\n",
1079 (void *)(offset + head),
1080 (void *)(long)(event->header.size),
1081 event->header.type);
1082
1083 /*
1084 * assume we lost track of the stream, check alignment, and
1085 * increment a single u64 in the hope to catch on again 'soon'.
1086 */
1087
1088 if (unlikely(head & 7))
1089 head &= ~7ULL;
1090
1091 size = 8;
1092 } 1069 }
1093 1070
1094 head += size; 1071 return 0;
1072}
1095 1073
1096 if (offset + head >= header->data_offset + header->data_size) 1074static struct perf_file_handler file_handler = {
1097 goto done; 1075 .process_comm_event = process_comm_event,
1076 .process_fork_event = process_fork_event,
1077 .process_exit_event = process_exit_event,
1078 .process_sample_event = queue_sample_event,
1079 .sample_type_check = sample_type_check,
1080};
1098 1081
1099 if (offset + head < (unsigned long)statbuf.st_size) 1082static int __cmd_timechart(void)
1100 goto more; 1083{
1084 struct perf_header *header;
1085 int ret;
1101 1086
1102done: 1087 register_perf_file_handler(&file_handler);
1103 rc = EXIT_SUCCESS;
1104 close(input);
1105 1088
1089 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
1090 &event__cwdlen, &event__cwd);
1091 if (ret)
1092 return EXIT_FAILURE;
1106 1093
1107 process_samples(); 1094 process_samples();
1108 1095
@@ -1112,9 +1099,10 @@ done:
1112 1099
1113 write_svg_file(output_name); 1100 write_svg_file(output_name);
1114 1101
1115 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); 1102 pr_info("Written %2.1f seconds of trace to %s.\n",
1103 (last_time - first_time) / 1000000000.0, output_name);
1116 1104
1117 return rc; 1105 return EXIT_SUCCESS;
1118} 1106}
1119 1107
1120static const char * const timechart_usage[] = { 1108static const char * const timechart_usage[] = {
@@ -1153,6 +1141,14 @@ static int __cmd_record(int argc, const char **argv)
1153 return cmd_record(i, rec_argv, NULL); 1141 return cmd_record(i, rec_argv, NULL);
1154} 1142}
1155 1143
1144static int
1145parse_process(const struct option *opt __used, const char *arg, int __used unset)
1146{
1147 if (arg)
1148 add_process_filter(arg);
1149 return 0;
1150}
1151
1156static const struct option options[] = { 1152static const struct option options[] = {
1157 OPT_STRING('i', "input", &input_name, "file", 1153 OPT_STRING('i', "input", &input_name, "file",
1158 "input file name"), 1154 "input file name"),
@@ -1160,17 +1156,18 @@ static const struct option options[] = {
1160 "output file name"), 1156 "output file name"),
1161 OPT_INTEGER('w', "width", &svg_page_width, 1157 OPT_INTEGER('w', "width", &svg_page_width,
1162 "page width"), 1158 "page width"),
1163 OPT_BOOLEAN('p', "power-only", &power_only, 1159 OPT_BOOLEAN('P', "power-only", &power_only,
1164 "output power data only"), 1160 "output power data only"),
1161 OPT_CALLBACK('p', "process", NULL, "process",
1162 "process selector. Pass a pid or process name.",
1163 parse_process),
1165 OPT_END() 1164 OPT_END()
1166}; 1165};
1167 1166
1168 1167
1169int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1168int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1170{ 1169{
1171 symbol__init(); 1170 symbol__init(0);
1172
1173 page_size = getpagesize();
1174 1171
1175 argc = parse_options(argc, argv, options, timechart_usage, 1172 argc = parse_options(argc, argv, options, timechart_usage,
1176 PARSE_OPT_STOP_AT_NON_OPTION); 1173 PARSE_OPT_STOP_AT_NON_OPTION);