CppAD: A C++ Algorithmic Differentiation Package
20130918
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_TAPE_LINK_INCLUDED 00003 # define CPPAD_TAPE_LINK_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-14 Bradley M. Bell 00007 00008 CppAD is distributed under multiple licenses. This distribution is under 00009 the terms of the 00010 Eclipse Public License Version 1.0. 00011 00012 A copy of this license is included in the COPYING file of this distribution. 00013 Please visit http://www.coin-or.org/CppAD/ for information on other licenses. 00014 -------------------------------------------------------------------------- */ 00015 00016 # include <cppad/local/define.hpp> 00017 # include <cppad/thread_alloc.hpp> 00018 # include <cppad/local/cppad_assert.hpp> 00019 00020 // needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL 00021 # include <cppad/thread_alloc.hpp> 00022 00023 namespace CppAD { // BEGIN_CPPAD_NAMESPACE 00024 /*! 00025 \file tape_link.hpp 00026 Routines that Link AD<Base> and ADTape<Base> Objects. 00027 00028 The routines that connect the AD<Base> class to the corresponding tapes 00029 (one for each thread). 00030 */ 00031 00032 /*! 00033 Handle to the tape identifier for this AD<Base> class and the specific thread. 00034 00035 \tparam Base 00036 is the base type for this AD<Base> class. 00037 00038 \param thread 00039 is the thread number. The following condition must hold 00040 \code 00041 (! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() 00042 \endcode 00043 00044 \return 00045 is a handle to the tape identifier for this thread 00046 and AD<Base> class. 00047 */ 00048 template <class Base> 00049 inline tape_id_t** AD<Base>::tape_id_handle(size_t thread) 00050 { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; 00051 static tape_id_t* tape_id_table[CPPAD_MAX_NUM_THREADS]; 00052 CPPAD_ASSERT_UNKNOWN( 00053 (! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() 00054 ); 00055 00056 return tape_id_table + thread; 00057 } 00058 00059 /*! 00060 Pointer to the tape identifier for this AD<Base> class and the specific thread. 00061 00062 \tparam Base 00063 is the base type for this AD<Base> class. 00064 00065 \param thread 00066 is the thread number; i.e., 00067 \code 00068 thread == thread_alloc::thread_num() 00069 \endcode 00070 If this condition is not satisfied, and \c NDEBUG is not defined, 00071 a CPPAD_ASSERT_UNKNOWN is generated. 00072 00073 \return 00074 is a pointer to the tape identifier for this thread 00075 and AD<Base> class. 00076 00077 \par Restrictions 00078 This routine should only be called if there was a tape created 00079 for the specified thread (it may no longer be recording). 00080 */ 00081 template <class Base> 00082 inline tape_id_t* AD<Base>::tape_id_ptr(size_t thread) 00083 { CPPAD_ASSERT_UNKNOWN( *tape_id_handle(thread) != CPPAD_NULL ) 00084 return *tape_id_handle(thread); 00085 } 00086 00087 /*! 00088 Handle for the tape for this AD<Base> class and the specific thread. 00089 00090 \tparam Base 00091 is the base type for this AD<Base> class. 00092 00093 00094 \param thread 00095 is the thread number; i.e., 00096 \code 00097 thread == thread_alloc::thread_num() 00098 \endcode 00099 If this condition is not satisfied, and \c NDEBUG is not defined, 00100 a CPPAD_ASSERT_UNKNOWN is generated. 00101 00102 \return 00103 is a handle for the AD<Base> class and the specified thread. 00104 */ 00105 template <class Base> 00106 inline ADTape<Base>** AD<Base>::tape_handle(size_t thread) 00107 { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; 00108 static ADTape<Base>* tape_table[CPPAD_MAX_NUM_THREADS]; 00109 CPPAD_ASSERT_UNKNOWN( thread == thread_alloc::thread_num() ); 00110 00111 return tape_table + thread; 00112 } 00113 00114 /*! 00115 Pointer for the tape for this AD<Base> class and the current thread. 00116 00117 \code 00118 thread == thread_alloc::thread_num() 00119 \endcode 00120 00121 \tparam Base 00122 is the base type corresponding to AD<Base> operations. 00123 00124 \return 00125 is a pointer to the tape that is currently recording AD<Base> operations 00126 for the current thread. 00127 If this value is \c CPPAD_NULL, there is no tape currently 00128 recording AD<Base> operations for this thread. 00129 */ 00130 template <class Base> 00131 inline ADTape<Base>* AD<Base>::tape_ptr(void) 00132 { size_t thread = thread_alloc::thread_num(); 00133 return *tape_handle(thread); 00134 } 00135 00136 /*! 00137 Pointer for the tape for this AD<Base> class and the specified tape 00138 identifier. 00139 00140 \tparam Base 00141 is the base type corresponding to AD<Base> operations. 00142 00143 \param tape_id 00144 is the identifier for the tape that is currently recording 00145 AD<Base> operations for the current thread. 00146 It must hold that the current thread is 00147 \code 00148 thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS ) 00149 \endcode 00150 and that there is a tape recording AD<Base> operations 00151 for this thread. 00152 If this is not the currently executing thread, 00153 a variable from a different thread is being recorded on the 00154 tape for this thread which is a user error. 00155 00156 \return 00157 is a pointer to the tape that is currently recording AD<Base> operations 00158 for the current thread (and it is not \c CPPAD_NULL). 00159 00160 \par Restrictions 00161 This routine should only be called if there is a tape recording operaitons 00162 for the specified thread. 00163 */ 00164 template <class Base> 00165 inline ADTape<Base>* AD<Base>::tape_ptr(tape_id_t tape_id) 00166 { size_t thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS ); 00167 CPPAD_ASSERT_KNOWN( 00168 thread == thread_alloc::thread_num(), 00169 "Attempt to use an AD variable with two different threads." 00170 ); 00171 CPPAD_ASSERT_UNKNOWN( tape_id == *tape_id_ptr(thread) ); 00172 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00173 return *tape_handle(thread); 00174 } 00175 00176 /*! 00177 Create and delete tapes that record AD<Base> operations for current thread. 00178 00179 \par thread 00180 the current thread is given by 00181 \code 00182 thread = thread_alloc::thread_num() 00183 \endcode 00184 00185 \tparam Base 00186 is the base type corresponding to AD<Base> operations. 00187 00188 \param job 00189 This argument determines if we are creating a new tape, or deleting an 00190 old one. 00191 - \c tape_manage_new : 00192 Creates and a new tape. 00193 It is assumed that there is no tape recording AD<Base> operations 00194 for this thread when \c tape_manage is called. 00195 It the input value of <tt>*tape_id_handle(thread)</tt> is \c CPPAD_NULL, 00196 it will be changed to a non-zero pointer and the corresponding value 00197 of <tt>*tape_id_ptr(thread)</tt> will be set to 00198 <tt>thread + CPPAD_MAX_NUM_THREADS</tt>. 00199 - \c tape_manage_delete : 00200 It is assumed that there is a tape recording AD<Base> operations 00201 for this thread when \c tape_manage is called. 00202 The value of <tt>*tape_id_ptr(thread)</tt> will be advanced by 00203 \c CPPAD_MAX_NUM_THREADS. 00204 00205 00206 \return 00207 - <tt>job == tape_manage_new</tt>: a pointer to the new tape is returned. 00208 - <tt>job == tape_manage_delete</tt>: the value \c CPPAD_NULL is returned. 00209 */ 00210 template <class Base> 00211 ADTape<Base>* AD<Base>::tape_manage(tape_manage_job job) 00212 { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL 00213 static ADTape<Base>* tape_table[CPPAD_MAX_NUM_THREADS]; 00214 static ADTape<Base> tape_zero; 00215 static tape_id_t tape_id_save[CPPAD_MAX_NUM_THREADS]; 00216 00217 size_t thread = thread_alloc::thread_num(); 00218 if( job == tape_manage_clear ) 00219 { CPPAD_ASSERT_UNKNOWN(thread == 0 && (! thread_alloc::in_parallel())); 00220 for(thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) 00221 { if( tape_table[thread] != CPPAD_NULL ) 00222 { tape_id_save[thread] = tape_table[thread]->id_; 00223 *tape_id_handle(thread) = &tape_id_save[thread]; 00224 00225 if( thread != 0 ) 00226 delete( tape_table[thread] ); 00227 tape_table[thread] = CPPAD_NULL; 00228 } 00229 } 00230 return CPPAD_NULL; 00231 } 00232 tape_id_t** tape_id = tape_id_handle(thread); 00233 ADTape<Base>** tape = tape_handle(thread); 00234 00235 if( tape_table[thread] == CPPAD_NULL ) 00236 { // allocate separate memroy to avoid false sharing 00237 if( thread == 0 ) 00238 tape_table[thread] = &tape_zero; 00239 else tape_table[thread] = new ADTape<Base>(); 00240 tape_table[thread]->id_ = tape_id_save[thread]; 00241 *tape_id = &tape_table[thread]->id_; 00242 00243 // init tape id > 0 and thread == tape id % CPPAD_MAX_NUM_THREADS 00244 if( **tape_id == 0 ) 00245 **tape_id = thread + CPPAD_MAX_NUM_THREADS; 00246 } 00247 // make sure tape_id_handle(thread) is pointing to the proper place 00248 CPPAD_ASSERT_UNKNOWN( *tape_id == &tape_table[thread]->id_ ); 00249 // make sure tape_id value is valid for this thread 00250 CPPAD_ASSERT_UNKNOWN( 00251 size_t( **tape_id % CPPAD_MAX_NUM_THREADS ) == thread 00252 ); 00253 00254 switch(job) 00255 { case tape_manage_new: 00256 // tape for this thread must be null at the start 00257 CPPAD_ASSERT_UNKNOWN( *tape == CPPAD_NULL ); 00258 *tape = tape_table[thread]; 00259 break; 00260 00261 case tape_manage_delete: 00262 CPPAD_ASSERT_UNKNOWN( *tape == tape_table[thread] ); 00263 CPPAD_ASSERT_KNOWN( 00264 std::numeric_limits<CPPAD_TAPE_ID_TYPE>::max() 00265 - CPPAD_MAX_NUM_THREADS > **tape_id, 00266 "To many different tapes given the type used for " 00267 "CPPAD_TAPE_ID_TYPE" 00268 ); 00269 // advance tape identfier so all AD<Base> variables become parameters 00270 **tape_id += CPPAD_MAX_NUM_THREADS; 00271 // free memory corresponding to recording in the old tape 00272 tape_table[thread]->Rec_.free(); 00273 // inform rest of CppAD that no tape recording for this thread 00274 *tape = CPPAD_NULL; 00275 break; 00276 00277 case tape_manage_clear: 00278 CPPAD_ASSERT_UNKNOWN(false); 00279 } 00280 return *tape; 00281 } 00282 00283 /*! 00284 Get a pointer to tape that records AD<Base> operations for the current thread. 00285 00286 \tparam Base 00287 is the base type corresponding to AD<Base> operations. 00288 00289 \par thread 00290 The current thread must be given by 00291 \code 00292 thread = this->tape_id_ % CPPAD_MAX_NUM_THREADS 00293 \endcode 00294 00295 \return 00296 is a pointer to the tape that is currently recording AD<Base> operations 00297 for the current thread. 00298 This value must not be \c CPPAD_NULL; i.e., there must be a tape currently 00299 recording AD<Base> operations for this thread. 00300 */ 00301 00302 template <class Base> 00303 inline ADTape<Base> *AD<Base>::tape_this(void) const 00304 { 00305 size_t thread = size_t( tape_id_ % CPPAD_MAX_NUM_THREADS ); 00306 CPPAD_ASSERT_UNKNOWN( tape_id_ == *tape_id_ptr(thread) ); 00307 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00308 return *tape_handle(thread); 00309 } 00310 00311 } // END_CPPAD_NAMESPACE 00312 # endif