| David Daney | bba9076 | 2010-02-16 15:26:35 -0800 | [diff] [blame] | 1 | #include <linux/init.h> | 
 | 2 | #include <linux/kthread.h> | 
 | 3 | #include <linux/hrtimer.h> | 
 | 4 | #include <linux/fs.h> | 
 | 5 | #include <linux/debugfs.h> | 
 | 6 | #include <linux/module.h> | 
 | 7 | #include <linux/spinlock.h> | 
 | 8 |  | 
 | 9 |  | 
 | 10 | static int ss_get(void *data, u64 *val) | 
 | 11 | { | 
 | 12 | 	ktime_t start, finish; | 
 | 13 | 	int loops; | 
 | 14 | 	int cont; | 
 | 15 | 	DEFINE_RAW_SPINLOCK(ss_spin); | 
 | 16 |  | 
 | 17 | 	loops = 1000000; | 
 | 18 | 	cont = 1; | 
 | 19 |  | 
 | 20 | 	start = ktime_get(); | 
 | 21 |  | 
 | 22 | 	while (cont) { | 
 | 23 | 		raw_spin_lock(&ss_spin); | 
 | 24 | 		loops--; | 
 | 25 | 		if (loops == 0) | 
 | 26 | 			cont = 0; | 
 | 27 | 		raw_spin_unlock(&ss_spin); | 
 | 28 | 	} | 
 | 29 |  | 
 | 30 | 	finish = ktime_get(); | 
 | 31 |  | 
 | 32 | 	*val = ktime_us_delta(finish, start); | 
 | 33 |  | 
 | 34 | 	return 0; | 
 | 35 | } | 
 | 36 |  | 
 | 37 | DEFINE_SIMPLE_ATTRIBUTE(fops_ss, ss_get, NULL, "%llu\n"); | 
 | 38 |  | 
 | 39 |  | 
 | 40 |  | 
 | 41 | struct spin_multi_state { | 
 | 42 | 	raw_spinlock_t lock; | 
 | 43 | 	atomic_t start_wait; | 
 | 44 | 	atomic_t enter_wait; | 
 | 45 | 	atomic_t exit_wait; | 
 | 46 | 	int loops; | 
 | 47 | }; | 
 | 48 |  | 
 | 49 | struct spin_multi_per_thread { | 
 | 50 | 	struct spin_multi_state *state; | 
 | 51 | 	ktime_t start; | 
 | 52 | }; | 
 | 53 |  | 
 | 54 | static int multi_other(void *data) | 
 | 55 | { | 
 | 56 | 	int loops; | 
 | 57 | 	int cont; | 
 | 58 | 	struct spin_multi_per_thread *pt = data; | 
 | 59 | 	struct spin_multi_state *s = pt->state; | 
 | 60 |  | 
 | 61 | 	loops = s->loops; | 
 | 62 | 	cont = 1; | 
 | 63 |  | 
 | 64 | 	atomic_dec(&s->enter_wait); | 
 | 65 |  | 
 | 66 | 	while (atomic_read(&s->enter_wait)) | 
 | 67 | 		; /* spin */ | 
 | 68 |  | 
 | 69 | 	pt->start = ktime_get(); | 
 | 70 |  | 
 | 71 | 	atomic_dec(&s->start_wait); | 
 | 72 |  | 
 | 73 | 	while (atomic_read(&s->start_wait)) | 
 | 74 | 		; /* spin */ | 
 | 75 |  | 
 | 76 | 	while (cont) { | 
 | 77 | 		raw_spin_lock(&s->lock); | 
 | 78 | 		loops--; | 
 | 79 | 		if (loops == 0) | 
 | 80 | 			cont = 0; | 
 | 81 | 		raw_spin_unlock(&s->lock); | 
 | 82 | 	} | 
 | 83 |  | 
 | 84 | 	atomic_dec(&s->exit_wait); | 
 | 85 | 	while (atomic_read(&s->exit_wait)) | 
 | 86 | 		; /* spin */ | 
 | 87 | 	return 0; | 
 | 88 | } | 
 | 89 |  | 
 | 90 | static int multi_get(void *data, u64 *val) | 
 | 91 | { | 
 | 92 | 	ktime_t finish; | 
 | 93 | 	struct spin_multi_state ms; | 
 | 94 | 	struct spin_multi_per_thread t1, t2; | 
 | 95 |  | 
 | 96 | 	ms.lock = __RAW_SPIN_LOCK_UNLOCKED("multi_get"); | 
 | 97 | 	ms.loops = 1000000; | 
 | 98 |  | 
 | 99 | 	atomic_set(&ms.start_wait, 2); | 
 | 100 | 	atomic_set(&ms.enter_wait, 2); | 
 | 101 | 	atomic_set(&ms.exit_wait, 2); | 
 | 102 | 	t1.state = &ms; | 
 | 103 | 	t2.state = &ms; | 
 | 104 |  | 
 | 105 | 	kthread_run(multi_other, &t2, "multi_get"); | 
 | 106 |  | 
 | 107 | 	multi_other(&t1); | 
 | 108 |  | 
 | 109 | 	finish = ktime_get(); | 
 | 110 |  | 
 | 111 | 	*val = ktime_us_delta(finish, t1.start); | 
 | 112 |  | 
 | 113 | 	return 0; | 
 | 114 | } | 
 | 115 |  | 
 | 116 | DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n"); | 
 | 117 |  | 
 | 118 |  | 
 | 119 | extern struct dentry *mips_debugfs_dir; | 
 | 120 | static int __init spinlock_test(void) | 
 | 121 | { | 
 | 122 | 	struct dentry *d; | 
 | 123 |  | 
 | 124 | 	if (!mips_debugfs_dir) | 
 | 125 | 		return -ENODEV; | 
 | 126 |  | 
 | 127 | 	d = debugfs_create_file("spin_single", S_IRUGO, | 
 | 128 | 				mips_debugfs_dir, NULL, | 
 | 129 | 				&fops_ss); | 
 | 130 | 	if (!d) | 
 | 131 | 		return -ENOMEM; | 
 | 132 |  | 
 | 133 | 	d = debugfs_create_file("spin_multi", S_IRUGO, | 
 | 134 | 				mips_debugfs_dir, NULL, | 
 | 135 | 				&fops_multi); | 
 | 136 | 	if (!d) | 
 | 137 | 		return -ENOMEM; | 
 | 138 |  | 
 | 139 | 	return 0; | 
 | 140 | } | 
 | 141 | device_initcall(spinlock_test); |