diff -Nru linux-2.6.18.5.ori/arch/i386/Kconfig linux-2.6.18.5/arch/i386/Kconfig
--- linux-2.6.18.5.ori/arch/i386/Kconfig	2006-12-02 01:13:05.000000000 +0100
+++ linux-2.6.18.5/arch/i386/Kconfig	2006-12-05 03:20:51.000000000 +0100
@@ -737,6 +737,39 @@
 
 	  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.
+
+config EXECTIME_X86_I686
+	tristate "Intel P6 family performance counters"
+	depends on EXECTIME_X86 && !SMP
+	default y
+	help
+	  ExecTime hardware driver using Intel P6 family processor
+	  performance counters.
+
+config EXECTIME_X86_AMD
+	tristate "AMD K7/K8 performance counters"
+	depends on EXECTIME_X86 && !SMP
+	default y
+	help
+	  ExecTime hardware driver using AMD K7/K8 performance counters.
+
+comment "x86 ExecTime drivers requires !SMP"
+	depends on EXECTIME_X86 && SMP
+
 source kernel/Kconfig.hz
 
 config KEXEC
diff -Nru linux-2.6.18.5.ori/arch/i386/kernel/Makefile linux-2.6.18.5/arch/i386/kernel/Makefile
--- linux-2.6.18.5.ori/arch/i386/kernel/Makefile	2006-12-02 01:13:05.000000000 +0100
+++ linux-2.6.18.5/arch/i386/kernel/Makefile	2006-12-05 03:21:30.000000000 +0100
@@ -39,6 +39,9 @@
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
 obj-$(CONFIG_K8_NB)		+= k8.o
+obj-$(CONFIG_EXECTIME_X86_P4)   += exectime-p4.o
+obj-$(CONFIG_EXECTIME_X86_I686) += exectime-i686.o
+obj-$(CONFIG_EXECTIME_X86_AMD)  += exectime-amd.o
 
 EXTRA_AFLAGS   := -traditional
 
