]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/xen/spinlock.c
xen: measure how long spinlocks spend blocking
[linux-2.6-omap-h63xx.git] / arch / x86 / xen / spinlock.c
index 0d8f3b2d9beca99dd98f372ae74e606d860928e5..d072823bc06d5715173cac52528367e6752525d9 100644 (file)
@@ -23,17 +23,20 @@ static struct xen_spinlock_stats
        u32 taken_slow_nested;
        u32 taken_slow_pickup;
        u32 taken_slow_spurious;
+       u32 taken_slow_irqenable;
 
        u64 released;
        u32 released_slow;
        u32 released_slow_kicked;
 
-#define HISTO_BUCKETS  20
-       u32 histo_spin_fast[HISTO_BUCKETS+1];
-       u32 histo_spin[HISTO_BUCKETS+1];
+#define HISTO_BUCKETS  30
+       u32 histo_spin_total[HISTO_BUCKETS+1];
+       u32 histo_spin_spinning[HISTO_BUCKETS+1];
+       u32 histo_spin_blocked[HISTO_BUCKETS+1];
 
-       u64 spinning_time;
-       u64 total_time;
+       u64 time_total;
+       u64 time_spinning;
+       u64 time_blocked;
 } spinlock_stats;
 
 static u8 zero_stats;
@@ -69,20 +72,28 @@ static void __spin_time_accum(u64 delta, u32 *array)
                array[HISTO_BUCKETS]++;
 }
 
-static inline void spin_time_accum_fast(u64 start)
+static inline void spin_time_accum_spinning(u64 start)
 {
        u32 delta = xen_clocksource_read() - start;
 
-       __spin_time_accum(delta, spinlock_stats.histo_spin_fast);
-       spinlock_stats.spinning_time += delta;
+       __spin_time_accum(delta, spinlock_stats.histo_spin_spinning);
+       spinlock_stats.time_spinning += delta;
 }
 
-static inline void spin_time_accum(u64 start)
+static inline void spin_time_accum_total(u64 start)
 {
        u32 delta = xen_clocksource_read() - start;
 
-       __spin_time_accum(delta, spinlock_stats.histo_spin);
-       spinlock_stats.total_time += delta;
+       __spin_time_accum(delta, spinlock_stats.histo_spin_total);
+       spinlock_stats.time_total += delta;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+       u32 delta = xen_clocksource_read() - start;
+
+       __spin_time_accum(delta, spinlock_stats.histo_spin_blocked);
+       spinlock_stats.time_blocked += delta;
 }
 #else  /* !CONFIG_XEN_DEBUG_FS */
 #define TIMEOUT                        (1 << 10)
@@ -93,10 +104,13 @@ static inline u64 spin_time_start(void)
        return 0;
 }
 
-static inline void spin_time_accum_fast(u64 start)
+static inline void spin_time_accum_total(u64 start)
 {
 }
-static inline void spin_time_accum(u64 start)
+static inline void spin_time_accum_spinning(u64 start)
+{
+}
+static inline void spin_time_accum_blocked(u64 start)
 {
 }
 #endif  /* CONFIG_XEN_DEBUG_FS */
@@ -167,20 +181,30 @@ static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock
        __get_cpu_var(lock_spinners) = prev;
 }
 
-static noinline int xen_spin_lock_slow(struct raw_spinlock *lock)
+static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enable)
 {
        struct xen_spinlock *xl = (struct xen_spinlock *)lock;
        struct xen_spinlock *prev;
        int irq = __get_cpu_var(lock_kicker_irq);
        int ret;
+       unsigned long flags;
+       u64 start;
 
        /* If kicker interrupts not initialized yet, just spin */
        if (irq == -1)
                return 0;
 
+       start = spin_time_start();
+
        /* announce we're spinning */
        prev = spinning_lock(xl);
 
+       flags = __raw_local_save_flags();
+       if (irq_enable) {
+               ADD_STATS(taken_slow_irqenable, 1);
+               raw_local_irq_enable();
+       }
+
        ADD_STATS(taken_slow, 1);
        ADD_STATS(taken_slow_nested, prev != NULL);
 
@@ -220,11 +244,14 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock)
        kstat_this_cpu.irqs[irq]++;
 
 out:
+       raw_local_irq_restore(flags);
        unspinning_lock(xl, prev);
+       spin_time_accum_blocked(start);
+
        return ret;
 }
 
-static void xen_spin_lock(struct raw_spinlock *lock)
+static inline void __xen_spin_lock(struct raw_spinlock *lock, bool irq_enable)
 {
        struct xen_spinlock *xl = (struct xen_spinlock *)lock;
        unsigned timeout;
@@ -253,10 +280,22 @@ static void xen_spin_lock(struct raw_spinlock *lock)
                    : "1" (1)
                    : "memory");
 
-               spin_time_accum_fast(start_spin_fast);
-       } while (unlikely(oldval != 0 && (TIMEOUT == ~0 || !xen_spin_lock_slow(lock))));
+               spin_time_accum_spinning(start_spin_fast);
+
+       } while (unlikely(oldval != 0 &&
+                         (TIMEOUT == ~0 || !xen_spin_lock_slow(lock, irq_enable))));
+
+       spin_time_accum_total(start_spin);
+}
+
+static void xen_spin_lock(struct raw_spinlock *lock)
+{
+       __xen_spin_lock(lock, false);
+}
 
-       spin_time_accum(start_spin);
+static void xen_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+       __xen_spin_lock(lock, !raw_irqs_disabled_flags(flags));
 }
 
 static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
@@ -323,6 +362,7 @@ void __init xen_init_spinlocks(void)
        pv_lock_ops.spin_is_locked = xen_spin_is_locked;
        pv_lock_ops.spin_is_contended = xen_spin_is_contended;
        pv_lock_ops.spin_lock = xen_spin_lock;
+       pv_lock_ops.spin_lock_flags = xen_spin_lock_flags;
        pv_lock_ops.spin_trylock = xen_spin_trylock;
        pv_lock_ops.spin_unlock = xen_spin_unlock;
 }
@@ -353,6 +393,8 @@ static int __init xen_spinlock_debugfs(void)
                           &spinlock_stats.taken_slow_pickup);
        debugfs_create_u32("taken_slow_spurious", 0444, d_spin_debug,
                           &spinlock_stats.taken_slow_spurious);
+       debugfs_create_u32("taken_slow_irqenable", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_irqenable);
 
        debugfs_create_u64("released", 0444, d_spin_debug, &spinlock_stats.released);
        debugfs_create_u32("released_slow", 0444, d_spin_debug,
@@ -361,14 +403,18 @@ static int __init xen_spinlock_debugfs(void)
                           &spinlock_stats.released_slow_kicked);
 
        debugfs_create_u64("time_spinning", 0444, d_spin_debug,
-                          &spinlock_stats.spinning_time);
+                          &spinlock_stats.time_spinning);
+       debugfs_create_u64("time_blocked", 0444, d_spin_debug,
+                          &spinlock_stats.time_blocked);
        debugfs_create_u64("time_total", 0444, d_spin_debug,
-                          &spinlock_stats.total_time);
+                          &spinlock_stats.time_total);
 
        xen_debugfs_create_u32_array("histo_total", 0444, d_spin_debug,
-                                    spinlock_stats.histo_spin, HISTO_BUCKETS + 1);
+                                    spinlock_stats.histo_spin_total, HISTO_BUCKETS + 1);
        xen_debugfs_create_u32_array("histo_spinning", 0444, d_spin_debug,
-                                    spinlock_stats.histo_spin_fast, HISTO_BUCKETS + 1);
+                                    spinlock_stats.histo_spin_spinning, HISTO_BUCKETS + 1);
+       xen_debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
+                                    spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
 
        return 0;
 }