aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-12-14 10:00:59 -0500
committerSteven Rostedt <rostedt@goodmis.org>2009-12-14 10:00:59 -0500
commit37250afc820f712eb0de4340d25c9625ef6fa634 (patch)
treeb76111805c7f8007c97a52d64c0cce6a2746839f
parent8883a04e689e370e3ca3383003909d3d0b8558bf (diff)
Move writing to data file to library
We need a way to have other applications easily make the output file. This moves the recording of the trace.dat file to the trace-cmd library. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile9
-rw-r--r--parse-events.h2
-rw-r--r--trace-cmd.c642
-rw-r--r--trace-cmd.h33
-rw-r--r--trace-input.c2
-rw-r--r--trace-output.c700
-rw-r--r--trace-record.c133
-rw-r--r--trace-util.c42
8 files changed, 1000 insertions, 563 deletions
diff --git a/Makefile b/Makefile
index f159a46..42cb7ad 100644
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,12 @@ trace-util.o:: trace-util.c
39trace-input.o:: trace-input.c 39trace-input.o:: trace-input.c
40 $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@ 40 $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@
41 41
42trace-output.o:: trace-output.c
43 $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@
44
45trace-record.o:: trace-record.c
46 $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@
47
42trace-ftrace.o:: trace-ftrace.c 48trace-ftrace.o:: trace-ftrace.c
43 $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@ 49 $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@
44 50
@@ -50,7 +56,8 @@ libparsevent.so: $(PEVENT_LIB_OBJS)
50libparsevent.a: $(PEVENT_LIB_OBJS) 56libparsevent.a: $(PEVENT_LIB_OBJS)
51 $(RM) $@; $(AR) rcs $@ $^ 57 $(RM) $@; $(AR) rcs $@ $^
52 58
53TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o 59TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \
60 trace-output.o trace-record.o
54 61
55libtracecmd.so: $(TCMD_LIB_OBJS) 62libtracecmd.so: $(TCMD_LIB_OBJS)
56 $(CC) --shared $^ -o $@ 63 $(CC) --shared $^ -o $@
diff --git a/parse-events.h b/parse-events.h
index db7e259..9b5ba0d 100644
--- a/parse-events.h
+++ b/parse-events.h
@@ -273,8 +273,6 @@ void die(char *fmt, ...);
273void *malloc_or_die(unsigned int size); 273void *malloc_or_die(unsigned int size);
274void warning(char *fmt, ...); 274void warning(char *fmt, ...);
275 275
276int bigendian(void);
277
278static inline unsigned short 276static inline unsigned short
279__data2host2(struct pevent *pevent, unsigned short data) 277__data2host2(struct pevent *pevent, unsigned short data)
280{ 278{
diff --git a/trace-cmd.c b/trace-cmd.c
index aca6f90..aada9a4 100644
--- a/trace-cmd.c
+++ b/trace-cmd.c
@@ -35,8 +35,6 @@
35 35
36#include "trace-local.h" 36#include "trace-local.h"
37 37
38#define VERSION "0.5"
39
40#define _STR(x) #x 38#define _STR(x) #x
41#define STR(x) _STR(x) 39#define STR(x) _STR(x)
42#define MAX_PATH 256 40#define MAX_PATH 256
@@ -51,7 +49,6 @@
51unsigned int page_size; 49unsigned int page_size;
52 50
53static const char *output_file = "trace.dat"; 51static const char *output_file = "trace.dat";
54static int output_fd;
55 52
56static int latency; 53static int latency;
57 54
@@ -72,6 +69,25 @@ struct events {
72 char *name; 69 char *name;
73}; 70};
74 71
72static struct tracecmd_recorder *recorder;
73
74static char *get_temp_file(int cpu)
75{
76 char *file = NULL;
77 int size;
78
79 size = snprintf(file, 0, "%s.cpu%d", output_file, cpu);
80 file = malloc_or_die(size + 1);
81 sprintf(file, "%s.cpu%d", output_file, cpu);
82
83 return file;
84}
85
86static void put_temp_file(char *file)
87{
88 free(file);
89}
90
75static void delete_temp_file(int cpu) 91static void delete_temp_file(int cpu)
76{ 92{
77 char file[MAX_PATH]; 93 char file[MAX_PATH];
@@ -174,79 +190,6 @@ void *malloc_or_die(unsigned int size)
174 return data; 190 return data;
175} 191}
176 192
177static const char *find_debugfs(void)
178{
179 static char debugfs[MAX_PATH+1];
180 static int debugfs_found;
181 char type[100];
182 FILE *fp;
183
184 if (debugfs_found)
185 return debugfs;
186
187 if ((fp = fopen("/proc/mounts","r")) == NULL)
188 die("Can't open /proc/mounts for read");
189
190 while (fscanf(fp, "%*s %"
191 STR(MAX_PATH)
192 "s %99s %*s %*d %*d\n",
193 debugfs, type) == 2) {
194 if (strcmp(type, "debugfs") == 0)
195 break;
196 }
197 fclose(fp);
198
199 if (strcmp(type, "debugfs") != 0)
200 die("debugfs not mounted, please mount");
201
202 debugfs_found = 1;
203
204 return debugfs;
205}
206
207/*
208 * Finds the path to the debugfs/tracing
209 * Allocates the string and stores it.
210 */
211static const char *find_tracing_dir(void)
212{
213 static char *tracing;
214 static int tracing_found;
215 const char *debugfs;
216
217 if (tracing_found)
218 return tracing;
219
220 debugfs = find_debugfs();
221
222 tracing = malloc_or_die(strlen(debugfs) + 9);
223
224 sprintf(tracing, "%s/tracing", debugfs);
225
226 tracing_found = 1;
227 return tracing;
228}
229
230static char *get_tracing_file(const char *name)
231{
232 const char *tracing;
233 char *file;
234
235 tracing = find_tracing_dir();
236 if (!tracing)
237 return NULL;
238
239 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
240
241 sprintf(file, "%s/%s", tracing, name);
242 return file;
243}
244
245static void put_tracing_file(char *file)
246{
247 free(file);
248}
249
250static int set_ftrace(int set) 193static int set_ftrace(int set)
251{ 194{
252 struct stat buf; 195 struct stat buf;
@@ -284,6 +227,30 @@ void run_cmd(int argc, char **argv)
284 waitpid(pid, &status, 0); 227 waitpid(pid, &status, 0);
285} 228}
286 229
230static char *get_tracing_file(const char *name)
231{
232 static const char *tracing;
233 char *file;
234
235 if (!tracing) {
236 tracing = tracecmd_find_tracing_dir();
237 if (!tracing)
238 die("Can't find tracing dir");
239 }
240
241 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
242 if (!file)
243 return NULL;
244
245 sprintf(file, "%s/%s", tracing, name);
246 return file;
247}
248
249static void put_tracing_file(char *file)
250{
251 free(file);
252}
253
287static void show_events(void) 254static void show_events(void)
288{ 255{
289 char buf[BUFSIZ]; 256 char buf[BUFSIZ];
@@ -572,20 +539,15 @@ static int finished;
572static void finish(int sig) 539static void finish(int sig)
573{ 540{
574 /* all done */ 541 /* all done */
542 if (recorder)
543 tracecmd_stop_recording(recorder);
575 finished = 1; 544 finished = 1;
576} 545}
577 546
578static int create_recorder(int cpu) 547static int create_recorder(int cpu)
579{ 548{
580 char file[MAX_PATH]; 549 char *file;
581 const char *tracing;
582 char *path;
583 int out_fd;
584 int in_fd;
585 int brass[2];
586 int pid; 550 int pid;
587 int ret;
588 char buf[page_size];
589 551
590 pid = fork(); 552 pid = fork();
591 if (pid < 0) 553 if (pid < 0)
@@ -599,40 +561,15 @@ static int create_recorder(int cpu)
599 /* do not kill tasks on error */ 561 /* do not kill tasks on error */
600 cpu_count = 0; 562 cpu_count = 0;
601 563
602 snprintf(file, MAX_PATH, "%s.cpu%d", output_file, cpu); 564 file = get_temp_file(cpu);
603 565
604 out_fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); 566 recorder = tracecmd_create_recorder(file, cpu);
605 if (out_fd < 0) 567 put_temp_file(file);
606 die("can't create file '%s'", file);
607 568
608 tracing = find_tracing_dir(); 569 if (!recorder)
609 570 die ("can't create recorder");
610 path = malloc_or_die(strlen(tracing) + 40); 571 tracecmd_start_recording(recorder);
611 572 tracecmd_free_recorder(recorder);
612 sprintf(path, "%s/per_cpu/cpu%d/trace_pipe_raw", tracing, cpu);
613 in_fd = open(path, O_RDONLY);
614 if (in_fd < 0)
615 die("can not read '%s'", path);
616
617 ret = pipe(brass);
618 if (ret < 0)
619 die("can not create pipe");
620
621 do {
622 ret = splice(in_fd, NULL, brass[1], NULL, page_size, 1 /* SPLICE_F_MOVE */);
623 if (ret < 0)
624 die("splice in");
625 ret = splice(brass[0], NULL, out_fd, NULL, page_size, 3 /* and NON_BLOCK */);
626 if (ret < 0 && errno != EAGAIN)
627 die("splice out");
628 } while (!finished);
629
630 /* splice only reads full pages */
631 do {
632 ret = read(in_fd, buf, page_size);
633 if (ret > 0)
634 write(out_fd, buf, ret);
635 } while (ret > 0);
636 573
637 exit(0); 574 exit(0);
638} 575}
@@ -656,442 +593,32 @@ static void start_threads(void)
656 } 593 }
657} 594}
658 595
659static ssize_t write_or_die(const void *buf, size_t len) 596static void record_data(void)
660{
661 int ret;
662
663 ret = write(output_fd, buf, len);
664 if (ret < 0)
665 die("writing to '%s'", output_file);
666
667 return ret;
668}
669
670int bigendian(void)
671{
672 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
673 unsigned int *ptr;
674
675 ptr = (unsigned int *)str;
676 return *ptr == 0x01020304;
677}
678
679static unsigned long long copy_file_fd(int fd)
680{
681 unsigned long long size = 0;
682 char buf[BUFSIZ];
683 int r;
684
685 do {
686 r = read(fd, buf, BUFSIZ);
687 if (r > 0) {
688 size += r;
689 write_or_die(buf, r);
690 }
691 } while (r > 0);
692
693 return size;
694}
695
696static unsigned long long copy_file(const char *file)
697{ 597{
698 unsigned long long size = 0; 598 struct tracecmd_output *handle;
699 int fd; 599 char **temp_files;
700
701 fd = open(file, O_RDONLY);
702 if (fd < 0)
703 die("Can't read '%s'", file);
704 size = copy_file_fd(fd);
705 close(fd);
706
707 return size;
708}
709
710static unsigned long get_size_fd(int fd)
711{
712 unsigned long long size = 0;
713 char buf[BUFSIZ];
714 int r;
715
716 do {
717 r = read(fd, buf, BUFSIZ);
718 if (r > 0)
719 size += r;
720 } while (r > 0);
721
722 lseek(fd, 0, SEEK_SET);
723
724 return size;
725}
726
727static unsigned long get_size(const char *file)
728{
729 unsigned long long size = 0;
730 int fd;
731
732 fd = open(file, O_RDONLY);
733 if (fd < 0)
734 die("Can't read '%s'", file);
735 size = get_size_fd(fd);
736 close(fd);
737
738 return size;
739}
740
741static void read_header_files(void)
742{
743 unsigned long long size, check_size;
744 struct stat st;
745 char *path;
746 int fd;
747 int ret;
748
749 path = get_tracing_file("events/header_page");
750
751 ret = stat(path, &st);
752 if (ret < 0) {
753 /* old style did not show this info, just add zero */
754 put_tracing_file(path);
755 write_or_die("header_page", 12);
756 size = 0;
757 write_or_die(&size, 8);
758 write_or_die("header_event", 13);
759 write_or_die(&size, 8);
760 return;
761 }
762
763 fd = open(path, O_RDONLY);
764 if (fd < 0)
765 die("can't read '%s'", path);
766
767 /* unfortunately, you can not stat debugfs files for size */
768 size = get_size_fd(fd);
769
770 write_or_die("header_page", 12);
771 write_or_die(&size, 8);
772 check_size = copy_file_fd(fd);
773 if (size != check_size)
774 die("wrong size for '%s' size=%lld read=%lld",
775 path, size, check_size);
776 put_tracing_file(path);
777
778 path = get_tracing_file("events/header_event");
779 fd = open(path, O_RDONLY);
780 if (fd < 0)
781 die("can't read '%s'", path);
782
783 size = get_size_fd(fd);
784
785 write_or_die("header_event", 13);
786 write_or_die(&size, 8);
787 check_size = copy_file_fd(fd);
788 if (size != check_size)
789 die("wrong size for '%s'", path);
790 put_tracing_file(path);
791}
792
793static void copy_event_system(const char *sys)
794{
795 unsigned long long size, check_size;
796 struct dirent *dent;
797 struct stat st;
798 char *format;
799 DIR *dir;
800 int count = 0;
801 int ret;
802
803 dir = opendir(sys);
804 if (!dir)
805 die("can't read directory '%s'", sys);
806
807 while ((dent = readdir(dir))) {
808 if (strcmp(dent->d_name, ".") == 0 ||
809 strcmp(dent->d_name, "..") == 0)
810 continue;
811 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
812 sprintf(format, "%s/%s/format", sys, dent->d_name);
813 ret = stat(format, &st);
814 free(format);
815 if (ret < 0)
816 continue;
817 count++;
818 }
819
820 write_or_die(&count, 4);
821
822 rewinddir(dir);
823 while ((dent = readdir(dir))) {
824 if (strcmp(dent->d_name, ".") == 0 ||
825 strcmp(dent->d_name, "..") == 0)
826 continue;
827 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
828 sprintf(format, "%s/%s/format", sys, dent->d_name);
829 ret = stat(format, &st);
830
831 if (ret >= 0) {
832 /* unfortunately, you can not stat debugfs files for size */
833 size = get_size(format);
834 write_or_die(&size, 8);
835 check_size = copy_file(format);
836 if (size != check_size)
837 die("error in size of file '%s'", format);
838 }
839
840 free(format);
841 }
842}
843
844static void read_ftrace_files(void)
845{
846 char *path;
847
848 path = get_tracing_file("events/ftrace");
849
850 copy_event_system(path);
851
852 put_tracing_file(path);
853}
854
855static void read_event_files(void)
856{
857 struct dirent *dent;
858 struct stat st;
859 char *path;
860 char *sys;
861 DIR *dir;
862 int count = 0;
863 int ret;
864
865 path = get_tracing_file("events");
866
867 dir = opendir(path);
868 if (!dir)
869 die("can't read directory '%s'", path);
870
871 while ((dent = readdir(dir))) {
872 if (strcmp(dent->d_name, ".") == 0 ||
873 strcmp(dent->d_name, "..") == 0 ||
874 strcmp(dent->d_name, "ftrace") == 0)
875 continue;
876 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
877 sprintf(sys, "%s/%s", path, dent->d_name);
878 ret = stat(sys, &st);
879 free(sys);
880 if (ret < 0)
881 continue;
882 if (S_ISDIR(st.st_mode))
883 count++;
884 }
885
886 write_or_die(&count, 4);
887
888 rewinddir(dir);
889 while ((dent = readdir(dir))) {
890 if (strcmp(dent->d_name, ".") == 0 ||
891 strcmp(dent->d_name, "..") == 0 ||
892 strcmp(dent->d_name, "ftrace") == 0)
893 continue;
894 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
895 sprintf(sys, "%s/%s", path, dent->d_name);
896 ret = stat(sys, &st);
897 if (ret >= 0) {
898 if (S_ISDIR(st.st_mode)) {
899 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
900 copy_event_system(sys);
901 }
902 }
903 free(sys);
904 }
905
906 put_tracing_file(path);
907}
908
909static void read_proc_kallsyms(void)
910{
911 unsigned int size, check_size;
912 const char *path = "/proc/kallsyms";
913 struct stat st;
914 int ret;
915
916 ret = stat(path, &st);
917 if (ret < 0) {
918 /* not found */
919 size = 0;
920 write_or_die(&size, 4);
921 return;
922 }
923 size = get_size(path);
924 write_or_die(&size, 4);
925 check_size = copy_file(path);
926 if (size != check_size)
927 die("error in size of file '%s'", path);
928
929}
930
931static void read_ftrace_printk(void)
932{
933 unsigned int size, check_size;
934 const char *path;
935 struct stat st;
936 int ret;
937
938 path = get_tracing_file("printk_formats");
939 ret = stat(path, &st);
940 if (ret < 0) {
941 /* not found */
942 size = 0;
943 write_or_die(&size, 4);
944 return;
945 }
946 size = get_size(path);
947 write_or_die(&size, 4);
948 check_size = copy_file(path);
949 if (size != check_size)
950 die("error in size of file '%s'", path);
951
952}
953
954static void read_tracing_data(void)
955{
956 char buf[BUFSIZ];
957
958 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
959 if (output_fd < 0)
960 die("creating file '%s'", output_file);
961
962 buf[0] = 23;
963 buf[1] = 8;
964 buf[2] = 68;
965 memcpy(buf + 3, "tracing", 7);
966
967 write_or_die(buf, 10);
968
969 write_or_die(VERSION, strlen(VERSION) + 1);
970
971 /* save endian */
972 if (bigendian())
973 buf[0] = 1;
974 else
975 buf[0] = 0;
976
977 write_or_die(buf, 1);
978
979 /* save size of long */
980 buf[0] = sizeof(long);
981 write_or_die(buf, 1);
982
983 /* save page_size */
984 page_size = getpagesize();
985 write_or_die(&page_size, 4);
986
987 read_header_files();
988 read_ftrace_files();
989 read_event_files();
990 read_proc_kallsyms();
991 read_ftrace_printk();
992}
993
994static unsigned long long read_thread_file(int cpu)
995{
996 unsigned long long size;
997 char *file;
998
999 file = malloc_or_die(strlen(output_file) + 20);
1000 snprintf(file, MAX_PATH, "%s.cpu%d", output_file, cpu);
1001
1002 size = copy_file(file);
1003 free(file);
1004 return size;
1005}
1006
1007static void read_trace_data(void)
1008{
1009 char *path;
1010
1011 write_or_die("latency ", 10);
1012
1013 path = get_tracing_file("trace");
1014
1015 copy_file(path);
1016
1017 put_tracing_file(path);
1018}
1019
1020static void read_thread_data(void)
1021{
1022 unsigned long long offset, check_size;
1023 unsigned long long *offsets;
1024 unsigned long long *sizes;
1025 unsigned long long size;
1026 long long ret;
1027 struct stat st;
1028 char *file;
1029 int i; 600 int i;
1030
1031 if (!cpu_count)
1032 return;
1033
1034 /*
1035 * Save the command lines;
1036 */
1037 file = get_tracing_file("saved_cmdlines");
1038 ret = stat(file, &st);
1039 if (ret >= 0) {
1040 size = get_size(file);
1041 write_or_die(&size, 8);
1042 check_size = copy_file(file);
1043 if (size != check_size)
1044 die("error in size of file '%s'", file);
1045 } else {
1046 size = 0;
1047 write_or_die(&size, 8);
1048 }
1049 put_tracing_file(file);
1050
1051 write_or_die(&cpu_count, 4);
1052
1053 if (latency) {
1054 read_trace_data();
1055 return;
1056 }
1057 601
1058 write_or_die("flyrecord", 10); 602 if (latency)
603 handle = tracecmd_create_file_latency(output_file, cpu_count);
604 else {
605 if (!cpu_count)
606 return;
1059 607
1060 offsets = malloc_or_die(sizeof(*offsets) * cpu_count); 608 temp_files = malloc_or_die(sizeof(*temp_files) * cpu_count);
1061 sizes = malloc_or_die(sizeof(*sizes) * cpu_count);
1062 609
1063 offset = lseek(output_fd, 0, SEEK_CUR); 610 for (i = 0; i < cpu_count; i++)
611 temp_files[i] = get_temp_file(i);
1064 612
1065 /* hold any extra data for data */ 613 handle = tracecmd_create_file(output_file, cpu_count, temp_files);
1066 offset += cpu_count * (16);
1067 offset = (offset + (page_size - 1)) & ~(PAGE_MASK);
1068 614
1069 for (i = 0; i < cpu_count; i++) { 615 for (i = 0; i < cpu_count; i++)
1070 file = malloc_or_die(strlen(output_file) + 20); 616 put_temp_file(temp_files[i]);
1071 sprintf(file, "%s.cpu%d", output_file, i); 617 free(temp_files);
1072 ret = stat(file, &st);
1073 if (ret < 0)
1074 die("can not stat '%s'", file);
1075 free(file);
1076 offsets[i] = offset;
1077 sizes[i] = st.st_size;
1078 offset += st.st_size;
1079 offset = (offset + (page_size - 1)) & ~(PAGE_MASK);
1080
1081 write_or_die(&offsets[i], 8);
1082 write_or_die(&sizes[i], 8);
1083 }
1084
1085 for (i = 0; i < cpu_count; i++) {
1086 fprintf(stderr, "offset=%llx\n", offsets[i]);
1087 ret = lseek64(output_fd, offsets[i], SEEK_SET);
1088 if (ret < 0)
1089 die("could not seek to %lld\n", offsets[i]);
1090 check_size = read_thread_file(i);
1091 if (check_size != sizes[i])
1092 die("did not match size of %lld to %lld",
1093 check_size, sizes[i]);
1094 } 618 }
619 if (!handle)
620 die("could not write to file");
621 tracecmd_output_close(handle);
1095} 622}
1096 623
1097void usage(char **argv) 624void usage(char **argv)
@@ -1137,7 +664,7 @@ void usage(char **argv)
1137 " -e list available events\n" 664 " -e list available events\n"
1138 " -p list available plugins\n" 665 " -p list available plugins\n"
1139 " -o list available options\n" 666 " -o list available options\n"
1140 "\n", p, VERSION, p, p, p, p, p, p); 667 "\n", p, TRACECMD_VERSION, p, p, p, p, p, p);
1141 exit(-1); 668 exit(-1);
1142} 669}
1143 670
@@ -1268,15 +795,8 @@ int main (int argc, char **argv)
1268 if (!events && !plugin) 795 if (!events && !plugin)
1269 die("no event or plugin was specified... aborting"); 796 die("no event or plugin was specified... aborting");
1270 797
1271 if (record) { 798 if (output)
1272 if (output) 799 output_file = output;
1273 output_file = output;
1274
1275 read_tracing_data();
1276
1277 start_threads();
1278 signal(SIGINT, finish);
1279 }
1280 800
1281 fset = set_ftrace(!disable); 801 fset = set_ftrace(!disable);
1282 disable_all(); 802 disable_all();
@@ -1294,9 +814,6 @@ int main (int argc, char **argv)
1294 strcmp(plugin, "wakeup") == 0 || 814 strcmp(plugin, "wakeup") == 0 ||
1295 strcmp(plugin, "wakeup_rt") == 0) { 815 strcmp(plugin, "wakeup_rt") == 0) {
1296 latency = 1; 816 latency = 1;
1297 if (record)
1298 stop_threads();
1299 reset_max_latency();
1300 } 817 }
1301 if (fset < 0 && (strcmp(plugin, "function") == 0 || 818 if (fset < 0 && (strcmp(plugin, "function") == 0 ||
1302 strcmp(plugin, "function_graph") == 0)) 819 strcmp(plugin, "function_graph") == 0))
@@ -1304,7 +821,15 @@ int main (int argc, char **argv)
1304 set_plugin(plugin); 821 set_plugin(plugin);
1305 } 822 }
1306 823
824 if (record) {
825 if (!latency)
826 start_threads();
827 signal(SIGINT, finish);
828 }
829
1307 enable_tracing(); 830 enable_tracing();
831 if (latency)
832 reset_max_latency();
1308 833
1309 if (!record) 834 if (!record)
1310 exit(0); 835 exit(0);
@@ -1316,14 +841,13 @@ int main (int argc, char **argv)
1316 printf("Hit Ctrl^C to stop recording\n"); 841 printf("Hit Ctrl^C to stop recording\n");
1317 while (!finished) 842 while (!finished)
1318 sleep(10); 843 sleep(10);
1319
1320 } 844 }
1321 845
1322 disable_tracing(); 846 disable_tracing();
1323 847
1324 stop_threads(); 848 stop_threads();
1325 849
1326 read_thread_data(); 850 record_data();
1327 delete_thread_data(); 851 delete_thread_data();
1328 852
1329 exit(0); 853 exit(0);
diff --git a/trace-cmd.h b/trace-cmd.h
index cc63627..9fbd475 100644
--- a/trace-cmd.h
+++ b/trace-cmd.h
@@ -10,6 +10,8 @@ extern const char *input_file;
10#define PAGE_MASK (page_size - 1) 10#define PAGE_MASK (page_size - 1)
11#endif 11#endif
12 12
13#define TRACECMD_VERSION "0.5"
14
13void parse_cmdlines(struct pevent *pevent, char *file, int size); 15void parse_cmdlines(struct pevent *pevent, char *file, int size);
14void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 16void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
15void parse_ftrace_printk(char *file, unsigned int size); 17void parse_ftrace_printk(char *file, unsigned int size);
@@ -35,6 +37,21 @@ struct record {
35}; 37};
36 38
37struct tracecmd_input; 39struct tracecmd_input;
40struct tracecmd_output;
41struct tracecmd_recorder;
42
43static inline int tracecmd_host_bigendian(void)
44{
45 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
46 unsigned int *ptr;
47
48 ptr = (unsigned int *)str;
49 return *ptr == 0x01020304;
50}
51
52char *tracecmd_find_tracing_dir(void);
53
54/* --- Opening and Reading the trace.dat file --- */
38 55
39struct tracecmd_input *tracecmd_open(int fd); 56struct tracecmd_input *tracecmd_open(int fd);
40int tracecmd_read_headers(struct tracecmd_input *handle); 57int tracecmd_read_headers(struct tracecmd_input *handle);
@@ -68,4 +85,20 @@ struct pevent *tracecmd_get_pevent(struct tracecmd_input *handle);
68/* hack for function graph work around */ 85/* hack for function graph work around */
69extern __thread struct tracecmd_input *tracecmd_curr_thread_handle; 86extern __thread struct tracecmd_input *tracecmd_curr_thread_handle;
70 87
88
89/* --- Creating and Writing the trace.dat file --- */
90
91struct tracecmd_output *tracecmd_create_file_latency(const char *output_file, int cpus);
92struct tracecmd_output *tracecmd_create_file(const char *output_file,
93 int cpus, char * const *cpu_data_files);
94void tracecmd_output_close(struct tracecmd_output *handle);
95
96/* --- Reading the Fly Recorder Trace --- */
97
98void tracecmd_free_recorder(struct tracecmd_recorder *recorder);
99struct tracecmd_recorder *tracecmd_create_recorder(const char *file, int cpu);
100int tracecmd_start_recording(struct tracecmd_recorder *recorder);
101void tracecmd_stop_recording(struct tracecmd_recorder *recorder);
102
103
71#endif /* _TRACE_CMD_H */ 104#endif /* _TRACE_CMD_H */
diff --git a/trace-input.c b/trace-input.c
index 9e61d20..f37fb6a 100644
--- a/trace-input.c
+++ b/trace-input.c
@@ -1197,7 +1197,7 @@ struct tracecmd_input *tracecmd_open(int fd)
1197 goto failed_read; 1197 goto failed_read;
1198 1198
1199 handle->pevent->file_bigendian = buf[0]; 1199 handle->pevent->file_bigendian = buf[0];
1200 handle->pevent->host_bigendian = bigendian(); 1200 handle->pevent->host_bigendian = tracecmd_host_bigendian();
1201 1201
1202 do_read_check(handle, buf, 1); 1202 do_read_check(handle, buf, 1);
1203 handle->long_size = buf[0]; 1203 handle->long_size = buf[0];
diff --git a/trace-output.c b/trace-output.c
new file mode 100644
index 0000000..8f21fe4
--- /dev/null
+++ b/trace-output.c
@@ -0,0 +1,700 @@
1#define _LARGEFILE64_SOURCE
2#define _GNU_SOURCE
3#include <dirent.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <getopt.h>
8#include <stdarg.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <sys/wait.h>
12#include <sys/mman.h>
13#include <pthread.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <ctype.h>
17#include <errno.h>
18
19#include "trace-cmd.h"
20
21struct tracecmd_output {
22 int fd;
23 int page_size;
24 int cpus;
25 char *tracing_dir;
26};
27
28static int do_write(struct tracecmd_output *handle, void *data, int size)
29{
30 int tot = 0;
31 int w;
32
33 do {
34 w = write(handle->fd, data, size - tot);
35 tot += w;
36
37 if (!w)
38 break;
39 if (w < 0)
40 return w;
41 } while (tot != size);
42
43 return tot;
44}
45
46static int
47do_write_check(struct tracecmd_output *handle, void *data, int size)
48{
49 int ret;
50
51 ret = do_write(handle, data, size);
52 if (ret < 0)
53 return ret;
54 if (ret != size)
55 return -1;
56
57 return 0;
58}
59
60void tracecmd_output_close(struct tracecmd_output *handle)
61{
62 if (!handle)
63 return;
64
65 if (handle->fd >= 0) {
66 close(handle->fd);
67 handle->fd = -1;
68 }
69
70 if (handle->tracing_dir)
71 free(handle->tracing_dir);
72
73 free(handle);
74}
75
76static unsigned long get_size_fd(int fd)
77{
78 unsigned long long size = 0;
79 char buf[BUFSIZ];
80 int r;
81
82 do {
83 r = read(fd, buf, BUFSIZ);
84 if (r > 0)
85 size += r;
86 } while (r > 0);
87
88 lseek(fd, 0, SEEK_SET);
89
90 return size;
91}
92
93static unsigned long get_size(const char *file)
94{
95 unsigned long long size = 0;
96 int fd;
97
98 fd = open(file, O_RDONLY);
99 if (fd < 0)
100 die("Can't read '%s'", file);
101 size = get_size_fd(fd);
102 close(fd);
103
104 return size;
105}
106
107static unsigned long long copy_file_fd(struct tracecmd_output *handle, int fd)
108{
109 unsigned long long size = 0;
110 char buf[BUFSIZ];
111 int r;
112
113 do {
114 r = read(fd, buf, BUFSIZ);
115 if (r > 0) {
116 size += r;
117 if (do_write_check(handle, buf, r))
118 return 0;
119 }
120 } while (r > 0);
121
122 return size;
123}
124
125static unsigned long long copy_file(struct tracecmd_output *handle,
126 const char *file)
127{
128 unsigned long long size = 0;
129 int fd;
130
131 fd = open(file, O_RDONLY);
132 if (fd < 0)
133 die("Can't read '%s'", file);
134 size = copy_file_fd(handle, fd);
135 close(fd);
136
137 return size;
138}
139
140/*
141 * Finds the path to the debugfs/tracing
142 * Allocates the string and stores it.
143 */
144static const char *find_tracing_dir(struct tracecmd_output *handle)
145{
146 if (!handle->tracing_dir)
147 handle->tracing_dir = tracecmd_find_tracing_dir();
148
149 return handle->tracing_dir;
150}
151
152static char *get_tracing_file(struct tracecmd_output *handle, const char *name)
153{
154 const char *tracing;
155 char *file;
156
157 tracing = find_tracing_dir(handle);
158 if (!tracing)
159 return NULL;
160
161 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
162 if (!file)
163 return NULL;
164
165 sprintf(file, "%s/%s", tracing, name);
166 return file;
167}
168
169static void put_tracing_file(char *file)
170{
171 free(file);
172}
173
174int tracecmd_ftrace_enable(int set)
175{
176 struct stat buf;
177 char *path = "/proc/sys/kernel/ftrace_enabled";
178 int fd;
179 char *val = set ? "1" : "0";
180 int ret = 0;
181
182 /* if ftace_enable does not exist, simply ignore it */
183 fd = stat(path, &buf);
184 if (fd < 0)
185 return ENODEV;
186
187 fd = open(path, O_WRONLY);
188 if (fd < 0)
189 die ("Can't %s ftrace", set ? "enable" : "disable");
190
191 if (write(fd, val, 1) < 0)
192 ret = -1;
193 close(fd);
194
195 return ret;
196}
197
198static int read_header_files(struct tracecmd_output *handle)
199{
200 unsigned long long size, check_size;
201 struct stat st;
202 char *path;
203 int fd;
204 int ret;
205
206 path = get_tracing_file(handle, "events/header_page");
207 if (!path)
208 return -1;
209
210 ret = stat(path, &st);
211 if (ret < 0) {
212 /* old style did not show this info, just add zero */
213 put_tracing_file(path);
214 if (do_write_check(handle, "header_page", 12))
215 return -1;
216 size = 0;
217 if (do_write_check(handle, &size, 8))
218 return -1;
219 if (do_write_check(handle, "header_event", 13))
220 return -1;
221 if (do_write_check(handle, &size, 8))
222 return -1;
223 return 0;
224 }
225
226 fd = open(path, O_RDONLY);
227 if (fd < 0) {
228 warning("can't read '%s'", path);
229 return -1;
230 }
231
232 /* unfortunately, you can not stat debugfs files for size */
233 size = get_size_fd(fd);
234
235 if (do_write_check(handle, "header_page", 12))
236 goto out_close;
237 if (do_write_check(handle, &size, 8))
238 goto out_close;
239 check_size = copy_file_fd(handle, fd);
240 close(fd);
241 if (size != check_size) {
242 warning("wrong size for '%s' size=%lld read=%lld",
243 path, size, check_size);
244 errno = EINVAL;
245 return -1;
246 }
247 put_tracing_file(path);
248
249 path = get_tracing_file(handle, "events/header_event");
250 if (!path)
251 return -1;
252
253 fd = open(path, O_RDONLY);
254 if (fd < 0)
255 die("can't read '%s'", path);
256
257 size = get_size_fd(fd);
258
259 if (do_write_check(handle, "header_event", 13))
260 goto out_close;
261 if (do_write_check(handle, &size, 8))
262 goto out_close;
263 check_size = copy_file_fd(handle, fd);
264 close(fd);
265 if (size != check_size) {
266 warning("wrong size for '%s'", path);
267 return -1;
268 }
269 put_tracing_file(path);
270 return 0;
271
272 out_close:
273 close(fd);
274 return -1;
275}
276
277static int copy_event_system(struct tracecmd_output *handle, const char *sys)
278{
279 unsigned long long size, check_size;
280 struct dirent *dent;
281 struct stat st;
282 char *format;
283 DIR *dir;
284 int count = 0;
285 int ret;
286
287 dir = opendir(sys);
288 if (!dir) {
289 warning("can't read directory '%s'", sys);
290 return -1;
291 }
292
293 while ((dent = readdir(dir))) {
294 if (strcmp(dent->d_name, ".") == 0 ||
295 strcmp(dent->d_name, "..") == 0)
296 continue;
297 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
298 if (!format)
299 return -1;
300 sprintf(format, "%s/%s/format", sys, dent->d_name);
301 ret = stat(format, &st);
302 free(format);
303 if (ret < 0)
304 continue;
305 count++;
306 }
307
308 if (do_write_check(handle, &count, 4))
309 return -1;
310
311 rewinddir(dir);
312 while ((dent = readdir(dir))) {
313 if (strcmp(dent->d_name, ".") == 0 ||
314 strcmp(dent->d_name, "..") == 0)
315 continue;
316 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
317 if (!format)
318 return -1;
319 sprintf(format, "%s/%s/format", sys, dent->d_name);
320 ret = stat(format, &st);
321
322 if (ret >= 0) {
323 /* unfortunately, you can not stat debugfs files for size */
324 size = get_size(format);
325 if (do_write_check(handle, &size, 8))
326 goto out_free;
327 check_size = copy_file(handle, format);
328 if (size != check_size) {
329 warning("error in size of file '%s'", format);
330 goto out_free;
331 }
332 }
333
334 free(format);
335 }
336
337 return 0;
338
339 out_free:
340 free(format);
341 return -1;
342}
343
344static int read_ftrace_files(struct tracecmd_output *handle)
345{
346 char *path;
347 int ret;
348
349 path = get_tracing_file(handle, "events/ftrace");
350 if (!path)
351 return -1;
352
353 ret = copy_event_system(handle, path);
354
355 put_tracing_file(path);
356
357 return ret;
358}
359
360static int read_event_files(struct tracecmd_output *handle)
361{
362 struct dirent *dent;
363 struct stat st;
364 char *path;
365 char *sys;
366 DIR *dir;
367 int count = 0;
368 int ret;
369
370 path = get_tracing_file(handle, "events");
371 if (!path)
372 return -1;
373
374 dir = opendir(path);
375 if (!dir)
376 die("can't read directory '%s'", path);
377
378 while ((dent = readdir(dir))) {
379 if (strcmp(dent->d_name, ".") == 0 ||
380 strcmp(dent->d_name, "..") == 0 ||
381 strcmp(dent->d_name, "ftrace") == 0)
382 continue;
383 ret = -1;
384 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
385 if (!sys)
386 goto out_close_dir;
387 sprintf(sys, "%s/%s", path, dent->d_name);
388 ret = stat(sys, &st);
389 free(sys);
390 if (ret < 0)
391 continue;
392 if (S_ISDIR(st.st_mode))
393 count++;
394 }
395
396 ret = -1;
397 if (do_write_check(handle, &count, 4))
398 goto out_close_dir;
399
400 rewinddir(dir);
401 while ((dent = readdir(dir))) {
402 if (strcmp(dent->d_name, ".") == 0 ||
403 strcmp(dent->d_name, "..") == 0 ||
404 strcmp(dent->d_name, "ftrace") == 0)
405 continue;
406 ret = -1;
407 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
408 if (!sys)
409 goto out_close_dir;
410
411 sprintf(sys, "%s/%s", path, dent->d_name);
412 ret = stat(sys, &st);
413 if (ret >= 0) {
414 if (S_ISDIR(st.st_mode)) {
415 if (do_write_check(handle, dent->d_name,
416 strlen(dent->d_name) + 1)) {
417 free(sys);
418 ret = -1;
419 goto out_close_dir;
420 }
421 copy_event_system(handle, sys);
422 }
423 }
424 free(sys);
425 }
426
427 put_tracing_file(path);
428
429 ret = 0;
430
431 out_close_dir:
432 closedir(dir);
433 return ret;
434}
435
436static int read_proc_kallsyms(struct tracecmd_output *handle)
437{
438 unsigned int size, check_size;
439 const char *path = "/proc/kallsyms";
440 struct stat st;
441 int ret;
442
443 ret = stat(path, &st);
444 if (ret < 0) {
445 /* not found */
446 size = 0;
447 if (do_write_check(handle, &size, 4))
448 return -1;
449 return 0;
450 }
451 size = get_size(path);
452 if (do_write_check(handle, &size, 4))
453 return -1;
454 check_size = copy_file(handle, path);
455 if (size != check_size) {
456 errno = EINVAL;
457 warning("error in size of file '%s'", path);
458 return -1;
459 }
460
461 return 0;
462}
463
464static int read_ftrace_printk(struct tracecmd_output *handle)
465{
466 unsigned int size, check_size;
467 const char *path;
468 struct stat st;
469 int ret;
470
471 path = get_tracing_file(handle, "printk_formats");
472 if (!path)
473 return -1;
474
475 ret = stat(path, &st);
476 if (ret < 0) {
477 /* not found */
478 size = 0;
479 if (do_write_check(handle, &size, 4))
480 return -1;
481 return 0;
482 }
483 size = get_size(path);
484 if (do_write_check(handle, &size, 4))
485 return -1;
486 check_size = copy_file(handle, path);
487 if (size != check_size) {
488 errno = EINVAL;
489 warning("error in size of file '%s'", path);
490 return -1;
491 }
492
493 return 0;
494}
495
496static struct tracecmd_output *create_file(const char *output_file, int cpus)
497{
498 struct tracecmd_output *handle;
499 char buf[BUFSIZ];
500 char *file = NULL;
501 struct stat st;
502 off64_t check_size;
503 off64_t size;
504 int ret;
505
506 handle = malloc(sizeof(*handle));
507 if (!handle)
508 return NULL;
509 memset(handle, 0, sizeof(*handle));
510
511 handle->fd = open(output_file, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
512 if (handle->fd < 0)
513 goto out_free;
514
515 buf[0] = 23;
516 buf[1] = 8;
517 buf[2] = 68;
518 memcpy(buf + 3, "tracing", 7);
519
520 if (do_write_check(handle, buf, 10))
521 goto out_free;
522
523 if (do_write_check(handle, TRACECMD_VERSION, strlen(TRACECMD_VERSION) + 1))
524 goto out_free;
525
526 /* save endian */
527 if (tracecmd_host_bigendian())
528 buf[0] = 1;
529 else
530 buf[0] = 0;
531
532 if (do_write_check(handle, buf, 1))
533 goto out_free;
534
535 /* save size of long (this may not be what the kernel is) */
536 buf[0] = sizeof(long);
537 if (do_write_check(handle, buf, 1))
538 goto out_free;
539
540 /* save page_size */
541 handle->page_size = getpagesize();
542 if (do_write_check(handle, &handle->page_size, 4))
543 goto out_free;
544
545 if (read_header_files(handle))
546 goto out_free;
547 if (read_ftrace_files(handle))
548 goto out_free;
549 if (read_event_files(handle))
550 goto out_free;
551 if (read_proc_kallsyms(handle))
552 goto out_free;
553 if (read_ftrace_printk(handle))
554 goto out_free;
555
556 /*
557 * Save the command lines;
558 */
559 file = get_tracing_file(handle, "saved_cmdlines");
560 ret = stat(file, &st);
561 if (ret >= 0) {
562 size = get_size(file);
563 if (do_write_check(handle, &size, 8))
564 goto out_free;
565 check_size = copy_file(handle, file);
566 if (size != check_size) {
567 errno = EINVAL;
568 warning("error in size of file '%s'", file);
569 goto out_free;
570 }
571 } else {
572 size = 0;
573 if (do_write_check(handle, &size, 8))
574 goto out_free;
575 }
576 put_tracing_file(file);
577 file = NULL;
578
579 if (do_write_check(handle, &cpus, 4))
580 goto out_free;
581
582 return handle;
583
584 out_free:
585 tracecmd_output_close(handle);
586 return NULL;
587}
588
589struct tracecmd_output *tracecmd_create_file_latency(const char *output_file, int cpus)
590{
591 struct tracecmd_output *handle;
592 char *path;
593
594 handle = create_file(output_file, cpus);
595 if (!handle)
596 return NULL;
597
598 if (do_write_check(handle, "latency ", 10))
599 goto out_free;
600
601 path = get_tracing_file(handle, "trace");
602 if (!path)
603 goto out_free;
604
605 copy_file(handle, path);
606
607 put_tracing_file(path);
608
609 return handle;
610
611out_free:
612 tracecmd_output_close(handle);
613 return NULL;
614}
615
616struct tracecmd_output *tracecmd_create_file(const char *output_file,
617 int cpus, char * const *cpu_data_files)
618{
619 unsigned long long *offsets = NULL;
620 unsigned long long *sizes = NULL;
621 struct tracecmd_output *handle;
622 unsigned long long offset;
623 off64_t check_size;
624 char *file = NULL;
625 struct stat st;
626 int ret;
627 int i;
628
629 handle = create_file(output_file, cpus);
630 if (!handle)
631 return NULL;
632
633 if (do_write_check(handle, "flyrecord", 10))
634 goto out_free;
635
636 offsets = malloc_or_die(sizeof(*offsets) * cpus);
637 if (!offsets)
638 goto out_free;
639 sizes = malloc_or_die(sizeof(*sizes) * cpus);
640 if (!sizes)
641 goto out_free;
642
643 offset = lseek(handle->fd, 0, SEEK_CUR);
644
645 /* hold any extra data for data */
646 offset += cpus * (16);
647 offset = (offset + (handle->page_size - 1)) & ~(handle->page_size - 1);
648
649 for (i = 0; i < cpus; i++) {
650 file = malloc_or_die(strlen(output_file) + 20);
651 if (!file)
652 goto out_free;
653 sprintf(file, "%s.cpu%d", output_file, i);
654 ret = stat(file, &st);
655 if (ret < 0) {
656 warning("can not stat '%s'", file);
657 goto out_free;
658 }
659 free(file);
660 file = NULL;
661 offsets[i] = offset;
662 sizes[i] = st.st_size;
663 offset += st.st_size;
664 offset = (offset + (handle->page_size - 1)) & ~(handle->page_size - 1);
665
666 if (do_write_check(handle, &offsets[i], 8))
667 goto out_free;
668 if (do_write_check(handle, &sizes[i], 8))
669 goto out_free;
670 }
671
672 for (i = 0; i < cpus; i++) {
673 fprintf(stderr, "offset=%llx\n", offsets[i]);
674 ret = lseek64(handle->fd, offsets[i], SEEK_SET);
675 if (ret < 0) {
676 warning("could not seek to %lld\n", offsets[i]);
677 goto out_free;
678 }
679 check_size = copy_file(handle, cpu_data_files[i]);
680 if (check_size != sizes[i]) {
681 errno = EINVAL;
682 warning("did not match size of %lld to %lld",
683 check_size, sizes[i]);
684 goto out_free;
685 }
686 }
687
688 free(offsets);
689 free(sizes);
690
691 return handle;
692
693 out_free:
694 free(file);
695 free(offsets);
696 free(sizes);
697
698 tracecmd_output_close(handle);
699 return NULL;
700}
diff --git a/trace-record.c b/trace-record.c
new file mode 100644
index 0000000..0cd81ac
--- /dev/null
+++ b/trace-record.c
@@ -0,0 +1,133 @@
1#define _LARGEFILE64_SOURCE
2#define _GNU_SOURCE
3#include <dirent.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <stdarg.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <sys/wait.h>
11#include <pthread.h>
12#include <fcntl.h>
13#include <unistd.h>
14#include <ctype.h>
15#include <errno.h>
16
17#include "trace-cmd.h"
18
19struct tracecmd_recorder {
20 int fd;
21 int trace_fd;
22 int brass[2];
23 int page_size;
24 int cpu;
25 int stop;
26};
27
28void tracecmd_free_recorder(struct tracecmd_recorder *recorder)
29{
30 if (!recorder)
31 return;
32
33 if (recorder->fd)
34 close(recorder->fd);
35
36 free(recorder);
37}
38
39struct tracecmd_recorder *tracecmd_create_recorder(const char *file, int cpu)
40{
41 struct tracecmd_recorder *recorder;
42 char *tracing = NULL;
43 char *path = NULL;
44 int ret;
45
46 recorder = malloc_or_die(sizeof(*recorder));
47 if (!recorder)
48 return NULL;
49
50 recorder->cpu = cpu;
51
52 /* Init to know what to free and release */
53 recorder->trace_fd = -1;
54 recorder->brass[0] = -1;
55 recorder->brass[1] = -1;
56
57 recorder->page_size = getpagesize();
58
59 recorder->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
60 if (recorder->fd < 0)
61 goto out_free;
62
63 tracing = tracecmd_find_tracing_dir();
64 if (!tracing) {
65 errno = ENODEV;
66 goto out_free;
67 }
68
69 path = malloc_or_die(strlen(tracing) + 40);
70 if (!path)
71 goto out_free;
72
73 sprintf(path, "%s/per_cpu/cpu%d/trace_pipe_raw", tracing, cpu);
74 recorder->trace_fd = open(path, O_RDONLY);
75 if (recorder->trace_fd < 0)
76 goto out_free;
77
78 free(tracing);
79 free(path);
80
81 ret = pipe(recorder->brass);
82 if (ret < 0)
83 goto out_free;
84
85 return recorder;
86
87 out_free:
88 free(tracing);
89 free(path);
90
91 tracecmd_free_recorder(recorder);
92 return NULL;
93}
94
95int tracecmd_start_recording(struct tracecmd_recorder *recorder)
96{
97 char *buf[recorder->page_size];
98 int ret;
99
100 recorder->stop = 0;
101
102 do {
103 ret = splice(recorder->trace_fd, NULL, recorder->brass[1], NULL,
104 recorder->page_size, 1 /* SPLICE_F_MOVE */);
105 if (ret < 0) {
106 warning("recorder error in splice input");
107 return -1;
108 }
109 ret = splice(recorder->brass[0], NULL, recorder->fd, NULL,
110 recorder->page_size, 3 /* and NON_BLOCK */);
111 if (ret < 0 && errno != EAGAIN) {
112 warning("recorder error in splice output");
113 return -1;
114 }
115 } while (!recorder->stop);
116
117 /* splice only reads full pages */
118 do {
119 ret = read(recorder->trace_fd, buf, recorder->page_size);
120 if (ret > 0)
121 write(recorder->fd, buf, ret);
122 } while (ret > 0);
123
124 return 0;
125}
126
127void tracecmd_stop_recording(struct tracecmd_recorder *recorder)
128{
129 if (!recorder)
130 return;
131
132 recorder->stop = 1;
133}
diff --git a/trace-util.c b/trace-util.c
index a3ee05c..c3d89c6 100644
--- a/trace-util.c
+++ b/trace-util.c
@@ -15,6 +15,13 @@
15 15
16#define __weak __attribute__((weak)) 16#define __weak __attribute__((weak))
17 17
18#define _STR(x) #x
19#define STR(x) _STR(x)
20
21#ifndef MAX_PATH
22# define MAX_PATH 1024
23#endif
24
18void __weak die(char *fmt, ...) 25void __weak die(char *fmt, ...)
19{ 26{
20 va_list ap; 27 va_list ap;
@@ -173,6 +180,41 @@ static int load_plugin(struct pevent *pevent,
173 return ret; 180 return ret;
174} 181}
175 182
183char *tracecmd_find_tracing_dir(void)
184{
185 char debugfs[MAX_PATH+1];
186 char *tracing_dir;
187 char type[100];
188 FILE *fp;
189
190 if ((fp = fopen("/proc/mounts","r")) == NULL) {
191 warning("Can't open /proc/mounts for read");
192 return NULL;
193 }
194
195 while (fscanf(fp, "%*s %"
196 STR(MAX_PATH)
197 "s %99s %*s %*d %*d\n",
198 debugfs, type) == 2) {
199 if (strcmp(type, "debugfs") == 0)
200 break;
201 }
202 fclose(fp);
203
204 if (strcmp(type, "debugfs") != 0) {
205 warning("debugfs not mounted, please mount");
206 return NULL;
207 }
208
209 tracing_dir = malloc_or_die(strlen(debugfs) + 9);
210 if (!tracing_dir)
211 return NULL;
212
213 sprintf(tracing_dir, "%s/tracing", debugfs);
214
215 return tracing_dir;
216}
217
176int trace_load_plugins(struct pevent *pevent) 218int trace_load_plugins(struct pevent *pevent)
177{ 219{
178 struct dirent *dent; 220 struct dirent *dent;