/****************************************************************************** * * 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 #include #include #include "proj.h" #ifdef _WIN32 #include #else #include #include #endif #define num_threads 10 static int num_iterations = 1000000; static int reinit_every_iteration=0; typedef struct { const char *src_def; const char *dst_def; PJ_COORD src; PJ_COORD dst; int dst_error; int skip; } TestItem; static TestItem test_list[] = { { "+proj=utm +zone=11 +datum=WGS84", "+proj=latlong +datum=WGS84", proj_coord(150000.0, 3000000.0, 0.0, 0), proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=utm +zone=11 +datum=NAD83", "+proj=latlong +datum=NAD27", proj_coord(150000.0, 3000000.0, 0.0, 0.0), proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=utm +zone=11 +datum=NAD83", "+proj=latlong +nadgrids=@null +ellps=WGS84", proj_coord(150000.0, 3000000.0, 0.0, 0.0), proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=utm +zone=11 +datum=WGS84", "+proj=merc +datum=potsdam", proj_coord(150000.0, 3000000.0, 0.0, 0.0), proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=latlong +nadgrids=nzgd2kgrid0005.gsb", "+proj=latlong +datum=WGS84", proj_coord(150000.0, 3000000.0, 0.0, 0.0), proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=latlong +nadgrids=nzgd2kgrid0005.gsb", "+proj=latlong +datum=WGS84", proj_coord(170, -40, 0.0, 0.0), proj_coord(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", proj_coord(170, -40, 0.0, 0.0), proj_coord(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 ", proj_coord(150000.0, 250000.0, 0.0, 0.0), proj_coord(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 ", proj_coord(150000.0, 250000.0, 0.0, 0.0), proj_coord(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 ", proj_coord(150000.0, 250000.0, 0.0, 0.0), proj_coord(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 ", proj_coord(150000.0, 250000.0, 0.0, 0.0), proj_coord(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 ", proj_coord(150000.0, 250000.0, 0.0, 0.0), proj_coord(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 ", proj_coord(150000.0, 250000.0, 0.0, 0.0), proj_coord(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 ", proj_coord(150000.0, 250000.0, 0.0, 0.0), proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+init=epsg:3309", "+init=epsg:4326", proj_coord(150000.0, 30000.0, 0.0, 0.0), proj_coord(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", proj_coord(150000.0, 3000000.0, 0.0, 0.0), proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 } }; static volatile int active_thread_count = 0; /************************************************************************/ /* 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. */ /* -------------------------------------------------------------------- */ PJ **pj_list; PJ_CONTEXT *ctx = proj_context_create(); pj_list = (PJ **) calloc(test_count,sizeof(PJ*)); if(!reinit_every_iteration) { for( i = 0; i < test_count; i++ ) { TestItem *test = test_list + i; pj_list[i] = proj_create_crs_to_crs( ctx, test->src_def, test->dst_def, nullptr ); } } /* -------------------------------------------------------------------- */ /* 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; if( reinit_every_iteration ) { proj_context_use_proj4_init_rules(nullptr, true); pj_list[i] = proj_create_crs_to_crs( ctx, test->src_def, test->dst_def, nullptr ); { int skipTest = (pj_list[i] == nullptr); if ( skipTest != test->skip ) fprintf( stderr, "Threaded projection initialization does not match unthreaded initialization\n" ); if (skipTest) { proj_destroy( pj_list[i] ); continue; } } } if ( test->skip ) continue; PJ_COORD out = proj_trans(pj_list[i], PJ_FWD, test->src); int error = proj_errno(pj_list[i]); if( error != test->dst_error ) { fprintf( stderr, "Got error %d, expected %d\n", error, test->dst_error ); } proj_errno_reset(pj_list[i]); if ( out.xyz.x != test->dst.xyz.x || out.xyz.y != test->dst.xyz.y || out.xyz.z != test->dst.xyz.z) //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", out.xyz.x, out.xyz.y, out.xyz.z, test->dst.xyz.x, test->dst.xyz.y, test->dst.xyz.z, out.xyz.x-test->dst.xyz.x, out.xyz.y-test->dst.xyz.y, out.xyz.z-test->dst.xyz.z); } if( reinit_every_iteration ) { proj_destroy( pj_list[i] ); } } } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ if( !reinit_every_iteration ) { for( i = 0; i < test_count; i++ ) { proj_destroy( pj_list[i] ); } } free( pj_list ); proj_context_destroy( 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; PJ *pj; proj_context_use_proj4_init_rules(nullptr, true); pj = proj_create_crs_to_crs( nullptr, test->src_def, test->dst_def, nullptr ); if( pj == nullptr ) { printf( "Unable to translate:\n%s\n or\n%s\n", test->src_def, test->dst_def ); test->skip = 1; proj_destroy(pj); continue; } PJ_COORD out = proj_trans(pj, PJ_FWD, test->src); test->dst = out; test->dst_error = proj_errno(pj); proj_destroy(pj); test->skip = 0; #ifdef nodef printf( "Test %d - output %.14g,%.14g,%g\n", i, test->dst.xyz.x, test->dst.xyz.y, test->dst.xyz.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