diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/testsuite/test-acmemcpy.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/testsuite/test-acmemcpy.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/testsuite/test-acmemcpy.c b/debian/transcode/transcode-1.1.7/testsuite/test-acmemcpy.c new file mode 100644 index 00000000..8d3eede2 --- /dev/null +++ b/debian/transcode/transcode-1.1.7/testsuite/test-acmemcpy.c @@ -0,0 +1,271 @@ +/*compile-command +set -x +gcc -O3 -g -I. -I.. "$0" -DARCH_X86 +exit $? +*/ + +/* + * test-acmemcpy.c - test accelerated memcpy() implementations to check + * that they work with all alignments and sizes + * Written by Andrew Church <achurch@achurch.org> + * + * This file is part of transcode, a video stream processing tool. + * transcode is free software, distributable under the terms of the GNU + * General Public License (version 2 or later). See the file COPYING + * for details. + */ + +#define _GNU_SOURCE /* for strsignal */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include "config.h" + +#define ac_memcpy local_ac_memcpy /* to avoid clash with libac.a */ +#define ac_memcpy_init local_ac_memcpy_init /* to avoid clash with libac.a */ +#include "aclib/ac.h" + +/* Include memcpy.c directly to get access to the particular implementations */ +#include "../aclib/memcpy.c" +#undef ac_memcpy +/* Make sure all names are available, to simplify function table */ +#if !defined(ARCH_X86) || !defined(HAVE_ASM_MMX) +# define memcpy_mmx memcpy +#endif +#if !defined(ARCH_X86) || !defined(HAVE_ASM_SSE) +# define memcpy_sse memcpy +#endif +#if !defined(ARCH_X86_64) || !defined(HAVE_ASM_SSE2) +# define memcpy_amd64 memcpy +#endif + +/* Constant `spill' value for tests */ +static const int SPILL = 8; + +/*************************************************************************/ + +static void *old_SIGSEGV = NULL, *old_SIGILL = NULL; +static sigjmp_buf env; + + +static void sighandler(int sig) +{ + printf("*** %s\n", strsignal(sig)); + siglongjmp(env, 1); +} + +static void set_signals(void) +{ + old_SIGSEGV = signal(SIGSEGV, sighandler); + old_SIGILL = signal(SIGILL , sighandler); +} + +static void clear_signals(void) +{ + signal(SIGSEGV, old_SIGSEGV); + signal(SIGILL , old_SIGILL ); +} + +/*************************************************************************/ + +/* Test the given function with the given data size. Print error + * information if verbose is nonzero. Performs tests on all alignments + * from 0 through block-1, and checks that `spill' bytes on either side of + * the target region are not affected. `block' is assumed to be a power + * of 2. */ + +static int testit(void *(*func)(void *, const void *, size_t), + int size, int block, int spill, int verbose) +{ + char *chunk1, *chunk1_base, *chunk1_copy; + char *chunk2, *chunk2_base, *chunk2_test; + int align1, align2, result; + + chunk1_base = malloc(size + block-1); + chunk1_copy = malloc(size + block-1); + chunk2_base = malloc(size + block-1 + spill*2); + chunk2_test = malloc(size + spill*2); + memset(chunk1_base, 0x11, size + block-1); + memset(chunk1_copy, 0x11, size + block-1); + memset(chunk2_test, 0x22, size + spill*2); + memset(chunk2_test + spill, 0x11, size); + + result = 1; + for (align1 = 0; align1 < block-1; align1++) { + for (align2 = 0; align2 < block-1; align2++) { + chunk1 = chunk1_base + align1; + chunk2 = chunk2_base + spill + align2; + memset(chunk2-spill, 0x22, size+spill*2); + set_signals(); + if (sigsetjmp(env, 1)) { + result = 0; + } else { + (*func)(chunk2, chunk1, size); + result = (memcmp(chunk2-spill, chunk2_test, size+spill*2) == 0 + && memcmp(chunk1_base, chunk1_copy, size+block-1)==0); + } + clear_signals(); + if (!result) { + if (verbose) { + printf("FAILED: size=%d align1=%d align2=%d\n", + size, align1, align2); + } + /* Just in case */ + memset(chunk1_base, 0x11, size+block-1); + } + } + } + + free(chunk1_base); + free(chunk1_copy); + free(chunk2_base); + free(chunk2_test); + return result; +} + +/*************************************************************************/ + +/* Turn presence/absence of #define into a number */ +#if defined(ARCH_X86) +# define defined_ARCH_X86 1 +#else +# define defined_ARCH_X86 0 +#endif +#if defined(ARCH_X86_64) +# define defined_ARCH_X86_64 1 +#else +# define defined_ARCH_X86_64 0 +#endif +#if defined(HAVE_ASM_MMX) +# define defined_HAVE_ASM_MMX 1 +#else +# define defined_HAVE_ASM_MMX 0 +#endif +#if defined(HAVE_ASM_SSE) +# define defined_HAVE_ASM_SSE 1 +#else +# define defined_HAVE_ASM_SSE 0 +#endif +#if defined(HAVE_ASM_SSE2) +# define defined_HAVE_ASM_SSE2 1 +#else +# define defined_HAVE_ASM_SSE2 0 +#endif + +/* List of routines to test, NULL-terminated */ +static struct { + const char *name; + int arch_ok; /* defined(ARCH_xxx), etc. */ + int acflags; /* required ac_cpuinfo() flags */ + void *(*func)(void *, const void *, size_t); +} testfuncs[] = { + { "mmx", defined_ARCH_X86 && defined_HAVE_ASM_MMX, + AC_MMX, memcpy_mmx }, + { "sse", defined_ARCH_X86 && defined_HAVE_ASM_SSE, + AC_CMOVE|AC_SSE, memcpy_sse }, + { "amd64", defined_ARCH_X86_64 && defined_HAVE_ASM_SSE2, + AC_CMOVE|AC_SSE2, memcpy_amd64 }, + { NULL } +}; + +/* List of sizes to test, min==0 terminated */ +static struct { + const char *name; /* Function to limit this test to, or NULL for all */ + int min, max; /* Size range (inclusive) */ + int block; /* Block alignment */ +} testvals[] = { + /* Test all small block sizes, with alignments 0..7 (for amd64's movq) */ + {NULL, 1, 63, 8}, + /* Test up to 2 medium blocks plus small sizes (MMX=64, SSE=8, SSE2=16) */ + {"mmx", 64, 191, 64}, + {"sse", 64, 71, 64}, + {"amd64", 64, 79, 64}, + /* Test large block size plus up to 2 cache lines minus 1 */ + {"sse", 0x10040, 0x100BF, 64}, + {"amd64", 0x38000, 0x3807F, 64}, + /* End of list */ + {NULL,0,0} +}; + +int main(int argc, char *argv[]) +{ + int verbose = 1; + int ch, i, failed; + + while ((ch = getopt(argc, argv, "hqv")) != EOF) { + if (ch == 'q') { + verbose = 0; + } else if (ch == 'v') { + verbose = 2; + } else { + fprintf(stderr, + "Usage: %s [-q | -v]\n" + "-q: quiet (don't print test names)\n" + "-v: verbose (print each block size as processed)\n", + argv[0]); + return 1; + } + } + + failed = 0; + for (i = 0; testfuncs[i].name; i++) { + int j; + int thisfailed = 0; + if (verbose > 0) { + printf("%s: ", testfuncs[i].name); + fflush(stdout); + } + if (!testfuncs[i].arch_ok) { + printf("WARNING: unable to test (wrong architecture or not" + " compiled in)\n"); + continue; + } + if ((ac_cpuinfo() & testfuncs[i].acflags) != testfuncs[i].acflags) { + printf("WARNING: unable to test (no support in CPU)\n"); + continue; + } + for (j = 0; testvals[j].min > 0; j++) { + int size; + if (testvals[j].name + && strcmp(testvals[j].name, testfuncs[i].name) != 0) + continue; + for (size = testvals[j].min; size <= testvals[j].max; size++) { + if (verbose >= 2) { + printf("%-10d\b\b\b\b\b\b\b\b\b\b", size); + fflush(stdout); + } + if (!testit(testfuncs[i].func, size, testvals[j].block, + SPILL, verbose)) + thisfailed = 1; + } /* for each size */ + } /* for each size range */ + if (thisfailed) { + /* FAILED message printed by testit() */ + failed = 1; + } else { + if (verbose > 0) + printf("ok\n"); + } + } /* for each function */ + + return failed ? 1 : 0; +} + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ |
