| /* |
| Copyright 2005-2010 Intel Corporation. All Rights Reserved. |
| |
| This file is part of Threading Building Blocks. |
| |
| Threading Building Blocks is free software; you can redistribute it |
| and/or modify it under the terms of the GNU General Public License |
| version 2 as published by the Free Software Foundation. |
| |
| Threading Building Blocks 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 Threading Building Blocks; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| |
| As a special exception, you may use this file as part of a free software |
| library without restriction. Specifically, if other files instantiate |
| templates or use macros or inline functions from this file, or you compile |
| this file and link it with other files to produce an executable, this |
| file does not by itself cause the resulting executable to be covered by |
| the GNU General Public License. This exception does not however |
| invalidate any other reasons why the executable file might be covered by |
| the GNU General Public License. |
| */ |
| |
| #include "rml_omp.h" |
| #define HARNESS_DEFAULT_MIN_THREADS 0 |
| #include "test_server.h" |
| #include "tbb/tbb_misc.h" |
| |
| typedef __kmp::rml::omp_server MyServer; |
| typedef __kmp::rml::omp_factory MyFactory; |
| |
| static bool StrictTeam; |
| |
| class MyTeam { |
| MyTeam& operator=( const MyTeam& ) ; |
| public: |
| struct info_type { |
| rml::job* job; |
| bool ran; |
| info_type() : job(NULL), ran(false) {} |
| }; |
| MyTeam( MyServer& /* server */, size_t max_thread_ ) : |
| max_thread(max_thread_) |
| { |
| self_ptr = this; |
| info = new info_type[max_thread]; |
| } |
| ~MyTeam() { |
| delete[] info; |
| } |
| const size_t max_thread; |
| size_t n_thread; |
| tbb::atomic<int> barrier; |
| /** Indexed with 1-origin index */ |
| info_type* info; |
| int iteration; |
| MyTeam* self_ptr; |
| }; |
| |
| class MyClient: public ClientBase<__kmp::rml::omp_client> { |
| public: |
| MyServer* server; |
| /*override*/void process( job& j, void* cookie, size_type index ) { |
| MyTeam& t = *static_cast<MyTeam*>(cookie); |
| ASSERT( t.self_ptr==&t, "trashed cookie" ); |
| ASSERT( index<t.max_thread, NULL ); |
| ASSERT( !t.info[index].ran, "duplicate index?" ); |
| t.info[index].job = &j; |
| t.info[index].ran = true; |
| do_process(j); |
| if( index==1 && nesting.level<nesting.limit ) { |
| DoOneConnection<MyFactory,MyClient> doc(MaxThread,Nesting(nesting.level+1,nesting.limit),0,false); |
| doc(0); |
| } |
| #if _WIN32||_WIN64 |
| // test activate/deactivate |
| if( t.n_thread>1 && t.n_thread%2==0 ) { |
| if( nesting.level==0 ) { |
| if( index&1 ) { |
| size_type target = index-1; |
| ASSERT( target<t.max_thread, NULL ); |
| // wait until t.info[target].job is defined |
| tbb::internal::spin_wait_until_eq( t.info[target].ran, true ); |
| server->try_increase_load( 1, true ); |
| server->reactivate( t.info[target].job ); |
| } else { |
| server->deactivate( &j ); |
| } |
| } |
| } |
| #endif /* _WIN32||_WIN64 */ |
| ++t.barrier; |
| } |
| static const bool is_omp = true; |
| bool is_strict() const {return StrictTeam;} |
| }; |
| |
| void FireUpJobs( MyServer& server, MyClient& client, int max_thread, int n_extra, Checker* checker ) { |
| ASSERT( max_thread>=0, NULL ); |
| #if _WIN32||_WIN64 |
| ::rml::server::execution_resource_t me; |
| server.register_master( me ); |
| #endif /* _WIN32||_WIN64 */ |
| client.server = &server; |
| MyTeam team(server,size_t(max_thread)); |
| MyServer::size_type n_thread = 0; |
| for( int iteration=0; iteration<4; ++iteration ) { |
| for( size_t i=0; i<team.max_thread; ++i ) |
| team.info[i].ran = false; |
| switch( iteration ) { |
| default: |
| n_thread = int(max_thread); |
| break; |
| case 1: |
| // No change in number of threads |
| break; |
| case 2: |
| // Decrease number of threads. |
| n_thread = int(max_thread)/2; |
| break; |
| // Case 3 is same code as the default, but has effect of increasing the number of threads. |
| } |
| team.barrier = 0; |
| REMARK("client %d: server.run with n_thread=%d\n", client.client_id(), int(n_thread) ); |
| server.independent_thread_number_changed( n_extra ); |
| if( checker ) { |
| // Give RML time to respond to change in number of threads. |
| MilliSleep(1); |
| } |
| int n_delivered = server.try_increase_load( n_thread, StrictTeam ); |
| ASSERT( !StrictTeam || n_delivered==int(n_thread), "server failed to satisfy strict request" ); |
| if( n_delivered<0 ) { |
| REMARK( "client %d: oversubscription occurred (by %d)\n", client.client_id(), -n_delivered ); |
| server.independent_thread_number_changed( -n_extra ); |
| n_delivered = 0; |
| } else { |
| team.n_thread = n_delivered; |
| ::rml::job* job_array[JobArraySize]; |
| job_array[n_delivered] = (::rml::job*)intptr_t(-1); |
| server.get_threads( n_delivered, &team, job_array ); |
| __TBB_ASSERT( job_array[n_delivered]== (::rml::job*)intptr_t(-1), NULL ); |
| for( int i=0; i<n_delivered; ++i ) { |
| MyJob* j = static_cast<MyJob*>(job_array[i]); |
| int s = j->state; |
| ASSERT( s==MyJob::idle||s==MyJob::busy, NULL ); |
| } |
| server.independent_thread_number_changed( -n_extra ); |
| REMARK("client %d: team size is %d\n", client.client_id(), n_delivered); |
| if( checker ) { |
| checker->check_number_of_threads_delivered( n_delivered, n_thread, n_extra ); |
| } |
| // Protocol requires that master wait until workers have called "done_processing" |
| while( team.barrier!=n_delivered ) { |
| ASSERT( team.barrier>=0, NULL ); |
| ASSERT( team.barrier<=n_delivered, NULL ); |
| __TBB_Yield(); |
| } |
| REMARK("client %d: team completed\n", client.client_id() ); |
| for( int i=0; i<n_delivered; ++i ) { |
| ASSERT( team.info[i].ran, "thread on team allegedly delivered, but did not run?" ); |
| } |
| } |
| for( MyServer::size_type i=n_delivered; i<MyServer::size_type(max_thread); ++i ) { |
| ASSERT( !team.info[i].ran, "thread on team ran with illegal index" ); |
| } |
| } |
| #if _WIN32||_WIN64 |
| server.unregister_master( me ); |
| #endif |
| } |
| |
| void DoClientSpecificVerification( MyServer& server, int /*n_thread*/ ) |
| { |
| ASSERT( server.current_balance()==int(tbb::internal::DetectNumberOfWorkers())-1, NULL ); |
| } |
| |
| int TestMain () { |
| StrictTeam = true; |
| VerifyInitialization<MyFactory,MyClient>( MaxThread ); |
| SimpleTest<MyFactory,MyClient>(); |
| |
| StrictTeam = false; |
| VerifyInitialization<MyFactory,MyClient>( MaxThread ); |
| SimpleTest<MyFactory,MyClient>(); |
| |
| return Harness::Done; |
| } |