* [RFC In-kernel benchmarks 1/3] Add slab performance tests
2009-10-13 20:02 [RFC In-kernel benchmarks 0/3] Introduce in kernel benchmarks Christoph Lameter
@ 2009-10-13 20:02 ` Christoph Lameter
2009-10-13 20:02 ` [RFC In-kernel benchmarks 2/3] Vm statistics performance test Christoph Lameter
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Christoph Lameter @ 2009-10-13 20:02 UTC (permalink / raw)
To: Mel Gorman
Cc: linux-kernel, Pekka Enberg, Tejun Heo, Mathieu Desnoyers, akpm,
Ingo Molnar, Eric Dumazet
[-- Attachment #1: 0001-Add-slab-performance-tests.patch --]
[-- Type: text/plain, Size: 11422 bytes --]
This is a test of slab allocator performance tests.
Run
modprobe slab_test
to execute. Output will be written to the syslog.
Signed-off-by: Christoph Lameter <cl@linux-foundation.org>
---
Makefile | 2
include/Kbuild | 1
lib/Kconfig.debug | 1
tests/Kconfig | 19 ++
tests/Makefile | 2
tests/slab_test.c | 373 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 397 insertions(+), 1 deletion(-)
create mode 100644 tests/Makefile
create mode 100644 tests/slab_test.c
Index: linux-2.6/Makefile
===================================================================
--- linux-2.6.orig/Makefile 2009-10-12 15:32:26.000000000 -0500
+++ linux-2.6/Makefile 2009-10-12 15:32:30.000000000 -0500
@@ -686,7 +686,7 @@ export mod_strip_cmd
ifeq ($(KBUILD_EXTMOD),)
-core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ tests/
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
Index: linux-2.6/include/Kbuild
===================================================================
--- linux-2.6.orig/include/Kbuild 2009-10-12 15:32:26.000000000 -0500
+++ linux-2.6/include/Kbuild 2009-10-12 15:32:30.000000000 -0500
@@ -10,3 +10,4 @@ header-y += video/
header-y += drm/
header-y += xen/
header-y += scsi/
+header-y += tests/
Index: linux-2.6/tests/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/tests/Makefile 2009-10-12 15:32:30.000000000 -0500
@@ -0,0 +1,2 @@
+obj-$(CONFIG_BENCHMARK_SLAB) += slab_test.o
+
Index: linux-2.6/tests/slab_test.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/tests/slab_test.c 2009-10-12 15:32:47.000000000 -0500
@@ -0,0 +1,373 @@
+/* test-slab.c
+ *
+ * Test module for synthetic in kernel slab allocator testing.
+ *
+ * The test is triggered by loading the module (which will fail).
+ *
+ * (C) 2009 Linux Foundation <cl@linux-foundation.org>
+ */
+
+
+#include <linux/jiffies.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/timex.h>
+#include <asm/system.h>
+
+#define TEST_COUNT 10000
+
+#ifdef CONFIG_SMP
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/kthread.h>
+
+static struct test_struct {
+ struct task_struct *task;
+ int cpu;
+ int size;
+ int count;
+ void **v;
+ void (*test_p1)(struct test_struct *);
+ void (*test_p2)(struct test_struct *);
+ unsigned long start1;
+ unsigned long stop1;
+ unsigned long start2;
+ unsigned long stop2;
+} test[NR_CPUS];
+
+/*
+ * Allocate TEST_COUNT objects on cpus > 0 and then all the
+ * objects later on cpu 0
+ */
+static void remote_free_test_p1(struct test_struct *t)
+{
+ int i;
+
+ /* Perform no allocations on cpu 0 */
+ for (i = 0; i < t->count; i++) {
+ u8 *p;
+
+ if (smp_processor_id()) {
+ p = kmalloc(t->size, GFP_KERNEL);
+ /* Use object */
+ *p = 17;
+ } else
+ p = NULL;
+ t->v[i] = p;
+ }
+}
+
+static void remote_free_test_p2(struct test_struct *t)
+{
+ int i;
+ int cpu;
+
+ /* All frees are completed on cpu zero */
+ if (smp_processor_id())
+ return;
+
+ for_each_online_cpu(cpu)
+ for (i = 0; i < t->count; i++) {
+ u8 *p = test[cpu].v[i];
+
+ if (!p)
+ continue;
+
+ *p = 16;
+ kfree(p);
+ }
+}
+
+/*
+ * Allocate TEST_COUNT objects on cpu 0 and free them immediately on the
+ * other processors.
+ */
+static void alloc_n_free_test_p1(struct test_struct *t)
+{
+ int i;
+ int cpu;
+ char *p;
+
+ if (smp_processor_id()) {
+ /* Consumer */
+ for (i = 0; i < t->count / num_online_cpus(); i++) {
+ do {
+ p = t->v[i];
+ if (!p)
+ cpu_relax();
+ else
+ *p = 17;
+ } while (!p);
+ kfree(p);
+ t->v[i] = NULL;
+ }
+ return;
+ }
+ /* Producer */
+ for (i = 0; i < t->count; i++) {
+ for_each_online_cpu(cpu) {
+ if (cpu) {
+ p = kmalloc(t->size, GFP_KERNEL);
+ /* Use object */
+ *p = 17;
+ test[cpu].v[i] = p;
+ }
+ }
+ }
+}
+
+/*
+ * Allocate TEST_COUNT objects and later free them all again
+ */
+static void kmalloc_alloc_then_free_test_p1(struct test_struct *t)
+{
+ int i;
+
+ for (i = 0; i < t->count; i++) {
+ u8 *p = kmalloc(t->size, GFP_KERNEL);
+
+ *p = 14;
+ t->v[i] = p;
+ }
+}
+
+static void kmalloc_alloc_then_free_test_p2(struct test_struct *t)
+{
+ int i;
+
+ for (i = 0; i < t->count; i++) {
+ u8 *p = t->v[i];
+
+ *p = 13;
+ kfree(p);
+ }
+}
+
+/*
+ * Allocate TEST_COUNT objects. Free them immediately.
+ */
+static void kmalloc_alloc_free_test_p1(struct test_struct *t)
+{
+ int i;
+
+ for (i = 0; i < TEST_COUNT; i++) {
+ u8 *p = kmalloc(t->size, GFP_KERNEL);
+
+ *p = 12;
+ kfree(p);
+ }
+}
+
+static atomic_t tests_running;
+static atomic_t phase1_complete;
+static DECLARE_COMPLETION(completion1);
+static DECLARE_COMPLETION(completion2);
+static int started;
+
+static int test_func(void *private)
+{
+ struct test_struct *t = private;
+ cpumask_t newmask = CPU_MASK_NONE;
+
+ cpu_set(t->cpu, newmask);
+ set_cpus_allowed(current, newmask);
+ t->v = kzalloc(t->count * sizeof(void *), GFP_KERNEL);
+
+ atomic_inc(&tests_running);
+ wait_for_completion(&completion1);
+ t->start1 = get_cycles();
+ t->test_p1(t);
+ t->stop1 = get_cycles();
+ atomic_inc(&phase1_complete);
+ wait_for_completion(&completion2);
+ t->start2 = get_cycles();
+ if (t->test_p2)
+ t->test_p2(t);
+ t->stop2 = get_cycles();
+ kfree(t->v);
+ atomic_dec(&tests_running);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ return 0;
+}
+
+static void do_concurrent_test(void (*p1)(struct test_struct *),
+ void (*p2)(struct test_struct *),
+ int size, const char *name)
+{
+ int cpu;
+ unsigned long time1 = 0;
+ unsigned long time2 = 0;
+ unsigned long sum1 = 0;
+ unsigned long sum2 = 0;
+
+ atomic_set(&tests_running, 0);
+ atomic_set(&phase1_complete, 0);
+ started = 0;
+ init_completion(&completion1);
+ init_completion(&completion2);
+
+ for_each_online_cpu(cpu) {
+ struct test_struct *t = &test[cpu];
+
+ t->cpu = cpu;
+ t->count = TEST_COUNT;
+ t->test_p1 = p1;
+ t->test_p2 = p2;
+ t->size = size;
+ t->task = kthread_run(test_func, t, "test%d", cpu);
+ if (IS_ERR(t->task)) {
+ printk("Failed to start test func\n");
+ return;
+ }
+ }
+
+ /* Wait till all processes are running */
+ while (atomic_read(&tests_running) < num_online_cpus()) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+ complete_all(&completion1);
+
+ /* Wait till all processes have completed phase 1 */
+ while (atomic_read(&phase1_complete) < num_online_cpus()) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+ complete_all(&completion2);
+
+ while (atomic_read(&tests_running)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+
+ for_each_online_cpu(cpu)
+ kthread_stop(test[cpu].task);
+
+ printk(KERN_ALERT "%s(%d):", name, size);
+ for_each_online_cpu(cpu) {
+ struct test_struct *t = &test[cpu];
+
+ time1 = t->stop1 - t->start1;
+ time2 = t->stop2 - t->start2;
+ sum1 += time1;
+ sum2 += time2;
+ printk(" %d=%lu", cpu, time1 / TEST_COUNT);
+ if (p2)
+ printk("/%lu", time2 / TEST_COUNT);
+ }
+ printk(" Average=%lu", sum1 / num_online_cpus() / TEST_COUNT);
+ if (p2)
+ printk("/%lu", sum2 / num_online_cpus() / TEST_COUNT);
+ printk("\n");
+ schedule_timeout(200);
+}
+#endif
+
+static int slab_test_init(void)
+{
+ void **v = kmalloc(TEST_COUNT * sizeof(void *), GFP_KERNEL);
+ unsigned int i;
+ cycles_t time1, time2, time;
+ int rem;
+ int size;
+
+ printk(KERN_ALERT "test init\n");
+
+ printk(KERN_ALERT "Single thread testing\n");
+ printk(KERN_ALERT "=====================\n");
+ printk(KERN_ALERT "1. Kmalloc: Repeatedly allocate then free test\n");
+ for (size = 8; size <= PAGE_SIZE << 2; size <<= 1) {
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++) {
+ u8 *p = kmalloc(size, GFP_KERNEL);
+
+ *p = 22;
+ v[i] = p;
+ }
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk(KERN_ALERT "%i times kmalloc(%d) ", i, size);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles ", time);
+
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++) {
+ u8 *p = v[i];
+
+ *p = 23;
+ kfree(p);
+ }
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk("kfree ");
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles\n", time);
+ }
+
+ printk(KERN_ALERT "2. Kmalloc: alloc/free test\n");
+ for (size = 8; size <= PAGE_SIZE << 2; size <<= 1) {
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++) {
+ u8 *p = kmalloc(size, GFP_KERNEL);
+
+ kfree(p);
+ }
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk(KERN_ALERT "%i times kmalloc(%d)/kfree ", i, size);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles\n", time);
+ }
+ kfree(v);
+#ifdef CONFIG_SMP
+ printk(KERN_INFO "Concurrent allocs\n");
+ printk(KERN_INFO "=================\n");
+ for (i = 3; i <= PAGE_SHIFT; i++) {
+ do_concurrent_test(kmalloc_alloc_then_free_test_p1,
+ kmalloc_alloc_then_free_test_p2,
+ 1 << i, "Kmalloc N*alloc N*free");
+ }
+ for (i = 3; i <= PAGE_SHIFT; i++) {
+ do_concurrent_test(kmalloc_alloc_free_test_p1, NULL,
+ 1 << i, "Kmalloc N*(alloc free)");
+ }
+
+ printk(KERN_INFO "Remote free test\n");
+ printk(KERN_INFO "================\n");
+ for (i = 3; i <= PAGE_SHIFT; i++) {
+ do_concurrent_test(remote_free_test_p1,
+ remote_free_test_p2,
+ 1 << i, "N*remote free");
+ }
+
+ printk(KERN_INFO "1 alloc N free test\n");
+ printk(KERN_INFO "===================\n");
+ for (i = 3; i <= PAGE_SHIFT; i++) {
+ do_concurrent_test(alloc_n_free_test_p1,
+ NULL,
+ 1 << i, "1 alloc N free");
+ }
+
+#endif
+ return -EAGAIN; /* Fail will directly unload the module */
+}
+
+static void slab_test_exit(void)
+{
+ printk(KERN_ALERT "test exit\n");
+}
+
+module_init(slab_test_init)
+module_exit(slab_test_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christoph Lameter and Mathieu Desnoyers");
+MODULE_DESCRIPTION("SLAB test");
+
Index: linux-2.6/lib/Kconfig.debug
===================================================================
--- linux-2.6.orig/lib/Kconfig.debug 2009-10-12 15:32:26.000000000 -0500
+++ linux-2.6/lib/Kconfig.debug 2009-10-12 15:32:30.000000000 -0500
@@ -920,6 +920,7 @@ config SYSCTL_SYSCALL_CHECK
source mm/Kconfig.debug
source kernel/trace/Kconfig
+source tests/Kconfig
config PROVIDE_OHCI1394_DMA_INIT
bool "Remote debugging over FireWire early on boot"
Index: linux-2.6/tests/Kconfig
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/tests/Kconfig 2009-10-12 15:32:30.000000000 -0500
@@ -0,0 +1,19 @@
+menuconfig BENCHMARKS
+ bool "In kernel benchmarks"
+ def_bool n
+ help
+ Includes in kernel benchmark modules in the build. These modules can
+ be loaded later to trigger benchmarking kernel subsystems.
+ Output will be generated in the system log.
+
+if BENCHMARKS
+
+config BENCHMARK_SLAB
+ tristate "Slab allocator Benchmark"
+ depends on m
+ default m
+ help
+ A benchmark that measures slab allocator performance.
+
+endif # BENCHMARKS
+
--
^ permalink raw reply [flat|nested] 5+ messages in thread* [RFC In-kernel benchmarks 2/3] Vm statistics performance test
2009-10-13 20:02 [RFC In-kernel benchmarks 0/3] Introduce in kernel benchmarks Christoph Lameter
2009-10-13 20:02 ` [RFC In-kernel benchmarks 1/3] Add slab performance tests Christoph Lameter
@ 2009-10-13 20:02 ` Christoph Lameter
2009-10-13 20:02 ` [RFC In-kernel benchmarks 3/3] Page allocator test Christoph Lameter
2009-10-15 8:09 ` [RFC In-kernel benchmarks 0/3] Introduce in kernel benchmarks David Rientjes
3 siblings, 0 replies; 5+ messages in thread
From: Christoph Lameter @ 2009-10-13 20:02 UTC (permalink / raw)
To: Mel Gorman
Cc: linux-kernel, Pekka Enberg, Tejun Heo, Mathieu Desnoyers, akpm,
Ingo Molnar, Eric Dumazet
[-- Attachment #1: 0002-Vm-statistics-performance-test.patch --]
[-- Type: text/plain, Size: 3891 bytes --]
Tests the performance of some key vm statistics functions.
Signed-off-by: Christoph Lameter <cl@linux-foundation.org>
---
tests/Kconfig | 7 +++
tests/Makefile | 1
tests/vmstat_test.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 105 insertions(+)
create mode 100644 tests/vmstat_test.c
Index: linux-2.6/tests/Makefile
===================================================================
--- linux-2.6.orig/tests/Makefile 2009-10-12 15:13:04.000000000 -0500
+++ linux-2.6/tests/Makefile 2009-10-12 15:15:08.000000000 -0500
@@ -1,2 +1,3 @@
obj-$(CONFIG_BENCHMARK_SLAB) += slab_test.o
+obj-#(CONFIG_BENCHMARK_VMSTAT) += vmstat_test.o
Index: linux-2.6/tests/vmstat_test.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/tests/vmstat_test.c 2009-10-12 15:15:08.000000000 -0500
@@ -0,0 +1,97 @@
+/* test-vmstat.c
+ *
+ * Test module for in kernel synthetic vm statistics performance.
+ *
+ * execute
+ *
+ * modprobe test-vmstat
+ *
+ * to run this test
+ *
+ * (C) 2009 Linux Foundation, Christoph Lameter <cl@linux-foundation.org>
+ */
+
+#include <linux/jiffies.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/timex.h>
+#include <asm/system.h>
+
+#define TEST_COUNT 10000
+
+static int vmstat_test_init(void)
+{
+ unsigned int i;
+ cycles_t time1, time2, time;
+ int rem;
+ struct page *page = alloc_page(GFP_KERNEL);
+
+ printk(KERN_ALERT "VMstat testing\n");
+ printk(KERN_ALERT "=====================\n");
+ printk(KERN_ALERT "1. inc_zone_page_state() then dec_zone_page_state()\n");
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++)
+ inc_zone_page_state(page, NR_BOUNCE);
+
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk(KERN_ALERT "%i times inc_zone_page_state() ", i);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles ", time);
+
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++)
+ __dec_zone_page_state(page, NR_BOUNCE);
+
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk("__dec_z_p_s() ");
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles\n", time);
+
+ printk(KERN_ALERT "2. inc_zone_page_state()/dec_zone_page_state()\n");
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++) {
+ inc_zone_page_state(page, NR_BOUNCE);
+ dec_zone_page_state(page, NR_BOUNCE);
+ }
+
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk(KERN_ALERT "%i times inc/dec ", i);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles\n", time);
+
+ printk(KERN_ALERT "3. count_vm_event()\n");
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++)
+ count_vm_event(SLABS_SCANNED);
+
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ count_vm_events(SLABS_SCANNED, -TEST_COUNT);
+ printk(KERN_ALERT "%i count_vm_events ", i);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles\n", time);
+ __free_page(page);
+ return -EAGAIN; /* Fail will directly unload the module */
+}
+
+static void vmstat_test_exit(void)
+{
+ printk(KERN_ALERT "test exit\n");
+}
+
+module_init(vmstat_test_init)
+module_exit(vmstat_test_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christoph Lameter");
+MODULE_DESCRIPTION("VM statistics test");
+
Index: linux-2.6/tests/Kconfig
===================================================================
--- linux-2.6.orig/tests/Kconfig 2009-10-12 15:14:54.000000000 -0500
+++ linux-2.6/tests/Kconfig 2009-10-12 15:15:55.000000000 -0500
@@ -15,5 +15,12 @@ config BENCHMARK_SLAB
help
A benchmark that measures slab allocator performance.
+config BENCHMARK_VMSTAT
+ tristate "VM statistics Benchmark"
+ default m
+ depends on m
+ help
+ A benchmark measuring the performance of vm statistics.
+
endif # BENCHMARKS
--
^ permalink raw reply [flat|nested] 5+ messages in thread* [RFC In-kernel benchmarks 3/3] Page allocator test
2009-10-13 20:02 [RFC In-kernel benchmarks 0/3] Introduce in kernel benchmarks Christoph Lameter
2009-10-13 20:02 ` [RFC In-kernel benchmarks 1/3] Add slab performance tests Christoph Lameter
2009-10-13 20:02 ` [RFC In-kernel benchmarks 2/3] Vm statistics performance test Christoph Lameter
@ 2009-10-13 20:02 ` Christoph Lameter
2009-10-15 8:09 ` [RFC In-kernel benchmarks 0/3] Introduce in kernel benchmarks David Rientjes
3 siblings, 0 replies; 5+ messages in thread
From: Christoph Lameter @ 2009-10-13 20:02 UTC (permalink / raw)
To: Mel Gorman
Cc: linux-kernel, Pekka Enberg, Tejun Heo, Mathieu Desnoyers, akpm,
Ingo Molnar, Eric Dumazet
[-- Attachment #1: 0003-Page-allocator-test.patch --]
[-- Type: text/plain, Size: 9560 bytes --]
Implement a test of the page allocator speed in the same way as for the
slab allocators.
Signed-off-by: Christoph Lameter <cl@linux-foundation.org>
---
tests/Kconfig | 7 +
tests/Makefile | 3
tests/pagealloc_test.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 343 insertions(+), 1 deletion(-)
create mode 100644 tests/page_test.c
Index: linux-2.6/tests/Makefile
===================================================================
--- linux-2.6.orig/tests/Makefile 2009-10-12 15:17:45.000000000 -0500
+++ linux-2.6/tests/Makefile 2009-10-12 15:17:46.000000000 -0500
@@ -1,3 +1,4 @@
obj-$(CONFIG_BENCHMARK_SLAB) += slab_test.o
-obj-#(CONFIG_BENCHMARK_VMSTAT) += vmstat_test.o
+obj-$(CONFIG_BENCHMARK_VMSTAT) += vmstat_test.o
+obj-$(CONFIG_BENCHMARK_PAGEALLOC) += pagealloc_test.o
Index: linux-2.6/tests/pagealloc_test.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/tests/pagealloc_test.c 2009-10-12 15:17:46.000000000 -0500
@@ -0,0 +1,334 @@
+/* pagealloc_test.c
+ *
+ * Test module for in kernel synthetic page allocator testing.
+ *
+ * Compiled as a module. The module needs to be loaded to run.
+ *
+ * (C) 2009 Linux Foundation, Christoph Lameter <cl@linux-foundation.org>
+ */
+
+
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <asm/timex.h>
+#include <asm/system.h>
+
+#define TEST_COUNT 1000
+
+#define CONCURRENT_MAX_ORDER 6
+
+#ifdef CONFIG_SMP
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/kthread.h>
+
+static struct test_struct {
+ struct task_struct *task;
+ int cpu;
+ int order;
+ int count;
+ struct page **v;
+ void (*test_p1)(struct test_struct *);
+ void (*test_p2)(struct test_struct *);
+ unsigned long start1;
+ unsigned long stop1;
+ unsigned long start2;
+ unsigned long stop2;
+} test[NR_CPUS];
+
+/*
+ * Allocate TEST_COUNT objects on cpus > 0 and then all the
+ * objects later on cpu 0
+ */
+static void remote_free_test_p1(struct test_struct *t)
+{
+ int i;
+
+ /* Perform no allocations on cpu 0 */
+ for (i = 0; i < t->count; i++) {
+ struct page *p;
+
+ if (smp_processor_id()) {
+ p = alloc_pages(GFP_KERNEL | __GFP_COMP, t->order);
+ /* Use object */
+ memset(page_address(p), 17, 4);
+ } else
+ p = NULL;
+ t->v[i] = p;
+ }
+}
+
+static void remote_free_test_p2(struct test_struct *t)
+{
+ int i;
+ int cpu;
+
+ /* All frees are completed on cpu zero */
+ if (smp_processor_id())
+ return;
+
+ for_each_online_cpu(cpu)
+ for (i = 0; i < t->count; i++) {
+ struct page *p = test[cpu].v[i];
+
+ if (!p)
+ continue;
+
+ __free_pages(p, t->order);
+ }
+}
+
+/*
+ * Allocate TEST_COUNT objects and later free them all again
+ */
+static void alloc_then_free_test_p1(struct test_struct *t)
+{
+ int i;
+
+ for (i = 0; i < t->count; i++) {
+ struct page *p = alloc_pages(GFP_KERNEL | __GFP_COMP, t->order);
+
+ memset(page_address(p), 14, 4);
+ t->v[i] = p;
+ }
+}
+
+static void alloc_then_free_test_p2(struct test_struct *t)
+{
+ int i;
+
+ for (i = 0; i < t->count; i++) {
+ struct page *p = t->v[i];
+
+ __free_pages(p, t->order);
+ }
+}
+
+/*
+ * Allocate TEST_COUNT objects. Free them immediately.
+ */
+static void alloc_free_test_p1(struct test_struct *t)
+{
+ int i;
+
+ for (i = 0; i < TEST_COUNT; i++) {
+ struct page *p = alloc_pages(GFP_KERNEL | __GFP_COMP, t->order);
+
+ memset(page_address(p), 12, 4);
+ __free_pages(p, t->order);
+ }
+}
+
+static atomic_t tests_running;
+static atomic_t phase1_complete;
+static DECLARE_COMPLETION(completion1);
+static DECLARE_COMPLETION(completion2);
+static int started;
+
+static int test_func(void *private)
+{
+ struct test_struct *t = private;
+ cpumask_t newmask = CPU_MASK_NONE;
+
+ cpu_set(t->cpu, newmask);
+ set_cpus_allowed(current, newmask);
+ t->v = kmalloc(t->count * sizeof(struct page *), GFP_KERNEL);
+
+ atomic_inc(&tests_running);
+ wait_for_completion(&completion1);
+ t->start1 = get_cycles();
+ t->test_p1(t);
+ t->stop1 = get_cycles();
+ atomic_inc(&phase1_complete);
+ wait_for_completion(&completion2);
+ t->start2 = get_cycles();
+ if (t->test_p2)
+ t->test_p2(t);
+ t->stop2 = get_cycles();
+ kfree(t->v);
+ atomic_dec(&tests_running);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ return 0;
+}
+
+static void do_concurrent_test(void (*p1)(struct test_struct *),
+ void (*p2)(struct test_struct *),
+ int order, const char *name)
+{
+ int cpu;
+ unsigned long time1 = 0;
+ unsigned long time2 = 0;
+ unsigned long sum1 = 0;
+ unsigned long sum2 = 0;
+
+ atomic_set(&tests_running, 0);
+ atomic_set(&phase1_complete, 0);
+ started = 0;
+ init_completion(&completion1);
+ init_completion(&completion2);
+
+ for_each_online_cpu(cpu) {
+ struct test_struct *t = &test[cpu];
+
+ t->cpu = cpu;
+ t->count = TEST_COUNT;
+ t->test_p1 = p1;
+ t->test_p2 = p2;
+ t->order = order;
+ t->task = kthread_run(test_func, t, "test%d", cpu);
+ if (IS_ERR(t->task)) {
+ printk("Failed to start test func\n");
+ return;
+ }
+ }
+
+ /* Wait till all processes are running */
+ while (atomic_read(&tests_running) < num_online_cpus()) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+ complete_all(&completion1);
+
+ /* Wait till all processes have completed phase 1 */
+ while (atomic_read(&phase1_complete) < num_online_cpus()) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+ complete_all(&completion2);
+
+ while (atomic_read(&tests_running)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+
+ for_each_online_cpu(cpu)
+ kthread_stop(test[cpu].task);
+
+ printk(KERN_ALERT "%s(%d):", name, order);
+ for_each_online_cpu(cpu) {
+ struct test_struct *t = &test[cpu];
+
+ time1 = t->stop1 - t->start1;
+ time2 = t->stop2 - t->start2;
+ sum1 += time1;
+ sum2 += time2;
+ printk(" %d=%lu", cpu, time1 / TEST_COUNT);
+ if (p2)
+ printk("/%lu", time2 / TEST_COUNT);
+ }
+ printk(" Average=%lu", sum1 / num_online_cpus() / TEST_COUNT);
+ if (p2)
+ printk("/%lu", sum2 / num_online_cpus() / TEST_COUNT);
+ printk("\n");
+ schedule_timeout(200);
+}
+#endif
+
+static int pagealloc_test_init(void)
+{
+ void **v = kmalloc(TEST_COUNT * sizeof(void *), GFP_KERNEL);
+ unsigned int i;
+ cycles_t time1, time2, time;
+ int rem;
+ int order;
+
+ printk(KERN_ALERT "test init\n");
+
+ printk(KERN_ALERT "Single thread testing\n");
+ printk(KERN_ALERT "=====================\n");
+ printk(KERN_ALERT "1. Repeatedly allocate then free test\n");
+ for (order = 0; order < MAX_ORDER; order++) {
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++) {
+ struct page *p = alloc_pages(GFP_KERNEL | __GFP_COMP,
+ order);
+
+ if (!p) {
+ printk("Cannot allocate order=%d\n", order);
+ break;
+ }
+
+ /* Touch page */
+ memset(page_address(p), 22, 4);
+ v[i] = p;
+ }
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk(KERN_ALERT "%i times alloc_page(,%d) ", i, order);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles ", time);
+
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++) {
+ struct page *p = v[i];
+
+ __free_pages(p, order);
+ }
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk("__free_pages(,%d)", order);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles\n", time);
+ }
+
+ printk(KERN_ALERT "2. alloc/free test\n");
+ for (order = 0; order < MAX_ORDER; order++) {
+ time1 = get_cycles();
+ for (i = 0; i < TEST_COUNT; i++) {
+ struct page *p = alloc_pages(GFP_KERNEL| __GFP_COMP, order);
+
+ __free_pages(p, order);
+ }
+ time2 = get_cycles();
+ time = time2 - time1;
+
+ printk(KERN_ALERT "%i times alloc( ,%d)/free ", i, order);
+ time = div_u64_rem(time, TEST_COUNT, &rem);
+ printk("-> %llu cycles\n", time);
+ }
+ kfree(v);
+#ifdef CONFIG_SMP
+ printk(KERN_INFO "Concurrent allocs\n");
+ printk(KERN_INFO "=================\n");
+ for (order = 0; order < CONCURRENT_MAX_ORDER; order++) {
+ do_concurrent_test(alloc_then_free_test_p1,
+ alloc_then_free_test_p2,
+ order, "Page alloc N*alloc N*free");
+ }
+ printk("----Fastpath---\n");
+ for (order = 0; order < CONCURRENT_MAX_ORDER; order++) {
+ do_concurrent_test(alloc_free_test_p1, NULL,
+ order, "Page N*(alloc free)");
+ }
+
+ printk(KERN_INFO "Remote free test\n");
+ printk(KERN_INFO "================\n");
+ for (order = 0; order < CONCURRENT_MAX_ORDER; order++) {
+ do_concurrent_test(remote_free_test_p1,
+ remote_free_test_p2,
+ order, "N*remote free");
+ }
+
+#endif
+
+ return -EAGAIN; /* Fail will directly unload the module */
+}
+
+static void pagealloc_test_exit(void)
+{
+ printk(KERN_ALERT "test exit\n");
+}
+
+module_init(pagealloc_test_init)
+module_exit(pagealloc_test_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christoph Lameter");
+MODULE_DESCRIPTION("page allocator performance test");
+
Index: linux-2.6/tests/Kconfig
===================================================================
--- linux-2.6.orig/tests/Kconfig 2009-10-12 15:17:45.000000000 -0500
+++ linux-2.6/tests/Kconfig 2009-10-12 15:17:46.000000000 -0500
@@ -22,5 +22,12 @@ config BENCHMARK_VMSTAT
help
A benchmark measuring the performance of vm statistics.
+config BENCHMARK_PAGEALLOC
+ tristate "Page Allocator Benchmark"
+ default m
+ depends on m
+ help
+ A benchmark measuring the performance of the page allocator.
+
endif # BENCHMARKS
--
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [RFC In-kernel benchmarks 0/3] Introduce in kernel benchmarks
2009-10-13 20:02 [RFC In-kernel benchmarks 0/3] Introduce in kernel benchmarks Christoph Lameter
` (2 preceding siblings ...)
2009-10-13 20:02 ` [RFC In-kernel benchmarks 3/3] Page allocator test Christoph Lameter
@ 2009-10-15 8:09 ` David Rientjes
3 siblings, 0 replies; 5+ messages in thread
From: David Rientjes @ 2009-10-15 8:09 UTC (permalink / raw)
To: Christoph Lameter
Cc: Mel Gorman, linux-kernel, Pekka Enberg, Tejun Heo,
Mathieu Desnoyers, akpm, Ingo Molnar, Eric Dumazet
On Tue, 13 Oct 2009, Christoph Lameter wrote:
> In kernel benchmarks are benchmarks that directly run in kernel space.
>
> The test modules are regular kernel modules that can be loaded with
>
> modprobe slab_test
>
> or so.
>
> The initialization function of the module will then run the test
> and fail so that the module is not loaded. The output of the test
> results will be written to the system log.
>
> This is a rough draft. I have used these in the past to benchmark
> page allocator, slab allocator and vmstat performance.
>
I like the addition of these benchmarks to the kernel source, I've been
adding Mathieu's slab benchmark to my tree for a while. It looks like
they all need some degree of cleanup, though: they have checkpatch
warnings, they frequently do not handle memory allocation failures, and it
would be nice to have a consistent loglevel for all the results.
^ permalink raw reply [flat|nested] 5+ messages in thread