/* * Copyright (c) 2008 Travis Geiselbrecht * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include static uint8_t *src; static uint8_t *dst; static uint8_t *src2; static uint8_t *dst2; #define BUFFER_SIZE (1024*1024) #define ITERATIONS 16 extern void *mymemcpy(void *dst, const void *src, size_t len); extern void *mymemset(void *dst, int c, size_t len); static void *null_memcpy(void *dst, const void *src, size_t len) { return dst; } static time_t bench_memcpy_routine(void *memcpy_routine(void *, const void *, size_t), size_t srcalign, size_t dstalign) { int i; time_t t0; t0 = current_time(); for (i=0; i < ITERATIONS; i++) { memcpy_routine(dst + dstalign, src + srcalign, BUFFER_SIZE); } return current_time() - t0; } static void bench_memcpy(void) { time_t null, libc, mine; size_t srcalign, dstalign; printf("memcpy speed test\n"); thread_sleep(200); // let the debug string clear the serial port for (srcalign = 0; srcalign < 64; ) { for (dstalign = 0; dstalign < 64; ) { null = bench_memcpy_routine(&null_memcpy, srcalign, dstalign); libc = bench_memcpy_routine(&memcpy, srcalign, dstalign); mine = bench_memcpy_routine(&mymemcpy, srcalign, dstalign); printf("srcalign %lu, dstalign %lu\n", srcalign, dstalign); printf(" null memcpy %u msecs\n", null); printf(" libc memcpy %u msecs, %llu bytes/sec\n", libc, BUFFER_SIZE * ITERATIONS * 1000ULL / libc); printf(" my memcpy %u msecs, %llu bytes/sec\n", mine, BUFFER_SIZE * ITERATIONS * 1000ULL / mine); if (dstalign == 0) dstalign = 1; else dstalign <<= 1; } if (srcalign == 0) srcalign = 1; else srcalign <<= 1; } } static void fillbuf(void *ptr, size_t len, uint32_t seed) { size_t i; for (i = 0; i < len; i++) { ((char *)ptr)[i] = seed; seed *= 0x1234567; } } static void validate_memcpy(void) { size_t srcalign, dstalign, size; const size_t maxsize = 256; printf("testing memcpy for correctness\n"); /* * do the simple tests to make sure that memcpy doesn't color outside * the lines for all alignment cases */ for (srcalign = 0; srcalign < 64; srcalign++) { for (dstalign = 0; dstalign < 64; dstalign++) { // printf("srcalign %zu, dstalign %zu\n", srcalign, dstalign); for (size = 0; size < maxsize; size++) { // printf("srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size); fillbuf(src, maxsize * 2, 567); fillbuf(src2, maxsize * 2, 567); fillbuf(dst, maxsize * 2, 123514); fillbuf(dst2, maxsize * 2, 123514); memcpy(dst + dstalign, src + srcalign, size); mymemcpy(dst2 + dstalign, src2 + srcalign, size); int comp = memcmp(dst, dst2, maxsize * 2); if (comp != 0) { printf("error! srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size); } } } } } static void validate_memcpy_overlap(void) { size_t srcalign, dstalign, size; const size_t maxsize = 256; int comp; printf("testing memcpy for correctness in overlap cases\n"); for (dstalign = 0; dstalign < 64; dstalign++) { for (size = 0; size < maxsize; size++) { fillbuf(src, maxsize * 2, 567); fillbuf(src2, maxsize * 2, 567); /* Case one will check cpy memory is the same - fwd*/ memcpy(src + dstalign, src, size); comp = memcmp(src + dstalign, src2, size); if (comp != 0) { printf("ERROR (Case1): dstalign %zu, size %zu, ret %d\n", dstalign, size, comp); } fillbuf(src, maxsize * 2, 8588485); fillbuf(src2, maxsize * 2, 8588485); /* Case two will check cpy memory is the same - bkwd*/ memcpy(src, src + dstalign, size); comp = memcmp(src, src2 + dstalign, size); if (comp != 0) { printf("ERROR (Case2): dstalign %zu, size %zu, ret %d\n", dstalign, size, comp); } } } } static time_t bench_memset_routine(void *memset_routine(void *, int, size_t), size_t dstalign) { int i; time_t t0; t0 = current_time(); for (i=0; i < ITERATIONS; i++) { memset_routine(dst + dstalign, 0, BUFFER_SIZE); } return current_time() - t0; } static void bench_memset(void) { time_t libc, mine; size_t dstalign; printf("memset speed test\n"); thread_sleep(200); // let the debug string clear the serial port for (dstalign = 0; dstalign < 64; dstalign++) { libc = bench_memset_routine(&memset, dstalign); mine = bench_memset_routine(&mymemset, dstalign); printf("dstalign %lu\n", dstalign); printf(" libc memset %u msecs, %llu bytes/sec\n", libc, BUFFER_SIZE * ITERATIONS * 1000ULL / libc); printf(" my memset %u msecs, %llu bytes/sec\n", mine, BUFFER_SIZE * ITERATIONS * 1000ULL / mine); } } static void validate_memset(void) { size_t dstalign, size; int c; const size_t maxsize = 256; printf("testing memset for correctness\n"); for (dstalign = 0; dstalign < 64; dstalign++) { printf("align %zd\n", dstalign); for (size = 0; size < maxsize; size++) { for (c = 0; c < 256; c++) { fillbuf(dst, maxsize * 2, 123514); fillbuf(dst2, maxsize * 2, 123514); memset(dst + dstalign, c, size); mymemset(dst2 + dstalign, c, size); int comp = memcmp(dst, dst2, maxsize * 2); if (comp != 0) { printf("error! align %zu, c %d, size %zu\n", dstalign, c, size); } } } } } #if defined(WITH_LIB_CONSOLE) #include static int string_tests(int argc, cmd_args *argv) { src = memalign(64, BUFFER_SIZE + 256); dst = memalign(64, BUFFER_SIZE + 256); src2 = memalign(64, BUFFER_SIZE + 256); dst2 = memalign(64, BUFFER_SIZE + 256); printf("src %p, dst %p\n", src, dst); printf("src2 %p, dst2 %p\n", src2, dst2); if (argc < 3) { printf("not enough arguments:\n"); usage: printf("%s validate \n", argv[0].str); printf("%s bench \n", argv[0].str); goto out; } if (!strcmp(argv[1].str, "validate")) { if (!strcmp(argv[2].str, "memcpy")) { validate_memcpy(); } else if (!strcmp(argv[2].str, "memset")) { validate_memset(); } else if (!strcmp(argv[2].str, "memcpy_overlap")) { validate_memcpy_overlap(); } } else if (!strcmp(argv[1].str, "bench")) { if (!strcmp(argv[2].str, "memcpy")) { bench_memcpy(); } else if (!strcmp(argv[2].str, "memset")) { bench_memset(); } } else { goto usage; } out: free(src); free(dst); free(src2); free(dst2); return 0; } STATIC_COMMAND_START { "string", NULL, &string_tests }, STATIC_COMMAND_END(stringtests); #endif APP_START(stringtests) APP_END