ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / oprofile / cpu_buffer.c
1 /**
2  * @file cpu_buffer.c
3  *
4  * @remark Copyright 2002 OProfile authors
5  * @remark Read the file COPYING
6  *
7  * @author John Levon <levon@movementarian.org>
8  *
9  * Each CPU has a local buffer that stores PC value/event
10  * pairs. We also log context switches when we notice them.
11  * Eventually each CPU's buffer is processed into the global
12  * event buffer by sync_cpu_buffers().
13  *
14  * We use a local buffer for two reasons: an NMI or similar
15  * interrupt cannot synchronise, and high sampling rates
16  * would lead to catastrophic global synchronisation if
17  * a global buffer was used.
18  */
19
20 #include <linux/sched.h>
21 #include <linux/vmalloc.h>
22 #include <linux/errno.h>
23  
24 #include "cpu_buffer.h"
25 #include "oprof.h"
26
27 struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned;
28
29 static void __free_cpu_buffers(int num)
30 {
31         int i;
32  
33         for (i=0; i < num; ++i) {
34                 struct oprofile_cpu_buffer * b = &cpu_buffer[i];
35  
36                 if (!cpu_possible(i)) 
37                         continue;
38  
39                 vfree(b->buffer);
40         }
41 }
42  
43  
44 int alloc_cpu_buffers(void)
45 {
46         int i;
47  
48         unsigned long buffer_size = fs_cpu_buffer_size;
49  
50         for (i=0; i < NR_CPUS; ++i) {
51                 struct oprofile_cpu_buffer * b = &cpu_buffer[i];
52  
53                 if (!cpu_possible(i)) 
54                         continue;
55  
56                 b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size);
57                 if (!b->buffer)
58                         goto fail;
59  
60                 b->last_task = 0;
61                 b->last_is_kernel = -1;
62                 b->buffer_size = buffer_size;
63                 b->tail_pos = 0;
64                 b->head_pos = 0;
65                 b->sample_received = 0;
66                 b->sample_lost_overflow = 0;
67                 b->sample_lost_task_exit = 0;
68         }
69         return 0;
70 fail:
71         __free_cpu_buffers(i);
72         return -ENOMEM;
73 }
74  
75
76 void free_cpu_buffers(void)
77 {
78         __free_cpu_buffers(NR_CPUS);
79 }
80
81
82 /* compute number of available slots in cpu_buffer queue */
83 static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b)
84 {
85         unsigned long head = b->head_pos;
86         unsigned long tail = b->tail_pos;
87
88         if (tail > head)
89                 return (tail - head) - 1;
90
91         return tail + (b->buffer_size - head) - 1;
92 }
93
94
95 static void increment_head(struct oprofile_cpu_buffer * b)
96 {
97         unsigned long new_head = b->head_pos + 1;
98
99         /* Ensure anything written to the slot before we
100          * increment is visible */
101         wmb();
102
103         if (new_head < (b->buffer_size))
104                 b->head_pos = new_head;
105         else
106                 b->head_pos = 0;
107 }
108
109
110 /* This must be safe from any context. It's safe writing here
111  * because of the head/tail separation of the writer and reader
112  * of the CPU buffer.
113  *
114  * is_kernel is needed because on some architectures you cannot
115  * tell if you are in kernel or user space simply by looking at
116  * eip. We tag this in the buffer by generating kernel enter/exit
117  * events whenever is_kernel changes
118  */
119 void oprofile_add_sample(unsigned long eip, unsigned int is_kernel, 
120         unsigned long event, int cpu)
121 {
122         struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu];
123         struct task_struct * task;
124
125         is_kernel = !!is_kernel;
126
127         cpu_buf->sample_received++;
128  
129
130         if (nr_available_slots(cpu_buf) < 3) {
131                 cpu_buf->sample_lost_overflow++;
132                 return;
133         }
134
135         task = current;
136
137         /* notice a switch from user->kernel or vice versa */
138         if (cpu_buf->last_is_kernel != is_kernel) {
139                 cpu_buf->last_is_kernel = is_kernel;
140                 cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL;
141                 cpu_buf->buffer[cpu_buf->head_pos].event = is_kernel;
142                 increment_head(cpu_buf);
143         }
144
145         /* notice a task switch */
146         if (cpu_buf->last_task != task) {
147                 cpu_buf->last_task = task;
148                 if (!(task->flags & PF_EXITING)) {
149                         cpu_buf->buffer[cpu_buf->head_pos].eip = ~0UL;
150                         cpu_buf->buffer[cpu_buf->head_pos].event = (unsigned long)task;
151                         increment_head(cpu_buf);
152                 }
153         }
154  
155         /* If the task is exiting it's not safe to take a sample
156          * as the task_struct is about to be freed. We can't just
157          * notify at release_task() time because of CLONE_DETACHED
158          * tasks that release_task() themselves.
159          */
160         if (task->flags & PF_EXITING) {
161                 cpu_buf->sample_lost_task_exit++;
162                 return;
163         }
164  
165         cpu_buf->buffer[cpu_buf->head_pos].eip = eip;
166         cpu_buf->buffer[cpu_buf->head_pos].event = event;
167         increment_head(cpu_buf);
168 }
169
170
171 /* Resets the cpu buffer to a sane state. */
172 void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf)
173 {
174         /* reset these to invalid values; the next sample
175          * collected will populate the buffer with proper
176          * values to initialize the buffer
177          */
178         cpu_buf->last_is_kernel = -1;
179         cpu_buf->last_task = 0;
180 }