gator: ARM DS-5.6 Streamline gator driver
[android-sdk/arm-ds5-gator.git] / gator_trace_sched.c
1 /**
2  * Copyright (C) ARM Limited 2010-2011. 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 <trace/events/sched.h>
11 #include "gator.h"
13 #define SCHED_TIMER_EVENT               0
14 #define SCHED_WAIT_TASK                 1
15 #define SCHED_WAKEUP                    2
16 #define SCHED_WAKEUP_NEW                3
17 #define SCHED_SWITCH                    4
18 #define SCHED_MIGRATE_TASK              5
19 #define SCHED_PROCESS_FREE              6
20 #define SCHED_PROCESS_EXIT              7
21 #define SCHED_PROCESS_WAIT              8
22 #define SCHED_PROCESS_FORK              9
23 #define SCHED_OVERFLOW                  -1
25 #define SCHEDSIZE                               (16*1024)
27 static DEFINE_PER_CPU(int *[2], theSchedBuf);
28 static DEFINE_PER_CPU(int, theSchedSel);
29 static DEFINE_PER_CPU(int, theSchedPos);
30 static DEFINE_PER_CPU(int, theSchedErr);
32 static void probe_sched_write(int type, int param1, int param2, int param3)
33 {
34         unsigned long flags;
35         int cpu = smp_processor_id();
36         uint64_t time = gator_get_time();
37         int *schedBuf;
38         int schedPos;
40         if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
41                 return;
43         // disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used
44         local_irq_save(flags);
46         schedPos = per_cpu(theSchedPos, cpu);
47         schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
49         if (schedPos < (SCHEDSIZE-100)) {
50                 // capture
51                 schedBuf[schedPos+0] = type;
52                 schedBuf[schedPos+1] = (int)time;
53                 schedBuf[schedPos+2] = (int)(time >> 32);
54                 schedBuf[schedPos+3] = param1;
55                 schedBuf[schedPos+4] = param2;
56                 schedBuf[schedPos+5] = param3;
57                 per_cpu(theSchedPos, cpu) = schedPos + 6;
58         } else if (!per_cpu(theSchedErr, cpu)) {
59                 per_cpu(theSchedErr, cpu) = 1;
60                 schedBuf[schedPos+0] = SCHED_OVERFLOW;
61                 schedBuf[schedPos+1] = 0;
62                 schedBuf[schedPos+2] = 0;
63                 schedBuf[schedPos+3] = 0;
64                 schedBuf[schedPos+4] = 0;
65                 schedBuf[schedPos+5] = 0;
66                 per_cpu(theSchedPos, cpu) = schedPos + 6;
67                 pr_debug("gator: tracepoint overflow\n");
68         }
69         local_irq_restore(flags);
70 }
72 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
73 GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct rq *rq, struct task_struct *p))
74 #else
75 GATOR_DEFINE_PROBE(sched_wait_task, TP_PROTO(struct task_struct *p))
76 #endif
77 {
78         probe_sched_write(SCHED_WAIT_TASK, 0, p->pid, 0);
79 }
81 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
82 GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
83 #else
84 GATOR_DEFINE_PROBE(sched_wakeup, TP_PROTO(struct task_struct *p, int success))
85 #endif
86 {
87         if (success)
88                 probe_sched_write(SCHED_WAKEUP, 0, p->pid, 0);
89 }
91 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
92 GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct rq *rq, struct task_struct *p, int success))
93 #else
94 GATOR_DEFINE_PROBE(sched_wakeup_new, TP_PROTO(struct task_struct *p, int success))
95 #endif
96 {
97         if (success)
98                 probe_sched_write(SCHED_WAKEUP_NEW, 0, p->tgid, p->pid);
99 }
101 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
102 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
103 #else
104 GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
105 #endif
107         probe_sched_write(SCHED_SWITCH, (int)next, next->tgid, next->pid);
110 GATOR_DEFINE_PROBE(sched_migrate_task, TP_PROTO(struct task_struct *p, int dest_cpu))
112         probe_sched_write(SCHED_MIGRATE_TASK, 0, dest_cpu, p->pid);
115 GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
117         probe_sched_write(SCHED_PROCESS_FREE, 0, p->pid, 0);
120 GATOR_DEFINE_PROBE(sched_process_exit, TP_PROTO(struct task_struct *p))
122         probe_sched_write(SCHED_PROCESS_EXIT, 0, p->pid, 0);
125 GATOR_DEFINE_PROBE(sched_process_wait, TP_PROTO(struct pid *pid))
127         probe_sched_write(SCHED_PROCESS_WAIT, 0, pid_nr(pid), 0);
130 GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child))
132         probe_sched_write(SCHED_PROCESS_FORK, (int)child, parent->pid, child->pid);
135 int gator_trace_sched_init(void)
137         return 0;
140 int gator_trace_sched_start(void)
142         int cpu;
144         for_each_present_cpu(cpu) {
145                 per_cpu(theSchedSel, cpu) = 0;
146                 per_cpu(theSchedPos, cpu) = 0;
147                 per_cpu(theSchedErr, cpu) = 0;
148                 per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
149                 per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(int), GFP_KERNEL);
150                 if (!per_cpu(theSchedBuf, cpu))
151                         return -1;
152         }
154         // register tracepoints
155         if (GATOR_REGISTER_TRACE(sched_wait_task))
156                 goto fail_sched_wait_task;
157         if (GATOR_REGISTER_TRACE(sched_wakeup))
158                 goto fail_sched_wakeup;
159         if (GATOR_REGISTER_TRACE(sched_wakeup_new))
160                 goto fail_sched_wakeup_new;
161         if (GATOR_REGISTER_TRACE(sched_switch))
162                 goto fail_sched_switch;
163         if (GATOR_REGISTER_TRACE(sched_migrate_task))
164                 goto fail_sched_migrate_task;
165         if (GATOR_REGISTER_TRACE(sched_process_free))
166                 goto fail_sched_process_free;
167         if (GATOR_REGISTER_TRACE(sched_process_exit))
168                 goto fail_sched_process_exit;
169         if (GATOR_REGISTER_TRACE(sched_process_wait))
170                 goto fail_sched_process_wait;
171         if (GATOR_REGISTER_TRACE(sched_process_fork))
172                 goto fail_sched_process_fork;
173         pr_debug("gator: registered tracepoints\n");
175         return 0;
177         // unregister tracepoints on error
178 fail_sched_process_fork:
179         GATOR_UNREGISTER_TRACE(sched_process_wait);
180 fail_sched_process_wait:
181         GATOR_UNREGISTER_TRACE(sched_process_exit);
182 fail_sched_process_exit:
183         GATOR_UNREGISTER_TRACE(sched_process_free);
184 fail_sched_process_free:
185         GATOR_UNREGISTER_TRACE(sched_migrate_task);
186 fail_sched_migrate_task:
187         GATOR_UNREGISTER_TRACE(sched_switch);
188 fail_sched_switch:
189         GATOR_UNREGISTER_TRACE(sched_wakeup_new);
190 fail_sched_wakeup_new:
191         GATOR_UNREGISTER_TRACE(sched_wakeup);
192 fail_sched_wakeup:
193         GATOR_UNREGISTER_TRACE(sched_wait_task);
194 fail_sched_wait_task:
195         pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
197         return -1;
200 void gator_trace_sched_stop(void)
202         int cpu;
203         GATOR_UNREGISTER_TRACE(sched_wait_task);
204         GATOR_UNREGISTER_TRACE(sched_wakeup);
205         GATOR_UNREGISTER_TRACE(sched_wakeup_new);
206         GATOR_UNREGISTER_TRACE(sched_switch);
207         GATOR_UNREGISTER_TRACE(sched_migrate_task);
208         GATOR_UNREGISTER_TRACE(sched_process_free);
209         GATOR_UNREGISTER_TRACE(sched_process_exit);
210         GATOR_UNREGISTER_TRACE(sched_process_wait);
211         GATOR_UNREGISTER_TRACE(sched_process_fork);
212         pr_debug("gator: unregistered tracepoints\n");
214         for_each_present_cpu(cpu) {
215                 kfree(per_cpu(theSchedBuf, cpu)[0]);
216                 kfree(per_cpu(theSchedBuf, cpu)[1]);
217                 per_cpu(theSchedBuf, cpu)[0] = NULL;
218                 per_cpu(theSchedBuf, cpu)[1] = NULL;
219         }
222 int gator_trace_sched_read(int **buffer)
224         uint64_t time = gator_get_time();
225         int cpu = smp_processor_id();
226         unsigned long flags;
227         int *schedBuf;
228         int schedPos;
229         int i;
231         if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
232                 return 0;
234         local_irq_save(flags);
236         schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
237         schedPos = per_cpu(theSchedPos, cpu);
239         per_cpu(theSchedSel, cpu) = !per_cpu(theSchedSel, cpu);
240         per_cpu(theSchedPos, cpu) = 0;
241         per_cpu(theSchedErr, cpu) = 0;
243         local_irq_restore(flags);
245         // find mm and replace with cookies
246         for (i = 0; i < schedPos; i += 6) {
247                 uint32_t cookie = schedBuf[i+3];
248                 if (cookie) {
249                         struct task_struct *task = (struct task_struct *)cookie;
250                         schedBuf[i+3] = get_exec_cookie(cpu, task);
251                 }
252         }
254         // timer/end event
255         schedBuf[schedPos++] = SCHED_TIMER_EVENT;
256         schedBuf[schedPos++] = (int)time;
257         schedBuf[schedPos++] = (int)(time >> 32);
259         if (buffer)
260                 *buffer = schedBuf;
262         return schedPos;