diff -Nru linux-2.6.18.5.ori/arch/i386/kernel/exectime-amd.c linux-2.6.18.5/arch/i386/kernel/exectime-amd.c
--- linux-2.6.18.5.ori/arch/i386/kernel/exectime-amd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.5/arch/i386/kernel/exectime-amd.c	2006-12-05 03:20:51.000000000 +0100
@@ -0,0 +1,81 @@
+/*
+ *  linux/arch/i386/kernel/exectime-amd.c
+ *
+ *  Copyright (C) 2006  Szymon Acedanski
+ *
+ *  ExecTime driver using P6 family performance counters.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/exectime.h>
+#include <asm/msr.h>
+
+MODULE_AUTHOR("Szymon Acedanski");
+MODULE_DESCRIPTION("AMD K7/K8 ExecTime driver");
+MODULE_LICENSE("GPL");
+
+static int method;
+module_param(method, int, 0444);
+MODULE_PARM_DESC(method, "Counting method: 1 - instr_retired, 2 - uop_retired");
+ 
+static int setup(void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+
+	if (!cpu_has(c, X86_FEATURE_K7) && !cpu_has(c, X86_FEATURE_K8))
+		goto notavail;
+	
+    if (method == 2) {
+		printk(KERN_INFO "exectime-amd: using UOPS_RETIRED event counter\n");
+        wrmsr(MSR_K7_EVNTSEL0, 0x004100c1UL, 0);
+	} else {
+		printk(KERN_INFO "exectime-amd: using INST_RETIRED event counter\n");
+        wrmsr(MSR_K7_EVNTSEL0, 0x004100c0UL, 0);
+	}
+
+	return 0;
+
+notavail:
+	printk(KERN_INFO
+			"exectime-amd: AMD performance monitoring not available\n");
+	return -ENODEV;
+}
+
+static unsigned long long read_counter(void)
+{
+	unsigned long a[2];
+	rdmsr(MSR_K7_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;
+    /* XXX: I'm not sure if the counter is 40-bit on AMD processors. */
+	if (now < prev->exectime_u0) /* 40-bit counter overflow */
+		prev->exectime += 0x00000100000000000ULL;
+	next->exectime_u0 = now;
+}
+
+static struct exectime_module module = {
+	.name = "amd",
+	.setup = setup,
+	.on_switch = on_switch,
+};
+
+int __init exectime_amd_init(void)
+{
+	return exectime_register_module(&module);
+}
+
+void __exit exectime_amd_exit(void)
+{
+	exectime_unregister_module();
+}
+
+module_init(exectime_amd_init);
+module_exit(exectime_amd_exit);
+
diff -Nru linux-2.6.18.5.ori/arch/i386/kernel/exectime-i686.c linux-2.6.18.5/arch/i386/kernel/exectime-i686.c
--- linux-2.6.18.5.ori/arch/i386/kernel/exectime-i686.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.5/arch/i386/kernel/exectime-i686.c	2006-12-05 03:20:51.000000000 +0100
@@ -0,0 +1,80 @@
+/*
+ *  linux/arch/i386/kernel/exectime-i686.c
+ *
+ *  Copyright (C) 2006  Szymon Acedanski
+ *
+ *  ExecTime driver using P6 family performance counters.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/exectime.h>
+#include <asm/msr.h>
+
+MODULE_AUTHOR("Szymon Acedanski");
+MODULE_DESCRIPTION("Intel P6 family ExecTime driver");
+MODULE_LICENSE("GPL");
+
+static int method;
+module_param(method, int, 0444);
+MODULE_PARM_DESC(method, "Counting method: 1 - instr_retired, 2 - uop_retired");
+ 
+static int setup(void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+
+	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 != 6)
+		goto notavail;
+	
+    if (method == 2) {
+		printk(KERN_INFO "exectime-i686: using UOPS_RETIRED event counter\n");
+        wrmsr(MSR_P6_EVNTSEL0, 0x004100c2UL, 0);
+	} else {
+		printk(KERN_INFO "exectime-i686: using INST_RETIRED event counter\n");
+        wrmsr(MSR_P6_EVNTSEL0, 0x004100c0UL, 0);
+	}
+
+	return 0;
+
+notavail:
+	printk(KERN_INFO
+			"exectime-i686: P6 family performance monitoring not available\n");
+	return -ENODEV;
+}
+
+static unsigned long long read_counter(void)
+{
+	unsigned long a[2];
+	rdmsr(MSR_P6_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;
+}
+
+static struct exectime_module module = {
+	.name = "i686",
+	.setup = setup,
+	.on_switch = on_switch,
+};
+
+int __init exectime_i686_init(void)
+{
+	return exectime_register_module(&module);
+}
+
+void __exit exectime_i686_exit(void)
+{
+	exectime_unregister_module();
+}
+
+module_init(exectime_i686_init);
+module_exit(exectime_i686_exit);
+
diff -Nru linux-2.6.18.5.ori/arch/i386/kernel/exectime-p4.c linux-2.6.18.5/arch/i386/kernel/exectime-p4.c
--- linux-2.6.18.5.ori/arch/i386/kernel/exectime-p4.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.5/arch/i386/kernel/exectime-p4.c	2006-12-05 03:20:51.000000000 +0100
@@ -0,0 +1,95 @@
+/*
+ *  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/moduleparam.h>
+#include <linux/exectime.h>
+#include <asm/msr.h>
+
+MODULE_AUTHOR("Szymon Acedanski");
+MODULE_DESCRIPTION("Pentium4 ExecTime driver");
+MODULE_LICENSE("GPL");
+
+static int method;
+module_param(method, int, 0444);
+MODULE_PARM_DESC(method, "Counting method: 0 - instr_completed, 1 - instr_retired, 2 - uop_retired");
+ 
+static int setup(void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+	unsigned long feat;
+
+	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 15)
+		goto notavail;
+	
+	rdmsrl(MSR_IA32_MISC_ENABLE, feat);
+	if (!(feat & (1UL << 7)))
+		goto notavail;
+
+	if ((c->x86_model == 3 || c->x86_model == 4) && method == 0) {
+		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 if (method == 2) {
+		printk(KERN_INFO "exectime-p4: using uop_retired event counter\n");
+		wrmsr(MSR_P4_CRU_ESCR0, 0x02000204UL, 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;
+}
+
+static 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 linux-2.6.18.5.ori/fs/proc/base.c linux-2.6.18.5/fs/proc/base.c
--- linux-2.6.18.5.ori/fs/proc/base.c	2006-12-02 01:13:05.000000000 +0100
+++ linux-2.6.18.5/fs/proc/base.c	2006-12-05 03:20:51.000000000 +0100
@@ -138,6 +138,9 @@
 #endif
 	PROC_TGID_OOM_SCORE,
 	PROC_TGID_OOM_ADJUST,
+#ifdef CONFIG_EXECTIME
+	PROC_TGID_EXECTIME,
+#endif
 	PROC_TID_INO,
 	PROC_TID_STATUS,
 	PROC_TID_MEM,
@@ -181,9 +184,12 @@
 #endif
 	PROC_TID_OOM_SCORE,
 	PROC_TID_OOM_ADJUST,
-
-	/* Add new entries before this */
-	PROC_TID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
+#ifdef CONFIG_EXECTIME
+	PROC_TID_EXECTIME,
+#endif
+ 
+ 	/* Add new entries before this */
+ 	PROC_TID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
 
 /* Worst case buffer size needed for holding an integer. */
