diff options
Diffstat (limited to 'drivers/oprofile')
-rw-r--r-- | drivers/oprofile/buffer_sync.c | 240 | ||||
-rw-r--r-- | drivers/oprofile/buffer_sync.h | 4 | ||||
-rw-r--r-- | drivers/oprofile/cpu_buffer.c | 114 | ||||
-rw-r--r-- | drivers/oprofile/cpu_buffer.h | 14 | ||||
-rw-r--r-- | drivers/oprofile/event_buffer.c | 34 | ||||
-rw-r--r-- | drivers/oprofile/event_buffer.h | 17 | ||||
-rw-r--r-- | drivers/oprofile/oprof.c | 26 | ||||
-rw-r--r-- | drivers/oprofile/oprof.h | 12 | ||||
-rw-r--r-- | drivers/oprofile/oprofile_files.c | 36 | ||||
-rw-r--r-- | drivers/oprofile/oprofile_stats.c | 24 | ||||
-rw-r--r-- | drivers/oprofile/oprofile_stats.h | 10 | ||||
-rw-r--r-- | drivers/oprofile/oprofilefs.c | 78 | ||||
-rw-r--r-- | drivers/oprofile/timer_int.c | 4 |
13 files changed, 398 insertions, 215 deletions
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 9304c455507..b55cd23ffde 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -5,6 +5,7 @@ * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> + * @author Barry Kasindorf * * This is the core of the buffer management. Each * CPU buffer is processed and entered into the @@ -33,14 +34,13 @@ #include "event_buffer.h" #include "cpu_buffer.h" #include "buffer_sync.h" - + static LIST_HEAD(dying_tasks); static LIST_HEAD(dead_tasks); static cpumask_t marked_cpus = CPU_MASK_NONE; static DEFINE_SPINLOCK(task_mortuary); static void process_task_mortuary(void); - /* Take ownership of the task struct and place it on the * list for processing. Only after two full buffer syncs * does the task eventually get freed, because by then @@ -48,10 +48,11 @@ static void process_task_mortuary(void); * Can be invoked from softirq via RCU callback due to * call_rcu() of the task struct, hence the _irqsave. */ -static int task_free_notify(struct notifier_block * self, unsigned long val, void * data) +static int +task_free_notify(struct notifier_block *self, unsigned long val, void *data) { unsigned long flags; - struct task_struct * task = data; + struct task_struct *task = data; spin_lock_irqsave(&task_mortuary, flags); list_add(&task->tasks, &dying_tasks); spin_unlock_irqrestore(&task_mortuary, flags); @@ -62,13 +63,14 @@ static int task_free_notify(struct notifier_block * self, unsigned long val, voi /* The task is on its way out. A sync of the buffer means we can catch * any remaining samples for this task. */ -static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data) +static int +task_exit_notify(struct notifier_block *self, unsigned long val, void *data) { /* To avoid latency problems, we only process the current CPU, * hoping that most samples for the task are on this CPU */ sync_buffer(raw_smp_processor_id()); - return 0; + return 0; } @@ -77,11 +79,12 @@ static int task_exit_notify(struct notifier_block * self, unsigned long val, voi * we don't lose any. This does not have to be exact, it's a QoI issue * only. */ -static int munmap_notify(struct notifier_block * self, unsigned long val, void * data) +static int +munmap_notify(struct notifier_block *self, unsigned long val, void *data) { unsigned long addr = (unsigned long)data; - struct mm_struct * mm = current->mm; - struct vm_area_struct * mpnt; + struct mm_struct *mm = current->mm; + struct vm_area_struct *mpnt; down_read(&mm->mmap_sem); @@ -99,11 +102,12 @@ static int munmap_notify(struct notifier_block * self, unsigned long val, void * return 0; } - + /* We need to be told about new modules so we don't attribute to a previously * loaded module, or drop the samples on the floor. */ -static int module_load_notify(struct notifier_block * self, unsigned long val, void * data) +static int +module_load_notify(struct notifier_block *self, unsigned long val, void *data) { #ifdef CONFIG_MODULES if (val != MODULE_STATE_COMING) @@ -118,7 +122,7 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v return 0; } - + static struct notifier_block task_free_nb = { .notifier_call = task_free_notify, }; @@ -135,7 +139,7 @@ static struct notifier_block module_load_nb = { .notifier_call = module_load_notify, }; - + static void end_sync(void) { end_cpu_work(); @@ -208,14 +212,14 @@ static inline unsigned long fast_get_dcookie(struct path *path) * not strictly necessary but allows oprofile to associate * shared-library samples with particular applications */ -static unsigned long get_exec_dcookie(struct mm_struct * mm) +static unsigned long get_exec_dcookie(struct mm_struct *mm) { unsigned long cookie = NO_COOKIE; - struct vm_area_struct * vma; - + struct vm_area_struct *vma; + if (!mm) goto out; - + for (vma = mm->mmap; vma; vma = vma->vm_next) { if (!vma->vm_file) continue; @@ -235,13 +239,14 @@ out: * sure to do this lookup before a mm->mmap modification happens so * we don't lose track. */ -static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset) +static unsigned long +lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) { unsigned long cookie = NO_COOKIE; - struct vm_area_struct * vma; + struct vm_area_struct *vma; for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { - + if (addr < vma->vm_start || addr >= vma->vm_end) continue; @@ -263,9 +268,20 @@ static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, o 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 synchromized */ + + 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) { add_event_entry(ESCAPE_CODE); @@ -278,16 +294,16 @@ static void add_kernel_ctx_switch(unsigned int in_kernel) { add_event_entry(ESCAPE_CODE); if (in_kernel) - add_event_entry(KERNEL_ENTER_SWITCH_CODE); + add_event_entry(KERNEL_ENTER_SWITCH_CODE); else - add_event_entry(KERNEL_EXIT_SWITCH_CODE); + add_event_entry(KERNEL_EXIT_SWITCH_CODE); } - + static void -add_user_ctx_switch(struct task_struct const * task, unsigned long cookie) +add_user_ctx_switch(struct task_struct const *task, unsigned long cookie) { add_event_entry(ESCAPE_CODE); - add_event_entry(CTX_SWITCH_CODE); + add_event_entry(CTX_SWITCH_CODE); add_event_entry(task->pid); add_event_entry(cookie); /* Another code for daemon back-compat */ @@ -296,7 +312,7 @@ add_user_ctx_switch(struct task_struct const * task, unsigned long cookie) add_event_entry(task->tgid); } - + static void add_cookie_switch(unsigned long cookie) { add_event_entry(ESCAPE_CODE); @@ -304,13 +320,78 @@ static void add_cookie_switch(unsigned long cookie) add_event_entry(cookie); } - + static void add_trace_begin(void) { add_event_entry(ESCAPE_CODE); add_event_entry(TRACE_BEGIN_CODE); } +#ifdef CONFIG_OPROFILE_IBS + +#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) + +/* + * 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) +{ + unsigned long rip; + int i, count; + unsigned long ibs_cookie = 0; + off_t offset; + + increment_tail(cpu_buf); /* move to RIP entry */ + + rip = IBS_EIP(cpu_buf->tail_pos); + +#ifdef __LP64__ + rip += IBS_EVENT(cpu_buf->tail_pos) << 32; +#endif + + if (mm) { + ibs_cookie = lookup_dcookie(mm, rip, &offset); + + if (ibs_cookie == NO_COOKIE) + offset = rip; + if (ibs_cookie == INVALID_COOKIE) { + atomic_inc(&oprofile_stats.sample_lost_no_mapping); + offset = rip; + } + if (ibs_cookie != last_cookie) { + add_cookie_switch(ibs_cookie); + last_cookie = ibs_cookie; + } + } else + offset = rip; + + add_event_entry(ESCAPE_CODE); + 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(IBS_EIP(cpu_buf->tail_pos)); + add_event_entry(IBS_EVENT(cpu_buf->tail_pos)); + + 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++) { + increment_tail(cpu_buf); + add_event_entry(IBS_EIP(cpu_buf->tail_pos)); + add_event_entry(IBS_EVENT(cpu_buf->tail_pos)); + } +} + +#endif static void add_sample_entry(unsigned long offset, unsigned long event) { @@ -319,13 +400,13 @@ static void add_sample_entry(unsigned long offset, unsigned long event) } -static int add_us_sample(struct mm_struct * mm, struct op_sample * s) +static int add_us_sample(struct mm_struct *mm, struct op_sample *s) { unsigned long cookie; off_t offset; - - cookie = lookup_dcookie(mm, s->eip, &offset); - + + cookie = lookup_dcookie(mm, s->eip, &offset); + if (cookie == INVALID_COOKIE) { atomic_inc(&oprofile_stats.sample_lost_no_mapping); return 0; @@ -341,13 +422,13 @@ static int add_us_sample(struct mm_struct * mm, struct op_sample * s) return 1; } - + /* 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) +add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) { if (in_kernel) { add_sample_entry(s->eip, s->event); @@ -359,9 +440,9 @@ add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel) } return 0; } - -static void release_mm(struct mm_struct * mm) + +static void release_mm(struct mm_struct *mm) { if (!mm) return; @@ -370,9 +451,9 @@ static void release_mm(struct mm_struct * mm) } -static struct mm_struct * take_tasks_mm(struct task_struct * task) +static struct mm_struct *take_tasks_mm(struct task_struct *task) { - struct mm_struct * mm = get_task_mm(task); + struct mm_struct *mm = get_task_mm(task); if (mm) down_read(&mm->mmap_sem); return mm; @@ -383,10 +464,10 @@ static inline int is_code(unsigned long val) { return val == ESCAPE_CODE; } - + /* "acquire" as many cpu buffer slots as we can */ -static unsigned long get_slots(struct oprofile_cpu_buffer * b) +static unsigned long get_slots(struct oprofile_cpu_buffer *b) { unsigned long head = b->head_pos; unsigned long tail = b->tail_pos; @@ -412,19 +493,6 @@ static unsigned long get_slots(struct oprofile_cpu_buffer * b) } -static void increment_tail(struct oprofile_cpu_buffer * b) -{ - unsigned long new_tail = b->tail_pos + 1; - - rmb(); - - if (new_tail < b->buffer_size) - b->tail_pos = new_tail; - else - b->tail_pos = 0; -} - - /* 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, @@ -435,8 +503,8 @@ static void process_task_mortuary(void) { unsigned long flags; LIST_HEAD(local_dead_tasks); - struct task_struct * task; - struct task_struct * ttask; + struct task_struct *task; + struct task_struct *ttask; spin_lock_irqsave(&task_mortuary, flags); @@ -493,24 +561,30 @@ void sync_buffer(int cpu) { struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); struct mm_struct *mm = NULL; - struct task_struct * new; + struct task_struct *new; unsigned long cookie = 0; int in_kernel = 1; - unsigned int i; 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 */ +#ifndef CONFIG_OPROFILE_IBS available = get_slots(cpu_buf); for (i = 0; i < available; ++i) { - struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos]; - +#else + while (get_slots(cpu_buf)) { +#endif + struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos]; + if (is_code(s->eip)) { if (s->event <= CPU_IS_KERNEL) { /* kernel/userspace switch */ @@ -521,8 +595,16 @@ void sync_buffer(int cpu) } else if (s->event == CPU_TRACE_BEGIN) { state = sb_bt_start; add_trace_begin(); +#ifdef CONFIG_OPROFILE_IBS + } else if (s->event == IBS_FETCH_BEGIN) { + state = sb_bt_start; + add_ibs_begin(cpu_buf, IBS_FETCH_CODE, mm); + } else if (s->event == IBS_OP_BEGIN) { + state = sb_bt_start; + add_ibs_begin(cpu_buf, IBS_OP_CODE, mm); +#endif } else { - struct mm_struct * oldmm = mm; + struct mm_struct *oldmm = mm; /* userspace context switch */ new = (struct task_struct *)s->event; @@ -533,13 +615,11 @@ void sync_buffer(int cpu) cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); } - } 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); - } + } 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); } } @@ -551,3 +631,27 @@ void sync_buffer(int cpu) mutex_unlock(&buffer_mutex); } + +/* The function can be used to add a buffer worth of data directly to + * the kernel buffer. The buffer is assumed to be a circular buffer. + * Take the entries from index start and end at index end, wrapping + * at max_entries. + */ +void oprofile_put_buff(unsigned long *buf, unsigned int start, + unsigned int stop, unsigned int max) +{ + int i; + + i = start; + + mutex_lock(&buffer_mutex); + while (i != stop) { + add_event_entry(buf[i++]); + + if (i >= max) + i = 0; + } + + mutex_unlock(&buffer_mutex); +} + diff --git a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h index 08866f6a96a..3110732c183 100644 --- a/drivers/oprofile/buffer_sync.h +++ b/drivers/oprofile/buffer_sync.h @@ -9,13 +9,13 @@ #ifndef OPROFILE_BUFFER_SYNC_H #define OPROFILE_BUFFER_SYNC_H - + /* add the necessary profiling hooks */ int sync_start(void); /* remove the hooks */ void sync_stop(void); - + /* sync the given CPU's buffer */ void sync_buffer(int cpu); diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 7ba78e6d210..01d38e78cde 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -5,6 +5,7 @@ * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> + * @author Barry Kasindorf <barry.kasindorf@amd.com> * * Each CPU has a local buffer that stores PC value/event * pairs. We also log context switches when we notice them. @@ -21,7 +22,7 @@ #include <linux/oprofile.h> #include <linux/vmalloc.h> #include <linux/errno.h> - + #include "event_buffer.h" #include "cpu_buffer.h" #include "buffer_sync.h" @@ -37,27 +38,40 @@ static int work_enabled; void free_cpu_buffers(void) { int i; - - for_each_online_cpu(i) { + + for_each_possible_cpu(i) { vfree(per_cpu(cpu_buffer, i).buffer); per_cpu(cpu_buffer, i).buffer = NULL; } } +unsigned long oprofile_get_cpu_buffer_size(void) +{ + return fs_cpu_buffer_size; +} + +void oprofile_cpu_buffer_inc_smpl_lost(void) +{ + struct oprofile_cpu_buffer *cpu_buf + = &__get_cpu_var(cpu_buffer); + + cpu_buf->sample_lost_overflow++; +} + int alloc_cpu_buffers(void) { int i; - + unsigned long buffer_size = fs_cpu_buffer_size; - - for_each_online_cpu(i) { + + 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; @@ -111,7 +125,7 @@ void end_cpu_work(void) } /* Resets the cpu buffer to a sane state. */ -void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf) +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 @@ -122,7 +136,7 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf) } /* compute number of available slots in cpu_buffer queue */ -static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b) +static unsigned long nr_available_slots(struct oprofile_cpu_buffer const *b) { unsigned long head = b->head_pos; unsigned long tail = b->tail_pos; @@ -133,7 +147,7 @@ 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) +static void increment_head(struct oprofile_cpu_buffer *b) { unsigned long new_head = b->head_pos + 1; @@ -148,17 +162,17 @@ static void increment_head(struct oprofile_cpu_buffer * b) } static inline void -add_sample(struct oprofile_cpu_buffer * cpu_buf, - unsigned long pc, unsigned long event) +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_buf->buffer[cpu_buf->head_pos]; entry->eip = pc; entry->event = event; increment_head(cpu_buf); } static inline void -add_code(struct oprofile_cpu_buffer * buffer, unsigned long value) +add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) { add_sample(buffer, ESCAPE_CODE, value); } @@ -172,10 +186,10 @@ add_code(struct oprofile_cpu_buffer * buffer, unsigned long value) * 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, +static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, int is_kernel, unsigned long event) { - struct task_struct * task; + struct task_struct *task; cpu_buf->sample_received++; @@ -204,12 +218,12 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, cpu_buf->last_task = task; add_code(cpu_buf, (unsigned long)task); } - + add_sample(cpu_buf, pc, event); return 1; } -static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf) +static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) { if (nr_available_slots(cpu_buf) < 4) { cpu_buf->sample_lost_overflow++; @@ -221,7 +235,7 @@ static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf) return 1; } -static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf) +static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) { cpu_buf->tracing = 0; } @@ -254,6 +268,57 @@ 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 + +#define MAX_IBS_SAMPLE_SIZE 14 + +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); + struct task_struct *task; + + 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; + add_code(cpu_buf, is_kernel); + } + + /* notice a task switch */ + if (!is_kernel) { + task = current; + if (cpu_buf->last_task != task) { + 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]); + + 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]); + } + + if (backtrace_depth) + oprofile_ops.backtrace(regs, backtrace_depth); +} + +#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); @@ -293,11 +358,16 @@ void oprofile_add_trace(unsigned long pc) */ static void wq_sync_buffer(struct work_struct *work) { - struct oprofile_cpu_buffer * b = + struct oprofile_cpu_buffer *b = container_of(work, struct oprofile_cpu_buffer, work.work); if (b->cpu != smp_processor_id()) { - printk("WQ on CPU%d, prefer CPU%d\n", + printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n", smp_processor_id(), b->cpu); + + if (!cpu_online(b->cpu)) { + cancel_delayed_work(&b->work); + return; + } } sync_buffer(b->cpu); diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index c3e366b5226..d3cc26264db 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -15,9 +15,9 @@ #include <linux/workqueue.h> #include <linux/cache.h> #include <linux/sched.h> - + struct task_struct; - + int alloc_cpu_buffers(void); void free_cpu_buffers(void); @@ -31,15 +31,15 @@ struct op_sample { unsigned long eip; unsigned long event; }; - + struct oprofile_cpu_buffer { volatile unsigned long head_pos; volatile unsigned long tail_pos; unsigned long buffer_size; - struct task_struct * last_task; + struct task_struct *last_task; int last_is_kernel; int tracing; - struct op_sample * buffer; + struct op_sample *buffer; unsigned long sample_received; unsigned long sample_lost_overflow; unsigned long backtrace_aborted; @@ -50,10 +50,12 @@ struct oprofile_cpu_buffer { DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); -void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); +void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf); /* 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 #endif /* OPROFILE_CPU_BUFFER_H */ diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index 8d692a5c8e7..d962ba0dd87 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -19,16 +19,16 @@ #include <linux/dcookies.h> #include <linux/fs.h> #include <asm/uaccess.h> - + #include "oprof.h" #include "event_buffer.h" #include "oprofile_stats.h" DEFINE_MUTEX(buffer_mutex); - + static unsigned long buffer_opened; static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); -static unsigned long * event_buffer; +static unsigned long *event_buffer; static unsigned long buffer_size; static unsigned long buffer_watershed; static size_t buffer_pos; @@ -66,7 +66,7 @@ void wake_up_buffer_waiter(void) mutex_unlock(&buffer_mutex); } - + int alloc_event_buffer(void) { int err = -ENOMEM; @@ -76,13 +76,13 @@ int alloc_event_buffer(void) buffer_size = fs_buffer_size; buffer_watershed = fs_buffer_watershed; spin_unlock_irqrestore(&oprofilefs_lock, flags); - + if (buffer_watershed >= buffer_size) return -EINVAL; - + event_buffer = vmalloc(sizeof(unsigned long) * buffer_size); if (!event_buffer) - goto out; + goto out; err = 0; out: @@ -97,8 +97,8 @@ void free_event_buffer(void) event_buffer = NULL; } - -static int event_buffer_open(struct inode * inode, struct file * file) + +static int event_buffer_open(struct inode *inode, struct file *file) { int err = -EPERM; @@ -116,14 +116,14 @@ static int event_buffer_open(struct inode * inode, struct file * file) file->private_data = dcookie_register(); if (!file->private_data) goto out; - + if ((err = oprofile_setup())) goto fail; /* NB: the actual start happens from userspace * echo 1 >/dev/oprofile/enable */ - + return 0; fail: @@ -134,7 +134,7 @@ out: } -static int event_buffer_release(struct inode * inode, struct file * file) +static int event_buffer_release(struct inode *inode, struct file *file) { oprofile_stop(); oprofile_shutdown(); @@ -146,8 +146,8 @@ static int event_buffer_release(struct inode * inode, struct file * file) } -static ssize_t event_buffer_read(struct file * file, char __user * buf, - size_t count, loff_t * offset) +static ssize_t event_buffer_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) { int retval = -EINVAL; size_t const max = buffer_size * sizeof(unsigned long); @@ -172,18 +172,18 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf, retval = -EFAULT; count = buffer_pos * sizeof(unsigned long); - + if (copy_to_user(buf, event_buffer, count)) goto out; retval = count; buffer_pos = 0; - + out: mutex_unlock(&buffer_mutex); return retval; } - + const struct file_operations event_buffer_fops = { .open = event_buffer_open, .release = event_buffer_release, diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h index 5076ed1ebd8..4e70749f8d1 100644 --- a/drivers/oprofile/event_buffer.h +++ b/drivers/oprofile/event_buffer.h @@ -10,13 +10,20 @@ #ifndef EVENT_BUFFER_H #define EVENT_BUFFER_H -#include <linux/types.h> +#include <linux/types.h> #include <asm/mutex.h> - + int alloc_event_buffer(void); void free_event_buffer(void); - + +/** + * Add data to the event buffer. + * The data passed is free-form, but typically consists of + * file offsets, dcookies, context information, and ESCAPE codes. + */ +void add_event_entry(unsigned long data); + /* wake up the process sleeping on the event file */ void wake_up_buffer_waiter(void); @@ -24,10 +31,10 @@ void wake_up_buffer_waiter(void); #define NO_COOKIE 0UL extern const struct file_operations event_buffer_fops; - + /* mutex between sync_cpu_buffers() and the * file reading code. */ extern struct mutex buffer_mutex; - + #endif /* EVENT_BUFFER_H */ diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 2c645170f06..cd375907f26 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -19,7 +19,7 @@ #include "cpu_buffer.h" #include "buffer_sync.h" #include "oprofile_stats.h" - + struct oprofile_operations oprofile_ops; unsigned long oprofile_started; @@ -36,7 +36,7 @@ static int timer = 0; int oprofile_setup(void) { int err; - + mutex_lock(&start_mutex); if ((err = alloc_cpu_buffers())) @@ -44,10 +44,10 @@ int oprofile_setup(void) if ((err = alloc_event_buffer())) goto out1; - + if (oprofile_ops.setup && (err = oprofile_ops.setup())) goto out2; - + /* Note even though this starts part of the * profiling overhead, it's necessary to prevent * us missing task deaths and eventually oopsing @@ -74,7 +74,7 @@ post_sync: is_setup = 1; mutex_unlock(&start_mutex); return 0; - + out3: if (oprofile_ops.shutdown) oprofile_ops.shutdown(); @@ -92,17 +92,17 @@ out: int oprofile_start(void) { int err = -EINVAL; - + mutex_lock(&start_mutex); - + if (!is_setup) goto out; - err = 0; - + err = 0; + if (oprofile_started) goto out; - + oprofile_reset_stats(); if ((err = oprofile_ops.start())) @@ -114,7 +114,7 @@ out: return err; } - + /* echo 0>/dev/oprofile/enable */ void oprofile_stop(void) { @@ -204,13 +204,13 @@ static void __exit oprofile_exit(void) oprofile_arch_exit(); } - + module_init(oprofile_init); module_exit(oprofile_exit); module_param_named(timer, timer, int, 0644); MODULE_PARM_DESC(timer, "force use of timer interrupt"); - + MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Levon <levon@movementarian.org>"); MODULE_DESCRIPTION("OProfile system profiler"); diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 18323650806..5df0c21a608 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -11,7 +11,7 @@ #define OPROF_H int oprofile_setup(void); -void oprofile_shutdown(void); +void oprofile_shutdown(void); int oprofilefs_register(void); void oprofilefs_unregister(void); @@ -20,20 +20,20 @@ int oprofile_start(void); 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 struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long backtrace_depth; - + struct super_block; struct dentry; -void oprofile_create_files(struct super_block * sb, struct dentry * root); -void oprofile_timer_init(struct oprofile_operations * ops); +void oprofile_create_files(struct super_block *sb, struct dentry *root); +void oprofile_timer_init(struct oprofile_operations *ops); int oprofile_set_backtrace(unsigned long depth); - + #endif /* OPROF_H */ diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index ef953ba5ab6..cc106d503ac 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -13,18 +13,18 @@ #include "event_buffer.h" #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 */ -static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset) +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); } -static ssize_t depth_write(struct file * file, char const __user * buf, size_t count, loff_t * offset) +static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) { unsigned long val; int retval; @@ -49,8 +49,8 @@ static const struct file_operations depth_fops = { .write = depth_write }; - -static ssize_t pointer_size_read(struct file * file, char __user * buf, size_t count, loff_t * offset) + +static ssize_t pointer_size_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { return oprofilefs_ulong_to_user(sizeof(void *), buf, count, offset); } @@ -61,24 +61,24 @@ static const struct file_operations pointer_size_fops = { }; -static ssize_t cpu_type_read(struct file * file, char __user * buf, size_t count, loff_t * offset) +static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { return oprofilefs_str_to_user(oprofile_ops.cpu_type, buf, count, offset); } - - + + static const struct file_operations cpu_type_fops = { .read = cpu_type_read, }; - - -static ssize_t enable_read(struct file * file, char __user * buf, size_t count, loff_t * offset) + + +static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset); } -static ssize_t enable_write(struct file * file, char const __user * buf, size_t count, loff_t * offset) +static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) { unsigned long val; int retval; @@ -89,7 +89,7 @@ static ssize_t enable_write(struct file * file, char const __user * buf, size_t retval = oprofilefs_ulong_from_user(&val, buf, count); if (retval) return retval; - + if (val) retval = oprofile_start(); else @@ -100,14 +100,14 @@ static ssize_t enable_write(struct file * file, char const __user * buf, size_t return count; } - + static const struct file_operations enable_fops = { .read = enable_read, .write = enable_write, }; -static ssize_t dump_write(struct file * file, char const __user * buf, size_t count, loff_t * offset) +static ssize_t dump_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) { wake_up_buffer_waiter(); return count; @@ -117,8 +117,8 @@ static ssize_t dump_write(struct file * file, char const __user * buf, size_t co static const struct file_operations dump_fops = { .write = dump_write, }; - -void oprofile_create_files(struct super_block * sb, struct dentry * root) + +void oprofile_create_files(struct super_block *sb, struct dentry *root) { oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); @@ -126,7 +126,7 @@ void oprofile_create_files(struct super_block * sb, struct dentry * root) 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_file(sb, root, "cpu_type", &cpu_type_fops); + 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); oprofile_create_stats_files(sb, root); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index f99b28e7b79..e1f6ce03705 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -11,17 +11,17 @@ #include <linux/smp.h> #include <linux/cpumask.h> #include <linux/threads.h> - + #include "oprofile_stats.h" #include "cpu_buffer.h" - + struct oprofile_stat_struct oprofile_stats; - + void oprofile_reset_stats(void) { - struct oprofile_cpu_buffer * cpu_buf; + struct oprofile_cpu_buffer *cpu_buf; int i; - + for_each_possible_cpu(i) { cpu_buf = &per_cpu(cpu_buffer, i); cpu_buf->sample_received = 0; @@ -29,18 +29,18 @@ void oprofile_reset_stats(void) cpu_buf->backtrace_aborted = 0; cpu_buf->sample_invalid_eip = 0; } - + atomic_set(&oprofile_stats.sample_lost_no_mm, 0); atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); } -void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) +void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) { - struct oprofile_cpu_buffer * cpu_buf; - struct dentry * cpudir; - struct dentry * dir; + struct oprofile_cpu_buffer *cpu_buf; + struct dentry *cpudir; + struct dentry *dir; char buf[10]; int i; @@ -52,7 +52,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) cpu_buf = &per_cpu(cpu_buffer, i); snprintf(buf, 10, "cpu%d", i); cpudir = oprofilefs_mkdir(sb, dir, buf); - + /* Strictly speaking access to these ulongs is racy, * but we can't simply lock them, and they are * informational only. @@ -66,7 +66,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) oprofilefs_create_ro_ulong(sb, cpudir, "sample_invalid_eip", &cpu_buf->sample_invalid_eip); } - + oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm", &oprofile_stats.sample_lost_no_mm); oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mapping", diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index 6d755a633f1..3da0d08dc1f 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h @@ -11,7 +11,7 @@ #define OPROFILE_STATS_H #include <asm/atomic.h> - + struct oprofile_stat_struct { atomic_t sample_lost_no_mm; atomic_t sample_lost_no_mapping; @@ -20,14 +20,14 @@ struct oprofile_stat_struct { }; extern struct oprofile_stat_struct oprofile_stats; - + /* reset all stats to zero */ void oprofile_reset_stats(void); - + struct super_block; struct dentry; - + /* create the stats/ dir */ -void oprofile_create_stats_files(struct super_block * sb, struct dentry * root); +void oprofile_create_stats_files(struct super_block *sb, struct dentry *root); #endif /* OPROFILE_STATS_H */ diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 8543cb26cf3..ddc4c59f02d 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -23,9 +23,9 @@ DEFINE_SPINLOCK(oprofilefs_lock); -static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode) +static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode) { - struct inode * inode = new_inode(sb); + struct inode *inode = new_inode(sb); if (inode) { inode->i_mode = mode; @@ -44,7 +44,7 @@ static struct super_operations s_ops = { }; -ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count, loff_t * offset) +ssize_t oprofilefs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset) { return simple_read_from_buffer(buf, count, offset, str, strlen(str)); } @@ -52,7 +52,7 @@ ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count #define TMPBUFSIZE 50 -ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t count, loff_t * offset) +ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset) { char tmpbuf[TMPBUFSIZE]; size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val); @@ -62,7 +62,7 @@ ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t co } -int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count) +int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count) { char tmpbuf[TMPBUFSIZE]; unsigned long flags; @@ -85,16 +85,16 @@ int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, siz } -static ssize_t ulong_read_file(struct file * file, char __user * buf, size_t count, loff_t * offset) +static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) { - unsigned long * val = file->private_data; + unsigned long *val = file->private_data; return oprofilefs_ulong_to_user(*val, buf, count, offset); } -static ssize_t ulong_write_file(struct file * file, char const __user * buf, size_t count, loff_t * offset) +static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset) { - unsigned long * value = file->private_data; + unsigned long *value = file->private_data; int retval; if (*offset) @@ -108,7 +108,7 @@ static ssize_t ulong_write_file(struct file * file, char const __user * buf, siz } -static int default_open(struct inode * inode, struct file * filp) +static int default_open(struct inode *inode, struct file *filp) { if (inode->i_private) filp->private_data = inode->i_private; @@ -129,12 +129,12 @@ static const struct file_operations ulong_ro_fops = { }; -static struct dentry * __oprofilefs_create_file(struct super_block * sb, - struct dentry * root, char const * name, const struct file_operations * fops, +static struct dentry *__oprofilefs_create_file(struct super_block *sb, + struct dentry *root, char const *name, const struct file_operations *fops, int perm) { - struct dentry * dentry; - struct inode * inode; + struct dentry *dentry; + struct inode *inode; dentry = d_alloc_name(root, name); if (!dentry) @@ -150,10 +150,10 @@ static struct dentry * __oprofilefs_create_file(struct super_block * sb, } -int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, - char const * name, unsigned long * val) +int oprofilefs_create_ulong(struct super_block *sb, struct dentry *root, + char const *name, unsigned long *val) { - struct dentry * d = __oprofilefs_create_file(sb, root, name, + struct dentry *d = __oprofilefs_create_file(sb, root, name, &ulong_fops, 0644); if (!d) return -EFAULT; @@ -163,10 +163,10 @@ int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, } -int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, - char const * name, unsigned long * val) +int oprofilefs_create_ro_ulong(struct super_block *sb, struct dentry *root, + char const *name, unsigned long *val) { - struct dentry * d = __oprofilefs_create_file(sb, root, name, + struct dentry *d = __oprofilefs_create_file(sb, root, name, &ulong_ro_fops, 0444); if (!d) return -EFAULT; @@ -176,23 +176,23 @@ int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, } -static ssize_t atomic_read_file(struct file * file, char __user * buf, size_t count, loff_t * offset) +static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) { - atomic_t * val = file->private_data; + atomic_t *val = file->private_data; return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset); } - + static const struct file_operations atomic_ro_fops = { .read = atomic_read_file, .open = default_open, }; - -int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, - char const * name, atomic_t * val) + +int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root, + char const *name, atomic_t *val) { - struct dentry * d = __oprofilefs_create_file(sb, root, name, + struct dentry *d = __oprofilefs_create_file(sb, root, name, &atomic_ro_fops, 0444); if (!d) return -EFAULT; @@ -201,9 +201,9 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, return 0; } - -int oprofilefs_create_file(struct super_block * sb, struct dentry * root, - char const * name, const struct file_operations * fops) + +int oprofilefs_create_file(struct super_block *sb, struct dentry *root, + char const *name, const struct file_operations *fops) { if (!__oprofilefs_create_file(sb, root, name, fops, 0644)) return -EFAULT; @@ -211,8 +211,8 @@ int oprofilefs_create_file(struct super_block * sb, struct dentry * root, } -int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root, - char const * name, const struct file_operations * fops, int perm) +int oprofilefs_create_file_perm(struct super_block *sb, struct dentry *root, + char const *name, const struct file_operations *fops, int perm) { if (!__oprofilefs_create_file(sb, root, name, fops, perm)) return -EFAULT; @@ -220,11 +220,11 @@ int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root, } -struct dentry * oprofilefs_mkdir(struct super_block * sb, - struct dentry * root, char const * name) +struct dentry *oprofilefs_mkdir(struct super_block *sb, + struct dentry *root, char const *name) { - struct dentry * dentry; - struct inode * inode; + struct dentry *dentry; + struct inode *inode; dentry = d_alloc_name(root, name); if (!dentry) @@ -241,10 +241,10 @@ struct dentry * oprofilefs_mkdir(struct super_block * sb, } -static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent) +static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent) { - struct inode * root_inode; - struct dentry * root_dentry; + struct inode *root_inode; + struct dentry *root_dentry; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 710a45f0d73..333f915568c 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c @@ -19,7 +19,7 @@ static int timer_notify(struct pt_regs *regs) { - oprofile_add_sample(regs, 0); + oprofile_add_sample(regs, 0); return 0; } @@ -35,7 +35,7 @@ static void timer_stop(void) } -void __init oprofile_timer_init(struct oprofile_operations * ops) +void __init oprofile_timer_init(struct oprofile_operations *ops) { ops->create_files = NULL; ops->setup = NULL; |