lockmeter port for ppc64

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 ([email protected])
+ *  Based on klstat.h by Jack Steiner ([email protected])
+ *
+ *  Modified by Ray Bryant ([email protected])
+ *  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 ([email protected])
+ *  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 */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux