From 7d468abee0f1a7e918b5e2f23120436a54ba9f33 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 27 Nov 2008 10:57:09 +0100 Subject: oprofile: adding cpu buffer r/w access functions This is in preparation for changes in the cpu buffer implementation. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index d3cc26264db5..08706991fdd2 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -52,6 +52,18 @@ DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf); +static inline +struct op_sample *cpu_buffer_write_entry(struct oprofile_cpu_buffer *cpu_buf) +{ + return &cpu_buf->buffer[cpu_buf->head_pos]; +} + +static inline +struct op_sample *cpu_buffer_read_entry(struct oprofile_cpu_buffer *cpu_buf) +{ + return &cpu_buf->buffer[cpu_buf->tail_pos]; +} + /* transient events for the CPU buffer -> event buffer */ #define CPU_IS_KERNEL 1 #define CPU_TRACE_BEGIN 2 -- cgit v1.2.2 From 229234ae4a5ed9376b2e0524da04b0e5edadbf76 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 27 Nov 2008 18:36:08 +0100 Subject: oprofile: adding cpu_buffer_write_commit() This is in preparation for changes in the cpu buffer implementation. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 08706991fdd2..e6089768ae66 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -58,6 +58,23 @@ struct op_sample *cpu_buffer_write_entry(struct oprofile_cpu_buffer *cpu_buf) return &cpu_buf->buffer[cpu_buf->head_pos]; } +static inline +void cpu_buffer_write_commit(struct oprofile_cpu_buffer *b) +{ + unsigned long new_head = b->head_pos + 1; + + /* + * Ensure anything written to the slot before we increment is + * visible + */ + wmb(); + + if (new_head < b->buffer_size) + b->head_pos = new_head; + else + b->head_pos = 0; +} + static inline struct op_sample *cpu_buffer_read_entry(struct oprofile_cpu_buffer *cpu_buf) { -- cgit v1.2.2 From bf589e32960181fa8cbca7bfdd92265e49dc2dfa Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 27 Nov 2008 22:33:37 +0100 Subject: oprofile: adding cpu_buffer_entries() This is in preparation for changes in the cpu buffer implementation. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index e6089768ae66..6055b5678394 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -81,6 +81,33 @@ struct op_sample *cpu_buffer_read_entry(struct oprofile_cpu_buffer *cpu_buf) return &cpu_buf->buffer[cpu_buf->tail_pos]; } +/* "acquire" as many cpu buffer slots as we can */ +static inline +unsigned long cpu_buffer_entries(struct oprofile_cpu_buffer *b) +{ + unsigned long head = b->head_pos; + unsigned long tail = b->tail_pos; + + /* + * Subtle. This resets the persistent last_task + * and in_kernel values used for switching notes. + * BUT, there is a small window between reading + * head_pos, and this call, that means samples + * can appear at the new head position, but not + * be prefixed with the notes for switching + * kernel mode or a task switch. This small hole + * can lead to mis-attribution or samples where + * we don't know if it's in the kernel or not, + * at the start of an event buffer. + */ + cpu_buffer_reset(b); + + if (head >= tail) + return head - tail; + + return head + (b->buffer_size - tail); +} + /* transient events for the CPU buffer -> event buffer */ #define CPU_IS_KERNEL 1 #define CPU_TRACE_BEGIN 2 -- cgit v1.2.2 From fbc9bf9f0ed4f0fbc47dcb5b1c26c28c93b60e33 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 4 Dec 2008 16:27:00 +0100 Subject: oprofile: moving cpu_buffer_reset() to cpu_buffer.h This is in preparation for changes in the cpu buffer implementation. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 6055b5678394..895763f065e9 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -50,7 +50,19 @@ struct oprofile_cpu_buffer { DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); -void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf); +/* + * Resets the cpu buffer to a sane state. + * + * reset these to invalid values; the next sample collected will + * populate the buffer with proper values to initialize the buffer + */ +static inline void cpu_buffer_reset(int cpu) +{ + struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); + + cpu_buf->last_is_kernel = -1; + cpu_buf->last_task = NULL; +} static inline struct op_sample *cpu_buffer_write_entry(struct oprofile_cpu_buffer *cpu_buf) @@ -88,20 +100,6 @@ unsigned long cpu_buffer_entries(struct oprofile_cpu_buffer *b) unsigned long head = b->head_pos; unsigned long tail = b->tail_pos; - /* - * Subtle. This resets the persistent last_task - * and in_kernel values used for switching notes. - * BUT, there is a small window between reading - * head_pos, and this call, that means samples - * can appear at the new head position, but not - * be prefixed with the notes for switching - * kernel mode or a task switch. This small hole - * can lead to mis-attribution or samples where - * we don't know if it's in the kernel or not, - * at the start of an event buffer. - */ - cpu_buffer_reset(b); - if (head >= tail) return head - tail; -- cgit v1.2.2 From 6dad828b76c7224a22ddc9ce7aa495d994f03b31 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 9 Dec 2008 01:21:32 +0100 Subject: oprofile: port to the new ring_buffer This patch replaces the current oprofile cpu buffer implementation with the ring buffer provided by the tracing framework. The motivation here is to leave the pain of implementing ring buffers to others. Oh, no, there are more advantages. Main reason is the support of different sample sizes that could be stored in the buffer. Use cases for this are IBS and Cell spu profiling. Using the new ring buffer ensures valid and complete samples and allows copying the cpu buffer stateless without knowing its content. Second it will use generic kernel API and also reduce code size. And hopefully, there are less bugs. Since the new tracing ring buffer implementation uses spin locks to protect the buffer during read/write access, it is difficult to use the buffer in an NMI handler. In this case, writing to the buffer by the 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. The new buffer requires more size to store the same amount of samples because each sample includes an u32 header. Also, there is more code to execute for buffer access. Nonetheless, the buffer implementation is proven in the ftrace environment and worth to use also in oprofile. Patches that changes the internal IBS buffer usage will follow. Cc: Steven Rostedt Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 71 +++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 30 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 895763f065e9..aacb0f0bc566 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -15,6 +15,7 @@ #include #include #include +#include struct task_struct; @@ -32,6 +33,12 @@ struct op_sample { unsigned long event; }; +struct op_entry { + struct ring_buffer_event *event; + struct op_sample *sample; + unsigned long irq_flags; +}; + struct oprofile_cpu_buffer { volatile unsigned long head_pos; volatile unsigned long tail_pos; @@ -39,7 +46,6 @@ struct oprofile_cpu_buffer { struct task_struct *last_task; int last_is_kernel; int tracing; - struct op_sample *buffer; unsigned long sample_received; unsigned long sample_lost_overflow; unsigned long backtrace_aborted; @@ -48,6 +54,8 @@ struct oprofile_cpu_buffer { struct delayed_work work; }; +extern struct ring_buffer *op_ring_buffer_read; +extern struct ring_buffer *op_ring_buffer_write; DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); /* @@ -64,46 +72,49 @@ static inline void cpu_buffer_reset(int cpu) cpu_buf->last_task = NULL; } -static inline -struct op_sample *cpu_buffer_write_entry(struct oprofile_cpu_buffer *cpu_buf) +static inline int cpu_buffer_write_entry(struct op_entry *entry) { - return &cpu_buf->buffer[cpu_buf->head_pos]; -} + entry->event = ring_buffer_lock_reserve(op_ring_buffer_write, + sizeof(struct op_sample), + &entry->irq_flags); + if (entry->event) + entry->sample = ring_buffer_event_data(entry->event); + else + entry->sample = NULL; -static inline -void cpu_buffer_write_commit(struct oprofile_cpu_buffer *b) -{ - unsigned long new_head = b->head_pos + 1; + if (!entry->sample) + return -ENOMEM; - /* - * Ensure anything written to the slot before we increment is - * visible - */ - wmb(); + return 0; +} - if (new_head < b->buffer_size) - b->head_pos = new_head; - else - b->head_pos = 0; +static inline int cpu_buffer_write_commit(struct op_entry *entry) +{ + return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, + entry->irq_flags); } -static inline -struct op_sample *cpu_buffer_read_entry(struct oprofile_cpu_buffer *cpu_buf) +static inline struct op_sample *cpu_buffer_read_entry(int cpu) { - return &cpu_buf->buffer[cpu_buf->tail_pos]; + struct ring_buffer_event *e; + e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); + if (e) + return ring_buffer_event_data(e); + if (ring_buffer_swap_cpu(op_ring_buffer_read, + op_ring_buffer_write, + cpu)) + return NULL; + e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); + if (e) + return ring_buffer_event_data(e); + return NULL; } /* "acquire" as many cpu buffer slots as we can */ -static inline -unsigned long cpu_buffer_entries(struct oprofile_cpu_buffer *b) +static inline unsigned long cpu_buffer_entries(int cpu) { - unsigned long head = b->head_pos; - unsigned long tail = b->tail_pos; - - if (head >= tail) - return head - tail; - - return head + (b->buffer_size - tail); + return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) + + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); } /* transient events for the CPU buffer -> event buffer */ -- cgit v1.2.2 From 6d2c53f3cd81e33eec17aa99845d43e599986982 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 24 Dec 2008 16:53:53 +0100 Subject: oprofile: rename cpu buffer functions This patch renames cpu buffer functions to something more oprofile specific names. Functions will be moved to the global name space. Cc: Andrew Morton Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index aacb0f0bc566..83d491e273fe 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -64,7 +64,7 @@ DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); * reset these to invalid values; the next sample collected will * populate the buffer with proper values to initialize the buffer */ -static inline void cpu_buffer_reset(int cpu) +static inline void op_cpu_buffer_reset(int cpu) { struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); @@ -72,7 +72,7 @@ static inline void cpu_buffer_reset(int cpu) cpu_buf->last_task = NULL; } -static inline int cpu_buffer_write_entry(struct op_entry *entry) +static inline int op_cpu_buffer_write_entry(struct op_entry *entry) { entry->event = ring_buffer_lock_reserve(op_ring_buffer_write, sizeof(struct op_sample), @@ -88,13 +88,13 @@ static inline int cpu_buffer_write_entry(struct op_entry *entry) return 0; } -static inline int cpu_buffer_write_commit(struct op_entry *entry) +static inline int op_cpu_buffer_write_commit(struct op_entry *entry) { return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, entry->irq_flags); } -static inline struct op_sample *cpu_buffer_read_entry(int cpu) +static inline struct op_sample *op_cpu_buffer_read_entry(int cpu) { struct ring_buffer_event *e; e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); @@ -111,7 +111,7 @@ static inline struct op_sample *cpu_buffer_read_entry(int cpu) } /* "acquire" as many cpu buffer slots as we can */ -static inline unsigned long cpu_buffer_entries(int cpu) +static inline unsigned long op_cpu_buffer_entries(int cpu) { return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); -- cgit v1.2.2 From 9966718daee592fbdc523703b2d8200009642506 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 16 Dec 2008 16:19:54 +0100 Subject: oprofile: remove ring buffer inline functions in cpu_buffer.h This patch moves ring buffer inline functions to cpu_buffer.c. Cc: Andrew Morton Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 50 ++++--------------------------------------- 1 file changed, 4 insertions(+), 46 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 83d491e273fe..cd28abc06960 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -54,8 +54,6 @@ struct oprofile_cpu_buffer { struct delayed_work work; }; -extern struct ring_buffer *op_ring_buffer_read; -extern struct ring_buffer *op_ring_buffer_write; DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); /* @@ -72,50 +70,10 @@ static inline void op_cpu_buffer_reset(int cpu) cpu_buf->last_task = NULL; } -static inline int op_cpu_buffer_write_entry(struct op_entry *entry) -{ - entry->event = ring_buffer_lock_reserve(op_ring_buffer_write, - sizeof(struct op_sample), - &entry->irq_flags); - if (entry->event) - entry->sample = ring_buffer_event_data(entry->event); - else - entry->sample = NULL; - - if (!entry->sample) - return -ENOMEM; - - return 0; -} - -static inline int op_cpu_buffer_write_commit(struct op_entry *entry) -{ - return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, - entry->irq_flags); -} - -static inline struct op_sample *op_cpu_buffer_read_entry(int cpu) -{ - struct ring_buffer_event *e; - e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); - if (e) - return ring_buffer_event_data(e); - if (ring_buffer_swap_cpu(op_ring_buffer_read, - op_ring_buffer_write, - cpu)) - return NULL; - e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); - if (e) - return ring_buffer_event_data(e); - return NULL; -} - -/* "acquire" as many cpu buffer slots as we can */ -static inline unsigned long op_cpu_buffer_entries(int cpu) -{ - return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) - + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); -} +int op_cpu_buffer_write_entry(struct op_entry *entry); +int op_cpu_buffer_write_commit(struct op_entry *entry); +struct op_sample *op_cpu_buffer_read_entry(int cpu); +unsigned long op_cpu_buffer_entries(int cpu); /* transient events for the CPU buffer -> event buffer */ #define CPU_IS_KERNEL 1 -- cgit v1.2.2 From 8d15df84a42b140a8262a325b987a283ef9f5f63 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 24 Dec 2008 15:42:58 +0100 Subject: oprofile: remove unused components in struct oprofile_cpu_buffer Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index cd28abc06960..65b763ad72da 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -40,8 +40,6 @@ struct op_entry { }; struct oprofile_cpu_buffer { - volatile unsigned long head_pos; - volatile unsigned long tail_pos; unsigned long buffer_size; struct task_struct *last_task; int last_is_kernel; -- cgit v1.2.2 From 2cc28b9f261dd28d69767a34682ce55a27d928ed Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 25 Dec 2008 17:26:07 +0100 Subject: oprofile: add op_cpu_buffer_write_reserve() This function prepares the cpu buffer to write a sample. Struct op_entry is used during operations on the ring buffer while struct op_sample contains the data that is stored in the ring buffer. Struct entry can be uninitialized. The function reserves a data array that is specified by size. Use op_cpu_buffer_write_commit() after preparing the sample. In case of errors a null pointer is returned, otherwise the pointer to the sample. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 65b763ad72da..2d4bfdeb7fba 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -1,10 +1,11 @@ /** * @file cpu_buffer.h * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon + * @author Robert Richter */ #ifndef OPROFILE_CPU_BUFFER_H @@ -31,12 +32,15 @@ void end_cpu_work(void); struct op_sample { unsigned long eip; unsigned long event; + unsigned long data[0]; }; struct op_entry { struct ring_buffer_event *event; struct op_sample *sample; unsigned long irq_flags; + unsigned long size; + unsigned long *data; }; struct oprofile_cpu_buffer { @@ -68,7 +72,8 @@ static inline void op_cpu_buffer_reset(int cpu) cpu_buf->last_task = NULL; } -int op_cpu_buffer_write_entry(struct op_entry *entry); +struct op_sample +*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size); int op_cpu_buffer_write_commit(struct op_entry *entry); struct op_sample *op_cpu_buffer_read_entry(int cpu); unsigned long op_cpu_buffer_entries(int cpu); -- cgit v1.2.2 From 2d87b14cf8d0b07720de26d90789d02124141616 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 30 Dec 2008 04:10:46 +0100 Subject: oprofile: modify op_cpu_buffer_read_entry() This implements the support of samples with attached data. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 2d4bfdeb7fba..d7c0545ef8b2 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -75,7 +75,7 @@ static inline void op_cpu_buffer_reset(int cpu) struct op_sample *op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size); int op_cpu_buffer_write_commit(struct op_entry *entry); -struct op_sample *op_cpu_buffer_read_entry(int cpu); +struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu); unsigned long op_cpu_buffer_entries(int cpu); /* transient events for the CPU buffer -> event buffer */ -- cgit v1.2.2 From ae735e9964b4584923f2997d98a8d80ae9c1a75c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 25 Dec 2008 17:26:07 +0100 Subject: oprofile: rework implementation of cpu buffer events Special events such as task or context switches are marked with an escape code in the cpu buffer followed by an event code or a task identifier. There is one escape code per event. To make escape sequences also available for data samples the internal cpu buffer format must be changed. The current implementation does not allow the extension of event codes since this would lead to collisions with the task identifiers. To avoid this, this patch introduces an event mask that allows the storage of multiple events with one escape code. Now, task identifiers are stored in the data section of the sample. The implementation also allows the usage of custom data in a sample. As a side effect the new code is much more readable and easier to understand. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index d7c0545ef8b2..e634dcf2f26f 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -78,10 +78,12 @@ int op_cpu_buffer_write_commit(struct op_entry *entry); struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu); unsigned long op_cpu_buffer_entries(int cpu); -/* transient events for the CPU buffer -> event buffer */ -#define CPU_IS_KERNEL 1 -#define CPU_TRACE_BEGIN 2 -#define IBS_FETCH_BEGIN 3 -#define IBS_OP_BEGIN 4 +/* extra data flags */ +#define KERNEL_CTX_SWITCH (1UL << 0) +#define IS_KERNEL (1UL << 1) +#define TRACE_BEGIN (1UL << 2) +#define USER_CTX_SWITCH (1UL << 3) +#define IBS_FETCH_BEGIN (1UL << 4) +#define IBS_OP_BEGIN (1UL << 5) #endif /* OPROFILE_CPU_BUFFER_H */ -- cgit v1.2.2 From d9928c25a6960cf128c2078a89fe6f8e0180ff60 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 25 Dec 2008 17:26:07 +0100 Subject: oprofile: add op_cpu_buffer_add_data() This function can be used to attach data to a sample. It returns the remaining free buffer size that has been reserved with op_cpu_buffer_write_reserve(). Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index e634dcf2f26f..e178dd2799c4 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -78,6 +78,18 @@ int op_cpu_buffer_write_commit(struct op_entry *entry); struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu); unsigned long op_cpu_buffer_entries(int cpu); +/* returns the remaining free size of data in the entry */ +static inline +int op_cpu_buffer_add_data(struct op_entry *entry, unsigned long val) +{ + if (!entry->size) + return 0; + *entry->data = val; + entry->size--; + entry->data++; + return entry->size; +} + /* extra data flags */ #define KERNEL_CTX_SWITCH (1UL << 0) #define IS_KERNEL (1UL << 1) -- cgit v1.2.2 From bd7dc46f770d317ada1348294ff1f319243b803b Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 6 Jan 2009 03:56:50 +0100 Subject: oprofile: add op_cpu_buffer_get_data() This function provides access to attached data of a sample. It returns the size of data including the current value. Also, op_cpu_buffer_get_size() is available to check if there is data attached. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index e178dd2799c4..f34376046573 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -90,6 +90,26 @@ int op_cpu_buffer_add_data(struct op_entry *entry, unsigned long val) return entry->size; } +/* returns the size of data in the entry */ +static inline +int op_cpu_buffer_get_size(struct op_entry *entry) +{ + return entry->size; +} + +/* returns 0 if empty or the size of data including the current value */ +static inline +int op_cpu_buffer_get_data(struct op_entry *entry, unsigned long *val) +{ + int size = entry->size; + if (!size) + return 0; + *val = *entry->data; + entry->size--; + entry->data++; + return size; +} + /* extra data flags */ #define KERNEL_CTX_SWITCH (1UL << 0) #define IS_KERNEL (1UL << 1) -- cgit v1.2.2 From 1acda878e20ea0cd3708ba66dca67d52eaafdd2b Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 5 Jan 2009 10:35:31 +0100 Subject: oprofile: use new data sample format for ibs The new ring buffer implementation allows the storage of samples with different size. This patch implements the usage of the new sample format to store ibs samples in the cpu buffer. Until now, writing to the cpu buffer could lead to incomplete sampling sequences since IBS samples were transfered in multiple samples. Due to a full buffer, data could be lost at any time. This can't happen any more since the complete data is reserved in advance and then stored in a single sample. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index f34376046573..525cc4d13d8d 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -115,7 +115,5 @@ int op_cpu_buffer_get_data(struct op_entry *entry, unsigned long *val) #define IS_KERNEL (1UL << 1) #define TRACE_BEGIN (1UL << 2) #define USER_CTX_SWITCH (1UL << 3) -#define IBS_FETCH_BEGIN (1UL << 4) -#define IBS_OP_BEGIN (1UL << 5) #endif /* OPROFILE_CPU_BUFFER_H */ -- cgit v1.2.2 From 14f0ca8eaea42a5b5a69cfcb699665dd2618db5f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Jan 2009 21:50:22 +0100 Subject: oprofile: make new cpu buffer functions part of the api This patch creates the new functions oprofile_write_reserve() oprofile_add_data() oprofile_write_commit() and makes them part of the oprofile api. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/oprofile/cpu_buffer.h') diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 525cc4d13d8d..63f81c44846a 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -35,13 +35,7 @@ struct op_sample { unsigned long data[0]; }; -struct op_entry { - struct ring_buffer_event *event; - struct op_sample *sample; - unsigned long irq_flags; - unsigned long size; - unsigned long *data; -}; +struct op_entry; struct oprofile_cpu_buffer { unsigned long buffer_size; -- cgit v1.2.2