|
PAPI
5.0.1.0
|
00001 00016 #define IN_MEM_FILE 00017 00018 #include <stdio.h> 00019 #include <stdlib.h> 00020 #include <string.h> 00021 #include "papi.h" 00022 #include "papi_lock.h" 00023 #include "papi_memory.h" 00024 #include "papi_internal.h" 00025 00026 00031 #define MEM_PROLOG (2*sizeof(void *)) 00032 00033 /* If you are tracing memory, then DEBUG must be set also. */ 00034 #ifdef DEBUG 00035 00038 #define MEM_EPILOG 4 00039 #define MEM_EPILOG_1 0xC 00040 #define MEM_EPILOG_2 0xA 00041 #define MEM_EPILOG_3 0xC 00042 #define MEM_EPILOG_4 0xA 00043 #endif 00044 00045 /* Local global variables */ 00046 static pmem_t *mem_head = NULL; 00047 00048 /* Local Prototypes */ 00049 static pmem_t *get_mem_ptr( void *ptr ); 00050 static pmem_t *init_mem_ptr( void *, int, char *, int ); 00051 static void insert_mem_ptr( pmem_t * ); 00052 static void remove_mem_ptr( pmem_t * ); 00053 static int set_epilog( pmem_t * mem_ptr ); 00054 00055 /********************************************************************** 00056 * Exposed papi versions of std memory management routines: * 00057 * _papi_realloc * 00058 * _papi_calloc * 00059 * _papi_malloc * 00060 * _papi_strdup * 00061 * _papi_free * 00062 * _papi_valid_free * 00063 * Exposed useful papi memory maintenance routines: * 00064 * _papi_mem_print_info * 00065 * _papi_mem_print_stats * 00066 * _papi_mem_overhead * 00067 * _papi_mem_cleanup_all * 00068 * _papi_mem_check_buf_overflow * 00069 * _papi_mem_check_all_overflow * 00070 **********************************************************************/ 00071 00076 void * 00077 _papi_realloc( char *file, int line, void *ptr, size_t size ) 00078 { 00079 size_t nsize = size + MEM_PROLOG; 00080 pmem_t *mem_ptr; 00081 void *nptr; 00082 00083 #ifdef DEBUG 00084 nsize += MEM_EPILOG; 00085 _papi_hwi_lock( MEMORY_LOCK ); 00086 _papi_mem_check_all_overflow( ); 00087 #endif 00088 00089 if ( !ptr ) 00090 return ( _papi_malloc( file, line, size ) ); 00091 00092 mem_ptr = get_mem_ptr( ptr ); 00093 nptr = ( pmem_t * ) realloc( ( ( char * ) ptr - MEM_PROLOG ), nsize ); 00094 00095 if ( !nptr ) 00096 return ( NULL ); 00097 00098 mem_ptr->size = ( int ) size; 00099 mem_ptr->ptr = ( char * ) nptr + MEM_PROLOG; 00100 #ifdef DEBUG 00101 strncpy( mem_ptr->file, file, DEBUG_FILE_LEN ); 00102 mem_ptr->file[DEBUG_FILE_LEN - 1] = '\0'; 00103 mem_ptr->line = line; 00104 set_epilog( mem_ptr ); 00105 _papi_hwi_unlock( MEMORY_LOCK ); 00106 #endif 00107 MEMDBG( "%p: Re-allocated: %lu bytes from File: %s Line: %d\n", 00108 mem_ptr->ptr, ( unsigned long ) size, file, line ); 00109 return ( mem_ptr->ptr ); 00110 } 00111 00112 void * 00113 _papi_calloc( char *file, int line, size_t nmemb, size_t size ) 00114 { 00115 void *ptr = _papi_malloc( file, line, size * nmemb ); 00116 00117 if ( !ptr ) 00118 return ( NULL ); 00119 memset( ptr, 0, size * nmemb ); 00120 return ( ptr ); 00121 } 00122 00123 void * 00124 _papi_malloc( char *file, int line, size_t size ) 00125 { 00126 void *ptr; 00127 void **tmp; 00128 pmem_t *mem_ptr; 00129 size_t nsize = size + MEM_PROLOG; 00130 00131 #ifdef DEBUG 00132 nsize += MEM_EPILOG; 00133 #endif 00134 00135 if ( size == 0 ) { 00136 MEMDBG( "Attempting to allocate %lu bytes from File: %s Line: %d\n", 00137 ( unsigned long ) size, file, line ); 00138 return ( NULL ); 00139 } 00140 00141 ptr = ( void * ) malloc( nsize ); 00142 00143 if ( !ptr ) 00144 return ( NULL ); 00145 else { 00146 if ( ( mem_ptr = 00147 init_mem_ptr( ( char * ) ptr + MEM_PROLOG, ( int ) size, file, 00148 line ) ) == NULL ) { 00149 free( ptr ); 00150 return ( NULL ); 00151 } 00152 tmp = ptr; 00153 *tmp = mem_ptr; 00154 ptr = mem_ptr->ptr; 00155 mem_ptr->ptr = ptr; 00156 _papi_hwi_lock( MEMORY_LOCK ); 00157 insert_mem_ptr( mem_ptr ); 00158 set_epilog( mem_ptr ); 00159 _papi_hwi_unlock( MEMORY_LOCK ); 00160 00161 MEMDBG( "%p: Allocated %lu bytes from File: %s Line: %d\n", 00162 mem_ptr->ptr, ( unsigned long ) size, file, line ); 00163 return ( ptr ); 00164 } 00165 return ( NULL ); 00166 } 00167 00168 char * 00169 _papi_strdup( char *file, int line, const char *s ) 00170 { 00171 size_t size; 00172 char *ptr; 00173 00174 if ( !s ) 00175 return ( NULL ); 00176 00177 /* String Length +1 for \0 */ 00178 size = strlen( s ) + 1; 00179 ptr = ( char * ) _papi_malloc( file, line, size ); 00180 00181 if ( !ptr ) 00182 return ( NULL ); 00183 00184 memcpy( ptr, s, size ); 00185 return ( ptr ); 00186 } 00187 00190 int 00191 _papi_valid_free( char *file, int line, void *ptr ) 00192 { 00193 pmem_t *tmp; 00194 int valid = 0; 00195 00196 if ( !ptr ) { 00197 ( void ) file; 00198 ( void ) line; 00199 return ( 0 ); 00200 } 00201 00202 _papi_hwi_lock( MEMORY_LOCK ); 00203 00204 for ( tmp = mem_head; tmp; tmp = tmp->next ) { 00205 if ( ptr == tmp->ptr ) { 00206 pmem_t *mem_ptr = get_mem_ptr( ptr ); 00207 00208 if ( mem_ptr ) { 00209 MEMDBG( "%p: Freeing %d bytes from File: %s Line: %d\n", 00210 mem_ptr->ptr, mem_ptr->size, file, line ); 00211 remove_mem_ptr( mem_ptr ); 00212 _papi_mem_check_all_overflow( ); 00213 } 00214 00215 valid = 1; 00216 break; 00217 } 00218 } 00219 00220 _papi_hwi_unlock( MEMORY_LOCK ); 00221 return ( valid ); 00222 } 00223 00225 void 00226 _papi_free( char *file, int line, void *ptr ) 00227 { 00228 pmem_t *mem_ptr = get_mem_ptr( ptr ); 00229 00230 if ( !mem_ptr ) { 00231 ( void ) file; 00232 ( void ) line; 00233 return; 00234 } 00235 00236 MEMDBG( "%p: Freeing %d bytes from File: %s Line: %d\n", mem_ptr->ptr, 00237 mem_ptr->size, file, line ); 00238 00239 _papi_hwi_lock( MEMORY_LOCK ); 00240 remove_mem_ptr( mem_ptr ); 00241 _papi_mem_check_all_overflow( ); 00242 _papi_hwi_unlock( MEMORY_LOCK ); 00243 } 00244 00246 void 00247 _papi_mem_print_info( void *ptr ) 00248 { 00249 pmem_t *mem_ptr = get_mem_ptr( ptr ); 00250 00251 #ifdef DEBUG 00252 fprintf( stderr, "%p: Allocated %d bytes from File: %s Line: %d\n", ptr, 00253 mem_ptr->size, mem_ptr->file, mem_ptr->line ); 00254 #else 00255 fprintf( stderr, "%p: Allocated %d bytes\n", ptr, mem_ptr->size ); 00256 #endif 00257 return; 00258 } 00259 00261 void 00262 _papi_mem_print_stats( ) 00263 { 00264 pmem_t *tmp = NULL; 00265 00266 _papi_hwi_lock( MEMORY_LOCK ); 00267 for ( tmp = mem_head; tmp; tmp = tmp->next ) { 00268 _papi_mem_print_info( tmp->ptr ); 00269 } 00270 _papi_hwi_unlock( MEMORY_LOCK ); 00271 } 00272 00279 int 00280 _papi_mem_overhead( int type ) 00281 { 00282 pmem_t *ptr = NULL; 00283 int size = 0; 00284 00285 _papi_hwi_lock( MEMORY_LOCK ); 00286 for ( ptr = mem_head; ptr; ptr = ptr->next ) { 00287 if ( type & PAPI_MEM_LIB_OVERHEAD ) 00288 size += ptr->size; 00289 if ( type & PAPI_MEM_OVERHEAD ) { 00290 size += ( int ) sizeof ( pmem_t ); 00291 size += ( int ) MEM_PROLOG; 00292 #ifdef DEBUG 00293 size += ( int ) MEM_EPILOG; 00294 #endif 00295 } 00296 } 00297 _papi_hwi_unlock( MEMORY_LOCK ); 00298 return size; 00299 } 00300 00302 void 00303 _papi_mem_cleanup_all( ) 00304 { 00305 pmem_t *ptr = NULL, *tmp = NULL; 00306 #ifdef DEBUG 00307 int cnt = 0; 00308 #endif 00309 00310 _papi_hwi_lock( MEMORY_LOCK ); 00311 _papi_mem_check_all_overflow( ); 00312 00313 for ( ptr = mem_head; ptr; ptr = tmp ) { 00314 tmp = ptr->next; 00315 #ifdef DEBUG 00316 LEAKDBG( "MEMORY LEAK: %p of %d bytes, from File: %s Line: %d\n", 00317 ptr->ptr, ptr->size, ptr->file, ptr->line ); 00318 cnt += ptr->size; 00319 #endif 00320 00321 remove_mem_ptr( ptr ); 00322 } 00323 _papi_hwi_unlock( MEMORY_LOCK ); 00324 #ifdef DEBUG 00325 if ( 0 != cnt ) { 00326 LEAKDBG( "TOTAL MEMORY LEAK: %d bytes.\n", cnt ); 00327 } 00328 #endif 00329 } 00330 00331 /* Loop through memory structures and look for buffer overflows 00332 * returns the number of overflows detected 00333 */ 00334 00335 /********************************************************************** 00336 * Private helper routines for papi memory management * 00337 **********************************************************************/ 00338 00339 /* Given a pointer returned by _papi_malloc, returns a pointer 00340 * to the related pmem_t structure describing this pointer. 00341 * Checks for NULL pointers and returns NULL if error. 00342 */ 00343 static pmem_t * 00344 get_mem_ptr( void *ptr ) 00345 { 00346 pmem_t **tmp_ptr = ( pmem_t ** ) ( ( char * ) ptr - MEM_PROLOG ); 00347 pmem_t *mem_ptr; 00348 00349 if ( !tmp_ptr || !ptr ) 00350 return ( NULL ); 00351 00352 mem_ptr = *tmp_ptr; 00353 return ( mem_ptr ); 00354 } 00355 00356 /* Allocate and initialize a memory pointer */ 00357 pmem_t * 00358 init_mem_ptr( void *ptr, int size, char *file, int line ) 00359 { 00360 pmem_t *mem_ptr = NULL; 00361 if ( ( mem_ptr = ( pmem_t * ) malloc( sizeof ( pmem_t ) ) ) == NULL ) 00362 return ( NULL ); 00363 00364 mem_ptr->ptr = ptr; 00365 mem_ptr->size = size; 00366 mem_ptr->next = NULL; 00367 mem_ptr->prev = NULL; 00368 #ifdef DEBUG 00369 strncpy( mem_ptr->file, file, DEBUG_FILE_LEN ); 00370 mem_ptr->file[DEBUG_FILE_LEN - 1] = '\0'; 00371 mem_ptr->line = line; 00372 #else 00373 ( void ) file; /*unused */ 00374 ( void ) line; /*unused */ 00375 #endif 00376 return ( mem_ptr ); 00377 } 00378 00379 /* Insert the memory information 00380 * Do not lock these routines, but lock in routines using these 00381 */ 00382 static void 00383 insert_mem_ptr( pmem_t * ptr ) 00384 { 00385 if ( !ptr ) 00386 return; 00387 00388 if ( !mem_head ) { 00389 mem_head = ptr; 00390 ptr->next = NULL; 00391 ptr->prev = NULL; 00392 } else { 00393 mem_head->prev = ptr; 00394 ptr->next = mem_head; 00395 mem_head = ptr; 00396 } 00397 return; 00398 } 00399 00400 /* Remove the memory information pointer and free the memory 00401 * Do not using locking in this routine, instead lock around 00402 * the sections of code that use this call. 00403 */ 00404 static void 00405 remove_mem_ptr( pmem_t * ptr ) 00406 { 00407 if ( !ptr ) 00408 return; 00409 00410 if ( ptr->prev ) 00411 ptr->prev->next = ptr->next; 00412 if ( ptr->next ) 00413 ptr->next->prev = ptr->prev; 00414 if ( ptr == mem_head ) 00415 mem_head = ptr->next; 00416 free( ptr ); 00417 } 00418 00419 static int 00420 set_epilog( pmem_t * mem_ptr ) 00421 { 00422 #ifdef DEBUG 00423 char *chptr = ( char * ) mem_ptr->ptr + mem_ptr->size; 00424 *chptr++ = MEM_EPILOG_1; 00425 *chptr++ = MEM_EPILOG_2; 00426 *chptr++ = MEM_EPILOG_3; 00427 *chptr++ = MEM_EPILOG_4; 00428 return ( _papi_mem_check_all_overflow( ) ); 00429 #else 00430 ( void ) mem_ptr; /*unused */ 00431 #endif 00432 return ( 0 ); 00433 } 00434 00435 /* Check for memory buffer overflows */ 00436 #ifdef DEBUG 00437 static int 00438 _papi_mem_check_buf_overflow( pmem_t * tmp ) 00439 { 00440 int fnd = 0; 00441 char *ptr; 00442 char *tptr; 00443 00444 if ( !tmp ) 00445 return ( 0 ); 00446 00447 tptr = tmp->ptr; 00448 tptr += tmp->size; 00449 00450 /* Move to the buffer overflow padding */ 00451 ptr = ( ( char * ) tmp->ptr ) + tmp->size; 00452 if ( *ptr++ != MEM_EPILOG_1 ) 00453 fnd = 1; 00454 else if ( *ptr++ != MEM_EPILOG_2 ) 00455 fnd = 2; 00456 else if ( *ptr++ != MEM_EPILOG_3 ) 00457 fnd = 3; 00458 else if ( *ptr++ != MEM_EPILOG_4 ) 00459 fnd = 4; 00460 00461 if ( fnd ) { 00462 LEAKDBG( "Buffer Overflow[%d] for %p allocated from %s at line %d\n", 00463 fnd, tmp->ptr, tmp->file, tmp->line ); 00464 } 00465 return ( fnd ); 00466 } 00467 #endif 00468 00469 int 00470 _papi_mem_check_all_overflow( ) 00471 { 00472 int fnd = 0; 00473 #ifdef DEBUG 00474 pmem_t *tmp; 00475 00476 for ( tmp = mem_head; tmp; tmp = tmp->next ) { 00477 if ( _papi_mem_check_buf_overflow( tmp ) ) 00478 fnd++; 00479 } 00480 00481 if ( fnd ) { 00482 LEAKDBG( "%d Total Buffer overflows detected!\n", fnd ); 00483 } 00484 #endif 00485 return ( fnd ); 00486 }