diff options
-rw-r--r-- | arch/mips/Kconfig.debug | 7 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/kernel/spinlock_test.c | 141 |
3 files changed, 149 insertions, 0 deletions
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 32a010d5edb..43dc2799773 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -121,4 +121,11 @@ config DEBUG_ZBOOT to reduce the kernel image size and speed up the booting procedure a little. +config SPINLOCK_TEST + bool "Enable spinlock timing tests in debugfs" + depends on DEBUG_FS + default n + help + Add several files to the debugfs to test spinlock speed. + endmenu diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 9326af5186f..ef20957ca14 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) diff --git a/arch/mips/kernel/spinlock_test.c b/arch/mips/kernel/spinlock_test.c new file mode 100644 index 00000000000..da61134dfc5 --- /dev/null +++ b/arch/mips/kernel/spinlock_test.c @@ -0,0 +1,141 @@ +#include <linux/init.h> +#include <linux/kthread.h> +#include <linux/hrtimer.h> +#include <linux/fs.h> +#include <linux/debugfs.h> +#include <linux/module.h> +#include <linux/spinlock.h> + + +static int ss_get(void *data, u64 *val) +{ + ktime_t start, finish; + int loops; + int cont; + DEFINE_RAW_SPINLOCK(ss_spin); + + loops = 1000000; + cont = 1; + + start = ktime_get(); + + while (cont) { + raw_spin_lock(&ss_spin); + loops--; + if (loops == 0) + cont = 0; + raw_spin_unlock(&ss_spin); + } + + finish = ktime_get(); + + *val = ktime_us_delta(finish, start); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_ss, ss_get, NULL, "%llu\n"); + + + +struct spin_multi_state { + raw_spinlock_t lock; + atomic_t start_wait; + atomic_t enter_wait; + atomic_t exit_wait; + int loops; +}; + +struct spin_multi_per_thread { + struct spin_multi_state *state; + ktime_t start; +}; + +static int multi_other(void *data) +{ + int loops; + int cont; + struct spin_multi_per_thread *pt = data; + struct spin_multi_state *s = pt->state; + + loops = s->loops; + cont = 1; + + atomic_dec(&s->enter_wait); + + while (atomic_read(&s->enter_wait)) + ; /* spin */ + + pt->start = ktime_get(); + + atomic_dec(&s->start_wait); + + while (atomic_read(&s->start_wait)) + ; /* spin */ + + while (cont) { + raw_spin_lock(&s->lock); + loops--; + if (loops == 0) + cont = 0; + raw_spin_unlock(&s->lock); + } + + atomic_dec(&s->exit_wait); + while (atomic_read(&s->exit_wait)) + ; /* spin */ + return 0; +} + +static int multi_get(void *data, u64 *val) +{ + ktime_t finish; + struct spin_multi_state ms; + struct spin_multi_per_thread t1, t2; + + ms.lock = __RAW_SPIN_LOCK_UNLOCKED("multi_get"); + ms.loops = 1000000; + + atomic_set(&ms.start_wait, 2); + atomic_set(&ms.enter_wait, 2); + atomic_set(&ms.exit_wait, 2); + t1.state = &ms; + t2.state = &ms; + + kthread_run(multi_other, &t2, "multi_get"); + + multi_other(&t1); + + finish = ktime_get(); + + *val = ktime_us_delta(finish, t1.start); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n"); + + +extern struct dentry *mips_debugfs_dir; +static int __init spinlock_test(void) +{ + struct dentry *d; + + if (!mips_debugfs_dir) + return -ENODEV; + + d = debugfs_create_file("spin_single", S_IRUGO, + mips_debugfs_dir, NULL, + &fops_ss); + if (!d) + return -ENOMEM; + + d = debugfs_create_file("spin_multi", S_IRUGO, + mips_debugfs_dir, NULL, + &fops_multi); + if (!d) + return -ENOMEM; + + return 0; +} +device_initcall(spinlock_test); |