Back to July of this year, I sent the first round of the tool.
Now I've polished it a little bit.
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 SMI. Currently the patch tests TSC, CPU Frequency, and
RDRAND, which is a new CPU instruction to get random number introudced
in new CPU like Intel Ivy Bridge, in stop_machine context.
Some test I did on a old P4 and a latest IvyBridge latpop: X230 as follows:
P4:
[root@p4 hw_latency_test]# modprobe hw_latency_test
[root@p4 hw_latency_test]# cd /sys/kernel/debug/hw_latency_test/
[root@p4 hw_latency_test]# ls
available count current enable max sample threshold window
[root@p4 hw_latency_test]# cat available
mem random_bytes freq tsc
[root@p4 hw_latency_test]# echo mem > current
[root@p4 hw_latency_test]# echo 1 > enable
[root@p4 hw_latency_test]# cat sample
[0]1061813091.0918683721 176ns [ffffffffc0001329]
[0]1061813092.0419683746 132ns [ffffffffc0002750]
[0]1061813092.0920683770 194ns [ffffffffc0003993]
[0]1061813093.0421683794 194ns [ffffffffc0004bd6]
[0]1061813093.0922683818 175ns [ffffffffc0005f51]
[0]1061813094.0423683843 177ns [ffffffffc000722b]
[0]1061813094.0924683867 178ns [ffffffffc00085a5]
[0]1061813095.0425683891 177ns [ffffffffc0009920]
[0]1061813095.0926683915 179ns [ffffffffc000ac9a]
[0]1061813096.0427683940 224ns [ffffffffc000c013]
[0]1061813096.0928683964 179ns [ffffffffc000d38d]
[0]1061813097.0429683988 175ns [ffffffffc000e708]
[0]1061813097.0930684012 179ns [ffffffffc000fa82]
[0]1061813098.0431684037 194ns [ffffffffc0010dfc]
^C
[root@p4 hw_latency_test]# echo 0 > enable
[root@p4 hw_latency_test]# echo random_bytes > current
[root@p4 hw_latency_test]# echo 1 > enable
[0]1061813148.0873686478 247us [0]
[0]1061813149.0874686526 244us [0]
[0]1061813150.0877686575 246us [0]
[0]1061813151.0878686623 245us [0]
^C
[root@p4 hw_latency_test]# echo 0 > enable
[root@p4 hw_latency_test]# echo freq > current
[root@p4 hw_latency_test]# echo 1 > enable
[root@p4 hw_latency_test]# cat sample
[0]1061813198.0701688889 245us [0]
[0]1061813199.0713688938 273us [0]
[0]1061813200.0725688987 232us [0]
[0]1061813201.0736689036 265us [0]
[0]1061813202.0747689085 257us [0]
[0]1061813203.0758689134 265us [0]
^C
[root@p4 hw_latency_test]# echo 0 > enable
[root@p4 hw_latency_test]# echo tsc > current
[root@p4 hw_latency_test]# echo 1 > enable
[0]1061813225.0514690187 138ns [0]
[0]1061813226.0015690211 139ns [0]
[0]1061813226.0516690236 152ns [0]
^C
[root@p4 hw_latency_test]#
IvyBridge (thinkpad x230):
[root@ivb hw_latency_test]# echo mem > current
[root@ivb hw_latency_test]# echo 1 > enable
[root@ivb hw_latency_test]# cat sample
[0]1352079648.0152669920 190ns [ffff880000002486]
[0]1352079648.0654669947 167ns [ffff88000000490c]
[0]1352079649.0155669973 317ns [ffff880000006d90]
[0]1352079649.0656669999 214ns [ffff880000009215]
[0]1352079650.0157670025 163ns [ffff88000000b72f]
[0]1352079650.0658670052 150ns [ffff88000000dbb5]
[0]1352079651.0159670078 398ns [ffff88000000ffa8]
[0]1352079651.0660670104 367ns [ffff88000001242a]
[0]1352079652.0161670131 193ns [ffff8800000148b0]
[root@ivb hw_latency_test]# echo 0 > enable
[root@ivb hw_latency_test]# echo random_bytes > current
[root@ivb hw_latency_test]# echo 1 > threshold
[root@ivb hw_latency_test]# echo 1 > enable
[root@ivb hw_latency_test]# cat sample
[3]1352079707.0143673015 17us [0]
[0]1352079708.0144673068 16us [0]
[1]1352079708.0144673068 16us [0]
[2]1352079708.0144673068 24us [0]
[3]1352079708.0144673068 17us [0]
[0]1352079709.0145673120 24us [0]
[1]1352079709.0145673120 17us [0]
[2]1352079709.0145673120 17us [0]
[3]1352079709.0145673120 22us [0]
^C
ot@ivb hw_latency_test]# echo 0 > enable
[root@ivb hw_latency_test]# echo freq > current
[root@ivb hw_latency_test]# echo 10 > threshold
[root@ivb hw_latency_test]# echo 1 > enable
[root@ivb hw_latency_test]#
[root@ivb hw_latency_test]# cat sample
[0]1352079763.0780675986 195us [0]
[1]1352079764.0285676013 281us [0]
[2]1352079764.0790676039 193us [0]
[3]1352079765.0296676066 225us [0]
[0]1352079766.0303676119 228us [0]
[1]1352079766.0808676145 269us [0]
[2]1352079767.0313676172 195us [0]
[3]1352079767.0819676198 220us [0]
^C
[root@ivb hw_latency_test]# echo 0 > enable
[root@ivb hw_latency_test]# echo tsc > current
[root@ivb hw_latency_test]# echo 1 > enable
[root@ivb hw_latency_test]# cat sample
[0]1352079798.0116677788 76ns [0]
[1]1352079798.0116677788 84ns [0]
[2]1352079798.0116677788 52ns [0]
[3]1352079798.0116677788 52ns [0]
[0]1352079798.0617677814 89ns [0]
[1]1352079798.0617677814 84ns [0]
[2]1352079798.0617677814 74ns [0]
[3]1352079798.0617677814 61ns [0]
^C
Luming Yu (13):
HW-latency: hardware latency test 0.10
HW-latency: Fix a lockdep warnning
HW-latency: Use get_random_bytes_arch
HW-latency: Differentiate three modes to use CPU carry out testing
HW-latency: Add CPU field in sample output
HW-latency: cycle through all online cpus to re-test cpufreq
HW-latency: delete too many "Fast TSC calibration using PIT" in
cpufreq sampling
HW-latency: A stupid memory scanner for raw memory latency test
HW-latency: Fix unwanted crash caused by write to dummy debugfs
interface
HW-latency: add address range for x86-32
HW-latency: fix a warnning in previous patch
HW-latency: Add sample unit in sample data
HW-latency: some sample data format change
arch/x86/kernel/tsc.c | 2 +-
drivers/misc/Kconfig | 7 +
drivers/misc/Makefile | 1 +
drivers/misc/hw_latency_test.c | 922 +++++++++++++++++++++++++++++++++++++++++
fs/libfs.c | 2 +-
5 files changed, 932 insertions(+), 2 deletions(-)
create mode 100644 drivers/misc/hw_latency_test.c
--
1.7.12.1
This patch is the first 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 SMI. Currently the patch tests TSC, CPU Frequency and
RDRAND which is a new CPU instruction to get random number introduced in
new CPU like Intel Ivy Bridge in stop_machine context,which is choosen to
make sure testers fully control their system under test to rule out some
level of unwanted noise.
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/Kconfig | 7 +
drivers/misc/Makefile | 1 +
drivers/misc/hw_latency_test.c | 833 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 841 insertions(+)
create mode 100644 drivers/misc/hw_latency_test.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b151b7c..5ed440b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -114,6 +114,13 @@ config IBM_ASM
for information on the specific driver level and support statement
for your IBM server.
+config HW_LATENCY_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
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2129377..c195cce 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -49,3 +49,4 @@ obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_INTEL_MEI) += mei/
+obj-$(CONFIG_HW_LATENCY_TEST) += hw_latency_test.o
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
new file mode 100644
index 0000000..2aa3a74
--- /dev/null
+++ b/drivers/misc/hw_latency_test.c
@@ -0,0 +1,833 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ring_buffer.h>
+#include <linux/stop_machine.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/kthread.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <asm/tlbflush.h>
+
+#define BUF_SIZE_DEFAULT 262144UL
+#define BUF_FLAGS (RB_FL_OVERWRITE)
+#define U64STR_SIZE 22
+#define DEBUGFS_BUF_SIZE 1024
+#define DEBUGFS_NAME_SIZE 32
+
+#define VERSION "0.1.0"
+#define BANNER "hardware latency test"
+#define DRVNAME "hw_latency_test"
+
+#define DEFAULT_SAMPLE_WINDOW 1000000
+#define DEFAULT_SAMPLE_WIDTH 500000
+#define DEFAULT_LAT_THRESHOLD 10
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luming Yu <[email protected]>");
+MODULE_DESCRIPTION("A simple hardware latency test");
+MODULE_VERSION(VERSION);
+
+static int debug;
+static int enabled;
+static int threshold;
+
+module_param(debug, int, 0);
+module_param(enabled, int, 0);
+module_param(threshold, int, 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 {
+ u64 seqnum;
+ u64 duration;
+ struct timespec timestamp;
+ unsigned long lost;
+};
+
+static struct data {
+ struct mutex lock;
+ u64 count;
+ u64 max_sample;
+ u64 threshold;
+
+ u64 sample_window;
+ u64 sample_width;
+
+ atomic_t sample_open;
+
+ wait_queue_head_t wq;
+} data;
+
+static ktime_t now;
+struct sample_function {
+ const char *name;
+ struct list_head list;
+ int (*get_sample)(void *unused);
+};
+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 int sample_function_register(struct sample_function *sf)
+{
+ struct list_head *entry = &sample_function_list;
+ mutex_lock(&sample_function_mutex);
+ list_add(&sf->list, entry);
+ current_sample_func = sf;
+ mutex_unlock(&sample_function_mutex);
+ return 0;
+}
+
+static int __buffer_add_sample(struct sample *sample)
+{
+ return ring_buffer_write(ring_buffer,
+ sizeof(struct sample), sample);
+}
+
+static struct sample *buffer_get_sample(struct sample *sample)
+{
+ struct ring_buffer_event *e = NULL;
+ struct sample *s = NULL;
+ unsigned int cpu = 0;
+
+ if (!sample)
+ return NULL;
+
+ mutex_lock(&ring_buffer_mutex);
+ for_each_online_cpu(cpu) {
+ e = ring_buffer_consume(ring_buffer, cpu, NULL, &sample->lost);
+ if (e)
+ break;
+ }
+ if (e) {
+ s = ring_buffer_event_data(e);
+ memcpy(sample, s, sizeof(struct sample));
+ } else
+ sample = NULL;
+ mutex_unlock(&ring_buffer_mutex);
+ return sample;
+}
+
+static int buffer_add_sample(u64 sample)
+{
+ int ret = 0;
+
+ if (sample > data.threshold) {
+ struct sample s;
+
+ data.count++;
+ s.seqnum = data.count;
+ s.duration = sample;
+ s.timestamp = CURRENT_TIME;
+ ret = __buffer_add_sample(&s);
+
+ if (sample > data.max_sample)
+ data.max_sample = sample;
+ }
+ return ret;
+}
+
+/*
+ * For new instruction rdrand since Intel Ivy Bridge processor
+ */
+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();
+ get_random_bytes(buffer, 1024);
+ t2 = ktime_get();
+ total = ktime_to_us(ktime_sub(t2, start));
+ diff = ktime_to_us(ktime_sub(t2, t1));
+
+ if (diff < 0) {
+ printk(KERN_ERR BANNER "time running backwards\n");
+ goto out;
+ }
+
+ if (diff > sample)
+ sample = diff;
+
+ } while (total <= data.sample_width);
+
+ ret = buffer_add_sample(sample);
+out:
+ kfree(buffer);
+ return ret;
+}
+
+/*
+ * For cpu frequency testing
+ */
+static int get_freq_sample(void *unused)
+{
+ ktime_t start, t1, t2;
+ s64 diff, total = 0;
+ u32 sample = 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);
+ t2 = ktime_get();
+ total = ktime_to_us(ktime_sub(t2, start));
+ diff = abs(cpu_tsc_freq - tsc_khz);
+
+ if (diff < 0) {
+ printk(KERN_ERR BANNER "time running backwards\n");
+ goto out;
+ }
+
+ if (diff > sample)
+ sample = diff;
+
+ } while (total <= data.sample_width);
+
+ ret = buffer_add_sample(sample);
+out:
+ return ret;
+}
+
+/*
+ * For TSC latency as well as SMI detecting
+ */
+static int get_tsc_sample(void *unused)
+{
+ ktime_t start, t1, t2;
+ s64 diff, total = 0;
+ u64 sample = 0;
+ int ret = 1;
+
+ now = start = ktime_get();
+ do {
+ t1 = now;
+ now = t2 = ktime_get();
+
+ total = ktime_to_ns(ktime_sub(t2, start));
+ diff = ktime_to_ns(ktime_sub(t2, t1));
+
+ if (diff < 0) {
+ printk(KERN_ERR BANNER "time running backwards\n");
+ goto out;
+ }
+
+ if (diff > sample)
+ sample = diff;
+
+ } while (total <= data.sample_width);
+
+ ret = buffer_add_sample(sample);
+out:
+ return ret;
+}
+
+
+struct sample_function tsc_sample = {
+ .name = "tsc",
+ .get_sample = get_tsc_sample,
+};
+
+struct sample_function tsc_freq_sample = {
+ .name = "freq",
+ .get_sample = get_freq_sample,
+};
+
+struct sample_function random_bytes_sample = {
+ .name = "random_bytes",
+ .get_sample = get_random_bytes_sample,
+};
+
+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)
+ get_sample = current_sample_func->get_sample;
+ else
+ goto out;
+
+ 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);
+
+ interval = data.sample_window - data.sample_width;
+ do_div(interval, USEC_PER_MSEC);
+
+ mutex_unlock(&data.lock);
+ if (msleep_interruptible(interval))
+ goto out;
+ }
+ goto out;
+err_out:
+ printk(KERN_ERR BANNER "could not call stop_machine, disabling\n");
+ enabled = 0;
+out:
+ mutex_unlock(&sample_function_mutex);
+ return err;
+}
+
+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;
+}
+
+static int stop_kthread(void)
+{
+ int ret;
+ ret = kthread_stop(kthread);
+ return ret;
+}
+
+static void __reset_stats(void)
+{
+ data.count = 0;
+ data.max_sample = 0;
+ ring_buffer_reset(ring_buffer);
+}
+
+static int init_stats(void)
+{
+ int ret = -ENOMEM;
+
+ mutex_init(&data.lock);
+ init_waitqueue_head(&data.wq);
+ atomic_set(&data.sample_open,0);
+
+ ring_buffer = ring_buffer_alloc(buf_size, BUF_FLAGS);
+
+ if (WARN(!ring_buffer, KERN_ERR BANNER
+ "failed to allocate ring buffer!\n"))
+ goto out;
+ __reset_stats();
+ data.threshold = DEFAULT_LAT_THRESHOLD;
+ data.sample_window = DEFAULT_SAMPLE_WINDOW;
+ data.sample_width = DEFAULT_SAMPLE_WIDTH;
+ ret = 0;
+out:
+ return ret;
+}
+
+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;
+ mutex_lock(&data.lock);
+ *entry = val;
+ mutex_unlock(&data.lock);
+ return csize;
+}
+
+#define debug_available_fopen simple_open
+
+static ssize_t debug_available_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct sample_function *sf;
+ ssize_t count = 0;
+ char *buf;
+
+ buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&sample_function_mutex);
+ list_for_each_entry(sf, &sample_function_list, list) {
+ count += snprintf(buf + count,
+ max((ssize_t)(DEBUGFS_BUF_SIZE - count), (ssize_t)0),
+ "%s ", sf->name);
+ }
+ mutex_unlock(&sample_function_mutex);
+
+ count += snprintf(buf + count,
+ max((ssize_t )DEBUGFS_BUF_SIZE - count, (ssize_t) 0),
+ "\n");
+ count = simple_read_from_buffer(ubuf, cnt, ppos, buf, count);
+ kfree(buf);
+ return count;
+}
+
+#define debug_available_fwrite simple_attr_write
+
+#define debug_available_release simple_attr_release
+
+#define debug_current_fopen simple_open
+
+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;
+}
+#define debug_current_release simple_attr_release
+
+#define debug_count_fopen simple_open
+
+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);
+}
+#define debug_count_release simple_attr_release
+
+#define debug_enable_fopen simple_open
+
+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;
+}
+#define debug_enable_release simple_attr_release
+
+#define debug_max_fopen simple_open
+
+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);
+}
+#define debug_max_release simple_attr_release
+
+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;
+}
+
+#define debug_sample_fwrite simple_attr_write
+
+static int debug_sample_release(struct inode *inode, struct file *filp)
+{
+ atomic_dec(&data.sample_open);
+ return 0;
+}
+
+#define debug_threshold_fopen simple_open
+
+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;
+}
+#define debug_threshold_release simple_attr_release
+
+#define debug_width_fopen simple_open
+
+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;
+}
+#define debug_width_release simple_attr_release
+
+#define debug_window_fopen simple_open
+
+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;
+}
+#define debug_window_release simple_attr_release
+
+#define DEFINE_DEBUGFS_FILE(name) \
+ static const struct file_operations name##_fops = { \
+ .open = debug_##name##_fopen, \
+ .read = debug_##name##_fread, \
+ .write = debug_##name##_fwrite, \
+ .release = debug_##name##_release, \
+ .owner = THIS_MODULE, \
+ };
+
+DEFINE_DEBUGFS_FILE(available)
+DEFINE_DEBUGFS_FILE(current)
+DEFINE_DEBUGFS_FILE(count)
+DEFINE_DEBUGFS_FILE(enable)
+DEFINE_DEBUGFS_FILE(max)
+DEFINE_DEBUGFS_FILE(sample)
+DEFINE_DEBUGFS_FILE(threshold)
+DEFINE_DEBUGFS_FILE(width)
+DEFINE_DEBUGFS_FILE(window)
+
+#undef DEFINE_DEBUGFS_FILE
+
+#undef current
+#define DEFINE_ENTRY(name) {__stringify(name), &name##_fops, NULL},
+
+static struct debugfs_file_table
+{
+ const char *file_name;
+ const struct file_operations *fops;
+ struct dentry *dentry;
+} file_table[] = {
+ DEFINE_ENTRY(available)
+ DEFINE_ENTRY(current)
+ DEFINE_ENTRY(sample)
+ DEFINE_ENTRY(count)
+ DEFINE_ENTRY(max)
+ DEFINE_ENTRY(window)
+ DEFINE_ENTRY(threshold)
+ DEFINE_ENTRY(enable)
+ {NULL, NULL,NULL},
+};
+#undef DEFINE_ENTRY
+
+static int init_debugfs(void)
+{
+ int ret = -ENOMEM;
+ int i=0;
+
+ debug_dir = debugfs_create_dir(DRVNAME, NULL);
+ if (!debug_dir)
+ goto err_debug_dir;
+
+ while (file_table[i].fops) {
+ file_table[i].dentry =
+ debugfs_create_file(file_table[i].file_name, 0444,
+ debug_dir, NULL,
+ file_table[i].fops);
+ if (!file_table[i].dentry)
+ break;
+ i++;
+ }
+ if (file_table[i].fops) {
+ i--;
+ while (i>=0 && file_table[i].fops && file_table[i].dentry) {
+ debugfs_remove(file_table[i].dentry);
+ i--;
+ }
+ debugfs_remove(debug_dir);
+ }
+ ret = 0;
+err_debug_dir:
+ return ret;
+}
+
+static void free_debugfs(void)
+{
+ int i=0;
+
+ while (file_table[i].fops && file_table[i].dentry) {
+ debugfs_remove(file_table[i].dentry);
+ i++;
+ }
+ 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);
--
1.7.12.1
To test rdrand on CPU like Ivy Bridget, we need feature aware random function.
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index e970642..8a8c6ba 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -155,7 +155,7 @@ static int get_random_bytes_sample(void *unused)
do {
t1 = ktime_get();
- get_random_bytes(buffer, 1024);
+ get_random_bytes_arch(buffer, 1024);
t2 = ktime_get();
total = ktime_to_us(ktime_sub(t2, start));
diff = ktime_to_us(ktime_sub(t2, t1));
--
1.7.12.1
The filed tells user the sample is from which cpu.
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index 4303644..256b1c0 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -124,11 +124,13 @@ static struct sample *buffer_get_sample(struct sample *sample)
static int buffer_add_sample(u64 sample)
{
int ret = 0;
+ unsigned int cpu = smp_processor_id();
if (sample > data.threshold) {
struct sample s;
data.count++;
+ s.cpu = cpu;
s.seqnum = data.count;
s.duration = sample;
s.timestamp = CURRENT_TIME;
@@ -615,7 +617,8 @@ static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
goto out;
}
}
- len = snprintf(buf, sizeof(buf), "%010lu.%010lu\t%llu\n",
+ len = snprintf(buf, sizeof(buf), "[%d]%010lu.%010lu\t%llu\n",
+ sample->cpu,
sample->timestamp.tv_sec,
sample->timestamp.tv_nsec,
sample->duration);
--
1.7.12.1
Fix a typo to enable cycling through all online cpus to get cpufreq
sample from all cpus sequentially.
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index 256b1c0..78436da 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -297,7 +297,7 @@ static int kthread_fn(void *unused)
for_each_cpu(cpu, cpu_online_mask) {
cpumask_clear(testing_cpu_mask);
cpumask_set_cpu(cpu, testing_cpu_mask);
- err = stop_machine(get_sample, unused, NULL);
+ err = stop_machine(get_sample, unused, testing_cpu_mask);
if (err)
break;
}
--
1.7.12.1
It's simple memory latency test without any consideration of memory
hierarchy and memory model. It just does simply scan byte by byte.
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 53 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index 78436da..f47b911 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -46,11 +46,15 @@ static DEFINE_MUTEX(ring_buffer_mutex);
static unsigned long buf_size = 262144UL;
static struct task_struct *kthread;
+static u8 *__start = (u8 *)0xffff880000000000;
+static u8 *__end = (u8 *)0xffffc7ffffffffff;
+
struct sample {
unsigned int cpu;
u64 seqnum;
u64 duration;
struct timespec timestamp;
+ u64 addr;
unsigned long lost;
};
@@ -134,6 +138,7 @@ static int buffer_add_sample(u64 sample)
s.seqnum = data.count;
s.duration = sample;
s.timestamp = CURRENT_TIME;
+ s.addr = (u64) __start;
ret = __buffer_add_sample(&s);
if (sample > data.max_sample)
@@ -247,6 +252,42 @@ out:
return ret;
}
+static int get_mem_sample(void *unused)
+{
+ ktime_t start, t1, t2;
+ s64 diff, total = 0;
+ u64 sample = 0;
+ int ret = 1;
+ u8 temp;
+
+ now = start = ktime_get();
+ do {
+ t1 = now;
+ now = t2 = ktime_get();
+
+ total = ktime_to_ns(ktime_sub(t2, start));
+ temp = *__start++;
+ diff = ktime_to_ns(ktime_sub(t2, t1));
+
+ if (diff < 0) {
+ printk(KERN_ERR BANNER "time running backwards\n");
+ goto out;
+ }
+
+ if (diff > sample)
+ sample = diff;
+
+ if (__start == __end) {
+ __start = (u8 *)0xffff880000000000;
+ printk(KERN_INFO BANNER "one pass finished, jmp to the beginning\n");
+ }
+
+ } while (total <= data.sample_width);
+
+ ret = buffer_add_sample(sample);
+out:
+ return ret;
+}
struct sample_function tsc_sample = {
.name = "tsc",
@@ -266,6 +307,12 @@ struct sample_function random_bytes_sample = {
.get_sample = get_random_bytes_sample,
};
+struct sample_function mem_sample = {
+ .name = "mem",
+ .type = 1,
+ .get_sample = get_mem_sample,
+};
+
static DECLARE_BITMAP(testing_cpu_map, NR_CPUS);
static int kthread_fn(void *unused)
@@ -617,11 +664,12 @@ static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
goto out;
}
}
- len = snprintf(buf, sizeof(buf), "[%d]%010lu.%010lu\t%llu\n",
+ len = snprintf(buf, sizeof(buf), "[%d]%010lu.%010lu\t%llu\t[%llx]\n",
sample->cpu,
sample->timestamp.tv_sec,
sample->timestamp.tv_nsec,
- sample->duration);
+ sample->duration,
+ sample->addr);
if (len > cnt)
goto out;
if (copy_to_user(ubuf, buf,len))
@@ -827,6 +875,7 @@ static int hw_test_init(void)
sample_function_register(&tsc_sample);
sample_function_register(&tsc_freq_sample);
sample_function_register(&random_bytes_sample);
+ sample_function_register(&mem_sample);
ret = init_stats();
if (0 != ret)
--
1.7.12.1
[ 141.311906] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
[ 141.314071] IP: [<ffffffff811f8f3c>] simple_attr_write+0x2c/0x100
[ 141.316195] PGD c3bd7067 PUD cb41d067 PMD 0
[ 141.318287] Oops: 0000 [#1] SMP
[ 141.320338] Modules linked in: hw_latency_test lockd sunrpc iptable_mangle nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack rfcomm bnep coretemp kvm arc4 iwldvm mac80211 snd_hda_codec_hdmi snd_hda_codec_realtek option usb_wwan snd_hda_intel snd_hda_codec btusb bluetooth snd_hwdep snd_seq snd_seq_device snd_pcm iwlwifi thinkpad_acpi cfg80211 snd_page_alloc snd_timer crc32c_intel snd e1000e tpm_tis ghash_clmulni_intel tpm tpm_bios soundcore iTCO_wdt rfkill joydev microcode i2c_i801 wmi iTCO_vendor_support mei lpc_ich mfd_core pcspkr uinput i915 usb_storage i2c_algo_bit uas drm_kms_helper sdhci_pci sdhci drm mmc_core i2c_core video
[ 141.329446] CPU 2
[ 141.329467] Pid: 804, comm: bash Not tainted 3.7.0-rc2+ #5 LENOVO 232045C/232045C
[ 141.333922] RIP: 0010:[<ffffffff811f8f3c>] [<ffffffff811f8f3c>] simple_attr_write+0x2c/0x100
[ 141.336173] RSP: 0018:ffff8800cb6c3eb8 EFLAGS: 00010286
[ 141.338377] RAX: ffffffff811f8f10 RBX: ffff8800c4549600 RCX: ffff8800cb6c3f50
[ 141.340573] RDX: 0000000000000002 RSI: 00007fcbf9ef0000 RDI: ffff8800c4549600
[ 141.342744] RBP: ffff8800cb6c3ef8 R08: 000000000000000a R09: 00007fcbf9edd740
[ 141.344896] R10: 0000000000000001 R11: 0000000000000246 R12: 0000000000000002
[ 141.347017] R13: 00007fcbf9ef0000 R14: ffff8800cb6c3f50 R15: 0000000000000000
[ 141.349115] FS: 00007fcbf9edd740(0000) GS:ffff880119200000(0000) knlGS:0000000000000000
[ 141.351209] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 141.353314] CR2: 0000000000000008 CR3: 00000000c696c000 CR4: 00000000001407e0
[ 141.355457] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 141.357590] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 141.359685] Process bash (pid: 804, threadinfo ffff8800cb6c2000, task ffff8800cb7ccd20)
[ 141.361767] Stack:
[ 141.363793] ffff8800c4549600 00007fcbf9ef0000 ffff8800cb6c3ef8 ffff8800c4549600
[ 141.365864] 0000000000000002 00007fcbf9ef0000 ffff8800cb6c3f50 0000000000000000
[ 141.367905] ffff8800cb6c3f28 ffffffff811cf27f ffff8800c4549600 00007fcbf9ef0000
[ 141.369924] Call Trace:
[ 141.371882] [<ffffffff811cf27f>] vfs_write+0xaf/0x190
[ 141.373827] [<ffffffff811cf5d5>] sys_write+0x55/0xa0
[ 141.375745] [<ffffffff816f0199>] system_call_fastpath+0x16/0x1b
[ 141.377661] Code: 1f 44 00 00 55 48 89 e5 48 83 ec 40 48 89 5d d8 4c 89 65 e0 4c 89 6d e8 4c 89 75 f0 4c 89 7d f8 4c 8b bf 28 01 00 00 48 89 75 c8 <49> 83 7f 08 00 0f 84 b1 00 00 00 4d 8d 67 50 31 f6 49 89 d5 4c
[ 141.382206] RIP [<ffffffff811f8f3c>] simple_attr_write+0x2c/0x100
[ 141.384326] RSP <ffff8800cb6c3eb8>
[ 141.386401] CR2: 0000000000000008
[ 141.388548] ---[ end trace 9c28eee46fcb7871 ]---
Signed-off-by: Luming Yu <[email protected]>
---
fs/libfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index 7cc37ca..bc51574 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -819,7 +819,7 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf,
ssize_t ret;
attr = file->private_data;
- if (!attr->set)
+ if (!attr || !attr->set)
return -EACCES;
ret = mutex_lock_interruptible(&attr->mutex);
--
1.7.12.1
drivers/misc/hw_latency_test.c:52:7: warning: "CONFIG_X86_32" is not defined [-Wundef]
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index 6e69d31..bcce8f4 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -49,7 +49,7 @@ static struct task_struct *kthread;
#ifdef CONFIG_X86_64
static u8 *__start = (u8 *)0xffff880000000000;
static u8 *__end = (u8 *)0xffffc7ffffffffff;
-#elif CONFIG_X86_32
+#else
static u8 *__start = (u8 *)0xc0000000;
static u8 *__end = (u8 *)0xffffffff;
#endif
--
1.7.12.1
ns and us
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index bcce8f4..0b79b5e 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -60,6 +60,7 @@ struct sample {
u64 duration;
struct timespec timestamp;
u64 addr;
+ u8 unit; /*0: ns 1:us*/
unsigned long lost;
};
@@ -130,7 +131,7 @@ static struct sample *buffer_get_sample(struct sample *sample)
return sample;
}
-static int buffer_add_sample(u64 sample)
+static int buffer_add_sample(u64 sample, u8 unit)
{
int ret = 0;
unsigned int cpu = smp_processor_id();
@@ -144,6 +145,7 @@ static int buffer_add_sample(u64 sample)
s.duration = sample;
s.timestamp = CURRENT_TIME;
s.addr = (u64) __start;
+ s.unit = unit;
ret = __buffer_add_sample(&s);
if (sample > data.max_sample)
@@ -184,7 +186,7 @@ static int get_random_bytes_sample(void *unused)
} while (total <= data.sample_width);
- ret = buffer_add_sample(sample);
+ ret = buffer_add_sample(sample, 1);
out:
kfree(buffer);
return ret;
@@ -219,7 +221,7 @@ static int get_freq_sample(void *unused)
} while (total <= data.sample_width);
- ret = buffer_add_sample(sample);
+ ret = buffer_add_sample(sample, 1);
out:
return ret;
}
@@ -252,7 +254,7 @@ static int get_tsc_sample(void *unused)
} while (total <= data.sample_width);
- ret = buffer_add_sample(sample);
+ ret = buffer_add_sample(sample, 0);
out:
return ret;
}
@@ -289,7 +291,7 @@ static int get_mem_sample(void *unused)
} while (total <= data.sample_width);
- ret = buffer_add_sample(sample);
+ ret = buffer_add_sample(sample, 0);
out:
return ret;
}
@@ -669,11 +671,12 @@ static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
goto out;
}
}
- len = snprintf(buf, sizeof(buf), "[%d]%010lu.%010lu\t%llu\t[%llx]\n",
+ len = snprintf(buf, sizeof(buf), "[%d]%010lu.%010lu\t%llu%2s\t[%llx]\n",
sample->cpu,
sample->timestamp.tv_sec,
sample->timestamp.tv_nsec,
sample->duration,
+ sample->unit ? "us":"ns",
sample->addr);
if (len > cnt)
goto out;
--
1.7.12.1
some trival format changes
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index 0b79b5e..549ea13 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -671,13 +671,15 @@ static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
goto out;
}
}
+
len = snprintf(buf, sizeof(buf), "[%d]%010lu.%010lu\t%llu%2s\t[%llx]\n",
sample->cpu,
sample->timestamp.tv_sec,
sample->timestamp.tv_nsec,
sample->duration,
sample->unit ? "us":"ns",
- sample->addr);
+ (((u64) (current_sample_func->get_sample)
+ == (u64) get_mem_sample) ? sample->addr: 0));
if (len > cnt)
goto out;
if (copy_to_user(ubuf, buf,len))
--
1.7.12.1
Add address range for x86-32
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index f47b911..6e69d31 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -46,8 +46,13 @@ static DEFINE_MUTEX(ring_buffer_mutex);
static unsigned long buf_size = 262144UL;
static struct task_struct *kthread;
+#ifdef CONFIG_X86_64
static u8 *__start = (u8 *)0xffff880000000000;
static u8 *__end = (u8 *)0xffffc7ffffffffff;
+#elif CONFIG_X86_32
+static u8 *__start = (u8 *)0xc0000000;
+static u8 *__end = (u8 *)0xffffffff;
+#endif
struct sample {
unsigned int cpu;
--
1.7.12.1
"Fast TSC calibration using PIT" should be a devel info.
Signed-off-by: Luming Yu <[email protected]>
---
arch/x86/kernel/tsc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index cfa5d4f..7765546 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -393,7 +393,7 @@ success:
*/
delta *= PIT_TICK_RATE;
do_div(delta, i*256*1000);
- pr_info("Fast TSC calibration using PIT\n");
+ pr_devel("Fast TSC calibration using PIT\n");
return delta;
}
--
1.7.12.1
0: all online cpus
1: any one of online cpus
2: all online cpus sequentially run test
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 37 ++++++++++++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 5 deletions(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index 8a8c6ba..4303644 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -47,6 +47,7 @@ static unsigned long buf_size = 262144UL;
static struct task_struct *kthread;
struct sample {
+ unsigned int cpu;
u64 seqnum;
u64 duration;
struct timespec timestamp;
@@ -70,6 +71,7 @@ static struct data {
static ktime_t now;
struct sample_function {
const char *name;
+ u8 type; /* 0=all parallel, 1=anyone, 2=all sequential*/
struct list_head list;
int (*get_sample)(void *unused);
};
@@ -186,14 +188,11 @@ static int get_freq_sample(void *unused)
u32 sample = 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);
t2 = ktime_get();
total = ktime_to_us(ktime_sub(t2, start));
diff = abs(cpu_tsc_freq - tsc_khz);
@@ -249,23 +248,30 @@ out:
struct sample_function tsc_sample = {
.name = "tsc",
+ .type = 0,
.get_sample = get_tsc_sample,
};
struct sample_function tsc_freq_sample = {
.name = "freq",
+ .type = 2,
.get_sample = get_freq_sample,
};
struct sample_function random_bytes_sample = {
.name = "random_bytes",
+ .type = 0,
.get_sample = get_random_bytes_sample,
};
+static DECLARE_BITMAP(testing_cpu_map, NR_CPUS);
+
static int kthread_fn(void *unused)
{
int err = 0;
u64 interval = 0;
+ int cpu;
+ struct cpumask *testing_cpu_mask = to_cpumask(testing_cpu_map);
int (*get_sample)(void *unused);
mutex_lock(&sample_function_mutex);
@@ -274,10 +280,31 @@ static int kthread_fn(void *unused)
else
goto out;
+ cpumask_or(testing_cpu_mask, testing_cpu_mask, cpu_online_mask);
while (!kthread_should_stop()) {
mutex_lock(&data.lock);
-
- err = stop_machine(get_sample, unused, cpu_online_mask);
+
+ switch (current_sample_func->type) {
+ case 0:
+ err = stop_machine(get_sample, unused, testing_cpu_mask);
+ break;
+ case 1:
+ err = stop_machine(get_sample, unused, NULL);
+ break;
+ case 2:
+ for_each_cpu(cpu, cpu_online_mask) {
+ cpumask_clear(testing_cpu_mask);
+ cpumask_set_cpu(cpu, testing_cpu_mask);
+ err = stop_machine(get_sample, unused, NULL);
+ if (err)
+ break;
+ }
+ break;
+ default:
+ mutex_unlock(&data.lock);
+ goto err_out;
+ }
+
if (err) {
mutex_unlock(&data.lock);
goto err_out;
--
1.7.12.1
[ 150.733088] in_atomic(): 1, irqs_disabled(): 1, pid: 19, name: migration/2
[ 150.735456] INFO: lockdep is turned off.
[ 150.738903] irq event stamp: 28
[ 150.741255] hardirqs last enabled at (27): [<ffffffff816e6a80>] _raw_spin_unlock_irq+0x30/0x50
[ 150.744884] hardirqs last disabled at (28): [<ffffffff816e616f>] _raw_spin_lock_irq+0x1f/0x90
[ 150.748505] softirqs last enabled at (24): [<ffffffff810724a7>] __do_softirq+0x167/0x3d0
[ 150.752121] softirqs last disabled at (19): [<ffffffff816f143c>] call_softirq+0x1c/0x30
[ 150.755709] Pid: 19, comm: migration/2 Tainted: G W 3.7.0-rc2+ #2
[ 150.759361] Call Trace:
[ 150.762952] [<ffffffff810d53e0>] ? print_irqtrace_events+0xd0/0xe0
[ 150.766610] [<ffffffff810a3b4c>] __might_sleep+0x18c/0x250
[ 150.769140] [<ffffffff816e2ab0>] mutex_lock_nested+0x40/0x390
[ 150.772765] [<ffffffff810d853d>] ? trace_hardirqs_on+0xd/0x10
[ 150.776392] [<ffffffff816e6a80>] ? _raw_spin_unlock_irq+0x30/0x50
[ 150.778899] [<ffffffff81021829>] ? read_tsc+0x9/0x20
[ 150.782546] [<ffffffffa05877e3>] get_freq_sample+0x33/0xd0 [hw_latency_test]
[ 150.786249] [<ffffffff810fac9b>] stop_machine_cpu_stop+0xab/0x110
[ 150.789964] [<ffffffff810fadd6>] cpu_stopper_thread+0xd6/0x1b0
[ 150.792528] [<ffffffff810fabf0>] ? cpu_stop_queue_work+0x80/0x80
[ 150.795044] [<ffffffff8115798e>] ? perf_event_alloc+0x5e/0x4a0
[ 150.797572] [<ffffffff816e4672>] ? __schedule+0x442/0xa00
[ 150.800079] [<ffffffff810fad00>] ? stop_machine_cpu_stop+0x110/0x110
[ 150.802512] [<ffffffff810938fd>] kthread+0xed/0x100
[ 150.805825] [<ffffffff81093810>] ? flush_kthread_worker+0x190/0x190
[ 150.808051] [<ffffffff816f00ec>] ret_from_fork+0x7c/0xb0
[ 150.810161] [<ffffffff81093810>] ? flush_kthread_worker+0x190/0x190
Signed-off-by: Luming Yu <[email protected]>
---
drivers/misc/hw_latency_test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
index 2aa3a74..e970642 100644
--- a/drivers/misc/hw_latency_test.c
+++ b/drivers/misc/hw_latency_test.c
@@ -149,7 +149,7 @@ static int get_random_bytes_sample(void *unused)
u64 sample = 0;
int ret = 1;
- buffer = kzalloc(1024, GFP_KERNEL);
+ buffer = kzalloc(1024, GFP_ATOMIC);
start = ktime_get();
do {
--
1.7.12.1
Hey,
Op 05-11-12 02:59, Luming Yu schreef:
> This patch is the first 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 SMI. Currently the patch tests TSC, CPU Frequency and
> RDRAND which is a new CPU instruction to get random number introduced in
> new CPU like Intel Ivy Bridge in stop_machine context,which is choosen to
> make sure testers fully control their system under test to rule out some
> level of unwanted noise.
>
> Signed-off-by: Luming Yu <[email protected]>
> ---
> drivers/misc/Kconfig | 7 +
> drivers/misc/Makefile | 1 +
> drivers/misc/hw_latency_test.c | 833 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 841 insertions(+)
> create mode 100644 drivers/misc/hw_latency_test.c
>
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index b151b7c..5ed440b 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -114,6 +114,13 @@ config IBM_ASM
> for information on the specific driver level and support statement
> for your IBM server.
>
> +config HW_LATENCY_TEST
> + tristate "Testing module to detect hardware lattency and throughput"
> + depends on DEBUG_FS
> + depends on RING_BUFFER
> + depends on X86
> + default m
Is there any reason this tester couldn't easily be made to work for !x86?
Also I think it would make more sense to squash all fixes, and submit fixes for the things like
'[PATCH 07/13] HW-latency: delete too many "Fast TSC calibration using PIT" in cpufreq sampling'
before the actual patch. It seems this is not necessarily a hw-latency specific patch to me.
~Maarten
On Mon, Nov 5, 2012 at 2:59 AM, Luming Yu <[email protected]> wrote:
>
> This patch is the first 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 SMI. Currently the patch tests TSC, CPU Frequency and
> RDRAND which is a new CPU instruction to get random number introduced in
> new CPU like Intel Ivy Bridge in stop_machine context,which is choosen to
> make sure testers fully control their system under test to rule out some
> level of unwanted noise.
>
> Signed-off-by: Luming Yu <[email protected]>
> ---
> drivers/misc/Kconfig | 7 +
> drivers/misc/Makefile | 1 +
> drivers/misc/hw_latency_test.c | 833 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 841 insertions(+)
> create mode 100644 drivers/misc/hw_latency_test.c
>
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index b151b7c..5ed440b 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -114,6 +114,13 @@ config IBM_ASM
> for information on the specific driver level and support statement
> for your IBM server.
>
> +config HW_LATENCY_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
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 2129377..c195cce 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -49,3 +49,4 @@ obj-y += carma/
> obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
> obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
> obj-$(CONFIG_INTEL_MEI) += mei/
> +obj-$(CONFIG_HW_LATENCY_TEST) += hw_latency_test.o
> diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
> new file mode 100644
> index 0000000..2aa3a74
> --- /dev/null
> +++ b/drivers/misc/hw_latency_test.c
> @@ -0,0 +1,833 @@
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/ring_buffer.h>
> +#include <linux/stop_machine.h>
> +#include <linux/time.h>
> +#include <linux/hrtimer.h>
> +#include <linux/kthread.h>
> +#include <linux/debugfs.h>
> +#include <linux/seq_file.h>
> +#include <linux/uaccess.h>
> +#include <linux/version.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/random.h>
> +#include <asm/tlbflush.h>
> +
> +#define BUF_SIZE_DEFAULT 262144UL
> +#define BUF_FLAGS (RB_FL_OVERWRITE)
> +#define U64STR_SIZE 22
> +#define DEBUGFS_BUF_SIZE 1024
> +#define DEBUGFS_NAME_SIZE 32
> +
> +#define VERSION "0.1.0"
> +#define BANNER "hardware latency test"
> +#define DRVNAME "hw_latency_test"
> +
> +#define DEFAULT_SAMPLE_WINDOW 1000000
> +#define DEFAULT_SAMPLE_WIDTH 500000
> +#define DEFAULT_LAT_THRESHOLD 10
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Luming Yu <[email protected]>");
> +MODULE_DESCRIPTION("A simple hardware latency test");
> +MODULE_VERSION(VERSION);
-------->o SNIP
Ok, hopefully this is just an unintentional oversight - but I don't
see where you are acknowledging that the original author of most of
this code is Jon Masters. It's fine for you to work on it, but you
have to somewhere acknowledge where it comes from.
Thanks
John
On Mon, 05 Nov 2012 02:59:32 +0100, Luming Yu <[email protected]> wrote:
> This patch is the first 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 SMI. Currently the patch tests TSC, CPU Frequency and
> RDRAND which is a new CPU instruction to get random number introduced in
> new CPU like Intel Ivy Bridge in stop_machine context,which is choosen to
> make sure testers fully control their system under test to rule out some
> level of unwanted noise.
>
> Signed-off-by: Luming Yu <[email protected]>
That patch has my full stamp of approval!
On Mon, 05 Nov 2012 02:59:32 +0100, Luming Yu <[email protected]> wrote:
> This patch is the first 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 SMI. Currently the patch tests TSC, CPU Frequency and
> RDRAND which is a new CPU instruction to get random number introduced in
> new CPU like Intel Ivy Bridge in stop_machine context,which is choosen to
> make sure testers fully control their system under test to rule out some
> level of unwanted noise.
>
> Signed-off-by: Luming Yu <[email protected]>
That patch has my full stamp of approval!
On Sun, Nov 4, 2012 at 4:07 PM, Maarten Lankhorst
<[email protected]> wrote:
> Hey,
>
> Op 05-11-12 02:59, Luming Yu schreef:
>> This patch is the first 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 SMI. Currently the patch tests TSC, CPU Frequency and
>> RDRAND which is a new CPU instruction to get random number introduced in
>> new CPU like Intel Ivy Bridge in stop_machine context,which is choosen to
>> make sure testers fully control their system under test to rule out some
>> level of unwanted noise.
>>
>> Signed-off-by: Luming Yu <[email protected]>
>> ---
>> drivers/misc/Kconfig | 7 +
>> drivers/misc/Makefile | 1 +
>> drivers/misc/hw_latency_test.c | 833 +++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 841 insertions(+)
>> create mode 100644 drivers/misc/hw_latency_test.c
>>
>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>> index b151b7c..5ed440b 100644
>> --- a/drivers/misc/Kconfig
>> +++ b/drivers/misc/Kconfig
>> @@ -114,6 +114,13 @@ config IBM_ASM
>> for information on the specific driver level and support statement
>> for your IBM server.
>>
>> +config HW_LATENCY_TEST
>> + tristate "Testing module to detect hardware lattency and throughput"
>> + depends on DEBUG_FS
>> + depends on RING_BUFFER
>> + depends on X86
>> + default m
> Is there any reason this tester couldn't easily be made to work for !x86?
>
Only problem is that I don't have platform to test.
> Also I think it would make more sense to squash all fixes, and submit fixes for the things like
> '[PATCH 07/13] HW-latency: delete too many "Fast TSC calibration using PIT" in cpufreq sampling'
> before the actual patch. It seems this is not necessarily a hw-latency specific patch to me.
Correct. I can do that later. I don't care it's a single big patch or
a patch series. It depends on how to help maintainers who would be
interested in taking this feature into upstream. Although I will take
all responsibility to fix all bugs coming with it and the future
enhancement of the feature.
The biggest problem to me right now for this feature is to find it a
way into upstream. I WILL do everything necessary. One big patch
instead of 13 patches-set is fine. Making it platform neutral is fine
too as long as it's necessary to make it upstream.
>
> ~Maarten
On Sun, Nov 4, 2012 at 4:23 PM, John Kacur <[email protected]> wrote:
> On Mon, Nov 5, 2012 at 2:59 AM, Luming Yu <[email protected]> wrote:
>>
>> This patch is the first 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 SMI. Currently the patch tests TSC, CPU Frequency and
>> RDRAND which is a new CPU instruction to get random number introduced in
>> new CPU like Intel Ivy Bridge in stop_machine context,which is choosen to
>> make sure testers fully control their system under test to rule out some
>> level of unwanted noise.
>>
>> Signed-off-by: Luming Yu <[email protected]>
>> ---
>> drivers/misc/Kconfig | 7 +
>> drivers/misc/Makefile | 1 +
>> drivers/misc/hw_latency_test.c | 833 +++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 841 insertions(+)
>> create mode 100644 drivers/misc/hw_latency_test.c
>>
>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>> index b151b7c..5ed440b 100644
>> --- a/drivers/misc/Kconfig
>> +++ b/drivers/misc/Kconfig
>> @@ -114,6 +114,13 @@ config IBM_ASM
>> for information on the specific driver level and support statement
>> for your IBM server.
>>
>> +config HW_LATENCY_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
>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>> index 2129377..c195cce 100644
>> --- a/drivers/misc/Makefile
>> +++ b/drivers/misc/Makefile
>> @@ -49,3 +49,4 @@ obj-y += carma/
>> obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
>> obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
>> obj-$(CONFIG_INTEL_MEI) += mei/
>> +obj-$(CONFIG_HW_LATENCY_TEST) += hw_latency_test.o
>> diff --git a/drivers/misc/hw_latency_test.c b/drivers/misc/hw_latency_test.c
>> new file mode 100644
>> index 0000000..2aa3a74
>> --- /dev/null
>> +++ b/drivers/misc/hw_latency_test.c
>> @@ -0,0 +1,833 @@
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/ring_buffer.h>
>> +#include <linux/stop_machine.h>
>> +#include <linux/time.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/kthread.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/seq_file.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/version.h>
>> +#include <linux/delay.h>
>> +#include <linux/slab.h>
>> +#include <linux/random.h>
>> +#include <asm/tlbflush.h>
>> +
>> +#define BUF_SIZE_DEFAULT 262144UL
>> +#define BUF_FLAGS (RB_FL_OVERWRITE)
>> +#define U64STR_SIZE 22
>> +#define DEBUGFS_BUF_SIZE 1024
>> +#define DEBUGFS_NAME_SIZE 32
>> +
>> +#define VERSION "0.1.0"
>> +#define BANNER "hardware latency test"
>> +#define DRVNAME "hw_latency_test"
>> +
>> +#define DEFAULT_SAMPLE_WINDOW 1000000
>> +#define DEFAULT_SAMPLE_WIDTH 500000
>> +#define DEFAULT_LAT_THRESHOLD 10
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Luming Yu <[email protected]>");
>> +MODULE_DESCRIPTION("A simple hardware latency test");
>> +MODULE_VERSION(VERSION);
>
>
> -------->o SNIP
>
> Ok, hopefully this is just an unintentional oversight - but I don't
> see where you are acknowledging that the original author of most of
> this code is Jon Masters. It's fine for you to work on it, but you
> have to somewhere acknowledge where it comes from.
Thanks very much for pointing it out.
I did ACK Jon Masters in the first push of this feature in July of this year.
Yes, I will add Jon Master to be the first author of the work in right
place, I will
claim secondary place for myself . :-)
>
> Thanks
>
> John
On Sun, Nov 04, 2012 at 08:59:31PM -0500, Luming Yu wrote:
> Back to July of this year, I sent the first round of the tool.
> Now I've polished it a little bit.
>
> 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 SMI. Currently the patch tests TSC, CPU Frequency, and
> RDRAND, which is a new CPU instruction to get random number introudced
> in new CPU like Intel Ivy Bridge, in stop_machine context.
You are adding a new file, drivers/misc/hw_latency_test.c to the
kernel. I don't think it makes sense to include the file, and then
follow it with 12 patches which modify the file. You don't need to
"show your work" with the various bug fixes that has been made since
July. I'd recommend collapsing all of the collected patches plus the
base file into a single commit.
Regards,
- Ted