cmtkThreads.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkThreads.h"
00034 
00035 // GJ: use sysctl library to query cpu number on apple macosx
00036 #ifdef __APPLE__
00037 #include <sys/sysctl.h>
00038 #endif
00039 
00040 #ifdef HAVE_UNISTD_H
00041 #  include <unistd.h>
00042 #endif
00043 
00044 #ifdef CMTK_USE_THREADS
00045 #  include <pthread.h>
00046 #  include <errno.h>
00047 #endif
00048 
00049 #ifdef _OPENMP
00050 #  include <omp.h>
00051 #endif // _OPENMP
00052 
00053 #include <limits.h>
00054 #include <stdlib.h>
00055 #include <iostream>
00056 
00057 #include <algorithm>
00058 
00059 #ifndef _SC_NPROCESSORS_ONLN
00060 #  ifdef _SC_NPROC_ONLN
00061 #    define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
00062 #  endif
00063 #endif
00064 
00065 #include <System/cmtkConsole.h>
00066 
00067 namespace
00068 cmtk
00069 {
00070 
00073 
00074 int Threads::NumberOfThreads = 0;
00075 
00076 int
00077 Threads::GetNumberOfThreads()
00078 {
00079   if ( !Threads::NumberOfThreads ) 
00080     Threads::CheckEnvironment();
00081   
00082   if ( Threads::NumberOfThreads ) 
00083     {
00084     return Threads::NumberOfThreads;
00085     } 
00086   else
00087     {
00088     return std::min( Threads::GetNumberOfProcessors(), Threads::GetMaxThreads() );
00089     }
00090 }
00091 
00092 bool
00093 Threads::Available()
00094 {
00095 #ifndef CMTK_BUILD_SMP
00096   // Threads are not activated in this library.
00097   return false;
00098 #else
00099 
00100 #ifdef _MSC_VER
00101   // we know that threads are available on Windows32.
00102   return true;
00103 #elif defined (__APPLE__)
00104         // GJ Apple doesn't seem to provide these _SC_THREADS etc constants 
00105         // in unistd.h -  I don't know how you get the info dynamically
00106         // so just get it statically at compile time
00107 #ifdef _POSIX_THREADS
00108   return true;
00109 #else
00110   return false;
00111 #endif
00112 #else
00113   return (sysconf(_SC_THREADS) == -1);
00114 #endif
00115 #endif
00116 }
00117 
00118 
00119 int
00120 Threads
00121 ::SetNumberOfThreads
00122 ( const int numberOfThreads, const bool force )
00123 {
00124   if ( numberOfThreads )
00125     {
00126     if ( force )
00127       {
00128       NumberOfThreads = std::min( numberOfThreads, Threads::GetMaxThreads() );
00129       }
00130     else
00131       {
00132       NumberOfThreads = std::min( numberOfThreads, Threads::GetNumberOfProcessors() );
00133       }
00134     }
00135   else
00136     NumberOfThreads = std::min( Threads::GetNumberOfProcessors(), Threads::GetMaxThreads() );
00137 
00138 #ifdef _OPENMP
00139   omp_set_num_threads( NumberOfThreads );
00140 #endif
00141 
00142   return NumberOfThreads;
00143 }
00144 
00145 int
00146 Threads::GetMaxThreads()
00147 {
00148 #ifdef _MSC_VER
00149   return CMTK_MAX_THREADS;
00150 #  elif defined(_POSIX_THREAD_THREADS_MAX)
00151   return  _POSIX_THREAD_THREADS_MAX;
00152 #  elif defined(PTHREAD_THREADS_MAX)
00153   return  PTHREAD_THREADS_MAX;
00154 // GJ added extra elif for Apple
00155 // not sure if this max is sensible, but can't find
00156 // anywhere to query it
00157 #elif defined(__APPLE__) && defined(CMTK_USE_THREADS)
00158   return std::min( CMTK_MAX_THREADS, CMTK_MAX_THREADS ); 
00159 #  elif defined(CMTK_USE_THREADS)
00160   const long sysconfNumThreads = sysconf( _SC_THREAD_THREADS_MAX );
00161   if ( sysconfNumThreads == -1 )
00162     return CMTK_MAX_THREADS;
00163   else
00164     return std::min( (int)sysconfNumThreads, CMTK_MAX_THREADS );
00165 #  else
00166   return 1;  
00167 #  endif
00168 }
00169 
00170 int
00171 Threads::GetNumberOfProcessors()
00172 {
00173 #ifdef _MSC_VER 
00174   SYSTEM_INFO systemInfo;
00175   GetSystemInfo( &systemInfo ); 
00176   return std::min<int>( systemInfo.dwNumberOfProcessors, CMTK_MAX_THREADS );
00177 #elif defined(__APPLE__)
00178   // use sysctl to get number of available cpus on apple.  Copied from:
00179   // developer.apple.com/documentation/Porting/Conceptual/PortingUnix/index.html
00180   char *name="hw.activecpu";
00181   int nproc;  size_t len=4;
00182   sysctlbyname(name, &nproc, &len, NULL, 0);
00183   return nproc;
00184 #elif defined(CMTK_USE_THREADS)
00185   return sysconf( _SC_NPROCESSORS_ONLN );
00186 #else
00187   return 1;
00188 #endif
00189 }
00190 
00191 void
00192 Threads::RunThreads
00193 ( ThreadFunction threadCall, const unsigned numberOfThreads, void *const parameters, const size_t parameterSize )
00194 {
00195 #ifdef _OPENMP
00196   const int nThreadsOMP = std::max<int>( 1, 1+GetNumberOfThreads()-numberOfThreads );
00197   omp_set_num_threads( nThreadsOMP );
00198 #endif
00199 
00200 #ifdef CMTK_BUILD_SMP
00201   ThreadIDType Thread[CMTK_MAX_THREADS];
00202 #ifdef _MSC_VER
00203   HANDLE ThreadHandles[CMTK_MAX_THREADS];
00204 #endif
00205 #endif
00206 
00207 #ifdef CMTK_USE_THREADS
00208   pthread_attr_t attr;
00209   pthread_attr_init(&attr);
00210   pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
00211 #endif
00212 
00213   for ( unsigned threadIdx = 1; threadIdx < numberOfThreads; ++threadIdx ) 
00214     {
00215     void *threadParameters = ((char*) parameters) + threadIdx * parameterSize;
00216 
00217     // nothing happened yet, so set status to OK
00218     int status = 0;
00219 
00220     // We do NOT run the last thread as a thread, but rather continue the
00221     // main thread. This should allow us to compute the actual real time
00222     // spent on the longest thread, at least approximately.
00223 #ifdef CMTK_BUILD_SMP
00224 #ifdef _MSC_VER
00225     ThreadHandles[threadIdx] = CreateThread( NULL /*default security attributes*/, 0/*use default stack size*/, (LPTHREAD_START_ROUTINE) threadCall, threadParameters,  0/*use default creation flags*/, &Thread[threadIdx] );
00226     if ( ThreadHandles[threadIdx] == NULL ) 
00227       {
00228       status = -1;
00229       }
00230 #else // _MSC_VER
00231     status = pthread_create( &Thread[threadIdx], &attr, threadCall, threadParameters );
00232 #endif // _MSC_VER
00233 #else
00234     // we're not actually using SMP, so simply run everything "by hand".
00235     threadCall( threadParameters );
00236     // this should never fail really
00237 #endif
00238     
00239     if ( status ) 
00240       {
00241       fprintf( stderr, "Creation of thread #%d failed with status %d.\n", threadIdx, status );
00242 #if defined(CMTK_BUILD_SMP) && defined(CMTK_USE_THREADS)
00243       Thread[threadIdx] = 0;
00244 #endif
00245       threadCall( threadParameters );
00246       }
00247     }
00248   
00249   // Run thread #0
00250   threadCall( parameters );
00251   
00252   // Collect thread results in reverse order. Threads with higher numbers are
00253   // likely to have to do an iteration less than those with lower numbers.
00254   // So we collect the shorter running ones first and give more time to the
00255   // longer running ones while dealing with the administrational overhead of
00256   // the ones that are already finished.
00257   for ( int threadIdx = numberOfThreads-1; threadIdx; --threadIdx ) 
00258     {
00259 #ifdef CMTK_BUILD_SMP
00260 #  ifdef _MSC_VER
00261     WaitForSingleObject( ThreadHandles[threadIdx], INFINITE /*no timeout*/ );
00262 #  else // _MSC_VER
00263     void *resultThread;
00264     if ( Thread[threadIdx] ) 
00265       {
00266       pthread_join( Thread[threadIdx], &resultThread );
00267       }
00268 #  endif // _MSC_VER
00269 #endif
00270     }
00271   
00272 #ifdef CMTK_BUILD_SMP
00273 #ifndef _MSC_VER
00274   pthread_attr_destroy(&attr);
00275 #endif
00276 #endif
00277 
00278 #ifdef _OPENMP
00279   omp_set_num_threads( GetNumberOfThreads() );
00280 #endif
00281 }
00282 
00283 void
00284 Threads::CheckEnvironment()
00285 {
00286   const char *env = getenv( "CMTK_NUM_THREADS" );
00287   // check legacy variable
00288   if ( ! env )
00289     env = getenv( "IGS_NUM_THREADS" );
00290 
00291   if ( env )
00292     {
00293     const int numThreads = atoi( env );
00294     if ( numThreads )
00295       {
00296       SetNumberOfThreads( numThreads );
00297       // cannot use StdErr here, because it may not be initialized yet
00298       std::cerr << "INFO: number of threads set to " << numThreads << " according to environment variable CMTK_NUM_THREADS\n";
00299       }
00300     else
00301       {
00302       // cannot use StdErr here, because it may not be initialized yet
00303       std::cerr << "WARNING: environment variable CMTK_NUM_THREADS is set but does not seem to contain a number larger than 0.\n";
00304       }
00305     }
00306 }
00307 
00308 
00310 
00311 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines