250 lines
6.4 KiB
C
250 lines
6.4 KiB
C
|
/*
|
||
|
* 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 <debug.h>
|
||
|
#include <string.h>
|
||
|
#include <malloc.h>
|
||
|
#include <app.h>
|
||
|
#include <platform.h>
|
||
|
#include <kernel/thread.h>
|
||
|
|
||
|
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 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 <lib/console.h>
|
||
|
|
||
|
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 <routine>\n", argv[0].str);
|
||
|
printf("%s bench <routine>\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[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
|
||
|
|