gator: ARM DS-5.3 Streamline gator driver
[android-sdk/arm-ds5-gator.git] / gator_trace_sched.c
1 /**
2  * Copyright (C) ARM Limited 2010. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  */
10 #include <linux/slab.h>
11 #include <linux/fs.h>
12 #include <linux/mm.h>
13 #include <linux/version.h>
14 #include <linux/hardirq.h>
15 #include <trace/events/sched.h>
17 #include "gator_trace.h"
19 #define SCHED_TIMER_EVENT               0
20 #define SCHED_WAIT_TASK                 1
21 #define SCHED_WAKEUP                    2
22 #define SCHED_WAKEUP_NEW                3
23 #define SCHED_SWITCH                    4
24 #define SCHED_MIGRATE_TASK              5
25 #define SCHED_PROCESS_FREE              6
26 #define SCHED_PROCESS_EXIT              7
27 #define SCHED_PROCESS_WAIT              8
28 #define SCHED_PROCESS_FORK              9
29 #define SCHED_OVERFLOW                  -1
31 #define SCHEDSIZE                               (16*1024)
33 static DEFINE_PER_CPU(int *[2], theSchedBuf);
34 static DEFINE_PER_CPU(int, theSchedSel);
35 static DEFINE_PER_CPU(int, theSchedPos);
36 static DEFINE_PER_CPU(int, theSchedErr);
38 static void probe_sched_write(int type, int param1, int param2, int param3)
39 {
40         unsigned long flags;
41         int cpu = smp_processor_id();
42         uint64_t time = gator_get_time();
43         int *schedBuf;
44         int schedPos;
46         if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
47                 return;
49         // disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used
50         local_irq_save(flags);
52         schedPos = per_cpu(theSchedPos, cpu);
53         schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
55         if (schedPos < (SCHEDSIZE-100)) {
56                 // capture
57                 schedBuf[schedPos+0] = type;
58                 schedBuf[schedPos+1] = (int)time;
59                 schedBuf[schedPos+2] = (int)(time >> 32);
60                 schedBuf[schedPos+3] = param1;
61                 schedBuf[schedPos+4] = param2;
62                 schedBuf[schedPos+5] = param3;
63                 per_cpu(theSchedPos, cpu) = schedPos + 6;
64         } else if (!per_cpu(theSchedErr, cpu)) {
65                 per_cpu(theSchedErr, cpu) = 1;
66                 schedBuf[schedPos+0] = SCHED_OVERFLOW;
67                 schedBuf[schedPos+1] = 0;
68                 schedBuf[schedPos+2] = 0;
69                 schedBuf[schedPos+3] = 0;
70                 schedBuf[schedPos+4] = 0;
71                 schedBuf[schedPos+5] = 0;
72                 per_cpu(theSchedPos, cpu) = schedPos + 6;
73                 pr_debug("gator: tracepoint overflow\n");
74         }
75         local_irq_restore(flags);
76 }
78 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
79 GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct rq *rq, struct task_struct *p))
80 #else
81 GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct task_struct *p))
82 #endif
83 {
84         probe_sched_write(SCHED_WAIT_TASK, 0, p->pid, 0);
85 }
87 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
88 GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
89 #else
90 GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct task_struct *p, int success))
91 #endif
92 {
93         if (success)
94                 probe_sched_write(SCHED_WAKEUP, 0, p->pid, 0);
95 }
97 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
98 GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
99 #else
100 GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct task_struct *p, int success))
101 #endif
103         if (success)
104                 probe_sched_write(SCHED_WAKEUP_NEW, 0, p->tgid, p->pid);
107 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
108 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
109 #else
110 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
111 #endif
113         probe_sched_write(SCHED_SWITCH, (int)next, next->tgid, next->pid);
116 GATOR_DEFINE_PROBE(sched_migrate_task, TP_PROTO(struct task_struct *p, int dest_cpu))
118         probe_sched_write(SCHED_MIGRATE_TASK, 0, dest_cpu, p->pid);
121 GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
123         probe_sched_write(SCHED_PROCESS_FREE, 0, p->pid, 0);
126 GATOR_DEFINE_PROBE(sched_process_exit, TP_PROTO(struct task_struct *p))
128         probe_sched_write(SCHED_PROCESS_EXIT, 0, p->pid, 0);
131 GATOR_DEFINE_PROBE(sched_process_wait, TP_PROTO(struct pid *pid))
133         probe_sched_write(SCHED_PROCESS_WAIT, 0, pid_nr(pid), 0);
136 GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child))
138         probe_sched_write(SCHED_PROCESS_FORK, (int)child, parent->pid, child->pid);
141 int gator_trace_sched_init(void)
143         return 0;
146 int gator_trace_sched_start(void)
148         int cpu;
150         for_each_possible_cpu(cpu) {
151                 per_cpu(theSchedSel, cpu) = 0;
152                 per_cpu(theSchedPos, cpu) = 0;
153                 per_cpu(theSchedErr, cpu) = 0;
154                 per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
155                 per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
156                 if (!per_cpu(theSchedBuf, cpu))
157                         return -1;
158         }
160         // register tracepoints
161         if (GATOR_REGISTER_TRACE(sched_wait_task))
162                 goto fail_sched_wait_task;
163         if (GATOR_REGISTER_TRACE(sched_wakeup))
164                 goto fail_sched_wakeup;
165         if (GATOR_REGISTER_TRACE(sched_wakeup_new))
166                 goto fail_sched_wakeup_new;
167         if (GATOR_REGISTER_TRACE(sched_switch))
168                 goto fail_sched_switch;
169         if (GATOR_REGISTER_TRACE(sched_migrate_task))
170                 goto fail_sched_migrate_task;
171         if (GATOR_REGISTER_TRACE(sched_process_free))
172                 goto fail_sched_process_free;
173         if (GATOR_REGISTER_TRACE(sched_process_exit))
174                 goto fail_sched_process_exit;
175         if (GATOR_REGISTER_TRACE(sched_process_wait))
176                 goto fail_sched_process_wait;
177         if (GATOR_REGISTER_TRACE(sched_process_fork))
178                 goto fail_sched_process_fork;
179         pr_debug("gator: registered tracepoints\n");
181         return 0;
183         // unregister tracepoints on error
184 fail_sched_process_fork:
185         GATOR_UNREGISTER_TRACE(sched_process_wait);
186 fail_sched_process_wait:
187         GATOR_UNREGISTER_TRACE(sched_process_exit);
188 fail_sched_process_exit:
189         GATOR_UNREGISTER_TRACE(sched_process_free);
190 fail_sched_process_free:
191         GATOR_UNREGISTER_TRACE(sched_migrate_task);
192 fail_sched_migrate_task:
193         GATOR_UNREGISTER_TRACE(sched_switch);
194 fail_sched_switch:
195         GATOR_UNREGISTER_TRACE(sched_wakeup_new);
196 fail_sched_wakeup_new:
197         GATOR_UNREGISTER_TRACE(sched_wakeup);
198 fail_sched_wakeup:
199         GATOR_UNREGISTER_TRACE(sched_wait_task);
200 fail_sched_wait_task:
201         pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
203         return -1;
206 void gator_trace_sched_stop(void)
208         int cpu;
209         GATOR_UNREGISTER_TRACE(sched_wait_task);
210         GATOR_UNREGISTER_TRACE(sched_wakeup);
211         GATOR_UNREGISTER_TRACE(sched_wakeup_new);
212         GATOR_UNREGISTER_TRACE(sched_switch);
213         GATOR_UNREGISTER_TRACE(sched_migrate_task);
214         GATOR_UNREGISTER_TRACE(sched_process_free);
215         GATOR_UNREGISTER_TRACE(sched_process_exit);
216         GATOR_UNREGISTER_TRACE(sched_process_wait);
217         GATOR_UNREGISTER_TRACE(sched_process_fork);
218         pr_debug("gator: unregistered tracepoints\n");
220         for_each_possible_cpu(cpu) {
221                 kfree(per_cpu(theSchedBuf, cpu)[0]);
222                 kfree(per_cpu(theSchedBuf, cpu)[1]);
223                 per_cpu(theSchedBuf, cpu)[0] = NULL;
224                 per_cpu(theSchedBuf, cpu)[1] = NULL;
225         }
228 int gator_trace_sched_read(int **buffer)
230         uint64_t time = gator_get_time();
231         int cpu = smp_processor_id();
232         unsigned long flags;
233         int *schedBuf;
234         int schedPos;
235         int i;
237         if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
238                 return 0;
240         local_irq_save(flags);
242         schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
243         schedPos = per_cpu(theSchedPos, cpu);
245         per_cpu(theSchedSel, cpu) = !per_cpu(theSchedSel, cpu);
246         per_cpu(theSchedPos, cpu) = 0;
247         per_cpu(theSchedErr, cpu) = 0;
249         local_irq_restore(flags);
251         // find mm and replace with cookies
252         for (i = 0; i < schedPos; i += 6) {
253                 uint32_t cookie = schedBuf[i+3];
254                 if (cookie) {
255                         struct task_struct *task = (struct task_struct *)cookie;
256                         schedBuf[i+3] = get_exec_cookie(cpu, task);
257                 }
258         }
260         // timer/end event
261         schedBuf[schedPos++] = SCHED_TIMER_EVENT;
262         schedBuf[schedPos++] = (int)time;
263         schedBuf[schedPos++] = (int)(time >> 32);
265         if (buffer)
266                 *buffer = schedBuf;
268         return schedPos;