Skip to content

Instantly share code, notes, and snippets.

@masami256
Last active December 30, 2015 03:19
Show Gist options
  • Select an option

  • Save masami256/7768697 to your computer and use it in GitHub Desktop.

Select an option

Save masami256/7768697 to your computer and use it in GitHub Desktop.
lockref、spinlock、atomic_incの比較。
#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