From: Mikael Pettersson <mikpe@csd.uu.se>

- core driver files and kernel changes
DESC
perfctr: remove bogus perfctr_sample_thread() calls
EDESC
From: Mikael Pettersson <mikpe@user.it.uu.se>

2.6.10-mm3 added perfctr_sample_thread() calls in
account_{user,system}_time().  I believe these to be bogus:

1. When they are called from update_process_times(), there
   will be two perfctr_sample_thread()s per tick, one of
   which is redundant.
2. s390's weird timer tick code calls both account_{user,system}_time()
   directly, bypassing update_process_times(). In this case there
   also be two perfctr_sample_thread()s per tick.

I believe the proper fix is to remove the new calls and, should s390 ever
get perfctr support, add _one_ perfctr_sample_thread() call in s390's
account_user_vtime().

The patch below removes the extraneous calls.

Signed-off-by: Mikael Pettersson <mikpe@csd.uu.se>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/CREDITS                   |    1 
 25-akpm/MAINTAINERS               |    6 +
 25-akpm/drivers/Makefile          |    1 
 25-akpm/drivers/perfctr/Kconfig   |   45 ++++++++++
 25-akpm/drivers/perfctr/Makefile  |   16 +++
 25-akpm/drivers/perfctr/cpumask.h |   24 +++++
 25-akpm/drivers/perfctr/init.c    |   97 +++++++++++++++++++++++
 25-akpm/drivers/perfctr/version.h |    1 
 25-akpm/include/linux/perfctr.h   |  158 ++++++++++++++++++++++++++++++++++++++
 25-akpm/kernel/sched.c            |    3 
 25-akpm/kernel/sys_ni.c           |    6 +
 25-akpm/kernel/timer.c            |    2 
 kernel/sys.c                      |    0 
 13 files changed, 360 insertions(+)

diff -puN CREDITS~perfctr-core CREDITS
--- 25/CREDITS~perfctr-core	2005-03-20 16:57:00.000000000 -0800
+++ 25-akpm/CREDITS	2005-03-20 16:57:00.000000000 -0800
@@ -2624,6 +2624,7 @@ N: Mikael Pettersson
 E: mikpe@csd.uu.se
 W: http://www.csd.uu.se/~mikpe/
 D: Miscellaneous fixes
+D: Performance-monitoring counters driver
 
 N: Reed H. Petty
 E: rhp@draper.net
diff -puN drivers/Makefile~perfctr-core drivers/Makefile
--- 25/drivers/Makefile~perfctr-core	2005-03-20 16:57:00.000000000 -0800
+++ 25-akpm/drivers/Makefile	2005-03-20 16:57:00.000000000 -0800
@@ -63,6 +63,7 @@ obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
+obj-$(CONFIG_PERFCTR)		+= perfctr/
 obj-$(CONFIG_INFINIBAND)	+= infiniband/
 obj-$(CONFIG_BLK_DEV_SGIIOC4)	+= sn/
 obj-y				+= firmware/
