lockmeter port for ppc64

tdgarcia tdgarcia at us.ibm.com
Wed Nov 2 09:51:24 EST 2005


My team and I adapted your lockmeter code to the ppc64 architecture.  I 
am attaching the ppc64 specific code to this email.  This code should 
patch cleanly to the 2.6.13 kernel. 

diff -Narup linux-2.6.13/arch/ppc64/Kconfig.debug 
linux-2.6.13-lockmeter/arch/ppc64/Kconfig.debug
--- linux-2.6.13/arch/ppc64/Kconfig.debug    2005-08-28 
16:41:01.000000000 -0700
+++ linux-2.6.13-lockmeter/arch/ppc64/Kconfig.debug    2005-10-11 
07:40:28.000000000 -0700
@@ -19,6 +19,13 @@ config KPROBES
       for kernel debugging, non-intrusive instrumentation and testing.
       If in doubt, say "N".
 
+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.
+
 config DEBUG_STACK_USAGE
     bool "Stack utilization instrumentation"
     depends on DEBUG_KERNEL
diff -Narup linux-2.6.13/arch/ppc64/lib/dec_and_lock.c 
linux-2.6.13-lockmeter/arch/ppc64/lib/dec_and_lock.c
--- linux-2.6.13/arch/ppc64/lib/dec_and_lock.c    2005-08-28 
16:41:01.000000000 -0700
+++ linux-2.6.13-lockmeter/arch/ppc64/lib/dec_and_lock.c    2005-10-10 
13:02:47.000000000 -0700
@@ -28,7 +28,13 @@
  */
 
 #ifndef ATOMIC_DEC_AND_LOCK
+
+#ifndef CONFIG_LOCKMETER
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+#else
 int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+#endif /* CONFIG_LOCKMETER */