@@ -240,6 +246,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[] = {
@@ -282,6 +291,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}
 };
 
@@ -1064,6 +1077,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 = get_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 void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct inode *inode = dentry->d_inode;
@@ -1834,6 +1873,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 linux-2.6.18.5.ori/include/linux/exectime.h linux-2.6.18.5/include/linux/exectime.h
--- linux-2.6.18.5.ori/include/linux/exectime.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.5/include/linux/exectime.h	2006-12-05 03:20:51.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 linux-2.6.18.5.ori/include/linux/sched.h linux-2.6.18.5/include/linux/sched.h
--- linux-2.6.18.5.ori/include/linux/sched.h	2006-12-02 01:13:05.000000000 +0100
+++ linux-2.6.18.5/include/linux/sched.h	2006-12-05 03:20:51.000000000 +0100
@@ -915,6 +915,11 @@
 	/* Deadlock detection and priority inheritance handling */
 	struct rt_mutex_waiter *pi_blocked_on;
 #endif
+#ifdef CONFIG_EXECTIME
+	u64 exectime;
+	u64 exectime_u0; // for module use
+	u64 exectime_u1; // for module use
+#endif
 
 #ifdef CONFIG_DEBUG_MUTEXES
 	/* mutex deadlock detection */
diff -Nru linux-2.6.18.5.ori/init/Kconfig linux-2.6.18.5/init/Kconfig
--- linux-2.6.18.5.ori/init/Kconfig	2006-12-02 01:13:05.000000000 +0100
+++ linux-2.6.18.5/init/Kconfig	2006-12-05 03:20:51.000000000 +0100
@@ -273,6 +273,15 @@
 	help
 	  This enables the legacy 16-bit UID syscall wrappers.
 
+config EXECTIME
+	bool "ExecTime Process Accounting"
+	default n
+	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" if EMBEDDED
 	default y
diff -Nru linux-2.6.18.5.ori/kernel/Makefile linux-2.6.18.5/kernel/Makefile
--- linux-2.6.18.5.ori/kernel/Makefile	2006-12-02 01:13:05.000000000 +0100
+++ linux-2.6.18.5/kernel/Makefile	2006-12-05 03:20:51.000000000 +0100
@@ -46,6 +46,7 @@
 obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
+obj-$(CONFIG_EXECTIME) += exectime.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_RELAY) += relay.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
diff -Nru linux-2.6.18.5.ori/kernel/exectime.c linux-2.6.18.5/kernel/exectime.c
--- linux-2.6.18.5.ori/kernel/exectime.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.5/kernel/exectime.c	2006-12-05 03:20:51.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 linux-2.6.18.5.ori/kernel/sched.c linux-2.6.18.5/kernel/sched.c
--- linux-2.6.18.5.ori/kernel/sched.c	2006-12-02 01:13:05.000000000 +0100
+++ linux-2.6.18.5/kernel/sched.c	2006-12-05 03:20:51.000000000 +0100
@@ -53,6 +53,7 @@
 #include <linux/kprobes.h>
 #include <linux/delayacct.h>
 #include <asm/tlb.h>
+#include <linux/exectime.h>
 
 #include <asm/unistd.h>
 
@@ -1836,6 +1837,10 @@
 	spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
 #endif
 
+#ifdef CONFIG_EXECTIME
+	exectime_on_switch(prev, next);
+#endif
+
 	/* Here we just switch the register state and the stack. */
 	switch_to(prev, next, prev);
 
