| 
									
										
										
										
											2010-02-16 15:26:35 -08:00
										 |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/kthread.h>
 | 
					
						
							|  |  |  | #include <linux/hrtimer.h>
 | 
					
						
							|  |  |  | #include <linux/fs.h>
 | 
					
						
							|  |  |  | #include <linux/debugfs.h>
 | 
					
						
							| 
									
										
										
										
											2011-07-23 16:30:40 -04:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2010-02-16 15:26:35 -08:00
										 |  |  | #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); |