a simple hardware detector for latency as well as throughput ver. 0.1.0
Subsystems (2)
PATCH 1/1 a simple hardware detector for latency as well as throughput ver. 0.1.0
Hi Jon,
The patch is the fist step to test some basic hardware functions like TSC to help people understand if there is any hardware latency as well as throughput problem exposed on bare metal or left behind by BIOS or interfered by SM. Currently the patch tests hardware features (tsc,freq, and rdrandom whiich is new instruction to get random number) in stop_machine context. I will add more after the first step get merged for those guys who want to directly play with new hardware functions.
I suppose I can add your signed-off-by as the code is derived from your hwlat_dector.
I'm also reuqesting if you are going to queue it up somewhere that can be pulled into 3.5.
Of cause, I will update the patch based upon any comments that you think must be fixed for 3.5 merge.
Thanks,
Luming
Signed-off-by Luming Yu <[email protected]>
Kconfig | 7 Makefile | 2 hw_test.c | 954 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 963 insertions(+)
drivers/misc/Kconfig +7 -0
@@ -123,6 +123,13 @@ config IBM_ASM for information on the specific driver level and support statement for your IBM server. +config HW_TEST + tristate "Testing module to detect hardware lattency and throughput" + depends on DEBUG_FS + depends on RING_BUFFER + depends on X86 + default m + config PHANTOM tristate "Sensable PHANToM (PCI)" depends on PCI
drivers/misc/Makefile +2 -0
@@ -48,4 +48,6 @@ obj-y += lis3lv02d/ obj-y += carma/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ +obj-$(CONFIG_HW_TEST) += hw_test.o + obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
drivers/misc/hw_test.c new file +954 -0
954 lines not on this page · raw message
A message that is not in the archive (sent off-list or not yet received): CAJRGBZxT2oSjecHabe7LCbmAon_0ycc__7jspTUHbru0o8DyAA@mail.gmail.com
PATCH 1/1 a simple hardware detector for latency as well as throughput ver. 0.1.0
Hi,
I'd like to know if the patch looks good for linux-next to find its way upstream in 3.6.
Thanks and regards,
Luming
---------- Forwarded message ----------
From: Luming Yu <[email protected]>
Date: Wed, May 30, 2012 at 7:47 AM
Subject: Fwd: [patch] a simple hardware detector for latency as well as throughput ver. 0.1.0
To: Andrew Morton <[email protected]>
Cc: [email protected]
Hello akpm,
I'd like to push the patch to upstream, but I'm not sure if jcm has extra bandwidth although he is also interested in having the tool upstream..So I'd like ping you to check if there is any chance to queue it up in your tree first.I will enhance it further after it's upstream.
Thanks,
Luming
---------- Forwarded message ----------
From: Luming Yu <[email protected]>
Date: Tue, May 29, 2012 at 4:37 AM
Subject: [patch] a simple hardware detector for latency as well as throughput ver. 0.1.0
To: [email protected]
Cc: [email protected]
Hi Jon,
The patch is the fist step to test some basic hardware functions like TSC to help people understand if there is any hardware latency as well as throughput problem exposed on bare metal or left behind by BIOS or interfered by SM. Currently the patch tests hardware features (tsc,freq, and rdrandom whiich is new instruction to get random number) in stop_machine context. I will add more after the first step get merged for those guys who want to directly play with new hardware functions.
I suppose I can add your signed-off-by as the code is derived from your hwlat_dector.
I'm also reuqesting if you are going to queue it up somewhere that can be pulled into 3.5.
Of cause, I will update the patch based upon any comments that you think must be fixed for 3.5 merge.
Thanks,
Luming
Signed-off-by Luming Yu <[email protected]>
Kconfig | 7
Makefile | 2
hw_test.c | 954
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 963 insertions(+)
drivers/misc/Kconfig +0 -0
@@ -123,6 +123,13 @@ config IBM_ASM
for information on the specific driver level and support statement for your IBM server.
+config HW_TEST
+ tristate "Testing module to detect hardware lattency and throughput"
+ depends on DEBUG_FS
+ depends on RING_BUFFER
+ depends on X86
+ default m
+
config PHANTOM
tristate "Sensable PHANToM (PCI)"
depends on PCI
drivers/misc/Makefile +0 -0
@@ -48,4 +48,6 @@ obj-y += lis3lv02d/
obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
+obj-$(CONFIG_HW_TEST) += hw_test.o
+
obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
drivers/misc/hw_test.c new file +447 -0
447 lines not on this page · raw message
count, (ssize_t) 0),
+ "\n");
+ count = simple_read_from_buffer(ubuf, cnt, ppos, buf, count);
+ kfree(buf);
+ return count;
+}
+
+static ssize_t debug_available_fwrite(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos) +{
+ return (ssize_t) 0;
+}
+
+static int debug_current_fopen(struct inode *inode, struct file *filp) +{
+ return 0;
+}
+
+static ssize_t debug_current_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos) +{
+ ssize_t count = 0;
+ char *buf;
+
+ buf = kzalloc(DEBUGFS_NAME_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ count += snprintf(buf + count,
+ max((ssize_t)DEBUGFS_NAME_SIZE - count, (ssize_t)0),
+ "%s ", current_sample_func->name);
+ count += snprintf(buf + count,
+ max((ssize_t)DEBUGFS_NAME_SIZE - count, (ssize_t)0),
+ "\n");
+ count = simple_read_from_buffer(ubuf, cnt, ppos, buf, count);
+ kfree(buf);
+
+ return count;
+}
+
+static ssize_t debug_current_fwrite(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos) +{
+ char *buf;
+ ssize_t count;
+ struct sample_function *sf;
+
+ buf = kzalloc(DEBUGFS_NAME_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ count = simple_write_to_buffer(buf, DEBUGFS_NAME_SIZE, ppos, ubuf, cnt);
+ mutex_lock(&sample_function_mutex);
+ list_for_each_entry(sf, &sample_function_list, list) {
+ if (strncmp(sf->name, buf, count-1) !=0)
+ continue;
+ current_sample_func = sf;
+ break;
+ }
+ mutex_unlock(&sample_function_mutex);
+ return (ssize_t) count;
+}
+
+static int debug_count_fopen(struct inode *inode, struct file *filp) +{
+ return 0;
+}
+
+static ssize_t debug_count_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos) +{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.count); +}
+static ssize_t debug_count_fwrite(struct file *filp, const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ return simple_data_write(filp, ubuf, cnt, ppos, &data.count); +}
+static int debug_enable_fopen(struct inode *inode, struct file *filp) +{
+ return 0;
+}
+static ssize_t debug_enable_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos) +{
+ char buf[4];
+ if ((cnt < sizeof(buf)) || (*ppos))
+ return 0;
+ buf[0] = enabled ? '1' : '0';
+ buf[1] = '\n';
+ buf[2] = '\0';
+ if (copy_to_user(ubuf, buf, strlen(buf)))
+ return -EFAULT;
+ return *ppos = strlen(buf);
+}
+static ssize_t debug_enable_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[4];
+ int csize = min(cnt, sizeof(buf));
+ long val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+ buf[sizeof(buf)-1] = '\0';
+ err = strict_strtoul(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+ if (val) {
+ if (enabled)
+ goto unlock;
+ enabled = 1;
+ if (start_kthread())
+ return -EFAULT;
+ } else {
+ if (!enabled)
+ goto unlock;
+ enabled = 0;
+ err = stop_kthread();
+ if (err) {
+ printk(KERN_ERR BANNER "cannot stop kthread\n");
+ return -EFAULT;
+ }
+ wake_up(&data.wq);
+ }
+unlock:
+ return csize;
+}
+static int debug_max_fopen(struct inode *inode, struct file *filp) +{
+ return 0;
+}
+static ssize_t debug_max_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.max_sample); +}
+static ssize_t debug_max_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ return simple_data_write(filp, ubuf, cnt, ppos, &data.max_sample); +}
+static int debug_sample_fopen(struct inode *inode, struct file *filp) +{
+ if (!atomic_add_unless(&data.sample_open, 1, 1))
+ return -EBUSY;
+ else
+ return 0;
+}
+static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos) +{
+ int len = 0;
+ char buf[64];
+ struct sample *sample = NULL;
+
+ if (!enabled)
+ return 0;
+ sample = kzalloc(sizeof(struct sample), GFP_KERNEL);
+ if(!sample)
+ return -ENOMEM;
+
+ while (!buffer_get_sample(sample)) {
+ DEFINE_WAIT(wait);
+ if (filp->f_flags & O_NONBLOCK) {
+ len = -EAGAIN;
+ goto out;
+ }
+ prepare_to_wait(&data.wq, &wait, TASK_INTERRUPTIBLE);
+ schedule();
+ finish_wait(&data.wq, &wait);
+ if (signal_pending(current)) {
+ len = -EINTR;
+ goto out;
+ }
+ if (!enabled) {
+ len = 0;
+ goto out;
+ }
+ }
+ len = snprintf(buf, sizeof(buf), "%010lu.%010lu\t%llu\n",
+ sample->timestamp.tv_sec,
+ sample->timestamp.tv_nsec,
+ sample->duration);
+ if (len > cnt)
+ goto out;
+ if (copy_to_user(ubuf, buf,len))
+ len = -EFAULT;
+out:
+ kfree(sample);
+ return len;
+}
+
+static int debug_sample_release(struct inode *inode, struct file *filp) +{
+ atomic_dec(&data.sample_open);
+ return 0;
+}
+static int debug_threshold_fopen(struct inode *inode, struct file *filp) +{
+ return 0;
+}
+static ssize_t debug_threshold_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos) +{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.threshold); +}
+static ssize_t debug_threshold_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ int ret;
+ ret = simple_data_write(filp, ubuf, cnt, ppos, &data.threshold);
+ if (enabled)
+ wake_up_process(kthread);
+ return ret;
+}
+static int debug_width_fopen(struct inode *inode, struct file *filp) +{
+ return 0;
+}
+static ssize_t debug_width_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_width); +}
+static ssize_t debug_width_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+ buf[U64STR_SIZE-1] = '\0';
+ err = strict_strtoull(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+ mutex_lock(&data.lock);
+ if (val < data.sample_window)
+ data.sample_width = val;
+ else {
+ mutex_unlock(&data.lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&data.lock);
+ if (enabled)
+ wake_up_process(kthread);
+
+ return csize;
+}
+static int debug_window_fopen(struct inode *inode, struct file *filp) +{
+ return 0;
+}
+static ssize_t debug_window_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_window); +}
+static ssize_t debug_window_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+ buf[U64STR_SIZE-1] = '\0';
+ err = strict_strtoull(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+ mutex_lock(&data.lock);
+ if (data.sample_width < val)
+ data.sample_window = val;
+ else {
+ mutex_unlock(&data.lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&data.lock);
+ return csize;
+}
+
+static const struct file_operations available_fops = {
+ .open = debug_available_fopen,
+ .read = debug_available_fread,
+ .write = debug_available_fwrite,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations current_fops = {
+ .open = debug_current_fopen,
+ .read = debug_current_fread,
+ .write = debug_current_fwrite,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations count_fops = {
+ .open = debug_count_fopen,
+ .read = debug_count_fread,
+ .write = debug_count_fwrite,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations enable_fops = {
+ .open = debug_enable_fopen,
+ .read = debug_enable_fread,
+ .write = debug_enable_fwrite,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations max_fops = {
+ .open = debug_max_fopen,
+ .read = debug_max_fread,
+ .write = debug_max_fwrite,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations sample_fops = {
+ .open = debug_sample_fopen,
+ .read = debug_sample_fread,
+ .release = debug_sample_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations threshold_fops = {
+ .open = debug_threshold_fopen,
+ .read = debug_threshold_fread,
+ .write = debug_threshold_fwrite,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations width_fops = {
+ .open = debug_width_fopen,
+ .read = debug_width_fread,
+ .write = debug_width_fwrite,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations window_fops = {
+ .open = debug_window_fopen,
+ .read = debug_window_fread,
+ .write = debug_window_fwrite,
+ .owner = THIS_MODULE,
+};
+static int init_debugfs(void)
+{
+ int ret = -ENOMEM;
+
+ debug_dir = debugfs_create_dir(DRVNAME, NULL);
+ if (!debug_dir)
+ goto err_debug_dir;
+
+ debug_available = debugfs_create_file("available", 0444,
+ debug_dir, NULL,
+ &available_fops);
+ if (!debug_available)
+ goto err_available;
+
+ debug_current = debugfs_create_file("current", 0444,
+ debug_dir, NULL,
+ ¤t_fops);
+ if (!debug_current)
+ goto err_current;
+
+ debug_sample = debugfs_create_file("sample", 0444,
+ debug_dir, NULL,
+ &sample_fops);
+ if (!debug_sample)
+ goto err_sample;
+
+ debug_count = debugfs_create_file("count", 0444,
+ debug_dir, NULL,
+ &count_fops);
+ if (!debug_count)
+ goto err_count;
+
+ debug_max = debugfs_create_file("max", 0444,
+ debug_dir, NULL,
+ &max_fops);
+ if (!debug_max)
+ goto err_max;
+
+ debug_sample_window = debugfs_create_file("window", 0644,
+ debug_dir, NULL,
+ &window_fops);
+ if (!debug_sample_window)
+ goto err_window;
+
+ debug_sample_width = debugfs_create_file("width", 0644,
+ debug_dir, NULL,
+ &width_fops);
+ if (!debug_sample_width)
+ goto err_width;
+
+ debug_threshold = debugfs_create_file("threshold", 0644,
+ debug_dir, NULL,
+ &threshold_fops);
+ if (!debug_threshold)
+ goto err_threshold;
+
+ debug_enable = debugfs_create_file("enable", 0644,
+ debug_dir, &enabled,
+ &enable_fops);
+ if (!debug_enable)
+ goto err_enable;
+ else {
+ ret = 0;
+ goto out;
+ }
+
+err_enable:
+ debugfs_remove(debug_threshold);
+err_threshold:
+ debugfs_remove(debug_sample_width);
+err_width:
+ debugfs_remove(debug_sample_window);
+err_window:
+ debugfs_remove(debug_max);
+err_max:
+ debugfs_remove(debug_count);
+err_count:
+ debugfs_remove(debug_sample);
+err_sample:
+ debugfs_remove(debug_current);
+err_current:
+ debugfs_remove(debug_available);
+err_available:
+ debugfs_remove(debug_dir);
+err_debug_dir:
+out:
+ return ret;
+}
+
+static void free_debugfs(void)
+{
+ debugfs_remove(debug_enable);
+ debugfs_remove(debug_threshold);
+ debugfs_remove(debug_sample_width);
+ debugfs_remove(debug_sample_window);
+ debugfs_remove(debug_max);
+ debugfs_remove(debug_count);
+ debugfs_remove(debug_sample);
+ debugfs_remove(debug_current);
+ debugfs_remove(debug_available);
+ debugfs_remove(debug_dir);
+}
+
+static int hw_test_init(void)
+{
+ int ret = -ENOMEM;
+
+ printk(KERN_INFO BANNER "version %s\n", VERSION);
+
+ sample_function_register(&tsc_sample);
+ sample_function_register(&tsc_freq_sample);
+ sample_function_register(&random_bytes_sample);
+
+ ret = init_stats();
+ if (0 != ret)
+ goto out;
+ ret = init_debugfs();
+ if (0 != ret)
+ goto err_stats;
+ if (enabled)
+ ret = start_kthread();
+ goto out;
+
+err_stats:
+ ring_buffer_free(ring_buffer);
+out:
+ return ret;
+}
+
+static void hw_test_exit(void)
+{
+ int err;
+
+ if (enabled) {
+ enabled = 0;
+ err = stop_kthread();
+ if (err)
+ printk(KERN_ERR BANNER "cannot stop kthread\n");
+ }
+
+ free_debugfs();
+ ring_buffer_free(ring_buffer);
+}
+
+module_init(hw_test_init);
+module_exit(hw_test_exit);
PATCH 1/1 a simple hardware detector for latency as well as throughput ver. 0.1.0
Hello everyone,
I'm trying to push a new tool upstream. I'd like to hear back from you what the best practice is to get the job done.
Thanks,
Luming
---------- Forwarded message ----------
From: Luming Yu <[email protected]>
Date: Mon, Jun 11, 2012 at 9:59 PM
Subject: Fwd: [patch] a simple hardware detector for latency as well as throughput ver. 0.1.0
To: [email protected]
Cc: Andrew Morton <[email protected]>, [email protected], [email protected]
Hi,
I'd like to know if the patch looks good for linux-next to find its way upstream in 3.6.
Thanks and regards,
Luming
---------- Forwarded message ----------
From: Luming Yu <[email protected]>
Date: Wed, May 30, 2012 at 7:47 AM
Subject: Fwd: [patch] a simple hardware detector for latency as well as throughput ver. 0.1.0
To: Andrew Morton <[email protected]>
Cc: [email protected]
Hello akpm,
I'd like to push the patch to upstream, but I'm not sure if jcm has extra bandwidth although he is also interested in having the tool upstream..So I'd like ping you to check if there is any chance to queue it up in your tree first.I will enhance it further after it's upstream.
Thanks,
Luming
---------- Forwarded message ----------
From: Luming Yu <[email protected]>
Date: Tue, May 29, 2012 at 4:37 AM
Subject: [patch] a simple hardware detector for latency as well as throughput ver. 0.1.0
To: [email protected]
Cc: [email protected]
Hi Jon,
The patch is the fist step to test some basic hardware functions like TSC to help people understand if there is any hardware latency as well as throughput problem exposed on bare metal or left behind by BIOS or interfered by SM. Currently the patch tests hardware features (tsc,freq, and rdrandom whiich is new instruction to get random number) in stop_machine context. I will add more after the first step get merged for those guys who want to directly play with new hardware functions.
I suppose I can add your signed-off-by as the code is derived from your hwlat_dector.
I'm also reuqesting if you are going to queue it up somewhere that can be pulled into 3.5.
Of cause, I will update the patch based upon any comments that you think must be fixed for 3.5 merge.
Thanks,
Luming
Signed-off-by Luming Yu <[email protected]>
Kconfig | 7
Makefile | 2
hw_test.c | 954
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 963 insertions(+)
Arnd Bergmann
maintainerHi Luming,
Quoted 18 lines · Luming Yu
The patch is the fist step to test some basic hardware functions like TSC to help people understand if there is any hardware latency as well as throughput problem exposed on bare metal or left behind by BIOS or interfered by SM. Currently the patch tests hardware features (tsc,freq, and rdrandom whiich is new instruction to get random number) in
stop_machinecontext. I will add more after the first step get merged for those guys who want to directly play with new hardware functions.I suppose I can add your signed-off-by as the code is derived from your
hwlat_dector.I'm also reuqesting if you are going to queue it up somewhere that can be pulled into 3.5.
Of cause, I will update the patch based upon any comments that you think must be fixed for 3.5 merge.
Quoted 8 lines
Signed-off-by Luming Yu <[email protected]>
Kconfig | 7 Makefile | 2 hw_test.c | 954 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 963 insertions(+)
Please write the text in the email so that it can be used as a permanent changelog entry for the kernel git history. Everything that you do not want to have in that history can go under the "---" line that separates the Signed-off-by from the diffstat.
Quoted 8 lines
drivers/misc/Kconfig +0
-0@@ -123,6 +123,13 @@ config IBM_ASM for information on the specific driver level and support statement for your IBM server.
drivers/misc/Kconfig config IBM_ASM · line 135
Quoted 10 lines
drivers/misc/Kconfig +7
-0+config HW_TEST + tristate "Testing module to detect hardware lattency and throughput" + depends on DEBUG_FS + depends on RING_BUFFER + depends on X86 + default m + config PHANTOM tristate "Sensable PHANToM (PCI)" depends on PCI
Any reason why this depends on X86?
I think the name "HW_TEST" is too generic. Maybe "HW_LATENCY_TEST"?
drivers/misc/Kconfig
Quoted 13 lines
drivers/misc/Kconfig +13
-0+static struct ring_buffer *ring_buffer; +static DEFINE_MUTEX(ring_buffer_mutex); +static unsigned long buf_size = 262144UL; +static struct task_struct *kthread; + +struct sample; +struct data; + +struct sample_function { + const char *name; + struct list_head list; + int (*get_sample)(void *unused); +};
why the "unused" argument?
Quoted 5 lines
drivers/misc/Kconfig +5
-0+static struct sample_function *current_sample_func = NULL; +static LIST_HEAD(sample_function_list); +static DEFINE_MUTEX(sample_function_mutex); +static int sample_function_register(struct sample_function *sf); +
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+static struct dentry *debug_dir; +static struct dentry *debug_available; +static struct dentry *debug_current; +static struct dentry *debug_max; +static struct dentry *debug_count; +static struct dentry *debug_sample_width; +static struct dentry *debug_sample_window; +static struct dentry *debug_sample; +static struct dentry *debug_threshold; +static struct dentry *debug_enable;
I think it would help here to put the local variables into a data structure that gets allocated at module load time.
Quoted 3 lines
drivers/misc/Kconfig +3
-0+static int __buffer_add_sample(struct sample *sample); +static struct sample *buffer_get_sample(struct sample *sample); +
...
drivers/misc/Kconfig
Quoted 8 lines
drivers/misc/Kconfig +8
-0+static ssize_t debug_enable_fwrite(struct file *filp, + const char __user *user_buffer, + size_t user_size, loff_t *offset); + +static int init_debugfs(void); +static void free_debugfs(void); +static int hw_test_init(void); +static void hw_test_exit(void);
Please reorder all the functions so that you no longer need forward declarations.
Quoted 8 lines
drivers/misc/Kconfig +8
-0+static int get_random_bytes_sample(void *unused) +{ + u32 *buffer; + ktime_t start, t1, t2; + s64 diff, total = 0; + u64 sample = 0; + int ret = 1; +
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ buffer = kzalloc(1024, GFP_KERNEL); + + start = ktime_get(); + do { + + t1 = ktime_get(); + get_random_bytes(buffer, 1024); + t2 = ktime_get(); + total = ktime_to_us(ktime_sub(t2, start)); + diff = ktime_to_us(ktime_sub(t2, t1));
You need more comments to explain why you are doing things. For instance
here: why is it a useful thing to test how long get_random_bytes() takes?
Quoted 5 lines
drivers/misc/Kconfig +5
-0+static int get_freq_sample(void *unused) +{ + ktime_t start, t1, t2; + s64 diff, total = 0; + u32 sample = 0;
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ int ret = 1; + unsigned int cpu_tsc_freq; + static DEFINE_MUTEX(freq_pit_mutex); + + start = ktime_get(); + do { + t1 = ktime_get(); + mutex_lock(&freq_pit_mutex); + cpu_tsc_freq = x86_platform.calibrate_tsc(); + mutex_unlock(&freq_pit_mutex);
Or the calibrate_tsc() function.
It's also not clear what function the freq_pit_mutex has. I don't see how the code could ever get run twice at the same time.
Quoted 63 lines
drivers/misc/Kconfig +51
-1+static int kthread_fn(void *unused) +{ + int err = 0; + u64 interval = 0; + int (*get_sample)(void *unused); + + mutex_lock(&sample_function_mutex); + if (current_sample_func) +static int hw_test_init(void) +{ + int ret = -ENOMEM; + + printk(KERN_INFO BANNER "version %s\n", VERSION); + + sample_function_register(&tsc_sample); + sample_function_register(&tsc_freq_sample); + sample_function_register(&random_bytes_sample); + + ret = init_stats(); + if (0 != ret) + goto out; + ret = init_debugfs(); + if (0 != ret) + goto err_stats; + if (enabled) + ret = start_kthread(); + goto out; + +err_stats: + ring_buffer_free(ring_buffer); +out: + return ret; +} + +static void hw_test_exit(void) +{ + int err; + + if (enabled) { + enabled = 0; + err = stop_kthread(); + if (err) + printk(KERN_ERR BANNER "cannot stop kthread\n"); + } + + free_debugfs(); + ring_buffer_free(ring_buffer); +} + +module_init(hw_test_init); +module_exit(hw_test_exit); --To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/drivers/misc/Kconfig +4
-0+ get_sample = current_sample_func->get_sample; + else + goto out; +
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ while (!kthread_should_stop()) { + mutex_lock(&data.lock); + + err = stop_machine(get_sample, unused, cpu_online_mask); + if (err) { + mutex_unlock(&data.lock); + goto err_out; + } + + wake_up(&data.wq);
Using stop_machine() sounds like a very expensive thing to do here. Is it necessary?
drivers/misc/Kconfig
Quoted 2 lines
drivers/misc/Kconfig +2
-0+ interval = data.sample_window - data.sample_width; + do_div(interval, USEC_PER_MSEC);
Have you tried avoiding the need for do_div? You could use an "unsigned long" to count the microseconds here, or you could do everything using miliseconds.
Quoted 7 lines
drivers/misc/Kconfig +7
-0+static int start_kthread(void) +{ + kthread = kthread_run(kthread_fn, NULL, DRVNAME); + if (IS_ERR(kthread)) { + printk(KERN_ERR BANNER "could not start sampling thread\n"); + enabled = 0; + return -ENOMEM;
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ } + return 0; +} + +static int stop_kthread(void) +{ + int ret; + ret = kthread_stop(kthread); + return ret; +}
These helper functions do not appear to help. Just remove them.
Quoted 27 lines
drivers/misc/Kconfig +27
-0+static ssize_t simple_data_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos, const u64 *entry) +{ + char buf[U64STR_SIZE]; + u64 val = 0; + int len = 0; + + memset(buf, 0, sizeof(buf)); + if (!entry) + return -EFAULT; + mutex_lock(&data.lock); + val = *entry; + mutex_unlock(&data.lock); + len = snprintf(buf, sizeof(buf), "%llu\n", (unsigned long long)val); + return simple_read_from_buffer(ubuf, cnt, ppos, buf, len); +} + +static ssize_t simple_data_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos, u64 *entry) +{ + char buf[U64STR_SIZE]; + int csize = min(cnt, sizeof(buf)); + u64 val = 0; + int err = 0; + + memset(buf, '\0', sizeof(buf)); + if (copy_from_user(buf, ubuf, csize))
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ return -EFAULT; + buf[U64STR_SIZE-1] = '\0'; + err = strict_strtoull(buf, 10, &val); + if (err) + return -EINVAL; + mutex_lock(&data.lock); + *entry = val; + mutex_unlock(&data.lock); + return csize; +}
These look like you can use DEFINE_SIMPLE_ATTRIBUTE() or debugfs_create_u64() to simplify your code.
drivers/misc/Kconfig
Quoted 4 lines
drivers/misc/Kconfig +4
-0+static int debug_available_fopen(struct inode *inode, struct file *filp) +{ + return 0; +}
Just use simple_open() or no open function in the file_operations, there is no need to provide an empty function.
drivers/misc/Kconfig
Quoted 5 lines
drivers/misc/Kconfig +5
-0+static ssize_t debug_available_fwrite(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + return (ssize_t) 0; +}
Same for empty write functions.
Quoted 19 lines
drivers/misc/Kconfig +19
-0+static int init_debugfs(void) +{ + int ret = -ENOMEM; + + debug_dir = debugfs_create_dir(DRVNAME, NULL); + if (!debug_dir) + goto err_debug_dir; + + debug_available = debugfs_create_file("available", 0444, + debug_dir, NULL, + &available_fops); + if (!debug_available) + goto err_available; + + debug_current = debugfs_create_file("current", 0444, + debug_dir, NULL, + ¤t_fops); + if (!debug_current) + goto err_current;
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ + debug_sample = debugfs_create_file("sample", 0444, + debug_dir, NULL, + &sample_fops); + if (!debug_sample) + goto err_sample; + + debug_count = debugfs_create_file("count", 0444, + debug_dir, NULL, + &count_fops);
Just use an array of file_operations and create the files using a loop.
Arnd
Quoted 30 lines · Arnd Bergmann
Hi Luming,
Quoted 18 lines · Luming Yu
The patch is the fist step to test some basic hardware functions like TSC to help people understand if there is any hardware latency as well as throughput problem exposed on bare metal or left behind by BIOS or interfered by SM. Currently the patch tests hardware features (tsc,freq, and rdrandom whiich is new instruction to get random number) in
stop_machinecontext. I will add more after the first step get merged for those guys who want to directly play with new hardware functions.I suppose I can add your signed-off-by as the code is derived from your
hwlat_dector.I'm also reuqesting if you are going to queue it up somewhere that can be pulled into 3.5.
Of cause, I will update the patch based upon any comments that you think must be fixed for 3.5 merge.
Quoted 8 lines
Signed-off-by Luming Yu <[email protected]>
Kconfig | 7
Makefile | 2
hw_test.c | 954
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++3 files changed, 963 insertions(+)
Quoted 4 lines
Please write the text in the email so that it can be used as a permanent changelog entry for the kernel git history. Everything that you do not want to have in that history can go under the "---" line that separates the Signed-off-by from the diffstat.
Done in patch update.
Quoted 22 lines
Quoted 16 lines
drivers/misc/Kconfig +0
-0@@ -123,6 +123,13 @@ config IBM_ASMfor information on the specific driver level and support statement for your IBM server.
drivers/misc/Kconfig +7
-0+config HW_TEST + tristate "Testing module to detect hardware lattency and throughput" + depends on DEBUG_FS + depends on RING_BUFFER + depends on X86 + default m +Quoted 3 lines
config PHANTOM
tristate "Sensable PHANToM (PCI)"
depends on PCIAny reason why this depends on X86?
Quoted 1 line
I think the name "
HW_TEST" is too generic. Maybe "HW_LATENCY_TEST"?
Done in update
Quoted 16 lines
Quoted 4 lines
drivers/misc/Kconfig +3
-0+static struct ring_buffer *ring_buffer; +static DEFINE_MUTEX(ring_buffer_mutex); +static unsigned long buf_size = 262144UL;drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+static struct task_struct *kthread; + +struct sample; +struct data; + +struct sample_function { + const char *name; + struct list_head list; + int (*get_sample)(void *unused); +};why the "unused" argument?
It's a placeholder for future use although it's not used right now in current tests.
Quoted 11 lines
Quoted 11 lines
drivers/misc/Kconfig +10
-0+static struct sample_function *current_sample_func = NULL; +static LIST_HEAD(sample_function_list); +static DEFINE_MUTEX(sample_function_mutex); +static int sample_function_register(struct sample_function *sf); + +static struct dentry *debug_dir; +static struct dentry *debug_available; +static struct dentry *debug_current; +static struct dentry *debug_max; +static struct dentry *debug_count;
Quoted 8 lines
drivers/misc/Kconfig
Quoted 5 lines
drivers/misc/Kconfig +5
-0+static struct dentry *debug_sample_width; +static struct dentry *debug_sample_window; +static struct dentry *debug_sample; +static struct dentry *debug_threshold; +static struct dentry *debug_enable;I think it would help here to put the local variables into a data structure that gets allocated at module load time.
I've reduced the code redundancy in update.
Quoted 5 lines
Quoted 4 lines
drivers/misc/Kconfig +3
-0+static int __buffer_add_sample(struct sample *sample); +static struct sample *buffer_get_sample(struct sample *sample); +...
Quoted 11 lines
drivers/misc/Kconfig
Quoted 8 lines
drivers/misc/Kconfig +8
-0+static ssize_t debug_enable_fwrite(struct file *filp, + const char __user *user_buffer, + size_t user_size, loff_t *offset); + +static int init_debugfs(void); +static void free_debugfs(void); +static int hw_test_init(void); +static void hw_test_exit(void);Please reorder all the functions so that you no longer need forward declarations.
Done
Quoted 15 lines
Quoted 15 lines
drivers/misc/Kconfig +14
-0+static int get_random_bytes_sample(void *unused) +{ + u32 *buffer; + ktime_t start, t1, t2; + s64 diff, total = 0; + u64 sample = 0; + int ret = 1; + + buffer = kzalloc(1024, GFP_KERNEL); + + start = ktime_get(); + do { + + t1 = ktime_get();
Quoted 8 lines
Quoted 4 lines
+
get_random_bytes(buffer, 1024);
+ t2 =ktime_get();
+ total =ktime_to_us(ktime_sub(t2, start));
+ diff =ktime_to_us(ktime_sub(t2, t1));You need more comments to explain why you are doing things. For instance
here: why is it a useful thing to test how longget_random_bytes()takes?
It is for testing new instruction rdrand for new cpus like Intel Ivy Bridge.
Quoted 19 lines
Quoted 6 lines
drivers/misc/Kconfig +5
-0+static int get_freq_sample(void *unused) +{ + ktime_t start, t1, t2; + s64 diff, total = 0; + u32 sample = 0;drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ int ret = 1; + unsigned int cpu_tsc_freq; + static DEFINE_MUTEX(freq_pit_mutex); + + start = ktime_get(); + do { + t1 = ktime_get(); + mutex_lock(&freq_pit_mutex); + cpu_tsc_freq = x86_platform.calibrate_tsc(); + mutex_unlock(&freq_pit_mutex);Or the
calibrate_tsc()function.
Quoted 2 lines
It's also not clear what function the
freq_pit_mutexhas. I don't see how the code could ever get run twice at the same time.
The purpose is to sequentially test all cpu's frequency.
Quoted 69 lines
Quoted 69 lines
drivers/misc/Kconfig +51
-1+static int kthread_fn(void *unused) +{ + int err = 0; + u64 interval = 0; + int (*get_sample)(void *unused); + + mutex_lock(&sample_function_mutex); + if (current_sample_func) +static int hw_test_init(void) +{ + int ret = -ENOMEM; + + printk(KERN_INFO BANNER "version %s\n", VERSION); + + sample_function_register(&tsc_sample); + sample_function_register(&tsc_freq_sample); + sample_function_register(&random_bytes_sample); + + ret = init_stats(); + if (0 != ret) + goto out; + ret = init_debugfs(); + if (0 != ret) + goto err_stats; + if (enabled) + ret = start_kthread(); + goto out; + +err_stats: + ring_buffer_free(ring_buffer); +out: + return ret; +} + +static void hw_test_exit(void) +{ + int err; + + if (enabled) { + enabled = 0; + err = stop_kthread(); + if (err) + printk(KERN_ERR BANNER "cannot stop kthread\n"); + } + + free_debugfs(); + ring_buffer_free(ring_buffer); +} + +module_init(hw_test_init); +module_exit(hw_test_exit); --To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/+
get_sample=current_sample_func->get_sample;
+ else
+ goto out;drivers/misc/Kconfig +6
-0+ + while (!kthread_should_stop()) { + mutex_lock(&data.lock); + + err = stop_machine(get_sample, unused, cpu_online_mask); + if (err) {
Quoted 8 lines
Quoted 5 lines
+
mutex_unlock(&data.lock);
+ gotoerr_out;
+ }
+
+wake_up(&data.wq);Using
stop_machine()sounds like a very expensive thing to do here. Is it necessary?
Yes, the only purpose of the tool is to measure various hardware operation's latency
as well as bandwidth. We need the test done with least invasion from others.
Quoted 6 lines
Quoted 3 lines
+ interval = data.sample_window - data.sample_width;
+do_div(interval, USEC_PER_MSEC);Have you tried avoiding the need for
do_div? You could use an "unsigned long" to count the microseconds here, or you could do everything using miliseconds.
It's out the testing loops. I didn't notice it hurts testing results so far. I will change it
in 0.1-> 0.2
Quoted 12 lines
Quoted 12 lines
drivers/misc/Kconfig +11
-0+static int start_kthread(void) +{ + kthread = kthread_run(kthread_fn, NULL, DRVNAME); + if (IS_ERR(kthread)) { + printk(KERN_ERR BANNER "could not start sampling thread\n"); + enabled = 0; + return -ENOMEM; + } + return 0; +} +
Quoted 8 lines
drivers/misc/Kconfig
Quoted 6 lines
drivers/misc/Kconfig +6
-0+static int stop_kthread(void) +{ + int ret; + ret = kthread_stop(kthread); + return ret; +}These helper functions do not appear to help. Just remove them.
There is a data.lock encapsulated in the helper. I can't remove them otherwise the data protection will get lost.
Quoted 33 lines
Quoted 33 lines
drivers/misc/Kconfig +32
-0+static ssize_t simple_data_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos, const u64 *entry) +{ + char buf[U64STR_SIZE]; + u64 val = 0; + int len = 0; + + memset(buf, 0, sizeof(buf)); + if (!entry) + return -EFAULT; + mutex_lock(&data.lock); + val = *entry; + mutex_unlock(&data.lock); + len = snprintf(buf, sizeof(buf), "%llu\n", (unsigned long long)val); + return simple_read_from_buffer(ubuf, cnt, ppos, buf, len); +} + +static ssize_t simple_data_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos, u64 *entry) +{ + char buf[U64STR_SIZE]; + int csize = min(cnt, sizeof(buf)); + u64 val = 0; + int err = 0; + + memset(buf, '\0', sizeof(buf)); + if (copy_from_user(buf, ubuf, csize)) + return -EFAULT; + buf[U64STR_SIZE-1] = '\0'; + err = strict_strtoull(buf, 10, &val); + if (err) + return -EINVAL;
Quoted 8 lines
Quoted 5 lines
+
mutex_lock(&data.lock);
+ *entry = val;
+mutex_unlock(&data.lock);
+ return csize;
+}These look like you can use
DEFINE_SIMPLE_ATTRIBUTE()ordebugfs_create_u64()to simplify your code.
I've simplified syfs interface code in other ways. Basically use define magic.
Quoted 8 lines
drivers/misc/Kconfig
Quoted 5 lines
drivers/misc/Kconfig +4
-0+static int debug_available_fopen(struct inode *inode, struct file *filp) +{ + return 0; +}Just use
simple_open()or no open function in thefile_operations, there is no need to provide an empty function.
I've used define magic in patch update.
Quoted 8 lines
drivers/misc/Kconfig
Quoted 6 lines
drivers/misc/Kconfig +5
-0+static ssize_t debug_available_fwrite(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + return (ssize_t) 0; +}Same for empty write functions.
All empty functions are gone.
Quoted 24 lines
Quoted 24 lines
drivers/misc/Kconfig +23
-0+static int init_debugfs(void) +{ + int ret = -ENOMEM; + + debug_dir = debugfs_create_dir(DRVNAME, NULL); + if (!debug_dir) + goto err_debug_dir; + + debug_available = debugfs_create_file("available", 0444, + debug_dir, NULL, + &available_fops); + if (!debug_available) + goto err_available; + + debug_current = debugfs_create_file("current", 0444, + debug_dir, NULL, + ¤t_fops); + if (!debug_current) + goto err_current; + + debug_sample = debugfs_create_file("sample", 0444, + debug_dir, NULL, + &sample_fops);
Quoted 8 lines
Quoted 6 lines
+ if (!debug_sample)
+ gotoerr_sample;
+
+debug_count= debugfs_create_file("count", 0444,
+debug_dir, NULL,
+&count_fops);Just use an array of
file_operationsand create the files using a loop.
Done in update patch.
Quoted 3 lines
Arnd
Thanks for detailed review. An update patch is being prepared right now. Will send in few minutes.
/l