update test
[lttv.git] / trunk / tests / kernel / test-wbias-rwlock.c
index 8e77216d9f7441a2544328c32962d70b89082c1c..61c75ae45a5a89933f470ada3f13bf8969e19a6a 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/proc_fs.h>
 #include <linux/sched.h>
 #include <linux/timex.h>
-#include <linux/wbias-rwlock.h>
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/hardirq.h>
@@ -14,6 +13,7 @@
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 #include <asm/ptrace.h>
+#include <linux/wbias-rwlock.h>
 
 /* Test with no contention duration, in seconds */
 #define SINGLE_WRITER_TEST_DURATION 10
@@ -26,7 +26,6 @@
 #define NR_VARS 100
 #define NR_WRITERS 2
 #define NR_TRYLOCK_WRITERS 1
-#define NR_PREADERS 2
 #define NR_NPREADERS 2
 #define NR_TRYLOCK_READERS 1
 
 #define NR_TRYLOCK_INTERRUPT_READERS 0
 #endif
 
+/*
+ * 1 : test with thread preemption readers.
+ * 0 : test only with non-preemptable thread readers.
+ */
+#define TEST_PREEMPT 1
+
+#if (TEST_PREEMPT)
+#define NR_PREADERS 2
+#else
+#define NR_PREADERS 0
+#endif
+
+
 /*
  * Writer iteration delay, in us. 0 for busy loop. Caution : writers can
  * starve readers.
@@ -102,11 +114,32 @@ static DEFINE_RWLOCK(std_rw_lock);
 
 #else
 
-static DEFINE_WBIAS_RWLOCK(wbiasrwlock);
+#if (TEST_INTERRUPTS)
+#if (TEST_PREEMPT)
+#define WBIASRWLOCKMASK (BW_WPTHREAD | BW_RIRQ | BW_RNPTHREAD | BW_RPTHREAD)
+#else
+#define WBIASRWLOCKMASK (BW_WNPTHREAD | BW_RIRQ | BW_RNPTHREAD)
+#endif
+#else
+#if (TEST_PREEMPT)
+#define WBIASRWLOCKMASK (BW_WPTHREAD | BW_RNPTHREAD | BW_RPTHREAD)
+#else
+#define WBIASRWLOCKMASK (BW_WNPTHREAD | BW_RNPTHREAD)
+#endif
+#endif
+static DEFINE_WBIAS_RWLOCK(wbiasrwlock, WBIASRWLOCKMASK);
+CHECK_WBIAS_RWLOCK_MAP(wbiasrwlock, WBIASRWLOCKMASK);
+       
 
+#if (TEST_PREEMPT)
 #define wrap_read_lock()       wbias_read_lock(&wbiasrwlock)
 #define wrap_read_trylock()    wbias_read_trylock(&wbiasrwlock)
 #define wrap_read_unlock()     wbias_read_unlock(&wbiasrwlock)
+#else
+#define wrap_read_lock()       wbias_read_lock_inatomic(&wbiasrwlock)
+#define wrap_read_trylock()    wbias_read_trylock_inatomic(&wbiasrwlock)
+#define wrap_read_unlock()     wbias_read_unlock_inatomic(&wbiasrwlock)
+#endif
 
 #define wrap_read_lock_inatomic()      wbias_read_lock_inatomic(&wbiasrwlock)
 #define wrap_read_trylock_inatomic()   \
@@ -118,13 +151,16 @@ static DEFINE_WBIAS_RWLOCK(wbiasrwlock);
 #define wrap_read_trylock_irq()        wbias_read_trylock_irq(&wbiasrwlock)
 #define wrap_read_unlock_irq() wbias_read_unlock_irq(&wbiasrwlock)
 
-#if (TEST_INTERRUPTS)
-#define wrap_write_lock()      wbias_write_lock_irq(&wbiasrwlock)
-#define wrap_write_unlock()    wbias_write_unlock_irq(&wbiasrwlock)
-#else
-#define wrap_write_lock()      wbias_write_lock(&wbiasrwlock)
-#define wrap_write_unlock()    wbias_write_unlock(&wbiasrwlock)
-#endif
+#define wrap_write_lock()                      \
+       wbias_write_lock(&wbiasrwlock, WBIASRWLOCKMASK)
+#define wrap_write_unlock()                    \
+       wbias_write_unlock(&wbiasrwlock, WBIASRWLOCKMASK)
+#define wrap_write_trylock_else_subscribe()    \
+       wbias_write_trylock_else_subscribe(&wbiasrwlock, WBIASRWLOCKMASK)
+#define wrap_write_trylock_subscribed()                \
+       wbias_write_trylock_subscribed(&wbiasrwlock, WBIASRWLOCKMASK)
+#define wrap_write_unsubscribe()               \
+       wbias_write_unsubscribe(&wbiasrwlock, WBIASRWLOCKMASK)
 
 #endif
 
@@ -145,8 +181,9 @@ static int p_or_np_reader_thread(const char *typename,
        int i;
        int prev, cur;
        unsigned long iter = 0;
-       cycles_t time1, time2, delay, delaymax = 0, delaymin = ULLONG_MAX,
-               delayavg = 0;
+       cycles_t time1, time2, delay;
+       cycles_t ldelaymax = 0, ldelaymin = ULLONG_MAX, ldelayavg = 0;
+       cycles_t udelaymax = 0, udelaymin = ULLONG_MAX, udelayavg = 0;
 
        printk("%s/%lu runnning\n", typename, (unsigned long)data);
        do {
@@ -166,9 +203,9 @@ static int p_or_np_reader_thread(const char *typename,
                time2 = get_cycles();
                rdtsc_barrier();
                delay = time2 - time1;
-               delaymax = max(delaymax, delay);
-               delaymin = min(delaymin, delay);
-               delayavg += delay;
+               ldelaymax = max(ldelaymax, delay);
+               ldelaymin = min(ldelaymin, delay);
+               ldelayavg += delay;
                prev = var[0];
                for (i = 1; i < NR_VARS; i++) {
                        cur = var[i];
@@ -178,12 +215,25 @@ static int p_or_np_reader_thread(const char *typename,
                                "in thread\n", cur, prev, i, iter);
                }
 
+               rdtsc_barrier();
+               time1 = get_cycles();
+               rdtsc_barrier();
+
                if (!preemptable)
                        wrap_read_unlock_inatomic();
                else
                        wrap_read_unlock();
+               rdtsc_barrier();
+               time2 = get_cycles();
+               rdtsc_barrier();
+               delay = time2 - time1;
+               udelaymax = max(udelaymax, delay);
+               udelaymin = min(udelaymin, delay);
+               udelayavg += delay;
+
                if (!preemptable)
                        preempt_enable();
+
                if (THREAD_READER_DELAY)
                        msleep(THREAD_READER_DELAY);
        } while (!kthread_should_stop());
@@ -191,14 +241,22 @@ static int p_or_np_reader_thread(const char *typename,
                printk("%s/%lu iterations : %lu", typename,
                        (unsigned long)data, iter);
        } else {
-               delayavg /= iter;
+               ldelayavg /= iter;
+               udelayavg /= iter;
                printk("%s/%lu iterations : %lu, "
                        "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
                        typename,
                        (unsigned long)data, iter,
-                       calibrate_cycles(delaymin),
-                       calibrate_cycles(delayavg),
-                       calibrate_cycles(delaymax));
+                       calibrate_cycles(ldelaymin),
+                       calibrate_cycles(ldelayavg),
+                       calibrate_cycles(ldelaymax));
+               printk("%s/%lu iterations : %lu, "
+                       "unlock delay [min,avg,max] %llu,%llu,%llu cycles\n",
+                       typename,
+                       (unsigned long)data, iter,
+                       calibrate_cycles(udelaymin),
+                       calibrate_cycles(udelayavg),
+                       calibrate_cycles(udelaymax));
        }
        return 0;
 }
@@ -221,6 +279,9 @@ static int trylock_reader_thread(void *data)
 
        printk("trylock_reader_thread/%lu runnning\n", (unsigned long)data);
        do {
+#if (!TEST_PREEMPT)
+               preempt_disable();
+#endif
                while (!wrap_read_trylock())
                        iter++;
                success_iter++;
@@ -233,6 +294,9 @@ static int trylock_reader_thread(void *data)
                                "in thread\n", cur, prev, i, iter);
                }
                wrap_read_unlock();
+#if (!TEST_PREEMPT)
+               preempt_enable();
+#endif
                if (THREAD_READER_DELAY)
                        msleep(THREAD_READER_DELAY);
        } while (!kthread_should_stop());
@@ -242,9 +306,12 @@ static int trylock_reader_thread(void *data)
        return 0;
 }
 
-DEFINE_PER_CPU(cycles_t, int_delaymin);
-DEFINE_PER_CPU(cycles_t, int_delayavg);
-DEFINE_PER_CPU(cycles_t, int_delaymax);
+DEFINE_PER_CPU(cycles_t, int_ldelaymin);
+DEFINE_PER_CPU(cycles_t, int_ldelayavg);
+DEFINE_PER_CPU(cycles_t, int_ldelaymax);
+DEFINE_PER_CPU(cycles_t, int_udelaymin);
+DEFINE_PER_CPU(cycles_t, int_udelayavg);
+DEFINE_PER_CPU(cycles_t, int_udelaymax);
 DEFINE_PER_CPU(cycles_t, int_ipi_nr);
 
 static void interrupt_reader_ipi(void *data)
@@ -252,7 +319,8 @@ static void interrupt_reader_ipi(void *data)
        int i;
        int prev, cur;
        cycles_t time1, time2;
-       cycles_t *delaymax, *delaymin, *delayavg, *ipi_nr, delay;
+       cycles_t *ldelaymax, *ldelaymin, *ldelayavg, *ipi_nr, delay;
+       cycles_t *udelaymax, *udelaymin, *udelayavg;
 
        /*
         * Skip the ipi caller, not in irq context.
@@ -260,9 +328,12 @@ static void interrupt_reader_ipi(void *data)
        if (!in_irq())
                return;
 
-       delaymax = &per_cpu(int_delaymax, smp_processor_id());
-       delaymin = &per_cpu(int_delaymin, smp_processor_id());
-       delayavg = &per_cpu(int_delayavg, smp_processor_id());
+       ldelaymax = &per_cpu(int_ldelaymax, smp_processor_id());
+       ldelaymin = &per_cpu(int_ldelaymin, smp_processor_id());
+       ldelayavg = &per_cpu(int_ldelayavg, smp_processor_id());
+       udelaymax = &per_cpu(int_udelaymax, smp_processor_id());
+       udelaymin = &per_cpu(int_udelaymin, smp_processor_id());
+       udelayavg = &per_cpu(int_udelayavg, smp_processor_id());
        ipi_nr = &per_cpu(int_ipi_nr, smp_processor_id());
 
        rdtsc_barrier();
@@ -275,9 +346,9 @@ static void interrupt_reader_ipi(void *data)
        time2 = get_cycles();
        rdtsc_barrier();
        delay = time2 - time1;
-       *delaymax = max(*delaymax, delay);
-       *delaymin = min(*delaymin, delay);
-       *delayavg += delay;
+       *ldelaymax = max(*ldelaymax, delay);
+       *ldelaymin = min(*ldelaymin, delay);
+       *ldelayavg += delay;
        (*ipi_nr)++;
        prev = var[0];
        for (i = 1; i < NR_VARS; i++) {
@@ -287,7 +358,16 @@ static void interrupt_reader_ipi(void *data)
                        "Unequal cur %d/prev %d at i %d in interrupt\n",
                                cur, prev, i);
        }
+       rdtsc_barrier();
+       time1 = get_cycles();
+       rdtsc_barrier();
        wrap_read_unlock_irq();
+       time2 = get_cycles();
+       rdtsc_barrier();
+       delay = time2 - time1;
+       *udelaymax = max(*udelaymax, delay);
+       *udelaymin = min(*udelaymin, delay);
+       *udelayavg += delay;
 }
 
 DEFINE_PER_CPU(unsigned long, trylock_int_iter);
@@ -326,9 +406,12 @@ static int interrupt_reader_thread(void *data)
        int i;
 
        for_each_online_cpu(i) {
-               per_cpu(int_delaymax, i) = 0;
-               per_cpu(int_delaymin, i) = ULLONG_MAX;
-               per_cpu(int_delayavg, i) = 0;
+               per_cpu(int_ldelaymax, i) = 0;
+               per_cpu(int_ldelaymin, i) = ULLONG_MAX;
+               per_cpu(int_ldelayavg, i) = 0;
+               per_cpu(int_udelaymax, i) = 0;
+               per_cpu(int_udelaymin, i) = ULLONG_MAX;
+               per_cpu(int_udelayavg, i) = 0;
                per_cpu(int_ipi_nr, i) = 0;
        }
        do {
@@ -342,13 +425,20 @@ static int interrupt_reader_thread(void *data)
        for_each_online_cpu(i) {
                if (!per_cpu(int_ipi_nr, i))
                        continue;
-               per_cpu(int_delayavg, i) /= per_cpu(int_ipi_nr, i);
+               per_cpu(int_ldelayavg, i) /= per_cpu(int_ipi_nr, i);
+               per_cpu(int_udelayavg, i) /= per_cpu(int_ipi_nr, i);
                printk("interrupt readers on CPU %i, "
                        "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
                        i,
-                       calibrate_cycles(per_cpu(int_delaymin, i)),
-                       calibrate_cycles(per_cpu(int_delayavg, i)),
-                       calibrate_cycles(per_cpu(int_delaymax, i)));
+                       calibrate_cycles(per_cpu(int_ldelaymin, i)),
+                       calibrate_cycles(per_cpu(int_ldelayavg, i)),
+                       calibrate_cycles(per_cpu(int_ldelaymax, i)));
+               printk("interrupt readers on CPU %i, "
+                       "unlock delay [min,avg,max] %llu,%llu,%llu cycles\n",
+                       i,
+                       calibrate_cycles(per_cpu(int_udelaymin, i)),
+                       calibrate_cycles(per_cpu(int_udelayavg, i)),
+                       calibrate_cycles(per_cpu(int_udelaymax, i)));
        }
        return 0;
 }
@@ -383,13 +473,16 @@ static int writer_thread(void *data)
        int i;
        int new;
        unsigned long iter = 0;
-       cycles_t time1, time2, delay, delaymax = 0, delaymin = ULLONG_MAX,
-               delayavg = 0;
+       cycles_t time1, time2, delay;
+       cycles_t ldelaymax = 0, ldelaymin = ULLONG_MAX, ldelayavg = 0;
+       cycles_t udelaymax = 0, udelaymin = ULLONG_MAX, udelayavg = 0;
 
        printk("writer_thread/%lu runnning\n", (unsigned long)data);
        do {
                iter++;
-               //preempt_disable();    /* for get_cycles accuracy */
+#if (!TEST_PREEMPT)
+               preempt_disable();
+#endif
                rdtsc_barrier();
                time1 = get_cycles();
                rdtsc_barrier();
