From: "David S. Miller" Ok, this gets lockmeter going on sparc64 and a quick test with 'lockstat' shows that it even appears to be working properly :) arch/sparc64/Kconfig | 9 ++++++- arch/sparc64/kernel/devices.c | 0 include/asm-sparc64/lockmeter.h | 20 +++++++---------- include/asm-sparc64/spinlock.h | 4 +++ include/linux/lockmeter.h | 4 +-- kernel/lockmeter.c | 46 ++++++++++++++++++++-------------------- 6 files changed, 46 insertions(+), 37 deletions(-) diff -puN arch/sparc64/Kconfig~sparc64-lockmeter-fix-2 arch/sparc64/Kconfig --- 25/arch/sparc64/Kconfig~sparc64-lockmeter-fix-2 2003-08-20 17:33:19.000000000 -0700 +++ 25-akpm/arch/sparc64/Kconfig 2003-08-20 17:33:19.000000000 -0700 @@ -852,12 +852,19 @@ config DEBUG_SPINLOCK best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP && !PREEMPT + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + # We have a custom atomic_dec_and_lock() implementation but it's not # compatible with spinlock debugging so we need to fall back on # the generic version in that case. config HAVE_DEC_LOCK bool - depends on !DEBUG_SPINLOCK + depends on !DEBUG_SPINLOCK && !LOCKMETER default y config DEBUG_SPINLOCK_SLEEP diff -puN arch/sparc64/kernel/devices.c~sparc64-lockmeter-fix-2 arch/sparc64/kernel/devices.c diff -puN include/asm-sparc64/lockmeter.h~sparc64-lockmeter-fix-2 include/asm-sparc64/lockmeter.h --- 25/include/asm-sparc64/lockmeter.h~sparc64-lockmeter-fix-2 2003-08-20 17:33:19.000000000 -0700 +++ 25-akpm/include/asm-sparc64/lockmeter.h 2003-08-20 17:33:23.000000000 -0700 @@ -1,23 +1,21 @@ /* * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) */ #ifndef _SPARC64_LOCKMETER_H #define _SPARC64_LOCKMETER_H +#include #include +#include +#include -#include - -extern unsigned long cpu_hz; -#define CPU_CYCLE_FREQUENCY cpu_hz - -#define THIS_CPU_NUMBER __cpu_number_map[smp_processor_id()] - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define local_irq_save(x) __save_and_cli(x) -#define local_irq_restore(x) __restore_flags(x) -#endif /* Linux version 2.2.x */ +/* Actually, this is not the CPU frequency by the system tick + * frequency which is good enough for lock metering. + */ +#define CPU_CYCLE_FREQUENCY (timer_tick_offset * HZ) +#define THIS_CPU_NUMBER smp_processor_id() #define PUT_INDEX(lock_ptr,indexv) (lock_ptr)->index = (indexv) #define GET_INDEX(lock_ptr) (lock_ptr)->index diff -puN include/asm-sparc64/spinlock.h~sparc64-lockmeter-fix-2 include/asm-sparc64/spinlock.h --- 25/include/asm-sparc64/spinlock.h~sparc64-lockmeter-fix-2 2003-08-20 17:33:19.000000000 -0700 +++ 25-akpm/include/asm-sparc64/spinlock.h 2003-08-20 17:33:23.000000000 -0700 @@ -134,13 +134,17 @@ typedef struct { #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) ((x)->lock != 0) +extern int __read_trylock(rwlock_t *); extern void __read_lock(rwlock_t *); extern void __read_unlock(rwlock_t *); +extern int __write_trylock(rwlock_t *); extern void __write_lock(rwlock_t *); extern void __write_unlock(rwlock_t *); +#define _raw_read_trylock(p) __read_trylock(p) #define _raw_read_lock(p) __read_lock(p) #define _raw_read_unlock(p) __read_unlock(p) +#define _raw_write_trylock(p) __write_trylock(p) #define _raw_write_lock(p) __write_lock(p) #define _raw_write_unlock(p) __write_unlock(p) diff -puN include/linux/lockmeter.h~sparc64-lockmeter-fix-2 include/linux/lockmeter.h --- 25/include/linux/lockmeter.h~sparc64-lockmeter-fix-2 2003-08-20 17:33:19.000000000 -0700 +++ 25-akpm/include/linux/lockmeter.h 2003-08-20 17:33:23.000000000 -0700 @@ -40,13 +40,13 @@ int lstat_update_time(void*, void*, int, #if defined(CONFIG_MIPS32_COMPAT) #define TIME_T uint32_t -#elif defined(CONFIG_SPARC32_COMPAT) +#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64) #define TIME_T uint64_t #else #define TIME_T time_t #endif -#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC32_COMPAT)) || (_MIPS_SZLONG==32) +#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32) #define POINTER void * #else #define POINTER int64_t diff -puN kernel/lockmeter.c~sparc64-lockmeter-fix-2 kernel/lockmeter.c --- 25/kernel/lockmeter.c~sparc64-lockmeter-fix-2 2003-08-20 17:33:19.000000000 -0700 +++ 25-akpm/kernel/lockmeter.c 2003-08-20 17:33:23.000000000 -0700 @@ -1142,28 +1142,28 @@ lockmeter_init() } } -asm(" -.align 4 -.globl __write_lock_failed -__write_lock_failed: - " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) -1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) - jne 1b - - " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) - jnz __write_lock_failed - ret - - -.align 4 -.globl __read_lock_failed -__read_lock_failed: - lock ; incl (%eax) -1: cmpl $1,(%eax) - js 1b - - lock ; decl (%eax) - js __read_lock_failed - ret +asm(" \ +.align 4 \ +.globl __write_lock_failed \ +__write_lock_failed: \ + " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) \ +1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) \ + jne 1b \ +\ + " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) \ + jnz __write_lock_failed \ + ret \ +\ +\ +.align 4 \ +.globl __read_lock_failed \ +__read_lock_failed: \ + lock ; incl (%eax) \ +1: cmpl $1,(%eax) \ + js 1b \ +\ + lock ; decl (%eax) \ + js __read_lock_failed \ + ret \ "); #endif _