/Users/huttone/Devel/sedflux-new/sedflux/trunk/ew/utils/eh_mem.c

Go to the documentation of this file.
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 //      if ( profile_data_malloc==NULL )
00033       if ( total_alloc<0 )
00034       {
00035 /*
00036          profile_data_malloc  = (glong*)calloc( EH_MEM_TABLE_SIZE , sizeof(glong) );
00037          profile_data_realloc = (glong*)calloc( EH_MEM_TABLE_SIZE , sizeof(glong) );
00038          profile_data_free    = (glong*)calloc( EH_MEM_TABLE_SIZE , sizeof(glong) );
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 //#define ALIGNMENT (sizeof(size_t))
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 new_handle( Heap_Prefix );
00109 new_handle( Heap_Postfix );
00110 
00111 typedef struct tag_Heap_Prefix
00112 {
00113    char pad[4];
00114    Heap_Prefix prev;
00115    Heap_Prefix next;
00116    Heap_Postfix postfix;
00117    char *file_name;
00118    gint32 line_no;
00119    void *mem;
00120    Class_Desc class_desc;
00121 }
00122 Prefix;
00123 
00124 typedef struct tag_Heap_Postfix
00125 {
00126    Heap_Prefix prefix;
00127 }
00128 Postfix;
00129 */
00130 /*
00131 typedef struct Heap_Prefix*  Heap_Prefix;
00132 typedef struct Heap_Postfix* Heap_Postfix;
00133 #define new_handle( Handle ) typedef struct tag_##Handle *Handle
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       /* Update profile data */
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          /* Update profile data */
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    glong total = 0;
00366 
00367    if ( heap_head )
00368    {
00369       Heap_Prefix cur = heap_head;
00370       while ( verify_heap_pointer( &cur[1] ) )
00371       {
00372          total += (size_t)(cur->postfix) - (size_t)cur->mem;
00373 
00374          cur = cur->next;
00375          if ( cur == heap_head )
00376          {
00377             break;
00378          }
00379       }
00380    }
00381 
00382    return total;
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 if ( mem==25217568 )
00476 {
00477    gchar buffer[2048];
00478    render_desc( (Heap_Prefix)mem-1 , buffer );
00479    eh_watch_str( buffer );
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       //if ( prefix->class_desc )
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 }

Generated on Fri Jan 4 18:04:16 2008 for sedflux by  doxygen 1.5.2