1 /* 2 * trace context switch 3 * 4 * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com> 5 * 6 */ 7 #include <linux/module.h> 8 #include <linux/kallsyms.h> 9 #include <linux/uaccess.h> 10 #include <linux/ftrace.h> 11 #include <trace/events/sched.h> 12 13 #include "trace.h" 14 15 #define RECORD_CMDLINE 1 16 #define RECORD_TGID 2 17 18 static int sched_cmdline_ref; 19 static int sched_tgid_ref; 20 static DEFINE_MUTEX(sched_register_mutex); 21 22 static void 23 probe_sched_switch(void *ignore, bool preempt, 24 struct task_struct *prev, struct task_struct *next) 25 { 26 int flags; 27 28 flags = (RECORD_TGID * !!sched_tgid_ref) + 29 (RECORD_CMDLINE * !!sched_cmdline_ref); 30 31 if (!flags) 32 return; 33 tracing_record_taskinfo_sched_switch(prev, next, flags); 34 } 35 36 static void 37 probe_sched_wakeup(void *ignore, struct task_struct *wakee) 38 { 39 int flags; 40 41 flags = (RECORD_TGID * !!sched_tgid_ref) + 42 (RECORD_CMDLINE * !!sched_cmdline_ref); 43 44 if (!flags) 45 return; 46 tracing_record_taskinfo(current, flags); 47 } 48 49 static int tracing_sched_register(void) 50 { 51 int ret; 52 53 ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL); 54 if (ret) { 55 pr_info("wakeup trace: Couldn't activate tracepoint" 56 " probe to kernel_sched_wakeup\n"); 57 return ret; 58 } 59 60 ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL); 61 if (ret) { 62 pr_info("wakeup trace: Couldn't activate tracepoint" 63 " probe to kernel_sched_wakeup_new\n"); 64 goto fail_deprobe; 65 } 66 67 ret = register_trace_sched_switch(probe_sched_switch, NULL); 68 if (ret) { 69 pr_info("sched trace: Couldn't activate tracepoint" 70 " probe to kernel_sched_switch\n"); 71 goto fail_deprobe_wake_new; 72 } 73 74 return ret; 75 fail_deprobe_wake_new: 76 unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL); 77 fail_deprobe: 78 unregister_trace_sched_wakeup(probe_sched_wakeup, NULL); 79 return ret; 80 } 81 82 static void tracing_sched_unregister(void) 83 { 84 unregister_trace_sched_switch(probe_sched_switch, NULL); 85 unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL); 86 unregister_trace_sched_wakeup(probe_sched_wakeup, NULL); 87 } 88 89 static void tracing_start_sched_switch(int ops) 90 { 91 bool sched_register = (!sched_cmdline_ref && !sched_tgid_ref); 92 mutex_lock(&sched_register_mutex); 93 94 switch (ops) { 95 case RECORD_CMDLINE: 96 sched_cmdline_ref++; 97 break; 98 99 case RECORD_TGID: 100 sched_tgid_ref++; 101 break; 102 } 103 104 if (sched_register && (sched_cmdline_ref || sched_tgid_ref)) 105 tracing_sched_register(); 106 mutex_unlock(&sched_register_mutex); 107 } 108 109 static void tracing_stop_sched_switch(int ops) 110 { 111 mutex_lock(&sched_register_mutex); 112 113 switch (ops) { 114 case RECORD_CMDLINE: 115 sched_cmdline_ref--; 116 break; 117 118 case RECORD_TGID: 119 sched_tgid_ref--; 120 break; 121 } 122 123 if (!sched_cmdline_ref && !sched_tgid_ref) 124 tracing_sched_unregister(); 125 mutex_unlock(&sched_register_mutex); 126 } 127 128 void tracing_start_cmdline_record(void) 129 { 130 tracing_start_sched_switch(RECORD_CMDLINE); 131 } 132 133 void tracing_stop_cmdline_record(void) 134 { 135 tracing_stop_sched_switch(RECORD_CMDLINE); 136 } 137 138 void tracing_start_tgid_record(void) 139 { 140 tracing_start_sched_switch(RECORD_TGID); 141 } 142 143 void tracing_stop_tgid_record(void) 144 { 145 tracing_stop_sched_switch(RECORD_TGID); 146 } 147