// SPDX-License-Identifier: GPL-2.0-only
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/timekeeping.h>
#include <linux/string.h>
#ifdef CONFIG_X86
#include <asm/cacheflush.h>
#endif
#define NUM_PAGES (1 << (MAX_ORDER + 5))
#define PG_SIZE (PAGE_SIZE * NUM_PAGES)
static __init int memcpy_align_selftest(void)
{
struct page *page1, *page2;
char *dst, *src;
ktime_t t0, t1;
int err = 0;
int i, j;
page1 = alloc_contig_pages(NUM_PAGES, GFP_KERNEL, NUMA_NO_NODE, 0);
if (!page1)
return 1;
page2 = alloc_contig_pages(NUM_PAGES, GFP_KERNEL, NUMA_NO_NODE, 0);
if (!page2) {
err = 1;
goto free1;
}
printk("Strings selftest: memcpy testing with size: %lu Mb\n", PG_SIZE >> 20);
src = page_to_virt(page1);
dst = page_to_virt(page2);
preempt_disable();
for (i = 0; i < sizeof(void*); i++) {
#ifdef CONFIG_X86
for (j = 0; j < PG_SIZE; j += L1_CACHE_BYTES) {
clflush(src + j);
clflush(dst + j);
cond_resched();
}
#endif
for (j = 0; j < sizeof(void*); j++) {
t0 = ktime_get();
memcpy(dst + i, src + j, PG_SIZE - max(i, j));
t1 = ktime_get();
printk("Strings selftest: memcpy(dst+%d, src+%d), distance %lu: %llu Mb/s\n",
i, j, (j - i) % sizeof(long),
PG_SIZE * (1000000000l / 1048576l) / (t1-t0));
cond_resched();
}
printk("\n");
}
preempt_enable();
free_contig_range(page_to_pfn(page2), NUM_PAGES);
free1:
free_contig_range(page_to_pfn(page1), NUM_PAGES);
return err;
}
Comments