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