135e8e302SSteven Rostedt /*
235e8e302SSteven Rostedt  * trace context switch
335e8e302SSteven Rostedt  *
435e8e302SSteven Rostedt  * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
535e8e302SSteven Rostedt  *
635e8e302SSteven Rostedt  */
735e8e302SSteven Rostedt #include <linux/module.h>
835e8e302SSteven Rostedt #include <linux/kallsyms.h>
935e8e302SSteven Rostedt #include <linux/uaccess.h>
1035e8e302SSteven Rostedt #include <linux/ftrace.h>
11ad8d75ffSSteven Rostedt #include <trace/events/sched.h>
1235e8e302SSteven Rostedt 
1335e8e302SSteven Rostedt #include "trace.h"
1435e8e302SSteven Rostedt 
15d914ba37SJoel Fernandes #define RECORD_CMDLINE	1
16d914ba37SJoel Fernandes #define RECORD_TGID	2
17d914ba37SJoel Fernandes 
18d914ba37SJoel Fernandes static int		sched_cmdline_ref;
19d914ba37SJoel Fernandes static int		sched_tgid_ref;
20efade6e7SFrederic Weisbecker static DEFINE_MUTEX(sched_register_mutex);
2182e04af4SFrederic Weisbecker 
22e309b41dSIngo Molnar static void
23c73464b1SPeter Zijlstra probe_sched_switch(void *ignore, bool preempt,
24c73464b1SPeter Zijlstra 		   struct task_struct *prev, struct task_struct *next)
2535e8e302SSteven Rostedt {
26d914ba37SJoel Fernandes 	int flags;
27b07c3f19SMathieu Desnoyers 
28d914ba37SJoel Fernandes 	flags = (RECORD_TGID * !!sched_tgid_ref) +
29d914ba37SJoel Fernandes 		(RECORD_CMDLINE * !!sched_cmdline_ref);
30d914ba37SJoel Fernandes 
31d914ba37SJoel Fernandes 	if (!flags)
32d914ba37SJoel Fernandes 		return;
33d914ba37SJoel Fernandes 	tracing_record_taskinfo_sched_switch(prev, next, flags);
3435e8e302SSteven Rostedt }
3535e8e302SSteven Rostedt 
365b82a1b0SMathieu Desnoyers static void
37fbd705a0SPeter Zijlstra probe_sched_wakeup(void *ignore, struct task_struct *wakee)
385b82a1b0SMathieu Desnoyers {
39d914ba37SJoel Fernandes 	int flags;
40dcef788eSZhaolei 
41d914ba37SJoel Fernandes 	flags = (RECORD_TGID * !!sched_tgid_ref) +
42d914ba37SJoel Fernandes 		(RECORD_CMDLINE * !!sched_cmdline_ref);
43d914ba37SJoel Fernandes 
44d914ba37SJoel Fernandes 	if (!flags)
45d914ba37SJoel Fernandes 		return;
46d914ba37SJoel Fernandes 	tracing_record_taskinfo(current, flags);
4757422797SIngo Molnar }
4857422797SIngo Molnar 
495b82a1b0SMathieu Desnoyers static int tracing_sched_register(void)
505b82a1b0SMathieu Desnoyers {
515b82a1b0SMathieu Desnoyers 	int ret;
525b82a1b0SMathieu Desnoyers 
5338516ab5SSteven Rostedt 	ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL);
545b82a1b0SMathieu Desnoyers 	if (ret) {
55b07c3f19SMathieu Desnoyers 		pr_info("wakeup trace: Couldn't activate tracepoint"
565b82a1b0SMathieu Desnoyers 			" probe to kernel_sched_wakeup\n");
575b82a1b0SMathieu Desnoyers 		return ret;
585b82a1b0SMathieu Desnoyers 	}
595b82a1b0SMathieu Desnoyers 
6038516ab5SSteven Rostedt 	ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
615b82a1b0SMathieu Desnoyers 	if (ret) {
62b07c3f19SMathieu Desnoyers 		pr_info("wakeup trace: Couldn't activate tracepoint"
635b82a1b0SMathieu Desnoyers 			" probe to kernel_sched_wakeup_new\n");
645b82a1b0SMathieu Desnoyers 		goto fail_deprobe;
655b82a1b0SMathieu Desnoyers 	}
665b82a1b0SMathieu Desnoyers 
6738516ab5SSteven Rostedt 	ret = register_trace_sched_switch(probe_sched_switch, NULL);
685b82a1b0SMathieu Desnoyers 	if (ret) {
69b07c3f19SMathieu Desnoyers 		pr_info("sched trace: Couldn't activate tracepoint"
7073d8b8bcSWenji Huang 			" probe to kernel_sched_switch\n");
715b82a1b0SMathieu Desnoyers 		goto fail_deprobe_wake_new;
725b82a1b0SMathieu Desnoyers 	}
735b82a1b0SMathieu Desnoyers 
745b82a1b0SMathieu Desnoyers 	return ret;
755b82a1b0SMathieu Desnoyers fail_deprobe_wake_new:
7638516ab5SSteven Rostedt 	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
775b82a1b0SMathieu Desnoyers fail_deprobe:
7838516ab5SSteven Rostedt 	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
795b82a1b0SMathieu Desnoyers 	return ret;
805b82a1b0SMathieu Desnoyers }
815b82a1b0SMathieu Desnoyers 
825b82a1b0SMathieu Desnoyers static void tracing_sched_unregister(void)
835b82a1b0SMathieu Desnoyers {
8438516ab5SSteven Rostedt 	unregister_trace_sched_switch(probe_sched_switch, NULL);
8538516ab5SSteven Rostedt 	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
8638516ab5SSteven Rostedt 	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
875b82a1b0SMathieu Desnoyers }
885b82a1b0SMathieu Desnoyers 
89d914ba37SJoel Fernandes static void tracing_start_sched_switch(int ops)
905b82a1b0SMathieu Desnoyers {
91d914ba37SJoel Fernandes 	bool sched_register = (!sched_cmdline_ref && !sched_tgid_ref);
92efade6e7SFrederic Weisbecker 	mutex_lock(&sched_register_mutex);
93d914ba37SJoel Fernandes 
94d914ba37SJoel Fernandes 	switch (ops) {
95d914ba37SJoel Fernandes 	case RECORD_CMDLINE:
96d914ba37SJoel Fernandes 		sched_cmdline_ref++;
97d914ba37SJoel Fernandes 		break;
98d914ba37SJoel Fernandes 
99d914ba37SJoel Fernandes 	case RECORD_TGID:
100d914ba37SJoel Fernandes 		sched_tgid_ref++;
101d914ba37SJoel Fernandes 		break;
102d914ba37SJoel Fernandes 	}
103d914ba37SJoel Fernandes 
104d914ba37SJoel Fernandes 	if (sched_register && (sched_cmdline_ref || sched_tgid_ref))
1055b82a1b0SMathieu Desnoyers 		tracing_sched_register();
106efade6e7SFrederic Weisbecker 	mutex_unlock(&sched_register_mutex);
1075b82a1b0SMathieu Desnoyers }
1085b82a1b0SMathieu Desnoyers 
109d914ba37SJoel Fernandes static void tracing_stop_sched_switch(int ops)
1105b82a1b0SMathieu Desnoyers {
111efade6e7SFrederic Weisbecker 	mutex_lock(&sched_register_mutex);
112d914ba37SJoel Fernandes 
113d914ba37SJoel Fernandes 	switch (ops) {
114d914ba37SJoel Fernandes 	case RECORD_CMDLINE:
115d914ba37SJoel Fernandes 		sched_cmdline_ref--;
116d914ba37SJoel Fernandes 		break;
117d914ba37SJoel Fernandes 
118d914ba37SJoel Fernandes 	case RECORD_TGID:
119d914ba37SJoel Fernandes 		sched_tgid_ref--;
120d914ba37SJoel Fernandes 		break;
121d914ba37SJoel Fernandes 	}
122d914ba37SJoel Fernandes 
123d914ba37SJoel Fernandes 	if (!sched_cmdline_ref && !sched_tgid_ref)
1245b82a1b0SMathieu Desnoyers 		tracing_sched_unregister();
125efade6e7SFrederic Weisbecker 	mutex_unlock(&sched_register_mutex);
1265b82a1b0SMathieu Desnoyers }
1275b82a1b0SMathieu Desnoyers 
12841bc8144SSteven Rostedt void tracing_start_cmdline_record(void)
12941bc8144SSteven Rostedt {
130d914ba37SJoel Fernandes 	tracing_start_sched_switch(RECORD_CMDLINE);
13141bc8144SSteven Rostedt }
13241bc8144SSteven Rostedt 
13341bc8144SSteven Rostedt void tracing_stop_cmdline_record(void)
13441bc8144SSteven Rostedt {
135d914ba37SJoel Fernandes 	tracing_stop_sched_switch(RECORD_CMDLINE);
136d914ba37SJoel Fernandes }
137d914ba37SJoel Fernandes 
138d914ba37SJoel Fernandes void tracing_start_tgid_record(void)
139d914ba37SJoel Fernandes {
140d914ba37SJoel Fernandes 	tracing_start_sched_switch(RECORD_TGID);
141d914ba37SJoel Fernandes }
142d914ba37SJoel Fernandes 
143d914ba37SJoel Fernandes void tracing_stop_tgid_record(void)
144d914ba37SJoel Fernandes {
145d914ba37SJoel Fernandes 	tracing_stop_sched_switch(RECORD_TGID);
14641bc8144SSteven Rostedt }
147