@@ -400,27 +493,53 @@ static int writer_thread(void *data)
                time2 = get_cycles();
                rdtsc_barrier();
                delay = time2 - time1;
-               delaymax = max(delaymax, delay);
-               delaymin = min(delaymin, delay);
-               delayavg += delay;
+               ldelaymax = max(ldelaymax, delay);
+               ldelaymin = min(ldelaymin, delay);
+               ldelayavg += delay;
                new = (int)get_cycles();
                for (i = 0; i < NR_VARS; i++) {
                        var[i] = new;
                }
 
+               rdtsc_barrier();
+               time1 = get_cycles();
+               rdtsc_barrier();
+
                wrap_write_unlock();
 
-               //preempt_enable();     /* for get_cycles accuracy */
+               rdtsc_barrier();
+               time2 = get_cycles();
+               rdtsc_barrier();
+               delay = time2 - time1;
+               udelaymax = max(udelaymax, delay);
+               udelaymin = min(udelaymin, delay);
+               udelayavg += delay;
+
+#if (!TEST_PREEMPT)
+               preempt_enable();
+#endif
                if (WRITER_DELAY > 0)
                        udelay(WRITER_DELAY);
+               cpu_relax();    /*
+                                * make sure we don't busy-loop faster than
+                                * the lock busy-loop, it would cause reader and
+                                * writer starvation.
+                                */
        } while (!kthread_should_stop());
