Ignore:
File:
1 edited

Legend:

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

    rceb7db8 rfd9b524  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
    19 // #define USE_SNZI
    20 
    2119#include "bits/defs.hfa"
    2220#include "kernel_private.hfa"
     
    150148//  queues or removing them.
    151149uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
    152         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    153 
    154150        // Step 1 : lock global lock
    155151        // It is needed to avoid processors that register mid Critical-Section
     
    166162        }
    167163
    168         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    169164        return s;
    170165}
    171166
    172167void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
    173         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    174 
    175168        // Step 1 : release local locks
    176169        // This must be done while the global lock is held to avoid
     
    187180        /*paranoid*/ assert(true == lock);
    188181        __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
    189 
    190         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    191182}
    192183
     
    201192void ^?{}(__ready_queue_t & this) with (this) {
    202193        verify( 1 == lanes.count );
    203         #ifdef USE_SNZI
    204                 verify( !query( snzi ) );
    205         #endif
     194        verify( !query( snzi ) );
    206195        free(lanes.data);
    207196}
     
    209198//-----------------------------------------------------------------------
    210199__attribute__((hot)) bool query(struct cluster * cltr) {
    211         #ifdef USE_SNZI
    212                 return query(cltr->ready_queue.snzi);
    213         #endif
    214         return true;
    215 }
    216 
    217 static 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];
     200        return query(cltr->ready_queue.snzi);
    240201}
    241202
     
    247208        thrd->link.ts = rdtscl();
    248209
    249         __attribute__((unused)) bool local;
    250         __attribute__((unused)) int preferred;
    251         #if defined(BIAS)
    252                 preferred =
     210        #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
     211                bool local = false;
     212                int preferred =
    253213                        //*
    254214                        kernelTLS.this_processor ? kernelTLS.this_processor->id * 4 : -1;
     
    256216                        thrd->link.preferred * 4;
    257217                        //*/
     218
     219
    258220        #endif
    259221
     
    262224        do {
    263225                // Pick the index of a lane
    264                 // unsigned r = __tls_rand();
    265                 unsigned r = __tls_rand_fwd();
    266                 [i, local] = idx_from_r(r, preferred);
    267 
    268                 #if !defined(__CFA_NO_STATISTICS__)
    269                         if(local) {
    270                                 __tls_stats()->ready.pick.push.local++;
    271                         }
     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();
    272248                #endif
    273249
     
    284260
    285261        // Actually push it
    286         #ifdef USE_SNZI
    287                 bool lane_first =
    288         #endif
    289 
    290         push(lanes.data[i], thrd);
    291 
    292         #ifdef USE_SNZI
    293                 // If this lane used to be empty we need to do more
    294                 if(lane_first) {
    295                         // Check if the entire queue used to be empty
    296                         first = !query(snzi);
    297 
    298                         // Update the snzi
    299                         arrive( snzi, i );
    300                 }
    301         #endif
    302 
    303         __tls_rand_advance_bck();
     262        bool lane_first = push(lanes.data[i], thrd);
     263
     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        }
    304272
    305273        // Unlock and return
     
    326294__attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
    327295        /* paranoid */ verify( lanes.count > 0 );
    328         unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    329         int preferred;
    330296        #if defined(BIAS)
    331297                // Don't bother trying locally too much
    332298                int local_tries = 8;
    333                 preferred = kernelTLS.this_processor->id * 4;
    334299        #endif
    335300
    336 
    337301        // As long as the list is not empty, try finding a lane that isn't empty and pop from it
    338         #ifdef USE_SNZI
    339                 while( query(snzi) ) {
    340         #else
    341                 for(25) {
    342         #endif
     302        while( query(snzi) ) {
    343303                // Pick two lists at random
    344                 // unsigned ri = __tls_rand();
    345                 // unsigned rj = __tls_rand();
    346                 unsigned ri = __tls_rand_bck();
    347                 unsigned rj = __tls_rand_bck();
    348 
    349                 unsigned i, j;
    350                 __attribute__((unused)) bool locali, localj;
    351                 [i, locali] = idx_from_r(ri, preferred);
    352                 [j, localj] = idx_from_r(rj, preferred);
    353 
    354                 #if !defined(__CFA_NO_STATISTICS__)
    355                         if(locali) {
    356                                 __tls_stats()->ready.pick.pop.local++;
    357                         }
    358                         if(localj) {
    359                                 __tls_stats()->ready.pick.pop.local++;
    360                         }
     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();
    361336                #endif
    362337
    363                 i %= count;
    364                 j %= count;
     338                i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     339                j %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    365340
    366341                // try popping from the 2 picked lists
     
    368343                if(thrd) {
    369344                        #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
    370                                 if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
     345                                if( local ) __tls_stats()->ready.pick.pop.lsuccess++;
    371346                        #endif
    372347                        return thrd;
     
    377352        return 0p;
    378353}
    379 
    380 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
    381         /* paranoid */ verify( lanes.count > 0 );
    382         unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    383         unsigned offset = __tls_rand();
    384         for(i; count) {
    385                 unsigned idx = (offset + i) % count;
    386                 struct $thread * thrd = try_pop(cltr, idx);
    387                 if(thrd) {
    388                         return thrd;
    389                 }
    390         }
    391 
    392         // All lanes where empty return 0p
    393         return 0p;
    394 }
    395 
    396354
    397355//-----------------------------------------------------------------------
     
    430388        // Actually pop the list
    431389        struct $thread * thrd;
    432         thrd = pop(lane);
     390        bool emptied;
     391        [thrd, emptied] = pop(lane);
    433392
    434393        /* paranoid */ verify(thrd);
    435394        /* paranoid */ verify(lane.lock);
    436395
    437         #ifdef USE_SNZI
    438                 // If this was the last element in the lane
    439                 if(emptied) {
    440                         depart( snzi, w );
    441                 }
    442         #endif
     396        // If this was the last element in the lane
     397        if(emptied) {
     398                depart( snzi, w );
     399        }
    443400
    444401        // Unlock and return
     
    467424                        if(head(lane)->link.next == thrd) {
    468425                                $thread * pthrd;
    469                                 pthrd = pop(lane);
     426                                bool emptied;
     427                                [pthrd, emptied] = pop(lane);
    470428
    471429                                /* paranoid */ verify( pthrd == thrd );
    472430
    473431                                removed = true;
    474                                 #ifdef USE_SNZI
    475                                         if(emptied) {
    476                                                 depart( snzi, i );
    477                                         }
    478                                 #endif
     432                                if(emptied) {
     433                                        depart( snzi, i );
     434                                }
    479435                        }
    480436                __atomic_unlock(&lane.lock);
     
    538494        // grow the ready queue
    539495        with( cltr->ready_queue ) {
    540                 #ifdef USE_SNZI
    541                         ^(snzi){};
    542                 #endif
     496                ^(snzi){};
    543497
    544498                // Find new count
     
    547501
    548502                // Allocate new array (uses realloc and memcpies the data)
    549                 lanes.data = alloc( ncount, lanes.data`realloc );
     503                lanes.data = alloc(lanes.data, ncount);
    550504
    551505                // Fix the moved data
     
    562516                lanes.count = ncount;
    563517
    564                 #ifdef USE_SNZI
    565                         // Re-create the snzi
    566                         snzi{ log2( lanes.count / 8 ) };
    567                         for( idx; (size_t)lanes.count ) {
    568                                 if( !is_empty(lanes.data[idx]) ) {
    569                                         arrive(snzi, idx);
    570                                 }
    571                         }
    572                 #endif
     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                }
    573525        }
    574526
     
    590542
    591543        with( cltr->ready_queue ) {
    592                 #ifdef USE_SNZI
    593                         ^(snzi){};
    594                 #endif
     544                ^(snzi){};
    595545
    596546                // Remember old count
     
    617567                        while(!is_empty(lanes.data[idx])) {
    618568                                struct $thread * thrd;
    619                                 thrd = pop(lanes.data[idx]);
     569                                __attribute__((unused)) bool _;
     570                                [thrd, _] = pop(lanes.data[idx]);
    620571
    621572                                push(cltr, thrd);
     
    638589
    639590                // Allocate new array (uses realloc and memcpies the data)
    640                 lanes.data = alloc( lanes.count, lanes.data`realloc );
     591                lanes.data = alloc(lanes.data, lanes.count);
    641592
    642593                // Fix the moved data
     
    645596                }
    646597
    647                 #ifdef USE_SNZI
    648                         // Re-create the snzi
    649                         snzi{ log2( lanes.count / 8 ) };
    650                         for( idx; (size_t)lanes.count ) {
    651                                 if( !is_empty(lanes.data[idx]) ) {
    652                                         arrive(snzi, idx);
    653                                 }
    654                         }
    655                 #endif
     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                }
    656605        }
    657606
Note: See TracChangeset for help on using the changeset viewer.