aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-02-23 13:28:04 -0500
committerSteven Rostedt <rostedt@goodmis.org>2011-02-23 13:28:04 -0500
commit6e7c1dd76377411dc89fdfd8e6320b1dd21aea71 (patch)
tree0580dc38f4227c30b7c25e0b01df9827a9bbb50e
parentc552d39859673910654c2a801554c44496b3f69c (diff)
trace-cmd: Move trace-cmd record code out of trace-cmd.c
Move the trace-cmd record code into its own file trace-record.c Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile3
-rw-r--r--trace-cmd.c1843
-rw-r--r--trace-local.h2
-rw-r--r--trace-record.c1869
4 files changed, 1882 insertions, 1835 deletions
diff --git a/Makefile b/Makefile
index bb5feac..277be99 100644
--- a/Makefile
+++ b/Makefile
@@ -261,7 +261,8 @@ $(obj)/%.o: $(src)/%.c
261 261
262TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \ 262TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \
263 trace-xml.o 263 trace-xml.o
264TRACE_CMD_OBJS = trace-cmd.o trace-read.o trace-split.o trace-listen.o trace-stack.o 264TRACE_CMD_OBJS = trace-cmd.o trace-record.o trace-read.o trace-split.o trace-listen.o \
265 trace-stack.o
265TRACE_VIEW_OBJS = trace-view.o trace-view-store.o 266TRACE_VIEW_OBJS = trace-view.o trace-view-store.o
266TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o 267TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o
267TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS) 268TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS)
diff --git a/trace-cmd.c b/trace-cmd.c
index 06e30c5..c0b564c 100644
--- a/trace-cmd.c
+++ b/trace-cmd.c
@@ -18,231 +18,16 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _GNU_SOURCE
22#include <dirent.h>
23#include <stdio.h> 21#include <stdio.h>
24#include <stdlib.h>
25#include <string.h> 22#include <string.h>
26#include <stdarg.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <sys/socket.h>
31#include <sys/ptrace.h>
32#include <netdb.h>
33#include <pthread.h>
34#include <fcntl.h>
35#include <unistd.h> 23#include <unistd.h>
36#include <ctype.h>
37#include <sched.h>
38#include <errno.h> 24#include <errno.h>
39#include <glob.h>
40 25
41#include "trace-local.h" 26#include "trace-local.h"
42 27
43#define _STR(x) #x
44#define STR(x) _STR(x)
45#define MAX_PATH 256
46
47#define TRACE_CTRL "tracing_on"
48#define TRACE "trace"
49#define AVAILABLE "available_tracers"
50#define CURRENT "current_tracer"
51#define ITER_CTRL "trace_options"
52#define MAX_LATENCY "tracing_max_latency"
53
54#define UDP_MAX_PACKET (65536 - 20)
55
56int silence_warnings; 28int silence_warnings;
57int show_status; 29int show_status;
58 30
59static int tracing_on_init_val;
60
61static int rt_prio;
62
63static int use_tcp;
64
65static unsigned int page_size;
66
67static int buffer_size;
68
69static const char *output_file = "trace.dat";
70
71static int latency;
72static int sleep_time = 1000;
73static int cpu_count;
74static int *pids;
75
76static char *host;
77static int *client_ports;
78static int sfd;
79
80static int do_ptrace;
81
82static int filter_task;
83static int filter_pid = -1;
84
85static int finished;
86
87struct func_list {
88 struct func_list *next;
89 const char *func;
90};
91
92static struct func_list *filter_funcs;
93static struct func_list *notrace_funcs;
94static struct func_list *graph_funcs;
95
96struct filter_pids {
97 struct filter_pids *next;
98 int pid;
99};
100
101static struct filter_pids *filter_pids;
102static int nr_filter_pids;
103static int len_filter_pids;
104
105struct opt_list {
106 struct opt_list *next;
107 const char *option;
108};
109
110static struct opt_list *options;
111
112struct event_list {
113 struct event_list *next;
114 const char *event;
115 char *filter;
116 char *filter_file;
117 char *enable_file;
118 int neg;
119};
120
121static struct event_list *sched_switch_event;
122static struct event_list *sched_wakeup_event;
123static struct event_list *sched_wakeup_new_event;
124static struct event_list *sched_event;
125
126static struct event_list *event_selection;
127struct tracecmd_event_list *listed_events;
128
129struct events {
130 struct events *sibling;
131 struct events *children;
132 struct events *next;
133 char *name;
134};
135
136static struct tracecmd_recorder *recorder;
137
138static int ignore_event_not_found = 0;
139
140static char *get_temp_file(int cpu)
141{
142 char *file = NULL;
143 int size;
144
145 size = snprintf(file, 0, "%s.cpu%d", output_file, cpu);
146 file = malloc_or_die(size + 1);
147 sprintf(file, "%s.cpu%d", output_file, cpu);
148
149 return file;
150}
151
152static void put_temp_file(char *file)
153{
154 free(file);
155}
156
157static void delete_temp_file(int cpu)
158{
159 char file[MAX_PATH];
160
161 snprintf(file, MAX_PATH, "%s.cpu%d", output_file, cpu);
162 unlink(file);
163}
164
165static void kill_threads(void)
166{
167 int i;
168
169 if (!cpu_count || !pids)
170 return;
171
172 for (i = 0; i < cpu_count; i++) {
173 if (pids[i] > 0) {
174 kill(pids[i], SIGKILL);
175 delete_temp_file(i);
176 pids[i] = 0;
177 }
178 }
179}
180
181static void delete_thread_data(void)
182{
183 int i;
184
185 if (!cpu_count)
186 return;
187
188 for (i = 0; i < cpu_count; i++) {
189 if (pids[i]) {
190 delete_temp_file(i);
191 if (pids[i] < 0)
192 pids[i] = 0;
193 }
194 }
195}
196
197static void stop_threads(void)
198{
199 int i;
200
201 if (!cpu_count)
202 return;
203
204 for (i = 0; i < cpu_count; i++) {
205 if (pids[i] > 0) {
206 kill(pids[i], SIGINT);
207 waitpid(pids[i], NULL, 0);
208 pids[i] = -1;
209 }
210 }
211}
212
213static void flush_threads(void)
214{
215 int i;
216
217 if (!cpu_count)
218 return;
219
220 for (i = 0; i < cpu_count; i++) {
221 if (pids[i] > 0)
222 kill(pids[i], SIGUSR1);
223 }
224}
225
226void die(const char *fmt, ...)
227{
228 va_list ap;
229 int ret = errno;
230
231 if (errno)
232 perror("trace-cmd");
233 else
234 ret = -1;
235
236 kill_threads();
237 va_start(ap, fmt);
238 fprintf(stderr, " ");
239 vfprintf(stderr, fmt, ap);
240 va_end(ap);
241
242 fprintf(stderr, "\n");
243 exit(ret);
244}
245
246void warning(const char *fmt, ...) 31void warning(const char *fmt, ...)
247{ 32{
248 va_list ap; 33 va_list ap;
@@ -286,315 +71,6 @@ void *malloc_or_die(unsigned int size)
286 return data; 71 return data;
287} 72}
288 73
289static int set_ftrace(int set)
290{
291 struct stat buf;
292 char *path = "/proc/sys/kernel/ftrace_enabled";
293 int fd;
294 char *val = set ? "1" : "0";
295
296 /* if ftace_enable does not exist, simply ignore it */
297 fd = stat(path, &buf);
298 if (fd < 0)
299 return -ENODEV;
300
301 fd = open(path, O_WRONLY);
302 if (fd < 0)
303 die ("Can't %s ftrace", set ? "enable" : "disable");
304
305 write(fd, val, 1);
306 close(fd);
307
308 return 0;
309}
310
311static void clear_trace(void)
312{
313 FILE *fp;
314 char *path;
315
316 /* reset the trace */
317 path = tracecmd_get_tracing_file("trace");
318 fp = fopen(path, "w");
319 if (!fp)
320 die("writing to '%s'", path);
321 tracecmd_put_tracing_file(path);
322 fwrite("0", 1, 1, fp);
323 fclose(fp);
324}
325
326static void reset_max_latency(void)
327{
328 FILE *fp;
329 char *path;
330
331 /* reset the trace */
332 path = tracecmd_get_tracing_file("tracing_max_latency");
333 fp = fopen(path, "w");
334 if (!fp)
335 die("writing to '%s'", path);
336 tracecmd_put_tracing_file(path);
337 fwrite("0", 1, 1, fp);
338 fclose(fp);
339}
340
341static void add_filter_pid(int pid)
342{
343 struct filter_pids *p;
344 char buf[100];
345
346 p = malloc_or_die(sizeof(*p));
347 p->next = filter_pids;
348 p->pid = pid;
349 filter_pids = p;
350 nr_filter_pids++;
351
352 len_filter_pids += sprintf(buf, "%d", pid);
353}
354
355static void update_ftrace_pid(const char *pid, int reset)
356{
357 static char *path;
358 int ret;
359 static int fd = -1;
360
361 if (!pid) {
362 if (fd >= 0)
363 close(fd);
364 if (path)
365 tracecmd_put_tracing_file(path);
366 fd = -1;
367 path = NULL;
368 return;
369 }
370
371 /* Force reopen on reset */
372 if (reset && fd >= 0) {
373 close(fd);
374 fd = -1;
375 }
376
377 if (fd < 0) {
378 if (!path)
379 path = tracecmd_get_tracing_file("set_ftrace_pid");
380 if (!path)
381 return;
382 fd = open(path, O_WRONLY | (reset ? O_TRUNC : 0));
383 if (fd < 0)
384 return;
385 }
386
387 ret = write(fd, pid, strlen(pid));
388
389 /*
390 * Older kernels required "-1" to disable pid
391 */
392 if (ret < 0 && !strlen(pid))
393 ret = write(fd, "-1", 2);
394
395 if (ret < 0)
396 die("error writing to %s", path);
397
398 /* add whitespace in case another pid is written */
399 write(fd, " ", 1);
400}
401
402static void update_event_filters(const char *pid_filter);
403static void update_pid_event_filters(const char *pid);
404static void enable_tracing(void);
405static void
406update_sched_event(struct event_list **event, const char *file,
407 const char *pid_filter, const char *field_filter);
408
409static char *make_pid_filter(const char *field)
410{
411 struct filter_pids *p;
412 char *filter;
413 char *orit;
414 char *str;
415 int len;
416
417 filter = malloc_or_die(len_filter_pids +
418 (strlen(field) + strlen("(==)||")) * nr_filter_pids);
419 /* Last '||' that is not used will cover the \0 */
420 str = filter;
421
422 for (p = filter_pids; p; p = p->next) {
423 if (p == filter_pids)
424 orit = "";
425 else
426 orit = "||";
427 len = sprintf(str, "%s(%s==%d)", orit, field, p->pid);
428 str += len;
429 }
430
431 return filter;
432}
433
434static void add_new_filter_pid(int pid)
435{
436 char *pid_filter;
437 char *filter;
438 char buf[100];
439
440 add_filter_pid(pid);
441 sprintf(buf, "%d", pid);
442 update_ftrace_pid(buf, 0);
443
444 pid_filter = make_pid_filter("common_pid");
445 update_event_filters(pid_filter);
446
447 if (!sched_event && !sched_switch_event
448 && !sched_wakeup_event && !sched_wakeup_new_event)
449 return;
450
451 /*
452 * Also make sure that the sched_switch to this pid
453 * and wakeups of this pid are also traced.
454 * Only need to do this if the events are active.
455 */
456 filter = make_pid_filter("next_pid");
457 update_sched_event(&sched_switch_event, "sched/sched_switch", pid_filter, filter);
458 free(filter);
459
460 filter = make_pid_filter("pid");
461 update_sched_event(&sched_wakeup_event, "sched/sched_wakeup",
462 pid_filter, filter);
463 update_sched_event(&sched_wakeup_new_event, "sched/sched_wakeup_new",
464 pid_filter, filter);
465 free(pid_filter);
466 free(filter);
467}
468
469static void update_task_filter(void)
470{
471 int pid = getpid();
472 char spid[100];
473
474 if (!filter_task && filter_pid < 0) {
475 update_ftrace_pid("", 1);
476 enable_tracing();
477 return;
478 }
479
480 if (filter_pid >= 0)
481 pid = filter_pid;
482
483 snprintf(spid, 100, "%d", pid);
484
485 update_ftrace_pid(spid, 1);
486
487 update_pid_event_filters(spid);
488
489 enable_tracing();
490}
491
492static void ptrace_attach(int pid)
493{
494 int ret;
495
496 ret = ptrace(PTRACE_ATTACH, pid, NULL, 0);
497 if (ret < 0) {
498 warning("Unable to trace process %d children", pid);
499 do_ptrace = 0;
500 return;
501 }
502 add_filter_pid(pid);
503}
504
505static void enable_ptrace(void)
506{
507 if (!do_ptrace || !filter_task)
508 return;
509
510 ptrace(PTRACE_TRACEME, 0, NULL, 0);
511}
512
513static void ptrace_wait(int main_pid)
514{
515 unsigned long send_sig;
516 unsigned long child;
517 siginfo_t sig;
518 int cstatus;
519 int status;
520 int event;
521 int pid;
522 int ret;
523
524 do {
525 ret = waitpid(-1, &status, WSTOPPED | __WALL);
526 if (ret < 0)
527 continue;
528
529 pid = ret;
530
531 if (WIFSTOPPED(status)) {
532 event = (status >> 16) & 0xff;
533 ptrace(PTRACE_GETSIGINFO, pid, NULL, &sig);
534 send_sig = sig.si_signo;
535 /* Don't send ptrace sigs to child */
536 if (send_sig == SIGTRAP || send_sig == SIGSTOP)
537 send_sig = 0;
538 switch (event) {
539 case PTRACE_EVENT_FORK:
540 case PTRACE_EVENT_VFORK:
541 case PTRACE_EVENT_CLONE:
542 /* forked a child */
543 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &child);
544 ptrace(PTRACE_SETOPTIONS, child, NULL,
545 PTRACE_O_TRACEFORK |
546 PTRACE_O_TRACEVFORK |
547 PTRACE_O_TRACECLONE |
548 PTRACE_O_TRACEEXIT);
549 add_new_filter_pid(child);
550 ptrace(PTRACE_CONT, child, NULL, 0);
551 break;
552
553 case PTRACE_EVENT_EXIT:
554 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &cstatus);
555 ptrace(PTRACE_DETACH, pid, NULL, NULL);
556 break;
557 }
558 ptrace(PTRACE_SETOPTIONS, pid, NULL,
559 PTRACE_O_TRACEFORK |
560 PTRACE_O_TRACEVFORK |
561 PTRACE_O_TRACECLONE |
562 PTRACE_O_TRACEEXIT);
563 ptrace(PTRACE_CONT, pid, NULL, send_sig);
564 }
565 } while (!finished && ret > 0 &&
566 (!WIFEXITED(status) || pid != main_pid));
567}
568
569void trace_or_sleep(void)
570{
571 if (do_ptrace && filter_pid >= 0)
572 ptrace_wait(filter_pid);
573 else
574 sleep(10);
575}
576
577void run_cmd(int argc, char **argv)
578{
579 int status;
580 int pid;
581
582 if ((pid = fork()) < 0)
583 die("failed to fork");
584 if (!pid) {
585 /* child */
586 update_task_filter();
587 enable_ptrace();
588 if (execvp(argv[0], argv))
589 exit(-1);
590 }
591 if (do_ptrace) {
592 add_filter_pid(pid);
593 ptrace_wait(pid);
594 } else
595 waitpid(pid, &status, 0);
596}
597
598static void show_events(void) 74static void show_events(void)
599{ 75{
600 char buf[BUFSIZ]; 76 char buf[BUFSIZ];
@@ -637,21 +113,6 @@ static void show_plugins(void)
637 fclose(fp); 113 fclose(fp);
638} 114}
639 115
640static void set_plugin(const char *name)
641{
642 FILE *fp;
643 char *path;
644
645 path = tracecmd_get_tracing_file("current_tracer");
646 fp = fopen(path, "w");
647 if (!fp)
648 die("writing to '%s'", path);
649 tracecmd_put_tracing_file(path);
650
651 fwrite(name, 1, strlen(name), fp);
652 fclose(fp);
653}
654
655static void show_options(void) 116static void show_options(void)
656{ 117{
657 char buf[BUFSIZ]; 118 char buf[BUFSIZ];
@@ -673,1020 +134,8 @@ static void show_options(void)
673 fclose(fp); 134 fclose(fp);
674} 135}
675 136
676static void save_option(const char *option)
677{
678 struct opt_list *opt;
679
680 opt = malloc_or_die(sizeof(*opt));
681 opt->next = options;
682 options = opt;
683 opt->option = option;
684}
685
686static void set_option(const char *option)
687{
688 FILE *fp;
689 char *path;
690
691 path = tracecmd_get_tracing_file("trace_options");
692 fp = fopen(path, "w");
693 if (!fp)
694 die("writing to '%s'", path);
695 tracecmd_put_tracing_file(path);
696
697 fwrite(option, 1, strlen(option), fp);
698 fclose(fp);
699}
700
701static void set_options(void)
702{
703 struct opt_list *opt;
704
705 while (options) {
706 opt = options;
707 options = opt->next;
708 set_option(opt->option);
709 free(opt);
710 }
711}
712
713static int use_old_event_method(void)
714{
715 static int old_event_method;
716 static int processed;
717 struct stat st;
718 char *path;
719 int ret;
720
721 if (processed)
722 return old_event_method;
723
724 /* Check if the kernel has the events/enable file */
725 path = tracecmd_get_tracing_file("events/enable");
726 ret = stat(path, &st);
727 tracecmd_put_tracing_file(path);
728 if (ret < 0)
729 old_event_method = 1;
730
731 processed = 1;
732
733 return old_event_method;
734}
735
736static void old_update_events(const char *name, char update)
737{
738 char *path;
739 FILE *fp;
740 int ret;
741
742 if (strcmp(name, "all") == 0)
743 name = "*:*";
744
745 /* need to use old way */
746 path = tracecmd_get_tracing_file("set_event");
747 fp = fopen(path, "w");
748 if (!fp)
749 die("opening '%s'", path);
750 tracecmd_put_tracing_file(path);
751
752 /* Disable the event with "!" */
753 if (update == '0')
754 fwrite("!", 1, 1, fp);
755
756 ret = fwrite(name, 1, strlen(name), fp);
757 if (ret < 0)
758 die("bad event '%s'", name);
759
760 ret = fwrite("\n", 1, 1, fp);
761 if (ret < 0)
762 die("bad event '%s'", name);
763
764 fclose(fp);
765
766 return;
767}
768
769static void reset_events()
770{
771 glob_t globbuf;
772 char *path;
773 char c;
774 int fd;
775 int i;
776 int ret;
777
778 if (use_old_event_method()) {
779 old_update_events("all", '0');
780 return;
781 }
782
783 c = '0';
784 path = tracecmd_get_tracing_file("events/enable");
785 fd = open(path, O_WRONLY);
786 if (fd < 0)
787 die("opening to '%s'", path);
788 ret = write(fd, &c, 1);
789 close(fd);
790 tracecmd_put_tracing_file(path);
791
792 path = tracecmd_get_tracing_file("events/*/filter");
793 globbuf.gl_offs = 0;
794 ret = glob(path, 0, NULL, &globbuf);
795 tracecmd_put_tracing_file(path);
796 if (ret < 0)
797 return;
798
799 for (i = 0; i < globbuf.gl_pathc; i++) {
800 path = globbuf.gl_pathv[i];
801 fd = open(path, O_WRONLY);
802 if (fd < 0)
803 die("opening to '%s'", path);
804 ret = write(fd, &c, 1);
805 close(fd);
806 }
807 globfree(&globbuf);
808}
809
810static void write_filter(const char *file, const char *filter)
811{
812 char buf[BUFSIZ];
813 int fd;
814 int ret;
815
816 fd = open(file, O_WRONLY);
817 if (fd < 0)
818 die("opening to '%s'", file);
819 ret = write(fd, filter, strlen(filter));
820 close(fd);
821 if (ret < 0) {
822 /* filter failed */
823 fd = open(file, O_RDONLY);
824 if (fd < 0)
825 die("writing to '%s'", file);
826 /* the filter has the error */
827 while ((ret = read(fd, buf, BUFSIZ)) > 0)
828 fprintf(stderr, "%.*s", ret, buf);
829 die("Failed filter of %s\n", file);
830 close(fd);
831 }
832}
833
834static void
835update_event(struct event_list *event, const char *filter,
836 int filter_only, char update)
837{
838 const char *name = event->event;
839 FILE *fp;
840 char *path;
841 int ret;
842
843 if (use_old_event_method()) {
844 if (filter_only)
845 return;
846 old_update_events(name, update);
847 return;
848 }
849
850 if (filter && event->filter_file)
851 write_filter(event->filter_file, filter);
852
853 if (filter_only || !event->enable_file)
854 return;
855
856 path = event->enable_file;
857
858 fp = fopen(path, "w");
859 if (!fp)
860 die("writing to '%s'", path);
861 ret = fwrite(&update, 1, 1, fp);
862 fclose(fp);
863 if (ret < 0)
864 die("writing to '%s'", path);
865}
866
867/*
868 * The debugfs file tracing_enabled needs to be deprecated.
869 * But just in case anyone fiddled with it. If it exists,
870 * make sure it is one.
871 * No error checking needed here.
872 */
873static void check_tracing_enabled(void)
874{
875 static int fd = -1;
876 char *path;
877
878 if (fd < 0) {
879 path = tracecmd_get_tracing_file("tracing_enabled");
880 fd = open(path, O_WRONLY);
881 tracecmd_put_tracing_file(path);
882
883 if (fd < 0)
884 return;
885 }
886 write(fd, "1", 1);
887}
888
889static int tracing_on_fd = -1;
890
891static int open_tracing_on(void)
892{
893 int fd = tracing_on_fd;
894 char *path;
895
896 if (fd >= 0)
897 return fd;
898
899 path = tracecmd_get_tracing_file("tracing_on");
900 fd = open(path, O_RDWR);
901 if (fd < 0)
902 die("opening '%s'", path);
903 tracecmd_put_tracing_file(path);
904 tracing_on_fd = fd;
905
906 return fd;
907}
908
909static void write_tracing_on(int on)
910{
911 int ret;
912 int fd;
913
914 fd = open_tracing_on();
915 if (fd < 0)
916 return;
917
918 if (on)
919 ret = write(fd, "1", 1);
920 else
921 ret = write(fd, "0", 1);
922
923 if (ret < 0)
924 die("writing 'tracing_on'");
925}
926
927static int read_tracing_on(void)
928{
929 int fd;
930 char buf[10];
931 int ret;
932
933 fd = open_tracing_on();
934 if (fd < 0)
935 return 0;
936
937 ret = read(fd, buf, 10);
938 if (ret <= 0)
939 die("Reading 'tracing_on'");
940 buf[9] = 0;
941 ret = atoi(buf);
942
943 return ret;
944}
945
946static void enable_tracing(void)
947{
948 check_tracing_enabled();
949
950 write_tracing_on(1);
951
952 if (latency)
953 reset_max_latency();
954}
955
956static void disable_tracing(void)
957{
958 write_tracing_on(0);
959}
960
961static void disable_all(void)
962{
963 disable_tracing();
964
965 set_plugin("nop");
966 reset_events();
967
968 /* Force close and reset of ftrace pid file */
969 update_ftrace_pid("", 1);
970 update_ftrace_pid(NULL, 0);
971
972 clear_trace();
973}
974
975static void
976update_sched_event(struct event_list **event, const char *file,
977 const char *pid_filter, const char *field_filter)
978{
979 char *event_filter;
980 char *filter;
981 char *path;
982 char *p;
983
984 if (!*event) {
985 /* No sched events are being processed, ignore */
986 if (!sched_event)
987 return;
988 *event = malloc_or_die(sizeof(**event));
989 memset(*event, 0, sizeof(**event));
990 (*event)->event = file;
991 p = malloc_or_die(strlen(file) + strlen("events//filter") + 1);
992 sprintf(p, "events/%s/filter", file);
993 path = tracecmd_get_tracing_file(p);
994 free(p);
995 (*event)->filter_file = strdup(path);
996 if (sched_event->filter)
997 (*event)->filter = strdup(sched_event->filter);
998 tracecmd_put_tracing_file(path);
999 }
1000
1001 path = (*event)->filter_file;
1002 if (!path)
1003 return;
1004
1005 filter = (*event)->filter;
1006
1007 if (filter) {
1008 event_filter = malloc_or_die(strlen(pid_filter) +
1009 strlen(field_filter) +
1010 strlen(filter) +
1011 strlen("(()||())&&()") + 1);
1012 sprintf(event_filter, "((%s)||(%s))&&(%s)",
1013 pid_filter, field_filter, filter);
1014 } else {
1015 event_filter = malloc_or_die(strlen(pid_filter) +
1016 strlen(field_filter) +
1017 strlen("(()||())") + 1);
1018 sprintf(event_filter, "((%s)||(%s))",
1019 pid_filter, field_filter);
1020 }
1021 write_filter(path, event_filter);
1022 free(event_filter);
1023}
1024
1025static void update_event_filters(const char *pid_filter)
1026{
1027 struct event_list *event;
1028 char *event_filter;
1029 int free_it;
1030 int len;
1031
1032 len = strlen(pid_filter);
1033 for (event = event_selection; event; event = event->next) {
1034 if (!event->neg) {
1035 free_it = 0;
1036 if (event->filter) {
1037 event_filter = malloc_or_die(len +
1038 strlen(event->filter) + strlen("()&&()" + 1));
1039 free_it = 1;
1040 sprintf(event_filter, "(%s)&&(%s)",
1041 pid_filter, event->filter);
1042 } else
1043 event_filter = (char *)pid_filter;
1044 update_event(event, event_filter, 1, '1');
1045 if (free_it)
1046 free(event_filter);
1047 }
1048 }
1049}
1050
1051static void update_pid_event_filters(const char *pid)
1052{
1053 char *pid_filter;
1054 char *filter;
1055
1056 pid_filter = malloc_or_die(strlen(pid) + strlen("common_pid==") + 1);
1057 sprintf(pid_filter, "common_pid==%s", pid);
1058 update_event_filters(pid_filter);
1059
1060 /*
1061 * Also make sure that the sched_switch to this pid
1062 * and wakeups of this pid are also traced.
1063 * Only need to do this if the events are active.
1064 */
1065 filter = malloc_or_die(strlen(pid) + strlen("next_pid==") + 1);
1066 sprintf(filter, "next_pid==%s", pid);
1067 update_sched_event(&sched_switch_event, "sched/sched_switch", pid_filter, filter);
1068 free(filter);
1069
1070 filter = malloc_or_die(strlen(pid) + strlen("pid==") + 1);
1071 sprintf(filter, "pid==%s", pid);
1072 update_sched_event(&sched_wakeup_event, "sched/sched_wakeup",
1073 pid_filter, filter);
1074 update_sched_event(&sched_wakeup_new_event, "sched/sched_wakeup_new",
1075 pid_filter, filter);
1076 free(pid_filter);
1077 free(filter);
1078}
1079
1080static void enable_events(void)
1081{
1082 struct event_list *event;
1083
1084 for (event = event_selection; event; event = event->next) {
1085 if (!event->neg)
1086 update_event(event, event->filter, 0, '1');
1087 }
1088
1089 /* Now disable any events */
1090 for (event = event_selection; event; event = event->next) {
1091 if (event->neg)
1092 update_event(event, NULL, 0, '0');
1093 }
1094}
1095
1096static void test_event(struct event_list *event, const char *path,
1097 const char *name, struct event_list **save, int len)
1098{
1099 path += len - strlen(name);
1100
1101 if (strcmp(path, name) != 0)
1102 return;
1103
1104 *save = event;
1105}
1106
1107static int expand_event_files(const char *file, struct event_list *old_event)
1108{
1109 struct event_list *save_events = event_selection;
1110 struct event_list *event;
1111 glob_t globbuf;
1112 struct stat st;
1113 char *path;
1114 char *p;
1115 int ret;
1116 int i;
1117
1118 p = malloc_or_die(strlen(file) + strlen("events//filter") + 1);
1119 sprintf(p, "events/%s/filter", file);
1120
1121 path = tracecmd_get_tracing_file(p);
1122 printf("%s\n", path);
1123
1124 globbuf.gl_offs = 0;
1125 ret = glob(path, 0, NULL, &globbuf);
1126 tracecmd_put_tracing_file(path);
1127 free(p);
1128
1129 if (ret < 0)
1130 die("No filters found");
1131
1132 for (i = 0; i < globbuf.gl_pathc; i++) {
1133 int len;
1134
1135 path = globbuf.gl_pathv[i];
1136
1137 event = malloc_or_die(sizeof(*event));
1138 *event = *old_event;
1139 event->next = event_selection;
1140 event_selection = event;
1141 if (event->filter || filter_task || filter_pid) {
1142 event->filter_file = strdup(path);
1143 if (!event->filter_file)
1144 die("malloc filter file");
1145 }
1146 for (p = path + strlen(path) - 1; p > path; p--)
1147 if (*p == '/')
1148 break;
1149 *p = '\0';
1150 p = malloc_or_die(strlen(path) + strlen("/enable") + 1);
1151 sprintf(p, "%s/enable", path);
1152 ret = stat(p, &st);
1153 if (ret >= 0)
1154 event->enable_file = p;
1155 else
1156 free(p);
1157
1158 len = strlen(path);
1159
1160 test_event(event, path, "sched/sched_switch", &sched_switch_event, len);
1161 test_event(event, path, "sched/sched_wakeup_new", &sched_wakeup_new_event, len);
1162 test_event(event, path, "sched/sched_wakeup", &sched_wakeup_event, len);
1163 test_event(event, path, "sched", &sched_event, len);
1164 }
1165 globfree(&globbuf);
1166
1167 return save_events == event_selection;
1168}
1169
1170static void expand_event(struct event_list *event)
1171{
1172 const char *name = event->event;
1173 char *str;
1174 char *ptr;
1175 int len;
1176 int ret;
1177 int ret2;
1178
1179 /*
1180 * We allow the user to use "all" to enable all events.
1181 * Expand event_selection to all systems.
1182 */
1183 if (strcmp(name, "all") == 0) {
1184 expand_event_files("*", event);
1185 return;
1186 }
1187
1188 ptr = strchr(name, ':');
1189
1190 if (ptr) {
1191 len = ptr - name;
1192 str = malloc_or_die(strlen(name) + 1); /* may add '*' */
1193 strcpy(str, name);
1194 str[len] = '/';
1195 ptr++;
1196 if (!strlen(ptr)) {
1197 str[len + 1] = '*';
1198 str[len + 2] = '\0';
1199 }
1200
1201 ret = expand_event_files(str, event);
1202 if (!ignore_event_not_found && ret)
1203 die("No events enabled with %s", name);
1204 free(str);
1205 return;
1206 }
1207
1208 /* No ':' so enable all matching systems and events */
1209 ret = expand_event_files(name, event);
1210
1211 len = strlen(name) + strlen("*/") + 1;
1212 str = malloc_or_die(len);
1213 snprintf(str, len, "*/%s", name);
1214 ret2 = expand_event_files(str, event);
1215 free(str);
1216
1217 if (!ignore_event_not_found && ret && ret2)
1218 die("No events enabled with %s", name);
1219
1220 return;
1221}
1222
1223static void expand_event_list(void)
1224{
1225 struct event_list *compressed_list = event_selection;
1226 struct event_list *event;
1227
1228 if (use_old_event_method())
1229 return;
1230
1231 event_selection = NULL;
1232
1233 while (compressed_list) {
1234 event = compressed_list;
1235 compressed_list = event->next;
1236 expand_event(event);
1237 free(event);
1238 }
1239}
1240
1241static int count_cpus(void)
1242{
1243 FILE *fp;
1244 char buf[1024];
1245 int cpus = 0;
1246 char *pbuf;
1247 size_t *pn;
1248 size_t n;
1249 int r;
1250
1251 cpus = sysconf(_SC_NPROCESSORS_ONLN);
1252 if (cpus > 0)
1253 return cpus;
1254
1255 warning("sysconf could not determine number of CPUS");
1256
1257 /* Do the hack to figure out # of CPUS */
1258 n = 1024;
1259 pn = &n;
1260 pbuf = buf;
1261
1262 fp = fopen("/proc/cpuinfo", "r");
1263 if (!fp)
1264 die("Can not read cpuinfo");
1265
1266 while ((r = getline(&pbuf, pn, fp)) >= 0) {
1267 char *p;
1268
1269 if (strncmp(buf, "processor", 9) != 0)
1270 continue;
1271 for (p = buf+9; isspace(*p); p++)
1272 ;
1273 if (*p == ':')
1274 cpus++;
1275 }
1276 fclose(fp);
1277
1278 return cpus;
1279}
1280
1281static void finish(int sig)
1282{
1283 /* all done */
1284 if (recorder)
1285 tracecmd_stop_recording(recorder);
1286 finished = 1;
1287}
1288
1289static void flush(int sig)
1290{
1291 if (recorder)
1292 tracecmd_stop_recording(recorder);
1293}
1294
1295static void connect_port(int cpu)
1296{
1297 struct addrinfo hints;
1298 struct addrinfo *results, *rp;
1299 int s;
1300 char buf[BUFSIZ];
1301
1302 snprintf(buf, BUFSIZ, "%d", client_ports[cpu]);
1303
1304 memset(&hints, 0, sizeof(hints));
1305 hints.ai_family = AF_UNSPEC;
1306 hints.ai_socktype = use_tcp ? SOCK_STREAM : SOCK_DGRAM;
1307
1308 s = getaddrinfo(host, buf, &hints, &results);
1309 if (s != 0)
1310 die("connecting to %s server %s:%s",
1311 use_tcp ? "TCP" : "UDP", host, buf);
1312
1313 for (rp = results; rp != NULL; rp = rp->ai_next) {
1314 sfd = socket(rp->ai_family, rp->ai_socktype,
1315 rp->ai_protocol);
1316 if (sfd == -1)
1317 continue;
1318 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
1319 break;
1320 close(sfd);
1321 }
1322
1323 if (rp == NULL)
1324 die("Can not connect to %s server %s:%s",
1325 use_tcp ? "TCP" : "UDP", host, buf);
1326
1327 freeaddrinfo(results);
1328
1329 client_ports[cpu] = sfd;
1330}
1331
1332static void set_prio(int prio)
1333{
1334 struct sched_param sp;
1335
1336 memset(&sp, 0, sizeof(sp));
1337 sp.sched_priority = prio;
1338 if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0)
1339 warning("failed to set priority");
1340}
1341
1342static int create_recorder(int cpu)
1343{
1344 char *file;
1345 int pid;
1346
1347 signal(SIGUSR1, flush);
1348
1349 pid = fork();
1350 if (pid < 0)
1351 die("fork");
1352
1353 if (pid)
1354 return pid;
1355
1356 if (rt_prio)
1357 set_prio(rt_prio);
1358
1359 /* do not kill tasks on error */
1360 cpu_count = 0;
1361
1362 if (client_ports) {
1363 connect_port(cpu);
1364 recorder = tracecmd_create_recorder_fd(client_ports[cpu], cpu);
1365 } else {
1366 file = get_temp_file(cpu);
1367 recorder = tracecmd_create_recorder(file, cpu);
1368 put_temp_file(file);
1369 }
1370
1371 if (!recorder)
1372 die ("can't create recorder");
1373 while (!finished) {
1374 if (tracecmd_start_recording(recorder, sleep_time) < 0)
1375 break;
1376 }
1377 tracecmd_free_recorder(recorder);
1378
1379 exit(0);
1380}
1381
1382static void setup_network(void)
1383{
1384 struct tracecmd_output *handle;
1385 struct addrinfo hints;
1386 struct addrinfo *result, *rp;
1387 int sfd, s;
1388 ssize_t n;
1389 char buf[BUFSIZ];
1390 char *server;
1391 char *port;
1392 char *p;
1393 int cpu;
1394 int i;
1395
1396 if (!strchr(host, ':')) {
1397 server = strdup("localhost");
1398 if (!server)
1399 die("alloctating server");
1400 port = host;
1401 host = server;
1402 } else {
1403 host = strdup(host);
1404 if (!host)
1405 die("alloctating server");
1406 server = strtok_r(host, ":", &p);
1407 port = strtok_r(NULL, ":", &p);
1408 }
1409
1410 memset(&hints, 0, sizeof(hints));
1411 hints.ai_family = AF_UNSPEC;
1412 hints.ai_socktype = SOCK_STREAM;
1413
1414 s = getaddrinfo(server, port, &hints, &result);
1415 if (s != 0)
1416 die("getaddrinfo: %s", gai_strerror(s));
1417
1418 for (rp = result; rp != NULL; rp = rp->ai_next) {
1419 sfd = socket(rp->ai_family, rp->ai_socktype,
1420 rp->ai_protocol);
1421 if (sfd == -1)
1422 continue;
1423
1424 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
1425 break;
1426 close(sfd);
1427 }
1428
1429 if (!rp)
1430 die("Can not connect to %s:%s", server, port);
1431
1432 freeaddrinfo(result);
1433
1434 n = read(sfd, buf, 8);
1435
1436 /* Make sure the server is the tracecmd server */
1437 if (memcmp(buf, "tracecmd", 8) != 0)
1438 die("server not tracecmd server");
1439
1440 /* write the number of CPUs we have (in ASCII) */
1441
1442 sprintf(buf, "%d", cpu_count);
1443
1444 /* include \0 */
1445 write(sfd, buf, strlen(buf)+1);
1446
1447 /* write the pagesize (in ASCII) */
1448
1449 page_size = getpagesize();
1450 sprintf(buf, "%d", page_size);
1451
1452 /* include \0 */
1453 write(sfd, buf, strlen(buf)+1);
1454
1455 /*
1456 * If we are using IPV4 and our page size is greater than
1457 * or equal to 64K, we need to punt and use TCP. :-(
1458 */
1459
1460 /* TODO, test for ipv4 */
1461 if (page_size >= UDP_MAX_PACKET) {
1462 warning("page size too big for UDP using TCP in live read");
1463 use_tcp = 1;
1464 }
1465
1466 if (use_tcp) {
1467 /* Send one option */
1468 write(sfd, "1", 2);
1469 /* Size 4 */
1470 write(sfd, "4", 2);
1471 /* use TCP */
1472 write(sfd, "TCP", 4);
1473 } else
1474 /* No options */
1475 write(sfd, "0", 2);
1476
1477 client_ports = malloc_or_die(sizeof(int) * cpu_count);
1478
1479 /*
1480 * Now we will receive back a comma deliminated list
1481 * of client ports to connect to.
1482 */
1483 for (cpu = 0; cpu < cpu_count; cpu++) {
1484 for (i = 0; i < BUFSIZ; i++) {
1485 n = read(sfd, buf+i, 1);
1486 if (n != 1)
1487 die("Error, reading server ports");
1488 if (!buf[i] || buf[i] == ',')
1489 break;
1490 }
1491 if (i == BUFSIZ)
1492 die("read bad port number");
1493 buf[i] = 0;
1494 client_ports[cpu] = atoi(buf);
1495 }
1496
1497 /* Now create the handle through this socket */
1498 handle = tracecmd_create_init_fd(sfd);
1499
1500 /* OK, we are all set, let'r rip! */
1501}
1502
1503static void finish_network(void)
1504{
1505 close(sfd);
1506 free(host);
1507}
1508
1509static void start_threads(void)
1510{
1511 int i;
1512
1513 cpu_count = count_cpus();
1514
1515 if (host)
1516 setup_network();
1517
1518 /* make a thread for every CPU we have */
1519 pids = malloc_or_die(sizeof(*pids) * cpu_count);
1520
1521 memset(pids, 0, sizeof(*pids) * cpu_count);
1522
1523 for (i = 0; i < cpu_count; i++) {
1524 pids[i] = create_recorder(i);
1525 }
1526}
1527
1528static void record_data(void)
1529{
1530 struct tracecmd_output *handle;
1531 char **temp_files;
1532 int i;
1533
1534 if (host) {
1535 finish_network();
1536 return;
1537 }
1538
1539 if (latency)
1540 handle = tracecmd_create_file_latency(output_file, cpu_count);
1541 else {
1542 if (!cpu_count)
1543 return;
1544
1545 temp_files = malloc_or_die(sizeof(*temp_files) * cpu_count);
1546
1547 for (i = 0; i < cpu_count; i++)
1548 temp_files[i] = get_temp_file(i);
1549
1550 handle = tracecmd_create_file_glob(output_file, cpu_count,
1551 temp_files, listed_events);
1552
1553 for (i = 0; i < cpu_count; i++)
1554 put_temp_file(temp_files[i]);
1555 free(temp_files);
1556 }
1557 if (!handle)
1558 die("could not write to file");
1559 tracecmd_output_close(handle);
1560}
1561
1562static int trace_empty(void)
1563{
1564 char *path;
1565 FILE *fp;
1566 char *line = NULL;
1567 size_t size;
1568 ssize_t n;
1569 int ret = 1;
1570
1571 /*
1572 * Test if the trace file is empty.
1573 *
1574 * Yes, this is a heck of a hack. What is done here
1575 * is to read the trace file and ignore the
1576 * lines starting with '#', and if we get a line
1577 * that is without a '#' the trace is not empty.
1578 * Otherwise it is.
1579 */
1580 path = tracecmd_get_tracing_file("trace");
1581 fp = fopen(path, "r");
1582 if (!fp)
1583 die("reading '%s'", path);
1584
1585 do {
1586 n = getline(&line, &size, fp);
1587 if (n > 0 && line && line[0] != '#') {
1588 ret = 0;
1589 break;
1590 }
1591 } while (line && n > 0);
1592
1593 tracecmd_put_tracing_file(path);
1594
1595 fclose(fp);
1596
1597 return ret;
1598}
1599
1600static void write_func_file(const char *file, struct func_list **list)
1601{
1602 struct func_list *item;
1603 char *path;
1604 int fd;
1605
1606 path = tracecmd_get_tracing_file(file);
1607
1608 fd = open(path, O_WRONLY | O_TRUNC);
1609 if (fd < 0)
1610 goto free;
1611
1612 while (*list) {
1613 item = *list;
1614 *list = item->next;
1615 write(fd, item->func, strlen(item->func));
1616 write(fd, " ", 1);
1617 free(item);
1618 }
1619 close(fd);
1620
1621 free:
1622 tracecmd_put_tracing_file(path);
1623}
1624
1625static void set_funcs(void)
1626{
1627 write_func_file("set_ftrace_filter", &filter_funcs);
1628 write_func_file("set_ftrace_notrace", &notrace_funcs);
1629 write_func_file("set_graph_function", &graph_funcs);
1630}
1631
1632static void add_func(struct func_list **list, const char *func)
1633{
1634 struct func_list *item;
1635
1636 item = malloc_or_die(sizeof(*item));
1637 item->func = func;
1638 item->next = *list;
1639 *list = item;
1640}
1641
1642void set_buffer_size(void)
1643{
1644 char buf[BUFSIZ];
1645 char *path;
1646 int ret;
1647 int fd;
1648
1649 if (!buffer_size)
1650 return;
1651
1652 if (buffer_size < 0)
1653 die("buffer size must be positive");
1654
1655 snprintf(buf, BUFSIZ, "%d", buffer_size);
1656
1657 path = tracecmd_get_tracing_file("buffer_size_kb");
1658 fd = open(path, O_WRONLY);
1659 if (fd < 0)
1660 die("can't open %s", path);
1661
1662 ret = write(fd, buf, strlen(buf));
1663 if (ret < 0)
1664 warning("Can't write to %s", path);
1665 close(fd);
1666}
1667
1668int main (int argc, char **argv) 137int main (int argc, char **argv)
1669{ 138{
1670 const char *plugin = NULL;
1671 const char *output = NULL;
1672 const char *option;
1673 struct event_list *event;
1674 struct event_list *last_event;
1675 struct tracecmd_event_list *list;
1676 struct trace_seq s;
1677 int record_all = 0;
1678 int disable = 0;
1679 int plug = 0;
1680 int events = 0;
1681 int options = 0;
1682 int record = 0;
1683 int extract = 0;
1684 int run_command = 0;
1685 int neg_event = 0;
1686 int keep = 0;
1687 int fset;
1688 int cpu;
1689
1690 int c; 139 int c;
1691 140
1692 errno = 0; 141 errno = 0;
@@ -1709,173 +158,18 @@ int main (int argc, char **argv)
1709 } else if (strcmp(argv[1], "stack") == 0) { 158 } else if (strcmp(argv[1], "stack") == 0) {
1710 trace_stack(argc, argv); 159 trace_stack(argc, argv);
1711 exit(0); 160 exit(0);
1712 } else if ((record = (strcmp(argv[1], "record") == 0)) || 161 } else if (strcmp(argv[1], "record") == 0 ||
1713 (strcmp(argv[1], "start") == 0) || 162 strcmp(argv[1], "start") == 0 ||
1714 ((extract = strcmp(argv[1], "extract") == 0))) { 163 strcmp(argv[1], "extract") == 0 ||
1715 164 strcmp(argv[1], "stop") == 0 ||
1716 while ((c = getopt(argc-1, argv+1, "+hae:f:Fp:cdo:O:s:r:vg:l:n:P:N:tb:ki")) >= 0) { 165 strcmp(argv[1], "reset") == 0) {
1717 switch (c) { 166 trace_record(argc, argv);
1718 case 'h':
1719 usage(argv);
1720 break;
1721 case 'a':
1722 record_all = 1;
1723 while (listed_events) {
1724 list = listed_events;
1725 listed_events = list->next;
1726 free(list);
1727 }
1728 list = malloc_or_die(sizeof(*list));
1729 list->next = NULL;
1730 list->glob = "*/*";
1731 listed_events = list;
1732
1733 break;
1734 case 'e':
1735 if (extract)
1736 usage(argv);
1737 events = 1;
1738 event = malloc_or_die(sizeof(*event));
1739 memset(event, 0, sizeof(*event));
1740 event->event = optarg;
1741 event->next = event_selection;
1742 event->neg = neg_event;
1743 event_selection = event;
1744 event->filter = NULL;
1745 last_event = event;
1746
1747 if (!record_all) {
1748 list = malloc_or_die(sizeof(*list));
1749 list->next = listed_events;
1750 list->glob = optarg;
1751 listed_events = list;
1752 }
1753
1754 break;
1755 case 'f':
1756 if (!last_event)
1757 die("filter must come after event");
1758 if (last_event->filter) {
1759 last_event->filter =
1760 realloc(last_event->filter,
1761 strlen(last_event->filter) +
1762 strlen("&&()") +
1763 strlen(optarg) + 1);
1764 strcat(last_event->filter, "&&(");
1765 strcat(last_event->filter, optarg);
1766 strcat(last_event->filter, ")");
1767 } else {
1768 last_event->filter =
1769 malloc_or_die(strlen(optarg) +
1770 strlen("()") + 1);
1771 sprintf(last_event->filter, "(%s)", optarg);
1772 }
1773 break;
1774
1775 case 'F':
1776 if (filter_pid >= 0)
1777 die("-P and -F can not both be specified");
1778 filter_task = 1;
1779 break;
1780 case 'P':
1781 if (filter_task)
1782 die("-P and -F can not both be specified");
1783 if (filter_pid >= 0)
1784 die("only one -P pid can be filtered at a time");
1785 filter_pid = atoi(optarg);
1786 break;
1787 case 'c':
1788 do_ptrace = 1;
1789 break;
1790 case 'v':
1791 if (extract)
1792 usage(argv);
1793 neg_event = 1;
1794 break;
1795 case 'l':
1796 add_func(&filter_funcs, optarg);
1797 break;
1798 case 'n':
1799 add_func(&notrace_funcs, optarg);
1800 break;
1801 case 'g':
1802 add_func(&graph_funcs, optarg);
1803 break;
1804 case 'p':
1805 if (plugin)
1806 die("only one plugin allowed");
1807 plugin = optarg;
1808 fprintf(stderr, " plugin %s\n", plugin);
1809 break;
1810 case 'd':
1811 if (extract)
1812 usage(argv);
1813 disable = 1;
1814 break;
1815 case 'o':
1816 if (host)
1817 die("-o incompatible with -N");
1818 if (!record && !extract)
1819 die("start does not take output\n"
1820 "Did you mean 'record'?");
1821 if (output)
1822 die("only one output file allowed");
1823 output = optarg;
1824 break;
1825 case 'O':
1826 option = optarg;
1827 save_option(option);
1828 break;
1829 case 's':
1830 if (extract)
1831 usage(argv);
1832 sleep_time = atoi(optarg);
1833 break;
1834 case 'r':
1835 rt_prio = atoi(optarg);
1836 break;
1837 case 'N':
1838 if (!record)
1839 die("-N only available with record");
1840 if (output)
1841 die("-N incompatible with -o");
1842 host = optarg;
1843 break;
1844 case 't':
1845 use_tcp = 1;
1846 break;
1847 case 'b':
1848 buffer_size = atoi(optarg);
1849 break;
1850 case 'k':
1851 keep = 1;
1852 break;
1853 case 'i':
1854 ignore_event_not_found = 1;
1855 break;
1856 }
1857 }
1858
1859 } else if (strcmp(argv[1], "stop") == 0) {
1860 disable_tracing();
1861 exit(0);
1862
1863 } else if (strcmp(argv[1], "reset") == 0) {
1864 while ((c = getopt(argc-1, argv+1, "b:")) >= 0) {
1865 switch (c) {
1866 case 'b':
1867 buffer_size = atoi(optarg);
1868 /* Min buffer size is 1 */
1869 if (strcmp(optarg, "0") == 0)
1870 buffer_size = 1;
1871 break;
1872 }
1873 }
1874 disable_all();
1875 set_buffer_size();
1876 exit(0); 167 exit(0);
1877 168
1878 } else if (strcmp(argv[1], "list") == 0) { 169 } else if (strcmp(argv[1], "list") == 0) {
170 int events = 0;
171 int plug = 0;
172 int options = 0;
1879 173
1880 while ((c = getopt(argc-1, argv+1, "+hepo")) >= 0) { 174 while ((c = getopt(argc-1, argv+1, "+hepo")) >= 0) {
1881 switch (c) { 175 switch (c) {
@@ -1924,125 +218,6 @@ int main (int argc, char **argv)
1924 usage(argv); 218 usage(argv);
1925 } 219 }
1926 220
1927 if (do_ptrace && !filter_task && (filter_pid < 0))
1928 die(" -c can only be used with -F or -P");
1929
1930 if ((argc - optind) >= 2) {
1931 if (!record)
1932 die("Command start does not take any commands\n"
1933 "Did you mean 'record'?");
1934 if (extract)
1935 die("Command extract does not take any commands\n"
1936 "Did you mean 'record'?");
1937 run_command = 1;
1938 }
1939
1940 if (!events && !plugin && !extract)
1941 die("no event or plugin was specified... aborting");
1942
1943 if (output)
1944 output_file = output;
1945
1946 tracing_on_init_val = read_tracing_on();
1947
1948 if (event_selection)
1949 expand_event_list();
1950
1951 if (!extract) {
1952 fset = set_ftrace(!disable);
1953 disable_all();
1954 set_funcs();
1955
1956 if (events)
1957 enable_events();
1958 set_buffer_size();
1959 }
1960
1961 if (plugin) {
1962 /*
1963 * Latency tracers just save the trace and kill
1964 * the threads.
1965 */
1966 if (strcmp(plugin, "irqsoff") == 0 ||
1967 strcmp(plugin, "preemptoff") == 0 ||
1968 strcmp(plugin, "preemptirqsoff") == 0 ||
1969 strcmp(plugin, "wakeup") == 0 ||
1970 strcmp(plugin, "wakeup_rt") == 0) {
1971 latency = 1;
1972 if (host)
1973 die("Network tracing not available with latency tracer plugins");
1974 }
1975 if (fset < 0 && (strcmp(plugin, "function") == 0 ||
1976 strcmp(plugin, "function_graph") == 0))
1977 die("function tracing not configured on this kernel");
1978 if (!extract)
1979 set_plugin(plugin);
1980 }
1981
1982 set_options();
1983
1984 if (record || extract) {
1985 signal(SIGINT, finish);
1986 if (!latency)
1987 start_threads();
1988 }
1989
1990 if (extract) {
1991 while (!finished && !trace_empty()) {
1992 flush_threads();
1993 sleep(1);
1994 }
1995 } else {
1996 if (!record) {
1997 update_task_filter();
1998 exit(0);
1999 }
2000
2001 if (run_command)
2002 run_cmd((argc - optind) - 1, &argv[optind + 1]);
2003 else {
2004 update_task_filter();
2005 /* We don't ptrace ourself */
2006 if (do_ptrace && filter_pid >= 0)
2007 ptrace_attach(filter_pid);
2008 /* sleep till we are woken with Ctrl^C */
2009 printf("Hit Ctrl^C to stop recording\n");
2010 while (!finished)
2011 trace_or_sleep();
2012 }
2013
2014 disable_tracing();
2015 }
2016
2017 stop_threads();
2018
2019 record_data();
2020 delete_thread_data();
2021
2022 printf("Kernel buffer statistics:\n"
2023 " Note: \"entries\" are the entries left in the kernel ring buffer and are not\n"
2024 " recorded in the trace data. They should all be zero.\n\n");
2025 for (cpu = 0; cpu < cpu_count; cpu++) {
2026 trace_seq_init(&s);
2027 trace_seq_printf(&s, "CPU: %d\n", cpu);
2028 tracecmd_stat_cpu(&s, cpu);
2029 trace_seq_do_printf(&s);
2030 trace_seq_destroy(&s);
2031 printf("\n");
2032 }
2033
2034 if (keep)
2035 exit(0);
2036
2037 /* Turn off everything */
2038 disable_all();
2039
2040 /* If tracing_on was enabled before we started, set it on now */
2041 if (tracing_on_init_val)
2042 write_tracing_on(tracing_on_init_val);
2043
2044 exit(0);
2045
2046 return 0; 221 return 0;
2047} 222}
2048 223
diff --git a/trace-local.h b/trace-local.h
index 72f6450..a73377f 100644
--- a/trace-local.h
+++ b/trace-local.h
@@ -36,6 +36,8 @@ extern int show_status;
36struct tracecmd_input *read_trace_header(const char *file); 36struct tracecmd_input *read_trace_header(const char *file);
37int read_trace_files(void); 37int read_trace_files(void);
38 38
39void trace_record(int argc, char **argv);
40
39void trace_report(int argc, char **argv); 41void trace_report(int argc, char **argv);
40 42
41void trace_split(int argc, char **argv); 43void trace_split(int argc, char **argv);
diff --git a/trace-record.c b/trace-record.c
new file mode 100644
index 0000000..139f632
--- /dev/null
+++ b/trace-record.c
@@ -0,0 +1,1869 @@
1/*
2 * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _GNU_SOURCE
22
23#include <dirent.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdarg.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/wait.h>
31#include <sys/socket.h>
32#include <sys/ptrace.h>
33#include <netdb.h>
34#include <pthread.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <ctype.h>
38#include <sched.h>
39#include <glob.h>
40#include <errno.h>
41
42#include "trace-local.h"
43
44#define _STR(x) #x
45#define STR(x) _STR(x)
46#define MAX_PATH 256
47
48#define TRACE_CTRL "tracing_on"
49#define TRACE "trace"
50#define AVAILABLE "available_tracers"
51#define CURRENT "current_tracer"
52#define ITER_CTRL "trace_options"
53#define MAX_LATENCY "tracing_max_latency"
54
55#define UDP_MAX_PACKET (65536 - 20)
56
57static int tracing_on_init_val;
58
59static int rt_prio;
60
61static int use_tcp;
62
63static unsigned int page_size;
64
65static int buffer_size;
66
67static const char *output_file = "trace.dat";
68
69static int latency;
70static int sleep_time = 1000;
71static int cpu_count;
72static int *pids;
73
74static char *host;
75static int *client_ports;
76static int sfd;
77
78static int do_ptrace;
79
80static int filter_task;
81static int filter_pid = -1;
82
83static int finished;
84
85struct func_list {
86 struct func_list *next;
87 const char *func;
88};
89
90static struct func_list *filter_funcs;
91static struct func_list *notrace_funcs;
92static struct func_list *graph_funcs;
93
94struct filter_pids {
95 struct filter_pids *next;
96 int pid;
97};
98
99static struct filter_pids *filter_pids;
100static int nr_filter_pids;
101static int len_filter_pids;
102
103struct opt_list {
104 struct opt_list *next;
105 const char *option;
106};
107
108static struct opt_list *options;
109
110struct event_list {
111 struct event_list *next;
112 const char *event;
113 char *filter;
114 char *filter_file;
115 char *enable_file;
116 int neg;
117};
118
119static struct event_list *sched_switch_event;
120static struct event_list *sched_wakeup_event;
121static struct event_list *sched_wakeup_new_event;
122static struct event_list *sched_event;
123
124static struct event_list *event_selection;
125struct tracecmd_event_list *listed_events;
126
127struct events {
128 struct events *sibling;
129 struct events *children;
130 struct events *next;
131 char *name;
132};
133
134static struct tracecmd_recorder *recorder;
135
136static int ignore_event_not_found = 0;
137
138static char *get_temp_file(int cpu)
139{
140 char *file = NULL;
141 int size;
142
143 size = snprintf(file, 0, "%s.cpu%d", output_file, cpu);
144 file = malloc_or_die(size + 1);
145 sprintf(file, "%s.cpu%d", output_file, cpu);
146
147 return file;
148}
149
150static void put_temp_file(char *file)
151{
152 free(file);
153}
154
155static void delete_temp_file(int cpu)
156{
157 char file[MAX_PATH];
158
159 snprintf(file, MAX_PATH, "%s.cpu%d", output_file, cpu);
160 unlink(file);
161}
162
163static void kill_threads(void)
164{
165 int i;
166
167 if (!cpu_count || !pids)
168 return;
169
170 for (i = 0; i < cpu_count; i++) {
171 if (pids[i] > 0) {
172 kill(pids[i], SIGKILL);
173 delete_temp_file(i);
174 pids[i] = 0;
175 }
176 }
177}
178
179void die(const char *fmt, ...)
180{
181 va_list ap;
182 int ret = errno;
183
184 if (errno)
185 perror("trace-cmd");
186 else
187 ret = -1;
188
189 kill_threads();
190 va_start(ap, fmt);
191 fprintf(stderr, " ");
192 vfprintf(stderr, fmt, ap);
193 va_end(ap);
194
195 fprintf(stderr, "\n");
196 exit(ret);
197}
198
199static void delete_thread_data(void)
200{
201 int i;
202
203 if (!cpu_count)
204 return;
205
206 for (i = 0; i < cpu_count; i++) {
207 if (pids[i]) {
208 delete_temp_file(i);
209 if (pids[i] < 0)
210 pids[i] = 0;
211 }
212 }
213}
214
215static void stop_threads(void)
216{
217 int i;
218
219 if (!cpu_count)
220 return;
221
222 for (i = 0; i < cpu_count; i++) {
223 if (pids[i] > 0) {
224 kill(pids[i], SIGINT);
225 waitpid(pids[i], NULL, 0);
226 pids[i] = -1;
227 }
228 }
229}
230
231static void flush_threads(void)
232{
233 int i;
234
235 if (!cpu_count)
236 return;
237
238 for (i = 0; i < cpu_count; i++) {
239 if (pids[i] > 0)
240 kill(pids[i], SIGUSR1);
241 }
242}
243
244static int set_ftrace(int set)
245{
246 struct stat buf;
247 char *path = "/proc/sys/kernel/ftrace_enabled";
248 int fd;
249 char *val = set ? "1" : "0";
250
251 /* if ftace_enable does not exist, simply ignore it */
252 fd = stat(path, &buf);
253 if (fd < 0)
254 return -ENODEV;
255
256 fd = open(path, O_WRONLY);
257 if (fd < 0)
258 die ("Can't %s ftrace", set ? "enable" : "disable");
259
260 write(fd, val, 1);
261 close(fd);
262
263 return 0;
264}
265
266static void clear_trace(void)
267{
268 FILE *fp;
269 char *path;
270
271 /* reset the trace */
272 path = tracecmd_get_tracing_file("trace");
273 fp = fopen(path, "w");
274 if (!fp)
275 die("writing to '%s'", path);
276 tracecmd_put_tracing_file(path);
277 fwrite("0", 1, 1, fp);
278 fclose(fp);
279}
280
281static void reset_max_latency(void)
282{
283 FILE *fp;
284 char *path;
285
286 /* reset the trace */
287 path = tracecmd_get_tracing_file("tracing_max_latency");
288 fp = fopen(path, "w");
289 if (!fp)
290 die("writing to '%s'", path);
291 tracecmd_put_tracing_file(path);
292 fwrite("0", 1, 1, fp);
293 fclose(fp);
294}
295
296static void add_filter_pid(int pid)
297{
298 struct filter_pids *p;
299 char buf[100];
300
301 p = malloc_or_die(sizeof(*p));
302 p->next = filter_pids;
303 p->pid = pid;
304 filter_pids = p;
305 nr_filter_pids++;
306
307 len_filter_pids += sprintf(buf, "%d", pid);
308}
309
310static void update_ftrace_pid(const char *pid, int reset)
311{
312 static char *path;
313 int ret;
314 static int fd = -1;
315
316 if (!pid) {
317 if (fd >= 0)
318 close(fd);
319 if (path)
320 tracecmd_put_tracing_file(path);
321 fd = -1;
322 path = NULL;
323 return;
324 }
325
326 /* Force reopen on reset */
327 if (reset && fd >= 0) {
328 close(fd);
329 fd = -1;
330 }
331
332 if (fd < 0) {
333 if (!path)
334 path = tracecmd_get_tracing_file("set_ftrace_pid");
335 if (!path)
336 return;
337 fd = open(path, O_WRONLY | (reset ? O_TRUNC : 0));
338 if (fd < 0)
339 return;
340 }
341
342 ret = write(fd, pid, strlen(pid));
343
344 /*
345 * Older kernels required "-1" to disable pid
346 */
347 if (ret < 0 && !strlen(pid))
348 ret = write(fd, "-1", 2);
349
350 if (ret < 0)
351 die("error writing to %s", path);
352
353 /* add whitespace in case another pid is written */
354 write(fd, " ", 1);
355}
356
357static void update_event_filters(const char *pid_filter);
358static void update_pid_event_filters(const char *pid);
359static void enable_tracing(void);
360static void
361update_sched_event(struct event_list **event, const char *file,
362 const char *pid_filter, const char *field_filter);
363
364static char *make_pid_filter(const char *field)
365{
366 struct filter_pids *p;
367 char *filter;
368 char *orit;
369 char *str;
370 int len;
371
372 filter = malloc_or_die(len_filter_pids +
373 (strlen(field) + strlen("(==)||")) * nr_filter_pids);
374 /* Last '||' that is not used will cover the \0 */
375 str = filter;
376
377 for (p = filter_pids; p; p = p->next) {
378 if (p == filter_pids)
379 orit = "";
380 else
381 orit = "||";
382 len = sprintf(str, "%s(%s==%d)", orit, field, p->pid);
383 str += len;
384 }
385
386 return filter;
387}
388
389static void add_new_filter_pid(int pid)
390{
391 char *pid_filter;
392 char *filter;
393 char buf[100];
394
395 add_filter_pid(pid);
396 sprintf(buf, "%d", pid);
397 update_ftrace_pid(buf, 0);
398
399 pid_filter = make_pid_filter("common_pid");
400 update_event_filters(pid_filter);
401
402 if (!sched_event && !sched_switch_event
403 && !sched_wakeup_event && !sched_wakeup_new_event)
404 return;
405
406 /*
407 * Also make sure that the sched_switch to this pid
408 * and wakeups of this pid are also traced.
409 * Only need to do this if the events are active.
410 */
411 filter = make_pid_filter("next_pid");
412 update_sched_event(&sched_switch_event, "sched/sched_switch", pid_filter, filter);
413 free(filter);
414
415 filter = make_pid_filter("pid");
416 update_sched_event(&sched_wakeup_event, "sched/sched_wakeup",
417 pid_filter, filter);
418 update_sched_event(&sched_wakeup_new_event, "sched/sched_wakeup_new",
419 pid_filter, filter);
420 free(pid_filter);
421 free(filter);
422}
423
424static void update_task_filter(void)
425{
426 int pid = getpid();
427 char spid[100];
428
429 if (!filter_task && filter_pid < 0) {
430 update_ftrace_pid("", 1);
431 enable_tracing();
432 return;
433 }
434
435 if (filter_pid >= 0)
436 pid = filter_pid;
437
438 snprintf(spid, 100, "%d", pid);
439
440 update_ftrace_pid(spid, 1);
441
442 update_pid_event_filters(spid);
443
444 enable_tracing();
445}
446
447static void ptrace_attach(int pid)
448{
449 int ret;
450
451 ret = ptrace(PTRACE_ATTACH, pid, NULL, 0);
452 if (ret < 0) {
453 warning("Unable to trace process %d children", pid);
454 do_ptrace = 0;
455 return;
456 }
457 add_filter_pid(pid);
458}
459
460static void enable_ptrace(void)
461{
462 if (!do_ptrace || !filter_task)
463 return;
464
465 ptrace(PTRACE_TRACEME, 0, NULL, 0);
466}
467
468static void ptrace_wait(int main_pid)
469{
470 unsigned long send_sig;
471 unsigned long child;
472 siginfo_t sig;
473 int cstatus;
474 int status;
475 int event;
476 int pid;
477 int ret;
478
479 do {
480 ret = waitpid(-1, &status, WSTOPPED | __WALL);
481 if (ret < 0)
482 continue;
483
484 pid = ret;
485
486 if (WIFSTOPPED(status)) {
487 event = (status >> 16) & 0xff;
488 ptrace(PTRACE_GETSIGINFO, pid, NULL, &sig);
489 send_sig = sig.si_signo;
490 /* Don't send ptrace sigs to child */
491 if (send_sig == SIGTRAP || send_sig == SIGSTOP)
492 send_sig = 0;
493 switch (event) {
494 case PTRACE_EVENT_FORK:
495 case PTRACE_EVENT_VFORK:
496 case PTRACE_EVENT_CLONE:
497 /* forked a child */
498 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &child);
499 ptrace(PTRACE_SETOPTIONS, child, NULL,
500 PTRACE_O_TRACEFORK |
501 PTRACE_O_TRACEVFORK |
502 PTRACE_O_TRACECLONE |
503 PTRACE_O_TRACEEXIT);
504 add_new_filter_pid(child);
505 ptrace(PTRACE_CONT, child, NULL, 0);
506 break;
507
508 case PTRACE_EVENT_EXIT:
509 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &cstatus);
510 ptrace(PTRACE_DETACH, pid, NULL, NULL);
511 break;
512 }
513 ptrace(PTRACE_SETOPTIONS, pid, NULL,
514 PTRACE_O_TRACEFORK |
515 PTRACE_O_TRACEVFORK |
516 PTRACE_O_TRACECLONE |
517 PTRACE_O_TRACEEXIT);
518 ptrace(PTRACE_CONT, pid, NULL, send_sig);
519 }
520 } while (!finished && ret > 0 &&
521 (!WIFEXITED(status) || pid != main_pid));
522}
523
524void trace_or_sleep(void)
525{
526 if (do_ptrace && filter_pid >= 0)
527 ptrace_wait(filter_pid);
528 else
529 sleep(10);
530}
531
532void run_cmd(int argc, char **argv)
533{
534 int status;
535 int pid;
536
537 if ((pid = fork()) < 0)
538 die("failed to fork");
539 if (!pid) {
540 /* child */
541 update_task_filter();
542 enable_ptrace();
543 if (execvp(argv[0], argv))
544 exit(-1);
545 }
546 if (do_ptrace) {
547 add_filter_pid(pid);
548 ptrace_wait(pid);
549 } else
550 waitpid(pid, &status, 0);
551}
552
553static void set_plugin(const char *name)
554{
555 FILE *fp;
556 char *path;
557
558 path = tracecmd_get_tracing_file("current_tracer");
559 fp = fopen(path, "w");
560 if (!fp)
561 die("writing to '%s'", path);
562 tracecmd_put_tracing_file(path);
563
564 fwrite(name, 1, strlen(name), fp);
565 fclose(fp);
566}
567
568static void save_option(const char *option)
569{
570 struct opt_list *opt;
571
572 opt = malloc_or_die(sizeof(*opt));
573 opt->next = options;
574 options = opt;
575 opt->option = option;
576}
577
578static void set_option(const char *option)
579{
580 FILE *fp;
581 char *path;
582
583 path = tracecmd_get_tracing_file("trace_options");
584 fp = fopen(path, "w");
585 if (!fp)
586 die("writing to '%s'", path);
587 tracecmd_put_tracing_file(path);
588
589 fwrite(option, 1, strlen(option), fp);
590 fclose(fp);
591}
592
593static void set_options(void)
594{
595 struct opt_list *opt;
596
597 while (options) {
598 opt = options;
599 options = opt->next;
600 set_option(opt->option);
601 free(opt);
602 }
603}
604
605static int use_old_event_method(void)
606{
607 static int old_event_method;
608 static int processed;
609 struct stat st;
610 char *path;
611 int ret;
612
613 if (processed)
614 return old_event_method;
615
616 /* Check if the kernel has the events/enable file */
617 path = tracecmd_get_tracing_file("events/enable");
618 ret = stat(path, &st);
619 tracecmd_put_tracing_file(path);
620 if (ret < 0)
621 old_event_method = 1;
622
623 processed = 1;
624
625 return old_event_method;
626}
627
628static void old_update_events(const char *name, char update)
629{
630 char *path;
631 FILE *fp;
632 int ret;
633
634 if (strcmp(name, "all") == 0)
635 name = "*:*";
636
637 /* need to use old way */
638 path = tracecmd_get_tracing_file("set_event");
639 fp = fopen(path, "w");
640 if (!fp)
641 die("opening '%s'", path);
642 tracecmd_put_tracing_file(path);
643
644 /* Disable the event with "!" */
645 if (update == '0')
646 fwrite("!", 1, 1, fp);
647
648 ret = fwrite(name, 1, strlen(name), fp);
649 if (ret < 0)
650 die("bad event '%s'", name);
651
652 ret = fwrite("\n", 1, 1, fp);
653 if (ret < 0)
654 die("bad event '%s'", name);
655
656 fclose(fp);
657
658 return;
659}
660
661static void reset_events()
662{
663 glob_t globbuf;
664 char *path;
665 char c;
666 int fd;
667 int i;
668 int ret;
669
670 if (use_old_event_method()) {
671 old_update_events("all", '0');
672 return;
673 }
674
675 c = '0';
676 path = tracecmd_get_tracing_file("events/enable");
677 fd = open(path, O_WRONLY);
678 if (fd < 0)
679 die("opening to '%s'", path);
680 ret = write(fd, &c, 1);
681 close(fd);
682 tracecmd_put_tracing_file(path);
683
684 path = tracecmd_get_tracing_file("events/*/filter");
685 globbuf.gl_offs = 0;
686 ret = glob(path, 0, NULL, &globbuf);
687 tracecmd_put_tracing_file(path);
688 if (ret < 0)
689 return;
690
691 for (i = 0; i < globbuf.gl_pathc; i++) {
692 path = globbuf.gl_pathv[i];
693 fd = open(path, O_WRONLY);
694 if (fd < 0)
695 die("opening to '%s'", path);
696 ret = write(fd, &c, 1);
697 close(fd);
698 }
699 globfree(&globbuf);
700}
701
702static void write_filter(const char *file, const char *filter)
703{
704 char buf[BUFSIZ];
705 int fd;
706 int ret;
707
708 fd = open(file, O_WRONLY);
709 if (fd < 0)
710 die("opening to '%s'", file);
711 ret = write(fd, filter, strlen(filter));
712 close(fd);
713 if (ret < 0) {
714 /* filter failed */
715 fd = open(file, O_RDONLY);
716 if (fd < 0)
717 die("writing to '%s'", file);
718 /* the filter has the error */
719 while ((ret = read(fd, buf, BUFSIZ)) > 0)
720 fprintf(stderr, "%.*s", ret, buf);
721 die("Failed filter of %s\n", file);
722 close(fd);
723 }
724}
725
726static void
727update_event(struct event_list *event, const char *filter,
728 int filter_only, char update)
729{
730 const char *name = event->event;
731 FILE *fp;
732 char *path;
733 int ret;
734
735 if (use_old_event_method()) {
736 if (filter_only)
737 return;
738 old_update_events(name, update);
739 return;
740 }
741
742 if (filter && event->filter_file)
743 write_filter(event->filter_file, filter);
744
745 if (filter_only || !event->enable_file)
746 return;
747
748 path = event->enable_file;
749
750 fp = fopen(path, "w");
751 if (!fp)
752 die("writing to '%s'", path);
753 ret = fwrite(&update, 1, 1, fp);
754 fclose(fp);
755 if (ret < 0)
756 die("writing to '%s'", path);
757}
758
759/*
760 * The debugfs file tracing_enabled needs to be deprecated.
761 * But just in case anyone fiddled with it. If it exists,
762 * make sure it is one.
763 * No error checking needed here.
764 */
765static void check_tracing_enabled(void)
766{
767 static int fd = -1;
768 char *path;
769
770 if (fd < 0) {
771 path = tracecmd_get_tracing_file("tracing_enabled");
772 fd = open(path, O_WRONLY);
773 tracecmd_put_tracing_file(path);
774
775 if (fd < 0)
776 return;
777 }
778 write(fd, "1", 1);
779}
780
781static int tracing_on_fd = -1;
782
783static int open_tracing_on(void)
784{
785 int fd = tracing_on_fd;
786 char *path;
787
788 if (fd >= 0)
789 return fd;
790
791 path = tracecmd_get_tracing_file("tracing_on");
792 fd = open(path, O_RDWR);
793 if (fd < 0)
794 die("opening '%s'", path);
795 tracecmd_put_tracing_file(path);
796 tracing_on_fd = fd;
797
798 return fd;
799}
800
801static void write_tracing_on(int on)
802{
803 int ret;
804 int fd;
805
806 fd = open_tracing_on();
807 if (fd < 0)
808 return;
809
810 if (on)
811 ret = write(fd, "1", 1);
812 else
813 ret = write(fd, "0", 1);
814
815 if (ret < 0)
816 die("writing 'tracing_on'");
817}
818
819static int read_tracing_on(void)
820{
821 int fd;
822 char buf[10];
823 int ret;
824
825 fd = open_tracing_on();
826 if (fd < 0)
827 return 0;
828
829 ret = read(fd, buf, 10);
830 if (ret <= 0)
831 die("Reading 'tracing_on'");
832 buf[9] = 0;
833 ret = atoi(buf);
834
835 return ret;
836}
837
838static void enable_tracing(void)
839{
840 check_tracing_enabled();
841
842 write_tracing_on(1);
843
844 if (latency)
845 reset_max_latency();
846}
847
848static void disable_tracing(void)
849{
850 write_tracing_on(0);
851}
852
853static void disable_all(void)
854{
855 disable_tracing();
856
857 set_plugin("nop");
858 reset_events();
859
860 /* Force close and reset of ftrace pid file */
861 update_ftrace_pid("", 1);
862 update_ftrace_pid(NULL, 0);
863
864 clear_trace();
865}
866
867static void
868update_sched_event(struct event_list **event, const char *file,
869 const char *pid_filter, const char *field_filter)
870{
871 char *event_filter;
872 char *filter;
873 char *path;
874 char *p;
875
876 if (!*event) {
877 /* No sched events are being processed, ignore */
878 if (!sched_event)
879 return;
880 *event = malloc_or_die(sizeof(**event));
881 memset(*event, 0, sizeof(**event));
882 (*event)->event = file;
883 p = malloc_or_die(strlen(file) + strlen("events//filter") + 1);
884 sprintf(p, "events/%s/filter", file);
885 path = tracecmd_get_tracing_file(p);
886 free(p);
887 (*event)->filter_file = strdup(path);
888 if (sched_event->filter)
889 (*event)->filter = strdup(sched_event->filter);
890 tracecmd_put_tracing_file(path);
891 }
892
893 path = (*event)->filter_file;
894 if (!path)
895 return;
896
897 filter = (*event)->filter;
898
899 if (filter) {
900 event_filter = malloc_or_die(strlen(pid_filter) +
901 strlen(field_filter) +
902 strlen(filter) +
903 strlen("(()||())&&()") + 1);
904 sprintf(event_filter, "((%s)||(%s))&&(%s)",
905 pid_filter, field_filter, filter);
906 } else {
907 event_filter = malloc_or_die(strlen(pid_filter) +
908 strlen(field_filter) +
909 strlen("(()||())") + 1);
910 sprintf(event_filter, "((%s)||(%s))",
911 pid_filter, field_filter);
912 }
913 write_filter(path, event_filter);
914 free(event_filter);
915}
916
917static void update_event_filters(const char *pid_filter)
918{
919 struct event_list *event;
920 char *event_filter;
921 int free_it;
922 int len;
923
924 len = strlen(pid_filter);
925 for (event = event_selection; event; event = event->next) {
926 if (!event->neg) {
927 free_it = 0;
928 if (event->filter) {
929 event_filter = malloc_or_die(len +
930 strlen(event->filter) + strlen("()&&()" + 1));
931 free_it = 1;
932 sprintf(event_filter, "(%s)&&(%s)",
933 pid_filter, event->filter);
934 } else
935 event_filter = (char *)pid_filter;
936 update_event(event, event_filter, 1, '1');
937 if (free_it)
938 free(event_filter);
939 }
940 }
941}
942
943static void update_pid_event_filters(const char *pid)
944{
945 char *pid_filter;
946 char *filter;
947
948 pid_filter = malloc_or_die(strlen(pid) + strlen("common_pid==") + 1);
949 sprintf(pid_filter, "common_pid==%s", pid);
950 update_event_filters(pid_filter);
951
952 /*
953 * Also make sure that the sched_switch to this pid
954 * and wakeups of this pid are also traced.
955 * Only need to do this if the events are active.
956 */
957 filter = malloc_or_die(strlen(pid) + strlen("next_pid==") + 1);
958 sprintf(filter, "next_pid==%s", pid);
959 update_sched_event(&sched_switch_event, "sched/sched_switch", pid_filter, filter);
960 free(filter);
961
962 filter = malloc_or_die(strlen(pid) + strlen("pid==") + 1);
963 sprintf(filter, "pid==%s", pid);
964 update_sched_event(&sched_wakeup_event, "sched/sched_wakeup",
965 pid_filter, filter);
966 update_sched_event(&sched_wakeup_new_event, "sched/sched_wakeup_new",
967 pid_filter, filter);
968 free(pid_filter);
969 free(filter);
970}
971
972static void enable_events(void)
973{
974 struct event_list *event;
975
976 for (event = event_selection; event; event = event->next) {
977 if (!event->neg)
978 update_event(event, event->filter, 0, '1');
979 }
980
981 /* Now disable any events */
982 for (event = event_selection; event; event = event->next) {
983 if (event->neg)
984 update_event(event, NULL, 0, '0');
985 }
986}
987
988static void test_event(struct event_list *event, const char *path,
989 const char *name, struct event_list **save, int len)
990{
991 path += len - strlen(name);
992
993 if (strcmp(path, name) != 0)
994 return;
995
996 *save = event;
997}
998
999static int expand_event_files(const char *file, struct event_list *old_event)
1000{
1001 struct event_list *save_events = event_selection;
1002 struct event_list *event;
1003 glob_t globbuf;
1004 struct stat st;
1005 char *path;
1006 char *p;
1007 int ret;
1008 int i;
1009
1010 p = malloc_or_die(strlen(file) + strlen("events//filter") + 1);
1011 sprintf(p, "events/%s/filter", file);
1012
1013 path = tracecmd_get_tracing_file(p);
1014 printf("%s\n", path);
1015
1016 globbuf.gl_offs = 0;
1017 ret = glob(path, 0, NULL, &globbuf);
1018 tracecmd_put_tracing_file(path);
1019 free(p);
1020
1021 if (ret < 0)
1022 die("No filters found");
1023
1024 for (i = 0; i < globbuf.gl_pathc; i++) {
1025 int len;
1026
1027 path = globbuf.gl_pathv[i];
1028
1029 event = malloc_or_die(sizeof(*event));
1030 *event = *old_event;
1031 event->next = event_selection;
1032 event_selection = event;
1033 if (event->filter || filter_task || filter_pid) {
1034 event->filter_file = strdup(path);
1035 if (!event->filter_file)
1036 die("malloc filter file");
1037 }
1038 for (p = path + strlen(path) - 1; p > path; p--)
1039 if (*p == '/')
1040 break;
1041 *p = '\0';
1042 p = malloc_or_die(strlen(path) + strlen("/enable") + 1);
1043 sprintf(p, "%s/enable", path);
1044 ret = stat(p, &st);
1045 if (ret >= 0)
1046 event->enable_file = p;
1047 else
1048 free(p);
1049
1050 len = strlen(path);
1051
1052 test_event(event, path, "sched/sched_switch", &sched_switch_event, len);
1053 test_event(event, path, "sched/sched_wakeup_new", &sched_wakeup_new_event, len);
1054 test_event(event, path, "sched/sched_wakeup", &sched_wakeup_event, len);
1055 test_event(event, path, "sched", &sched_event, len);
1056 }
1057 globfree(&globbuf);
1058
1059 return save_events == event_selection;
1060}
1061
1062static void expand_event(struct event_list *event)
1063{
1064 const char *name = event->event;
1065 char *str;
1066 char *ptr;
1067 int len;
1068 int ret;
1069 int ret2;
1070
1071 /*
1072 * We allow the user to use "all" to enable all events.
1073 * Expand event_selection to all systems.
1074 */
1075 if (strcmp(name, "all") == 0) {
1076 expand_event_files("*", event);
1077 return;
1078 }
1079
1080 ptr = strchr(name, ':');
1081
1082 if (ptr) {
1083 len = ptr - name;
1084 str = malloc_or_die(strlen(name) + 1); /* may add '*' */
1085 strcpy(str, name);
1086 str[len] = '/';
1087 ptr++;
1088 if (!strlen(ptr)) {
1089 str[len + 1] = '*';
1090 str[len + 2] = '\0';
1091 }
1092
1093 ret = expand_event_files(str, event);
1094 if (!ignore_event_not_found && ret)
1095 die("No events enabled with %s", name);
1096 free(str);
1097 return;
1098 }
1099
1100 /* No ':' so enable all matching systems and events */
1101 ret = expand_event_files(name, event);
1102
1103 len = strlen(name) + strlen("*/") + 1;
1104 str = malloc_or_die(len);
1105 snprintf(str, len, "*/%s", name);
1106 ret2 = expand_event_files(str, event);
1107 free(str);
1108
1109 if (!ignore_event_not_found && ret && ret2)
1110 die("No events enabled with %s", name);
1111
1112 return;
1113}
1114
1115static void expand_event_list(void)
1116{
1117 struct event_list *compressed_list = event_selection;
1118 struct event_list *event;
1119
1120 if (use_old_event_method())
1121 return;
1122
1123 event_selection = NULL;
1124
1125 while (compressed_list) {
1126 event = compressed_list;
1127 compressed_list = event->next;
1128 expand_event(event);
1129 free(event);
1130 }
1131}
1132
1133static int count_cpus(void)
1134{
1135 FILE *fp;
1136 char buf[1024];
1137 int cpus = 0;
1138 char *pbuf;
1139 size_t *pn;
1140 size_t n;
1141 int r;
1142
1143 cpus = sysconf(_SC_NPROCESSORS_ONLN);
1144 if (cpus > 0)
1145 return cpus;
1146
1147 warning("sysconf could not determine number of CPUS");
1148
1149 /* Do the hack to figure out # of CPUS */
1150 n = 1024;
1151 pn = &n;
1152 pbuf = buf;
1153
1154 fp = fopen("/proc/cpuinfo", "r");
1155 if (!fp)
1156 die("Can not read cpuinfo");
1157
1158 while ((r = getline(&pbuf, pn, fp)) >= 0) {
1159 char *p;
1160
1161 if (strncmp(buf, "processor", 9) != 0)
1162 continue;
1163 for (p = buf+9; isspace(*p); p++)
1164 ;
1165 if (*p == ':')
1166 cpus++;
1167 }
1168 fclose(fp);
1169
1170 return cpus;
1171}
1172
1173static void finish(int sig)
1174{
1175 /* all done */
1176 if (recorder)
1177 tracecmd_stop_recording(recorder);
1178 finished = 1;
1179}
1180
1181static void flush(int sig)
1182{
1183 if (recorder)
1184 tracecmd_stop_recording(recorder);
1185}
1186
1187static void connect_port(int cpu)
1188{
1189 struct addrinfo hints;
1190 struct addrinfo *results, *rp;
1191 int s;
1192 char buf[BUFSIZ];
1193
1194 snprintf(buf, BUFSIZ, "%d", client_ports[cpu]);
1195
1196 memset(&hints, 0, sizeof(hints));
1197 hints.ai_family = AF_UNSPEC;
1198 hints.ai_socktype = use_tcp ? SOCK_STREAM : SOCK_DGRAM;
1199
1200 s = getaddrinfo(host, buf, &hints, &results);
1201 if (s != 0)
1202 die("connecting to %s server %s:%s",
1203 use_tcp ? "TCP" : "UDP", host, buf);
1204
1205 for (rp = results; rp != NULL; rp = rp->ai_next) {
1206 sfd = socket(rp->ai_family, rp->ai_socktype,
1207 rp->ai_protocol);
1208 if (sfd == -1)
1209 continue;
1210 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
1211 break;
1212 close(sfd);
1213 }
1214
1215 if (rp == NULL)
1216 die("Can not connect to %s server %s:%s",
1217 use_tcp ? "TCP" : "UDP", host, buf);
1218
1219 freeaddrinfo(results);
1220
1221 client_ports[cpu] = sfd;
1222}
1223
1224static void set_prio(int prio)
1225{
1226 struct sched_param sp;
1227
1228 memset(&sp, 0, sizeof(sp));
1229 sp.sched_priority = prio;
1230 if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0)
1231 warning("failed to set priority");
1232}
1233
1234static int create_recorder(int cpu)
1235{
1236 char *file;
1237 int pid;
1238
1239 signal(SIGUSR1, flush);
1240
1241 pid = fork();
1242 if (pid < 0)
1243 die("fork");
1244
1245 if (pid)
1246 return pid;
1247
1248 if (rt_prio)
1249 set_prio(rt_prio);
1250
1251 /* do not kill tasks on error */
1252 cpu_count = 0;
1253
1254 if (client_ports) {
1255 connect_port(cpu);
1256 recorder = tracecmd_create_recorder_fd(client_ports[cpu], cpu);
1257 } else {
1258 file = get_temp_file(cpu);
1259 recorder = tracecmd_create_recorder(file, cpu);
1260 put_temp_file(file);
1261 }
1262
1263 if (!recorder)
1264 die ("can't create recorder");
1265 while (!finished) {
1266 if (tracecmd_start_recording(recorder, sleep_time) < 0)
1267 break;
1268 }
1269 tracecmd_free_recorder(recorder);
1270
1271 exit(0);
1272}
1273
1274static void setup_network(void)
1275{
1276 struct tracecmd_output *handle;
1277 struct addrinfo hints;
1278 struct addrinfo *result, *rp;
1279 int sfd, s;
1280 ssize_t n;
1281 char buf[BUFSIZ];
1282 char *server;
1283 char *port;
1284 char *p;
1285 int cpu;
1286 int i;
1287
1288 if (!strchr(host, ':')) {
1289 server = strdup("localhost");
1290 if (!server)
1291 die("alloctating server");
1292 port = host;
1293 host = server;
1294 } else {
1295 host = strdup(host);
1296 if (!host)
1297 die("alloctating server");
1298 server = strtok_r(host, ":", &p);
1299 port = strtok_r(NULL, ":", &p);
1300 }
1301
1302 memset(&hints, 0, sizeof(hints));
1303 hints.ai_family = AF_UNSPEC;
1304 hints.ai_socktype = SOCK_STREAM;
1305
1306 s = getaddrinfo(server, port, &hints, &result);
1307 if (s != 0)
1308 die("getaddrinfo: %s", gai_strerror(s));
1309
1310 for (rp = result; rp != NULL; rp = rp->ai_next) {
1311 sfd = socket(rp->ai_family, rp->ai_socktype,
1312 rp->ai_protocol);
1313 if (sfd == -1)
1314 continue;
1315
1316 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
1317 break;
1318 close(sfd);
1319 }
1320
1321 if (!rp)
1322 die("Can not connect to %s:%s", server, port);
1323
1324 freeaddrinfo(result);
1325
1326 n = read(sfd, buf, 8);
1327
1328 /* Make sure the server is the tracecmd server */
1329 if (memcmp(buf, "tracecmd", 8) != 0)
1330 die("server not tracecmd server");
1331
1332 /* write the number of CPUs we have (in ASCII) */
1333
1334 sprintf(buf, "%d", cpu_count);
1335
1336 /* include \0 */
1337 write(sfd, buf, strlen(buf)+1);
1338
1339 /* write the pagesize (in ASCII) */
1340
1341 page_size = getpagesize();
1342 sprintf(buf, "%d", page_size);
1343
1344 /* include \0 */
1345 write(sfd, buf, strlen(buf)+1);
1346
1347 /*
1348 * If we are using IPV4 and our page size is greater than
1349 * or equal to 64K, we need to punt and use TCP. :-(
1350 */
1351
1352 /* TODO, test for ipv4 */
1353 if (page_size >= UDP_MAX_PACKET) {
1354 warning("page size too big for UDP using TCP in live read");
1355 use_tcp = 1;
1356 }
1357
1358 if (use_tcp) {
1359 /* Send one option */
1360 write(sfd, "1", 2);
1361 /* Size 4 */
1362 write(sfd, "4", 2);
1363 /* use TCP */
1364 write(sfd, "TCP", 4);
1365 } else
1366 /* No options */
1367 write(sfd, "0", 2);
1368
1369 client_ports = malloc_or_die(sizeof(int) * cpu_count);
1370
1371 /*
1372 * Now we will receive back a comma deliminated list
1373 * of client ports to connect to.
1374 */
1375 for (cpu = 0; cpu < cpu_count; cpu++) {
1376 for (i = 0; i < BUFSIZ; i++) {
1377 n = read(sfd, buf+i, 1);
1378 if (n != 1)
1379 die("Error, reading server ports");
1380 if (!buf[i] || buf[i] == ',')
1381 break;
1382 }
1383 if (i == BUFSIZ)
1384 die("read bad port number");
1385 buf[i] = 0;
1386 client_ports[cpu] = atoi(buf);
1387 }
1388
1389 /* Now create the handle through this socket */
1390 handle = tracecmd_create_init_fd(sfd);
1391
1392 /* OK, we are all set, let'r rip! */
1393}
1394
1395static void finish_network(void)
1396{
1397 close(sfd);
1398 free(host);
1399}
1400
1401static void start_threads(void)
1402{
1403 int i;
1404
1405 cpu_count = count_cpus();
1406
1407 if (host)
1408 setup_network();
1409
1410 /* make a thread for every CPU we have */
1411 pids = malloc_or_die(sizeof(*pids) * cpu_count);
1412
1413 memset(pids, 0, sizeof(*pids) * cpu_count);
1414
1415 for (i = 0; i < cpu_count; i++) {
1416 pids[i] = create_recorder(i);
1417 }
1418}
1419
1420static void record_data(void)
1421{
1422 struct tracecmd_output *handle;
1423 char **temp_files;
1424 int i;
1425
1426 if (host) {
1427 finish_network();
1428 return;
1429 }
1430
1431 if (latency)
1432 handle = tracecmd_create_file_latency(output_file, cpu_count);
1433 else {
1434 if (!cpu_count)
1435 return;
1436
1437 temp_files = malloc_or_die(sizeof(*temp_files) * cpu_count);
1438
1439 for (i = 0; i < cpu_count; i++)
1440 temp_files[i] = get_temp_file(i);
1441
1442 handle = tracecmd_create_file_glob(output_file, cpu_count,
1443 temp_files, listed_events);
1444
1445 for (i = 0; i < cpu_count; i++)
1446 put_temp_file(temp_files[i]);
1447 free(temp_files);
1448 }
1449 if (!handle)
1450 die("could not write to file");
1451 tracecmd_output_close(handle);
1452}
1453
1454static int trace_empty(void)
1455{
1456 char *path;
1457 FILE *fp;
1458 char *line = NULL;
1459 size_t size;
1460 ssize_t n;
1461 int ret = 1;
1462
1463 /*
1464 * Test if the trace file is empty.
1465 *
1466 * Yes, this is a heck of a hack. What is done here
1467 * is to read the trace file and ignore the
1468 * lines starting with '#', and if we get a line
1469 * that is without a '#' the trace is not empty.
1470 * Otherwise it is.
1471 */
1472 path = tracecmd_get_tracing_file("trace");
1473 fp = fopen(path, "r");
1474 if (!fp)
1475 die("reading '%s'", path);
1476
1477 do {
1478 n = getline(&line, &size, fp);
1479 if (n > 0 && line && line[0] != '#') {
1480 ret = 0;
1481 break;
1482 }
1483 } while (line && n > 0);
1484
1485 tracecmd_put_tracing_file(path);
1486
1487 fclose(fp);
1488
1489 return ret;
1490}
1491
1492static void write_func_file(const char *file, struct func_list **list)
1493{
1494 struct func_list *item;
1495 char *path;
1496 int fd;
1497
1498 path = tracecmd_get_tracing_file(file);
1499
1500 fd = open(path, O_WRONLY | O_TRUNC);
1501 if (fd < 0)
1502 goto free;
1503
1504 while (*list) {
1505 item = *list;
1506 *list = item->next;
1507 write(fd, item->func, strlen(item->func));
1508 write(fd, " ", 1);
1509 free(item);
1510 }
1511 close(fd);
1512
1513 free:
1514 tracecmd_put_tracing_file(path);
1515}
1516
1517static void set_funcs(void)
1518{
1519 write_func_file("set_ftrace_filter", &filter_funcs);
1520 write_func_file("set_ftrace_notrace", &notrace_funcs);
1521 write_func_file("set_graph_function", &graph_funcs);
1522}
1523
1524static void add_func(struct func_list **list, const char *func)
1525{
1526 struct func_list *item;
1527
1528 item = malloc_or_die(sizeof(*item));
1529 item->func = func;
1530 item->next = *list;
1531 *list = item;
1532}
1533
1534void set_buffer_size(void)
1535{
1536 char buf[BUFSIZ];
1537 char *path;
1538 int ret;
1539 int fd;
1540
1541 if (!buffer_size)
1542 return;
1543
1544 if (buffer_size < 0)
1545 die("buffer size must be positive");
1546
1547 snprintf(buf, BUFSIZ, "%d", buffer_size);
1548
1549 path = tracecmd_get_tracing_file("buffer_size_kb");
1550 fd = open(path, O_WRONLY);
1551 if (fd < 0)
1552 die("can't open %s", path);
1553
1554 ret = write(fd, buf, strlen(buf));
1555 if (ret < 0)
1556 warning("Can't write to %s", path);
1557 close(fd);
1558}
1559
1560void trace_record (int argc, char **argv)
1561{
1562 const char *plugin = NULL;
1563 const char *output = NULL;
1564 const char *option;
1565 struct event_list *event;
1566 struct event_list *last_event;
1567 struct tracecmd_event_list *list;
1568 struct trace_seq s;
1569 int record_all = 0;
1570 int disable = 0;
1571 int events = 0;
1572 int record = 0;
1573 int extract = 0;
1574 int run_command = 0;
1575 int neg_event = 0;
1576 int keep = 0;
1577 int fset;
1578 int cpu;
1579
1580 int c;
1581
1582 if ((record = (strcmp(argv[1], "record") == 0)))
1583 ; /* do nothing */
1584 else if (strcmp(argv[1], "start") == 0)
1585 ; /* do nothing */
1586 else if ((extract = strcmp(argv[1], "extract") == 0))
1587 ; /* do nothing */
1588 else if (strcmp(argv[1], "stop") == 0) {
1589 disable_tracing();
1590 exit(0);
1591 } else if (strcmp(argv[1], "reset") == 0) {
1592 while ((c = getopt(argc-1, argv+1, "b:")) >= 0) {
1593 switch (c) {
1594 case 'b':
1595 buffer_size = atoi(optarg);
1596 /* Min buffer size is 1 */
1597 if (strcmp(optarg, "0") == 0)
1598 buffer_size = 1;
1599 break;
1600 }
1601 }
1602 disable_all();
1603 set_buffer_size();
1604 exit(0);
1605 } else
1606 usage(argv);
1607
1608 while ((c = getopt(argc-1, argv+1, "+hae:f:Fp:cdo:O:s:r:vg:l:n:P:N:tb:ki")) >= 0) {
1609 switch (c) {
1610 case 'h':
1611 usage(argv);
1612 break;
1613 case 'a':
1614 record_all = 1;
1615 while (listed_events) {
1616 list = listed_events;
1617 listed_events = list->next;
1618 free(list);
1619 }
1620 list = malloc_or_die(sizeof(*list));
1621 list->next = NULL;
1622 list->glob = "*/*";
1623 listed_events = list;
1624
1625 break;
1626 case 'e':
1627 if (extract)
1628 usage(argv);
1629 events = 1;
1630 event = malloc_or_die(sizeof(*event));
1631 memset(event, 0, sizeof(*event));
1632 event->event = optarg;
1633 event->next = event_selection;
1634 event->neg = neg_event;
1635 event_selection = event;
1636 event->filter = NULL;
1637 last_event = event;
1638
1639 if (!record_all) {
1640 list = malloc_or_die(sizeof(*list));
1641 list->next = listed_events;
1642 list->glob = optarg;
1643 listed_events = list;
1644 }
1645
1646 break;
1647 case 'f':
1648 if (!last_event)
1649 die("filter must come after event");
1650 if (last_event->filter) {
1651 last_event->filter =
1652 realloc(last_event->filter,
1653 strlen(last_event->filter) +
1654 strlen("&&()") +
1655 strlen(optarg) + 1);
1656 strcat(last_event->filter, "&&(");
1657 strcat(last_event->filter, optarg);
1658 strcat(last_event->filter, ")");
1659 } else {
1660 last_event->filter =
1661 malloc_or_die(strlen(optarg) +
1662 strlen("()") + 1);
1663 sprintf(last_event->filter, "(%s)", optarg);
1664 }
1665 break;
1666
1667 case 'F':
1668 if (filter_pid >= 0)
1669 die("-P and -F can not both be specified");
1670 filter_task = 1;
1671 break;
1672 case 'P':
1673 if (filter_task)
1674 die("-P and -F can not both be specified");
1675 if (filter_pid >= 0)
1676 die("only one -P pid can be filtered at a time");
1677 filter_pid = atoi(optarg);
1678 break;
1679 case 'c':
1680 do_ptrace = 1;
1681 break;
1682 case 'v':
1683 if (extract)
1684 usage(argv);
1685 neg_event = 1;
1686 break;
1687 case 'l':
1688 add_func(&filter_funcs, optarg);
1689 break;
1690 case 'n':
1691 add_func(&notrace_funcs, optarg);
1692 break;
1693 case 'g':
1694 add_func(&graph_funcs, optarg);
1695 break;
1696 case 'p':
1697 if (plugin)
1698 die("only one plugin allowed");
1699 plugin = optarg;
1700 fprintf(stderr, " plugin %s\n", plugin);
1701 break;
1702 case 'd':
1703 if (extract)
1704 usage(argv);
1705 disable = 1;
1706 break;
1707 case 'o':
1708 if (host)
1709 die("-o incompatible with -N");
1710 if (!record && !extract)
1711 die("start does not take output\n"
1712 "Did you mean 'record'?");
1713 if (output)
1714 die("only one output file allowed");
1715 output = optarg;
1716 break;
1717 case 'O':
1718 option = optarg;
1719 save_option(option);
1720 break;
1721 case 's':
1722 if (extract)
1723 usage(argv);
1724 sleep_time = atoi(optarg);
1725 break;
1726 case 'r':
1727 rt_prio = atoi(optarg);
1728 break;
1729 case 'N':
1730 if (!record)
1731 die("-N only available with record");
1732 if (output)
1733 die("-N incompatible with -o");
1734 host = optarg;
1735 break;
1736 case 't':
1737 use_tcp = 1;
1738 break;
1739 case 'b':
1740 buffer_size = atoi(optarg);
1741 break;
1742 case 'k':
1743 keep = 1;
1744 break;
1745 case 'i':
1746 ignore_event_not_found = 1;
1747 break;
1748 }
1749 }
1750
1751 if (do_ptrace && !filter_task && (filter_pid < 0))
1752 die(" -c can only be used with -F or -P");
1753
1754 if ((argc - optind) >= 2) {
1755 if (!record)
1756 die("Command start does not take any commands\n"
1757 "Did you mean 'record'?");
1758 if (extract)
1759 die("Command extract does not take any commands\n"
1760 "Did you mean 'record'?");
1761 run_command = 1;
1762 }
1763
1764 if (!events && !plugin && !extract)
1765 die("no event or plugin was specified... aborting");
1766
1767 if (output)
1768 output_file = output;
1769
1770 tracing_on_init_val = read_tracing_on();
1771
1772 if (event_selection)
1773 expand_event_list();
1774
1775 if (!extract) {
1776 fset = set_ftrace(!disable);
1777 disable_all();
1778 set_funcs();
1779
1780 if (events)
1781 enable_events();
1782 set_buffer_size();
1783 }
1784
1785 if (plugin) {
1786 /*
1787 * Latency tracers just save the trace and kill
1788 * the threads.
1789 */
1790 if (strcmp(plugin, "irqsoff") == 0 ||
1791 strcmp(plugin, "preemptoff") == 0 ||
1792 strcmp(plugin, "preemptirqsoff") == 0 ||
1793 strcmp(plugin, "wakeup") == 0 ||
1794 strcmp(plugin, "wakeup_rt") == 0) {
1795 latency = 1;
1796 if (host)
1797 die("Network tracing not available with latency tracer plugins");
1798 }
1799 if (fset < 0 && (strcmp(plugin, "function") == 0 ||
1800 strcmp(plugin, "function_graph") == 0))
1801 die("function tracing not configured on this kernel");
1802 if (!extract)
1803 set_plugin(plugin);
1804 }
1805
1806 set_options();
1807
1808 if (record || extract) {
1809 signal(SIGINT, finish);
1810 if (!latency)
1811 start_threads();
1812 }
1813
1814 if (extract) {
1815 while (!finished && !trace_empty()) {
1816 flush_threads();
1817 sleep(1);
1818 }
1819 } else {
1820 if (!record) {
1821 update_task_filter();
1822 exit(0);
1823 }
1824
1825 if (run_command)
1826 run_cmd((argc - optind) - 1, &argv[optind + 1]);
1827 else {
1828 update_task_filter();
1829 /* We don't ptrace ourself */
1830 if (do_ptrace && filter_pid >= 0)
1831 ptrace_attach(filter_pid);
1832 /* sleep till we are woken with Ctrl^C */
1833 printf("Hit Ctrl^C to stop recording\n");
1834 while (!finished)
1835 trace_or_sleep();
1836 }
1837
1838 disable_tracing();
1839 }
1840
1841 stop_threads();
1842
1843 record_data();
1844 delete_thread_data();
1845
1846 printf("Kernel buffer statistics:\n"
1847 " Note: \"entries\" are the entries left in the kernel ring buffer and are not\n"
1848 " recorded in the trace data. They should all be zero.\n\n");
1849 for (cpu = 0; cpu < cpu_count; cpu++) {
1850 trace_seq_init(&s);
1851 trace_seq_printf(&s, "CPU: %d\n", cpu);
1852 tracecmd_stat_cpu(&s, cpu);
1853 trace_seq_do_printf(&s);
1854 trace_seq_destroy(&s);
1855 printf("\n");
1856 }
1857
1858 if (keep)
1859 exit(0);
1860
1861 /* Turn off everything */
1862 disable_all();
1863
1864 /* If tracing_on was enabled before we started, set it on now */
1865 if (tracing_on_init_val)
1866 write_tracing_on(tracing_on_init_val);
1867
1868 exit(0);
1869}