Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    rfeb999f rbe10079  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Apr  7 21:54:29 2024
    13 // Update Count     : 1644
     12// Last Modified On : Wed Jan  3 21:30:54 2024
     13// Update Count     : 1619
    1414//
    1515
     
    114114
    115115
    116 // CFA generic Bsearchl does not inline, so substitute with hand-coded binary-search.
     116// generic Bsearchl does not inline, so substitute with hand-coded binary-search.
    117117inline __attribute__((always_inline))
    118118static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
     
    190190                unsigned int realloc_calls, realloc_0_calls;
    191191                unsigned long long int realloc_storage_request, realloc_storage_alloc;
    192                 unsigned int free_calls, free_null_0_calls;
     192                unsigned int free_calls, free_null_calls;
    193193                unsigned long long int free_storage_request, free_storage_alloc;
    194194                unsigned int return_pulls, return_pushes;
     
    232232                struct Header {                                                                 // header
    233233                        union Kind {
    234                                 struct RealHeader {                                             // 4-byte word => 8-byte header, 8-byte word => 16-byte header
     234                                struct RealHeader {
    235235                                        union {
    236                                                 // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
    237                                                 // FreeHeader * home;                   // allocated block points back to home locations (must overlay alignment)
    238                                                 void * home;                                    // allocated block points back to home locations (must overlay alignment)
    239                                                 size_t blockSize;                               // size for munmap (must overlay alignment)
    240                                                 Storage * next;                                 // freed block points to next freed block of same size
     236                                                struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
     237                                                        union {
     238                                                                // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
     239                                                                // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
     240                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
     241                                                                size_t blockSize;               // size for munmap (must overlay alignment)
     242                                                                Storage * next;                 // freed block points to next freed block of same size
     243                                                        };
     244                                                        size_t size;                            // allocation size in bytes
     245                                                };
    241246                                        };
    242                                         size_t size;                                            // allocation size in bytes
    243247                                } real; // RealHeader
    244248
     
    257261
    258262        struct CALIGN FreeHeader {
     263                size_t blockSize CALIGN;                                                // size of allocations on this list
    259264                #ifdef OWNERSHIP
    260265                #ifdef RETURNSPIN
     
    266271                Storage * freeList;                                                             // thread free list
    267272                Heap * homeManager;                                                             // heap owner (free storage to bucket, from bucket to heap)
    268                 size_t blockSize;                                                               // size of allocations on this list
    269273        }; // FreeHeader
    270274
     
    365369static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing
    366370static __thread Heap * heapManager CALIGN TLSMODEL;
    367 static __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
     371static  __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;
    368372static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing
    369373
     
    591595
    592596#ifdef __STATISTICS__
     597static HeapStatistics stats;                                                    // zero filled
     598
    593599#define prtFmt \
    594600        "\nHeap statistics: (storage request / allocation)\n" \
     
    601607        "  resize    >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
    602608        "  realloc   >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \
    603         "  free      !null calls %'u; null/0 calls %'u; storage %'llu / %'llu bytes\n" \
     609        "  free      !null calls %'u; null calls %'u; storage %'llu / %'llu bytes\n" \
    604610        "  return    pulls %'u; pushes %'u; storage %'llu / %'llu bytes\n" \
    605611        "  sbrk      calls %'u; storage %'llu bytes\n" \
     
    621627                        resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
    622628                        realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
    623                         free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
     629                        free_calls, free_null_calls, free_storage_request, free_storage_alloc,
    624630                        return_pulls, return_pushes, return_storage_request, return_storage_alloc,
    625631                        sbrk_calls, sbrk_storage,
     
    644650        "<total type=\"resize\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    645651        "<total type=\"realloc\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    646         "<total type=\"free\" !null=\"%'u;\" 0 null/0=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
     652        "<total type=\"free\" !null=\"%'u;\" 0 null=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    647653        "<total type=\"return\" pulls=\"%'u;\" 0 pushes=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \
    648654        "<total type=\"sbrk\" count=\"%'u;\" size=\"%'llu\"/> bytes\n" \
     
    664670                        resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc,
    665671                        realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc,
    666                         free_calls, free_null_0_calls, free_storage_request, free_storage_alloc,
     672                        free_calls, free_null_calls, free_storage_request, free_storage_alloc,
    667673                        return_pulls, return_pushes, return_storage_request, return_storage_alloc,
    668674                        sbrk_calls, sbrk_storage,
     
    793799        } else {
    794800                fakeHeader( header, alignment );
    795                 if ( unlikely( MmappedBit( header ) ) ) {               // mmapped storage ?
     801                if ( unlikely( MmappedBit( header ) ) ) {               // mmapped ?
    796802                        verify( addr < heapBegin || heapEnd < addr );
    797803                        size = ClearStickyBits( header->kind.real.blockSize ); // mmap size
    798                         freeHead = 0p;                                                          // prevent uninitialized warning
    799804                        return true;
    800805                } // if
     
    899904
    900905
     906#define BOOT_HEAP_MANAGER \
     907        if ( unlikely( ! heapMasterBootFlag ) ) { \
     908                heapManagerCtor(); /* trigger for first heap */ \
     909        } /* if */
     910
    901911#ifdef __STATISTICS__
    902912#define STAT_NAME __counter
    903913#define STAT_PARM , unsigned int STAT_NAME
    904914#define STAT_ARG( name ) , name
    905 #define STAT_0_CNT( counter ) heapManager->stats.counters[counter].calls_0 += 1
     915#define STAT_0_CNT( counter ) stats.counters[counter].calls_0 += 1
    906916#else
    907917#define STAT_NAME
     
    911921#endif // __STATISTICS__
    912922
    913 #define BOOT_HEAP_MANAGER \
    914         if ( unlikely( ! heapMasterBootFlag ) ) { \
    915                 heapManagerCtor(); /* trigger for first heap */ \
    916         } /* if */ \
    917         verify( heapManager );
    918 
    919 #define __NONNULL_0_ALLOC__ /* Uncomment to return non-null address for malloc( 0 ). */
    920 #ifndef __NONNULL_0_ALLOC__
    921 #define __NULL_0_ALLOC__( counter, ... ) /* 0 byte allocation returns null pointer */ \
    922         if ( unlikely( size == 0 ) ) { \
     923// Uncomment to get allocation addresses for a 0-sized allocation rather than a null pointer.
     924//#define __NONNULL_0_ALLOC__
     925#if ! defined( __NONNULL_0_ALLOC__ )
     926#define __NULL_0_ALLOC__ unlikely( size == 0 ) ||               /* 0 BYTE ALLOCATION RETURNS NULL POINTER */
     927#else
     928#define __NULL_0_ALLOC__
     929#endif // __NONNULL_0_ALLOC__
     930
     931#define PROLOG( counter, ... ) \
     932        BOOT_HEAP_MANAGER; \
     933        if ( \
     934                __NULL_0_ALLOC__ \
     935                unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \
    923936                STAT_0_CNT( counter ); \
    924                 __VA_ARGS__; /* call routine, if specified */ \
     937                __VA_ARGS__; \
    925938                return 0p; \
    926939        } /* if */
    927 #else
    928 #define __NULL_0_ALLOC__( counter, ... )
    929 #endif // __NONNULL_0_ALLOC__
    930 
    931 #ifdef __DEBUG__
    932 #define __OVERFLOW_MALLOC__( ... ) \
    933         if ( unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \
    934                 __VA_ARGS__; /* call routine, if specified */ \
    935                 return 0p; \
    936         } /* if */
    937 #else
    938 #define __OVERFLOW_MALLOC__( ... )
    939 #endif // __DEBUG__
    940 
    941 #define PROLOG( counter, ... ) \
    942         BOOT_HEAP_MANAGER; \
    943         __NULL_0_ALLOC__( counter, __VA_ARGS__ ) \
    944         __OVERFLOW_MALLOC__( __VA_ARGS__ )
     940
    945941
    946942#define SCRUB_SIZE 1024lu
     
    952948        PROLOG( STAT_NAME );
    953949
     950        verify( heapManager );
    954951        Heap.Storage * block;                                                           // pointer to new block of storage
    955952
     
    959956
    960957        #ifdef __STATISTICS__
    961         #ifdef __NONNULL_0_ALLOC__
    962         if ( unlikely( size == 0 ) )                                            // malloc( 0 ) ?
    963                 stats.counters[STAT_NAME].calls_0 += 1;
    964         else
    965         #endif // __NONNULL_0_ALLOC__
    966                 stats.counters[STAT_NAME].calls += 1;
     958        stats.counters[STAT_NAME].calls += 1;
    967959        stats.counters[STAT_NAME].request += size;
    968960        #endif // __STATISTICS__
     
    10861078
    10871079static void doFree( void * addr ) libcfa_nopreempt with( *heapManager ) {
    1088         // char buf[64];
    1089         // int len = sprintf( buf, "doFree addr %p\n", addr );
    1090         // write( 2, buf, len );
    1091 
    10921080        verify( addr );
    10931081
     
    11031091        #endif // __STATISTICS__ || __CFA_DEBUG__
    11041092
    1105         // Do not move these down because heap can be null!
    11061093        #ifdef __STATISTICS__
    1107         #ifdef __NONNULL_0_ALLOC__
    1108         if ( unlikely( rsize == 0 ) )                                           // malloc( 0 ) ?
    1109                 stats.free_null_0_calls += 1;
    1110         else
    1111         #endif // __NONNULL_0_ALLOC__
    1112                 heapManager->stats.free_calls += 1;                             // count free amd implicit frees from resize/realloc
    11131094        stats.free_storage_request += rsize;
    11141095        stats.free_storage_alloc += size;
     
    11361117                } // if
    11371118        } else {
    1138                 assert( freeHead );
    11391119                #ifdef __CFA_DEBUG__
    11401120                // memset is NOT always inlined!
     
    13411321        // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
    13421322        void * resize( void * oaddr, size_t size ) libcfa_public {
    1343           if ( unlikely( oaddr == 0p ) ) {                                      // => malloc( size )
     1323          if ( unlikely( oaddr == 0p ) ) {                              // => malloc( size )
    13441324                        return doMalloc( size STAT_ARG( RESIZE ) );
    13451325                } // if
     
    13531333
    13541334                size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket
    1355                 // same size, DO NOT PRESERVE STICKY PROPERTIES.
     1335                // same size, DO NOT preserve STICKY PROPERTIES.
    13561336                if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    13571337                        ClearZeroFillBit( header );                                     // no alignment and turn off 0 fill
     
    13661346                } // if
    13671347
    1368                 // change size, DO NOT PRESERVE STICKY PROPERTIES.
     1348                // change size, DO NOT preserve STICKY PROPERTIES.
    13691349                doFree( oaddr );                                                                // free previous storage
    13701350
     
    13761356        // the old and new sizes.
    13771357        void * realloc( void * oaddr, size_t size ) libcfa_public {
    1378                 // char buf[64];
    1379                 // int len = sprintf( buf, "realloc1 oaddr %p size %d\n", oaddr, size );
    1380                 // write( 2, buf, len );
    13811358          if ( unlikely( oaddr == 0p ) ) {                                      // => malloc( size )
    13821359                  return doMalloc( size STAT_ARG( REALLOC ) );
     
    15211498                } // if
    15221499
     1500                #ifdef __STATISTICS__
     1501                incCalls( FREE );
     1502                #endif // __STATISTICS__
     1503
    15231504                doFree( addr );                                                                 // handles heapManager == nullptr
    15241505        } // free
     
    15981579                #endif // __STATISTICS__
    15991580        } // malloc_stats_clear
     1581
    16001582
    16011583        // Changes the file descriptor where malloc_stats() writes statistics.
     
    17181700        } // if
    17191701
    1720         // change size, DO NOT PRESERVE STICKY PROPERTIES.
     1702        // change size, DO NOT preserve STICKY PROPERTIES.
    17211703        doFree( oaddr );                                                                        // free previous storage
    17221704        return memalignNoStats( nalign, size STAT_ARG( RESIZE ) ); // create new aligned area
     
    17251707
    17261708void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public {
    1727         // char buf[64];
    1728         // int len = sprintf( buf, "realloc2 oaddr %p size %d\n", oaddr, size );
    1729         // write( 2, buf, len );
    17301709  if ( unlikely( oaddr == 0p ) ) {                                              // => malloc( size )
    17311710                return memalignNoStats( nalign, size STAT_ARG( REALLOC ) );
Note: See TracChangeset for help on using the changeset viewer.