CppAD: A C++ Algorithmic Differentiation Package 20110419
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_TRACK_NEW_DEL_INCLUDED 00003 # define CPPAD_TRACK_NEW_DEL_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-08 Bradley M. Bell 00007 00008 CppAD is distributed under multiple licenses. This distribution is under 00009 the terms of the 00010 Common 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 $begin TrackNewDel$$ 00017 $spell 00018 cppad.hpp 00019 Cpp 00020 newptr 00021 Vec 00022 oldptr 00023 newlen 00024 ncopy 00025 const 00026 $$ 00027 00028 $section Routines That Track Use of New and Delete$$ 00029 $index new, track$$ 00030 $index delete, track$$ 00031 $index track, new and delete$$ 00032 $index memory, track$$ 00033 00034 $head Syntax$$ 00035 $syntax%# include <cppad/track_new_del.hpp> 00036 %$$ 00037 $syntax%%newptr% = TrackNewVec(%file%, %line%, %newlen%, %oldptr%) 00038 %$$ 00039 $syntax%TrackDelVec(%file%, %line%, %oldptr%) 00040 %$$ 00041 $syntax%%newptr% = TrackExtend(%file%, %line%, %newlen%, %ncopy%, %oldptr%) 00042 %$$ 00043 $syntax%%count% = TrackCount(%file%, %line%)%$$ 00044 00045 00046 $head Purpose$$ 00047 These routines 00048 aid in the use of $code new[]$$ and $code delete[]$$ 00049 during the execution of a C++ program. 00050 00051 $head Include$$ 00052 The file $code cppad/track_new_del.hpp$$ is included by 00053 $code cppad/cppad.hpp$$ 00054 but it can also be included separately with out the rest of the 00055 CppAD include files. 00056 00057 00058 $head file$$ 00059 The argument $italic file$$ has prototype 00060 $syntax% 00061 const char *%file% 00062 %$$ 00063 It should be the source code file name 00064 where the call to $code TrackNew$$ is located. 00065 The best way to accomplish this is the use the preprocessor symbol 00066 $code __FILE__$$ for this argument. 00067 00068 $head line$$ 00069 The argument $italic line$$ has prototype 00070 $syntax% 00071 int %line% 00072 %$$ 00073 It should be the source code file line number 00074 where the call to $code TrackNew$$ is located. 00075 The best way to accomplish this is the use the preprocessor symbol 00076 $code __LINE__$$ for this argument. 00077 00078 $head oldptr$$ 00079 The argument $italic oldptr$$ has prototype 00080 $syntax% 00081 %Type% *%oldptr% 00082 %$$ 00083 This argument is used to identify the type $italic Type$$. 00084 00085 $subhead OpenMP$$ 00086 $index OpenMP, TrackNewDel$$ 00087 $index TrackNewDel, OpenMP$$ 00088 In the case of multi-threading with OpenMP, 00089 calls with the argument $italic oldptr$$ must be made with the 00090 same thread as when $italic oldptr$$ was created 00091 (except for $code TrackNewVec$$ where the value of $italic oldptr$$ 00092 does not matter). 00093 00094 00095 $head newlen$$ 00096 The argument $italic newlen$$ has prototype 00097 $syntax% 00098 size_t %newlen% 00099 %$$ 00100 00101 $head head newptr$$ 00102 The return value $italic newptr$$ has prototype 00103 $syntax% 00104 %Type% *%newptr% 00105 %$$ 00106 It points to the newly allocated vector of objects 00107 that were allocated using 00108 $syntax% 00109 new Type[%newlen%] 00110 %$$ 00111 00112 $head ncopy$$ 00113 The argument $italic ncopy$$ has prototype 00114 $syntax% 00115 size_t %ncopy% 00116 %$$ 00117 This specifies the number of elements that are copied from 00118 the old array to the new array. 00119 The value of $italic ncopy$$ 00120 must be less than or equal $italic newlen$$. 00121 00122 $head TrackNewVec$$ 00123 $index TrackNewVec$$ 00124 $index NDEBUG$$ 00125 If $code NDEBUG$$ is defined, this routine only sets 00126 $syntax% 00127 %newptr% = %Type% new[%newlen%] 00128 %$$ 00129 The value of $italic oldptr$$ does not matter 00130 (except that it is used to identify $italic Type$$). 00131 If $code NDEBUG$$ is not defined, $code TrackNewVec$$ also 00132 tracks the this memory allocation. 00133 In this case, if memory cannot be allocated 00134 $xref/ErrorHandler/$$ is used to generate a message 00135 stating that there was not sufficient memory. 00136 00137 $subhead Macro$$ 00138 $index CPPAD_TRACK_NEW_VEC$$ 00139 The preprocessor macro call 00140 $syntax% 00141 CPPAD_TRACK_NEW_VEC(%newlen%, %oldptr%) 00142 %$$ 00143 expands to 00144 $syntax% 00145 CppAD::TrackNewVec(__FILE__, __LINE__, %newlen%, %oldptr%) 00146 %$$ 00147 00148 $subhead Deprecated$$ 00149 $index CppADTrackNewVec$$ 00150 The preprocessor macro $code CppADTrackNewVec$$ is the 00151 same as $code CPPAD_TRACK_NEW_VEC$$. 00152 It has been deprecated; i.e., 00153 it is still defined in the CppAD distribution, but it should 00154 not be used. 00155 00156 $head TrackDelVec$$ 00157 $index TrackDelVec$$ 00158 This routine is used to a vector of objects 00159 that have been allocated using $code TrackNew$$ or $code TrackExtend$$. 00160 If $code NDEBUG$$ is defined, this routine only frees memory with 00161 $syntax% 00162 delete [] %oldptr% 00163 %$$ 00164 If $code NDEBUG$$ is not defined, $code TrackDelete$$ also checks that 00165 $italic oldptr$$ was allocated by $code TrackNew$$ or $code TrackExtend$$ 00166 and has not yet been freed. 00167 If this is not the case, 00168 $xref/ErrorHandler/$$ is used to generate an error message. 00169 00170 $subhead Macro$$ 00171 $index CPPAD_TRACK_DEL_VEC$$ 00172 The preprocessor macro call 00173 $syntax% 00174 CPPAD_TRACK_DEL_VEC(%oldptr%) 00175 %$$ 00176 expands to 00177 $syntax% 00178 CppAD::TrackDelVec(__FILE__, __LINE__, %oldptr%) 00179 %$$ 00180 00181 $subhead Deprecated$$ 00182 $index CppADTrackDelVec$$ 00183 The preprocessor macro $code CppADTrackDelVec$$ is the 00184 same as $code CPPAD_TRACK_DEL_VEC$$. 00185 It has been deprecated; i.e., 00186 it is still defined in the CppAD distribution, but it should 00187 not be used. 00188 00189 $head TrackExtend$$ 00190 $index TrackExtend$$ 00191 This routine is used to 00192 allocate a new vector (using $code TrackNewVec$$), 00193 copy $italic ncopy$$ elements from the old vector to the new vector. 00194 If $italic ncopy$$ is greater than zero, $italic oldptr$$ 00195 must have been allocated using $code TrackNewVec$$ or $code TrackExtend$$. 00196 In this case, the vector pointed to by $italic oldptr$$ 00197 must be have at least $italic ncopy$$ elements 00198 and it will be deleted (using $code TrackDelVec$$). 00199 Note that the dependence of $code TrackExtend$$ on $code NDEBUG$$ 00200 is indirectly through the routines $code TrackNewVec$$ and 00201 $code TrackDelVec$$. 00202 00203 $subhead Macro$$ 00204 $index CPPAD_TRACK_EXTEND$$ 00205 The preprocessor macro call 00206 $syntax% 00207 CPPAD_TRACK_EXTEND(%newlen%, %ncopy%, %oldptr%) 00208 %$$ 00209 expands to 00210 $syntax% 00211 CppAD::TrackExtend(__FILE__, __LINE__, %newlen%, %ncopy%, %oldptr%) 00212 %$$ 00213 00214 $subhead Deprecated$$ 00215 $index CppADTrackExtend$$ 00216 The preprocessor macro $code CppADTrackExtend$$ is the 00217 same as $code CPPAD_TRACK_EXTEND$$. 00218 It has been deprecated; i.e., 00219 it is still defined in the CppAD distribution, but it should 00220 not be used. 00221 00222 $head TrackCount$$ 00223 $index TrackCount$$ 00224 The return value $italic count$$ has prototype 00225 $syntax% 00226 size_t %count% 00227 %$$ 00228 If $code NDEBUG$$ is defined, $italic count$$ will be zero. 00229 Otherwise, it will be 00230 the number of vectors that 00231 have been allocated 00232 (by $code TrackNewVec$$ or $code TrackExtend$$) 00233 and not yet freed 00234 (by $code TrackDelete$$). 00235 00236 $subhead Macro$$ 00237 $index CPPAD_TRACK_COUNT$$ 00238 The preprocessor macro call 00239 $syntax% 00240 CPPAD_TRACK_COUNT() 00241 %$$ 00242 expands to 00243 $syntax% 00244 CppAD::TrackCount(__FILE__, __LINE__) 00245 %$$ 00246 00247 $subhead Deprecated$$ 00248 $index CppADTrackNewVec$$ 00249 The preprocessor macro $code CppADTrackCount$$ is the 00250 same as $code CPPAD_TRACK_COUNT$$. 00251 It has been deprecated; i.e., 00252 it is still defined in the CppAD distribution, but it should 00253 not be used. 00254 00255 $subhead OpenMP$$ 00256 $index OpenMP, TrackCount$$ 00257 $index TrackCount, OpenMP$$ 00258 In the case of multi-threading with OpenMP, 00259 the information for all of the threads is checked 00260 so only one thread can be running 00261 when this routine is called. 00262 00263 $head Example$$ 00264 $children% 00265 example/track_new_del.cpp 00266 %$$ 00267 The file $xref/TrackNewDel.cpp/$$ 00268 contains an example and test of these functions. 00269 It returns true, if it succeeds, and false otherwise. 00270 00271 $end 00272 ------------------------------------------------------------------------------ 00273 */ 00274 # include <cppad/local/cppad_assert.hpp> 00275 # include <sstream> 00276 # include <string> 00277 00278 # ifdef _OPENMP 00279 # include <omp.h> 00280 # endif 00281 00282 00283 # ifndef CPPAD_NULL 00284 # define CPPAD_NULL 0 00285 # endif 00286 00287 # ifndef CPPAD_MAX_NUM_THREADS 00288 # ifdef _OPENMP 00289 # define CPPAD_MAX_NUM_THREADS 32 00290 # else 00291 # define CPPAD_MAX_NUM_THREADS 1 00292 # endif 00293 # endif 00294 00295 # define CPPAD_TRACK_DEBUG 0 00296 00297 // ------------------------------------------------------------------------- 00298 # define CPPAD_TRACK_NEW_VEC(newlen, oldptr) \ 00299 CppAD::TrackNewVec(__FILE__, __LINE__, newlen, oldptr) 00300 00301 # define CPPAD_TRACK_DEL_VEC(oldptr) \ 00302 CppAD::TrackDelVec(__FILE__, __LINE__, oldptr) 00303 00304 # define CPPAD_TRACK_EXTEND(newlen, ncopy, oldptr) \ 00305 CppAD::TrackExtend(__FILE__, __LINE__, newlen, ncopy, oldptr) 00306 00307 # define CPPAD_TRACK_COUNT() \ 00308 CppAD::TrackCount(__FILE__, __LINE__) 00309 // ------------------------------------------------------------------------- 00310 # define CppADTrackNewVec CPPAD_TRACK_NEW_VEC 00311 # define CppADTrackDelVec CPPAD_TRACK_DEL_VEC 00312 # define CppADTrackExtend CPPAD_TRACK_EXTEND 00313 # define CppADTrackCount CPPAD_TRACK_COUNT 00314 // ------------------------------------------------------------------------- 00315 namespace CppAD { // Begin CppAD namespace 00316 00317 // TrackElement ------------------------------------------------------------ 00318 class TrackElement { 00319 00320 public: 00321 std::string file; // corresponding file name 00322 int line; // corresponding line number 00323 void *ptr; // value returned by TrackNew 00324 TrackElement *next; // next element in linked list 00325 00326 // default contructor (used to initialize root) 00327 TrackElement(void) 00328 : file(""), line(0), ptr(CPPAD_NULL), next(CPPAD_NULL) 00329 { } 00330 00331 TrackElement(const char *f, int l, void *p) 00332 : file(f), line(l), ptr(p), next(CPPAD_NULL) 00333 { CPPAD_ASSERT_UNKNOWN( p != CPPAD_NULL); 00334 } 00335 00336 // There is only one tracking list and it starts it here 00337 static TrackElement *root_for(size_t thread) 00338 { static TrackElement root[CPPAD_MAX_NUM_THREADS]; 00339 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS ); 00340 return root + thread; 00341 } 00342 00343 // There is only one tracking list and it starts it here 00344 static TrackElement *Root(void) 00345 { 00346 # ifdef _OPENMP 00347 size_t thread = static_cast<size_t> ( omp_get_thread_num() ); 00348 # else 00349 size_t thread = 0; 00350 # endif 00351 CPPAD_ASSERT_KNOWN( 00352 thread < CPPAD_MAX_NUM_THREADS, 00353 "TrackNewDel: too many OpenMP threads are active." 00354 ); 00355 return root_for(thread); 00356 } 00357 00358 // Print the linked list 00359 static void Print(size_t thread) 00360 { using std::cout; 00361 using std::endl; 00362 TrackElement *E = Root(); 00363 // convert int(size_t) to avoid warning on _MSC_VER systems 00364 cout << "Begin Track List for thread " << int(thread) << endl; 00365 while( E->next != CPPAD_NULL ) 00366 { E = E->next; 00367 cout << "next = " << E->next; 00368 cout << ", ptr = " << E->ptr; 00369 cout << ", line = " << E->line; 00370 cout << ", file = " << E->file; 00371 cout << endl; 00372 } 00373 cout << "End Track List for thread " << int(thread) << endl; 00374 cout << endl; 00375 } 00376 }; 00377 00378 00379 // TrackError ---------------------------------------------------------------- 00380 inline void TrackError( 00381 const char *routine, 00382 const char *file, 00383 int line, 00384 const char *msg ) 00385 { 00386 std::ostringstream buf; 00387 buf << routine 00388 << ": at line " 00389 << line 00390 << " in file " 00391 << file 00392 << std::endl 00393 << msg; 00394 std::string str = buf.str(); 00395 size_t n = str.size(); 00396 size_t i; 00397 char *message = new char[n + 1]; 00398 for(i = 0; i < n; i++) 00399 message[i] = str[i]; 00400 message[n] = '\0'; 00401 CPPAD_ASSERT_KNOWN( false , message); 00402 } 00403 00404 // TrackNewVec --------------------------------------------------------------- 00405 # ifdef NDEBUG 00406 template <class Type> 00407 inline Type *TrackNewVec( 00408 const char *file, int line, size_t len, Type * /* oldptr */ ) 00409 { return (new Type[len]); 00410 } 00411 00412 # else 00413 00414 template <class Type> 00415 Type *TrackNewVec( 00416 const char *file , 00417 int line , 00418 size_t len , 00419 Type * /* oldptr */ ) 00420 { 00421 // try to allocate the new memrory 00422 Type *newptr = CPPAD_NULL; 00423 try 00424 { newptr = new Type[len]; 00425 } 00426 catch(...) 00427 { TrackError("TrackNewVec", file, line, 00428 "Cannot allocate sufficient memory" 00429 ); 00430 } 00431 // create tracking element 00432 void *vptr = static_cast<void *>(newptr); 00433 TrackElement *E = new TrackElement(file, line, vptr); 00434 00435 // get the root 00436 TrackElement *root = TrackElement::Root(); 00437 00438 // put this elemenent at the front of linked list 00439 E->next = root->next; 00440 root->next = E; 00441 00442 return newptr; 00443 } 00444 00445 # endif 00446 00447 // TrackDelVec -------------------------------------------------------------- 00448 # ifdef NDEBUG 00449 template <class Type> 00450 inline void TrackDelVec(const char *file, int line, Type *oldptr) 00451 { delete [] oldptr; 00452 } 00453 00454 # else 00455 00456 template <class Type> 00457 void TrackDelVec( 00458 const char *file , 00459 int line , 00460 Type *oldptr ) 00461 { 00462 TrackElement *P; 00463 TrackElement *E; 00464 00465 // search list for pointer 00466 P = TrackElement::Root(); 00467 E = P->next; 00468 void *vptr = static_cast<void *>(oldptr); 00469 while(E != CPPAD_NULL && E->ptr != vptr) 00470 { P = E; 00471 E = E->next; 00472 } 00473 00474 // check if pointer was not in list 00475 if( E == CPPAD_NULL || E->ptr != vptr ) TrackError( 00476 "TrackDelVec", file, line, 00477 "Invalid value for the argument oldptr.\n" 00478 "Possible linking of debug and NDEBUG compliations of CppAD." 00479 ); 00480 00481 // remove tracking element from list 00482 P->next = E->next; 00483 00484 // delete allocated pointer 00485 delete [] oldptr; 00486 00487 // delete tracking element 00488 delete E; 00489 00490 return; 00491 } 00492 00493 # endif 00494 00495 // TrackExtend -------------------------------------------------------------- 00496 template <class Type> 00497 Type *TrackExtend( 00498 const char *file , 00499 int line , 00500 size_t newlen , 00501 size_t ncopy , 00502 Type *oldptr ) 00503 { // check size of ncopy 00504 CPPAD_ASSERT_KNOWN( 00505 ncopy <= newlen, 00506 "TrackExtend: ncopy is greater than newlen." 00507 ); 00508 00509 // allocate the new memrory 00510 Type *newptr = TrackNewVec(file, line, newlen, oldptr); 00511 00512 // copy the data 00513 size_t i = ncopy; 00514 while(i) 00515 { --i; 00516 newptr[i] = oldptr[i]; 00517 } 00518 00519 // delete the old vector 00520 if( ncopy > 0 ) 00521 TrackDelVec(file, line, oldptr); 00522 00523 return newptr; 00524 } 00525 00526 // TrackCount -------------------------------------------------------------- 00527 inline size_t TrackCount(const char *file, int line) 00528 { 00529 size_t count = 0; 00530 size_t thread; 00531 for(thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) 00532 { 00533 TrackElement *E = TrackElement::root_for(thread); 00534 # if CPPAD_TRACK_DEBUG 00535 if( E->next != CPPAD_NULL ) 00536 TrackElement::Print(thread); 00537 # endif 00538 00539 while( E->next != CPPAD_NULL ) 00540 { ++count; 00541 E = E->next; 00542 } 00543 } 00544 return count; 00545 } 00546 // --------------------------------------------------------------------------- 00547 00548 } // End CppAD namespace 00549 00550 # undef CppADDebugTrack 00551 00552 # endif