diff options
Diffstat (limited to 'src/tests/multistresstest.cpp')
| -rw-r--r-- | src/tests/multistresstest.cpp | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/src/tests/multistresstest.cpp b/src/tests/multistresstest.cpp new file mode 100644 index 00000000..234783b3 --- /dev/null +++ b/src/tests/multistresstest.cpp @@ -0,0 +1,488 @@ +/****************************************************************************** + * + * Project: PROJ.4 + * Purpose: Mainline program to stress test multithreaded PROJ.4 processing. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2010, Frank Warmerdam + * + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H +#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H +#endif + +#include "proj_api.h" + +#ifdef _WIN32 + #include <windows.h> +#else + #include <pthread.h> + #include <unistd.h> +#endif + +#define num_threads 10 +static int num_iterations = 1000000; +static int reinit_every_iteration=0; +static int add_no_defs = 0; + +typedef struct { + const char *src_def; + const char *dst_def; + + double src_x, src_y, src_z; + double dst_x, dst_y, dst_z; + + int dst_error; + int skip; +} TestItem; + +static TestItem test_list[] = { + { + "+proj=utm +zone=11 +datum=WGS84", + "+proj=latlong +datum=WGS84", + 150000.0, 3000000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=utm +zone=11 +datum=NAD83", + "+proj=latlong +datum=NAD27", + 150000.0, 3000000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=utm +zone=11 +datum=NAD83", + "+proj=latlong +nadgrids=@null +ellps=WGS84", + 150000.0, 3000000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=utm +zone=11 +datum=WGS84", + "+proj=merc +datum=potsdam", + 150000.0, 3000000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=latlong +nadgrids=nzgd2kgrid0005.gsb", + "+proj=latlong +datum=WGS84", + 150000.0, 3000000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=latlong +nadgrids=nzgd2kgrid0005.gsb", + "+proj=latlong +datum=WGS84", + 170 * DEG_TO_RAD, -40 * DEG_TO_RAD, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=latlong +ellps=GRS80 +towgs84=2,3,5", + "+proj=latlong +ellps=intl +towgs84=10,12,15", + 170 * DEG_TO_RAD, -40 * DEG_TO_RAD, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=eqc +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", + "+proj=stere +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", + 150000.0, 250000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=cea +lat_ts=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", + "+proj=merc +lon_0=12 +k=0.999 +x_0=100000 +y_0=200000 +datum=WGS84 ", + 150000.0, 250000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=bonne +lat_1=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", + "+proj=cass +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", + 150000.0, 250000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=nzmg +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", + "+proj=gnom +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", + 150000.0, 250000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=ortho +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", + "+proj=laea +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", + 150000.0, 250000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=aeqd +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", + "+proj=eqdc +lat_1=20 +lat_2=5 +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", + 150000.0, 250000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+proj=mill +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", + "+proj=moll +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", + 150000.0, 250000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + "+init=epsg:3309", + "+init=epsg:4326", + 150000.0, 30000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + }, + { + /* Bad projection (invalid ellipsoid parameter +R_A=0) */ + "+proj=utm +zone=11 +datum=WGS84", + "+proj=merc +datum=potsdam +R_A=0", + 150000.0, 3000000.0, 0.0, + 0.0, 0.0, 0.0, + 0, 0 + } +}; + +static volatile int active_thread_count = 0; + +static projPJ custom_pj_init_plus_ctx(projCtx ctx, const char* def) +{ + if( add_no_defs ) + { + char szBuffer[256]; + strcpy(szBuffer, def); + strcat(szBuffer, " +no_defs"); + return pj_init_plus_ctx(ctx, szBuffer); + } + else + return pj_init_plus_ctx(ctx, def); +} + +/************************************************************************/ +/* TestThread() */ +/************************************************************************/ + +static void TestThread() + +{ + int i, test_count = sizeof(test_list) / sizeof(TestItem); + int repeat_count = num_iterations; + int i_iter; + +/* -------------------------------------------------------------------- */ +/* Initialize coordinate system definitions. */ +/* -------------------------------------------------------------------- */ + projPJ *src_pj_list, *dst_pj_list; + projCtx ctx = pj_ctx_alloc(); + + src_pj_list = (projPJ *) calloc(test_count,sizeof(projPJ)); + dst_pj_list = (projPJ *) calloc(test_count,sizeof(projPJ)); + + if(!reinit_every_iteration) + { + for( i = 0; i < test_count; i++ ) + { + TestItem *test = test_list + i; + + src_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->src_def ); + dst_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->dst_def ); + } + } + +/* -------------------------------------------------------------------- */ +/* Perform tests - over and over. */ +/* -------------------------------------------------------------------- */ + + for( i_iter = 0; i_iter < repeat_count; i_iter++ ) + { + for( i = 0; i < test_count; i++ ) + { + TestItem *test = test_list + i; + double x, y, z; + int error; + + x = test->src_x; + y = test->src_y; + z = test->src_z; + + if( reinit_every_iteration ) + { + src_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->src_def ); + dst_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->dst_def ); + + { + int skipTest = (src_pj_list[i] == nullptr || dst_pj_list[i] == nullptr); + + if ( skipTest != test->skip ) + fprintf( stderr, "Threaded projection initialization does not match unthreaded initialization\n" ); + + if (skipTest) + { + pj_free( src_pj_list[i] ); + pj_free( dst_pj_list[i] ); + continue; + } + } + } + + if ( test->skip ) + continue; + + error = pj_transform( src_pj_list[i], dst_pj_list[i], 1, 0, + &x, &y, &z ); + + + if( error != test->dst_error ) + { + fprintf( stderr, "Got error %d, expected %d\n", + error, test->dst_error ); + } + + if( x != test->dst_x || y != test->dst_y || z != test->dst_z ) + { + fprintf( stderr, + "Got %.15g,%.15g,%.15g\n" + "Expected %.15g,%.15g,%.15g\n" + "Diff %.15g,%.15g,%.15g\n", + x, y, z, + test->dst_x, test->dst_y, test->dst_z, + x-test->dst_x, y-test->dst_y, z-test->dst_z); + } + + if( reinit_every_iteration ) + { + pj_free( src_pj_list[i] ); + pj_free( dst_pj_list[i] ); + } + } + } + +/* -------------------------------------------------------------------- */ +/* Cleanup */ +/* -------------------------------------------------------------------- */ + if( !reinit_every_iteration ) + { + for( i = 0; i < test_count; i++ ) + { + pj_free( src_pj_list[i] ); + pj_free( dst_pj_list[i] ); + } + } + + free( src_pj_list ); + free( dst_pj_list ); + + pj_ctx_free( ctx ); + + printf( "%d iterations of the %d tests complete in thread X\n", + repeat_count, test_count ); + + active_thread_count--; +} + +#ifdef _WIN32 +/************************************************************************/ +/* WinTestThread() */ +/************************************************************************/ + +static DWORD WINAPI WinTestThread( LPVOID lpParameter ) + +{ + TestThread(); + + return 0; +} + +#else +/************************************************************************/ +/* PosixTestThread() */ +/************************************************************************/ + +static void *PosixTestThread( void *pData ) + +{ + (void)pData; + TestThread(); + return nullptr; +} +#endif + +/************************************************************************/ +/* main() */ +/************************************************************************/ +#ifdef _WIN32 +static DWORD WINAPI do_main( LPVOID unused ) +#else +static int do_main(void) +#endif +{ +/* -------------------------------------------------------------------- */ +/* Our first pass is to establish the correct answers for all */ +/* the tests. */ +/* -------------------------------------------------------------------- */ + int i, test_count = sizeof(test_list) / sizeof(TestItem); + + for( i = 0; i < test_count; i++ ) + { + TestItem *test = test_list + i; + + projPJ src_pj, dst_pj; + + src_pj = custom_pj_init_plus_ctx( pj_get_default_ctx(), test->src_def ); + dst_pj = custom_pj_init_plus_ctx( pj_get_default_ctx(), test->dst_def ); + + if( src_pj == nullptr ) + { + printf( "Unable to translate:\n%s\n", test->src_def ); + test->skip = 1; + pj_free (dst_pj); + continue; + } + + if( dst_pj == nullptr ) + { + printf( "Unable to translate:\n%s\n", test->dst_def ); + test->skip = 1; + pj_free (src_pj); + continue; + } + + test->dst_x = test->src_x; + test->dst_y = test->src_y; + test->dst_z = test->src_z; + + test->dst_error = pj_transform( src_pj, dst_pj, 1, 0, + &(test->dst_x), + &(test->dst_y), + &(test->dst_z) ); + + pj_free( src_pj ); + pj_free( dst_pj ); + + test->skip = 0; + +#ifdef notdef + printf( "Test %d - output %.14g,%.14g,%g\n", i, test->dst_x, test->dst_y, test->dst_z ); +#endif + } + + printf( "%d tests initialized.\n", test_count ); + +/* -------------------------------------------------------------------- */ +/* Now launch a bunch of threads to repeat the tests. */ +/* -------------------------------------------------------------------- */ +#ifdef _WIN32 + + { //Scoped to workaround lack of c99 support in VS + HANDLE ahThread[num_threads]; + + for( i = 0; i < num_threads; i++ ) + { + active_thread_count++; + + ahThread[i] = CreateThread(NULL, 0, WinTestThread, NULL, 0, NULL); + + if (ahThread[i] == 0) + { + printf( "Thread creation failed."); + return 1; + } + } + + printf( "%d test threads launched.\n", num_threads ); + + WaitForMultipleObjects(num_threads, ahThread, TRUE, INFINITE); + } + +#else + { + pthread_t ahThread[num_threads]; + pthread_attr_t hThreadAttr; + + pthread_attr_init( &hThreadAttr ); + pthread_attr_setdetachstate( &hThreadAttr, PTHREAD_CREATE_DETACHED ); + + for( i = 0; i < num_threads; i++ ) + { + active_thread_count++; + + pthread_create( &(ahThread[i]), &hThreadAttr, + PosixTestThread, nullptr ); + } + + printf( "%d test threads launched.\n", num_threads ); + + while( active_thread_count > 0 ) + sleep( 1 ); + } +#endif + + printf( "all tests complete.\n" ); + + return 0; +} + + +int main( int argc, char **argv ) +{ + int i; + for(i=0;i<argc;i++) + { + if( strcmp(argv[i], "-reinit") == 0 ) + reinit_every_iteration = 1; + else if( strcmp(argv[i], "-add_no_defs") == 0 ) + add_no_defs = 1; + else if( strcmp(argv[i], "-num_iterations") == 0 && i+1 < argc ) + { + num_iterations = atoi(argv[i+1]); + i++; + } + } + +#ifdef _WIN32 + /* This is an incredible weirdness but with mingw cross-compiler */ + /* 1. - b/a; where double a = 6378206.4; and double b = 6356583.8; */ + /* does not evaluate the same in the main thread or in a thread forked */ + /* by CreateThread(), so run the main in a thread... */ + { + HANDLE thread = CreateThread(NULL, 0, do_main, NULL, 0, NULL); + WaitForSingleObject(thread, INFINITE); + CloseHandle( thread ); + } +#else + do_main(); +#endif + return 0; +} |
