diff options
Diffstat (limited to 'trace-cmd.c')
-rw-r--r-- | trace-cmd.c | 196 |
1 files changed, 186 insertions, 10 deletions
diff --git a/trace-cmd.c b/trace-cmd.c index e89362d..cdd78f4 100644 --- a/trace-cmd.c +++ b/trace-cmd.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <sys/types.h> | 27 | #include <sys/types.h> |
28 | #include <sys/stat.h> | 28 | #include <sys/stat.h> |
29 | #include <sys/wait.h> | 29 | #include <sys/wait.h> |
30 | #include <sys/socket.h> | ||
31 | #include <netdb.h> | ||
30 | #include <pthread.h> | 32 | #include <pthread.h> |
31 | #include <fcntl.h> | 33 | #include <fcntl.h> |
32 | #include <unistd.h> | 34 | #include <unistd.h> |
@@ -48,7 +50,7 @@ | |||
48 | #define ITER_CTRL "trace_options" | 50 | #define ITER_CTRL "trace_options" |
49 | #define MAX_LATENCY "tracing_max_latency" | 51 | #define MAX_LATENCY "tracing_max_latency" |
50 | 52 | ||
51 | unsigned int page_size; | 53 | static unsigned int page_size; |
52 | 54 | ||
53 | static const char *output_file = "trace.dat"; | 55 | static const char *output_file = "trace.dat"; |
54 | 56 | ||
@@ -57,6 +59,10 @@ static int sleep_time = 1000; | |||
57 | static int cpu_count; | 59 | static int cpu_count; |
58 | static int *pids; | 60 | static int *pids; |
59 | 61 | ||
62 | static char *host; | ||
63 | static int *client_ports; | ||
64 | static int sfd; | ||
65 | |||
60 | static int filter_task; | 66 | static int filter_task; |
61 | static int filter_pid = -1; | 67 | static int filter_pid = -1; |
62 | 68 | ||
@@ -116,7 +122,7 @@ static void kill_threads(void) | |||
116 | { | 122 | { |
117 | int i; | 123 | int i; |
118 | 124 | ||
119 | if (!cpu_count) | 125 | if (!cpu_count || !pids) |
120 | return; | 126 | return; |
121 | 127 | ||
122 | for (i = 0; i < cpu_count; i++) { | 128 | for (i = 0; i < cpu_count; i++) { |
@@ -895,6 +901,41 @@ static void flush(int sig) | |||
895 | tracecmd_stop_recording(recorder); | 901 | tracecmd_stop_recording(recorder); |
896 | } | 902 | } |
897 | 903 | ||
904 | static void connect_port(int cpu) | ||
905 | { | ||
906 | struct addrinfo hints; | ||
907 | struct addrinfo *results, *rp; | ||
908 | int s; | ||
909 | char buf[BUFSIZ]; | ||
910 | |||
911 | snprintf(buf, BUFSIZ, "%d", client_ports[cpu]); | ||
912 | |||
913 | memset(&hints, 0, sizeof(hints)); | ||
914 | hints.ai_family = AF_UNSPEC; | ||
915 | hints.ai_socktype = SOCK_DGRAM; | ||
916 | |||
917 | s = getaddrinfo(host, buf, &hints, &results); | ||
918 | if (s != 0) | ||
919 | die("connecting to UDP server %s:%s", host, buf); | ||
920 | |||
921 | for (rp = results; rp != NULL; rp = rp->ai_next) { | ||
922 | sfd = socket(rp->ai_family, rp->ai_socktype, | ||
923 | rp->ai_protocol); | ||
924 | if (sfd == -1) | ||
925 | continue; | ||
926 | if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != 1) | ||
927 | break; | ||
928 | close(sfd); | ||
929 | } | ||
930 | |||
931 | if (rp == NULL) | ||
932 | die("Can not connect to UDP server %s:%s", host, buf); | ||
933 | |||
934 | freeaddrinfo(results); | ||
935 | |||
936 | client_ports[cpu] = sfd; | ||
937 | } | ||
938 | |||
898 | static int create_recorder(int cpu) | 939 | static int create_recorder(int cpu) |
899 | { | 940 | { |
900 | char *file; | 941 | char *file; |
@@ -913,10 +954,14 @@ static int create_recorder(int cpu) | |||
913 | /* do not kill tasks on error */ | 954 | /* do not kill tasks on error */ |
914 | cpu_count = 0; | 955 | cpu_count = 0; |
915 | 956 | ||
916 | file = get_temp_file(cpu); | 957 | if (client_ports) { |
917 | 958 | connect_port(cpu); | |
918 | recorder = tracecmd_create_recorder(file, cpu); | 959 | recorder = tracecmd_create_recorder_fd(client_ports[cpu], cpu); |
919 | put_temp_file(file); | 960 | } else { |
961 | file = get_temp_file(cpu); | ||
962 | recorder = tracecmd_create_recorder(file, cpu); | ||
963 | put_temp_file(file); | ||
964 | } | ||
920 | 965 | ||
921 | if (!recorder) | 966 | if (!recorder) |
922 | die ("can't create recorder"); | 967 | die ("can't create recorder"); |
@@ -927,18 +972,125 @@ static int create_recorder(int cpu) | |||
927 | exit(0); | 972 | exit(0); |
928 | } | 973 | } |
929 | 974 | ||
975 | static void setup_network(void) | ||
976 | { | ||
977 | struct tracecmd_output *handle; | ||
978 | struct addrinfo hints; | ||
979 | struct addrinfo *result, *rp; | ||
980 | int sfd, s; | ||
981 | ssize_t n; | ||
982 | char buf[BUFSIZ]; | ||
983 | char *server; | ||
984 | char *port; | ||
985 | char *p; | ||
986 | int cpu; | ||
987 | int i; | ||
988 | |||
989 | if (!strchr(host, ':')) { | ||
990 | server = strdup("localhost"); | ||
991 | if (!server) | ||
992 | die("alloctating server"); | ||
993 | port = host; | ||
994 | host = server; | ||
995 | } else { | ||
996 | host = strdup(host); | ||
997 | if (!host) | ||
998 | die("alloctating server"); | ||
999 | server = strtok_r(host, ":", &p); | ||
1000 | port = strtok_r(NULL, ":", &p); | ||
1001 | } | ||
1002 | |||
1003 | memset(&hints, 0, sizeof(hints)); | ||
1004 | hints.ai_family = AF_UNSPEC; | ||
1005 | hints.ai_socktype = SOCK_STREAM; | ||
1006 | |||
1007 | s = getaddrinfo(server, port, &hints, &result); | ||
1008 | if (s != 0) | ||
1009 | die("getaddrinfo: %s", gai_strerror(s)); | ||
1010 | |||
1011 | for (rp = result; rp != NULL; rp = rp->ai_next) { | ||
1012 | sfd = socket(rp->ai_family, rp->ai_socktype, | ||
1013 | rp->ai_protocol); | ||
1014 | if (sfd == -1) | ||
1015 | continue; | ||
1016 | |||
1017 | if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) | ||
1018 | break; | ||
1019 | close(sfd); | ||
1020 | } | ||
1021 | |||
1022 | if (!rp) | ||
1023 | die("Can not connect to %s:%d", server, port); | ||
1024 | |||
1025 | freeaddrinfo(result); | ||
1026 | |||
1027 | n = read(sfd, buf, 8); | ||
1028 | |||
1029 | /* Make sure the server is the tracecmd server */ | ||
1030 | if (memcmp(buf, "tracecmd", 8) != 0) | ||
1031 | die("server not tracecmd server"); | ||
1032 | |||
1033 | /* write the number of CPUs we have (in ASCII) */ | ||
1034 | |||
1035 | sprintf(buf, "%d", cpu_count); | ||
1036 | |||
1037 | /* include \0 */ | ||
1038 | write(sfd, buf, strlen(buf)+1); | ||
1039 | |||
1040 | /* write the pagesize (in ASCII) */ | ||
1041 | |||
1042 | page_size = getpagesize(); | ||
1043 | sprintf(buf, "%d", page_size); | ||
1044 | |||
1045 | /* include \0 */ | ||
1046 | write(sfd, buf, strlen(buf)+1); | ||
1047 | |||
1048 | client_ports = malloc_or_die(sizeof(int) * cpu_count); | ||
1049 | |||
1050 | /* | ||
1051 | * Now we will receive back a comma deliminated list | ||
1052 | * of client ports to connect to. | ||
1053 | */ | ||
1054 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
1055 | for (i = 0; i < BUFSIZ; i++) { | ||
1056 | n = read(sfd, buf+i, 1); | ||
1057 | if (n != 1) | ||
1058 | die("Error, reading server ports"); | ||
1059 | if (!buf[i] || buf[i] == ',') | ||
1060 | break; | ||
1061 | } | ||
1062 | if (i == BUFSIZ) | ||
1063 | die("read bad port number"); | ||
1064 | buf[i] = 0; | ||
1065 | client_ports[cpu] = atoi(buf); | ||
1066 | } | ||
1067 | |||
1068 | /* Now create the handle through this socket */ | ||
1069 | handle = tracecmd_create_init_fd(sfd, cpu_count); | ||
1070 | |||
1071 | /* OK, we are all set, let'r rip! */ | ||
1072 | } | ||
1073 | |||
1074 | static void finish_network(void) | ||
1075 | { | ||
1076 | close(sfd); | ||
1077 | free(host); | ||
1078 | } | ||
1079 | |||
930 | static void start_threads(void) | 1080 | static void start_threads(void) |
931 | { | 1081 | { |
932 | int i; | 1082 | int i; |
933 | 1083 | ||
934 | cpu_count = count_cpus(); | 1084 | cpu_count = count_cpus(); |
935 | 1085 | ||
1086 | if (host) | ||
1087 | setup_network(); | ||
1088 | |||
936 | /* make a thread for every CPU we have */ | 1089 | /* make a thread for every CPU we have */ |
937 | pids = malloc_or_die(sizeof(*pids) * cpu_count); | 1090 | pids = malloc_or_die(sizeof(*pids) * cpu_count); |
938 | 1091 | ||
939 | memset(pids, 0, sizeof(*pids) * cpu_count); | 1092 | memset(pids, 0, sizeof(*pids) * cpu_count); |
940 | 1093 | ||
941 | |||
942 | for (i = 0; i < cpu_count; i++) { | 1094 | for (i = 0; i < cpu_count; i++) { |
943 | pids[i] = create_recorder(i); | 1095 | pids[i] = create_recorder(i); |
944 | } | 1096 | } |
@@ -950,6 +1102,11 @@ static void record_data(void) | |||
950 | char **temp_files; | 1102 | char **temp_files; |
951 | int i; | 1103 | int i; |
952 | 1104 | ||
1105 | if (host) { | ||
1106 | finish_network(); | ||
1107 | return; | ||
1108 | } | ||
1109 | |||
953 | if (latency) | 1110 | if (latency) |
954 | handle = tracecmd_create_file_latency(output_file, cpu_count); | 1111 | handle = tracecmd_create_file_latency(output_file, cpu_count); |
955 | else { | 1112 | else { |
@@ -1066,7 +1223,7 @@ void usage(char **argv) | |||
1066 | "usage:\n" | 1223 | "usage:\n" |
1067 | " %s record [-v][-e event [-f filter]][-p plugin][-F][-d][-o file] \\\n" | 1224 | " %s record [-v][-e event [-f filter]][-p plugin][-F][-d][-o file] \\\n" |
1068 | " [-s usecs][-O option ][-l func][-g func][-n func]\n" | 1225 | " [-s usecs][-O option ][-l func][-g func][-n func]\n" |
1069 | " [-P pid][command ...]\n" | 1226 | " [-P pid][-N host:port][command ...]\n" |
1070 | " -e run command with event enabled\n" | 1227 | " -e run command with event enabled\n" |
1071 | " -f filter for previous -e event\n" | 1228 | " -f filter for previous -e event\n" |
1072 | " -p run command with plugin enabled\n" | 1229 | " -p run command with plugin enabled\n" |
@@ -1080,6 +1237,7 @@ void usage(char **argv) | |||
1080 | " -o data output file [default trace.dat]\n" | 1237 | " -o data output file [default trace.dat]\n" |
1081 | " -O option to enable (or disable)\n" | 1238 | " -O option to enable (or disable)\n" |
1082 | " -s sleep interval between recording (in usecs) [default: 1000]\n" | 1239 | " -s sleep interval between recording (in usecs) [default: 1000]\n" |
1240 | " -N host:port to connect to (see listen)\n" | ||
1083 | "\n" | 1241 | "\n" |
1084 | " %s start [-e event][-p plugin][-d][-O option ][-P pid]\n" | 1242 | " %s start [-e event][-p plugin][-d][-O option ][-P pid]\n" |
1085 | " Uses same options as record, but does not run a command.\n" | 1243 | " Uses same options as record, but does not run a command.\n" |
@@ -1122,11 +1280,17 @@ void usage(char **argv) | |||
1122 | " if left out, will start at beginning of file\n" | 1280 | " if left out, will start at beginning of file\n" |
1123 | " end - decimal end time in seconds\n" | 1281 | " end - decimal end time in seconds\n" |
1124 | "\n" | 1282 | "\n" |
1283 | " %s listen -p port[-D][-o file][-d dir]\n" | ||
1284 | " Creates a socket to listen for clients.\n" | ||
1285 | " -D create it in daemon mode.\n" | ||
1286 | " -o file name to use for clients.\n" | ||
1287 | " -d diretory to store client files.\n" | ||
1288 | "\n" | ||
1125 | " %s list [-e][-p]\n" | 1289 | " %s list [-e][-p]\n" |
1126 | " -e list available events\n" | 1290 | " -e list available events\n" |
1127 | " -p list available plugins\n" | 1291 | " -p list available plugins\n" |
1128 | " -o list available options\n" | 1292 | " -o list available options\n" |
1129 | "\n", p, VERSION_STRING, p, p, p, p, p, p, p, p); | 1293 | "\n", p, VERSION_STRING, p, p, p, p, p, p, p, p, p); |
1130 | exit(-1); | 1294 | exit(-1); |
1131 | } | 1295 | } |
1132 | 1296 | ||
@@ -1159,6 +1323,9 @@ int main (int argc, char **argv) | |||
1159 | if (strcmp(argv[1], "report") == 0) { | 1323 | if (strcmp(argv[1], "report") == 0) { |
1160 | trace_report(argc, argv); | 1324 | trace_report(argc, argv); |
1161 | exit(0); | 1325 | exit(0); |
1326 | } else if (strcmp(argv[1], "listen") == 0) { | ||
1327 | trace_listen(argc, argv); | ||
1328 | exit(0); | ||
1162 | } else if (strcmp(argv[1], "split") == 0) { | 1329 | } else if (strcmp(argv[1], "split") == 0) { |
1163 | trace_split(argc, argv); | 1330 | trace_split(argc, argv); |
1164 | exit(0); | 1331 | exit(0); |
@@ -1166,7 +1333,7 @@ int main (int argc, char **argv) | |||
1166 | (strcmp(argv[1], "start") == 0) || | 1333 | (strcmp(argv[1], "start") == 0) || |
1167 | ((extract = strcmp(argv[1], "extract") == 0))) { | 1334 | ((extract = strcmp(argv[1], "extract") == 0))) { |
1168 | 1335 | ||
1169 | while ((c = getopt(argc-1, argv+1, "+he:f:Fp:do:O:s:vg:l:n:P:")) >= 0) { | 1336 | while ((c = getopt(argc-1, argv+1, "+he:f:Fp:do:O:s:vg:l:n:P:N:")) >= 0) { |
1170 | switch (c) { | 1337 | switch (c) { |
1171 | case 'h': | 1338 | case 'h': |
1172 | usage(argv); | 1339 | usage(argv); |
@@ -1241,6 +1408,8 @@ int main (int argc, char **argv) | |||
1241 | disable = 1; | 1408 | disable = 1; |
1242 | break; | 1409 | break; |
1243 | case 'o': | 1410 | case 'o': |
1411 | if (host) | ||
1412 | die("-o incompatible with -N"); | ||
1244 | if (!record && !extract) | 1413 | if (!record && !extract) |
1245 | die("start does not take output\n" | 1414 | die("start does not take output\n" |
1246 | "Did you mean 'record'?"); | 1415 | "Did you mean 'record'?"); |
@@ -1257,6 +1426,13 @@ int main (int argc, char **argv) | |||
1257 | usage(argv); | 1426 | usage(argv); |
1258 | sleep_time = atoi(optarg); | 1427 | sleep_time = atoi(optarg); |
1259 | break; | 1428 | break; |
1429 | case 'N': | ||
1430 | if (!record) | ||
1431 | die("-N only available with record"); | ||
1432 | if (output) | ||
1433 | die("-N incompatible with -o"); | ||
1434 | host = optarg; | ||
1435 | break; | ||
1260 | } | 1436 | } |
1261 | } | 1437 | } |
1262 | 1438 | ||