+
 {
     int counter;
     int newcount;
@@ -51,5 +57,10 @@ int _atomic_dec_and_lock(atomic_t *atomi
     return 0;
 }
 
+#ifndef CONFIG_LOCKMETER
+EXPORT_SYMBOL(atomic_dec_and_lock);
+#else
 EXPORT_SYMBOL(_atomic_dec_and_lock);
+#endif /* CONFIG_LOCKMETER */
+
 #endif /* ATOMIC_DEC_AND_LOCK */
diff -Narup linux-2.6.13/include/asm-ppc64/lockmeter.h 
linux-2.6.13-lockmeter/include/asm-ppc64/lockmeter.h
--- linux-2.6.13/include/asm-ppc64/lockmeter.h    1969-12-31 
16:00:00.000000000 -0800
+++ linux-2.6.13-lockmeter/include/asm-ppc64/lockmeter.h    2005-10-11 
08:48:48.000000000 -0700
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes at sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner at sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry at us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks.
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code here from include/lockmeter.h.
+ *
+ *  Modified by Tony Garcia (garcia1 at us.ibm.com)
+ *  Ported to Power PC 64
+ */
+
+#ifndef _PPC64_LOCKMETER_H
+#define _PPC64_LOCKMETER_H
+
+
+#include <asm/spinlock.h>
+#include <linux/version.h>
+#include <linux/cpufreq.h>
+
+#include <asm/processor.h>   /* definitions for SPRN_TBRL
+                                SPRN_TBRU, mftb()  */
+extern unsigned long ppc_proc_freq;
+
+#define CPU_CYCLE_FREQUENCY ppc_proc_freq
+
+#define THIS_CPU_NUMBER    smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a spin lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.  Not normally a problem!!
+ * we also assume that the hash table has less than 65535 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+        volatile unsigned int lock; 
+        unsigned int index;
+} inst_spinlock_t;
+
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t 
*)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+        volatile signed int lock;  
+        unsigned int index;
+        unsigned int cpu;
+} inst_rwlock_t;
+
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t 
*)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t 
*)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t 
*)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+/* Return number of readers */
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+        signed int tmp = rwlock_ptr->lock;
+
+        if ( tmp > 0 )
+                return tmp;
+        else
+                return 0;
+}
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((signed 
int)(rwlock_ptr)->lock < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((signed 
int)(rwlock_ptr)->lock > 0 )
+
+/*Written by Carl L. to get the time base counters on ppc,
+  rplaces the Intel only call rtds*/
+static inline long get_cycles64 (void)
+{
+        unsigned long tb;
+
+        /* read the upper and lower 32 bit Time base counter */
+        tb = mfspr(SPRN_TBRU);
+        tb = (tb << 32)  | mfspr(SPRN_TBRL);
+
+        return(tb);
+}
+
+#endif /* _PPC64_LOCKMETER_H */
diff -Narup linux-2.6.13/include/asm-ppc64/spinlock.h 
linux-2.6.13-lockmeter/include/asm-ppc64/spinlock.h
--- linux-2.6.13/include/asm-ppc64/spinlock.h    2005-08-28 
16:41:01.000000000 -0700
+++ linux-2.6.13-lockmeter/include/asm-ppc64/spinlock.h    2005-10-10 
14:04:25.000000000 -0700
@@ -23,6 +23,9 @@
 
 typedef struct {
     volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+  unsigned int lockmeter_magic;
+#endif /* CONFIG_LOCKMETER */
 #ifdef CONFIG_PREEMPT
     unsigned int break_lock;
 #endif
@@ -30,13 +33,20 @@ typedef struct {
 
 typedef struct {
     volatile signed int lock;
+#ifdef CONFIG_LOCKMETER
+ unsigned int index;
+ unsigned int cpu;
+#endif /* CONFIG_LOCKMETER */
 #ifdef CONFIG_PREEMPT
     unsigned int break_lock;
 #endif
 } rwlock_t;
 
-#ifdef __KERNEL__
-#define SPIN_LOCK_UNLOCKED    (spinlock_t) { 0 }
+#ifdef CONFIG_LOCKMETER
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#else
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 , 0}
+#endif /* CONFIG_LOCKMETER */
 
 #define spin_is_locked(x)    ((x)->lock != 0)
 #define spin_lock_init(x)    do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
@@ -144,7 +154,7 @@ static void __inline__ _raw_spin_lock_fl
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0 , 0 , 0 }
 
 #define rwlock_init(x)        do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
@@ -157,6 +167,44 @@ static __inline__ void _raw_write_unlock
     rw->lock = 0;
 }
 
+#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK)
+extern void _metered_spin_lock  (spinlock_t *lock, void *caller_pc);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Matches what is in arch/ppc64/lib/dec_and_lock.c, except this one is
+ *  "static inline" so that the spin_lock(), if actually invoked, is 
charged
+ *  against the real caller, not against the catch-all atomic_dec_and_lock
+ */
+static inline int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+        int counter;
+        int newcount;
+
+        for (;;) {
+                counter = atomic_read(atomic);
+                newcount = counter - 1;
+                if (!newcount)
+                        break;    /* do it the slow way */
+
+                newcount = cmpxchg(&atomic->counter, counter, newcount);
+                if (newcount == counter)
+                        return 0;
+        }
+
+        preempt_disable();
+        _metered_spin_lock(lock, __builtin_return_address(0));
+        if (atomic_dec_and_test(atomic))
+                return 1;
+        _metered_spin_unlock(lock);
+        preempt_enable();
+
+        return 0;
+}
+
+#define ATOMIC_DEC_AND_LOCK
+#endif  /* CONFIG_LOCKMETER and CONFIG_HAVE_DEC_LOCK  */
+
 /*
  * This returns the old value in the lock + 1,
  * so we got a read lock if the return value is > 0.
@@ -256,5 +304,4 @@ static void __inline__ _raw_write_lock(r
     }
 }
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_SPINLOCK_H */



More information about the Linuxppc64-dev mailing list