diff -Nurb linux-2.6.22-580/arch/i386/Kconfig linux-2.6.22-590/arch/i386/Kconfig --- linux-2.6.22-580/arch/i386/Kconfig 2008-03-21 18:07:23.000000000 -0400 +++ linux-2.6.22-590/arch/i386/Kconfig 2008-03-21 18:07:50.000000000 -0400 @@ -1217,6 +1217,14 @@ source "arch/i386/oprofile/Kconfig" +config CHOPSTIX + bool "Chopstix (PlanetLab)" + depends on MODULES && OPROFILE + help + Chopstix allows you to monitor various events by summarizing them + in lossy data structures and transferring these data structures + into user space. If in doubt, say "N". + config KPROBES bool "Kprobes (EXPERIMENTAL)" depends on KALLSYMS && EXPERIMENTAL && MODULES diff -Nurb linux-2.6.22-580/drivers/oprofile/cpu_buffer.c linux-2.6.22-590/drivers/oprofile/cpu_buffer.c --- linux-2.6.22-580/drivers/oprofile/cpu_buffer.c 2007-07-08 19:32:17.000000000 -0400 +++ linux-2.6.22-590/drivers/oprofile/cpu_buffer.c 2008-03-21 18:07:50.000000000 -0400 @@ -21,6 +21,7 @@ #include #include #include +#include #include "event_buffer.h" #include "cpu_buffer.h" @@ -143,6 +144,17 @@ b->head_pos = 0; } +#ifdef CONFIG_CHOPSTIX + +struct event_spec { + unsigned int pc; + unsigned long dcookie; + unsigned count; +}; + +extern void (*rec_event)(void *,unsigned int); +#endif + static inline void add_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, unsigned long event) @@ -151,6 +163,7 @@ entry->eip = pc; entry->event = event; increment_head(cpu_buf); + } static inline void @@ -237,12 +250,75 @@ oprofile_end_trace(cpu_buf); } +#ifdef CONFIG_CHOPSTIX + +static int proc_pid_cmdline(struct task_struct *task, char * buffer) +{ + int res = 0; + unsigned int len; + struct mm_struct *mm = get_task_mm(task); + if (!mm) + goto out; + if (!mm->arg_end) + goto out_mm; /* Shh! No looking before we're done */ + + len = mm->arg_end - mm->arg_start; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + res = access_process_vm(task, mm->arg_start, buffer, len, 0); + + // If the nul at the end of args has been overwritten, then + // assume application is using setproctitle(3). + if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) { + len = strnlen(buffer, res); + if (len < res) { + res = len; + } else { + len = mm->env_end - mm->env_start; + if (len > PAGE_SIZE - res) + len = PAGE_SIZE - res; + res += access_process_vm(task, mm->env_start, buffer+res, len, 0); + res = strnlen(buffer, res); + } + } +out_mm: + mmput(mm); +out: + return res; +} +#endif + + + void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) { int is_kernel = !user_mode(regs); unsigned long pc = profile_pc(regs); + int res=0; +#ifdef CONFIG_CHOPSTIX + if (rec_event) { + struct event esig; + struct event_spec espec; + /*res = proc_pid_cmdline(current, espec->appname);*/ + esig.task = current; + espec.pc=pc; + espec.count=1; + esig.event_data=&espec; + esig.event_type=event; /* index in the event array currently set up */ + /* make sure the counters are loaded in the order we want them to show up*/ + (*rec_event)(&esig, 1); + } + else { oprofile_add_ext_sample(pc, regs, event, is_kernel); + } +#else + oprofile_add_ext_sample(pc, regs, event, is_kernel); +#endif + + } void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) diff -Nurb linux-2.6.22-580/fs/exec.c linux-2.6.22-590/fs/exec.c --- linux-2.6.22-580/fs/exec.c 2008-03-21 18:07:24.000000000 -0400 +++ linux-2.6.22-590/fs/exec.c 2008-03-21 18:07:50.000000000 -0400 @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -488,6 +489,12 @@ if (!err) { struct inode *inode = nd.dentry->d_inode; +#ifdef CONFIG_CHOPSTIX + unsigned long cookie; + if (!nd.dentry->d_cookie) + get_dcookie(nd.dentry, nd.mnt, &cookie); +#endif + file = ERR_PTR(-EACCES); if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && S_ISREG(inode->i_mode)) { diff -Nurb linux-2.6.22-580/include/linux/arrays.h linux-2.6.22-590/include/linux/arrays.h --- linux-2.6.22-580/include/linux/arrays.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.22-590/include/linux/arrays.h 2008-03-21 18:07:50.000000000 -0400 @@ -0,0 +1,35 @@ +#ifndef __ARRAYS_H__ +#define __ARRAYS_H__ +#include + +#define SAMPLING_METHOD_DEFAULT 0 +#define SAMPLING_METHOD_LOG 1 + +/* Every probe has an array handler */ + +/* XXX - Optimize this structure */ + +struct array_handler { + struct list_head link; + unsigned int (*hash_func)(void *); + unsigned int (*sampling_func)(void *,int,void *); + unsigned short size; + unsigned int threshold; + unsigned char **expcount; + unsigned int sampling_method; + unsigned int **arrays; + unsigned int arraysize; + unsigned int num_samples[2]; + void **epoch_samples; /* size-sized lists of samples */ + unsigned int (*serialize)(void *, void *); + unsigned char code[5]; +}; + +struct event { + struct list_head link; + void *event_data; + unsigned int count; + unsigned int event_type; + struct task_struct *task; +}; +#endif diff -Nurb linux-2.6.22-580/include/linux/sched.h linux-2.6.22-590/include/linux/sched.h --- linux-2.6.22-580/include/linux/sched.h 2008-03-21 18:07:27.000000000 -0400 +++ linux-2.6.22-590/include/linux/sched.h 2008-03-24 15:32:53.000000000 -0400 @@ -850,6 +850,10 @@ #endif unsigned long sleep_avg; unsigned long long timestamp, last_ran; +#ifdef CONFIG_CHOPSTIX + unsigned long last_interrupted, last_ran_j; +#endif + unsigned long long sched_time; /* sched_clock time spent running */ enum sleep_type sleep_type; diff -Nurb linux-2.6.22-580/kernel/fork.c linux-2.6.22-590/kernel/fork.c --- linux-2.6.22-580/kernel/fork.c 2008-03-21 18:07:28.000000000 -0400 +++ linux-2.6.22-590/kernel/fork.c 2008-03-21 18:07:50.000000000 -0400 @@ -197,6 +197,11 @@ tsk->btrace_seq = 0; #endif tsk->splice_pipe = NULL; + //tsk->cmdline[0]='\0'; +#ifdef CONFIG_CHOPSTIX + tsk->last_interrupted = 0; + tsk->last_ran_j = 0; +#endif return tsk; } diff -Nurb linux-2.6.22-580/kernel/sched.c linux-2.6.22-590/kernel/sched.c --- linux-2.6.22-580/kernel/sched.c 2008-03-21 18:07:28.000000000 -0400 +++ linux-2.6.22-590/kernel/sched.c 2008-03-21 18:07:50.000000000 -0400 @@ -10,7 +10,7 @@ * 1998-11-19 Implemented schedule_timeout() and related stuff * by Andrea Arcangeli * 2002-01-04 New ultra-scalable O(1) scheduler by Ingo Molnar: - * hybrid priority-list and round-robin design with + * hybrid priority-list and round-robin deventn with * an array-switch method of distributing timeslices * and per-CPU runqueues. Cleanups and useful suggestions * by Davide Libenzi, preemptible kernel bits by Robert Love. @@ -56,6 +56,7 @@ #include #include +#include #include #include @@ -3608,6 +3609,7 @@ #endif + static inline int interactive_sleep(enum sleep_type sleep_type) { return (sleep_type == SLEEP_INTERACTIVE || @@ -3617,16 +3619,54 @@ /* * schedule() is the main scheduler function. */ + +#ifdef CONFIG_CHOPSTIX +extern void (*rec_event)(void *,unsigned int); +struct event_spec { + unsigned long pc; + unsigned long dcookie; + unsigned count; + unsigned char reason; +}; + +#define top_esp (THREAD_SIZE - sizeof(unsigned long)) +#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long)) + +static inline unsigned long my_get_wchan(struct task_struct *p) +{ + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + stack_page = (unsigned long)task_stack_page(p); + esp = p->thread.esp; + if (!stack_page || esp < stack_page || esp > top_esp+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp > top_ebp+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (!in_sched_functions(eip)) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); + return 0; +} +/* CHOPSTIX */ +#endif + asmlinkage void __sched schedule(void) { struct task_struct *prev, *next; struct prio_array *array; struct list_head *queue; unsigned long long now; - unsigned long run_time; + unsigned long run_time, diff; int cpu, idx, new_prio; long *switch_count; struct rq *rq; + int sampling_reason; /* * Test if we are atomic. Since do_exit() needs to call into @@ -3680,6 +3720,7 @@ switch_count = &prev->nivcsw; if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { switch_count = &prev->nvcsw; + if (unlikely((prev->state & TASK_INTERRUPTIBLE) && unlikely(signal_pending(prev)))) prev->state = TASK_RUNNING; @@ -3689,6 +3730,11 @@ vx_uninterruptible_inc(prev); } deactivate_task(prev, rq); +#ifdef CONFIG_CHOPSTIX + if (prev->state & TASK_INTERRUPTIBLE) { + prev->last_interrupted=jiffies; + } +#endif } } @@ -3763,8 +3809,45 @@ prev->sleep_avg -= run_time; if ((long)prev->sleep_avg <= 0) prev->sleep_avg = 0; + prev->timestamp = prev->last_ran = now; +#ifdef CONFIG_CHOPSTIX + /* CHOPSTIX */ + + prev->last_ran_j = jiffies; + if (next->last_interrupted) { + diff = (jiffies-next->last_interrupted); + next->last_interrupted = 0; + sampling_reason = 0; + } + else { + diff = jiffies-next->last_ran_j; + sampling_reason = 1; + } + + if (rec_event && (diff>HZ/5)) { + struct event event; + struct event_spec espec; + unsigned long eip; + unsigned int state = next->state; + + espec.reason = sampling_reason; + + next->state = 0; + eip = next->thread.esp; + next->state = state; + + next->last_interrupted = 0; + event.event_data=&espec; + event.task=next; + espec.pc=eip; + event.event_type=2; + /* index in the event array currently set up */ + /* make sure the counters are loaded in the order we want them to show up*/ + (*rec_event)(&event, diff); + } +#endif sched_info_switch(prev, next); if (likely(prev != next)) { next->timestamp = next->last_ran = now; @@ -7275,3 +7358,9 @@ } #endif + +#ifdef CONFIG_CHOPSTIX +void (*rec_event)(void *,unsigned int); +EXPORT_SYMBOL(rec_event); +EXPORT_SYMBOL(in_sched_functions); +#endif