Mercurial > ecos-v2_0-branch
changeset 552:fddb77989fbb
* cdl/kernel.cdl:
* tests/fptest.c: Added this program to test interaction of FPU
with multiple threads.
| author | nickg |
|---|---|
| date | Fri, 31 Jan 2003 11:44:02 +0000 |
| parents | 4ecc6abc8be2 |
| children | 489b846deeff |
| files | packages/kernel/current/ChangeLog packages/kernel/current/cdl/kernel.cdl packages/kernel/current/tests/fptest.c |
| diffstat | 3 files changed, 330 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/kernel/current/ChangeLog +++ b/packages/kernel/current/ChangeLog @@ -1,3 +1,9 @@ +2003-01-31 Nick Garnett <nickg@calivar.com> + + * cdl/kernel.cdl: + * tests/fptest.c: Added this program to test interaction of FPU + with multiple threads. + 2003-01-30 Jonathan Larmour <jifl@eCosCentric.com> * src/common/thread.cxx: Fix potential warning and overflow with
--- a/packages/kernel/current/cdl/kernel.cdl +++ b/packages/kernel/current/cdl/kernel.cdl @@ -326,7 +326,7 @@ cdl_package CYGPKG_KERNEL { no_define calculated { "tests/bin_sem0 tests/bin_sem1 tests/bin_sem2 tests/clock0 tests/clock1 tests/clockcnv tests/clocktruth tests/cnt_sem0 tests/cnt_sem1 tests/except1 tests/flag0 tests/flag1 tests/intr0 tests/kill tests/mbox1 tests/mqueue1 tests/mutex0 tests/mutex1 tests/mutex2 tests/mutex3 tests/release tests/sched1 tests/sync2 tests/sync3 tests/thread0 tests/thread1 tests/thread2" - . ((CYGFUN_KERNEL_API_C) ? " tests/kclock0 tests/kclock1 tests/kexcept1 tests/kflag0 tests/kflag1 tests/kintr0 tests/klock tests/kmbox1 tests/kmutex0 tests/kmutex1 tests/kmutex3 tests/kmutex4 tests/ksched1 tests/ksem0 tests/ksem1 tests/kthread0 tests/kthread1 tests/stress_threads tests/thread_gdb tests/timeslice tests/tm_basic" : "") + . ((CYGFUN_KERNEL_API_C) ? " tests/kclock0 tests/kclock1 tests/kexcept1 tests/kflag0 tests/kflag1 tests/kintr0 tests/klock tests/kmbox1 tests/kmutex0 tests/kmutex1 tests/kmutex3 tests/kmutex4 tests/ksched1 tests/ksem0 tests/ksem1 tests/kthread0 tests/kthread1 tests/stress_threads tests/thread_gdb tests/timeslice tests/tm_basic tests/fptest" : "") . ((!CYGPKG_INFRA_DEBUG && !CYGPKG_KERNEL_INSTRUMENT && CYGFUN_KERNEL_API_C) ? " tests/dhrystone" : "") . ((CYGPKG_KERNEL_SMP_SUPPORT && CYGFUN_KERNEL_API_C) ? " tests/smp" : "") . ((!CYGINT_HAL_TESTS_NO_CACHES && CYGFUN_KERNEL_API_C) ? " tests/kcache1 tests/kcache2" : "")
new file mode 100644 --- /dev/null +++ b/packages/kernel/current/tests/fptest.c @@ -0,0 +1,323 @@ +//========================================================================== +// +// fptest.cxx +// +// Basic FPU test +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2003 Nick Garnett +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg@calivar.com +// Contributors: nickg@calivar.com +// Date: 2003-01-27 +// Description: Simple FPU test. This is not very sophisticated as far +// as checking FPU performance or accuracy. It is more +// concerned with checking that several threads doing FP +// operations do not interfere with eachother's use of the +// FPU. +// +//####DESCRIPTIONEND#### +//========================================================================== + +#include <pkgconf/kernel.h> +#include <pkgconf/hal.h> + +#include <cyg/hal/hal_arch.h> + +#include <cyg/kernel/kapi.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> + +//#include <cyg/kernel/test/stackmon.h> +//#include CYGHWR_MEMORY_LAYOUT_H + +//========================================================================== + +#if defined(CYGFUN_KERNEL_API_C) && \ + defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ + (CYGNUM_KERNEL_SCHED_PRIORITIES > 12) + +//========================================================================== +// Multiplier for loop counter. This allows us to tune the runtime of +// the whole program easily. The current value gives a runtime of +// about 90s on an 800Mz Pentium III. + +#define MULTIPLIER 100 + +//========================================================================== +// Thread parameters + +#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM+4096) + +cyg_uint8 stacks[3][STACK_SIZE]; +cyg_handle_t thread[3]; +cyg_thread thread_struct[3]; + +//========================================================================== +// Random number generator. Ripped out of the C library. + +static int rand( unsigned int *seed ) +{ +// This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom + +#define RAND_MAX 0x7fffffff +#define MM 2147483647 // a Mersenne prime +#define AA 48271 // this does well in the spectral test +#define QQ 44488 // (long)(MM/AA) +#define RR 3399 // MM % AA; it is important that RR<QQ + + *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ); + if (*seed < 0) + *seed += MM; + + return (int)( *seed & RAND_MAX ); +} + +//========================================================================== +// Test calculation. +// +// Generates an array of random FP values and then repeatedly applies +// a calculation to them and checks that the same result is reached +// each time. The calculation, in the macro CALC, is intended to make +// maximum use of the FPU registers. However, the i386 compiler +// doesn't let this expression get very complex before it starts +// spilling values out to memory. + +static void do_test( double *values, + int count, + int loops, + char *name) +{ + int i, j; + double sum = 1.0; + double last_sum; + unsigned int seed; + +#define V(__i) (values[(__i)%count]) +#define CALC ((V(i-1)*V(i+1))*(V(i-2)*V(i+2))*(V(i-3)*sum)) + + seed = ((unsigned int)&i)*loops*count; + + // Set up an array of values... + for( i = 0; i < count; i++ ) + values[i] = (double)rand( &seed )/(double)0x7fffffff; + + // Now calculate something from them... + for( i = 0; i < count; i++ ) + sum += CALC; + last_sum = sum; + + // Now recalculate the sum in a loop and look for errors + for( j = 0; j < loops; j++ ) + { + sum = 1.0; + for( i = 0; i < count; i++ ) + sum += CALC; + + if( sum != last_sum ) + diag_printf("%s: Sum mismatch! %d\n",name,j); + + last_sum = sum; + } + +} + +//========================================================================== + +volatile int done[4]; + +volatile cyg_tick_count_t start, end; + +//========================================================================== + +#define FP1_COUNT 1000 +#define FP1_LOOPS 1000*MULTIPLIER + +static double fpt1_values[FP1_COUNT]; + +void fptest1( CYG_ADDRWORD id ) +{ + diag_printf("fptest1: start\n"); + + do_test( &fpt1_values, FP1_COUNT, FP1_LOOPS, "fptest1" ); + + done[id] = 1; + + diag_printf("fptest1: done\n"); +} + +//========================================================================== + +#define FP2_COUNT 10000 +#define FP2_LOOPS 100*MULTIPLIER + +static double fpt2_values[FP2_COUNT]; + +void fptest2( CYG_ADDRWORD id ) +{ + diag_printf("fptest2: start\n"); + + do_test( &fpt2_values, FP2_COUNT, FP2_LOOPS, "fptest2" ); + + done[id] = 1; + + diag_printf("fptest2: done\n"); +} + +//========================================================================== + +#define FP3_COUNT 10000 +#define FP3_LOOPS 100*MULTIPLIER + +static double fpt3_values[FP3_COUNT]; + +void fptest3( CYG_ADDRWORD id ) +{ + int all_done; + + diag_printf("fptest3: start\n"); + + do_test( &fpt3_values, FP3_COUNT, FP3_LOOPS, "fptest3" ); + + done[id] = 1; + + diag_printf("fptest3: done\n"); + + // Spin here waiting for the other threads to finish. We should + // only wake up and test every third or second timeslice. + do { + int i; + + cyg_thread_yield(); + + all_done = 0; + for( i = 0; i < 4; i++ ) + all_done += done[i]; + + } while(all_done != 4 ); + + end = cyg_current_time(); + + diag_printf("Elapsed time %d ticks\n",end-start); + + CYG_TEST_PASS_FINISH("FP Test OK"); + +} + +//========================================================================== + +void fptest_main( void ) +{ + + CYG_TEST_INIT(); + + start = cyg_current_time(); + + diag_printf("Run fptest1 in cyg_start\n"); + fptest1( 0 ); + + cyg_thread_create( 5, + fptest1, + 1, + "fptest1", + &stacks[0][0], + STACK_SIZE, + &thread[0], + &thread_struct[0]); + + cyg_thread_resume( thread[0] ); + + cyg_thread_create( 5, + fptest2, + 2, + "fptest2", + &stacks[1][0], + STACK_SIZE, + &thread[1], + &thread_struct[1]); + + cyg_thread_resume( thread[1] ); + + cyg_thread_create( 5, + fptest3, + 3, + "fptest3", + &stacks[2][0], + STACK_SIZE, + &thread[2], + &thread_struct[2]); + + cyg_thread_resume( thread[2] ); + + cyg_scheduler_start(); + +} + +//========================================================================== + +#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG +externC void +cyg_hal_invoke_constructors(); +#endif + +externC void +cyg_start( void ) +{ +#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG + cyg_hal_invoke_constructors(); +#endif + fptest_main(); +} + +//========================================================================== + +#else // CYGFUN_KERNEL_API_C... + +externC void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA("FP test requires:\n" + "CYGFUN_KERNEL_API_C && \n" + "CYGSEM_KERNEL_SCHED_MLQUEUE && \n" + "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n"); +} + +#endif // CYGFUN_KERNEL_API_C, etc. + +//========================================================================== +// EOF fptest.cxx
