Changeset 7a2057a for libcfa/src


Ignore:
Timestamp:
Oct 30, 2022, 3:58:39 PM (18 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, ast-experimental, master
Children:
c7f12a4
Parents:
0b1ca47
Message:

remove unused BUCKETLOCK, restructure OWNERSHIP and RETURNSPIN

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r0b1ca47 r7a2057a  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Oct 13 22:21:52 2022
    13 // Update Count     : 1557
     12// Last Modified On : Sun Oct 30 15:33:13 2022
     13// Update Count     : 1580
    1414//
    1515
     
    4343
    4444#define FASTLOOKUP                                                                              // use O(1) table lookup from allocation size to bucket size
    45 #define RETURNSPIN                                                                              // toggle spinlock / lockfree stack
    4645#define OWNERSHIP                                                                               // return freed memory to owner thread
     46#define RETURNSPIN                                                                              // toggle spinlock / lockfree queue
     47#if ! defined( OWNERSHIP ) && defined( RETURNSPIN )
     48#warning "RETURNSPIN is ignored without OWNERSHIP; suggest commenting out RETURNSPIN"
     49#endif // ! OWNERSHIP && RETURNSPIN
    4750
    4851#define CACHE_ALIGN 64
     
    109112
    110113
    111 //######################### Spin Lock #########################
     114//######################### Helpers #########################
     115
     116
     117// generic Bsearchl does not inline, so substitute with hand-coded binary-search.
     118inline __attribute__((always_inline))
     119static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
     120        size_t l = 0, m, h = dim;
     121        while ( l < h ) {
     122                m = (l + h) / 2;
     123                if ( (unsigned int &)(vals[m]) < key ) {                // cast away const
     124                        l = m + 1;
     125                } else {
     126                        h = m;
     127                } // if
     128        } // while
     129        return l;
     130} // Bsearchl
    112131
    113132
     
    206225
    207226
    208 #define SPINLOCK 0
    209 #define LOCKFREE 1
    210 #define BUCKETLOCK SPINLOCK
    211 #if BUCKETLOCK == SPINLOCK
    212 #elif BUCKETLOCK == LOCKFREE
    213 #include <containers/lockfree.hfa>
    214 #else
    215         #error undefined lock type for bucket lock
    216 #endif // LOCKFREE
    217 
    218227// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    219228// Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
     
    232241                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    233242                                                                size_t blockSize;               // size for munmap (must overlay alignment)
    234                                                                 #if BUCKETLOCK == SPINLOCK
    235243                                                                Storage * next;                 // freed block points to next freed block of same size
    236                                                                 #endif // SPINLOCK
    237244                                                        };
    238245                                                        size_t size;                            // allocation size in bytes
    239246                                                };
    240                                                 #if BUCKETLOCK == LOCKFREE
    241                                                 Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
    242                                                 #endif // LOCKFREE
    243247                                        };
    244248                                } real; // RealHeader
     
    259263        struct __attribute__(( aligned (8) )) FreeHeader {
    260264                size_t blockSize __attribute__(( aligned(8) )); // size of allocations on this list
    261                 #if BUCKETLOCK == SPINLOCK
    262265                #ifdef OWNERSHIP
    263266                #ifdef RETURNSPIN
     
    266269                Storage * returnList;                                                   // other thread return list
    267270                #endif // OWNERSHIP
     271
    268272                Storage * freeList;                                                             // thread free list
    269                 #else
    270                 StackLF(Storage) freeList;
    271                 #endif // BUCKETLOCK
    272273                Heap * homeManager;                                                             // heap owner (free storage to bucket, from bucket to heap)
    273274        }; // FreeHeader
     
    290291        #endif // __STATISTICS__
    291292}; // Heap
    292 
    293 #if BUCKETLOCK == LOCKFREE
    294 inline __attribute__((always_inline))
    295 static {
    296         Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; }
    297         void ?{}( Heap.FreeHeader & ) {}
    298         void ^?{}( Heap.FreeHeader & ) {}
    299 } // distribution
    300 #endif // LOCKFREE
    301293
    302294
     
    385377
    386378
    387 // generic Bsearchl does not inline, so substitute with hand-coded binary-search.
    388 inline __attribute__((always_inline))
    389 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
    390         size_t l = 0, m, h = dim;
    391         while ( l < h ) {
    392                 m = (l + h) / 2;
    393                 if ( (unsigned int &)(vals[m]) < key ) {                // cast away const
    394                         l = m + 1;
    395                 } else {
    396                         h = m;
    397                 } // if
    398         } // while
    399         return l;
    400 } // Bsearchl
    401 
    402 
    403379void heapMasterCtor() with( heapMaster ) {
    404380        // Singleton pattern to initialize heap master
     
    409385        __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
    410386
    411         ?{}( extLock );
    412         ?{}( mgrLock );
     387        extLock = 0;
     388        mgrLock = 0;
    413389
    414390        char * end = (char *)sbrk( 0 );
     
    497473                                #ifdef OWNERSHIP
    498474                                #ifdef RETURNSPIN
    499                                 ?{}( freeLists[j].returnLock );
     475                                freeLists[j].returnLock = 0;
     476                                freeLists[j].returnList = 0p;
    500477                                #endif // RETURNSPIN
    501                                 freeLists[j].returnList = 0p;
    502478                                #endif // OWNERSHIP
     479
    503480                                freeLists[j].freeList = 0p;
    504481                                freeLists[j].homeManager = heap;
     
    710687        // find the closest bucket size less than or equal to the mmapStart size
    711688        maxBucketsUsed = Bsearchl( mmapStart, bucketSizes, NoBucketSizes ); // binary search
     689
    712690        verify( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    713691        verify( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
     
    971949                #endif // __STATISTICS__
    972950
    973                 // Spin until the lock is acquired for this particular size of block.
    974 
    975                 #if BUCKETLOCK == SPINLOCK
    976951                block = freeHead->freeList;                                             // remove node from stack
    977                 #else
    978                 block = pop( freeHead->freeList );
    979                 #endif // BUCKETLOCK
    980952                if ( unlikely( block == 0p ) ) {                                // no free block ?
     953                        // Freelist for this size is empty, so check return list (OWNERSHIP), carve it out of the heap, if there
     954                        // is enough left, or get some more heap storage and carve it off.
    981955                        #ifdef OWNERSHIP
    982                         // Freelist for that size is empty, so carve it out of the heap, if there is enough left, or get some more
    983                         // and then carve it off.
    984                         #ifdef RETURNSPIN
    985                         #if BUCKETLOCK == SPINLOCK
    986                         lock( freeHead->returnLock );
    987                         block = freeHead->returnList;
    988                         freeHead->returnList = 0p;
    989                         unlock( freeHead->returnLock );
    990                         #else
    991                         block = __atomic_exchange_n( &freeHead->returnList, nullptr, __ATOMIC_SEQ_CST );
    992                         #endif // RETURNSPIN
    993 
    994                         if ( likely( block == 0p ) ) {                  // return list also empty?
     956                        if ( unlikely( freeHead->returnList ) ) {       // race, get next time if lose race
     957                                #ifdef RETURNSPIN
     958                                lock( freeHead->returnLock );
     959                                block = freeHead->returnList;
     960                                freeHead->returnList = 0p;
     961                                unlock( freeHead->returnLock );
     962                                #else
     963                                block = __atomic_exchange_n( &freeHead->returnList, 0p, __ATOMIC_SEQ_CST );
     964                                #endif // RETURNSPIN
     965
     966                                verify( block );
     967                                #ifdef __STATISTICS__
     968                                stats.return_pulls += 1;
     969                                #endif // __STATISTICS__
     970
     971                                // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
     972
     973                                freeHead->freeList = block->header.kind.real.next; // merge returnList into freeHead
     974                        } else {
    995975                        #endif // OWNERSHIP
    996976                                // Do not leave kernel thread as manager_extend accesses heapManager.
     
    1002982
    1003983                                #ifdef __CFA_DEBUG__
    1004                                 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes.
     984                                // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes.
    1005985                                memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) );
    1006986                                #endif // __CFA_DEBUG__
    1007                         #endif // BUCKETLOCK
    1008987                        #ifdef OWNERSHIP
    1009                         } else {                                                                        // merge returnList into freeHead
    1010                                 #ifdef __STATISTICS__
    1011                                 stats.return_pulls += 1;
    1012                                 #endif // __STATISTICS__
    1013 
    1014                                 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
    1015 
    1016                                 freeHead->freeList = block->header.kind.real.next;
    1017988                        } // if
    1018989                        #endif // OWNERSHIP
     
    1026997  if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p;
    1027998                tsize = ceiling2( tsize, __page_size );                 // must be multiple of page size
     999
    10281000                #ifdef __STATISTICS__
    10291001                stats.counters[STAT_NAME].alloc += tsize;
     
    10421014                        if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
    10431015                        // Do not call strerror( errno ) as it may call malloc.
    1044                         abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", size, heapMaster.mmapStart, errno );
     1016                        abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.",
     1017                                   size, heapMaster.mmapStart, errno );
    10451018                } // if
    10461019                block->header.kind.real.blockSize = MarkMmappedBit( tsize ); // storage size for munmap
    10471020
    10481021                #ifdef __CFA_DEBUG__
    1049                 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes.  The rest of
    1050                 // the storage set to 0 by mmap.
     1022                // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes. The
     1023                // rest of the storage set to 0 by mmap.
    10511024                memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) );
    10521025                #endif // __CFA_DEBUG__
     
    11261099                #endif // __CFA_DEBUG__
    11271100
     1101                #ifdef OWNERSHIP
    11281102                if ( likely( heapManager == freeHead->homeManager ) ) { // belongs to this thread
    11291103                        header->kind.real.next = freeHead->freeList; // push on stack
     
    11321106                        verify( heapManager );
    11331107
    1134                         #ifdef OWNERSHIP
    11351108                        #ifdef RETURNSPIN
    11361109                        lock( freeHead->returnLock );
     
    11411114                        header->kind.real.next = freeHead->returnList; // link new node to top node
    11421115                        // CAS resets header->kind.real.next = freeHead->returnList on failure
    1143                         while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, header,
     1116                        while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, (Heap.Storage *)header,
    11441117                                                                                                   false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) );
    11451118                        #endif // RETURNSPIN
    1146 
    1147                         #else                                                                           // no OWNERSHIP
    1148 
    1149                         freeHead = &heap->freeLists[ClearStickyBits( header->kind.real.home ) - &freeHead->homeManager->freeLists[0]];
    1150                         header->kind.real.next = freeHead->freeList; // push on stack
    1151                         freeHead->freeList = (Heap.Storage *)header;
    1152                         #endif // ! OWNERSHIP
    1153 
    1154                         #ifdef __U_STATISTICS__
    1155                         stats.return_pushes += 1;
    1156                         stats.return_storage_request += rsize;
    1157                         stats.return_storage_alloc += size;
    1158                         #endif // __U_STATISTICS__
    1159 
    1160                         // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
    1161                 } // if
     1119                } // if
     1120
     1121                #else                                                                                   // no OWNERSHIP
     1122
     1123                // kind.real.home is address in owner thread's freeLists, so compute the equivalent position in this thread's freeList.
     1124                freeHead = &freeLists[ClearStickyBits( (Heap.FreeHeader *)(header->kind.real.home) ) - &freeHead->homeManager->freeLists[0]];
     1125                header->kind.real.next = freeHead->freeList;    // push on stack
     1126                freeHead->freeList = (Heap.Storage *)header;
     1127                #endif // ! OWNERSHIP
     1128
     1129                #ifdef __U_STATISTICS__
     1130                stats.return_pushes += 1;
     1131                stats.return_storage_request += rsize;
     1132                stats.return_storage_alloc += size;
     1133                #endif // __U_STATISTICS__
     1134
     1135                // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
    11621136        } // if
    11631137
     
    11861160                #endif // __STATISTICS__
    11871161
    1188                 #if BUCKETLOCK == SPINLOCK
    11891162                for ( Heap.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    1190                 #else
    1191                         for(;;) {
    1192 //              for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
    1193 //              for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
    1194 //                      Heap.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
    1195 //                      typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works`
    1196 //                      p = temp;
    1197                 #endif // BUCKETLOCK
    11981163                        total += size;
    11991164                        #ifdef __STATISTICS__
Note: See TracChangeset for help on using the changeset viewer.