diff -puN /dev/null drivers/perfctr/cpumask.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/perfctr/cpumask.h	2005-03-20 16:57:00.000000000 -0800
@@ -0,0 +1,24 @@
+/* $Id: cpumask.h,v 1.7 2004/05/12 19:59:01 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Partial simulation of cpumask_t on non-cpumask_t kernels.
+ * Extension to allow inspecting a cpumask_t as array of ulong.
+ * Appropriate definition of perfctr_cpus_forbidden_mask.
+ *
+ * Copyright (C) 2003-2004  Mikael Pettersson
+ */
+
+#ifdef CPU_ARRAY_SIZE
+#define PERFCTR_CPUMASK_NRLONGS	CPU_ARRAY_SIZE
+#else
+#define PERFCTR_CPUMASK_NRLONGS	1
+#endif
+
+/* `perfctr_cpus_forbidden_mask' used to be defined in <asm/perfctr.h>,
+   but cpumask_t compatibility issues forced it to be moved here. */
+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+extern cpumask_t perfctr_cpus_forbidden_mask;
+#define perfctr_cpu_is_forbidden(cpu)	cpu_isset((cpu), perfctr_cpus_forbidden_mask)
+#else
+#define perfctr_cpus_forbidden_mask	CPU_MASK_NONE
+#define perfctr_cpu_is_forbidden(cpu)	0 /* cpu_isset() needs an lvalue :-( */
+#endif
diff -puN /dev/null drivers/perfctr/init.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/perfctr/init.c	2005-03-20 16:57:00.000000000 -0800
@@ -0,0 +1,97 @@
+/* $Id: init.c,v 1.76 2004/05/31 18:18:55 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Top-level initialisation code.
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/perfctr.h>
+
+#include <asm/uaccess.h>
+
+#include "cpumask.h"
+#include "virtual.h"
+#include "version.h"
+
+struct perfctr_info perfctr_info = {
+	.abi_version = PERFCTR_ABI_VERSION,
+	.driver_version = VERSION,
+};
+
+char *perfctr_cpu_name __initdata;
+
+static int cpus_copy_to_user(const cpumask_t *cpus, struct perfctr_cpu_mask *argp)
+{
+	const unsigned int k_nrwords = PERFCTR_CPUMASK_NRLONGS*(sizeof(long)/sizeof(int));
+	unsigned int u_nrwords;
+	unsigned int ui, ki, j;
+
+	if (get_user(u_nrwords, &argp->nrwords))
+		return -EFAULT;
+	if (put_user(k_nrwords, &argp->nrwords))
+		return -EFAULT;
+	if (u_nrwords < k_nrwords)
+		return -EOVERFLOW;
+	for(ui = 0, ki = 0; ki < PERFCTR_CPUMASK_NRLONGS; ++ki) {
+		unsigned long mask = cpus_addr(*cpus)[ki];
+		for(j = 0; j < sizeof(long)/sizeof(int); ++j) {
+			if (put_user((unsigned int)mask, &argp->mask[ui]))
+				return -EFAULT;
+			++ui;
+			mask = (mask >> (8*sizeof(int)-1)) >> 1;
+		}
+	}
+	return 0;
+}
+
+asmlinkage long sys_perfctr_info(struct perfctr_info *infop,
+				 struct perfctr_cpu_mask *cpusp,
+				 struct perfctr_cpu_mask *forbiddenp)
+{
+	if (infop && copy_to_user(infop, &perfctr_info, sizeof perfctr_info))
+		return -EFAULT;
+	if (cpusp) {
+		cpumask_t cpus = cpu_online_map;
+		int err = cpus_copy_to_user(&cpus, cpusp);
+		if (err)
+			return err;
+	}
+	if (forbiddenp) {
+		cpumask_t cpus = perfctr_cpus_forbidden_mask;
+		int err = cpus_copy_to_user(&cpus, forbiddenp);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+int __init perfctr_init(void)
+{
+	int err;
+
+	err = perfctr_cpu_init();
+	if (err) {
+		printk(KERN_INFO "perfctr: not supported by this processor\n");
+		return err;
+	}
+	err = vperfctr_init();
+	if (err)
+		return err;
+	printk(KERN_INFO "perfctr: driver %s, cpu type %s at %u kHz\n",
+	       perfctr_info.driver_version,
+	       perfctr_cpu_name,
+	       perfctr_info.cpu_khz);
+	return 0;
+}
+
+void __exit perfctr_exit(void)
+{
+	vperfctr_exit();
+	perfctr_cpu_exit();
+}
+
+module_init(perfctr_init)
+module_exit(perfctr_exit)
diff -puN /dev/null drivers/perfctr/Kconfig
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/perfctr/Kconfig	2005-03-20 16:57:00.000000000 -0800
@@ -0,0 +1,45 @@
+# $Id: Kconfig,v 1.10 2004/05/24 11:00:55 mikpe Exp $
+# Performance-monitoring counters driver configuration
+#
+
+menu "Performance-monitoring counters support"
+
+config PERFCTR
+	bool "Performance monitoring counters support"
+	help
+	  This driver provides access to the performance-monitoring counter
+	  registers available in some (but not all) modern processors.
+	  These special-purpose registers can be programmed to count low-level
+	  performance-related events which occur during program execution,
+	  such as cache misses, pipeline stalls, etc.
+
+	  You can safely say Y here, even if you intend to run the kernel
+	  on a processor without performance-monitoring counters.
+
+config PERFCTR_INIT_TESTS
+	bool "Init-time hardware tests"
+	depends on PERFCTR
+	help
+	  This option makes the driver perform additional hardware tests
+	  during initialisation, and log their results in the kernel's
+	  message buffer. For most supported processors, these tests simply
+	  measure the runtime overheads of performance counter operations.
+
+	  If you have a less well-known processor (one not listed in the
+	  etc/costs/ directory in the user-space package), you should enable
+	  this option and email the results to the perfctr developers.
+
+	  If unsure, say N.
+
+config PERFCTR_VIRTUAL
+	bool "Virtual performance counters support"
+	depends on PERFCTR
+	help
+	  The processor's performance-monitoring counters are special-purpose
+	  global registers. This option adds support for virtual per-process
+	  performance-monitoring counters which only run when the process
+	  to which they belong is executing. This improves the accuracy of
+	  performance measurements by reducing "noise" from other processes.
+
+	  Say Y.
+endmenu
diff -puN /dev/null drivers/perfctr/Makefile
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/perfctr/Makefile	2005-03-20 16:57:00.000000000 -0800
@@ -0,0 +1,16 @@
+# $Id: Makefile,v 1.26 2004/05/30 23:02:14 mikpe Exp $
+# Makefile for the Performance-monitoring counters driver.
+
+# This also covers x86_64.
+perfctr-objs-$(CONFIG_X86) := x86.o
+tests-objs-$(CONFIG_X86) := x86_tests.o
+
+perfctr-objs-$(CONFIG_PPC32) := ppc.o
+tests-objs-$(CONFIG_PPC32) := ppc_tests.o
+
+perfctr-objs-y += init.o
+perfctr-objs-$(CONFIG_PERFCTR_INIT_TESTS) += $(tests-objs-y)
+perfctr-objs-$(CONFIG_PERFCTR_VIRTUAL) += virtual.o
+
+perfctr-objs		:= $(perfctr-objs-y)
+obj-$(CONFIG_PERFCTR)	:= perfctr.o
diff -puN /dev/null drivers/perfctr/version.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/perfctr/version.h	2005-03-20 16:57:00.000000000 -0800
@@ -0,0 +1 @@
+#define VERSION "2.7.3"
diff -puN /dev/null include/linux/perfctr.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/include/linux/perfctr.h	2005-03-20 16:57:00.000000000 -0800
@@ -0,0 +1,158 @@
+/* $Id: perfctr.h,v 1.78 2004/05/31 20:45:51 mikpe Exp $
+ * Performance-Monitoring Counters driver
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#ifndef _LINUX_PERFCTR_H
+#define _LINUX_PERFCTR_H
+
+#ifdef CONFIG_PERFCTR	/* don't break archs without <asm/perfctr.h> */
+
+#include <asm/perfctr.h>
+
+struct perfctr_info {
+	unsigned int abi_version;
+	char driver_version[32];
+	unsigned int cpu_type;
+	unsigned int cpu_features;
+	unsigned int cpu_khz;
+	unsigned int tsc_to_cpu_mult;
+	unsigned int _reserved2;
+	unsigned int _reserved3;
+	unsigned int _reserved4;
+};
+
+struct perfctr_cpu_mask {
+	unsigned int nrwords;
+	unsigned int mask[1];	/* actually 'nrwords' */
+};
+
+/* abi_version values: Lower 16 bits contain the CPU data version, upper
+   16 bits contain the API version. Each half has a major version in its
+   upper 8 bits, and a minor version in its lower 8 bits. */
+#define PERFCTR_API_VERSION	0x0600	/* 6.0 */
+#define PERFCTR_ABI_VERSION	((PERFCTR_API_VERSION<<16)|PERFCTR_CPU_VERSION)
+
+/* cpu_features flag bits */
+#define PERFCTR_FEATURE_RDPMC	0x01
+#define PERFCTR_FEATURE_RDTSC	0x02
+#define PERFCTR_FEATURE_PCINT	0x04
+
+/* user's view of mmap:ed virtual perfctr */
+struct vperfctr_state {
+	struct perfctr_cpu_state cpu_state;
+};
+
+/* virtual perfctr control object */
+struct vperfctr_control {
+	int si_signo;
+	struct perfctr_cpu_control cpu_control;
+	unsigned int preserve;
+	unsigned int _reserved1;
+	unsigned int _reserved2;
+	unsigned int _reserved3;
+	unsigned int _reserved4;
+};
+
+#else
+struct perfctr_info;
+struct perfctr_cpu_mask;
+struct perfctr_sum_ctrs;
+struct vperfctr_control;
+#endif	/* CONFIG_PERFCTR */
+
+#ifdef __KERNEL__
+
+/*
+ * The perfctr system calls.
+ */
+asmlinkage long sys_perfctr_info(struct perfctr_info*, struct perfctr_cpu_mask*, struct perfctr_cpu_mask*);
+asmlinkage long sys_vperfctr_open(int tid, int creat);
+asmlinkage long sys_vperfctr_control(int fd, const struct vperfctr_control*);
+asmlinkage long sys_vperfctr_unlink(int fd);
+asmlinkage long sys_vperfctr_iresume(int fd);
+asmlinkage long sys_vperfctr_read(int fd,
+				  struct perfctr_sum_ctrs*,
+				  struct vperfctr_control*);
+
+extern struct perfctr_info perfctr_info;
+
+#ifdef CONFIG_PERFCTR_VIRTUAL
+
+/*
+ * Virtual per-process performance-monitoring counters.
+ */
+struct vperfctr;	/* opaque */
+
+/* process management operations */
+extern struct vperfctr *__vperfctr_copy(struct vperfctr*);
+extern void __vperfctr_exit(struct vperfctr*);
+extern void __vperfctr_suspend(struct vperfctr*);
+extern void __vperfctr_resume(struct vperfctr*);
+extern void __vperfctr_sample(struct vperfctr*);
+extern void __vperfctr_set_cpus_allowed(struct task_struct*, struct vperfctr*, cpumask_t);
+
+static inline void perfctr_copy_thread(struct thread_struct *thread)
+{
+	thread->perfctr = NULL;
+}
+
+static inline void perfctr_exit_thread(struct thread_struct *thread)
+{
+	struct vperfctr *perfctr;
+	perfctr = thread->perfctr;
+	if (perfctr)
+		__vperfctr_exit(perfctr);
+}
+
+static inline void perfctr_suspend_thread(struct thread_struct *prev)
+{
+	struct vperfctr *perfctr;
+	perfctr = prev->perfctr;
+	if (perfctr)
+		__vperfctr_suspend(perfctr);
+}
+
+static inline void perfctr_resume_thread(struct thread_struct *next)
+{
+	struct vperfctr *perfctr;
+	perfctr = next->perfctr;
+	if (perfctr)
+		__vperfctr_resume(perfctr);
+}
+
+static inline void perfctr_sample_thread(struct thread_struct *thread)
+{
+	struct vperfctr *perfctr;
+	perfctr = thread->perfctr;
+	if (perfctr)
+		__vperfctr_sample(perfctr);
+}
+
+static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
+{
+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+	struct vperfctr *perfctr;
+
+	task_lock(p);
+	perfctr = p->thread.perfctr;
+	if (perfctr)
+		__vperfctr_set_cpus_allowed(p, perfctr, new_mask);
+	task_unlock(p);
+#endif
+}
+
+#else	/* !CONFIG_PERFCTR_VIRTUAL */
+
+static inline void perfctr_copy_thread(struct thread_struct *t) { }
+static inline void perfctr_exit_thread(struct thread_struct *t) { }
+static inline void perfctr_suspend_thread(struct thread_struct *t) { }
+static inline void perfctr_resume_thread(struct thread_struct *t) { }
+static inline void perfctr_sample_thread(struct thread_struct *t) { }
+static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t m) { }
+
+#endif	/* CONFIG_PERFCTR_VIRTUAL */
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _LINUX_PERFCTR_H */
diff -puN kernel/sched.c~perfctr-core kernel/sched.c
--- 25/kernel/sched.c~perfctr-core	2005-03-20 16:57:00.000000000 -0800
+++ 25-akpm/kernel/sched.c	2005-03-20 16:57:00.000000000 -0800
@@ -42,6 +42,7 @@
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
 #include <linux/percpu.h>
