From 6378724095a1b00a21a543318ae115a185fb0884 Mon Sep 17 00:00:00 2001 From: compudj Date: Tue, 20 Mar 2007 20:36:29 +0000 Subject: [PATCH] add test-tsc git-svn-id: http://ltt.polymtl.ca/svn@2446 04897980-b3bd-0310-b5e0-8ef037075253 --- tests/kernel/Makefile | 1 + tests/kernel/test-tsc-sync.c | 2 +- tests/kernel/test-tsc.c | 107 +++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 tests/kernel/test-tsc.c diff --git a/tests/kernel/Makefile b/tests/kernel/Makefile index 69d5ff2a..01259f55 100644 --- a/tests/kernel/Makefile +++ b/tests/kernel/Makefile @@ -12,6 +12,7 @@ ifneq ($(CONFIG_LTT),) endif # obj-m += test-async-tsc.o obj-m += test-tsc-sync.o + obj-m += test-tsc.o # obj-m += test-hpet.o #obj-m += test-debugfs.o # obj-m += test-mod.o diff --git a/tests/kernel/test-tsc-sync.c b/tests/kernel/test-tsc-sync.c index 200839ab..14cd008b 100644 --- a/tests/kernel/test-tsc-sync.c +++ b/tests/kernel/test-tsc-sync.c @@ -24,7 +24,7 @@ static void test_each(void *info) atomic_dec(&kernel_threads_to_run); while(atomic_read(&kernel_threads_to_run)) cpu_relax(); - __get_cpu_var(count) = get_cycles(); + __get_cpu_var(count) = get_cycles_sync(); local_irq_restore(flags); } diff --git a/tests/kernel/test-tsc.c b/tests/kernel/test-tsc.c new file mode 100644 index 00000000..8a3991f0 --- /dev/null +++ b/tests/kernel/test-tsc.c @@ -0,0 +1,107 @@ +/* test-tsc.c + * + * Test TSC synchronization + */ + + +#include +#include +#include +#include +#include +#include + +#define MAX_CYCLES_DELTA 1000ULL + +static DEFINE_PER_CPU(cycles_t, tsc_count) = 0; + +static atomic_t wait_sync; +static atomic_t wait_end_sync; + +/* Mark it noinline so we make sure it is not unrolled. + * Wait until value is reached. */ +static noinline void tsc_barrier(int value) +{ + sync_core(); + atomic_dec(&wait_sync); + do { + barrier(); + } while(unlikely(atomic_read(&wait_sync) > value)); + __get_cpu_var(tsc_count) = get_cycles_sync(); +} + +/* worker thread called on each CPU. + * First wait with interrupts enabled, then wait with interrupt disabled, + * for precision. We are already bound to one CPU. */ +static void test_sync(void *arg) +{ + unsigned long flags; + + local_irq_save(flags); + tsc_barrier(2); /* Make sure the instructions are in I-CACHE */ + tsc_barrier(0); + atomic_dec(&wait_end_sync); + do { + barrier(); + } while(unlikely(atomic_read(&wait_end_sync))); + local_irq_restore(flags); +} + +/* Do loops (making sure no unexpected event changes the timing), keep the + * best one. The result of each loop is the highest tsc delta between the + * master CPU and the slaves. */ +static int test_synchronization(void) +{ + int cpu, master; + cycles_t max_diff = 0, diff, best_loop, worse_loop = 0; + int i; + + preempt_disable(); + master = smp_processor_id(); + for_each_online_cpu(cpu) { + if (master == cpu) + continue; + best_loop = ULLONG_MAX; + for (i = 0; i < 10; i++) { + /* Each CPU (master and slave) must decrement the + * wait_sync value twice (one for priming in cache) */ + atomic_set(&wait_sync, 4); + atomic_set(&wait_end_sync, 2); + smp_call_function_single(cpu, test_sync, NULL, 1, 0); + test_sync(NULL); + diff = abs(per_cpu(tsc_count, cpu) + - per_cpu(tsc_count, master)); + best_loop = min(best_loop, diff); + worse_loop = max(worse_loop, diff); + } + max_diff = max(best_loop, max_diff); + } + preempt_enable(); + if (max_diff >= MAX_CYCLES_DELTA) { + printk("Synchronization tsc : %llu cycles delta is over " + "threshold %llu\n", max_diff, MAX_CYCLES_DELTA); + printk("Synchronization tsc (worse loop) : %llu cycles delta\n", + worse_loop); + } + return max_diff < MAX_CYCLES_DELTA; +} + +static int __init test_init(void) +{ + int ret; + + ret = test_synchronization(); + return 0; +} + +static void __exit test_exit(void) +{ +} + +module_init(test_init); +module_exit(test_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("sync tsc test"); + -- 2.34.1