Name: kmalloc testing patch Author: Rusty Russell Status: Tested on 2.6.10-rc2-bk13 This adds simple test code to __alloc_percpu. Index: linux-2.6.10-rc2-bk13-Percpu/mm/percpu.c =================================================================== --- linux-2.6.10-rc2-bk13-Percpu.orig/mm/percpu.c 2004-12-02 14:21:08.000000000 +1100 +++ linux-2.6.10-rc2-bk13-Percpu/mm/percpu.c 2004-12-02 14:50:04.124129536 +1100 @@ -332,3 +339,182 @@ up(&percpu_lock); } EXPORT_SYMBOL(free_percpu); + +#if 1 +#include + +static void check_values(unsigned int *ptrs[], + unsigned int sizes[], + unsigned int num) +{ + unsigned int cpu, i; + unsigned char *ptr; + + if (!ptrs[num]) + return; + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + ptr = (unsigned char *)per_cpu_ptr(ptrs[num], cpu); + for (i = 0; i < sizes[num]; i++) { + if (ptr[i] != (unsigned char)(num + cpu)) + BUG(); + } + } +} + +static void count_blocks(void) +{ + struct percpu_block *i; + unsigned int count = 0; + + list_for_each_entry(i, &percpu_core.list, list) + count++; + + printk("Total blocks = %u\n", count); +} + +static void check_blocklen(struct percpu_block *b) +{ + unsigned int i, size = 0; + + for (i = 0; i < b->num_used; i++) { + if (b->size[i] == 0) + printk("Block %p has bad zero size in %u/%u\n", + b, i, b->num_used); + if (i > 0 && b->size[i-1] > 0 && b->size[i] > 0) + printk("Free block %p not merged %u\n", b, i); + size += block_size(b->size[i]); + } + if (size != percpu_size) + printk("Block %p size %u not %lu\n", b, size, percpu_size); +} + +static void dump_blocks(const char *start_or_end) +{ + struct percpu_block *i; + + if (percpu_core.num_used != 2) + printk("Core block has %u blocks at %s\n", + percpu_core.num_used, start_or_end); + check_blocklen(&percpu_core); + + list_for_each_entry(i, &percpu_core.list, list) { + if (i->num_used != 1) { + printk("Block %p has %u subs at %s\n", + i->start, i->num_used, start_or_end); + } + check_blocklen(i); + } +} + +static void mymemset(void *ptr, int c, unsigned long len) +{ + unsigned char *p = ptr; + while (len > 0) { + *p = c; + p++; + len--; + } +} + +static int random(void) +{ + unsigned short s; + + get_random_bytes(&s, sizeof(s)); + return s; +} + +#define PERCPU_MAX 100 + +static int test_percpu(void) +{ + unsigned int i, allocs, frees; + unsigned int *ptr; + static unsigned int *ptrs[PERCPU_MAX], sizes[PERCPU_MAX]; + + dump_blocks("start"); + allocs = frees = 0; + ptr = __alloc_percpu(4, 4); allocs++; + printk("This cpu = %p (%u)\n", + __get_cpu_ptr(ptr), *__get_cpu_ptr(ptr)); + for (i = 0; i < NR_CPUS; i++) { + printk("&ptr[i] == %p (%u)\n", + per_cpu_ptr(ptr, i), *per_cpu_ptr(ptr, i)); + *per_cpu_ptr(ptr, i) = i; + } + free_percpu(ptr); frees++; + + BUG_ON(allocs != frees); + + printk("Stepped allocations...\n"); + for (i = 4; i < PERCPU_MAX; i+=27) { + unsigned int j; + ptrs[i] = __alloc_percpu(i, 4); allocs++; + for (j = 0; j < NR_CPUS; j++) { + mymemset(per_cpu_ptr(ptrs[i], j), 0, i); + *per_cpu_ptr(ptrs[i], j) = i; + } + } + + for (i = 4; i < PERCPU_MAX; i+=27) { + unsigned int j; + for (j = 0; j < NR_CPUS; j++) + if (*per_cpu_ptr(ptrs[i], j) != i) + BUG(); + } + + printk("Stepped frees...\n"); + for (i = 4; i < PERCPU_MAX; i+=27) { + free_percpu(ptrs[i]); frees++; + ptrs[i] = NULL; + } + + BUG_ON(allocs != frees); + + printk("Randomized test...\n"); + /* Randomized test. */ + for (i = 0; i < 100000; i++) { + unsigned int j = random() % PERCPU_MAX; + if (!ptrs[j]) { + unsigned int cpu; + + sizes[j] = random() % PERCPU_MAX; + if (sizes[j] < 4) + sizes[j] = 4; + ptrs[j] = __alloc_percpu(sizes[j], 1<<(random()%L1_CACHE_SHIFT)); + allocs++; + + for (cpu = 0; cpu < NR_CPUS; cpu++) + memset(per_cpu_ptr(ptrs[j], cpu), j+cpu, + sizes[j]); + } else { + if (random() % 1000 == 0) { + printk("c"); + for (j = 0; j < PERCPU_MAX; j++) + check_values(ptrs, sizes, j); + } else { + check_values(ptrs, sizes, j); + free_percpu(ptrs[j]); frees++; + ptrs[j] = NULL; + } + } + if (i % (10000/10) == 0) + printk("."); + } + printk("\n"); + count_blocks(); + + printk("Freeing after randomized test...\n"); + for (i = 0; i < PERCPU_MAX; i++) { + if (ptrs[i]) { + free_percpu(ptrs[i]); frees++; + ptrs[i] = NULL; + } + } + BUG_ON(allocs != frees); + dump_blocks("end"); + return 0; +} +late_initcall(test_percpu); +#endif