00001 #include <eh_utils.h>
00002
00003 USE_WIN_ASSERT
00004
00005 #define EH_MEM_TABLE_SIZE (40960)
00006 static glong profile_data_malloc[EH_MEM_TABLE_SIZE];
00007 static glong profile_data_realloc[EH_MEM_TABLE_SIZE];
00008 static glong profile_data_free[EH_MEM_TABLE_SIZE];
00009 static glong total_alloc = -1;
00010 static glong total_realloc = 0;
00011 static glong total_free = 0;
00012
00013 static glong total_in_use = 0;
00014
00015 typedef enum
00016 {
00017 EH_MEM_PROFILE_MALLOC ,
00018 EH_MEM_PROFILE_REALLOC ,
00019 EH_MEM_PROFILE_FREE
00020 }
00021 Eh_mem_job;
00022
00023 #include <stdlib.h>
00024
00025 void
00026 eh_mem_profile_log( Eh_mem_job job , gulong size )
00027 {
00028 if ( size>0 )
00029 {
00030 gulong ind = size-1;
00031
00032
00033 if ( total_alloc<0 )
00034 {
00035
00036
00037
00038
00039
00040 total_alloc = 0;
00041
00042 memset( profile_data_malloc , 0 , EH_MEM_TABLE_SIZE );
00043 memset( profile_data_realloc , 0 , EH_MEM_TABLE_SIZE );
00044 memset( profile_data_free , 0 , EH_MEM_TABLE_SIZE );
00045 }
00046
00047
00048 if ( ind>EH_MEM_TABLE_SIZE-1 )
00049 ind = EH_MEM_TABLE_SIZE-1;
00050
00051 if ( job == EH_MEM_PROFILE_MALLOC )
00052 {
00053 profile_data_malloc[ind] += 1;
00054 total_alloc += size;
00055 }
00056 else if ( job == EH_MEM_PROFILE_REALLOC )
00057 {
00058 profile_data_realloc[ind] += 1;
00059 total_realloc += size;
00060 }
00061 else if ( job == EH_MEM_PROFILE_FREE )
00062 {
00063 profile_data_free[ind] += 1;
00064 total_free += size;
00065 }
00066 }
00067 }
00068
00069 void
00070 eh_mem_profile_fprint( FILE* fp )
00071 {
00072 glong i;
00073 glong t_alloc, t_realloc, t_free, t_left;
00074 glong total;
00075
00076 fprintf( fp , " Block Size | N Mallocs | N Reallocs | N Frees | Remaining\n" );
00077 fprintf( fp , " (in bytes) | | | | (in bytes)\n" );
00078
00079 for ( i=0 ; i<EH_MEM_TABLE_SIZE ; i++ )
00080 {
00081 t_alloc = profile_data_malloc[i];
00082 t_realloc = profile_data_realloc[i];
00083 t_free = profile_data_free[i];
00084 t_left = (i+1)*(t_alloc + t_realloc - t_free);
00085
00086 if ( t_alloc!=0 || t_realloc!=0 || t_free!=0 )
00087 fprintf( fp , "%11ld | %9ld | %10ld | %10ld | %10ld\n" ,
00088 i+1 , t_alloc , t_realloc , t_free , t_left );
00089
00090 total_alloc += (i+1)*(t_alloc+t_realloc);
00091 total_free += (i+1)*t_free;
00092 }
00093
00094 total = total_alloc+total_realloc;
00095
00096 fprintf( fp , "Bytes allocated : %12ld\n" , total_alloc );
00097 fprintf( fp , "Bytes re-allocated : %12ld\n" , total_realloc );
00098 fprintf( fp , "Bytes freed : %12ld (%f%%)\n" , total_free , total_free*100./total );
00099 fprintf( fp , "Bytes in use : %12ld (%f%%)\n" , total-total_free , (total-total_free)*100./total );
00100 }
00101
00102
00103 #define ALIGNMENT (8)
00104 #define DO_ALIGN( x ) (((x)+ALIGNMENT-1)&~(ALIGNMENT-1))
00105
00106 eh_compiler_require( IS_POWER_2(ALIGNMENT) );
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 typedef struct Heap_Prefix* Heap_Prefix;
00136 typedef struct Heap_Postfix* Heap_Postfix;
00137
00138 typedef struct Heap_Prefix
00139 {
00140 char pad[4];
00141 Heap_Prefix prev;
00142 Heap_Prefix next;
00143 Heap_Postfix postfix;
00144 char *file_name;
00145 gint32 line_no;
00146 void *mem;
00147 Class_Desc class_desc;
00148 } Prefix;
00149
00150 typedef struct Heap_Postfix
00151 {
00152 Heap_Prefix prefix;
00153 } Postfix;
00154
00155 eh_compiler_require( !(sizeof(Prefix)%ALIGNMENT) );
00156
00157 static Heap_Prefix heap_head = NULL;
00158
00159 G_GNUC_INTERNAL void add_to_linked_list ( Heap_Prefix );
00160 G_GNUC_INTERNAL void remove_from_linked_list ( Heap_Prefix );
00161 G_GNUC_INTERNAL gboolean verify_heap_pointer ( void* );
00162 G_GNUC_INTERNAL gsize render_desc ( Heap_Prefix , char* );
00163
00164 #include <stdlib.h>
00165
00166 gpointer API_ENTRY eh_malloc( gsize w_size ,
00167 Class_Desc desc ,
00168 const char* file ,
00169 int line_no )
00170 {
00171 Heap_Prefix prefix;
00172
00173 eh_require( w_size>=0 );
00174
00175 if ( w_size <= 0 )
00176 return NULL;
00177
00178 w_size = DO_ALIGN( w_size );
00179 prefix = (Heap_Prefix)malloc( sizeof(Prefix)+w_size+sizeof(Postfix) );
00180
00181 if ( prefix )
00182 {
00183 add_to_linked_list( prefix );
00184
00185 prefix->postfix = (Heap_Postfix)( (char*)(prefix+1)+w_size );
00186 prefix->postfix->prefix = prefix;
00187 prefix->file_name = file;
00188 prefix->line_no = line_no;
00189 prefix->mem = prefix+1;
00190 prefix->class_desc = desc;
00191 memset( prefix->mem , 0 , w_size );
00192
00193
00194 eh_mem_profile_log( EH_MEM_PROFILE_MALLOC , w_size );
00195
00196 total_in_use += w_size;
00197 }
00198 else
00199 {
00200 assert_error;
00201 }
00202
00203 return ( prefix ? prefix+1 : NULL );
00204 }
00205
00206 gpointer API_ENTRY eh_malloc_c_style( gsize w_size )
00207 {
00208 if ( w_size )
00209 {
00210 gpointer mem;
00211
00212 mem = eh_malloc( w_size , NULL , __FILE__ , __LINE__ );
00213
00214 if ( mem )
00215 return mem;
00216
00217 eh_error( "Could not allocate %d bytes." , (gint)w_size );
00218 }
00219 return NULL;
00220 }
00221
00222 gpointer API_ENTRY eh_calloc_c_style( gsize n_blocks , gsize n_block_bytes )
00223 {
00224 if ( n_blocks*n_block_bytes )
00225 {
00226 gpointer mem;
00227
00228 mem = eh_malloc( n_blocks*n_block_bytes , NULL , __FILE__ , __LINE__ );
00229
00230 if ( mem )
00231 return mem;
00232
00233 eh_error( "Could not allocate %d bytes." , (gint)(n_blocks*n_block_bytes) );
00234 }
00235
00236 return NULL;
00237 }
00238
00239 #if defined( USE_MY_VTABLE )
00240
00241 void* API_ENTRY eh_free_mem( gpointer mem )
00242 {
00243 if ( !mem )
00244 return NULL;
00245
00246 if ( verify_heap_pointer(mem) )
00247 {
00248 Heap_Prefix prefix = (Heap_Prefix)mem-1;
00249 size_t w_size = (size_t)(prefix->postfix) - (size_t)prefix->mem;
00250 remove_from_linked_list( prefix );
00251 memset( prefix , 0 , w_size );
00252 free( prefix );
00253
00254 eh_mem_profile_log( EH_MEM_PROFILE_FREE , w_size );
00255 total_in_use -= w_size;
00256 }
00257
00258 return NULL;
00259 }
00260
00261 void API_ENTRY eh_free_c_style( gpointer mem )
00262 {
00263 if ( mem )
00264 eh_free_mem( mem );
00265 }
00266
00267 #endif
00268
00269 gpointer API_ENTRY eh_realloc( gpointer old , gsize w_size ,
00270 const char *file , int line_no )
00271 {
00272 void *new = NULL;
00273
00274 if ( old )
00275 {
00276 if ( verify_heap_pointer( old ) )
00277 {
00278 Heap_Prefix prefix = (Heap_Prefix)old - 1;
00279 Heap_Prefix new_prefix;
00280 Heap_Prefix pre;
00281 size_t old_bytes = (size_t)(prefix->postfix) - (size_t)prefix->mem;
00282
00283 remove_from_linked_list( prefix );
00284 memset( prefix->postfix , 0 , sizeof( Postfix ) );
00285
00286 w_size = DO_ALIGN( w_size );
00287 new_prefix = (Heap_Prefix)realloc( prefix ,
00288 sizeof(Prefix)
00289 + w_size
00290 + sizeof(Postfix) );
00291
00292 pre = (new_prefix?new_prefix:prefix);
00293 add_to_linked_list( pre );
00294 pre->postfix = (Heap_Postfix)((char*)(pre+1)+w_size);
00295 pre->postfix->prefix = pre;
00296 pre->mem = pre+1;
00297
00298 new = ( new_prefix?&new_prefix[1]:NULL );
00299 if ( !new )
00300 {
00301 assert_error;
00302 }
00303
00304
00305 eh_mem_profile_log( EH_MEM_PROFILE_FREE , old_bytes );
00306 eh_mem_profile_log( EH_MEM_PROFILE_REALLOC , w_size );
00307
00308 total_in_use -= old_bytes;
00309 total_in_use += w_size;
00310
00311 }
00312 }
00313 else
00314 {
00315 new = eh_malloc( w_size , NULL , file , line_no );
00316 }
00317
00318 return new;
00319 }
00320
00321 gpointer API_ENTRY eh_realloc_c_style( gpointer old , gsize w_size )
00322 {
00323 if ( w_size )
00324 {
00325 gpointer mem;
00326
00327 mem = eh_realloc( old , w_size , __FILE__ , __LINE__ );
00328
00329 if ( mem )
00330 return mem;
00331
00332 eh_error( "Could not allocate %d bytes." , (gint)w_size );
00333 }
00334
00335 if ( old )
00336 eh_free_c_style( old );
00337
00338 return NULL;
00339 }
00340
00341 void API_ENTRY eh_walk_heap( void )
00342 {
00343 if ( heap_head )
00344 {
00345 Heap_Prefix cur = heap_head;
00346 while ( verify_heap_pointer( &cur[1] ) )
00347 {
00348 char buffer[1000];
00349 render_desc( cur , buffer );
00350 printf( "walk: %s\n" , buffer );
00351 cur = cur->next;
00352 if ( cur == heap_head )
00353 {
00354 break;
00355 }
00356 }
00357 }
00358 }
00359
00360 glong
00361 eh_mem_in_use( void )
00362 {
00363 return total_in_use;
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 }
00385
00386 #if defined( USE_MY_VTABLE )
00387
00388 void API_ENTRY eh_heap_dump( const char *file )
00389 {
00390 FILE *fp;
00391
00392 if ( !file )
00393 fp = stderr;
00394 else
00395 {
00396 fp = fopen( file , "w" );
00397 if ( !fp )
00398 fp = stderr;
00399 }
00400
00401 fprintf( fp , "Heap dump:\n" );
00402
00403 if ( heap_head )
00404 {
00405 Heap_Prefix cur = heap_head;
00406 gulong total_bytes = 0;
00407 while ( verify_heap_pointer( &cur[1] ) )
00408 {
00409 char buffer[2048];
00410 total_bytes += render_desc( cur , buffer );
00411
00412 if ( strlen(buffer)>0 )
00413 fprintf( fp , "%s\n" , buffer );
00414
00415 cur = cur->next;
00416
00417
00418 if ( cur == heap_head )
00419 {
00420 break;
00421 }
00422 }
00423 fprintf( fp ,
00424 "Total number of allocated bytes in heap: %ld\n" ,
00425 total_bytes );
00426
00427 eh_mem_profile_fprint( fp );
00428 }
00429 else
00430 fprintf( fp , "Heap is empty\n" );
00431
00432 fclose( fp );
00433
00434 }
00435
00436 #endif
00437
00438 void add_to_linked_list( Heap_Prefix add )
00439 {
00440 if ( heap_head )
00441 {
00442 add->prev = heap_head->prev;
00443 (add->prev)->next = add;
00444 add->next = heap_head;
00445 (add->next)->prev = add;
00446 }
00447 else
00448 {
00449 add->prev = add;
00450 add->next = add;
00451 }
00452
00453 heap_head = add;
00454 }
00455
00456 void remove_from_linked_list( Heap_Prefix remove )
00457 {
00458 (remove->prev)->next = remove->next;
00459 (remove->next)->prev = remove->prev;
00460
00461 if ( remove == heap_head )
00462 {
00463 heap_head = ((remove->next==remove) ? NULL : remove->next );
00464 }
00465 }
00466
00467 gboolean
00468 verify_heap_pointer( void *mem )
00469 {
00470 gboolean ok = FALSE;
00471
00472 if ( mem )
00473 {
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 if ( eh_is_ptr_ok(mem) )
00484 {
00485 Heap_Prefix prefix = (Heap_Prefix)mem - 1;
00486
00487 if ( prefix->mem == mem )
00488 {
00489 if ( prefix->postfix->prefix == prefix ) ok = TRUE;
00490 else fprintf( stderr , "(%08lx: %d) Pointer overwrite\n" , mem , mem );
00491 }
00492 else fprintf( stderr , "(%08lx: %d) Pointer underwrite\n" , mem , mem );
00493 }
00494 else fprintf( stderr , "(%08lx) Pointer is not aligned\n" , mem );
00495 }
00496
00497 return ok;
00498 }
00499
00500 gboolean API_ENTRY eh_is_ptr_ok( gpointer mem )
00501 {
00502 return ((mem) && (!((size_t)mem&(ALIGNMENT-1))));
00503 }
00504
00505 gsize
00506 render_desc( Heap_Prefix prefix , char* buffer )
00507 {
00508 gulong bytes = 0;
00509
00510 buffer[0] = '\0';
00511
00512 if ( prefix->mem == &prefix[1] )
00513 {
00514 bytes = (size_t)(prefix->postfix) - (size_t)prefix->mem;
00515
00516
00517 {
00518 sprintf( buffer , "%08lx" , prefix->mem );
00519 if ( prefix->file_name )
00520 {
00521 sprintf( buffer+strlen(buffer) ,
00522 "%s: line %d: %ld bytes allocated " ,
00523 prefix->file_name ,
00524 prefix->line_no ,
00525 bytes );
00526 }
00527 else
00528 sprintf( buffer+strlen(buffer) ,
00529 "%s: line %d: %ld bytes allocated but not yet freed." ,
00530 "(unknown file)" ,
00531 prefix->line_no ,
00532 bytes );
00533
00534 if ( prefix->class_desc )
00535 {
00536 sprintf( buffer+strlen(buffer) ,
00537 "of type %s" , prefix->class_desc );
00538 }
00539 else
00540 sprintf( buffer+strlen(buffer) , "(unknown type)" );
00541 }
00542 }
00543 else
00544 {
00545 strcpy( buffer , "(bad)" );
00546 }
00547
00548 return bytes;
00549 }
00550
00551 void API_ENTRY report_win_assert( char *file_name , int line_no )
00552 {
00553 printf( "win_assert: %s-%d (Press Enter) ", file_name , line_no );
00554 while ( '\n' != getchar() )
00555 {
00556 }
00557 }
00558
00559 void**
00560 eh_alloc_2( gssize m , gssize n , gssize size )
00561 {
00562 void **p=NULL;
00563
00564 if ( m>0 && n>0 && size>0 )
00565 {
00566 p = eh_new( void* , m );
00567
00568
00569 if ( p )
00570 {
00571 p[0] = eh_new( gchar , m*n*size );
00572
00573 if ( p[0] )
00574 {
00575 gint i;
00576 for ( i=1 ; i<m ; i++ )
00577 p[i] = (gint8*)(p[i-1])+size*n;
00578 }
00579 else
00580 eh_error( "Failed to allocate %d bytes" , n*m*size );
00581 }
00582 else
00583 eh_error( "Failed to allocate %d bytes" , n*sizeof(void*) );
00584 }
00585
00586 return p;
00587 }
00588
00589 void
00590 eh_free_void_2( void **p )
00591 {
00592 if ( p )
00593 {
00594 if ( p[0] ) eh_free( p[0] );
00595 eh_free( p );
00596 }
00597 }