From fd13f6c85144bb2026c534a35be1d7cb7628a64a Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 19 Oct 2008 21:00:09 +0200 Subject: oprofile: comment cleanup This fixes the coding style of some comments. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 31 ++++++++++++++++--------------- drivers/oprofile/cpu_buffer.c | 25 ++++++++++++++++--------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 509513760a6..fb67e1999d8 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -65,8 +65,10 @@ static unsigned long reset_value[NUM_COUNTERS]; #define IBS_FETCH_BEGIN 3 #define IBS_OP_BEGIN 4 -/* The function interface needs to be fixed, something like add - data. Should then be added to linux/oprofile.h. */ +/* + * The function interface needs to be fixed, something like add + * data. Should then be added to linux/oprofile.h. + */ extern void oprofile_add_ibs_sample(struct pt_regs *const regs, unsigned int *const ibs_sample, int ibs_code); @@ -106,7 +108,7 @@ struct ibs_op_sample { /* * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+ -*/ + */ static void clear_ibs_nmi(void); static int ibs_allowed; /* AMD Family10h and later */ @@ -223,7 +225,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, (unsigned int *)&ibs_fetch, IBS_FETCH_BEGIN); - /*reenable the IRQ */ + /* reenable the IRQ */ rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); high &= ~IBS_FETCH_HIGH_VALID_BIT; high |= IBS_FETCH_HIGH_ENABLE; @@ -331,8 +333,10 @@ static void op_amd_stop(struct op_msrs const * const msrs) unsigned int low, high; int i; - /* Subtle: stop on all counters to avoid race with - * setting our pm callback */ + /* + * Subtle: stop on all counters to avoid race with setting our + * pm callback + */ for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (!reset_value[i]) continue; @@ -343,13 +347,15 @@ static void op_amd_stop(struct op_msrs const * const msrs) #ifdef CONFIG_OPROFILE_IBS if (ibs_allowed && ibs_config.fetch_enabled) { - low = 0; /* clear max count and enable */ + /* clear max count and enable */ + low = 0; high = 0; wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); } if (ibs_allowed && ibs_config.op_enabled) { - low = 0; /* clear max count and enable */ + /* clear max count and enable */ + low = 0; high = 0; wrmsr(MSR_AMD64_IBSOPCTL, low, high); } @@ -443,10 +449,7 @@ static int pfm_amd64_setup_eilvt(void) return 0; } -/* - * initialize the APIC for the IBS interrupts - * if available (AMD Family10h rev B0 and later) - */ +/* initialize the APIC for the IBS interrupts if available */ static void setup_ibs(void) { ibs_allowed = boot_cpu_has(X86_FEATURE_IBS); @@ -463,9 +466,7 @@ static void setup_ibs(void) } -/* - * unitialize the APIC for the IBS interrupts if needed on AMD Family10h - * rev B0 and later */ +/* uninitialize the APIC for the IBS interrupts if needed */ static void clear_ibs_nmi(void) { if (ibs_allowed) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 01d38e78cde..3958107723f 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -127,9 +127,10 @@ void end_cpu_work(void) /* Resets the cpu buffer to a sane state. */ void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf) { - /* reset these to invalid values; the next sample - * collected will populate the buffer with proper - * values to initialize the buffer + /* + * reset these to invalid values; the next sample collected + * will populate the buffer with proper values to initialize + * the buffer */ cpu_buf->last_is_kernel = -1; cpu_buf->last_task = NULL; @@ -151,8 +152,10 @@ static void increment_head(struct oprofile_cpu_buffer *b) { unsigned long new_head = b->head_pos + 1; - /* Ensure anything written to the slot before we - * increment is visible */ + /* + * Ensure anything written to the slot before we increment is + * visible + */ wmb(); if (new_head < b->buffer_size) @@ -253,8 +256,10 @@ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, if (!oprofile_begin_trace(cpu_buf)) return; - /* if log_sample() fail we can't backtrace since we lost the source - * of this event */ + /* + * if log_sample() fail we can't backtrace since we lost the + * source of this event + */ if (log_sample(cpu_buf, pc, is_kernel, event)) oprofile_ops.backtrace(regs, backtrace_depth); oprofile_end_trace(cpu_buf); @@ -338,8 +343,10 @@ void oprofile_add_trace(unsigned long pc) return; } - /* broken frame can give an eip with the same value as an escape code, - * abort the trace if we get it */ + /* + * broken frame can give an eip with the same value as an + * escape code, abort the trace if we get it + */ if (pc == ESCAPE_CODE) { cpu_buf->tracing = 0; cpu_buf->backtrace_aborted++; -- cgit v1.2.3 From 58494487581cb143a0d763e3056a894d5009d60a Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 26 Nov 2008 12:02:53 +0100 Subject: oprofile: update comment for oprofile_add_sample() The cpu argument is no longer part of the parameter list. Signed-off-by: Robert Richter --- include/linux/oprofile.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 5231861f357..1ce9fe572e5 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -86,8 +86,7 @@ int oprofile_arch_init(struct oprofile_operations * ops); void oprofile_arch_exit(void); /** - * Add a sample. This may be called from any context. Pass - * smp_processor_id() as cpu. + * Add a sample. This may be called from any context. */ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event); -- cgit v1.2.3 From cdc1834d1aa2e5b574a25e66f82625b44cdd0d8f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 26 Sep 2008 22:18:44 -0400 Subject: oprofile: whitspace changes only Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 4 ++-- drivers/oprofile/cpu_buffer.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index fb67e1999d8..f71bd218b48 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -70,8 +70,8 @@ static unsigned long reset_value[NUM_COUNTERS]; * data. Should then be added to linux/oprofile.h. */ extern void -oprofile_add_ibs_sample(struct pt_regs *const regs, - unsigned int *const ibs_sample, int ibs_code); +oprofile_add_ibs_sample(struct pt_regs * const regs, + unsigned int * const ibs_sample, int ibs_code); struct ibs_fetch_sample { /* MSRC001_1031 IBS Fetch Linear Address Register */ diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 3958107723f..2c4d54187b9 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -277,8 +277,8 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) #define MAX_IBS_SAMPLE_SIZE 14 -void oprofile_add_ibs_sample(struct pt_regs *const regs, - unsigned int *const ibs_sample, int ibs_code) +void oprofile_add_ibs_sample(struct pt_regs * const regs, + unsigned int * const ibs_sample, int ibs_code) { int is_kernel = !user_mode(regs); struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); -- cgit v1.2.3 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(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b55cd23ffde..774b081b9b7 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.3 From 9fa6812dbab9207f7af52c3d0417f1f9eb89c386 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 24 Nov 2008 14:21:03 +0100 Subject: x86/oprofile: reordering IBS code in op_model_amd.c This is part of the cpu buffer rework. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index f71bd218b48..8ff657b3ff8 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -376,18 +376,7 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) } } -#ifndef CONFIG_OPROFILE_IBS - -/* no IBS support */ - -static int op_amd_init(struct oprofile_operations *ops) -{ - return 0; -} - -static void op_amd_exit(void) {} - -#else +#ifdef CONFIG_OPROFILE_IBS static u8 ibs_eilvt_off; @@ -531,7 +520,18 @@ static void op_amd_exit(void) clear_ibs_nmi(); } -#endif +#else + +/* no IBS support */ + +static int op_amd_init(struct oprofile_operations *ops) +{ + return 0; +} + +static void op_amd_exit(void) {} + +#endif /* CONFIG_OPROFILE_IBS */ struct op_x86_model_spec const op_amd_spec = { .init = op_amd_init, -- cgit v1.2.3 From fe615cbf34fc6a1c53c359417da4696328a488ed Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 24 Nov 2008 14:58:03 +0100 Subject: x86/oprofile: cleanup IBS init/exit functions in op_model_amd.c Implementation of pairwise init/exit funcions for IBS and IBS NMI setup. There are also some function renames and the removal of forward function declarations. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 8ff657b3ff8..98658f25f54 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -106,11 +106,6 @@ struct ibs_op_sample { unsigned int ibs_dc_phys_high; }; -/* - * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+ - */ -static void clear_ibs_nmi(void); - static int ibs_allowed; /* AMD Family10h and later */ struct op_ibs_config { @@ -390,7 +385,7 @@ static inline void apic_clear_ibs_nmi_per_cpu(void *arg) setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); } -static int pfm_amd64_setup_eilvt(void) +static int init_ibs_nmi(void) { #define IBSCTL_LVTOFFSETVAL (1 << 8) #define IBSCTL 0x1cc @@ -438,15 +433,22 @@ static int pfm_amd64_setup_eilvt(void) return 0; } +/* uninitialize the APIC for the IBS interrupts if needed */ +static void clear_ibs_nmi(void) +{ + if (ibs_allowed) + on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); +} + /* initialize the APIC for the IBS interrupts if available */ -static void setup_ibs(void) +static void ibs_init(void) { ibs_allowed = boot_cpu_has(X86_FEATURE_IBS); if (!ibs_allowed) return; - if (pfm_amd64_setup_eilvt()) { + if (init_ibs_nmi()) { ibs_allowed = 0; return; } @@ -454,12 +456,12 @@ static void setup_ibs(void) printk(KERN_INFO "oprofile: AMD IBS detected\n"); } - -/* uninitialize the APIC for the IBS interrupts if needed */ -static void clear_ibs_nmi(void) +static void ibs_exit(void) { - if (ibs_allowed) - on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); + if (!ibs_allowed) + return; + + clear_ibs_nmi(); } static int (*create_arch_files)(struct super_block *sb, struct dentry *root); @@ -509,7 +511,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) static int op_amd_init(struct oprofile_operations *ops) { - setup_ibs(); + ibs_init(); create_arch_files = ops->create_files; ops->create_files = setup_ibs_files; return 0; @@ -517,7 +519,7 @@ static int op_amd_init(struct oprofile_operations *ops) static void op_amd_exit(void) { - clear_ibs_nmi(); + ibs_exit(); } #else -- cgit v1.2.3 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(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 774b081b9b7..7d61ae8ee8c 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.3 From 37ca5eb341711d7aeb9f296873b9d46eb6af33ec Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 9 Dec 2008 16:56:01 +0100 Subject: oprofile: set values to default when creating oprofilefs This patch restores default values for: /dev/oprofile/cpu_buffer_size /dev/oprofile/buffer_watershed /dev/oprofile/buffer_size when creating the oprofilefs: # opcontrol --deinit # opcontrol --init # cat /dev/oprofile/cpu_buffer_size 8192 # echo 5123 > /dev/oprofile/cpu_buffer_size # cat /dev/oprofile/cpu_buffer_size 5123 # opcontrol --deinit # opcontrol --init # cat /dev/oprofile/cpu_buffer_size 8192 # opcontrol --deinit This sets the values in a defined state. Before, there was no way to restore the defaults without rebooting the system or reloading the module. Signed-off-by: Robert Richter --- drivers/oprofile/oprofile_files.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index cc106d503ac..d8201998b0b 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -14,9 +14,13 @@ #include "oprofile_stats.h" #include "oprof.h" -unsigned long fs_buffer_size = 131072; -unsigned long fs_cpu_buffer_size = 8192; -unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ +#define FS_BUFFER_SIZE_DEFAULT 131072 +#define FS_CPU_BUFFER_SIZE_DEFAULT 8192 +#define FS_BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ + +unsigned long fs_buffer_size; +unsigned long fs_cpu_buffer_size; +unsigned long fs_buffer_watershed; static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { @@ -120,6 +124,11 @@ static const struct file_operations dump_fops = { void oprofile_create_files(struct super_block *sb, struct dentry *root) { + /* reinitialize default values */ + fs_buffer_size = FS_BUFFER_SIZE_DEFAULT; + fs_cpu_buffer_size = FS_CPU_BUFFER_SIZE_DEFAULT; + fs_buffer_watershed = FS_BUFFER_WATERSHED_DEFAULT; + oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops); -- cgit v1.2.3 From 68814b58c52077da9561b544089fe532a0842f71 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 24 Nov 2008 12:24:12 +0100 Subject: ring_buffer: update description for ring_buffer_alloc() Trivial patch. Cc: Steven Rostedt Signed-off-by: Robert Richter --- kernel/trace/ring_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 668bbb5ef2b..c8996d239e4 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -381,7 +381,7 @@ extern int ring_buffer_page_too_big(void); /** * ring_buffer_alloc - allocate a new ring_buffer - * @size: the size in bytes that is needed. + * @size: the size in bytes per cpu that is needed. * @flags: attributes to set for the ring buffer. * * Currently the only flag that is available is the RB_FL_OVERWRITE -- cgit v1.2.3 From e2ac8ef576e45d9db7264abc51383e68d26067bb Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 12 Nov 2008 12:59:32 +0100 Subject: ftrace: remove unused function arg in trace_iterator_increment() This removes the unused cpu function parameter. Cc: Steven Rostedt Signed-off-by: Robert Richter --- kernel/trace/trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index d86e3252f30..a96b335fe75 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -914,7 +914,7 @@ enum trace_file_type { TRACE_FILE_LAT_FMT = 1, }; -static void trace_iterator_increment(struct trace_iterator *iter, int cpu) +static void trace_iterator_increment(struct trace_iterator *iter) { /* Don't allow ftrace to trace into the ring buffers */ ftrace_disable_cpu(); @@ -993,7 +993,7 @@ static void *find_next_entry_inc(struct trace_iterator *iter) iter->ent = __find_next_entry(iter, &iter->cpu, &iter->ts); if (iter->ent) - trace_iterator_increment(iter, iter->cpu); + trace_iterator_increment(iter); return iter->ent ? iter : NULL; } -- cgit v1.2.3 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 +++++++++----------- drivers/oprofile/cpu_buffer.c | 2 +- drivers/oprofile/cpu_buffer.h | 12 ++++++++++++ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 7d61ae8ee8c..44f676c8a51 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) { diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 2c4d54187b9..7e5e650e409 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -168,7 +168,7 @@ static inline void add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) { - struct op_sample *entry = &cpu_buf->buffer[cpu_buf->head_pos]; + struct op_sample *entry = cpu_buffer_write_entry(cpu_buf); entry->eip = pc; entry->event = event; increment_head(cpu_buf); diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index d3cc26264db..08706991fdd 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.3 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.c | 18 +----------------- drivers/oprofile/cpu_buffer.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 7e5e650e409..d6f5de68636 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -148,22 +148,6 @@ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const *b) return tail + (b->buffer_size - head) - 1; } -static void increment_head(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 void add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) @@ -171,7 +155,7 @@ add_sample(struct oprofile_cpu_buffer *cpu_buf, struct op_sample *entry = cpu_buffer_write_entry(cpu_buf); entry->eip = pc; entry->event = event; - increment_head(cpu_buf); + cpu_buffer_write_commit(cpu_buf); } static inline void diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 08706991fdd..e6089768ae6 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.3 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 ++----------------------------- drivers/oprofile/cpu_buffer.h | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 44f676c8a51..aed286c3f16 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); diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index e6089768ae6..6055b567839 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.3 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 + drivers/oprofile/cpu_buffer.c | 12 ------------ drivers/oprofile/cpu_buffer.h | 28 +++++++++++++--------------- 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index aed286c3f16..944a5832d9e 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); diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index d6f5de68636..5cf7efe38e6 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -124,18 +124,6 @@ void end_cpu_work(void) flush_scheduled_work(); } -/* Resets the cpu buffer to a sane state. */ -void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf) -{ - /* - * reset these to invalid values; the next sample collected - * will populate the buffer with proper values to initialize - * the buffer - */ - cpu_buf->last_is_kernel = -1; - cpu_buf->last_task = NULL; -} - /* compute number of available slots in cpu_buffer queue */ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const *b) { diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 6055b567839..895763f065e 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.3 From e09373f22e76cc048ca5fe10a9ff9012f5d64309 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 26 Nov 2008 14:04:19 +0100 Subject: ring_buffer: add remaining cpu functions to ring_buffer.h These functions are not yet in ring_buffer.h though they seems to be part of the API. Cc: Steven Rostedt Signed-off-by: Robert Richter --- include/linux/ring_buffer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index e097c2e6b6d..de9d8c12e5e 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -116,6 +116,8 @@ void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); unsigned long ring_buffer_entries(struct ring_buffer *buffer); unsigned long ring_buffer_overruns(struct ring_buffer *buffer); +unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu); +unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); u64 ring_buffer_time_stamp(int cpu); void ring_buffer_normalize_time_stamp(int cpu, u64 *ts); -- cgit v1.2.3 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 +++++++++++++++----------------------- drivers/oprofile/cpu_buffer.c | 63 ++++++++++++++++++++++++++++--------- drivers/oprofile/cpu_buffer.h | 71 ++++++++++++++++++++++++------------------ 3 files changed, 114 insertions(+), 85 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 944a5832d9e..737bd948482 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); diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 5cf7efe38e6..eb280ec96e2 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -28,6 +28,25 @@ #include "buffer_sync.h" #include "oprof.h" +#define OP_BUFFER_FLAGS 0 + +/* + * 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. + */ +struct ring_buffer *op_ring_buffer_read; +struct ring_buffer *op_ring_buffer_write; DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); static void wq_sync_buffer(struct work_struct *work); @@ -37,12 +56,12 @@ static int work_enabled; void free_cpu_buffers(void) { - int i; - - for_each_possible_cpu(i) { - vfree(per_cpu(cpu_buffer, i).buffer); - per_cpu(cpu_buffer, i).buffer = NULL; - } + if (op_ring_buffer_read) + ring_buffer_free(op_ring_buffer_read); + op_ring_buffer_read = NULL; + if (op_ring_buffer_write) + ring_buffer_free(op_ring_buffer_write); + op_ring_buffer_write = NULL; } unsigned long oprofile_get_cpu_buffer_size(void) @@ -64,14 +83,16 @@ int alloc_cpu_buffers(void) unsigned long buffer_size = fs_cpu_buffer_size; + op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS); + if (!op_ring_buffer_read) + goto fail; + op_ring_buffer_write = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS); + if (!op_ring_buffer_write) + goto fail; + for_each_possible_cpu(i) { struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); - b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, - cpu_to_node(i)); - if (!b->buffer) - goto fail; - b->last_task = NULL; b->last_is_kernel = -1; b->tracing = 0; @@ -140,10 +161,22 @@ static inline void add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) { - struct op_sample *entry = cpu_buffer_write_entry(cpu_buf); - entry->eip = pc; - entry->event = event; - cpu_buffer_write_commit(cpu_buf); + struct op_entry entry; + + if (cpu_buffer_write_entry(&entry)) + goto Error; + + entry.sample->eip = pc; + entry.sample->event = event; + + if (cpu_buffer_write_commit(&entry)) + goto Error; + + return; + +Error: + cpu_buf->sample_lost_overflow++; + return; } static inline void diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 895763f065e..aacb0f0bc56 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.3 From 1d7503b5dccf2b95babca050e4960e10d2633f2b Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 8 Dec 2008 11:59:52 +0100 Subject: oprofile: remove nr_available_slots() This function is no longer available after the port to the new ring buffer. Its removal can lead to incomplete sampling sequences since IBS samples and backtraces are transfered in multiple samples. Due to a full buffer, samples could be lost any time. The userspace daemon has to live with such incomplete sampling sequences as long as the data within one sample is consistent. This will be fixed by changing the internal buffer data there all data of one IBS sample or a backtrace is packed in a single ring buffer entry. This is possible since the new ring buffer supports variable data size. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index eb280ec96e2..7f7fc958297 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -145,18 +145,6 @@ void end_cpu_work(void) flush_scheduled_work(); } -/* compute number of available slots in cpu_buffer queue */ -static unsigned long nr_available_slots(struct oprofile_cpu_buffer const *b) -{ - unsigned long head = b->head_pos; - unsigned long tail = b->tail_pos; - - if (tail > head) - return (tail - head) - 1; - - return tail + (b->buffer_size - head) - 1; -} - static inline void add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) @@ -206,11 +194,6 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, return 0; } - if (nr_available_slots(cpu_buf) < 3) { - cpu_buf->sample_lost_overflow++; - return 0; - } - is_kernel = !!is_kernel; task = current; @@ -233,11 +216,6 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) { - if (nr_available_slots(cpu_buf) < 4) { - cpu_buf->sample_lost_overflow++; - return 0; - } - add_code(cpu_buf, CPU_TRACE_BEGIN); cpu_buf->tracing = 1; return 1; @@ -291,12 +269,6 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs, cpu_buf->sample_received++; - if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) { - /* we can't backtrace since we lost the source of this event */ - cpu_buf->sample_lost_overflow++; - return; - } - /* notice a switch from user->kernel or vice versa */ if (cpu_buf->last_is_kernel != is_kernel) { cpu_buf->last_is_kernel = is_kernel; @@ -342,12 +314,6 @@ void oprofile_add_trace(unsigned long pc) if (!cpu_buf->tracing) return; - if (nr_available_slots(cpu_buf) < 1) { - cpu_buf->tracing = 0; - cpu_buf->sample_lost_overflow++; - return; - } - /* * broken frame can give an eip with the same value as an * escape code, abort the trace if we get it -- cgit v1.2.3 From 211117ff09b7d81d91b7857651587128ed8b13d9 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 9 Dec 2008 02:13:25 +0100 Subject: oprofile: fix lost sample counter The number of lost samples could be greater than the number of received samples. This patches fixes this. The implementation introduces return values for add_sample() and add_code(). Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 83 +++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 7f7fc958297..61090969158 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -145,32 +145,31 @@ void end_cpu_work(void) flush_scheduled_work(); } -static inline void +static inline int add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) { struct op_entry entry; + int ret; - if (cpu_buffer_write_entry(&entry)) - goto Error; + ret = cpu_buffer_write_entry(&entry); + if (ret) + return ret; entry.sample->eip = pc; entry.sample->event = event; - if (cpu_buffer_write_commit(&entry)) - goto Error; + ret = cpu_buffer_write_commit(&entry); + if (ret) + return ret; - return; - -Error: - cpu_buf->sample_lost_overflow++; - return; + return 0; } -static inline void +static inline int add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) { - add_sample(buffer, ESCAPE_CODE, value); + return add_sample(buffer, ESCAPE_CODE, value); } /* This must be safe from any context. It's safe writing here @@ -201,17 +200,25 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, /* notice a switch from user->kernel or vice versa */ if (cpu_buf->last_is_kernel != is_kernel) { cpu_buf->last_is_kernel = is_kernel; - add_code(cpu_buf, is_kernel); + if (add_code(cpu_buf, is_kernel)) + goto fail; } /* notice a task switch */ if (cpu_buf->last_task != task) { cpu_buf->last_task = task; - add_code(cpu_buf, (unsigned long)task); + if (add_code(cpu_buf, (unsigned long)task)) + goto fail; } - add_sample(cpu_buf, pc, event); + if (add_sample(cpu_buf, pc, event)) + goto fail; + return 1; + +fail: + cpu_buf->sample_lost_overflow++; + return 0; } static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) @@ -266,37 +273,49 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs, int is_kernel = !user_mode(regs); struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); struct task_struct *task; + int fail = 0; cpu_buf->sample_received++; /* notice a switch from user->kernel or vice versa */ if (cpu_buf->last_is_kernel != is_kernel) { + if (add_code(cpu_buf, is_kernel)) + goto fail; cpu_buf->last_is_kernel = is_kernel; - add_code(cpu_buf, is_kernel); } /* notice a task switch */ if (!is_kernel) { task = current; if (cpu_buf->last_task != task) { + if (add_code(cpu_buf, (unsigned long)task)) + goto fail; cpu_buf->last_task = task; - add_code(cpu_buf, (unsigned long)task); } } - add_code(cpu_buf, ibs_code); - add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); - add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); - add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); + fail = fail || add_code(cpu_buf, ibs_code); + fail = fail || add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); + fail = fail || add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); + fail = fail || add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); if (ibs_code == IBS_OP_BEGIN) { - add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); - add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); - add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); + fail = fail || add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); + fail = fail || add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); + fail = fail || add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); } + if (fail) + goto fail; + if (backtrace_depth) oprofile_ops.backtrace(regs, backtrace_depth); + + return; + +fail: + cpu_buf->sample_lost_overflow++; + return; } #endif @@ -318,13 +337,17 @@ void oprofile_add_trace(unsigned long pc) * broken frame can give an eip with the same value as an * escape code, abort the trace if we get it */ - if (pc == ESCAPE_CODE) { - cpu_buf->tracing = 0; - cpu_buf->backtrace_aborted++; - return; - } + if (pc == ESCAPE_CODE) + goto fail; + + if (add_sample(cpu_buf, pc, 0)) + goto fail; - add_sample(cpu_buf, pc, 0); + return; +fail: + cpu_buf->tracing = 0; + cpu_buf->backtrace_aborted++; + return; } /* -- cgit v1.2.3 From c4f50183f90fb1fd99aa5941f01b90cd1b882d2e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 11 Dec 2008 16:49:22 +0100 Subject: ring_buffer: adding EXPORT_SYMBOLs I added EXPORT_SYMBOL_GPLs for all functions part of the API (ring_buffer.h). This is required since oprofile is using the ring buffer and the compilation as modules would fail otherwise. Signed-off-by: Robert Richter Signed-off-by: Ingo Molnar --- kernel/trace/ring_buffer.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index c8996d239e4..30d57dd01a8 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -31,6 +31,7 @@ void tracing_on(void) { ring_buffers_off = 0; } +EXPORT_SYMBOL_GPL(tracing_on); /** * tracing_off - turn off all tracing buffers @@ -44,6 +45,7 @@ void tracing_off(void) { ring_buffers_off = 1; } +EXPORT_SYMBOL_GPL(tracing_off); /* Up this if you want to test the TIME_EXTENTS and normalization */ #define DEBUG_SHIFT 0 @@ -60,12 +62,14 @@ u64 ring_buffer_time_stamp(int cpu) return time; } +EXPORT_SYMBOL_GPL(ring_buffer_time_stamp); void ring_buffer_normalize_time_stamp(int cpu, u64 *ts) { /* Just stupid testing the normalize function and deltas */ *ts >>= DEBUG_SHIFT; } +EXPORT_SYMBOL_GPL(ring_buffer_normalize_time_stamp); #define RB_EVNT_HDR_SIZE (sizeof(struct ring_buffer_event)) #define RB_ALIGNMENT_SHIFT 2 @@ -115,6 +119,7 @@ unsigned ring_buffer_event_length(struct ring_buffer_event *event) { return rb_event_length(event); } +EXPORT_SYMBOL_GPL(ring_buffer_event_length); /* inline for ring buffer fast paths */ static inline void * @@ -136,6 +141,7 @@ void *ring_buffer_event_data(struct ring_buffer_event *event) { return rb_event_data(event); } +EXPORT_SYMBOL_GPL(ring_buffer_event_data); #define for_each_buffer_cpu(buffer, cpu) \ for_each_cpu_mask(cpu, buffer->cpumask) @@ -444,6 +450,7 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags) kfree(buffer); return NULL; } +EXPORT_SYMBOL_GPL(ring_buffer_alloc); /** * ring_buffer_free - free a ring buffer. @@ -459,6 +466,7 @@ ring_buffer_free(struct ring_buffer *buffer) kfree(buffer); } +EXPORT_SYMBOL_GPL(ring_buffer_free); static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer); @@ -620,6 +628,7 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size) mutex_unlock(&buffer->mutex); return -ENOMEM; } +EXPORT_SYMBOL_GPL(ring_buffer_resize); static inline int rb_null_event(struct ring_buffer_event *event) { @@ -1220,6 +1229,7 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, preempt_enable_notrace(); return NULL; } +EXPORT_SYMBOL_GPL(ring_buffer_lock_reserve); static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event) @@ -1269,6 +1279,7 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer, return 0; } +EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit); /** * ring_buffer_write - write data to the buffer without reserving @@ -1334,6 +1345,7 @@ int ring_buffer_write(struct ring_buffer *buffer, return ret; } +EXPORT_SYMBOL_GPL(ring_buffer_write); static inline int rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer) { @@ -1360,6 +1372,7 @@ void ring_buffer_record_disable(struct ring_buffer *buffer) { atomic_inc(&buffer->record_disabled); } +EXPORT_SYMBOL_GPL(ring_buffer_record_disable); /** * ring_buffer_record_enable - enable writes to the buffer @@ -1372,6 +1385,7 @@ void ring_buffer_record_enable(struct ring_buffer *buffer) { atomic_dec(&buffer->record_disabled); } +EXPORT_SYMBOL_GPL(ring_buffer_record_enable); /** * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer @@ -1393,6 +1407,7 @@ void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu) cpu_buffer = buffer->buffers[cpu]; atomic_inc(&cpu_buffer->record_disabled); } +EXPORT_SYMBOL_GPL(ring_buffer_record_disable_cpu); /** * ring_buffer_record_enable_cpu - enable writes to the buffer @@ -1412,6 +1427,7 @@ void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu) cpu_buffer = buffer->buffers[cpu]; atomic_dec(&cpu_buffer->record_disabled); } +EXPORT_SYMBOL_GPL(ring_buffer_record_enable_cpu); /** * ring_buffer_entries_cpu - get the number of entries in a cpu buffer @@ -1428,6 +1444,7 @@ unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu) cpu_buffer = buffer->buffers[cpu]; return cpu_buffer->entries; } +EXPORT_SYMBOL_GPL(ring_buffer_entries_cpu); /** * ring_buffer_overrun_cpu - get the number of overruns in a cpu_buffer @@ -1444,6 +1461,7 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu) cpu_buffer = buffer->buffers[cpu]; return cpu_buffer->overrun; } +EXPORT_SYMBOL_GPL(ring_buffer_overrun_cpu); /** * ring_buffer_entries - get the number of entries in a buffer @@ -1466,6 +1484,7 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer) return entries; } +EXPORT_SYMBOL_GPL(ring_buffer_entries); /** * ring_buffer_overrun_cpu - get the number of overruns in buffer @@ -1488,6 +1507,7 @@ unsigned long ring_buffer_overruns(struct ring_buffer *buffer) return overruns; } +EXPORT_SYMBOL_GPL(ring_buffer_overruns); /** * ring_buffer_iter_reset - reset an iterator @@ -1513,6 +1533,7 @@ void ring_buffer_iter_reset(struct ring_buffer_iter *iter) else iter->read_stamp = iter->head_page->time_stamp; } +EXPORT_SYMBOL_GPL(ring_buffer_iter_reset); /** * ring_buffer_iter_empty - check if an iterator has no more to read @@ -1527,6 +1548,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter) return iter->head_page == cpu_buffer->commit_page && iter->head == rb_commit_index(cpu_buffer); } +EXPORT_SYMBOL_GPL(ring_buffer_iter_empty); static void rb_update_read_stamp(struct ring_buffer_per_cpu *cpu_buffer, @@ -1797,6 +1819,7 @@ ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts) return NULL; } +EXPORT_SYMBOL_GPL(ring_buffer_peek); /** * ring_buffer_iter_peek - peek at the next event to be read @@ -1867,6 +1890,7 @@ ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts) return NULL; } +EXPORT_SYMBOL_GPL(ring_buffer_iter_peek); /** * ring_buffer_consume - return an event and consume it @@ -1894,6 +1918,7 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts) return event; } +EXPORT_SYMBOL_GPL(ring_buffer_consume); /** * ring_buffer_read_start - start a non consuming read of the buffer @@ -1934,6 +1959,7 @@ ring_buffer_read_start(struct ring_buffer *buffer, int cpu) return iter; } +EXPORT_SYMBOL_GPL(ring_buffer_read_start); /** * ring_buffer_finish - finish reading the iterator of the buffer @@ -1950,6 +1976,7 @@ ring_buffer_read_finish(struct ring_buffer_iter *iter) atomic_dec(&cpu_buffer->record_disabled); kfree(iter); } +EXPORT_SYMBOL_GPL(ring_buffer_read_finish); /** * ring_buffer_read - read the next item in the ring buffer by the iterator @@ -1971,6 +1998,7 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts) return event; } +EXPORT_SYMBOL_GPL(ring_buffer_read); /** * ring_buffer_size - return the size of the ring buffer (in bytes) @@ -1980,6 +2008,7 @@ unsigned long ring_buffer_size(struct ring_buffer *buffer) { return BUF_PAGE_SIZE * buffer->pages; } +EXPORT_SYMBOL_GPL(ring_buffer_size); static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer) @@ -2022,6 +2051,7 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu) spin_unlock_irqrestore(&cpu_buffer->lock, flags); } +EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu); /** * ring_buffer_reset - reset a ring buffer @@ -2034,6 +2064,7 @@ void ring_buffer_reset(struct ring_buffer *buffer) for_each_buffer_cpu(buffer, cpu) ring_buffer_reset_cpu(buffer, cpu); } +EXPORT_SYMBOL_GPL(ring_buffer_reset); /** * rind_buffer_empty - is the ring buffer empty? @@ -2052,6 +2083,7 @@ int ring_buffer_empty(struct ring_buffer *buffer) } return 1; } +EXPORT_SYMBOL_GPL(ring_buffer_empty); /** * ring_buffer_empty_cpu - is a cpu buffer of a ring buffer empty? @@ -2068,6 +2100,7 @@ int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu) cpu_buffer = buffer->buffers[cpu]; return rb_per_cpu_empty(cpu_buffer); } +EXPORT_SYMBOL_GPL(ring_buffer_empty_cpu); /** * ring_buffer_swap_cpu - swap a CPU buffer between two ring buffers @@ -2117,6 +2150,7 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a, return 0; } +EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu); static ssize_t rb_simple_read(struct file *filp, char __user *ubuf, -- cgit v1.2.3 From d69d59f49763e6bd047c591c6c1f84c8e13da931 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 12 Dec 2008 09:38:57 +0100 Subject: oprofile: select RING_BUFFER Impact: build fix OProfile now depends on the ring buffer infrastructure: arch/x86/oprofile/built-in.o: In function `oprofile_add_ibs_sample': : undefined reference to `ring_buffer_unlock_commit' Select TRACING and RING_BUFFER when oprofile is enabled. Signed-off-by: Ingo Molnar --- arch/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index 471e72dbaf8..2e13aa26192 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -6,6 +6,8 @@ config OPROFILE tristate "OProfile system profiling (EXPERIMENTAL)" depends on PROFILING depends on HAVE_OPROFILE + select TRACING + select RING_BUFFER help OProfile is a profiling system capable of profiling the whole system, include the kernel, kernel modules, libraries, -- cgit v1.2.3 From bd2172f58094b3f8afa017e68f3f0b57577824e1 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 16 Dec 2008 16:19:54 +0100 Subject: oprofile: rename kernel-wide identifiers This patch renames kernel-wide identifiers to something more oprofile specific names. Cc: Andrew Morton Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 12 ++++++------ drivers/oprofile/event_buffer.c | 4 ++-- drivers/oprofile/oprof.c | 4 ++-- drivers/oprofile/oprof.h | 8 ++++---- drivers/oprofile/oprofile_files.c | 27 ++++++++++++++------------- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 61090969158..fcf96f608d8 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -66,7 +66,7 @@ void free_cpu_buffers(void) unsigned long oprofile_get_cpu_buffer_size(void) { - return fs_cpu_buffer_size; + return oprofile_cpu_buffer_size; } void oprofile_cpu_buffer_inc_smpl_lost(void) @@ -81,7 +81,7 @@ int alloc_cpu_buffers(void) { int i; - unsigned long buffer_size = fs_cpu_buffer_size; + unsigned long buffer_size = oprofile_cpu_buffer_size; op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS); if (!op_ring_buffer_read) @@ -238,7 +238,7 @@ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - if (!backtrace_depth) { + if (!oprofile_backtrace_depth) { log_sample(cpu_buf, pc, is_kernel, event); return; } @@ -251,7 +251,7 @@ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, * source of this event */ if (log_sample(cpu_buf, pc, is_kernel, event)) - oprofile_ops.backtrace(regs, backtrace_depth); + oprofile_ops.backtrace(regs, oprofile_backtrace_depth); oprofile_end_trace(cpu_buf); } @@ -308,8 +308,8 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs, if (fail) goto fail; - if (backtrace_depth) - oprofile_ops.backtrace(regs, backtrace_depth); + if (oprofile_backtrace_depth) + oprofile_ops.backtrace(regs, oprofile_backtrace_depth); return; diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index 191a3202cec..2b7ae366ceb 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -73,8 +73,8 @@ int alloc_event_buffer(void) unsigned long flags; spin_lock_irqsave(&oprofilefs_lock, flags); - buffer_size = fs_buffer_size; - buffer_watershed = fs_buffer_watershed; + buffer_size = oprofile_buffer_size; + buffer_watershed = oprofile_buffer_watershed; spin_unlock_irqrestore(&oprofilefs_lock, flags); if (buffer_watershed >= buffer_size) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index cd375907f26..3cffce90f82 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -23,7 +23,7 @@ struct oprofile_operations oprofile_ops; unsigned long oprofile_started; -unsigned long backtrace_depth; +unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); @@ -172,7 +172,7 @@ int oprofile_set_backtrace(unsigned long val) goto out; } - backtrace_depth = val; + oprofile_backtrace_depth = val; out: mutex_unlock(&start_mutex); diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 5df0c21a608..c288d3c24b5 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -21,12 +21,12 @@ void oprofile_stop(void); struct oprofile_operations; -extern unsigned long fs_buffer_size; -extern unsigned long fs_cpu_buffer_size; -extern unsigned long fs_buffer_watershed; +extern unsigned long oprofile_buffer_size; +extern unsigned long oprofile_cpu_buffer_size; +extern unsigned long oprofile_buffer_watershed; extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; -extern unsigned long backtrace_depth; +extern unsigned long oprofile_backtrace_depth; struct super_block; struct dentry; diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index d8201998b0b..5d36ffc30dd 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -14,17 +14,18 @@ #include "oprofile_stats.h" #include "oprof.h" -#define FS_BUFFER_SIZE_DEFAULT 131072 -#define FS_CPU_BUFFER_SIZE_DEFAULT 8192 -#define FS_BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ +#define BUFFER_SIZE_DEFAULT 131072 +#define CPU_BUFFER_SIZE_DEFAULT 8192 +#define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ -unsigned long fs_buffer_size; -unsigned long fs_cpu_buffer_size; -unsigned long fs_buffer_watershed; +unsigned long oprofile_buffer_size; +unsigned long oprofile_cpu_buffer_size; +unsigned long oprofile_buffer_watershed; static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { - return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset); + return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count, + offset); } @@ -125,16 +126,16 @@ static const struct file_operations dump_fops = { void oprofile_create_files(struct super_block *sb, struct dentry *root) { /* reinitialize default values */ - fs_buffer_size = FS_BUFFER_SIZE_DEFAULT; - fs_cpu_buffer_size = FS_CPU_BUFFER_SIZE_DEFAULT; - fs_buffer_watershed = FS_BUFFER_WATERSHED_DEFAULT; + oprofile_buffer_size = BUFFER_SIZE_DEFAULT; + oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; + oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops); - oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size); - oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); - oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_size", &oprofile_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_watershed", &oprofile_buffer_watershed); + oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &oprofile_cpu_buffer_size); oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); -- cgit v1.2.3 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 +++++----- drivers/oprofile/cpu_buffer.c | 4 ++-- drivers/oprofile/cpu_buffer.h | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 737bd948482..d295d92b57f 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; diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index fcf96f608d8..e52c085cd18 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -152,14 +152,14 @@ add_sample(struct oprofile_cpu_buffer *cpu_buf, struct op_entry entry; int ret; - ret = cpu_buffer_write_entry(&entry); + ret = op_cpu_buffer_write_entry(&entry); if (ret) return ret; entry.sample->eip = pc; entry.sample->event = event; - ret = cpu_buffer_write_commit(&entry); + ret = op_cpu_buffer_write_commit(&entry); if (ret) return ret; diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index aacb0f0bc56..83d491e273f 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.3 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.c | 48 +++++++++++++++++++++++++++++++++++++++-- drivers/oprofile/cpu_buffer.h | 50 ++++--------------------------------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index e52c085cd18..cd67d4dd30b 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -45,8 +45,8 @@ * can be changed to a single buffer solution when the ring buffer * access is implemented as non-locking atomic code. */ -struct ring_buffer *op_ring_buffer_read; -struct ring_buffer *op_ring_buffer_write; +static struct ring_buffer *op_ring_buffer_read; +static struct ring_buffer *op_ring_buffer_write; DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); static void wq_sync_buffer(struct work_struct *work); @@ -145,6 +145,50 @@ void end_cpu_work(void) flush_scheduled_work(); } +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; +} + +int op_cpu_buffer_write_commit(struct op_entry *entry) +{ + return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, + entry->irq_flags); +} + +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; +} + +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); +} + static inline int add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 83d491e273f..cd28abc0696 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.3 From 83bd9243956f30d91851b272988a237999b35b10 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 15 Dec 2008 15:09:50 +0100 Subject: x86/oprofile: fix pci_dev use count for AMD northbridge devices This patch fixes the PCI device use count for AMD northbridge devices. In case of an IBS LVT initialization failure, the PCI device is released now by calling pci_dev_put(). If there are no initialization errors, the devices are released in pci_get_device() while iterating. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 98658f25f54..c5b5c7fb3ce 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -409,6 +409,7 @@ static int init_ibs_nmi(void) | IBSCTL_LVTOFFSETVAL); pci_read_config_dword(cpu_cfg, IBSCTL, &value); if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { + pci_dev_put(cpu_cfg); printk(KERN_DEBUG "Failed to setup IBS LVT offset, " "IBSCTL = 0x%08x", value); return 1; -- cgit v1.2.3 From 300157768f050dabc73a99d958b504282088a132 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 23 Dec 2008 01:35:12 +0100 Subject: oprofile: reordering some code in cpu_buffer.c Reordering code to keep alloc/free functions together. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index cd67d4dd30b..b353b19bd78 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -54,16 +54,6 @@ static void wq_sync_buffer(struct work_struct *work); #define DEFAULT_TIMER_EXPIRE (HZ / 10) static int work_enabled; -void free_cpu_buffers(void) -{ - if (op_ring_buffer_read) - ring_buffer_free(op_ring_buffer_read); - op_ring_buffer_read = NULL; - if (op_ring_buffer_write) - ring_buffer_free(op_ring_buffer_write); - op_ring_buffer_write = NULL; -} - unsigned long oprofile_get_cpu_buffer_size(void) { return oprofile_cpu_buffer_size; @@ -77,6 +67,16 @@ void oprofile_cpu_buffer_inc_smpl_lost(void) cpu_buf->sample_lost_overflow++; } +void free_cpu_buffers(void) +{ + if (op_ring_buffer_read) + ring_buffer_free(op_ring_buffer_read); + op_ring_buffer_read = NULL; + if (op_ring_buffer_write) + ring_buffer_free(op_ring_buffer_write); + op_ring_buffer_write = NULL; +} + int alloc_cpu_buffers(void) { int i; -- cgit v1.2.3 From d45d23bed4bf7b25b7dcc336552a251db1aa1279 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 16 Dec 2008 12:00:10 +0100 Subject: oprofile: add inline function __oprofile_add_ext_sample() This patch adds the inline function __oprofile_add_ext_sample() to cpu_buffer.c and thus reduces overhead when calling oprofile_add_sample(). Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index b353b19bd78..9e66c384e01 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -277,8 +277,9 @@ static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) cpu_buf->tracing = 0; } -void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, - unsigned long event, int is_kernel) +static inline void +__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); @@ -299,12 +300,18 @@ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, oprofile_end_trace(cpu_buf); } +void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel) +{ + __oprofile_add_ext_sample(pc, regs, event, is_kernel); +} + void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) { int is_kernel = !user_mode(regs); unsigned long pc = profile_pc(regs); - oprofile_add_ext_sample(pc, regs, event, is_kernel); + __oprofile_add_ext_sample(pc, regs, event, is_kernel); } #ifdef CONFIG_OPROFILE_IBS -- cgit v1.2.3 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(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index d295d92b57f..0abe29e7e4c 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.3 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(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 0abe29e7e4c..22cdb510836 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.3 From 6352d92dec0c4b833c12a169e86762c05d0396f3 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 18 Dec 2008 22:09:13 +0100 Subject: oprofile: simplify oprofile_begin_trace() This patch removes the unused return parameter in oprofile_begin_trace(). Also, oprofile_begin_trace() and oprofile_end_trace() are inline now. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 9e66c384e01..435bd6e08d5 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -265,14 +265,13 @@ fail: return 0; } -static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) +static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) { add_code(cpu_buf, CPU_TRACE_BEGIN); cpu_buf->tracing = 1; - return 1; } -static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) +static inline void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) { cpu_buf->tracing = 0; } @@ -288,8 +287,7 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, return; } - if (!oprofile_begin_trace(cpu_buf)) - return; + oprofile_begin_trace(cpu_buf); /* * if log_sample() fail we can't backtrace since we lost the @@ -297,6 +295,7 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, */ if (log_sample(cpu_buf, pc, is_kernel, event)) oprofile_ops.backtrace(regs, oprofile_backtrace_depth); + oprofile_end_trace(cpu_buf); } -- cgit v1.2.3 From 3967e93e063d7ee608f465cbccb65abb518e9d33 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 30 Dec 2008 05:10:58 +0100 Subject: oprofile: simplify add_sample() in cpu_buffer.c Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 435bd6e08d5..d92f0020502 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -203,11 +203,7 @@ add_sample(struct oprofile_cpu_buffer *cpu_buf, entry.sample->eip = pc; entry.sample->event = event; - ret = op_cpu_buffer_write_commit(&entry); - if (ret) - return ret; - - return 0; + return op_cpu_buffer_write_commit(&entry); } static inline int -- cgit v1.2.3 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(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 22cdb510836..7415d2e6b3a 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.3 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.c | 2 -- drivers/oprofile/cpu_buffer.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index d92f0020502..b426ae8ad2e 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -97,8 +97,6 @@ int alloc_cpu_buffers(void) b->last_is_kernel = -1; b->tracing = 0; b->buffer_size = buffer_size; - b->tail_pos = 0; - b->head_pos = 0; b->sample_received = 0; b->sample_lost_overflow = 0; b->backtrace_aborted = 0; diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index cd28abc0696..65b763ad72d 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.3 From f4ff2364417f0092e49f6a3aa474549a56697f2d Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 5 Jan 2009 11:27:52 +0100 Subject: oprofile: remove unused ibs macro Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index b426ae8ad2e..8ae37c9d0ec 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -309,8 +309,6 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) #ifdef CONFIG_OPROFILE_IBS -#define MAX_IBS_SAMPLE_SIZE 14 - void oprofile_add_ibs_sample(struct pt_regs * const regs, unsigned int * const ibs_sample, int ibs_code) { -- cgit v1.2.3 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 -- drivers/oprofile/cpu_buffer.c | 10 ++-------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 7415d2e6b3a..e61e25fda1a 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 diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 8ae37c9d0ec..92bf8c0d86f 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -347,17 +347,11 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs, fail = fail || add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); } - if (fail) - goto fail; - - if (oprofile_backtrace_depth) - oprofile_ops.backtrace(regs, oprofile_backtrace_depth); - - return; + if (!fail) + return; fail: cpu_buf->sample_lost_overflow++; - return; } #endif -- cgit v1.2.3 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(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index e61e25fda1a..bf8fcc7163d 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.3 From fc81be8ca29e28bfb89aa23359036a8ad4118d0f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 18 Dec 2008 00:28:27 +0100 Subject: oprofile: rename variable ibs_allowed to has_ibs in op_model_amd.c This patch renames ibs_allowed to has_ibs. Varible name fits better now. Signed-off-by: Robert Richter --- arch/x86/oprofile/op_model_amd.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index c5b5c7fb3ce..423a95438cb 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -106,7 +106,7 @@ struct ibs_op_sample { unsigned int ibs_dc_phys_high; }; -static int ibs_allowed; /* AMD Family10h and later */ +static int has_ibs; /* AMD Family10h and later */ struct op_ibs_config { unsigned long op_enabled; @@ -201,7 +201,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, struct ibs_fetch_sample ibs_fetch; struct ibs_op_sample ibs_op; - if (!ibs_allowed) + if (!has_ibs) return 1; if (ibs_config.fetch_enabled) { @@ -305,14 +305,14 @@ static void op_amd_start(struct op_msrs const * const msrs) } #ifdef CONFIG_OPROFILE_IBS - if (ibs_allowed && ibs_config.fetch_enabled) { + if (has_ibs && ibs_config.fetch_enabled) { low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ + IBS_FETCH_HIGH_ENABLE; wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); } - if (ibs_allowed && ibs_config.op_enabled) { + if (has_ibs && ibs_config.op_enabled) { low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ + IBS_OP_LOW_ENABLE; @@ -341,14 +341,14 @@ static void op_amd_stop(struct op_msrs const * const msrs) } #ifdef CONFIG_OPROFILE_IBS - if (ibs_allowed && ibs_config.fetch_enabled) { + if (has_ibs && ibs_config.fetch_enabled) { /* clear max count and enable */ low = 0; high = 0; wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); } - if (ibs_allowed && ibs_config.op_enabled) { + if (has_ibs && ibs_config.op_enabled) { /* clear max count and enable */ low = 0; high = 0; @@ -437,20 +437,20 @@ static int init_ibs_nmi(void) /* uninitialize the APIC for the IBS interrupts if needed */ static void clear_ibs_nmi(void) { - if (ibs_allowed) + if (has_ibs) on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); } /* initialize the APIC for the IBS interrupts if available */ static void ibs_init(void) { - ibs_allowed = boot_cpu_has(X86_FEATURE_IBS); + has_ibs = boot_cpu_has(X86_FEATURE_IBS); - if (!ibs_allowed) + if (!has_ibs) return; if (init_ibs_nmi()) { - ibs_allowed = 0; + has_ibs = 0; return; } @@ -459,7 +459,7 @@ static void ibs_init(void) static void ibs_exit(void) { - if (!ibs_allowed) + if (!has_ibs) return; clear_ibs_nmi(); @@ -479,7 +479,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) if (ret) return ret; - if (!ibs_allowed) + if (!has_ibs) return ret; /* model specific files */ -- cgit v1.2.3 From d0e233846dcef56ae78f6d8fd0e0cba85a2a1489 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 23 Dec 2008 04:03:05 +0100 Subject: oprofile: rename add_sample() in cpu_buffer.c Rename the fucntion to op_add_sample() since there is a collision with another one with the same name in buffer_sync.c. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 92bf8c0d86f..ac79f667603 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -188,8 +188,8 @@ unsigned long op_cpu_buffer_entries(int cpu) } static inline int -add_sample(struct oprofile_cpu_buffer *cpu_buf, - unsigned long pc, unsigned long event) +op_add_sample(struct oprofile_cpu_buffer *cpu_buf, + unsigned long pc, unsigned long event) { struct op_entry entry; int ret; @@ -207,7 +207,7 @@ add_sample(struct oprofile_cpu_buffer *cpu_buf, static inline int add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) { - return add_sample(buffer, ESCAPE_CODE, value); + return op_add_sample(buffer, ESCAPE_CODE, value); } /* This must be safe from any context. It's safe writing here @@ -249,7 +249,7 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, goto fail; } - if (add_sample(cpu_buf, pc, event)) + if (op_add_sample(cpu_buf, pc, event)) goto fail; return 1; @@ -337,14 +337,14 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs, } fail = fail || add_code(cpu_buf, ibs_code); - fail = fail || add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); - fail = fail || add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); - fail = fail || add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); + fail = fail || op_add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); + fail = fail || op_add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); + fail = fail || op_add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); if (ibs_code == IBS_OP_BEGIN) { - fail = fail || add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); - fail = fail || add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); - fail = fail || add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); + fail = fail || op_add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); + fail = fail || op_add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); + fail = fail || op_add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); } if (!fail) @@ -376,7 +376,7 @@ void oprofile_add_trace(unsigned long pc) if (pc == ESCAPE_CODE) goto fail; - if (add_sample(cpu_buf, pc, 0)) + if (op_add_sample(cpu_buf, pc, 0)) goto fail; return; -- cgit v1.2.3 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(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index bf8fcc7163d..21fd249b6e0 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.3 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.c | 43 ++++++++++++++++++++++++++++++------------- drivers/oprofile/cpu_buffer.h | 9 +++++++-- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index ac79f667603..934ff159e70 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -1,11 +1,12 @@ /** * @file cpu_buffer.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 * * Each CPU has a local buffer that stores PC value/event * pairs. We also log context switches when we notice them. @@ -143,20 +144,36 @@ void end_cpu_work(void) flush_scheduled_work(); } -int op_cpu_buffer_write_entry(struct op_entry *entry) +/* + * 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. + * + */ +struct op_sample +*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size) { - entry->event = ring_buffer_lock_reserve(op_ring_buffer_write, - sizeof(struct op_sample), - &entry->irq_flags); + entry->event = ring_buffer_lock_reserve + (op_ring_buffer_write, sizeof(struct op_sample) + + size * sizeof(entry->sample->data[0]), &entry->irq_flags); if (entry->event) entry->sample = ring_buffer_event_data(entry->event); else entry->sample = NULL; if (!entry->sample) - return -ENOMEM; + return NULL; - return 0; + entry->size = size; + entry->data = entry->sample->data; + + return entry->sample; } int op_cpu_buffer_write_commit(struct op_entry *entry) @@ -192,14 +209,14 @@ op_add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) { struct op_entry entry; - int ret; + struct op_sample *sample; - ret = op_cpu_buffer_write_entry(&entry); - if (ret) - return ret; + sample = op_cpu_buffer_write_reserve(&entry, 0); + if (!sample) + return -ENOMEM; - entry.sample->eip = pc; - entry.sample->event = event; + sample->eip = pc; + sample->event = event; return op_cpu_buffer_write_commit(&entry); } diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 65b763ad72d..2d4bfdeb7fb 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.3 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 +++++++++++++---------- drivers/oprofile/cpu_buffer.c | 14 +++++++++++--- drivers/oprofile/cpu_buffer.h | 2 +- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 21fd249b6e0..908202afbae 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 */ diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 934ff159e70..400f7fcffdb 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -182,20 +182,28 @@ int op_cpu_buffer_write_commit(struct op_entry *entry) entry->irq_flags); } -struct op_sample *op_cpu_buffer_read_entry(int cpu) +struct op_sample *op_cpu_buffer_read_entry(struct op_entry *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); + goto event; 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); + goto event; return NULL; + +event: + entry->event = e; + entry->sample = ring_buffer_event_data(e); + entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample)) + / sizeof(entry->sample->data[0]); + entry->data = entry->sample->data; + return entry->sample; } unsigned long op_cpu_buffer_entries(int cpu) diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 2d4bfdeb7fb..d7c0545ef8b 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.3 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 --- arch/x86/oprofile/op_model_amd.c | 8 +-- drivers/oprofile/buffer_sync.c | 42 ++++++------ drivers/oprofile/cpu_buffer.c | 139 +++++++++++++++++++++------------------ drivers/oprofile/cpu_buffer.h | 12 ++-- 4 files changed, 106 insertions(+), 95 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 423a95438cb..f101724db80 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -2,7 +2,7 @@ * @file op_model_amd.c * athlon / K7 / K8 / Family 10h model-specific MSR operations * - * @remark Copyright 2002-2008 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon @@ -10,7 +10,7 @@ * @author Graydon Hoare * @author Robert Richter * @author Barry Kasindorf -*/ + */ #include #include @@ -62,8 +62,8 @@ static unsigned long reset_value[NUM_COUNTERS]; /* Codes used in cpu_buffer.c */ /* This produces duplicate code, need to be fixed */ -#define IBS_FETCH_BEGIN 3 -#define IBS_OP_BEGIN 4 +#define IBS_FETCH_BEGIN (1UL << 4) +#define IBS_OP_BEGIN (1UL << 5) /* * The function interface needs to be fixed, something like add diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 908202afbae..d969bb13a25 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; } diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 400f7fcffdb..e859d23cfc5 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -212,6 +212,59 @@ unsigned long op_cpu_buffer_entries(int cpu) + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); } +static int +op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace, + int is_kernel, struct task_struct *task) +{ + struct op_entry entry; + struct op_sample *sample; + unsigned long flags; + int size; + + flags = 0; + + if (backtrace) + flags |= TRACE_BEGIN; + + /* notice a switch from user->kernel or vice versa */ + is_kernel = !!is_kernel; + if (cpu_buf->last_is_kernel != is_kernel) { + cpu_buf->last_is_kernel = is_kernel; + flags |= KERNEL_CTX_SWITCH; + if (is_kernel) + flags |= IS_KERNEL; + } + + /* notice a task switch */ + if (cpu_buf->last_task != task) { + cpu_buf->last_task = task; + flags |= USER_CTX_SWITCH; + } + + if (!flags) + /* nothing to do */ + return 0; + + if (flags & USER_CTX_SWITCH) + size = 1; + else + size = 0; + + sample = op_cpu_buffer_write_reserve(&entry, size); + if (!sample) + return -ENOMEM; + + sample->eip = ESCAPE_CODE; + sample->event = flags; + + if (size) + sample->data[0] = (unsigned long)task; + + op_cpu_buffer_write_commit(&entry); + + return 0; +} + static inline int op_add_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, unsigned long event) @@ -229,26 +282,18 @@ op_add_sample(struct oprofile_cpu_buffer *cpu_buf, return op_cpu_buffer_write_commit(&entry); } -static inline int -add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) -{ - return op_add_sample(buffer, ESCAPE_CODE, value); -} - -/* This must be safe from any context. It's safe writing here - * because of the head/tail separation of the writer and reader - * of the CPU buffer. +/* + * This must be safe from any context. * * is_kernel is needed because on some architectures you cannot * tell if you are in kernel or user space simply by looking at * pc. We tag this in the buffer by generating kernel enter/exit * events whenever is_kernel changes */ -static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, - int is_kernel, unsigned long event) +static int +log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, + unsigned long backtrace, int is_kernel, unsigned long event) { - struct task_struct *task; - cpu_buf->sample_received++; if (pc == ESCAPE_CODE) { @@ -256,23 +301,8 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, return 0; } - is_kernel = !!is_kernel; - - task = current; - - /* notice a switch from user->kernel or vice versa */ - if (cpu_buf->last_is_kernel != is_kernel) { - cpu_buf->last_is_kernel = is_kernel; - if (add_code(cpu_buf, is_kernel)) - goto fail; - } - - /* notice a task switch */ - if (cpu_buf->last_task != task) { - cpu_buf->last_task = task; - if (add_code(cpu_buf, (unsigned long)task)) - goto fail; - } + if (op_add_code(cpu_buf, backtrace, is_kernel, current)) + goto fail; if (op_add_sample(cpu_buf, pc, event)) goto fail; @@ -286,7 +316,6 @@ fail: static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) { - add_code(cpu_buf, CPU_TRACE_BEGIN); cpu_buf->tracing = 1; } @@ -300,21 +329,21 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, unsigned long event, int is_kernel) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - - if (!oprofile_backtrace_depth) { - log_sample(cpu_buf, pc, is_kernel, event); - return; - } - - oprofile_begin_trace(cpu_buf); + unsigned long backtrace = oprofile_backtrace_depth; /* * if log_sample() fail we can't backtrace since we lost the * source of this event */ - if (log_sample(cpu_buf, pc, is_kernel, event)) - oprofile_ops.backtrace(regs, oprofile_backtrace_depth); + if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event)) + /* failed */ + return; + if (!backtrace) + return; + + oprofile_begin_trace(cpu_buf); + oprofile_ops.backtrace(regs, backtrace); oprofile_end_trace(cpu_buf); } @@ -339,29 +368,14 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs, { int is_kernel = !user_mode(regs); struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - struct task_struct *task; int fail = 0; cpu_buf->sample_received++; - /* notice a switch from user->kernel or vice versa */ - if (cpu_buf->last_is_kernel != is_kernel) { - if (add_code(cpu_buf, is_kernel)) - goto fail; - cpu_buf->last_is_kernel = is_kernel; - } + /* backtraces disabled for ibs */ + fail = fail || op_add_code(cpu_buf, 0, is_kernel, current); - /* notice a task switch */ - if (!is_kernel) { - task = current; - if (cpu_buf->last_task != task) { - if (add_code(cpu_buf, (unsigned long)task)) - goto fail; - cpu_buf->last_task = task; - } - } - - fail = fail || add_code(cpu_buf, ibs_code); + fail = fail || op_add_sample(cpu_buf, ESCAPE_CODE, ibs_code); fail = fail || op_add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); fail = fail || op_add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); fail = fail || op_add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); @@ -372,11 +386,8 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs, fail = fail || op_add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); } - if (!fail) - return; - -fail: - cpu_buf->sample_lost_overflow++; + if (fail) + cpu_buf->sample_lost_overflow++; } #endif @@ -384,7 +395,7 @@ fail: void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - log_sample(cpu_buf, pc, is_kernel, event); + log_sample(cpu_buf, pc, 0, is_kernel, event); } void oprofile_add_trace(unsigned long pc) diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index d7c0545ef8b..e634dcf2f26 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.3 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.c | 2 +- drivers/oprofile/cpu_buffer.h | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index e859d23cfc5..1b6590746be 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -258,7 +258,7 @@ op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace, sample->event = flags; if (size) - sample->data[0] = (unsigned long)task; + op_cpu_buffer_add_data(&entry, (unsigned long)task); op_cpu_buffer_write_commit(&entry); diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index e634dcf2f26..e178dd2799c 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.3 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 ++++-- drivers/oprofile/cpu_buffer.h | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index d969bb13a25..f9031d31eeb 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) diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index e178dd2799c..f3437604657 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.3 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 --- arch/x86/oprofile/op_model_amd.c | 119 ++++++++++++++------------------------- drivers/oprofile/buffer_sync.c | 53 ++++------------- drivers/oprofile/cpu_buffer.c | 39 +++++++------ drivers/oprofile/cpu_buffer.h | 2 - 4 files changed, 76 insertions(+), 137 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index f101724db80..cf310aeb462 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -22,6 +22,7 @@ #include "op_x86_model.h" #include "op_counter.h" +#include "../../../drivers/oprofile/cpu_buffer.h" #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 @@ -60,51 +61,16 @@ static unsigned long reset_value[NUM_COUNTERS]; #define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ #define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ -/* Codes used in cpu_buffer.c */ -/* This produces duplicate code, need to be fixed */ -#define IBS_FETCH_BEGIN (1UL << 4) -#define IBS_OP_BEGIN (1UL << 5) - /* * The function interface needs to be fixed, something like add * data. Should then be added to linux/oprofile.h. */ -extern void -oprofile_add_ibs_sample(struct pt_regs * const regs, - unsigned int * const ibs_sample, int ibs_code); - -struct ibs_fetch_sample { - /* MSRC001_1031 IBS Fetch Linear Address Register */ - unsigned int ibs_fetch_lin_addr_low; - unsigned int ibs_fetch_lin_addr_high; - /* MSRC001_1030 IBS Fetch Control Register */ - unsigned int ibs_fetch_ctl_low; - unsigned int ibs_fetch_ctl_high; - /* MSRC001_1032 IBS Fetch Physical Address Register */ - unsigned int ibs_fetch_phys_addr_low; - unsigned int ibs_fetch_phys_addr_high; -}; +extern +void oprofile_add_data(struct op_entry *entry, struct pt_regs * const regs, + unsigned long pc, int code, int size); -struct ibs_op_sample { - /* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */ - unsigned int ibs_op_rip_low; - unsigned int ibs_op_rip_high; - /* MSRC001_1035 IBS Op Data Register */ - unsigned int ibs_op_data1_low; - unsigned int ibs_op_data1_high; - /* MSRC001_1036 IBS Op Data 2 Register */ - unsigned int ibs_op_data2_low; - unsigned int ibs_op_data2_high; - /* MSRC001_1037 IBS Op Data 3 Register */ - unsigned int ibs_op_data3_low; - unsigned int ibs_op_data3_high; - /* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */ - unsigned int ibs_dc_linear_low; - unsigned int ibs_dc_linear_high; - /* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */ - unsigned int ibs_dc_phys_low; - unsigned int ibs_dc_phys_high; -}; +#define IBS_FETCH_SIZE 6 +#define IBS_OP_SIZE 12 static int has_ibs; /* AMD Family10h and later */ @@ -197,9 +163,9 @@ static inline int op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { - unsigned int low, high; - struct ibs_fetch_sample ibs_fetch; - struct ibs_op_sample ibs_op; + u32 low, high; + u64 msr; + struct op_entry entry; if (!has_ibs) return 1; @@ -207,21 +173,19 @@ op_amd_handle_ibs(struct pt_regs * const regs, if (ibs_config.fetch_enabled) { rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); if (high & IBS_FETCH_HIGH_VALID_BIT) { - ibs_fetch.ibs_fetch_ctl_high = high; - ibs_fetch.ibs_fetch_ctl_low = low; - rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high); - ibs_fetch.ibs_fetch_lin_addr_high = high; - ibs_fetch.ibs_fetch_lin_addr_low = low; - rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high); - ibs_fetch.ibs_fetch_phys_addr_high = high; - ibs_fetch.ibs_fetch_phys_addr_low = low; - - oprofile_add_ibs_sample(regs, - (unsigned int *)&ibs_fetch, - IBS_FETCH_BEGIN); + rdmsrl(MSR_AMD64_IBSFETCHLINAD, msr); + oprofile_add_data(&entry, regs, msr, IBS_FETCH_CODE, + IBS_FETCH_SIZE); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + op_cpu_buffer_add_data(&entry, low); + op_cpu_buffer_add_data(&entry, high); + rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, msr); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + op_cpu_buffer_write_commit(&entry); /* reenable the IRQ */ - rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); high &= ~IBS_FETCH_HIGH_VALID_BIT; high |= IBS_FETCH_HIGH_ENABLE; low &= IBS_FETCH_LOW_MAX_CNT_MASK; @@ -232,30 +196,29 @@ op_amd_handle_ibs(struct pt_regs * const regs, if (ibs_config.op_enabled) { rdmsr(MSR_AMD64_IBSOPCTL, low, high); if (low & IBS_OP_LOW_VALID_BIT) { - rdmsr(MSR_AMD64_IBSOPRIP, low, high); - ibs_op.ibs_op_rip_low = low; - ibs_op.ibs_op_rip_high = high; - rdmsr(MSR_AMD64_IBSOPDATA, low, high); - ibs_op.ibs_op_data1_low = low; - ibs_op.ibs_op_data1_high = high; - rdmsr(MSR_AMD64_IBSOPDATA2, low, high); - ibs_op.ibs_op_data2_low = low; - ibs_op.ibs_op_data2_high = high; - rdmsr(MSR_AMD64_IBSOPDATA3, low, high); - ibs_op.ibs_op_data3_low = low; - ibs_op.ibs_op_data3_high = high; - rdmsr(MSR_AMD64_IBSDCLINAD, low, high); - ibs_op.ibs_dc_linear_low = low; - ibs_op.ibs_dc_linear_high = high; - rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high); - ibs_op.ibs_dc_phys_low = low; - ibs_op.ibs_dc_phys_high = high; + rdmsrl(MSR_AMD64_IBSOPRIP, msr); + oprofile_add_data(&entry, regs, msr, IBS_OP_CODE, + IBS_OP_SIZE); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA, msr); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA2, msr); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA3, msr); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSDCLINAD, msr); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + rdmsrl(MSR_AMD64_IBSDCPHYSAD, msr); + op_cpu_buffer_add_data(&entry, (u32)msr); + op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + op_cpu_buffer_write_commit(&entry); /* reenable the IRQ */ - oprofile_add_ibs_sample(regs, - (unsigned int *)&ibs_op, - IBS_OP_BEGIN); - rdmsr(MSR_AMD64_IBSOPCTL, low, high); high = 0; low &= ~IBS_OP_LOW_VALID_BIT; low |= IBS_OP_LOW_ENABLE; diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index f9031d31eeb..d692fdc1a21 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; } diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 1b6590746be..ddba9d01f09 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -363,31 +363,38 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) #ifdef CONFIG_OPROFILE_IBS -void oprofile_add_ibs_sample(struct pt_regs * const regs, - unsigned int * const ibs_sample, int ibs_code) +/* + * Add samples with data to the ring buffer. + * + * Use op_cpu_buffer_add_data(&entry, val) to add data and + * op_cpu_buffer_write_commit(&entry) to commit the sample. + */ +void oprofile_add_data(struct op_entry *entry, struct pt_regs * const regs, + unsigned long pc, int code, int size) { + struct op_sample *sample; int is_kernel = !user_mode(regs); struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - int fail = 0; cpu_buf->sample_received++; - /* backtraces disabled for ibs */ - fail = fail || op_add_code(cpu_buf, 0, is_kernel, current); + /* no backtraces for samples with data */ + if (op_add_code(cpu_buf, 0, is_kernel, current)) + goto fail; - fail = fail || op_add_sample(cpu_buf, ESCAPE_CODE, ibs_code); - fail = fail || op_add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); - fail = fail || op_add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); - fail = fail || op_add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); + sample = op_cpu_buffer_write_reserve(entry, size + 2); + if (!sample) + goto fail; + sample->eip = ESCAPE_CODE; + sample->event = 0; /* no flags */ - if (ibs_code == IBS_OP_BEGIN) { - fail = fail || op_add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); - fail = fail || op_add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); - fail = fail || op_add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); - } + op_cpu_buffer_add_data(entry, code); + op_cpu_buffer_add_data(entry, pc); + + return; - if (fail) - cpu_buf->sample_lost_overflow++; +fail: + cpu_buf->sample_lost_overflow++; } #endif diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index f3437604657..525cc4d13d8 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.3 From 465634adc1d09b490c8ee31885575be39d375d53 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Jan 2009 15:32:11 +0100 Subject: ring_buffer: fix ring_buffer_event_length() Function ring_buffer_event_length() provides an interface to detect the length of data stored in an entry. However, the length contains offsets depending on the internal usage. This makes it unusable. This patch fixes this and now ring_buffer_event_length() returns the alligned length that has been used in ring_buffer_lock_reserve(). Cc: Steven Rostedt Signed-off-by: Robert Richter --- kernel/trace/ring_buffer.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 30d57dd01a8..d42b882dfe4 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -117,7 +117,13 @@ rb_event_length(struct ring_buffer_event *event) */ unsigned ring_buffer_event_length(struct ring_buffer_event *event) { - return rb_event_length(event); + unsigned length = rb_event_length(event); + if (event->type != RINGBUF_TYPE_DATA) + return length; + length -= RB_EVNT_HDR_SIZE; + if (length > RB_MAX_SMALL_DATA + sizeof(event->array[0])) + length -= sizeof(event->array[0]); + return length; } EXPORT_SYMBOL_GPL(ring_buffer_event_length); -- cgit v1.2.3 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 ------ drivers/oprofile/cpu_buffer.c | 4 ---- 2 files changed, 10 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index d692fdc1a21..ac014cb2791 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; } diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index ddba9d01f09..b846af632c8 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -361,8 +361,6 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) __oprofile_add_ext_sample(pc, regs, event, is_kernel); } -#ifdef CONFIG_OPROFILE_IBS - /* * Add samples with data to the ring buffer. * @@ -397,8 +395,6 @@ fail: cpu_buf->sample_lost_overflow++; } -#endif - void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); -- cgit v1.2.3 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 --- arch/x86/oprofile/op_model_amd.c | 57 +++++++++++++++++----------------------- drivers/oprofile/cpu_buffer.c | 17 +++++++++--- drivers/oprofile/cpu_buffer.h | 8 +----- include/linux/oprofile.h | 18 +++++++++++++ 4 files changed, 57 insertions(+), 43 deletions(-) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index cf310aeb462..8fdf06e4edf 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -22,7 +22,6 @@ #include "op_x86_model.h" #include "op_counter.h" -#include "../../../drivers/oprofile/cpu_buffer.h" #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 @@ -61,14 +60,6 @@ static unsigned long reset_value[NUM_COUNTERS]; #define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ #define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ -/* - * The function interface needs to be fixed, something like add - * data. Should then be added to linux/oprofile.h. - */ -extern -void oprofile_add_data(struct op_entry *entry, struct pt_regs * const regs, - unsigned long pc, int code, int size); - #define IBS_FETCH_SIZE 6 #define IBS_OP_SIZE 12 @@ -174,16 +165,16 @@ op_amd_handle_ibs(struct pt_regs * const regs, rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); if (high & IBS_FETCH_HIGH_VALID_BIT) { rdmsrl(MSR_AMD64_IBSFETCHLINAD, msr); - oprofile_add_data(&entry, regs, msr, IBS_FETCH_CODE, - IBS_FETCH_SIZE); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); - op_cpu_buffer_add_data(&entry, low); - op_cpu_buffer_add_data(&entry, high); + oprofile_write_reserve(&entry, regs, msr, + IBS_FETCH_CODE, IBS_FETCH_SIZE); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, low); + oprofile_add_data(&entry, high); rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, msr); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); - op_cpu_buffer_write_commit(&entry); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_write_commit(&entry); /* reenable the IRQ */ high &= ~IBS_FETCH_HIGH_VALID_BIT; @@ -197,26 +188,26 @@ op_amd_handle_ibs(struct pt_regs * const regs, rdmsr(MSR_AMD64_IBSOPCTL, low, high); if (low & IBS_OP_LOW_VALID_BIT) { rdmsrl(MSR_AMD64_IBSOPRIP, msr); - oprofile_add_data(&entry, regs, msr, IBS_OP_CODE, - IBS_OP_SIZE); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + oprofile_write_reserve(&entry, regs, msr, + IBS_OP_CODE, IBS_OP_SIZE); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); rdmsrl(MSR_AMD64_IBSOPDATA, msr); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); rdmsrl(MSR_AMD64_IBSOPDATA2, msr); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); rdmsrl(MSR_AMD64_IBSOPDATA3, msr); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); rdmsrl(MSR_AMD64_IBSDCLINAD, msr); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); rdmsrl(MSR_AMD64_IBSDCPHYSAD, msr); - op_cpu_buffer_add_data(&entry, (u32)msr); - op_cpu_buffer_add_data(&entry, (u32)(msr >> 32)); - op_cpu_buffer_write_commit(&entry); + oprofile_add_data(&entry, (u32)msr); + oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_write_commit(&entry); /* reenable the IRQ */ high = 0; diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index b846af632c8..2e03b6d796d 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -364,10 +364,11 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) /* * Add samples with data to the ring buffer. * - * Use op_cpu_buffer_add_data(&entry, val) to add data and - * op_cpu_buffer_write_commit(&entry) to commit the sample. + * Use oprofile_add_data(&entry, val) to add data and + * oprofile_write_commit(&entry) to commit the sample. */ -void oprofile_add_data(struct op_entry *entry, struct pt_regs * const regs, +void +oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, unsigned long pc, int code, int size) { struct op_sample *sample; @@ -395,6 +396,16 @@ fail: cpu_buf->sample_lost_overflow++; } +int oprofile_add_data(struct op_entry *entry, unsigned long val) +{ + return op_cpu_buffer_add_data(entry, val); +} + +int oprofile_write_commit(struct op_entry *entry) +{ + return op_cpu_buffer_write_commit(entry); +} + void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 525cc4d13d8..63f81c44846 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; diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 1ce9fe572e5..1d9518bc4c5 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -164,4 +164,22 @@ void oprofile_put_buff(unsigned long *buf, unsigned int start, unsigned long oprofile_get_cpu_buffer_size(void); void oprofile_cpu_buffer_inc_smpl_lost(void); +/* cpu buffer functions */ + +struct op_sample; + +struct op_entry { + struct ring_buffer_event *event; + struct op_sample *sample; + unsigned long irq_flags; + unsigned long size; + unsigned long *data; +}; + +void oprofile_write_reserve(struct op_entry *entry, + struct pt_regs * const regs, + unsigned long pc, int code, int size); +int oprofile_add_data(struct op_entry *entry, unsigned long val); +int oprofile_write_commit(struct op_entry *entry); + #endif /* OPROFILE_H */ -- cgit v1.2.3