CppAD: A C++ Algorithmic Differentiation Package
20130918
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_THREAD_ALLOC_INCLUDED 00003 # define CPPAD_THREAD_ALLOC_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 <sstream> 00017 # include <limits> 00018 # include <memory> 00019 00020 00021 # ifdef _MSC_VER 00022 // Supress warning that Microsoft compiler changed its behavior and is now 00023 // doing the correct thing at the statement: 00024 // new(array + i) Type(); 00025 # pragma warning(disable:4345) 00026 # endif 00027 00028 # include <cppad/local/cppad_assert.hpp> 00029 # include <cppad/local/define.hpp> 00030 namespace CppAD { // BEGIN_CPPAD_NAMESPACE 00031 /*! 00032 \file thread_alloc.hpp 00033 File used to define the CppAD multi-threading allocaor class 00034 */ 00035 00036 /*! 00037 \def CPPAD_MAX_NUM_CAPACITY 00038 Maximum number of different capacities the allocator will attempt. 00039 This must be larger than the log base two of numeric_limit<size_t>::max(). 00040 */ 00041 # define CPPAD_MAX_NUM_CAPACITY 100 00042 00043 /*! 00044 \def CPPAD_MIN_DOUBLE_CAPACITY 00045 Minimum number of double values that will fit in an allocation. 00046 */ 00047 # define CPPAD_MIN_DOUBLE_CAPACITY 16 00048 00049 /*! 00050 \def CPPAD_TRACE_CAPACITY 00051 If NDEBUG is not defined, print all calls to \c get_memory and \c return_memory 00052 that correspond to this capacity and thread CPPAD_TRACE_THREAD. 00053 (Note that if CPPAD_TRACE_CAPACITY is zero, or any other value not in the list 00054 of capacities, no tracing will be done.) 00055 */ 00056 # define CPPAD_TRACE_CAPACITY 0 00057 00058 /*! 00059 \def CPPAD_TRACE_THREAD 00060 If NDEBUG is not defined, print all calls to \c get_memory and \c return_memory 00061 that correspond to this thead and capacity CPPAD_TRACE_CAPACITY. 00062 */ 00063 # define CPPAD_TRACE_THREAD 0 00064 00065 /* 00066 Note that Section 3.6.2 of ISO/IEC 14882:1998(E) states: "The storage for 00067 objects with static storage duration (3.7.1) shall be zero-initialized 00068 (8.5) before any other initialization takes place." 00069 */ 00070 00071 /*! 00072 Capacity vector for memory allocation block sizes. 00073 00074 Only one of these objects should be created and used as a 00075 static variable inside of the \c thread_alloc::capacity_info function. 00076 */ 00077 00078 /*! 00079 Allocator class that works well with an multi-threading environment. 00080 */ 00081 class thread_alloc{ 00082 // ============================================================================ 00083 private: 00084 00085 class capacity_t { 00086 public: 00087 /// number of capacity values actually used 00088 size_t number; 00089 /// the different capacity values 00090 size_t value[CPPAD_MAX_NUM_CAPACITY]; 00091 /// ctor 00092 capacity_t(void) 00093 { // Cannot figure out how to call thread_alloc::in_parallel here. 00094 // CPPAD_ASSERT_UNKNOWN( 00095 // ! thread_alloc::in_parallel() , "thread_alloc: " 00096 // "parallel mode and parallel_setup not yet called." 00097 // ); 00098 number = 0; 00099 size_t capacity = CPPAD_MIN_DOUBLE_CAPACITY * sizeof(double); 00100 while( capacity < std::numeric_limits<size_t>::max() / 2 ) 00101 { CPPAD_ASSERT_UNKNOWN( number < CPPAD_MAX_NUM_CAPACITY ); 00102 value[number++] = capacity; 00103 // next capactiy is 3/2 times the current one 00104 capacity = 3 * ( (capacity + 1) / 2 ); 00105 } 00106 CPPAD_ASSERT_UNKNOWN( number > 0 ); 00107 } 00108 }; 00109 00110 class block_t { 00111 public: 00112 /// extra information (currently used by create and delete array) 00113 size_t extra_; 00114 /// an index that uniquely idenfifies both thread and capacity 00115 size_t tc_index_; 00116 /// pointer to the next memory allocation with the the same tc_index_ 00117 void* next_; 00118 // ----------------------------------------------------------------- 00119 /// make default constructor private. It is only used by constructor 00120 /// for `root arrays below. 00121 block_t(void) : extra_(0), tc_index_(0), next_(CPPAD_NULL) 00122 { } 00123 }; 00124 00125 // --------------------------------------------------------------------- 00126 /// Vector of fixed capacity values for this allocator 00127 static const capacity_t* capacity_info(void) 00128 { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; 00129 static const capacity_t capacity; 00130 return &capacity; 00131 } 00132 // --------------------------------------------------------------------- 00133 /// Structure of information for each thread 00134 struct thread_alloc_info { 00135 /// count of available bytes for this thread 00136 size_t count_inuse_; 00137 /// count of inuse bytes for this thread 00138 size_t count_available_; 00139 /// root of available list for this thread and each capacity 00140 block_t root_available_[CPPAD_MAX_NUM_CAPACITY]; 00141 /// root of inuse list for this thread and each capacity 00142 /// If NDEBUG is true, this memory is not used, but it still 00143 /// helps separate this structure from one for the next thread. 00144 block_t root_inuse_[CPPAD_MAX_NUM_CAPACITY]; 00145 }; 00146 // --------------------------------------------------------------------- 00147 /*! 00148 Set and Get hold available memory flag. 00149 00150 \param set [in] 00151 if true, the value returned by this return is changed. 00152 00153 \param new_value [in] 00154 if \a set is true, this is the new value returned by this routine. 00155 Otherwise, \c new_value is ignored. 00156 00157 \return 00158 the current setting for this routine (which is initially false). 00159 */ 00160 static bool set_get_hold_memory(bool set, bool new_value = false) 00161 { static bool value = false; 00162 if( set ) 00163 value = new_value; 00164 return value; 00165 } 00166 // --------------------------------------------------------------------- 00167 /*! 00168 Get pointer to the information for this thread. 00169 00170 \param thread [in] 00171 Is the thread number for this information pointer. 00172 00173 \param clear 00174 If \a clear is true, then the information pointer for this thread 00175 is deleted and the \c CPPAD_NULL pointer is returned. 00176 There must be no memory currently in either the inuse or avaialble 00177 lists when this routine is called. 00178 00179 \return 00180 is the current informaiton pointer for this thread. 00181 If \a clear is false, and the current pointer is CPPAD_NULL, 00182 a new infromation record is allocated and its pointer returned. 00183 In this case, if \c info is the retured pointer, 00184 <code>info->count_inuse == 0</code> and 00185 <code>info->count_available == 0</code>. 00186 In addition, 00187 for <code>c = 0 , ... , CPPAD_MAX_NUM_CAPACITY-1</code> 00188 <code>info->root_inuse_[c].next_ == CPPAD_NULL</code> and 00189 <code>info->root_available_[c].next_ == CPPAD_NULL</code>. 00190 */ 00191 static thread_alloc_info* thread_info( 00192 size_t thread , 00193 bool clear = false ) 00194 { static thread_alloc_info* all_info[CPPAD_MAX_NUM_THREADS]; 00195 static thread_alloc_info zero_info; 00196 00197 CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; 00198 00199 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS ); 00200 00201 thread_alloc_info* info = all_info[thread]; 00202 if( clear ) 00203 { if( info != CPPAD_NULL ) 00204 { 00205 # ifndef NDEBUG 00206 CPPAD_ASSERT_UNKNOWN( 00207 info->count_inuse_ == 0 && 00208 info->count_available_ == 0 00209 ); 00210 for(size_t c = 0; c < CPPAD_MAX_NUM_CAPACITY; c++) 00211 { CPPAD_ASSERT_UNKNOWN( 00212 info->root_inuse_[c].next_ == CPPAD_NULL && 00213 info->root_available_[c].next_ == CPPAD_NULL 00214 ); 00215 } 00216 # endif 00217 if( thread != 0 ) 00218 ::operator delete( reinterpret_cast<void*>(info) ); 00219 info = CPPAD_NULL; 00220 all_info[thread] = info; 00221 } 00222 } 00223 else if( info == CPPAD_NULL ) 00224 { if( thread == 0 ) 00225 info = &zero_info; 00226 else 00227 { size_t size = sizeof(thread_alloc_info); 00228 void* v_ptr = ::operator new(size); 00229 info = reinterpret_cast<thread_alloc_info*>(v_ptr); 00230 } 00231 all_info[thread] = info; 00232 00233 // initialize the information record 00234 for(size_t c = 0; c < CPPAD_MAX_NUM_CAPACITY; c++) 00235 { info->root_inuse_[c].next_ = CPPAD_NULL; 00236 info->root_available_[c].next_ = CPPAD_NULL; 00237 } 00238 info->count_inuse_ = 0; 00239 info->count_available_ = 0; 00240 } 00241 return info; 00242 } 00243 // ----------------------------------------------------------------------- 00244 /*! 00245 Increase the number of bytes of memory that are currently in use; i.e., 00246 that been obtained with \c get_memory and not yet returned. 00247 00248 \param inc [in] 00249 amount to increase memory in use. 00250 00251 \param thread [in] 00252 Thread for which we are increasing the number of bytes in use 00253 (must be less than \c num_threads). 00254 Durring parallel execution, this must be the thread 00255 that is currently executing. 00256 */ 00257 static void inc_inuse(size_t inc, size_t thread) 00258 { 00259 CPPAD_ASSERT_UNKNOWN( thread < num_threads() ); 00260 CPPAD_ASSERT_UNKNOWN( 00261 thread == thread_num() || (! in_parallel()) 00262 ); 00263 thread_alloc_info* info = thread_info(thread); 00264 00265 // do the addition 00266 size_t result = info->count_inuse_ + inc; 00267 CPPAD_ASSERT_UNKNOWN( result >= info->count_inuse_ ); 00268 00269 info->count_inuse_ = result; 00270 } 00271 // ----------------------------------------------------------------------- 00272 /*! 00273 Increase the number of bytes of memory that are currently avaialble; i.e., 00274 have been obtained obtained from the system and are being held future use. 00275 00276 \copydetails inc_inuse 00277 */ 00278 static void inc_available(size_t inc, size_t thread) 00279 { 00280 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); 00281 CPPAD_ASSERT_UNKNOWN( 00282 thread == thread_num() || (! in_parallel()) 00283 ); 00284 thread_alloc_info* info = thread_info(thread); 00285 // do the addition 00286 size_t result = info->count_available_ + inc; 00287 CPPAD_ASSERT_UNKNOWN( result >= info->count_available_ ); 00288 00289 info->count_available_ = result; 00290 } 00291 // ----------------------------------------------------------------------- 00292 /*! 00293 Decrease the number of bytes of memory that are currently in use; i.e., 00294 that been obtained with \c get_memory and not yet returned. 00295 00296 \param dec [in] 00297 amount to decrease number of bytes in use. 00298 00299 \param thread [in] 00300 Thread for which we are decreasing the number of bytes in use 00301 (must be less than \c num_threads). 00302 Durring parallel execution, this must be the thread 00303 that is currently executing. 00304 */ 00305 static void dec_inuse(size_t dec, size_t thread) 00306 { 00307 CPPAD_ASSERT_UNKNOWN( 00308 thread < num_threads() || (! in_parallel()) 00309 ); 00310 CPPAD_ASSERT_UNKNOWN( 00311 thread == thread_num() || (! in_parallel()) 00312 ); 00313 thread_alloc_info* info = thread_info(thread); 00314 00315 // do the subtraction 00316 CPPAD_ASSERT_UNKNOWN( info->count_inuse_ >= dec ); 00317 info->count_inuse_ = info->count_inuse_ - dec; 00318 } 00319 // ----------------------------------------------------------------------- 00320 /*! 00321 Decrease the number of bytes of memory that are currently avaialble; i.e., 00322 have been obtained obtained from the system and are being held future use. 00323 00324 \copydetails dec_inuse 00325 */ 00326 static void dec_available(size_t dec, size_t thread) 00327 { 00328 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); 00329 CPPAD_ASSERT_UNKNOWN( 00330 thread == thread_num() || (! in_parallel()) 00331 ); 00332 thread_alloc_info* info = thread_info(thread); 00333 // do the subtraction 00334 CPPAD_ASSERT_UNKNOWN( info->count_available_ >= dec ); 00335 info->count_available_ = info->count_available_ - dec; 00336 } 00337 00338 // ---------------------------------------------------------------------- 00339 /*! 00340 Set and get the number of threads that are sharing memory. 00341 00342 \param number_new 00343 If \c number is zero, we are only retreiving the current maximum 00344 number of threads. Otherwise, we are setting and retreiving 00345 maximum number of threads. 00346 00347 \return 00348 the number of threads that are sharing memory. 00349 If \c number_new is non-zero, the return value is equal to 00350 \c number_new. 00351 */ 00352 static size_t set_get_num_threads(size_t number_new) 00353 { static size_t number_user = 1; 00354 00355 CPPAD_ASSERT_UNKNOWN( number_new <= CPPAD_MAX_NUM_THREADS ); 00356 CPPAD_ASSERT_UNKNOWN( ! in_parallel() || (number_new == 0) ); 00357 00358 // case where we are changing the number of threads 00359 if( number_new != 0 ) 00360 number_user = number_new; 00361 00362 return number_user; 00363 } 00364 /*! 00365 Set and call the routine that determine if we are in parallel 00366 execution mode. 00367 00368 \return 00369 value retuned by most recent setting for \a parallel_new. 00370 If \a set is true, 00371 or the most recent setting is \c CPPAD_NULL (its initial value), 00372 the return value is false. 00373 Otherwise the function corresponding to the most recent setting 00374 is called and its value returned by \c set_get_in_parallel. 00375 00376 \param parallel_new [in] 00377 If \a set is false, \a parallel_new it is not used. 00378 Otherwise, the current value of \c parallel_new becomes the 00379 most recent setting for in_parallel. 00380 00381 \param set 00382 If \a set is true, then \a parallel_new is becomes the most 00383 recent setting for this \c set_get_in_parallel. 00384 */ 00385 static bool set_get_in_parallel( 00386 bool (*parallel_new)(void) , 00387 bool set = false ) 00388 { static bool (*parallel_user)(void) = CPPAD_NULL; 00389 00390 if( set ) 00391 { parallel_user = parallel_new; 00392 return false; 00393 } 00394 00395 if( parallel_user == CPPAD_NULL ) 00396 return false; 00397 00398 return parallel_user(); 00399 } 00400 /*! 00401 Set and call the routine that determine the current thread number. 00402 00403 \return 00404 returns value for the most recent setting for \a thread_num_new. 00405 If \a set is true, 00406 or the most recent setting is \c CPPAD_NULL (its initial value), 00407 the return value is zero. 00408 Otherwise the routine corresponding to the most recent setting 00409 is called and its value returned by \c set_get_thread_num. 00410 00411 \param thread_num_new [in] 00412 If \a set is false, \a thread_num_new it is not used. 00413 Otherwise, the current value of \c thread_num_new becomes the 00414 most recent setting for thread_num. 00415 00416 \param set 00417 If \a set is true, then \a thread_num_new is becomes the most 00418 recent setting for this \c set_get_thread_num. 00419 */ 00420 static size_t set_get_thread_num( 00421 size_t (*thread_num_new)(void) , 00422 bool set = false ) 00423 { static size_t (*thread_num_user)(void) = CPPAD_NULL; 00424 00425 if( set ) 00426 { thread_num_user = thread_num_new; 00427 return 0; 00428 } 00429 00430 if( thread_num_user == CPPAD_NULL ) 00431 return 0; 00432 00433 size_t thread = thread_num_user(); 00434 CPPAD_ASSERT_KNOWN( 00435 thread < set_get_num_threads(0) , 00436 "parallel_setup: thread_num() >= num_threads" 00437 ); 00438 return thread; 00439 } 00440 // ============================================================================ 00441 public: 00442 /* 00443 $begin ta_parallel_setup$$ 00444 $spell 00445 alloc 00446 num 00447 bool 00448 $$ 00449 $section Setup thread_alloc For Use in Multi-Threading Environment$$ 00450 00451 $index setup, thread_alloc$$ 00452 $index thread_alloc, setup$$ 00453 $index parallel, setup$$ 00454 $index setup, parallel$$ 00455 00456 $index num_threads$$ 00457 $index in_parallel$$ 00458 $index thread_num$$ 00459 00460 $index multi-threading, initialize$$ 00461 $index initialize, multi-threading$$ 00462 00463 $head Syntax$$ 00464 $codei%thread_alloc::parallel_setup(%num_threads%, %in_parallel%, %thread_num%) 00465 %$$ 00466 00467 $head Purpose$$ 00468 By default there is only one thread and all execution is in sequential mode, 00469 i.e., multiple threads are not sharing the same memory; i.e. 00470 not in parallel mode. 00471 00472 $head Speed$$ 00473 It should be faster, even when $icode num_thread$$ is equal to one, 00474 for $code thread_alloc$$ to hold onto memory. 00475 This can be accomplished using the function call 00476 $codei% 00477 thread_alloc::hold_memory(true) 00478 %$$ 00479 see $cref/hold_memory/ta_hold_memory/$$. 00480 00481 $head num_threads$$ 00482 This argument has prototype 00483 $codei% 00484 size_t %num_threads% 00485 %$$ 00486 and must be greater than zero. 00487 It specifies the number of threads that are sharing memory. 00488 The case $icode%num_threads% == 1%$$ is a special case that is 00489 used to terminate a multi-threading environment. 00490 00491 $head in_parallel$$ 00492 This function has prototype 00493 $codei% 00494 bool %in_parallel%(void) 00495 %$$ 00496 It must return $code true$$ if there is more than one thread 00497 currently executing. 00498 Otherwise it can return false. 00499 $pre 00500 00501 $$ 00502 In the special case where $icode%num_threads% == 1%$$, 00503 the routine $icode in_parallel$$ is not used. 00504 00505 $head thread_num$$ 00506 This function has prototype 00507 $codei% 00508 size_t %thread_num%(void) 00509 %$$ 00510 It must return a thread number that uniquely identifies the 00511 currently executing thread. 00512 Furthermore 00513 $codei% 00514 0 <= %thread_num%() < %num_threads% 00515 %$$. 00516 In the special case where $icode%num_threads% == 1%$$, 00517 the routine $icode thread_num$$ is not used. 00518 $pre 00519 00520 $$ 00521 Note that this function is called by other routines so, 00522 as soon as a new thread is executing, 00523 one must be certain that $icode thread_num()$$ will 00524 work for that thread. 00525 00526 $head Restrictions$$ 00527 The function $code parallel_setup$$ must be called before 00528 the program enters $cref/parallel/ta_in_parallel/$$ execution mode. 00529 In addition, this function cannot be called while in parallel mode. 00530 00531 $head Example$$ 00532 The files 00533 $cref simple_ad_openmp.cpp$$, 00534 $cref simple_ad_bthread.cpp$$, and 00535 $cref simple_ad_pthread.cpp$$, 00536 contain examples and tests that use this function. 00537 00538 $end 00539 */ 00540 /*! 00541 Set thread_alloc up for parallel mode usage. 00542 00543 \param num_threads [in] 00544 Is the number of thread that may be executing at the same time. 00545 00546 \param in_parallel [in] 00547 Is the routine that determines if we are in parallel mode or not. 00548 00549 \param thread_num [in] 00550 Is the routine that determines the current thread number 00551 (between zero and num_threads minus one). 00552 */ 00553 static void parallel_setup( 00554 size_t num_threads , 00555 bool (*in_parallel)(void) , 00556 size_t (*thread_num)(void) ) 00557 { 00558 // Special case where we go back to single thread mode right away 00559 // (previous settings may no longer be valid) 00560 if( num_threads == 1 ) 00561 { bool set = true; 00562 set_get_num_threads(num_threads); 00563 set_get_in_parallel(CPPAD_NULL, set); 00564 set_get_thread_num(CPPAD_NULL, set); 00565 return; 00566 } 00567 00568 CPPAD_ASSERT_KNOWN( 00569 num_threads <= CPPAD_MAX_NUM_THREADS , 00570 "parallel_setup: num_threads is too large" 00571 ); 00572 CPPAD_ASSERT_KNOWN( 00573 num_threads != 0 , 00574 "parallel_setup: num_threads == zero" 00575 ); 00576 CPPAD_ASSERT_KNOWN( 00577 in_parallel != CPPAD_NULL , 00578 "parallel_setup: num_threads != 1 and in_parallel == CPPAD_NULL" 00579 ); 00580 CPPAD_ASSERT_KNOWN( 00581 thread_num != CPPAD_NULL , 00582 "parallel_setup: num_threads != 1 and thread_num == CPPAD_NULL" 00583 ); 00584 00585 // Make sure that constructors for all static variables in this file 00586 // are called in sequential mode. 00587 for(size_t thread = 0; thread < num_threads; thread++) 00588 thread_info(thread); 00589 capacity_info(); 00590 size_t cap_bytes; 00591 void* v_ptr = get_memory(0, cap_bytes); 00592 00593 // free memory allocated by call to get_memory above 00594 return_memory(v_ptr); 00595 free_available( set_get_thread_num(CPPAD_NULL) ); 00596 00597 // delay this so thread_num() call above is in previous mode 00598 // (current setings may not yet be valid) 00599 if( num_threads > 1 ) 00600 { bool set = true; 00601 set_get_num_threads(num_threads); 00602 set_get_in_parallel(in_parallel, set); 00603 set_get_thread_num(thread_num, set); 00604 } 00605 } 00606 /* 00607 $begin ta_num_threads$$ 00608 $spell 00609 inv 00610 CppAD 00611 num 00612 alloc 00613 $$ 00614 $section Get Number of Threads$$ 00615 00616 $index num_threads, thread_alloc$$ 00617 $index thread_alloc, num_threads$$ 00618 $index threads, number of$$ 00619 00620 $head Syntax$$ 00621 $icode%number% = thread_alloc::num_threads()%$$ 00622 00623 $head Purpose$$ 00624 Determine the number of threads as set during $cref/parallel_setup/ta_parallel_setup/$$. 00625 00626 $head number$$ 00627 The return value $icode number$$ has prototype 00628 $codei% 00629 size_t %number% 00630 %$$ 00631 and is equal to the value of 00632 $cref/num_threads/ta_parallel_setup/num_threads/$$ 00633 in the previous call to $icode parallel_setup$$. 00634 If there was no such previous call, the value one is returned. 00635 00636 $head Example$$ 00637 The example and test $cref thread_alloc.cpp$$ uses this routine. 00638 00639 $end 00640 */ 00641 /*! 00642 Get the current number of threads that thread_alloc can use. 00643 */ 00644 static size_t num_threads(void) 00645 { return set_get_num_threads(0); } 00646 /* ----------------------------------------------------------------------- 00647 $begin ta_in_parallel$$ 00648 00649 $section Is The Current Execution in Parallel Mode$$ 00650 $spell 00651 thread_alloc 00652 bool 00653 $$ 00654 00655 $index in_parallel, thread_alloc$$ 00656 $index thread_alloc, in_parallel$$ 00657 $index parallel, execution$$ 00658 $index execution, parallel$$ 00659 $index sequential, execution$$ 00660 00661 $head Syntax$$ 00662 $icode%flag% = thread_alloc::in_parallel()%$$ 00663 00664 $head Purpose$$ 00665 Some of the $cref thread_alloc$$ allocation routines have different 00666 specifications for parallel (not sequential) execution mode. 00667 This routine enables you to determine if the current execution mode 00668 is sequential or parallel. 00669 00670 $head flag$$ 00671 The return value has prototype 00672 $codei% 00673 bool %flag% 00674 %$$ 00675 It is true if the current execution is in parallel mode 00676 (possibly multi-threaded) and false otherwise (sequential mode). 00677 00678 $head Example$$ 00679 $cref thread_alloc.cpp$$ 00680 00681 $end 00682 */ 00683 /// Are we in a parallel execution state; i.e., is it possible that 00684 /// other threads are currently executing. 00685 static bool in_parallel(void) 00686 { return set_get_in_parallel(0); } 00687 /* ----------------------------------------------------------------------- 00688 $begin ta_thread_num$$ 00689 $spell 00690 CppAD 00691 num 00692 thread_alloc 00693 cppad.hpp 00694 $$ 00695 00696 $section Get the Current Thread Number$$ 00697 00698 $index thread_num, thread_alloc$$ 00699 $index thread_alloc, thread_num$$ 00700 $index thread, current$$ 00701 $index current, thread$$ 00702 00703 $head Syntax$$ 00704 $icode%thread% = thread_alloc::thread_num()%$$ 00705 00706 $head Purpose$$ 00707 Some of the $cref thread_alloc$$ allocation routines have a thread number. 00708 This routine enables you to determine the current thread. 00709 00710 $head thread$$ 00711 The return value $icode thread$$ has prototype 00712 $codei% 00713 size_t %thread% 00714 %$$ 00715 and is the currently executing thread number. 00716 If $code _OPENMP$$ is not defined, $icode thread$$ is zero. 00717 00718 $head Example$$ 00719 $cref thread_alloc.cpp$$ 00720 00721 $end 00722 */ 00723 /// Get current thread number 00724 static size_t thread_num(void) 00725 { return set_get_thread_num(CPPAD_NULL); } 00726 /* ----------------------------------------------------------------------- 00727 $begin ta_get_memory$$ 00728 $spell 00729 std 00730 num 00731 ptr 00732 thread_alloc 00733 $$ 00734 00735 $section Get At Least A Specified Amount of Memory$$ 00736 00737 $index thread_num, thread_alloc$$ 00738 $index thread_alloc, thread_num$$ 00739 $index memory, allocate$$ 00740 $index allocate, memory$$ 00741 00742 $head Syntax$$ 00743 $icode%v_ptr% = thread_alloc::get_memory(%min_bytes%, %cap_bytes%)%$$ 00744 00745 $head Purpose$$ 00746 Use $cref thread_alloc$$ to obtain a minimum number of bytes of memory 00747 (for use by the $cref/current thread/ta_thread_num/$$). 00748 00749 $head min_bytes$$ 00750 This argument has prototype 00751 $codei% 00752 size_t %min_bytes% 00753 %$$ 00754 It specifies the minimum number of bytes to allocate. 00755 This value must be less than 00756 $codep 00757 std::numeric_limits<size_t>::max() / 2 00758 $$ 00759 00760 $head cap_bytes$$ 00761 This argument has prototype 00762 $codei% 00763 size_t& %cap_bytes% 00764 %$$ 00765 It's input value does not matter. 00766 Upon return, it is the actual number of bytes (capacity) 00767 that have been allocated for use, 00768 $codei% 00769 %min_bytes% <= %cap_bytes% 00770 %$$ 00771 00772 $head v_ptr$$ 00773 The return value $icode v_ptr$$ has prototype 00774 $codei% 00775 void* %v_ptr% 00776 %$$ 00777 It is the location where the $icode cap_bytes$$ of memory 00778 that have been allocated for use begins. 00779 00780 $head Allocation Speed$$ 00781 This allocation should be faster if the following conditions hold: 00782 $list number$$ 00783 The memory allocated by a previous call to $code get_memory$$ 00784 is currently available for use. 00785 $lnext 00786 The current $icode min_bytes$$ is between 00787 the previous $icode min_bytes$$ and previous $icode cap_bytes$$. 00788 $lend 00789 00790 $head Example$$ 00791 $cref thread_alloc.cpp$$ 00792 00793 $end 00794 */ 00795 /*! 00796 Use thread_alloc to get a specified amount of memory. 00797 00798 If the memory allocated by a previous call to \c get_memory is now 00799 avaialable, and \c min_bytes is between its previous value 00800 and the previous \c cap_bytes, this memory allocation will have 00801 optimal speed. Otherwise, the memory allocation is more complicated and 00802 may have to wait for other threads to complete an allocation. 00803 00804 \param min_bytes [in] 00805 The minimum number of bytes of memory to be obtained for use. 00806 00807 \param cap_bytes [out] 00808 The actual number of bytes of memory obtained for use. 00809 00810 \return 00811 pointer to the beginning of the memory allocated for use. 00812 */ 00813 static void* get_memory(size_t min_bytes, size_t& cap_bytes) 00814 { // see first_trace below 00815 CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; 00816 00817 // check that number of requested bytes is not to large 00818 CPPAD_ASSERT_KNOWN( 00819 min_bytes < std::numeric_limits<size_t>::max() / 2 , 00820 "get_memory(min_bytes, cap_bytes): min_bytes is too large" 00821 ); 00822 00823 size_t num_cap = capacity_info()->number; 00824 using std::cout; 00825 using std::endl; 00826 00827 // determine the capacity for this request 00828 size_t c_index = 0; 00829 const size_t* capacity_vec = capacity_info()->value; 00830 while( capacity_vec[c_index] < min_bytes ) 00831 { ++c_index; 00832 CPPAD_ASSERT_UNKNOWN(c_index < num_cap ); 00833 } 00834 cap_bytes = capacity_vec[c_index]; 00835 00836 // determine the thread, capacity, and info for this thread 00837 size_t thread = thread_num(); 00838 size_t tc_index = thread * num_cap + c_index; 00839 thread_alloc_info* info = thread_info(thread); 00840 00841 # ifndef NDEBUG 00842 // trace allocation 00843 static bool first_trace = true; 00844 if( cap_bytes == CPPAD_TRACE_CAPACITY && 00845 thread == CPPAD_TRACE_THREAD && first_trace ) 00846 { cout << endl; 00847 cout << "thread_alloc: Trace for Thread = " << thread; 00848 cout << " and capacity = " << cap_bytes << endl; 00849 if( first_trace ) 00850 first_trace = false; 00851 } 00852 00853 // Root nodes for both lists. Note these are different for different 00854 // threads because tc_index is different for different threads. 00855 block_t* inuse_root = info->root_inuse_ + c_index; 00856 # endif 00857 block_t* available_root = info->root_available_ + c_index; 00858 00859 // check if we already have a node we can use 00860 void* v_node = available_root->next_; 00861 block_t* node = reinterpret_cast<block_t*>(v_node); 00862 if( node != CPPAD_NULL ) 00863 { CPPAD_ASSERT_UNKNOWN( node->tc_index_ == tc_index ); 00864 00865 // remove node from available list 00866 available_root->next_ = node->next_; 00867 00868 // return value for get_memory 00869 void* v_ptr = reinterpret_cast<void*>(node + 1); 00870 # ifndef NDEBUG 00871 // add node to inuse list 00872 node->next_ = inuse_root->next_; 00873 inuse_root->next_ = v_node; 00874 00875 // trace allocation 00876 if( cap_bytes == CPPAD_TRACE_CAPACITY && 00877 thread == CPPAD_TRACE_THREAD ) 00878 { cout << "get_memory: v_ptr = " << v_ptr << endl; } 00879 # endif 00880 00881 // adjust counts 00882 inc_inuse(cap_bytes, thread); 00883 dec_available(cap_bytes, thread); 00884 00885 // return pointer to memory, do not inclue thread_alloc information 00886 return v_ptr; 00887 } 00888 00889 // Create a new node with thread_alloc information at front. 00890 // This uses the system allocator, which is thread safe, but slower, 00891 // because the thread might wait for a lock on the allocator. 00892 v_node = ::operator new(sizeof(block_t) + cap_bytes); 00893 node = reinterpret_cast<block_t*>(v_node); 00894 node->tc_index_ = tc_index; 00895 void* v_ptr = reinterpret_cast<void*>(node + 1); 00896 00897 # ifndef NDEBUG 00898 // add node to inuse list 00899 node->next_ = inuse_root->next_; 00900 inuse_root->next_ = v_node; 00901 00902 // trace allocation 00903 if( cap_bytes == CPPAD_TRACE_CAPACITY && 00904 thread == CPPAD_TRACE_THREAD ) 00905 { cout << "get_memory: v_ptr = " << v_ptr << endl; } 00906 # endif 00907 00908 // adjust counts 00909 inc_inuse(cap_bytes, thread); 00910 00911 return v_ptr; 00912 } 00913 00914 /* ----------------------------------------------------------------------- 00915 $begin ta_return_memory$$ 00916 $spell 00917 num 00918 ptr 00919 thread_alloc 00920 $$ 00921 00922 $section Return Memory to thread_alloc$$ 00923 00924 $index return_memory, thread_alloc$$ 00925 $index thread_alloc, return_memory$$ 00926 $index memory, available$$ 00927 $index available, memory$$ 00928 $index thread, available memory$$ 00929 00930 $head Syntax$$ 00931 $codei%thread_alloc::return_memory(%v_ptr%)%$$ 00932 00933 $head Purpose$$ 00934 If $cref/hold_memory/ta_hold_memory/$$ is false, 00935 the memory is returned to the system. 00936 Otherwise, the memory is retained by $cref thread_alloc$$ for quick future use 00937 by the thread that allocated to memory. 00938 00939 $head v_ptr$$ 00940 This argument has prototype 00941 $codei% 00942 void* %v_ptr% 00943 %$$. 00944 It must be a pointer to memory that is currently in use; i.e. 00945 obtained by a previous call to 00946 $cref/get_memory/ta_get_memory/$$ and not yet returned. 00947 00948 $head Thread$$ 00949 Either the $cref/current thread/ta_thread_num/$$ must be the same as during 00950 the corresponding call to $cref/get_memory/ta_get_memory/$$, 00951 or the current execution mode must be sequential 00952 (not $cref/parallel/ta_in_parallel/$$). 00953 00954 $head NDEBUG$$ 00955 If $code NDEBUG$$ is defined, $icode v_ptr$$ is not checked (this is faster). 00956 Otherwise, a list of in use pointers is searched to make sure 00957 that $icode v_ptr$$ is in the list. 00958 00959 $head Example$$ 00960 $cref thread_alloc.cpp$$ 00961 00962 $end 00963 */ 00964 /*! 00965 Return memory that was obtained by \c get_memory. 00966 If <code>num_threads() == 1</code>, 00967 the memory is returned to the system. 00968 Otherwise, it is retained by \c thread_alloc and available for use by 00969 \c get_memory for this thread. 00970 00971 \param v_ptr [in] 00972 Value of the pointer returned by \c get_memory and still in use. 00973 After this call, this pointer will available (and not in use). 00974 00975 \par 00976 We must either be in sequential (not parallel) execution mode, 00977 or the current thread must be the same as for the corresponding call 00978 to \c get_memory. 00979 */ 00980 static void return_memory(void* v_ptr) 00981 { size_t num_cap = capacity_info()->number; 00982 00983 block_t* node = reinterpret_cast<block_t*>(v_ptr) - 1; 00984 size_t tc_index = node->tc_index_; 00985 size_t thread = tc_index / num_cap; 00986 size_t c_index = tc_index % num_cap; 00987 size_t capacity = capacity_info()->value[c_index]; 00988 00989 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS ); 00990 CPPAD_ASSERT_KNOWN( 00991 thread == thread_num() || (! in_parallel()), 00992 "Attempt to return memory for a different thread " 00993 "while in parallel mode" 00994 ); 00995 00996 thread_alloc_info* info = thread_info(thread); 00997 # ifndef NDEBUG 00998 // remove node from inuse list 00999 void* v_node = reinterpret_cast<void*>(node); 01000 block_t* inuse_root = info->root_inuse_ + c_index; 01001 block_t* previous = inuse_root; 01002 while( (previous->next_ != CPPAD_NULL) & (previous->next_ != v_node) ) 01003 previous = reinterpret_cast<block_t*>(previous->next_); 01004 01005 // check that v_ptr is valid 01006 if( previous->next_ != v_node ) 01007 { using std::endl; 01008 std::ostringstream oss; 01009 oss << "return_memory: attempt to return memory not in use"; 01010 oss << endl; 01011 oss << "v_ptr = " << v_ptr << endl; 01012 oss << "thread = " << thread << endl; 01013 oss << "capacity = " << capacity << endl; 01014 oss << "See CPPAD_TRACE_THREAD & CPPAD_TRACE_CAPACITY in"; 01015 oss << endl << "# include <cppad/thread_alloc.hpp>" << endl; 01016 CPPAD_ASSERT_KNOWN(false, oss.str().c_str() ); 01017 } 01018 01019 // trace option 01020 if( capacity==CPPAD_TRACE_CAPACITY && thread==CPPAD_TRACE_THREAD ) 01021 { std::cout << "return_memory: v_ptr = " << v_ptr << std::endl; } 01022 01023 // remove v_ptr from inuse list 01024 previous->next_ = node->next_; 01025 # endif 01026 // capacity bytes are removed from the inuse pool 01027 dec_inuse(capacity, thread); 01028 01029 // check for case where we just return the memory to the system 01030 if( ! set_get_hold_memory(false) ) 01031 { ::operator delete( reinterpret_cast<void*>(node) ); 01032 return; 01033 } 01034 01035 // add this node to available list for this thread and capacity 01036 block_t* available_root = info->root_available_ + c_index; 01037 node->next_ = available_root->next_; 01038 available_root->next_ = reinterpret_cast<void*>(node); 01039 01040 // capacity bytes are added to the available pool 01041 inc_available(capacity, thread); 01042 } 01043 /* ----------------------------------------------------------------------- 01044 $begin ta_free_available$$ 01045 $spell 01046 num 01047 thread_alloc 01048 $$ 01049 01050 $section Free Memory Currently Available for Quick Use by a Thread$$ 01051 $spell 01052 inuse 01053 $$ 01054 01055 $index free_available, thread_alloc$$ 01056 $index thread_alloc, free_available$$ 01057 $index free, available$$ 01058 $index available, free$$ 01059 $index thread, free memory$$ 01060 01061 $head Syntax$$ 01062 $codei%thread_alloc::free_available(%thread%)%$$ 01063 01064 $head Purpose$$ 01065 Return to the system all the memory that is currently being 01066 $cref/held/ta_hold_memory/$$ for quick use by the specified thread. 01067 01068 $subhead Extra Memory$$ 01069 In the case where $icode%thread% > 0%$$, 01070 some extra memory is used to track allocations by the specified thread. 01071 If 01072 $codei% 01073 thread_alloc::inuse(%thread%) == 0 01074 %$$ 01075 the extra memory is also returned to the system. 01076 01077 $head thread$$ 01078 This argument has prototype 01079 $codei% 01080 size_t %thread% 01081 %$$ 01082 Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$, 01083 or the current execution mode must be sequential 01084 (not $cref/parallel/ta_in_parallel/$$). 01085 01086 $head Example$$ 01087 $cref thread_alloc.cpp$$ 01088 01089 $end 01090 */ 01091 /*! 01092 Return all the memory being held as available for a thread to the system. 01093 01094 \param thread [in] 01095 this thread that will no longer have any available memory after this call. 01096 This must either be the thread currently executing, or we must be 01097 in sequential (not parallel) execution mode. 01098 */ 01099 static void free_available(size_t thread) 01100 { CPPAD_ASSERT_KNOWN( 01101 thread < CPPAD_MAX_NUM_THREADS, 01102 "Attempt to free memory for a thread >= CPPAD_MAX_NUM_THREADS" 01103 ); 01104 CPPAD_ASSERT_KNOWN( 01105 thread == thread_num() || (! in_parallel()), 01106 "Attempt to free memory for a different thread " 01107 "while in parallel mode" 01108 ); 01109 01110 size_t num_cap = capacity_info()->number; 01111 if( num_cap == 0 ) 01112 return; 01113 const size_t* capacity_vec = capacity_info()->value; 01114 size_t c_index; 01115 thread_alloc_info* info = thread_info(thread); 01116 for(c_index = 0; c_index < num_cap; c_index++) 01117 { size_t capacity = capacity_vec[c_index]; 01118 block_t* available_root = info->root_available_ + c_index; 01119 void* v_ptr = available_root->next_; 01120 while( v_ptr != CPPAD_NULL ) 01121 { block_t* node = reinterpret_cast<block_t*>(v_ptr); 01122 void* next = node->next_; 01123 ::operator delete(v_ptr); 01124 v_ptr = next; 01125 01126 dec_available(capacity, thread); 01127 } 01128 available_root->next_ = CPPAD_NULL; 01129 } 01130 CPPAD_ASSERT_UNKNOWN( available(thread) == 0 ); 01131 if( inuse(thread) == 0 ) 01132 { // clear the information for this thread 01133 thread_info(thread, true); 01134 } 01135 } 01136 /* ----------------------------------------------------------------------- 01137 $begin ta_hold_memory$$ 01138 $spell 01139 alloc 01140 num 01141 $$ 01142 01143 $section Control When Thread Alloc Retains Memory For Future Use$$ 01144 $index thread_alloc, hold memory$$ 01145 $index hold, thread_alloc memory$$ 01146 $index memory, thread_alloc hold$$ 01147 01148 $head Syntax$$ 01149 $codei%thread_alloc::hold_memory(%value%)%$$ 01150 01151 $head Purpose$$ 01152 It should be faster, even when $icode num_thread$$ is equal to one, 01153 for $code thread_alloc$$ to hold onto memory. 01154 Calling $icode hold_memory$$ with $icode value$$ equal to true, 01155 instructs $code thread_alloc$$ to hold onto memory, 01156 and put it in the $cref/available/ta_available/$$ pool, 01157 after each call to $cref/return_memory/ta_return_memory/$$. 01158 01159 $head value$$ 01160 If $icode value$$ is true, 01161 $code thread_alloc$$ with hold onto memory for future quick use. 01162 If it is false, future calls to $cref/return_memory/ta_return_memory/$$ 01163 will return the corresponding memory to the system. 01164 By default (when $code hold_memory$$ has not been called) 01165 $code thread_alloc$$ does not hold onto memory. 01166 01167 $head free_available$$ 01168 Memory that is being held by $code thread_alloc$$ can be returned 01169 to the system using $cref/free_available/ta_free_available/$$. 01170 01171 $end 01172 */ 01173 /*! 01174 Change the thread_alloc hold memory setting. 01175 01176 \param value [in] 01177 New value for the thread_alloc hold memory setting. 01178 */ 01179 static void hold_memory(bool value) 01180 { bool set = true; 01181 set_get_hold_memory(set, value); 01182 } 01183 01184 /* ----------------------------------------------------------------------- 01185 $begin ta_inuse$$ 01186 $spell 01187 num 01188 inuse 01189 thread_alloc 01190 $$ 01191 01192 $section Amount of Memory a Thread is Currently Using$$ 01193 01194 $index inuse, thread_alloc$$ 01195 $index thread_alloc, inuse$$ 01196 $index use, memory$$ 01197 $index thread, memory inuse$$ 01198 01199 $head Syntax$$ 01200 $icode%num_bytes% = thread_alloc::inuse(%thread%)%$$ 01201 01202 $head Purpose$$ 01203 Memory being managed by $cref thread_alloc$$ has two states, 01204 currently in use by the specified thread, 01205 and quickly available for future use by the specified thread. 01206 This function informs the program how much memory is in use. 01207 01208 $head thread$$ 01209 This argument has prototype 01210 $codei% 01211 size_t %thread% 01212 %$$ 01213 Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$, 01214 or the current execution mode must be sequential 01215 (not $cref/parallel/ta_in_parallel/$$). 01216 01217 $head num_bytes$$ 01218 The return value has prototype 01219 $codei% 01220 size_t %num_bytes% 01221 %$$ 01222 It is the number of bytes currently in use by the specified thread. 01223 01224 $head Example$$ 01225 $cref thread_alloc.cpp$$ 01226 01227 $end 01228 */ 01229 /*! 01230 Determine the amount of memory that is currently inuse. 01231 01232 \param thread [in] 01233 Thread for which we are determining the amount of memory 01234 (must be < CPPAD_MAX_NUM_THREADS). 01235 Durring parallel execution, this must be the thread 01236 that is currently executing. 01237 01238 \return 01239 The amount of memory in bytes. 01240 */ 01241 static size_t inuse(size_t thread) 01242 { 01243 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); 01244 CPPAD_ASSERT_UNKNOWN( 01245 thread == thread_num() || (! in_parallel()) 01246 ); 01247 thread_alloc_info* info = thread_info(thread); 01248 return info->count_inuse_; 01249 } 01250 /* ----------------------------------------------------------------------- 01251 $begin ta_available$$ 01252 $spell 01253 num 01254 thread_alloc 01255 $$ 01256 01257 $section Amount of Memory Available for Quick Use by a Thread$$ 01258 01259 $index available, thread_alloc$$ 01260 $index thread_alloc, available$$ 01261 $index memory, available$$ 01262 $index thread, available memory$$ 01263 01264 $head Syntax$$ 01265 $icode%num_bytes% = thread_alloc::available(%thread%)%$$ 01266 01267 $head Purpose$$ 01268 Memory being managed by $cref thread_alloc$$ has two states, 01269 currently in use by the specified thread, 01270 and quickly available for future use by the specified thread. 01271 This function informs the program how much memory is available. 01272 01273 $head thread$$ 01274 This argument has prototype 01275 $codei% 01276 size_t %thread% 01277 %$$ 01278 Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$, 01279 or the current execution mode must be sequential 01280 (not $cref/parallel/ta_in_parallel/$$). 01281 01282 $head num_bytes$$ 01283 The return value has prototype 01284 $codei% 01285 size_t %num_bytes% 01286 %$$ 01287 It is the number of bytes currently available for use by the specified thread. 01288 01289 $head Example$$ 01290 $cref thread_alloc.cpp$$ 01291 01292 $end 01293 */ 01294 /*! 01295 Determine the amount of memory that is currently available for use. 01296 01297 \copydetails inuse 01298 */ 01299 static size_t available(size_t thread) 01300 { 01301 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); 01302 CPPAD_ASSERT_UNKNOWN( 01303 thread == thread_num() || (! in_parallel()) 01304 ); 01305 thread_alloc_info* info = thread_info(thread); 01306 return info->count_available_; 01307 } 01308 /* ----------------------------------------------------------------------- 01309 $begin ta_create_array$$ 01310 $spell 01311 inuse 01312 thread_alloc 01313 sizeof 01314 $$ 01315 01316 $section Allocate An Array and Call Default Constructor for its Elements$$ 01317 01318 $index create_array, thread_alloc$$ 01319 $index thread_alloc, create_array$$ 01320 $index array, allocate$$ 01321 $index allocate, array$$ 01322 01323 $head Syntax$$ 01324 $icode%array% = thread_alloc::create_array<%Type%>(%size_min%, %size_out%)%$$. 01325 01326 $head Purpose$$ 01327 Create a new raw array using $cref thread_alloc$$ memory allocator 01328 (works well in a multi-threading environment) 01329 and call default constructor for each element. 01330 01331 $head Type$$ 01332 The type of the elements of the array. 01333 01334 $head size_min$$ 01335 This argument has prototype 01336 $codei% 01337 size_t %size_min% 01338 %$$ 01339 This is the minimum number of elements that there can be 01340 in the resulting $icode array$$. 01341 01342 $head size_out$$ 01343 This argument has prototype 01344 $codei% 01345 size_t& %size_out% 01346 %$$ 01347 The input value of this argument does not matter. 01348 Upon return, it is the actual number of elements 01349 in $icode array$$ 01350 ($icode% size_min %<=% size_out%$$). 01351 01352 $head array$$ 01353 The return value $icode array$$ has prototype 01354 $codei% 01355 %Type%* %array% 01356 %$$ 01357 It is array with $icode size_out$$ elements. 01358 The default constructor for $icode Type$$ is used to initialize the 01359 elements of $icode array$$. 01360 Note that $cref/delete_array/ta_delete_array/$$ 01361 should be used to destroy the array when it is no longer needed. 01362 01363 $head Delta$$ 01364 The amount of memory $cref/inuse/ta_inuse/$$ by the current thread, 01365 will increase $icode delta$$ where 01366 $codei% 01367 sizeof(%Type%) * (%size_out% + 1) > %delta% >= sizeof(%Type%) * %size_out% 01368 %$$ 01369 The $cref/available/ta_available/$$ memory will decrease by $icode delta$$, 01370 (and the allocation will be faster) 01371 if a previous allocation with $icode size_min$$ between its current value 01372 and $icode size_out$$ is available. 01373 01374 $head Example$$ 01375 $cref thread_alloc.cpp$$ 01376 01377 $end 01378 */ 01379 /*! 01380 Use thread_alloc to allocate an array, then call default construtor 01381 for each element. 01382 01383 \tparam Type 01384 The type of the elements of the array. 01385 01386 \param size_min [in] 01387 The minimum number of elements in the array. 01388 01389 \param size_out [out] 01390 The actual number of elements in the array. 01391 01392 \return 01393 pointer to the first element of the array. 01394 The default constructor is used to initialize 01395 all the elements of the array. 01396 01397 \par 01398 The \c extra_ field, in the \c thread_alloc node before the return value, 01399 is set to size_out. 01400 */ 01401 template <class Type> 01402 static Type* create_array(size_t size_min, size_t& size_out) 01403 { // minimum number of bytes to allocate 01404 size_t min_bytes = size_min * sizeof(Type); 01405 // do the allocation 01406 size_t num_bytes; 01407 void* v_ptr = get_memory(min_bytes, num_bytes); 01408 // This is where the array starts 01409 Type* array = reinterpret_cast<Type*>(v_ptr); 01410 // number of Type values in the allocation 01411 size_out = num_bytes / sizeof(Type); 01412 // store this number in the extra field 01413 block_t* node = reinterpret_cast<block_t*>(v_ptr) - 1; 01414 node->extra_ = size_out; 01415 01416 // call default constructor for each element 01417 size_t i; 01418 for(i = 0; i < size_out; i++) 01419 new(array + i) Type(); 01420 01421 return array; 01422 } 01423 /* ----------------------------------------------------------------------- 01424 $begin ta_delete_array$$ 01425 $spell 01426 inuse 01427 thread_alloc 01428 sizeof 01429 deallocate 01430 $$ 01431 01432 $section Deallocate An Array and Call Destructor for its Elements$$ 01433 01434 $index delete_array, thread_alloc$$ 01435 $index thread_alloc, delete_array$$ 01436 $index array, allocate$$ 01437 $index allocate, array$$ 01438 01439 $head Syntax$$ 01440 $codei%thread_alloc::delete_array(%array%)%$$. 01441 01442 $head Purpose$$ 01443 Returns memory corresponding to an array created by 01444 (create by $cref/create_array/ta_create_array/$$) to the 01445 $cref/available/ta_available/$$ memory pool for the current thread. 01446 01447 $head Type$$ 01448 The type of the elements of the array. 01449 01450 $head array$$ 01451 The argument $icode array$$ has prototype 01452 $codei% 01453 %Type%* %array% 01454 %$$ 01455 It is a value returned by $cref/create_array/ta_create_array/$$ and not yet deleted. 01456 The $icode Type$$ destructor is called for each element in the array. 01457 01458 $head Thread$$ 01459 The $cref/current thread/ta_thread_num/$$ must be the 01460 same as when $cref/create_array/ta_create_array/$$ returned the value $icode array$$. 01461 There is an exception to this rule: 01462 when the current execution mode is sequential 01463 (not $cref/parallel/ta_in_parallel/$$) the current thread number does not matter. 01464 01465 $head Delta$$ 01466 The amount of memory $cref/inuse/ta_inuse/$$ will decrease by $icode delta$$, 01467 and the $cref/available/ta_available/$$ memory will increase by $icode delta$$, 01468 where $cref/delta/ta_create_array/Delta/$$ 01469 is the same as for the corresponding call to $code create_array$$. 01470 01471 $head Example$$ 01472 $cref thread_alloc.cpp$$ 01473 01474 $end 01475 */ 01476 /*! 01477 Return Memory Used for an Array to the Available Pool 01478 (include destructor call for each element). 01479 01480 \tparam Type 01481 The type of the elements of the array. 01482 01483 \param array [in] 01484 A value returned by \c create_array that has not yet been deleted. 01485 The \c Type destructor is used to destroy each of the elements 01486 of the array. 01487 01488 \par 01489 Durring parallel execution, the current thread must be the same 01490 as during the corresponding call to \c create_array. 01491 */ 01492 template <class Type> 01493 static void delete_array(Type* array) 01494 { // determine the number of values in the array 01495 block_t* node = reinterpret_cast<block_t*>(array) - 1; 01496 size_t size = node->extra_; 01497 01498 // call destructor for each element 01499 size_t i; 01500 for(i = 0; i < size; i++) 01501 (array + i)->~Type(); 01502 01503 // return the memory to the available pool for this thread 01504 thread_alloc::return_memory( reinterpret_cast<void*>(array) ); 01505 } 01506 /* ----------------------------------------------------------------------- 01507 $begin ta_free_all$$ 01508 $spell 01509 alloc 01510 bool 01511 inuse 01512 $$ 01513 01514 $section Free All Memory That Was Allocated for Use by thread_alloc$$ 01515 01516 $index free, all thread_alloc$$ 01517 $index thread_alloc, free all$$ 01518 01519 $head Syntax$$ 01520 $icode%ok% = thread_alloc::free_all()%$$. 01521 01522 $head Purpose$$ 01523 Returns all memory that was used by $code thread_alloc$$ to the system. 01524 01525 $head ok$$ 01526 The return value $icode ok$$ has prototype 01527 $codei% 01528 bool %ok% 01529 %$$ 01530 Its value will be $code true$$ if all the memory can be freed. 01531 This requires that for all $icode thread$$ indices, there is no memory 01532 $cref/inuse/ta_inuse/$$; i.e., 01533 $codei% 01534 0 == thread_alloc::inuse(%thread%) 01535 %$$ 01536 Otherwise, the return value will be false. 01537 01538 $head Restrictions$$ 01539 This function cannot be called while in parallel mode. 01540 01541 $head Example$$ 01542 $cref thread_alloc.cpp$$ 01543 $end 01544 */ 01545 /*! 01546 Return to the system all thread_alloc memory that is not currently inuse. 01547 01548 \return 01549 If no \c thread_alloc memory is currently inuse, 01550 all memory is returned to the system and the return value is true. 01551 Otherwise the return value is false. 01552 */ 01553 static bool free_all(void) 01554 { CPPAD_ASSERT_KNOWN( 01555 ! in_parallel(), 01556 "free_all cannot be used while in parallel execution" 01557 ); 01558 bool ok = true; 01559 size_t thread = CPPAD_MAX_NUM_THREADS; 01560 while(thread--) 01561 { ok &= inuse(thread) == 0; 01562 free_available(thread); 01563 } 01564 return ok; 01565 } 01566 }; 01567 01568 01569 } // END_CPPAD_NAMESPACE 01570 01571 // preprocessor symbols local to this file 01572 # undef CPPAD_MAX_NUM_CAPACITY 01573 # undef CPPAD_MIN_DOUBLE_CAPACITY 01574 # undef CPPAD_TRACE_CAPACITY 01575 # undef CPPAD_TRACE_THREAD 01576 # endif