From: Mikael Pettersson - core driver files and kernel changes DESC perfctr: remove bogus perfctr_sample_thread() calls EDESC From: Mikael Pettersson 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 Signed-off-by: Andrew Morton --- 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-01-23 01:42:29.896940504 -0800 +++ 25-akpm/CREDITS 2005-01-23 01:42:29.913937920 -0800 @@ -2601,6 +2601,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-01-23 01:42:29.898940200 -0800 +++ 25-akpm/drivers/Makefile 2005-01-23 01:42:29.914937768 -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-y += firmware/ obj-$(CONFIG_SUPERH) += sh/ 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-01-23 01:42:29.914937768 -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 , + 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-01-23 01:42:29.915937616 -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 +#include +#include +#include +#include + +#include + +#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-01-23 01:42:29.915937616 -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-01-23 01:42:29.916937464 -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-01-23 01:42:29.916937464 -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-01-23 01:42:29.917937312 -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 */ + +#include + +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-01-23 01:42:29.900939896 -0800 +++ 25-akpm/kernel/sched.c 2005-01-23 01:42:29.921936704 -0800 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -4073,6 +4074,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-01-23 01:42:29.903939440 -0800 +++ 25-akpm/kernel/timer.c 2005-01-23 01:42:29.923936400 -0800 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -821,6 +822,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-01-23 01:42:29.905939136 -0800 +++ 25-akpm/MAINTAINERS 2005-01-23 01:42:29.925936096 -0800 @@ -1800,6 +1800,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-01-23 01:42:29.907938832 -0800 +++ 25-akpm/kernel/sys_ni.c 2005-01-23 01:43:08.512070112 -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) _