Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/ready_queue.cfa

    rfd9b524 r772411a  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
     19// #define USE_SNZI
     20
    1921#include "bits/defs.hfa"
    2022#include "kernel_private.hfa"
     
    148150//  queues or removing them.
    149151uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
     152        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     153
    150154        // Step 1 : lock global lock
    151155        // It is needed to avoid processors that register mid Critical-Section
     
    162166        }
    163167
     168        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    164169        return s;
    165170}
    166171
    167172void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
     173        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     174
    168175        // Step 1 : release local locks
    169176        // This must be done while the global lock is held to avoid
     
    180187        /*paranoid*/ assert(true == lock);
    181188        __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
     189
     190        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    182191}
    183192
     
    192201void ^?{}(__ready_queue_t & this) with (this) {
    193202        verify( 1 == lanes.count );
    194         verify( !query( snzi ) );
     203        #ifdef USE_SNZI
     204                verify( !query( snzi ) );
     205        #endif
    195206        free(lanes.data);
    196207}
     
    198209//-----------------------------------------------------------------------
    199210__attribute__((hot)) bool query(struct cluster * cltr) {
    200         return query(cltr->ready_queue.snzi);
     211        #ifdef USE_SNZI
     212                return query(cltr->ready_queue.snzi);
     213        #endif
     214        return true;
     215}
     216
     217static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
     218        unsigned i;
     219        bool local;
     220        #if defined(BIAS)
     221                unsigned rlow  = r % BIAS;
     222                unsigned rhigh = r / BIAS;
     223                if((0 != rlow) && preferred >= 0) {
     224                        // (BIAS - 1) out of BIAS chances
     225                        // Use perferred queues
     226                        i = preferred + (rhigh % 4);
     227                        local = true;
     228                }
     229                else {
     230                        // 1 out of BIAS chances
     231                        // Use all queues
     232                        i = rhigh;
     233                        local = false;
     234                }
     235        #else
     236                i = r;
     237                local = false;
     238        #endif
     239        return [i, local];
    201240}
    202241
     
    208247        thrd->link.ts = rdtscl();
    209248
    210         #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
    211                 bool local = false;
    212                 int preferred =
     249        __attribute__((unused)) bool local;
     250        __attribute__((unused)) int preferred;
     251        #if defined(BIAS)
     252                preferred =
    213253                        //*
    214254                        kernelTLS.this_processor ? kernelTLS.this_processor->id * 4 : -1;
     
    216256                        thrd->link.preferred * 4;
    217257                        //*/
    218 
    219 
    220258        #endif
    221259
     
    224262        do {
    225263                // Pick the index of a lane
    226                 #if defined(BIAS)
    227                         unsigned r = __tls_rand();
    228                         unsigned rlow  = r % BIAS;
    229                         unsigned rhigh = r / BIAS;
    230                         if((0 != rlow) && preferred >= 0) {
    231                                 // (BIAS - 1) out of BIAS chances
    232                                 // Use perferred queues
    233                                 i = preferred + (rhigh % 4);
    234 
    235                                 #if !defined(__CFA_NO_STATISTICS__)
    236                                         local = true;
    237                                         __tls_stats()->ready.pick.push.local++;
    238                                 #endif
    239                         }
    240                         else {
    241                                 // 1 out of BIAS chances
    242                                 // Use all queues
    243                                 i = rhigh;
    244                                 local = false;
    245                         }
    246                 #else
    247                         i = __tls_rand();
     264                unsigned r = __tls_rand();
     265                [i, local] = idx_from_r(r, preferred);
     266
     267                #if !defined(__CFA_NO_STATISTICS__)
     268                        if(local) {
     269                                __tls_stats()->ready.pick.push.local++;
     270                        }
    248271                #endif
    249272
     
    262285        bool lane_first = push(lanes.data[i], thrd);
    263286
    264         // If this lane used to be empty we need to do more
    265         if(lane_first) {
    266                 // Check if the entire queue used to be empty
    267                 first = !query(snzi);
    268 
    269                 // Update the snzi
    270                 arrive( snzi, i );
    271         }
     287        #ifdef USE_SNZI
     288                // If this lane used to be empty we need to do more
     289                if(lane_first) {
     290                        // Check if the entire queue used to be empty
     291                        first = !query(snzi);
     292
     293                        // Update the snzi
     294                        arrive( snzi, i );
     295                }
     296        #endif
    272297
    273298        // Unlock and return
     
    294319__attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
    295320        /* paranoid */ verify( lanes.count > 0 );
     321        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     322        int preferred;
    296323        #if defined(BIAS)
    297324                // Don't bother trying locally too much
    298325                int local_tries = 8;
    299         #endif
     326                preferred = kernelTLS.this_processor->id * 4;
     327        #endif
     328
    300329
    301330        // As long as the list is not empty, try finding a lane that isn't empty and pop from it
    302         while( query(snzi) ) {
     331        #ifdef USE_SNZI
     332                while( query(snzi) ) {
     333        #else
     334                for(25) {
     335        #endif
    303336                // Pick two lists at random
    304                 unsigned i,j;
    305                 #if defined(BIAS)
    306                         #if !defined(__CFA_NO_STATISTICS__)
    307                                 bool local = false;
    308                         #endif
    309                         uint64_t r = __tls_rand();
    310                         unsigned rlow  = r % BIAS;
    311                         uint64_t rhigh = r / BIAS;
    312                         if(local_tries && 0 != rlow) {
    313                                 // (BIAS - 1) out of BIAS chances
    314                                 // Use perferred queues
    315                                 unsigned pid = kernelTLS.this_processor->id * 4;
    316                                 i = pid + (rhigh % 4);
    317                                 j = pid + ((rhigh >> 32ull) % 4);
    318 
    319                                 // count the tries
    320                                 local_tries--;
    321 
    322                                 #if !defined(__CFA_NO_STATISTICS__)
    323                                         local = true;
    324                                         __tls_stats()->ready.pick.pop.local++;
    325                                 #endif
    326                         }
    327                         else {
    328                                 // 1 out of BIAS chances
    329                                 // Use all queues
    330                                 i = rhigh;
    331                                 j = rhigh >> 32ull;
    332                         }
    333                 #else
    334                         i = __tls_rand();
    335                         j = __tls_rand();
    336                 #endif
    337 
    338                 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    339                 j %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     337                unsigned ri = __tls_rand();
     338                unsigned rj = __tls_rand();
     339
     340                unsigned i, j;
     341                __attribute__((unused)) bool locali, localj;
     342                [i, locali] = idx_from_r(ri, preferred);
     343                [j, localj] = idx_from_r(rj, preferred);
     344
     345                #if !defined(__CFA_NO_STATISTICS__)
     346                        if(locali) {
     347                                __tls_stats()->ready.pick.pop.local++;
     348                        }
     349                        if(localj) {
     350                                __tls_stats()->ready.pick.pop.local++;
     351                        }
     352                #endif
     353
     354                i %= count;
     355                j %= count;
    340356
    341357                // try popping from the 2 picked lists
     
    343359                if(thrd) {
    344360                        #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
    345                                 if( local ) __tls_stats()->ready.pick.pop.lsuccess++;
     361                                if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
    346362                        #endif
    347363                        return thrd;
     
    352368        return 0p;
    353369}
     370
     371__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
     372        /* paranoid */ verify( lanes.count > 0 );
     373        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     374        unsigned offset = __tls_rand();
     375        for(i; count) {
     376                unsigned idx = (offset + i) % count;
     377                struct $thread * thrd = try_pop(cltr, idx);
     378                if(thrd) {
     379                        return thrd;
     380                }
     381        }
     382
     383        // All lanes where empty return 0p
     384        return 0p;
     385}
     386
    354387
    355388//-----------------------------------------------------------------------
     
    388421        // Actually pop the list
    389422        struct $thread * thrd;
    390         bool emptied;
    391         [thrd, emptied] = pop(lane);
     423        thrd = pop(lane);
    392424
    393425        /* paranoid */ verify(thrd);
    394426        /* paranoid */ verify(lane.lock);
    395427
    396         // If this was the last element in the lane
    397         if(emptied) {
    398                 depart( snzi, w );
    399         }
     428        #ifdef USE_SNZI
     429                // If this was the last element in the lane
     430                if(emptied) {
     431                        depart( snzi, w );
     432                }
     433        #endif
    400434
    401435        // Unlock and return
     
    424458                        if(head(lane)->link.next == thrd) {
    425459                                $thread * pthrd;
    426                                 bool emptied;
    427                                 [pthrd, emptied] = pop(lane);
     460                                pthrd = pop(lane);
    428461
    429462                                /* paranoid */ verify( pthrd == thrd );
    430463
    431464                                removed = true;
    432                                 if(emptied) {
    433                                         depart( snzi, i );
    434                                 }
     465                                #ifdef USE_SNZI
     466                                        if(emptied) {
     467                                                depart( snzi, i );
     468                                        }
     469                                #endif
    435470                        }
    436471                __atomic_unlock(&lane.lock);
     
    494529        // grow the ready queue
    495530        with( cltr->ready_queue ) {
    496                 ^(snzi){};
     531                #ifdef USE_SNZI
     532                        ^(snzi){};
     533                #endif
    497534
    498535                // Find new count
     
    516553                lanes.count = ncount;
    517554
    518                 // Re-create the snzi
    519                 snzi{ log2( lanes.count / 8 ) };
    520                 for( idx; (size_t)lanes.count ) {
    521                         if( !is_empty(lanes.data[idx]) ) {
    522                                 arrive(snzi, idx);
    523                         }
    524                 }
     555                #ifdef USE_SNZI
     556                        // Re-create the snzi
     557                        snzi{ log2( lanes.count / 8 ) };
     558                        for( idx; (size_t)lanes.count ) {
     559                                if( !is_empty(lanes.data[idx]) ) {
     560                                        arrive(snzi, idx);
     561                                }
     562                        }
     563                #endif
    525564        }
    526565
     
    542581
    543582        with( cltr->ready_queue ) {
    544                 ^(snzi){};
     583                #ifdef USE_SNZI
     584                        ^(snzi){};
     585                #endif
    545586
    546587                // Remember old count
     
    567608                        while(!is_empty(lanes.data[idx])) {
    568609                                struct $thread * thrd;
    569                                 __attribute__((unused)) bool _;
    570                                 [thrd, _] = pop(lanes.data[idx]);
     610                                thrd = pop(lanes.data[idx]);
    571611
    572612                                push(cltr, thrd);
     
    596636                }
    597637
    598                 // Re-create the snzi
    599                 snzi{ log2( lanes.count / 8 ) };
    600                 for( idx; (size_t)lanes.count ) {
    601                         if( !is_empty(lanes.data[idx]) ) {
    602                                 arrive(snzi, idx);
    603                         }
    604                 }
     638                #ifdef USE_SNZI
     639                        // Re-create the snzi
     640                        snzi{ log2( lanes.count / 8 ) };
     641                        for( idx; (size_t)lanes.count ) {
     642                                if( !is_empty(lanes.data[idx]) ) {
     643                                        arrive(snzi, idx);
     644                                }
     645                        }
     646                #endif
    605647        }
    606648
Note: See TracChangeset for help on using the changeset viewer.