+#include <linux/perfctr.h>
 #include <linux/kthread.h>
 #include <linux/seq_file.h>
 #include <linux/syscalls.h>
@@ -4078,6 +4079,8 @@ int set_cpus_allowed(task_t *p, cpumask_
 	migration_req_t req;
 	runqueue_t *rq;
 
+	perfctr_set_cpus_allowed(p, new_mask);
+
 	rq = task_rq_lock(p, &flags);
 	if (!cpus_intersects(new_mask, cpu_online_map)) {
 		ret = -EINVAL;
diff -puN kernel/sys.c~perfctr-core kernel/sys.c
diff -puN kernel/timer.c~perfctr-core kernel/timer.c
--- 25/kernel/timer.c~perfctr-core	2005-03-20 16:57:00.000000000 -0800
+++ 25-akpm/kernel/timer.c	2005-03-20 16:57:00.000000000 -0800
@@ -32,6 +32,7 @@
 #include <linux/jiffies.h>
 #include <linux/posix-timers.h>
 #include <linux/cpu.h>
+#include <linux/perfctr.h>
 #include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
@@ -843,6 +844,7 @@ void update_process_times(int user_tick)
 		account_user_time(p, jiffies_to_cputime(1));
 	else
 		account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1));
+	perfctr_sample_thread(&p->thread);
 	run_local_timers();
 	if (rcu_pending(cpu))
 		rcu_check_callbacks(cpu, user_tick);
