Last active
December 30, 2015 03:19
-
-
Save masami256/7768697 to your computer and use it in GitHub Desktop.
lockref、spinlock、atomic_incの比較。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <linux/module.h> | |
| #include <linux/kernel.h> | |
| #include <linux/smp.h> | |
| #include <linux/time.h> | |
| #include <linux/debugfs.h> | |
| #include <linux/string.h> | |
| MODULE_DESCRIPTION("lock test module"); | |
| MODULE_AUTHOR("masami256"); | |
| MODULE_LICENSE("GPL"); | |
| struct testfunc_ops { | |
| void(*inc_count)(void); | |
| unsigned int (*get_count)(void); | |
| }; | |
| struct locktest_data; | |
| struct locktest_data testdata; | |
| static s64 total_nanosec; | |
| #define LOCKTEST_USE_LOCKREF | |
| //#define LOCKTEST_USE_ATOMIC_INC | |
| #ifdef LOCKTEST_USE_LOCKREF | |
| #define LOCKTEST_LOCK_NAME "lockref" | |
| #include <linux/lockref.h> | |
| struct locktest_data { | |
| struct lockref ld_lockref; | |
| }; | |
| static void | |
| locktest_lockref_inc_count(void) | |
| { | |
| lockref_get(&testdata.ld_lockref); | |
| } | |
| static unsigned int | |
| locktest_lockref_get_count(void) | |
| { | |
| return testdata.ld_lockref.count; | |
| } | |
| struct testfunc_ops testfunc = { | |
| .inc_count = locktest_lockref_inc_count, | |
| .get_count = locktest_lockref_get_count, | |
| }; | |
| #elif defined(LOCKTEST_USE_ATOMIC_INC) | |
| #include <linux/spinlock.h> | |
| #define LOCKTEST_LOCK_NAME "atomic_t" | |
| struct locktest_data { | |
| atomic_t count; | |
| }; | |
| static void | |
| locktest_atomic_inc_count(void) | |
| { | |
| atomic_inc(&testdata.count); | |
| } | |
| static unsigned int | |
| locktest_atomic_get_count(void) | |
| { | |
| return (unsigned int) atomic_read(&testdata.count); | |
| } | |
| struct testfunc_ops testfunc = { | |
| .inc_count = locktest_atomic_inc_count, | |
| .get_count = locktest_atomic_get_count, | |
| }; | |
| #else // use spinlock | |
| #define LOCKTEST_LOCK_NAME "spinlock" | |
| #include <linux/spinlock.h> | |
| struct locktest_data { | |
| unsigned int count; | |
| spinlock_t ld_lock; | |
| }; | |
| static void | |
| locktest_spinlock_inc_count(void) | |
| { | |
| spin_lock(&testdata.ld_lock); | |
| testdata.count++; | |
| spin_unlock(&testdata.ld_lock); | |
| } | |
| static unsigned int | |
| locktest_spinlock_get_count(void) | |
| { | |
| return testdata.count; | |
| } | |
| struct testfunc_ops testfunc = { | |
| .inc_count = locktest_spinlock_inc_count, | |
| .get_count = locktest_spinlock_get_count, | |
| }; | |
| #endif // LOCKTEST_USE_LOCKREF | |
| #define LOOP_COUNT 1000000 | |
| static unsigned int expected_count; | |
| static void | |
| locktest_run_test(void *info) | |
| { | |
| int i = 0; | |
| for (i = 0; i < LOOP_COUNT; i++) | |
| testfunc.inc_count(); | |
| } | |
| static s64 | |
| locktest_get_current_time_as_ns(void) | |
| { | |
| struct timeval v; | |
| do_gettimeofday(&v); | |
| return timeval_to_ns(&v); | |
| } | |
| static void | |
| save_test_total_time(s64 start, s64 end) | |
| { | |
| total_nanosec = end - start; | |
| } | |
| static int num_cpus; | |
| static void | |
| locktest_start_test(void) | |
| { | |
| s64 start, end; | |
| start = locktest_get_current_time_as_ns(); | |
| on_each_cpu(&locktest_run_test, NULL, 1); | |
| end = locktest_get_current_time_as_ns(); | |
| save_test_total_time(start, end); | |
| printk(KERN_INFO "Test took %lld nanoseconds\n", total_nanosec); | |
| WARN_ON(unlikely(expected_count != testfunc.get_count())); | |
| } | |
| // debugfs operations. | |
| static struct dentry *locktest_dir; | |
| static struct dentry *locktest_tc; | |
| static struct dentry *locktest_result; | |
| static char locktest_data[8]; | |
| static char locktest_result_data[64]; | |
| static ssize_t | |
| locktest_read_result(struct file *filp, char __user *buf, size_t len, loff_t *ppos) | |
| { | |
| memset(locktest_result_data, 0, sizeof(locktest_result_data)); | |
| sprintf(locktest_result_data, "%lld", total_nanosec); | |
| return simple_read_from_buffer(buf, len, ppos, locktest_result_data, sizeof(locktest_result_data)); | |
| } | |
| static ssize_t | |
| locktest_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) | |
| { | |
| return simple_read_from_buffer(buf, len, ppos, locktest_data, sizeof(locktest_data)); | |
| } | |
| static ssize_t | |
| locktest_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) | |
| { | |
| ssize_t s = simple_write_to_buffer(locktest_data, sizeof(locktest_data), ppos, buf, len); | |
| if (!strncmp(locktest_data, "run", 3)) | |
| locktest_start_test(); | |
| else if(!strncmp(locktest_data, "reset", 5)) | |
| memset(&testdata, 0, sizeof(testdata)); | |
| memset(locktest_data, 0x0, sizeof(locktest_data)); | |
| return s; | |
| } | |
| static int | |
| locktest_check_debugfs_func_result(const struct dentry *entry) | |
| { | |
| if (!entry) | |
| return -1; | |
| if (ERR_PTR(-ENODEV) == entry) | |
| return -ENODEV; | |
| return 0; | |
| } | |
| static void | |
| locktest_remove_debugfs_dir(void) | |
| { | |
| if (locktest_dir) | |
| debugfs_remove_recursive(locktest_dir); | |
| } | |
| static int | |
| locktest_create_debugfs_directory(void) | |
| { | |
| locktest_dir = debugfs_create_dir("locktest", NULL); | |
| return locktest_check_debugfs_func_result(locktest_dir); | |
| } | |
| struct file_operations locktest_fops = { | |
| .owner = THIS_MODULE, | |
| .read = locktest_read, | |
| .write = locktest_write, | |
| }; | |
| struct file_operations locktest_result_fops = { | |
| .owner = THIS_MODULE, | |
| .read = locktest_read_result, | |
| }; | |
| static int | |
| locktest_create_file(void) | |
| { | |
| int ret = 0; | |
| locktest_tc= debugfs_create_file("testcase", 0644, locktest_dir, &locktest_data, &locktest_fops); | |
| ret = locktest_check_debugfs_func_result(locktest_tc); | |
| if (ret) | |
| return ret; | |
| locktest_result = debugfs_create_file("test_result", 0644, locktest_dir, &locktest_result, &locktest_result_fops); | |
| ret = locktest_check_debugfs_func_result(locktest_tc); | |
| if (ret) | |
| return ret; | |
| return 0; | |
| } | |
| static int | |
| locktest_init(void) | |
| { | |
| int ret = 0; | |
| ret = locktest_create_debugfs_directory(); | |
| if (ret) | |
| goto error_out; | |
| ret = locktest_create_file(); | |
| if (ret) | |
| goto error_out; | |
| num_cpus = num_online_cpus(); | |
| expected_count = num_cpus * LOOP_COUNT; | |
| printk(KERN_INFO "Use %s mechanism\n", LOCKTEST_LOCK_NAME); | |
| printk(KERN_INFO "cpus: %d\n", num_cpus); | |
| printk(KERN_INFO "module loaded\n"); | |
| return 0; | |
| error_out: | |
| locktest_remove_debugfs_dir(); | |
| return ret; | |
| } | |
| static void | |
| locktest_cleanup(void) | |
| { | |
| locktest_remove_debugfs_dir(); | |
| printk(KERN_INFO "module unloaded\n"); | |
| } | |
| module_init(locktest_init); | |
| module_exit(locktest_cleanup); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment