diff options
Diffstat (limited to 'drivers/oprofile/cpu_buffer.c')
-rw-r--r-- | drivers/oprofile/cpu_buffer.c | 63 |
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 | */ | ||
48 | struct ring_buffer *op_ring_buffer_read; | ||
49 | struct ring_buffer *op_ring_buffer_write; | ||
31 | DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); | 50 | DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); |
32 | 51 | ||
33 | static void wq_sync_buffer(struct work_struct *work); | 52 | static void wq_sync_buffer(struct work_struct *work); |
@@ -37,12 +56,12 @@ static int work_enabled; | |||
37 | 56 | ||
38 | void free_cpu_buffers(void) | 57 | void 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 | ||
48 | unsigned long oprofile_get_cpu_buffer_size(void) | 67 | unsigned 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 | |||
140 | add_sample(struct oprofile_cpu_buffer *cpu_buf, | 161 | add_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 | |||
177 | Error: | ||
178 | cpu_buf->sample_lost_overflow++; | ||
179 | return; | ||
147 | } | 180 | } |
148 | 181 | ||
149 | static inline void | 182 | static inline void |