diff -puN MAINTAINERS~perfctr-core MAINTAINERS
--- 25/MAINTAINERS~perfctr-core	2005-03-20 16:57:00.000000000 -0800
+++ 25-akpm/MAINTAINERS	2005-03-20 16:57:00.000000000 -0800
@@ -1816,6 +1816,12 @@ M:	george@mvista.com
 L:	linux-net@vger.kernel.org
 S:	Supported
 
+PERFORMANCE-MONITORING COUNTERS DRIVER
+P:	Mikael Pettersson
+M:	mikpe@csd.uu.se
+W:	http://www.csd.uu.se/~mikpe/linux/perfctr/
+S:	Maintained
+
 PNP SUPPORT
 P:	Adam Belay
 M:	ambx1@neo.rr.com
diff -puN kernel/sys_ni.c~perfctr-core kernel/sys_ni.c
--- 25/kernel/sys_ni.c~perfctr-core	2005-03-20 16:57:00.000000000 -0800
+++ 25-akpm/kernel/sys_ni.c	2005-03-20 16:57:00.000000000 -0800
@@ -65,6 +65,12 @@ cond_syscall(compat_sys_mq_timedsend);
 cond_syscall(compat_sys_mq_timedreceive);
 cond_syscall(compat_sys_mq_notify);
 cond_syscall(compat_sys_mq_getsetattr);
+cond_syscall(sys_perfctr_info);
+cond_syscall(sys_vperfctr_open);
+cond_syscall(sys_vperfctr_control);
+cond_syscall(sys_vperfctr_unlink);
+cond_syscall(sys_vperfctr_iresume);
+cond_syscall(sys_vperfctr_read);
 cond_syscall(sys_mbind);
 cond_syscall(sys_get_mempolicy);
 cond_syscall(sys_set_mempolicy);
_