+diff -Nurb --exclude='*.swp' --exclude=tags --exclude='*.patch' --exclude='*.diff' linux-2.6.22-580/arch/i386/Kconfig linux-2.6.22-590/arch/i386/Kconfig
+--- linux-2.6.22-580/arch/i386/Kconfig 2009-02-18 09:56:02.000000000 -0500
++++ linux-2.6.22-590/arch/i386/Kconfig 2009-02-18 09:57:23.000000000 -0500
+@@ -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 --exclude='*.swp' --exclude=tags --exclude='*.patch' --exclude='*.diff' linux-2.6.22-580/arch/i386/kernel/asm-offsets.c linux-2.6.22-590/arch/i386/kernel/asm-offsets.c
+--- linux-2.6.22-580/arch/i386/kernel/asm-offsets.c 2007-07-08 19:32:17.000000000 -0400
++++ linux-2.6.22-590/arch/i386/kernel/asm-offsets.c 2009-02-18 09:57:23.000000000 -0500
+@@ -9,6 +9,7 @@
+ #include <linux/signal.h>
+ #include <linux/personality.h>
+ #include <linux/suspend.h>
++#include <linux/arrays.h>
+ #include <asm/ucontext.h>
+ #include "sigframe.h"
+ #include <asm/pgtable.h>
+@@ -25,9 +26,19 @@
+ #define OFFSET(sym, str, mem) \
+ DEFINE(sym, offsetof(struct str, mem));
+
++#define STACKOFFSET(sym, str, mem) \
++ DEFINE(sym, offsetof(struct str, mem)-sizeof(struct str));
++
+ /* workaround for a warning with -Wmissing-prototypes */
+ void foo(void);
+
++struct event_spec {
++ unsigned long pc;
++ unsigned long dcookie;
++ unsigned count;
++ unsigned int number;
++};
++
+ void foo(void)
+ {
+ OFFSET(SIGCONTEXT_eax, sigcontext, eax);
+@@ -51,7 +62,16 @@
+ OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
+ BLANK();
+
+- OFFSET(TI_task, thread_info, task);
++ STACKOFFSET(TASK_thread, task_struct, thread);
++ STACKOFFSET(THREAD_esp, thread_struct, esp);
++ STACKOFFSET(EVENT_event_data, event, event_data);
++ STACKOFFSET(EVENT_task, event, task);
++ STACKOFFSET(EVENT_event_type, event, event_data);
++ STACKOFFSET(SPEC_number, event_spec, number);
++ DEFINE(EVENT_SIZE, sizeof(struct event));
++ DEFINE(SPEC_SIZE, sizeof(struct event_spec));
++ DEFINE(SPEC_EVENT_SIZE, sizeof(struct event_spec)+sizeof(struct event));
++
+ OFFSET(TI_exec_domain, thread_info, exec_domain);
+ OFFSET(TI_flags, thread_info, flags);
+ OFFSET(TI_status, thread_info, status);
+diff -Nurb --exclude='*.swp' --exclude=tags --exclude='*.patch' --exclude='*.diff' linux-2.6.22-580/arch/i386/mm/fault.c linux-2.6.22-590/arch/i386/mm/fault.c
+--- linux-2.6.22-580/arch/i386/mm/fault.c 2009-02-18 09:56:02.000000000 -0500
++++ linux-2.6.22-590/arch/i386/mm/fault.c 2009-02-18 09:57:23.000000000 -0500
+@@ -60,6 +60,15 @@
+ DIE_PAGE_FAULT, &args);
+ }
+
++
++extern void (*rec_event)(void *,unsigned int);
++struct event_spec {
++ unsigned long pc;
++ unsigned long dcookie;
++ unsigned count;
++ unsigned char reason;
++};
++
+ /*
+ * Return EIP plus the CS segment base. The segment limit is also
+ * adjusted, clamped to the kernel/user address space (whichever is
+@@ -296,6 +305,8 @@
+ * bit 3 == 1 means use of reserved bit detected
+ * bit 4 == 1 means fault was an instruction fetch
+ */
++
++
+ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
+ unsigned long error_code)
+ {
+diff -Nurb --exclude='*.swp' --exclude=tags --exclude='*.patch' --exclude='*.diff' linux-2.6.22-580/block/ll_rw_blk.c linux-2.6.22-590/block/ll_rw_blk.c
+--- linux-2.6.22-580/block/ll_rw_blk.c 2009-02-18 09:55:48.000000000 -0500
++++ linux-2.6.22-590/block/ll_rw_blk.c 2009-02-18 09:57:23.000000000 -0500
+@@ -30,6 +30,7 @@
+ #include <linux/cpu.h>
+ #include <linux/blktrace_api.h>
+ #include <linux/fault-inject.h>
++#include <linux/arrays.h>
+
+ /*
+ * for max sense size
+@@ -3102,6 +3103,13 @@
+
+ #endif /* CONFIG_FAIL_MAKE_REQUEST */
+
++extern void (*rec_event)(void *,unsigned int);
++struct event_spec {
++ unsigned long pc;
++ unsigned long dcookie;
++ unsigned count;
++ unsigned char reason;
++};
+ /**
+ * generic_make_request: hand a buffer to its device driver for I/O
+ * @bio: The bio describing the location in memory and on the device.
+@@ -3220,7 +3228,23 @@
+ goto end_io;
+ }
+ }
+-
++#ifdef CONFIG_CHOPSTIX
++ if (rec_event) {
++ struct event event;
++ struct event_spec espec;
++ unsigned long eip;
++
++ espec.reason = 0;/*request */
++
++ eip = bio->bi_end_io;
++ event.event_data=&espec;
++ espec.pc=eip;
++ event.event_type=3;
++ /* 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, bio->bi_size);
++ }
++#endif
+ ret = q->make_request_fn(q, bio);
+ } while (ret);
+ }
+diff -Nurb --exclude='*.swp' --exclude=tags --exclude='*.patch' --exclude='*.diff' linux-2.6.22-580/drivers/oprofile/cpu_buffer.c linux-2.6.22-590/drivers/oprofile/cpu_buffer.c