aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/oprofile/cpu_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/oprofile/cpu_buffer.c')
-rw-r--r--drivers/oprofile/cpu_buffer.c63
1 files changed, 48 insertions, 15 deletions
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 5cf7efe38e67..eb280ec96e24 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -28,6 +28,25 @@
28#include "buffer_sync.h" 28#include "buffer_sync.h"
29#include "oprof.h" 29#include "oprof.h"
30 30
31#define OP_BUFFER_FLAGS 0
32
33/*
34 * Read and write access is using spin locking. Thus, writing to the
35 * buffer by NMI handler (x86) could occur also during critical
36 * sections when reading the buffer. To avoid this, there are 2
37 * buffers for independent read and write access. Read access is in
38 * process context only, write access only in the NMI handler. If the
39 * read buffer runs empty, both buffers are swapped atomically. There
40 * is potentially a small window during swapping where the buffers are
41 * disabled and samples could be lost.
42 *
43 * Using 2 buffers is a little bit overhead, but the solution is clear
44 * and does not require changes in the ring buffer implementation. It
45 * can be changed to a single buffer solution when the ring buffer
46 * access is implemented as non-locking atomic code.
47 */
48struct ring_buffer *op_ring_buffer_read;
49struct ring_buffer *op_ring_buffer_write;
31DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); 50DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
32 51
33static void wq_sync_buffer(struct work_struct *work); 52static void wq_sync_buffer(struct work_struct *work);
@@ -37,12 +56,12 @@ static int work_enabled;
37 56
38void free_cpu_buffers(void) 57void free_cpu_buffers(void)
39{ 58{
40 int i; 59 if (op_ring_buffer_read)
41 60 ring_buffer_free(op_ring_buffer_read);
42 for_each_possible_cpu(i) { 61 op_ring_buffer_read = NULL;
43 vfree(per_cpu(cpu_buffer, i).buffer); 62 if (op_ring_buffer_write)
44 per_cpu(cpu_buffer, i).buffer = NULL; 63 ring_buffer_free(op_ring_buffer_write);
45 } 64 op_ring_buffer_write = NULL;
46} 65}
47 66
48unsigned long oprofile_get_cpu_buffer_size(void) 67unsigned long oprofile_get_cpu_buffer_size(void)
@@ -64,14 +83,16 @@ int alloc_cpu_buffers(void)
64 83
65 unsigned long buffer_size = fs_cpu_buffer_size; 84 unsigned long buffer_size = fs_cpu_buffer_size;
66 85
86 op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS);
87 if (!op_ring_buffer_read)
88 goto fail;
89 op_ring_buffer_write = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS);
90 if (!op_ring_buffer_write)
91 goto fail;
92
67 for_each_possible_cpu(i) { 93 for_each_possible_cpu(i) {
68 struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); 94 struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
69 95
70 b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size,
71 cpu_to_node(i));
72 if (!b->buffer)
73 goto fail;
74
75 b->last_task = NULL; 96 b->last_task = NULL;
76 b->last_is_kernel = -1; 97 b->last_is_kernel = -1;
77 b->tracing = 0; 98 b->tracing = 0;
@@ -140,10 +161,22 @@ static inline void
140add_sample(struct oprofile_cpu_buffer *cpu_buf, 161add_sample(struct oprofile_cpu_buffer *cpu_buf,
141 unsigned long pc, unsigned long event) 162 unsigned long pc, unsigned long event)
142{ 163{
143 struct op_sample *entry = cpu_buffer_write_entry(cpu_buf); 164 struct op_entry entry;
144 entry->eip = pc; 165
145 entry->event = event; 166 if (cpu_buffer_write_entry(&entry))
146 cpu_buffer_write_commit(cpu_buf); 167 goto Error;
168
169 entry.sample->eip = pc;
170 entry.sample->event = event;
171
172 if (cpu_buffer_write_commit(&entry))
173 goto Error;
174
175 return;
176
177Error:
178 cpu_buf->sample_lost_overflow++;
179 return;
147} 180}
148 181
149static inline void 182static inline void