-       delayavg /= iter;
+       ldelayavg /= iter;
+       udelayavg /= iter;
        printk("writer_thread/%lu iterations : %lu, "
                "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
                (unsigned long)data, iter,
-               calibrate_cycles(delaymin),
-               calibrate_cycles(delayavg),
-               calibrate_cycles(delaymax));
+               calibrate_cycles(ldelaymin),
+               calibrate_cycles(ldelayavg),
+               calibrate_cycles(ldelaymax));
+       printk("writer_thread/%lu iterations : %lu, "
+               "unlock delay [min,avg,max] %llu,%llu,%llu cycles\n",
+               (unsigned long)data, iter,
+               calibrate_cycles(udelaymin),
+               calibrate_cycles(udelayavg),
+               calibrate_cycles(udelaymax));
        return 0;
 }
 
@@ -470,6 +589,11 @@ locked:
 loop:
                if (TRYLOCK_WRITER_DELAY > 0)
                        udelay(TRYLOCK_WRITER_DELAY);
+               cpu_relax();    /*
+                                * make sure we don't busy-loop faster than
+                                * the lock busy-loop, it would cause reader and
+                                * writer starvation.
+                                */
        } while (!kthread_should_stop());
        printk("trylock_writer_thread/%lu iterations : "
                "[try,success,fail after %d try], "
@@ -490,36 +614,27 @@ static int trylock_writer_thread(void *data)
        printk("trylock_writer_thread/%lu runnning\n", (unsigned long)data);
        do {
                iter++;
-#if (TEST_INTERRUPTS)
-               if (wbias_write_trylock_irq_else_subscribe(&wbiasrwlock))
-#else
-               if (wbias_write_trylock_else_subscribe(&wbiasrwlock))
+#if (!TEST_PREEMPT)
+               preempt_disable();
 #endif
+               if (wrap_write_trylock_else_subscribe())
                        goto locked;
 
 #if (TRYLOCK_WRITERS_FAIL_ITER == -1)
                for (;;) {
                        iter++;
-#if (TEST_INTERRUPTS)
-                       if (wbias_write_trylock_irq_subscribed(&wbiasrwlock))
-#else
-                       if (wbias_write_trylock_subscribed(&wbiasrwlock))
-#endif
+                       if (wrap_write_trylock_subscribed())
                                goto locked;
                }
 #else
                for (i = 0; i < TRYLOCK_WRITERS_FAIL_ITER - 1; i++) {
                        iter++;
-#if (TEST_INTERRUPTS)
-                       if (wbias_write_trylock_irq_subscribed(&wbiasrwlock))
-#else
-                       if (wbias_write_trylock_subscribed(&wbiasrwlock))
-#endif
+                       if (wrap_write_trylock_subscribed())
                                goto locked;
                }
 #endif
                fail++;
-               wbias_write_unsubscribe(&wbiasrwlock);
+               wrap_write_unsubscribe();
                goto loop;
 locked:
                success++;
@@ -527,14 +642,18 @@ locked:
                for (i = 0; i < NR_VARS; i++) {
                        var[i] = new;
                }
-#if (TEST_INTERRUPTS)
-               wbias_write_unlock_irq(&wbiasrwlock);
-#else
-               wbias_write_unlock(&wbiasrwlock);
-#endif
+               wrap_write_unlock();
 loop:
+#if (!TEST_PREEMPT)
+               preempt_enable();
+#endif
                if (TRYLOCK_WRITER_DELAY > 0)
                        udelay(TRYLOCK_WRITER_DELAY);
+               cpu_relax();    /*
+                                * make sure we don't busy-loop faster than
+                                * the lock busy-loop, it would cause reader and
+                                * writer starvation.
+                                */
        } while (!kthread_should_stop());
        printk("trylock_writer_thread/%lu iterations : "
                "[try,success,fail after %d try], "
@@ -690,6 +809,7 @@ static int my_open(struct inode *inode, struct file *file)
 
        wbias_rwlock_profile_latency_print();
 
+#if (TEST_PREEMPT)
        printk("** Single non-preemptable reader test, no contention **\n");
        wbias_rwlock_profile_latency_reset();
        npreader_threads[0] = kthread_run(npreader_thread, (void *)0,
@@ -700,15 +820,18 @@ static int my_open(struct inode *inode, struct file *file)
        printk("\n");
 
        wbias_rwlock_profile_latency_print();
+#endif
 
        printk("** Multiple p/non-p readers test, no contention **\n");
        wbias_rwlock_profile_latency_reset();
+#if (TEST_PREEMPT)
        for (i = 0; i < NR_PREADERS; i++) {
                printk("starting preader thread %lu\n", i);
                preader_threads[i] = kthread_run(preader_thread, (void *)i,
                        "wbiasrwlock_preader");
                BUG_ON(!preader_threads[i]);
        }
+#endif
        for (i = 0; i < NR_NPREADERS; i++) {
                printk("starting npreader thread %lu\n", i);
                npreader_threads[i] = kthread_run(npreader_thread, (void *)i,
@@ -718,8 +841,10 @@ static int my_open(struct inode *inode, struct file *file)
        ssleep(SINGLE_READER_TEST_DURATION);
        for (i = 0; i < NR_NPREADERS; i++)
                kthread_stop(npreader_threads[i]);
+#if (TEST_PREEMPT)
        for (i = 0; i < NR_PREADERS; i++)
                kthread_stop(preader_threads[i]);
+#endif
        printk("\n");
 
        wbias_rwlock_profile_latency_print();
@@ -761,6 +886,8 @@ int init_module(void)
        printk("WRITER_MUTEX     : %016lX\n", WRITER_MUTEX);
        printk("SOFTIRQ_WMASK    : %016lX\n", SOFTIRQ_WMASK);
        printk("HARDIRQ_WMASK    : %016lX\n", HARDIRQ_WMASK);
+       printk("WQ_MUTEX         : %016lX\n", WQ_MUTEX);
+       printk("WQ_ACTIVE        : %016lX\n", WQ_ACTIVE);
 
        return 0;
 }
This page took 0.029765 seconds and 4 git commands to generate.