Ignore:
Timestamp:
Aug 10, 2020, 2:43:02 PM (4 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
8465b4d
Parents:
6c144d8
Message:

Removed snzi and replaced it with a fast/slow path

File:
1 edited

Legend:

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

    r6c144d8 r1eb239e4  
    8686// Kernel Scheduling logic
    8787static $thread * __next_thread(cluster * this);
    88 static bool __has_next_thread(cluster * this);
     88static $thread * __next_thread_slow(cluster * this);
    8989static void __run_thread(processor * this, $thread * dst);
    90 static bool __wake_one(struct __processor_id_t * id, cluster * cltr);
    91 static void __halt(processor * this);
    92 bool __wake_proc(processor *);
     90static void __wake_one(struct __processor_id_t * id, cluster * cltr);
     91
     92static void push  (__cluster_idles & idles, processor & proc);
     93static void remove(__cluster_idles & idles, processor & proc);
     94static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
     95
    9396
    9497//=============================================================================================
     
    118121
    119122                $thread * readyThread = 0p;
    120                 for( unsigned int spin_count = 0;; spin_count++ ) {
     123                MAIN_LOOP:
     124                for() {
    121125                        // Try to get the next thread
    122126                        readyThread = __next_thread( this->cltr );
    123127
    124                         // Check if we actually found a thread
    125                         if( readyThread ) {
    126                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    127                                 /* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted);
    128                                 /* paranoid */ verifyf( readyThread->link.next == 0p, "Expected null got %p", readyThread->link.next );
    129                                 __builtin_prefetch( readyThread->context.SP );
    130 
    131                                 // We found a thread run it
    132                                 __run_thread(this, readyThread);
    133 
    134                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     128                        if( !readyThread ) {
     129                                readyThread = __next_thread_slow( this->cltr );
    135130                        }
    136131
    137                         if(__atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST)) break;
    138 
     132                        HALT:
    139133                        if( !readyThread ) {
    140                                 // Block until a thread is ready
    141                                 __halt(this);
     134                                // Don't block if we are done
     135                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     136
     137                                #if !defined(__CFA_NO_STATISTICS__)
     138                                        __tls_stats()->ready.sleep.halts++;
     139                                #endif
     140
     141                                // Push self to idle stack
     142                                push(this->cltr->idles, * this);
     143
     144                                // Confirm the ready-queue is empty
     145                                readyThread = __next_thread_slow( this->cltr );
     146                                if( readyThread ) {
     147                                        // A thread was found, cancel the halt
     148                                        remove(this->cltr->idles, * this);
     149
     150                                        #if !defined(__CFA_NO_STATISTICS__)
     151                                                __tls_stats()->ready.sleep.cancels++;
     152                                        #endif
     153
     154                                        // continue the mai loop
     155                                        break HALT;
     156                                }
     157
     158                                #if !defined(__CFA_NO_STATISTICS__)
     159                                        if(this->print_halts) {
     160                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
     161                                        }
     162                                #endif
     163
     164                                wait( this->idle );
     165
     166                                #if !defined(__CFA_NO_STATISTICS__)
     167                                        if(this->print_halts) {
     168                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
     169                                        }
     170                                #endif
     171
     172                                // We were woken up, remove self from idle
     173                                remove(this->cltr->idles, * this);
     174
     175                                // DON'T just proceed, start looking again
     176                                continue MAIN_LOOP;
    142177                        }
     178
     179                        /* paranoid */ verify( readyThread );
     180
     181                        // We found a thread run it
     182                        __run_thread(this, readyThread);
     183
     184                        // Are we done?
     185                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    143186                }
    144187
     
    165208// from the processor coroutine to the target thread
    166209static void __run_thread(processor * this, $thread * thrd_dst) {
     210        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     211        /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
     212        /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
     213        __builtin_prefetch( thrd_dst->context.SP );
     214
    167215        $coroutine * proc_cor = get_coroutine(this->runner);
    168216
     
    244292        proc_cor->state = Active;
    245293        kernelTLS.this_thread = 0p;
     294
     295        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    246296}
    247297
     
    300350        ready_schedule_lock  ( id );
    301351                push( thrd->curr_cluster, thrd );
    302 
    303                 #if !defined(__CFA_NO_STATISTICS__)
    304                         bool woke =
    305                 #endif
    306                         __wake_one(id, thrd->curr_cluster);
    307 
    308                 #if !defined(__CFA_NO_STATISTICS__)
    309                         if(woke) __tls_stats()->ready.sleep.wakes++;
    310                 #endif
     352                __wake_one(id, thrd->curr_cluster);
    311353        ready_schedule_unlock( id );
    312354
     
    315357
    316358// KERNEL ONLY
    317 static $thread * __next_thread(cluster * this) with( *this ) {
     359static inline $thread * __next_thread(cluster * this) with( *this ) {
    318360        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    319361
    320362        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    321                 $thread * head = pop( this );
     363                $thread * thrd = pop( this );
    322364        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    323365
    324366        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    325         return head;
     367        return thrd;
    326368}
    327369
    328370// KERNEL ONLY
    329 static bool __has_next_thread(cluster * this) with( *this ) {
     371static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    330372        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    331373
    332374        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    333                 bool not_empty = query( this );
     375                $thread * thrd = pop_slow( this );
    334376        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    335377
    336378        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    337         return not_empty;
     379        return thrd;
    338380}
    339381
     
    425467//=============================================================================================
    426468// Wake a thread from the front if there are any
    427 static bool __wake_one(struct __processor_id_t * id, cluster * this) {
     469static void __wake_one(struct __processor_id_t * id, cluster * this) {
     470        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    428471        /* paranoid */ verify( ready_schedule_islocked( id ) );
    429472
    430473        // Check if there is a sleeping processor
    431         processor * p = pop(this->idles);
     474        processor * p;
     475        unsigned idle;
     476        unsigned total;
     477        [idle, total, p] = query(this->idles);
    432478
    433479        // If no one is sleeping, we are done
    434         if( 0p == p ) return false;
     480        if( idle == 0 ) return;
    435481
    436482        // We found a processor, wake it up
    437483        post( p->idle );
    438484
    439         return true;
     485        #if !defined(__CFA_NO_STATISTICS__)
     486                __tls_stats()->ready.sleep.wakes++;
     487        #endif
     488
     489        /* paranoid */ verify( ready_schedule_islocked( id ) );
     490        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     491
     492        return;
    440493}
    441494
    442495// Unconditionnaly wake a thread
    443 bool __wake_proc(processor * this) {
     496void __wake_proc(processor * this) {
    444497        __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    445498
     
    448501                bool ret = post( this->idle );
    449502        enable_interrupts( __cfaabi_dbg_ctx );
    450 
    451         return ret;
    452 }
    453 
    454 static void __halt(processor * this) with( *this ) {
    455         if( do_terminate ) return;
    456 
    457         #if !defined(__CFA_NO_STATISTICS__)
    458                 __tls_stats()->ready.sleep.halts++;
    459         #endif
    460         // Push self to queue
    461         push(cltr->idles, *this);
    462 
    463         // Makre sure we don't miss a thread
    464         if( __has_next_thread(cltr) ) {
    465                 // A thread was posted, make sure a processor is woken up
    466                 struct __processor_id_t *id = (struct __processor_id_t *) this;
    467                 ready_schedule_lock  ( id );
    468                         __wake_one( id, cltr );
    469                 ready_schedule_unlock( id );
    470                 #if !defined(__CFA_NO_STATISTICS__)
    471                         __tls_stats()->ready.sleep.cancels++;
    472                 #endif
    473         }
    474 
    475         #if !defined(__CFA_NO_STATISTICS__)
    476                 if(this->print_halts) {
    477                         __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
    478                 }
    479         #endif
    480 
    481         wait( idle );
    482 
    483         #if !defined(__CFA_NO_STATISTICS__)
    484                 if(this->print_halts) {
    485                         __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
    486                 }
    487         #endif
     503}
     504
     505static void push  (__cluster_idles & this, processor & proc) {
     506        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     507        lock( this );
     508                this.idle++;
     509                /* paranoid */ verify( this.idle <= this.total );
     510
     511                insert_first(this.list, proc);
     512        unlock( this );
     513        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     514}
     515
     516static void remove(__cluster_idles & this, processor & proc) {
     517        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     518        lock( this );
     519                this.idle--;
     520                /* paranoid */ verify( this.idle >= 0 );
     521
     522                remove(proc);
     523        unlock( this );
     524        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     525}
     526
     527static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
     528        for() {
     529                uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
     530                if( 1 == (l % 2) ) { Pause(); continue; }
     531                unsigned idle    = this.idle;
     532                unsigned total   = this.total;
     533                processor * proc = &this.list`first;
     534                if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; }
     535                return [idle, total, proc];
     536        }
    488537}
    489538
Note: See TracChangeset for help on using the changeset viewer.