// SPDX-License-Identifier: GPL-2.0-only #include #include #include #include #include #ifdef CONFIG_X86 #include #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; }