From: "David S. Miller" <davem@redhat.com>

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 ++++++-
 include/asm-sparc64/lockmeter.h |   20 +++++++----------
 include/asm-sparc64/spinlock.h  |    4 +++
 include/linux/lockmeter.h       |    4 +--
 kernel/lockmeter.c              |   46 ++++++++++++++++++++--------------------
 5 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-30 15:41:11.000000000 -0700
+++ 25-akpm/arch/sparc64/Kconfig	2003-08-30 15:41:12.000000000 -0700
@@ -829,12 +829,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 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-30 15:41:11.000000000 -0700
+++ 25-akpm/include/asm-sparc64/lockmeter.h	2003-08-30 15:41:12.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 <linux/smp.h>
 #include <asm/spinlock.h>
+#include <asm/timer.h>
+#include <asm/timex.h>
 
-#include <linux/version.h>
-
-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-30 15:41:12.000000000 -0700
+++ 25-akpm/include/asm-sparc64/spinlock.h	2003-08-30 15:41:12.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-30 15:41:12.000000000 -0700
+++ 25-akpm/include/linux/lockmeter.h	2003-08-30 15:41:12.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-30 15:41:12.000000000 -0700
+++ 25-akpm/kernel/lockmeter.c	2003-08-30 15:41:12.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

_