From 8dbc50c322619eb821907e8dba75252f5378c712 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 26 Nov 2008 15:00:52 +0100 Subject: oprofile: fix typo Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b55cd23ffdef..774b081b9b7f 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -272,7 +272,7 @@ static void increment_tail(struct oprofile_cpu_buffer *b) { unsigned long new_tail = b->tail_pos + 1; - rmb(); /* be sure fifo pointers are synchromized */ + rmb(); /* be sure fifo pointers are synchronized */ if (new_tail < b->buffer_size) b->tail_pos = new_tail; -- cgit v1.2.2 From fd7826d56bde11ab142d2431093773ad2b3f0a59 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 26 Sep 2008 17:50:31 -0400 Subject: oprofile: implement switch/case in buffer_sync.c Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 774b081b9b7f..7d61ae8ee8cf 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -561,6 +561,7 @@ void sync_buffer(int cpu) { struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); struct mm_struct *mm = NULL; + struct mm_struct *oldmm; struct task_struct *new; unsigned long cookie = 0; int in_kernel = 1; @@ -586,34 +587,39 @@ void sync_buffer(int cpu) struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos]; if (is_code(s->eip)) { - if (s->event <= CPU_IS_KERNEL) { + switch (s->event) { + case 0: + case CPU_IS_KERNEL: /* kernel/userspace switch */ in_kernel = s->event; if (state == sb_buffer_start) state = sb_sample_start; add_kernel_ctx_switch(s->event); - } else if (s->event == CPU_TRACE_BEGIN) { + break; + case CPU_TRACE_BEGIN: state = sb_bt_start; add_trace_begin(); + break; #ifdef CONFIG_OPROFILE_IBS - } else if (s->event == IBS_FETCH_BEGIN) { + case IBS_FETCH_BEGIN: state = sb_bt_start; add_ibs_begin(cpu_buf, IBS_FETCH_CODE, mm); - } else if (s->event == IBS_OP_BEGIN) { + break; + case IBS_OP_BEGIN: state = sb_bt_start; add_ibs_begin(cpu_buf, IBS_OP_CODE, mm); + break; #endif - } else { - struct mm_struct *oldmm = mm; - + default: /* userspace context switch */ + oldmm = mm; new = (struct task_struct *)s->event; - release_mm(oldmm); mm = take_tasks_mm(new); if (mm != oldmm) cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); + break; } } else if (state >= sb_bt_start && !add_sample(mm, s, in_kernel)) { -- cgit v1.2.2 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/buffer_sync.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 7d61ae8ee8cf..44f676c8a51d 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -331,10 +331,8 @@ static void add_trace_begin(void) #define IBS_FETCH_CODE_SIZE 2 #define IBS_OP_CODE_SIZE 5 -#define IBS_EIP(offset) \ - (((struct op_sample *)&cpu_buf->buffer[(offset)])->eip) -#define IBS_EVENT(offset) \ - (((struct op_sample *)&cpu_buf->buffer[(offset)])->event) +#define IBS_EIP(cpu_buf) ((cpu_buffer_read_entry(cpu_buf))->eip) +#define IBS_EVENT(cpu_buf) ((cpu_buffer_read_entry(cpu_buf))->event) /* * Add IBS fetch and op entries to event buffer @@ -349,10 +347,10 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, increment_tail(cpu_buf); /* move to RIP entry */ - rip = IBS_EIP(cpu_buf->tail_pos); + rip = IBS_EIP(cpu_buf); #ifdef __LP64__ - rip += IBS_EVENT(cpu_buf->tail_pos) << 32; + rip += IBS_EVENT(cpu_buf) << 32; #endif if (mm) { @@ -376,8 +374,8 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, add_event_entry(offset); /* Offset from Dcookie */ /* we send the Dcookie offset, but send the raw Linear Add also*/ - add_event_entry(IBS_EIP(cpu_buf->tail_pos)); - add_event_entry(IBS_EVENT(cpu_buf->tail_pos)); + add_event_entry(IBS_EIP(cpu_buf)); + add_event_entry(IBS_EVENT(cpu_buf)); if (code == IBS_FETCH_CODE) count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ @@ -386,8 +384,8 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, for (i = 0; i < count; i++) { increment_tail(cpu_buf); - add_event_entry(IBS_EIP(cpu_buf->tail_pos)); - add_event_entry(IBS_EVENT(cpu_buf->tail_pos)); + add_event_entry(IBS_EIP(cpu_buf)); + add_event_entry(IBS_EVENT(cpu_buf)); } } @@ -584,7 +582,7 @@ void sync_buffer(int cpu) #else while (get_slots(cpu_buf)) { #endif - struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos]; + struct op_sample *s = cpu_buffer_read_entry(cpu_buf); if (is_code(s->eip)) { switch (s->event) { -- 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/buffer_sync.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 44f676c8a51d..aed286c3f16e 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -464,33 +464,6 @@ static inline int is_code(unsigned long val) } -/* "acquire" as many cpu buffer slots as we can */ -static unsigned long get_slots(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); -} - - /* Move tasks along towards death. Any tasks on dead_tasks * will definitely have no remaining references in any * CPU buffers at this point, because we use two lists, @@ -576,11 +549,11 @@ void sync_buffer(int cpu) /* Remember, only we can modify tail_pos */ #ifndef CONFIG_OPROFILE_IBS - available = get_slots(cpu_buf); + available = cpu_buffer_entries(cpu_buf); for (i = 0; i < available; ++i) { #else - while (get_slots(cpu_buf)) { + while (cpu_buffer_entries(cpu_buf)) { #endif struct op_sample *s = cpu_buffer_read_entry(cpu_buf); -- 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/buffer_sync.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index aed286c3f16e..944a5832d9e4 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -548,6 +548,7 @@ void sync_buffer(int cpu) /* Remember, only we can modify tail_pos */ + cpu_buffer_reset(cpu); #ifndef CONFIG_OPROFILE_IBS available = cpu_buffer_entries(cpu_buf); -- 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/buffer_sync.c | 65 ++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 40 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 944a5832d9e4..737bd9484822 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -268,18 +268,6 @@ lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) return cookie; } -static void increment_tail(struct oprofile_cpu_buffer *b) -{ - unsigned long new_tail = b->tail_pos + 1; - - rmb(); /* be sure fifo pointers are synchronized */ - - if (new_tail < b->buffer_size) - b->tail_pos = new_tail; - else - b->tail_pos = 0; -} - static unsigned long last_cookie = INVALID_COOKIE; static void add_cpu_switch(int i) @@ -331,26 +319,25 @@ static void add_trace_begin(void) #define IBS_FETCH_CODE_SIZE 2 #define IBS_OP_CODE_SIZE 5 -#define IBS_EIP(cpu_buf) ((cpu_buffer_read_entry(cpu_buf))->eip) -#define IBS_EVENT(cpu_buf) ((cpu_buffer_read_entry(cpu_buf))->event) /* * Add IBS fetch and op entries to event buffer */ -static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, - struct mm_struct *mm) +static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) { unsigned long rip; int i, count; unsigned long ibs_cookie = 0; off_t offset; + struct op_sample *sample; - increment_tail(cpu_buf); /* move to RIP entry */ - - rip = IBS_EIP(cpu_buf); + sample = cpu_buffer_read_entry(cpu); + if (!sample) + goto Error; + rip = sample->eip; #ifdef __LP64__ - rip += IBS_EVENT(cpu_buf) << 32; + rip += sample->event << 32; #endif if (mm) { @@ -374,8 +361,8 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, add_event_entry(offset); /* Offset from Dcookie */ /* we send the Dcookie offset, but send the raw Linear Add also*/ - add_event_entry(IBS_EIP(cpu_buf)); - add_event_entry(IBS_EVENT(cpu_buf)); + add_event_entry(sample->eip); + add_event_entry(sample->event); if (code == IBS_FETCH_CODE) count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ @@ -383,10 +370,17 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code, count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ for (i = 0; i < count; i++) { - increment_tail(cpu_buf); - add_event_entry(IBS_EIP(cpu_buf)); - add_event_entry(IBS_EVENT(cpu_buf)); + sample = cpu_buffer_read_entry(cpu); + if (!sample) + goto Error; + add_event_entry(sample->eip); + add_event_entry(sample->event); } + + return; + +Error: + return; } #endif @@ -530,33 +524,26 @@ typedef enum { */ void sync_buffer(int cpu) { - struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); struct mm_struct *mm = NULL; struct mm_struct *oldmm; struct task_struct *new; unsigned long cookie = 0; int in_kernel = 1; sync_buffer_state state = sb_buffer_start; -#ifndef CONFIG_OPROFILE_IBS unsigned int i; unsigned long available; -#endif mutex_lock(&buffer_mutex); add_cpu_switch(cpu); - /* Remember, only we can modify tail_pos */ - cpu_buffer_reset(cpu); -#ifndef CONFIG_OPROFILE_IBS - available = cpu_buffer_entries(cpu_buf); + available = cpu_buffer_entries(cpu); for (i = 0; i < available; ++i) { -#else - while (cpu_buffer_entries(cpu_buf)) { -#endif - struct op_sample *s = cpu_buffer_read_entry(cpu_buf); + struct op_sample *s = cpu_buffer_read_entry(cpu); + if (!s) + break; if (is_code(s->eip)) { switch (s->event) { @@ -575,11 +562,11 @@ void sync_buffer(int cpu) #ifdef CONFIG_OPROFILE_IBS case IBS_FETCH_BEGIN: state = sb_bt_start; - add_ibs_begin(cpu_buf, IBS_FETCH_CODE, mm); + add_ibs_begin(cpu, IBS_FETCH_CODE, mm); break; case IBS_OP_BEGIN: state = sb_bt_start; - add_ibs_begin(cpu_buf, IBS_OP_CODE, mm); + add_ibs_begin(cpu, IBS_OP_CODE, mm); break; #endif default: @@ -600,8 +587,6 @@ void sync_buffer(int cpu) atomic_inc(&oprofile_stats.bt_lost_no_mapping); } } - - increment_tail(cpu_buf); } release_mm(mm); -- 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/buffer_sync.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 737bd9484822..d295d92b57f0 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -331,7 +331,7 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) off_t offset; struct op_sample *sample; - sample = cpu_buffer_read_entry(cpu); + sample = op_cpu_buffer_read_entry(cpu); if (!sample) goto Error; rip = sample->eip; @@ -370,7 +370,7 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ for (i = 0; i < count; i++) { - sample = cpu_buffer_read_entry(cpu); + sample = op_cpu_buffer_read_entry(cpu); if (!sample) goto Error; add_event_entry(sample->eip); @@ -537,11 +537,11 @@ void sync_buffer(int cpu) add_cpu_switch(cpu); - cpu_buffer_reset(cpu); - available = cpu_buffer_entries(cpu); + op_cpu_buffer_reset(cpu); + available = op_cpu_buffer_entries(cpu); for (i = 0; i < available; ++i) { - struct op_sample *s = cpu_buffer_read_entry(cpu); + struct op_sample *s = op_cpu_buffer_read_entry(cpu); if (!s) break; -- cgit v1.2.2 From 9741b309bb4493eedd3cdb5c97b566338a0da2cc Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 18 Dec 2008 19:44:20 +0100 Subject: oprofile: simplify add_sample() This patch removes add_us_sample() and simplifies add_sample(). Code is much more readable now. Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index d295d92b57f0..0abe29e7e4c7 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -392,11 +392,29 @@ static void add_sample_entry(unsigned long offset, unsigned long event) } -static int add_us_sample(struct mm_struct *mm, struct op_sample *s) +/* + * Add a sample to the global event buffer. If possible the + * sample is converted into a persistent dentry/offset pair + * for later lookup from userspace. Return 0 on failure. + */ +static int +add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) { unsigned long cookie; off_t offset; + if (in_kernel) { + add_sample_entry(s->eip, s->event); + return 1; + } + + /* add userspace sample */ + + if (!mm) { + atomic_inc(&oprofile_stats.sample_lost_no_mm); + return 0; + } + cookie = lookup_dcookie(mm, s->eip, &offset); if (cookie == INVALID_COOKIE) { @@ -415,25 +433,6 @@ static int add_us_sample(struct mm_struct *mm, struct op_sample *s) } -/* Add a sample to the global event buffer. If possible the - * sample is converted into a persistent dentry/offset pair - * for later lookup from userspace. - */ -static int -add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) -{ - if (in_kernel) { - add_sample_entry(s->eip, s->event); - return 1; - } else if (mm) { - return add_us_sample(mm, s); - } else { - atomic_inc(&oprofile_stats.sample_lost_no_mm); - } - return 0; -} - - static void release_mm(struct mm_struct *mm) { if (!mm) -- cgit v1.2.2 From 317f33bce6d43367a2fd170bc87ba18a88d2621d Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 18 Dec 2008 19:44:20 +0100 Subject: oprofile: simplify sync_buffer() Make code more readable. No functional changes. Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 0abe29e7e4c7..22cdb5108360 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -579,12 +579,20 @@ void sync_buffer(int cpu) add_user_ctx_switch(new, cookie); break; } - } else if (state >= sb_bt_start && - !add_sample(mm, s, in_kernel)) { - if (state == sb_bt_start) { - state = sb_bt_ignore; - atomic_inc(&oprofile_stats.bt_lost_no_mapping); - } + continue; + } + + if (state < sb_bt_start) + /* ignore sample */ + continue; + + if (add_sample(mm, s, in_kernel)) + continue; + + /* ignore backtraces if failed to add a sample */ + if (state == sb_bt_start) { + state = sb_bt_ignore; + atomic_inc(&oprofile_stats.bt_lost_no_mapping); } } release_mm(mm); -- cgit v1.2.2 From dbe6e2835e32461e7d592077947081c32f3da1d5 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 16 Dec 2008 11:01:18 +0100 Subject: oprofile: simplify add_ibs_begin() Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 22cdb5108360..7415d2e6b3a1 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -333,7 +333,7 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) sample = op_cpu_buffer_read_entry(cpu); if (!sample) - goto Error; + return; rip = sample->eip; #ifdef __LP64__ @@ -372,15 +372,12 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) for (i = 0; i < count; i++) { sample = op_cpu_buffer_read_entry(cpu); if (!sample) - goto Error; + return; add_event_entry(sample->eip); add_event_entry(sample->event); } return; - -Error: - return; } #endif -- cgit v1.2.2 From 8350c78734e67ac1f8bfd4eb14b70ff4d01a9a12 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 19 Dec 2008 12:59:28 +0100 Subject: oprofile: remove backtrace code for ibs This code is broken since a TRACE_BEGIN_CODE is never sent to the daemon. The data becomes corrupt since the backtrace is interpreted as ibs sample. Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 7415d2e6b3a1..e61e25fda1ad 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -557,11 +557,9 @@ void sync_buffer(int cpu) break; #ifdef CONFIG_OPROFILE_IBS case IBS_FETCH_BEGIN: - state = sb_bt_start; add_ibs_begin(cpu, IBS_FETCH_CODE, mm); break; case IBS_OP_BEGIN: - state = sb_bt_start; add_ibs_begin(cpu, IBS_OP_CODE, mm); break; #endif -- cgit v1.2.2 From 6368a1f4d99fe9a1990ef3f04ab2d2ce9dad0a7c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 29 Dec 2008 18:44:21 +0100 Subject: oprofile: making add_sample_entry() inline Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index e61e25fda1ad..bf8fcc7163da 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -382,7 +382,7 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) #endif -static void add_sample_entry(unsigned long offset, unsigned long event) +static inline void add_sample_entry(unsigned long offset, unsigned long event) { add_event_entry(offset); add_event_entry(event); -- cgit v1.2.2 From d358e75fc40cc3bbab11654ba0a88b232c543d12 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 5 Jan 2009 13:14:04 +0100 Subject: oprofile: rename variables in add_ibs_begin() This unifies usage of variable names within oprofile. Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index bf8fcc7163da..21fd249b6e0b 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -325,36 +325,36 @@ static void add_trace_begin(void) */ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) { - unsigned long rip; + unsigned long pc; int i, count; - unsigned long ibs_cookie = 0; + unsigned long cookie = 0; off_t offset; struct op_sample *sample; sample = op_cpu_buffer_read_entry(cpu); if (!sample) return; - rip = sample->eip; + pc = sample->eip; #ifdef __LP64__ - rip += sample->event << 32; + pc += sample->event << 32; #endif if (mm) { - ibs_cookie = lookup_dcookie(mm, rip, &offset); + cookie = lookup_dcookie(mm, pc, &offset); - if (ibs_cookie == NO_COOKIE) - offset = rip; - if (ibs_cookie == INVALID_COOKIE) { + if (cookie == NO_COOKIE) + offset = pc; + if (cookie == INVALID_COOKIE) { atomic_inc(&oprofile_stats.sample_lost_no_mapping); - offset = rip; + offset = pc; } - if (ibs_cookie != last_cookie) { - add_cookie_switch(ibs_cookie); - last_cookie = ibs_cookie; + if (cookie != last_cookie) { + add_cookie_switch(cookie); + last_cookie = cookie; } } else - offset = rip; + offset = pc; add_event_entry(ESCAPE_CODE); add_event_entry(code); -- 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/buffer_sync.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 21fd249b6e0b..908202afbae9 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -329,9 +329,10 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) int i, count; unsigned long cookie = 0; off_t offset; + struct op_entry entry; struct op_sample *sample; - sample = op_cpu_buffer_read_entry(cpu); + sample = op_cpu_buffer_read_entry(&entry, cpu); if (!sample) return; pc = sample->eip; @@ -370,7 +371,7 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ for (i = 0; i < count; i++) { - sample = op_cpu_buffer_read_entry(cpu); + sample = op_cpu_buffer_read_entry(&entry, cpu); if (!sample) return; add_event_entry(sample->eip); @@ -528,6 +529,8 @@ void sync_buffer(int cpu) sync_buffer_state state = sb_buffer_start; unsigned int i; unsigned long available; + struct op_entry entry; + struct op_sample *sample; mutex_lock(&buffer_mutex); @@ -537,19 +540,19 @@ void sync_buffer(int cpu) available = op_cpu_buffer_entries(cpu); for (i = 0; i < available; ++i) { - struct op_sample *s = op_cpu_buffer_read_entry(cpu); - if (!s) + sample = op_cpu_buffer_read_entry(&entry, cpu); + if (!sample) break; - if (is_code(s->eip)) { - switch (s->event) { + if (is_code(sample->eip)) { + switch (sample->event) { case 0: case CPU_IS_KERNEL: /* kernel/userspace switch */ - in_kernel = s->event; + in_kernel = sample->event; if (state == sb_buffer_start) state = sb_sample_start; - add_kernel_ctx_switch(s->event); + add_kernel_ctx_switch(sample->event); break; case CPU_TRACE_BEGIN: state = sb_bt_start; @@ -566,7 +569,7 @@ void sync_buffer(int cpu) default: /* userspace context switch */ oldmm = mm; - new = (struct task_struct *)s->event; + new = (struct task_struct *)sample->event; release_mm(oldmm); mm = take_tasks_mm(new); if (mm != oldmm) @@ -581,7 +584,7 @@ void sync_buffer(int cpu) /* ignore sample */ continue; - if (add_sample(mm, s, in_kernel)) + if (add_sample(mm, sample, in_kernel)) continue; /* ignore backtraces if failed to add a sample */ -- 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/buffer_sync.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 908202afbae9..d969bb13a252 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -1,11 +1,12 @@ /** * @file buffer_sync.c * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon * @author Barry Kasindorf + * @author Robert Richter * * This is the core of the buffer management. Each * CPU buffer is processed and entered into the @@ -529,6 +530,7 @@ void sync_buffer(int cpu) sync_buffer_state state = sb_buffer_start; unsigned int i; unsigned long available; + unsigned long flags; struct op_entry entry; struct op_sample *sample; @@ -545,38 +547,34 @@ void sync_buffer(int cpu) break; if (is_code(sample->eip)) { - switch (sample->event) { - case 0: - case CPU_IS_KERNEL: + flags = sample->event; + if (flags & TRACE_BEGIN) { + state = sb_bt_start; + add_trace_begin(); + } + if (flags & KERNEL_CTX_SWITCH) { /* kernel/userspace switch */ - in_kernel = sample->event; + in_kernel = flags & IS_KERNEL; if (state == sb_buffer_start) state = sb_sample_start; - add_kernel_ctx_switch(sample->event); - break; - case CPU_TRACE_BEGIN: - state = sb_bt_start; - add_trace_begin(); - break; -#ifdef CONFIG_OPROFILE_IBS - case IBS_FETCH_BEGIN: - add_ibs_begin(cpu, IBS_FETCH_CODE, mm); - break; - case IBS_OP_BEGIN: - add_ibs_begin(cpu, IBS_OP_CODE, mm); - break; -#endif - default: + add_kernel_ctx_switch(flags & IS_KERNEL); + } + if (flags & USER_CTX_SWITCH) { /* userspace context switch */ oldmm = mm; - new = (struct task_struct *)sample->event; + new = (struct task_struct *)sample->data[0]; release_mm(oldmm); mm = take_tasks_mm(new); if (mm != oldmm) cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); - break; } +#ifdef CONFIG_OPROFILE_IBS + if (flags & IBS_FETCH_BEGIN) + add_ibs_begin(cpu, IBS_FETCH_CODE, mm); + if (flags & IBS_OP_BEGIN) + add_ibs_begin(cpu, IBS_OP_CODE, mm); +#endif continue; } -- 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/buffer_sync.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index d969bb13a252..f9031d31eeb7 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -524,6 +524,7 @@ void sync_buffer(int cpu) { struct mm_struct *mm = NULL; struct mm_struct *oldmm; + unsigned long val; struct task_struct *new; unsigned long cookie = 0; int in_kernel = 1; @@ -559,10 +560,11 @@ void sync_buffer(int cpu) state = sb_sample_start; add_kernel_ctx_switch(flags & IS_KERNEL); } - if (flags & USER_CTX_SWITCH) { + if (flags & USER_CTX_SWITCH + && op_cpu_buffer_get_data(&entry, &val)) { /* userspace context switch */ + new = (struct task_struct *)val; oldmm = mm; - new = (struct task_struct *)sample->data[0]; release_mm(oldmm); mm = take_tasks_mm(new); if (mm != oldmm) -- 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/buffer_sync.c | 53 ++++++++++-------------------------------- 1 file changed, 12 insertions(+), 41 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index f9031d31eeb7..d692fdc1a211 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -318,29 +318,18 @@ static void add_trace_begin(void) #ifdef CONFIG_OPROFILE_IBS -#define IBS_FETCH_CODE_SIZE 2 -#define IBS_OP_CODE_SIZE 5 - -/* - * Add IBS fetch and op entries to event buffer - */ -static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) +static void add_data(struct op_entry *entry, struct mm_struct *mm) { - unsigned long pc; - int i, count; - unsigned long cookie = 0; + unsigned long code, pc, val; + unsigned long cookie; off_t offset; - struct op_entry entry; - struct op_sample *sample; - sample = op_cpu_buffer_read_entry(&entry, cpu); - if (!sample) + if (!op_cpu_buffer_get_data(entry, &code)) + return; + if (!op_cpu_buffer_get_data(entry, &pc)) + return; + if (!op_cpu_buffer_get_size(entry)) return; - pc = sample->eip; - -#ifdef __LP64__ - pc += sample->event << 32; -#endif if (mm) { cookie = lookup_dcookie(mm, pc, &offset); @@ -362,24 +351,8 @@ static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) add_event_entry(code); add_event_entry(offset); /* Offset from Dcookie */ - /* we send the Dcookie offset, but send the raw Linear Add also*/ - add_event_entry(sample->eip); - add_event_entry(sample->event); - - if (code == IBS_FETCH_CODE) - count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ - else - count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ - - for (i = 0; i < count; i++) { - sample = op_cpu_buffer_read_entry(&entry, cpu); - if (!sample) - return; - add_event_entry(sample->eip); - add_event_entry(sample->event); - } - - return; + while (op_cpu_buffer_get_data(entry, &val)) + add_event_entry(val); } #endif @@ -572,10 +545,8 @@ void sync_buffer(int cpu) add_user_ctx_switch(new, cookie); } #ifdef CONFIG_OPROFILE_IBS - if (flags & IBS_FETCH_BEGIN) - add_ibs_begin(cpu, IBS_FETCH_CODE, mm); - if (flags & IBS_OP_BEGIN) - add_ibs_begin(cpu, IBS_OP_CODE, mm); + if (op_cpu_buffer_get_size(&entry)) + add_data(&entry, mm); #endif continue; } -- cgit v1.2.2 From ebf8d974e298018f0b4ee02b1b097bf5500d3d27 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Jan 2009 00:20:57 +0100 Subject: oprofile: remove #ifdef CONFIG_OPROFILE_IBS in non-ibs code The ifdefs can be removed since the code is no longer ibs specific and can be used for other purposes as well. IBS specific code is only in op_model_amd.c. Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/oprofile/buffer_sync.c') diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index d692fdc1a211..ac014cb27915 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -316,8 +316,6 @@ static void add_trace_begin(void) add_event_entry(TRACE_BEGIN_CODE); } -#ifdef CONFIG_OPROFILE_IBS - static void add_data(struct op_entry *entry, struct mm_struct *mm) { unsigned long code, pc, val; @@ -355,8 +353,6 @@ static void add_data(struct op_entry *entry, struct mm_struct *mm) add_event_entry(val); } -#endif - static inline void add_sample_entry(unsigned long offset, unsigned long event) { add_event_entry(offset); @@ -544,10 +540,8 @@ void sync_buffer(int cpu) cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); } -#ifdef CONFIG_OPROFILE_IBS if (op_cpu_buffer_get_size(&entry)) add_data(&entry, mm); -#endif continue; } -- cgit v1.2.2