Commit cb6e943c authored by Andi Kleen's avatar Andi Kleen Committed by Robert Richter

oprofile: remove double ring buffering

oprofile used a double buffer scheme for its cpu event buffer
to avoid races on reading with the old locked ring buffer.

But that is obsolete now with the new ring buffer, so simply
use a single buffer. This greatly simplifies the code and avoids
a lot of sample drops on large runs, especially with call graph.

Based on suggestions from Steven Rostedt

For stable kernels from v2.6.32, but not earlier.
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarRobert Richter <robert.richter@amd.com>
parent a36bf32e
...@@ -30,23 +30,7 @@ ...@@ -30,23 +30,7 @@
#define OP_BUFFER_FLAGS 0 #define OP_BUFFER_FLAGS 0
/* static struct ring_buffer *op_ring_buffer;
* Read and write access is using spin locking. Thus, writing to the
* buffer by NMI handler (x86) could occur also during critical
* sections when reading the buffer. To avoid this, there are 2
* buffers for independent read and write access. Read access is in
* process context only, write access only in the NMI handler. If the
* read buffer runs empty, both buffers are swapped atomically. There
* is potentially a small window during swapping where the buffers are
* disabled and samples could be lost.
*
* Using 2 buffers is a little bit overhead, but the solution is clear
* and does not require changes in the ring buffer implementation. It
* can be changed to a single buffer solution when the ring buffer
* access is implemented as non-locking atomic code.
*/
static struct ring_buffer *op_ring_buffer_read;
static struct ring_buffer *op_ring_buffer_write;
DEFINE_PER_CPU(struct oprofile_cpu_buffer, op_cpu_buffer); DEFINE_PER_CPU(struct oprofile_cpu_buffer, op_cpu_buffer);
static void wq_sync_buffer(struct work_struct *work); static void wq_sync_buffer(struct work_struct *work);
...@@ -68,12 +52,9 @@ void oprofile_cpu_buffer_inc_smpl_lost(void) ...@@ -68,12 +52,9 @@ void oprofile_cpu_buffer_inc_smpl_lost(void)
void free_cpu_buffers(void) void free_cpu_buffers(void)
{ {
if (op_ring_buffer_read) if (op_ring_buffer)
ring_buffer_free(op_ring_buffer_read); ring_buffer_free(op_ring_buffer);
op_ring_buffer_read = NULL; op_ring_buffer = NULL;
if (op_ring_buffer_write)
ring_buffer_free(op_ring_buffer_write);
op_ring_buffer_write = NULL;
} }
#define RB_EVENT_HDR_SIZE 4 #define RB_EVENT_HDR_SIZE 4
...@@ -86,11 +67,8 @@ int alloc_cpu_buffers(void) ...@@ -86,11 +67,8 @@ int alloc_cpu_buffers(void)
unsigned long byte_size = buffer_size * (sizeof(struct op_sample) + unsigned long byte_size = buffer_size * (sizeof(struct op_sample) +
RB_EVENT_HDR_SIZE); RB_EVENT_HDR_SIZE);
op_ring_buffer_read = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS); op_ring_buffer = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS);
if (!op_ring_buffer_read) if (!op_ring_buffer)
goto fail;
op_ring_buffer_write = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS);
if (!op_ring_buffer_write)
goto fail; goto fail;
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
...@@ -162,16 +140,11 @@ struct op_sample ...@@ -162,16 +140,11 @@ struct op_sample
*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size) *op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size)
{ {
entry->event = ring_buffer_lock_reserve entry->event = ring_buffer_lock_reserve
(op_ring_buffer_write, sizeof(struct op_sample) + (op_ring_buffer, sizeof(struct op_sample) +
size * sizeof(entry->sample->data[0])); size * sizeof(entry->sample->data[0]));
if (entry->event) if (!entry->event)
entry->sample = ring_buffer_event_data(entry->event);
else
entry->sample = NULL;
if (!entry->sample)
return NULL; return NULL;
entry->sample = ring_buffer_event_data(entry->event);
entry->size = size; entry->size = size;
entry->data = entry->sample->data; entry->data = entry->sample->data;
...@@ -180,25 +153,16 @@ struct op_sample ...@@ -180,25 +153,16 @@ struct op_sample
int op_cpu_buffer_write_commit(struct op_entry *entry) int op_cpu_buffer_write_commit(struct op_entry *entry)
{ {
return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event); return ring_buffer_unlock_commit(op_ring_buffer, entry->event);
} }
struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu) struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu)
{ {
struct ring_buffer_event *e; struct ring_buffer_event *e;
e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); e = ring_buffer_consume(op_ring_buffer, cpu, NULL);
if (e) if (!e)
goto event;
if (ring_buffer_swap_cpu(op_ring_buffer_read,
op_ring_buffer_write,
cpu))
return NULL; return NULL;
e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
if (e)
goto event;
return NULL;
event:
entry->event = e; entry->event = e;
entry->sample = ring_buffer_event_data(e); entry->sample = ring_buffer_event_data(e);
entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample)) entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample))
...@@ -209,8 +173,7 @@ struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu) ...@@ -209,8 +173,7 @@ struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu)
unsigned long op_cpu_buffer_entries(int cpu) unsigned long op_cpu_buffer_entries(int cpu)
{ {
return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) return ring_buffer_entries_cpu(op_ring_buffer, cpu);
+ ring_buffer_entries_cpu(op_ring_buffer_write, cpu);
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment