diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/arch/i386/Kconfig linux-2.6.12.4-test/arch/i386/Kconfig
--- linux/arch/i386/Kconfig	2005-08-09 10:46:27.000000000 +0200
+++ linux-2.6.12.4-test/arch/i386/Kconfig	2006-03-16 23:50:09.000000000 +0100
@@ -939,6 +939,24 @@
 
 	  If unsure, say Y. Only embedded should say N here.
 
+config EXECTIME_X86
+	bool "ExecTime drivers"
+	depends on EXECTIME
+	default y
+	help
+	  Choose Y here to show a list of available x86 hardware drivers
+	  for ExecTime performance measurement system.
+
+config EXECTIME_X86_P4
+	tristate "Pentium4 performance counters"
+	depends on EXECTIME_X86 && !SMP
+	default y
+	help
+	  ExecTime hardware driver using Pentium4 performance counters.
+
+comment "P4 ExecTime driver requires !SMP"
+	depends on EXECTIME_X86 && SMP
+
 endmenu
 
 
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/arch/i386/kernel/exectime-p4.c linux-2.6.12.4-test/arch/i386/kernel/exectime-p4.c
--- linux/arch/i386/kernel/exectime-p4.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12.4-test/arch/i386/kernel/exectime-p4.c	2006-03-17 00:30:13.000000000 +0100
@@ -0,0 +1,85 @@
+/*
+ *  linux/arch/i386/kernel/exectime-p4.c
+ *
+ *  Copyright (C) 2006  Szymon Acedanski
+ *
+ *  ExecTime driver using P4 performance counters.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/exectime.h>
+#include <asm/msr.h>
+
+MODULE_AUTHOR("Szymon Acedanski");
+MODULE_DESCRIPTION("Pentium4 ExecTime driver");
+MODULE_LICENSE("GPL");
+ 
+static int setup(void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+	unsigned long feat;
+
+	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6)
+		goto notavail;
+	
+	rdmsrl(MSR_IA32_MISC_ENABLE, feat);
+	if (!(feat & (1UL << 7)))
+		goto notavail;
+
+	if (c->x86_model == 3 || c->x86_model == 4) {
+		printk(KERN_INFO "exectime-p4: using instr_completed event counter\n");
+		wrmsr(MSR_P4_CRU_ESCR0, 0x07000204UL, 0);
+		wrmsr(MSR_P4_IQ_CCCR0, 0x00039000UL, 0);
+	} else {
+		printk(KERN_INFO "exectime-p4: using instr_retired event counter\n");
+
+		/* program instr_retired counter for non-bogus non-tagged uops,
+		   USR mode counting. */
+		wrmsr(MSR_P4_CRU_ESCR0, 0x04000204UL, 0);
+		wrmsr(MSR_P4_IQ_CCCR0, 0x00039000UL, 0);
+	}
+
+	return 0;
+
+notavail:
+	printk(KERN_INFO
+			"exectime-p4: P4 performance monitoring not available\n");
+	return -ENODEV;
+}
+
+static unsigned long long read_counter(void)
+{
+	unsigned long a[2];
+	rdmsr(MSR_P4_IQ_PERFCTR0, a[0], a[1]);
+	return *(unsigned long long*)a;
+}
+
+static void on_switch(struct task_struct* prev, struct task_struct* next)
+{
+	unsigned long long now = read_counter();
+	prev->exectime += now - prev->exectime_u0;
+	if (now < prev->exectime_u0) /* 40-bit counter overflow */
+		prev->exectime += 0x00000100000000000ULL;
+	next->exectime_u0 = now;
+}
+
+struct exectime_module module = {
+	.name = "pentium4",
+	.setup = setup,
+	.on_switch = on_switch,
+};
+
+int __init exectime_p4_init(void)
+{
+	return exectime_register_module(&module);
+}
+
+void __exit exectime_p4_exit(void)
+{
+	exectime_unregister_module();
+}
+
+module_init(exectime_p4_init);
+module_exit(exectime_p4_exit);
+
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/arch/i386/kernel/Makefile linux-2.6.12.4-test/arch/i386/kernel/Makefile
--- linux/arch/i386/kernel/Makefile	2005-08-09 10:46:27.000000000 +0200
+++ linux-2.6.12.4-test/arch/i386/kernel/Makefile	2006-03-16 20:50:46.000000000 +0100
@@ -33,6 +33,7 @@
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_EXECTIME_X86_P4) += exectime-p4.o
 
 EXTRA_AFLAGS   := -traditional
 
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/fs/proc/base.c linux-2.6.12.4-test/fs/proc/base.c
--- linux/fs/proc/base.c	2005-08-09 10:46:38.000000000 +0200
+++ linux-2.6.12.4-test/fs/proc/base.c	2006-03-16 21:36:11.000000000 +0100
@@ -86,6 +86,9 @@
 	PROC_TGID_FD_DIR,
 	PROC_TGID_OOM_SCORE,
 	PROC_TGID_OOM_ADJUST,
+#ifdef CONFIG_EXECTIME
+	PROC_TGID_EXECTIME,
+#endif
 	PROC_TID_INO,
 	PROC_TID_STATUS,
 	PROC_TID_MEM,
@@ -123,6 +126,9 @@
 	PROC_TID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 	PROC_TID_OOM_SCORE,
 	PROC_TID_OOM_ADJUST,
+#ifdef CONFIG_EXECTIME
+	PROC_TID_EXECTIME,
+#endif
 };
 
 struct pid_entry {
@@ -169,6 +175,9 @@
 #ifdef CONFIG_AUDITSYSCALL
 	E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
 #endif
+#ifdef CONFIG_EXECTIME
+	E(PROC_TGID_EXECTIME, "exectime", S_IFREG|S_IRUGO),
+#endif
 	{0,0,NULL,0}
 };
 static struct pid_entry tid_base_stuff[] = {
@@ -205,6 +214,10 @@
 #ifdef CONFIG_AUDITSYSCALL
 	E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
 #endif
+#ifdef CONFIG_EXECTIME
+	E(PROC_TID_EXECTIME, "exectime", S_IFREG|S_IRUGO),
+#endif
+	
 	{0,0,NULL,0}
 };
 
@@ -890,6 +903,32 @@
 };
 #endif /* CONFIG_SECCOMP */
 
+#ifdef CONFIG_EXECTIME
+static ssize_t exectime_read(struct file *file, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+	char __buf[20];
+	loff_t __ppos = *ppos;
+	size_t len;
+
+	/* no need to print the trailing zero, so use only len */
+	len = sprintf(__buf, "%llu\n", tsk->exectime);
+	if (__ppos >= len)
+		return 0;
+	if (count > len - __ppos)
+		count = len - __ppos;
+	if (copy_to_user(buf, __buf + __ppos, count))
+		return -EFAULT;
+	*ppos = __ppos + count;
+	return count;
+}
+
+static struct file_operations proc_exectime_operations = {
+	.read		= exectime_read,
+};
+#endif /* CONFIG_EXECTIME */
+
 static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct inode *inode = dentry->d_inode;
@@ -1594,6 +1633,12 @@
 			inode->i_fop = &proc_loginuid_operations;
 			break;
 #endif
+#ifdef CONFIG_EXECTIME
+		case PROC_TGID_EXECTIME:
+		case PROC_TID_EXECTIME:
+			inode->i_fop = &proc_exectime_operations;
+			break;
+#endif
 		default:
 			printk("procfs: impossible type (%d)",p->type);
 			iput(inode);
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/include/linux/exectime.h linux-2.6.12.4-test/include/linux/exectime.h
--- linux/include/linux/exectime.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12.4-test/include/linux/exectime.h	2006-03-16 20:35:43.000000000 +0100
@@ -0,0 +1,18 @@
+#ifndef __LINUX_EXECTIME_H
+#define __LINUX_EXECTIME_H
+
+struct task_struct;
+
+struct exectime_module {
+	const char* name;
+	int  (*setup)(void);
+	void (*on_switch)(struct task_struct* prev, struct task_struct* next);
+	void (*on_fork)(struct task_struct* p);
+};
+
+int exectime_register_module(struct exectime_module* m);
+void exectime_unregister_module(void);
+void exectime_on_switch(struct task_struct* prev, struct task_struct* next);
+void exectime_on_fork(struct task_struct* p);
+
+#endif
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/include/linux/sched.h linux-2.6.12.4-test/include/linux/sched.h
--- linux/include/linux/sched.h	2005-08-09 10:46:45.000000000 +0200
+++ linux-2.6.12.4-test/include/linux/sched.h	2006-03-16 20:20:31.000000000 +0100
@@ -740,6 +740,11 @@
 	nodemask_t mems_allowed;
 	int cpuset_mems_generation;
 #endif
+#ifdef CONFIG_EXECTIME
+	u64 exectime;
+	u64 exectime_u0; // for module use
+	u64 exectime_u1; // for module use
+#endif
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/init/Kconfig linux-2.6.12.4-test/init/Kconfig
--- linux/init/Kconfig	2005-08-09 10:46:46.000000000 +0200
+++ linux-2.6.12.4-test/init/Kconfig	2006-03-16 19:23:20.000000000 +0100
@@ -146,6 +146,15 @@
 	  for processing it. A preliminary version of these tools is available
 	  at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>.
 
+config EXECTIME
+	bool "ExecTime Process Accounting"
+	default y
+	help
+	  If you say Y here, each process's execution time will be measured
+	  using the new ExecTime technology. The result may be used by
+	  userspace applications for accurate evaluation of contestants
+	  programs of a programming competition.
+
 config SYSCTL
 	bool "Sysctl support"
 	---help---
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/kernel/exectime.c linux-2.6.12.4-test/kernel/exectime.c
--- linux/kernel/exectime.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12.4-test/kernel/exectime.c	2006-03-17 00:05:53.000000000 +0100
@@ -0,0 +1,70 @@
+/*
+ *  linux/kernel/exectime.c
+ *
+ *  Copyright (C) 2006  Szymon Acedanski
+ *
+ *  Precise ExecTime application performance measurement.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/exectime.h>
+
+
+/* Dummy module */
+
+static void dummy_on_switch(struct task_struct* prev, struct task_struct* next)
+{
+}
+
+static struct exectime_module dummy_module = {
+	.on_switch = dummy_on_switch,
+};
+
+/* Current module */
+
+static struct exectime_module* current_module = &dummy_module;
+static int is_active;
+
+/* Hooks */
+
+void exectime_on_switch(struct task_struct* prev, struct task_struct* next)
+{
+	current_module->on_switch(prev, next);
+}
+
+void exectime_on_fork(struct task_struct* p)
+{
+	p->exectime = 0;
+	if (current_module->on_fork)
+		current_module->on_fork(p);
+}
+
+int exectime_register_module(struct exectime_module* mod)
+{
+	int ret;
+	if (is_active)
+		return -EBUSY;
+	ret = mod->setup();
+	if (ret < 0)
+		return ret;
+
+	/* NOTE: this is racy, but we do not want to be too pedantic. */
+	
+	is_active = 1;
+	current_module = mod;
+	printk(KERN_INFO "exectime: activated module '%s'\n", mod->name);
+	return 0;
+}
+
+void exectime_unregister_module(void)
+{
+	current_module = &dummy_module;
+	is_active = 0;
+	printk(KERN_INFO "exectime: deactivated\n");
+}
+
+EXPORT_SYMBOL(exectime_register_module);
+EXPORT_SYMBOL(exectime_unregister_module);
+
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/kernel/Makefile linux-2.6.12.4-test/kernel/Makefile
--- linux/kernel/Makefile	2005-08-09 10:46:46.000000000 +0200
+++ linux-2.6.12.4-test/kernel/Makefile	2006-03-16 20:31:45.000000000 +0100
@@ -28,6 +28,7 @@
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
+obj-$(CONFIG_EXECTIME) += exectime.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/kernel/sched.c linux-2.6.12.4-test/kernel/sched.c
--- linux/kernel/sched.c	2005-08-09 10:46:47.000000000 +0200
+++ linux-2.6.12.4-test/kernel/sched.c	2006-03-16 20:06:30.000000000 +0100
@@ -1144,6 +1144,9 @@
 #ifdef CONFIG_SCHEDSTATS
 	memset(&p->sched_info, 0, sizeof(p->sched_info));
 #endif
+#ifdef CONFIG_EXECTIME
+	exectime_on_fork(p);
+#endif
 #ifdef CONFIG_PREEMPT
 	/*
 	 * During context-switch we hold precisely one spinlock, which
@@ -1372,6 +1375,10 @@
 		rq->prev_mm = oldmm;
 	}
 
+#ifdef CONFIG_EXECTIME
+	exectime_on_switch(prev, next);
+#endif
+
 	/* Here we just switch the register state and the stack. */
 	switch_to(prev, next, prev);
 
diff -Nru --exclude=asm-offsets.s --exclude=asm_offsets.h --exclude='*.o' --exclude='.*' --exclude=config --exclude='*.mod.c' --exclude='*.lds' --exclude='*.a' --exclude='*.so' --exclude=consolemap_deftbl.c --exclude=defkeymap.c --exclude=devlist.h --exclude=classlist.h --exclude='gen-*' --exclude='logo_*' --exclude='clut_*' --exclude=autoconf.h --exclude='vmlinu*' --exclude=version.h --exclude=crc32table.h --exclude='*.ko' --exclude='*.symvers' --exclude='*.map' --exclude='gen_*' --exclude='initramfs_*' linux/Makefile linux-2.6.12.4-test/Makefile
--- linux/Makefile	2005-08-09 10:52:02.000000000 +0200
+++ linux-2.6.12.4-test/Makefile	2006-03-14 21:45:41.000000000 +0100
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 12
-EXTRAVERSION = .4
+EXTRAVERSION = .4-exectime
 NAME=Woozy Numbat
 
 # *DOCUMENTATION*
