Ignore:
File:
1 edited

Legend:

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

    rc9c1c1cb r7cf3b1d  
    4242
    4343#if !defined(__CFA_NO_STATISTICS__)
    44         #define __STATS_DEF( ...) __VA_ARGS__
     44        #define __STATS( ...) __VA_ARGS__
    4545#else
    46         #define __STATS_DEF( ...)
     46        #define __STATS( ...)
    4747#endif
    4848
     
    122122static thread$ * __next_thread(cluster * this);
    123123static thread$ * __next_thread_slow(cluster * this);
    124 static thread$ * __next_thread_search(cluster * this);
    125124static inline bool __must_unpark( thread$ * thrd ) __attribute((nonnull(1)));
    126125static void __run_thread(processor * this, thread$ * dst);
     
    188187                MAIN_LOOP:
    189188                for() {
     189                        #define OLD_MAIN 1
     190                        #if OLD_MAIN
    190191                        // Check if there is pending io
    191192                        __maybe_io_drain( this );
     
    195196
    196197                        if( !readyThread ) {
    197                                 __IO_STATS__(true, io.flush.idle++; )
    198198                                __cfa_io_flush( this, 0 );
    199199
    200                                 readyThread = __next_thread( this->cltr );
    201                         }
    202 
    203                         if( !readyThread ) for(5) {
    204                                 __IO_STATS__(true, io.flush.idle++; )
    205 
    206200                                readyThread = __next_thread_slow( this->cltr );
    207 
    208                                 if( readyThread ) break;
    209 
    210                                 __cfa_io_flush( this, 0 );
    211201                        }
    212202
     
    220210
    221211                                // Confirm the ready-queue is empty
    222                                 readyThread = __next_thread_search( this->cltr );
     212                                readyThread = __next_thread_slow( this->cltr );
    223213                                if( readyThread ) {
    224214                                        // A thread was found, cancel the halt
    225215                                        mark_awake(this->cltr->procs, * this);
    226216
    227                                         __STATS__(true, ready.sleep.cancels++; )
     217                                        #if !defined(__CFA_NO_STATISTICS__)
     218                                                __tls_stats()->ready.sleep.cancels++;
     219                                        #endif
    228220
    229221                                        // continue the mai loop
     
    252244
    253245                        if(this->io.pending && !this->io.dirty) {
    254                                 __IO_STATS__(true, io.flush.dirty++; )
    255246                                __cfa_io_flush( this, 0 );
    256247                        }
     248
     249                        #else
     250                                #warning new kernel loop
     251                        SEARCH: {
     252                                /* paranoid */ verify( ! __preemption_enabled() );
     253
     254                                // First, lock the scheduler since we are searching for a thread
     255                                ready_schedule_lock();
     256
     257                                // Try to get the next thread
     258                                readyThread = pop_fast( this->cltr );
     259                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     260
     261                                // If we can't find a thread, might as well flush any outstanding I/O
     262                                if(this->io.pending) { __cfa_io_flush( this, 0 ); }
     263
     264                                // Spin a little on I/O, just in case
     265                                for(5) {
     266                                        __maybe_io_drain( this );
     267                                        readyThread = pop_fast( this->cltr );
     268                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     269                                }
     270
     271                                // no luck, try stealing a few times
     272                                for(5) {
     273                                        if( __maybe_io_drain( this ) ) {
     274                                                readyThread = pop_fast( this->cltr );
     275                                        } else {
     276                                                readyThread = pop_slow( this->cltr );
     277                                        }
     278                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     279                                }
     280
     281                                // still no luck, search for a thread
     282                                readyThread = pop_search( this->cltr );
     283                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     284
     285                                // Don't block if we are done
     286                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) {
     287                                        ready_schedule_unlock();
     288                                        break MAIN_LOOP;
     289                                }
     290
     291                                __STATS( __tls_stats()->ready.sleep.halts++; )
     292
     293                                // Push self to idle stack
     294                                ready_schedule_unlock();
     295                                if(!mark_idle(this->cltr->procs, * this)) goto SEARCH;
     296                                ready_schedule_lock();
     297
     298                                // Confirm the ready-queue is empty
     299                                __maybe_io_drain( this );
     300                                readyThread = pop_search( this->cltr );
     301                                ready_schedule_unlock();
     302
     303                                if( readyThread ) {
     304                                        // A thread was found, cancel the halt
     305                                        mark_awake(this->cltr->procs, * this);
     306
     307                                        __STATS( __tls_stats()->ready.sleep.cancels++; )
     308
     309                                        // continue the main loop
     310                                        break SEARCH;
     311                                }
     312
     313                                __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
     314                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
     315
     316                                {
     317                                        eventfd_t val;
     318                                        ssize_t ret = read( this->idle_fd, &val, sizeof(val) );
     319                                        if(ret < 0) {
     320                                                switch((int)errno) {
     321                                                case EAGAIN:
     322                                                #if EAGAIN != EWOULDBLOCK
     323                                                        case EWOULDBLOCK:
     324                                                #endif
     325                                                case EINTR:
     326                                                        // No need to do anything special here, just assume it's a legitimate wake-up
     327                                                        break;
     328                                                default:
     329                                                        abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     330                                                }
     331                                        }
     332                                }
     333
     334                                        __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
     335
     336                                // We were woken up, remove self from idle
     337                                mark_awake(this->cltr->procs, * this);
     338
     339                                // DON'T just proceed, start looking again
     340                                continue MAIN_LOOP;
     341                        }
     342
     343                RUN_THREAD:
     344                        /* paranoid */ verify( ! __preemption_enabled() );
     345                        /* paranoid */ verify( readyThread );
     346
     347                        // Reset io dirty bit
     348                        this->io.dirty = false;
     349
     350                        // We found a thread run it
     351                        __run_thread(this, readyThread);
     352
     353                        // Are we done?
     354                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     355
     356                        if(this->io.pending && !this->io.dirty) {
     357                                __cfa_io_flush( this, 0 );
     358                        }
     359
     360                        ready_schedule_lock();
     361                        __maybe_io_drain( this );
     362                        ready_schedule_unlock();
     363                        #endif
    257364                }
    258365
     
    365472                                break RUNNING;
    366473                        case TICKET_UNBLOCK:
    367                                 __STATS__(true, ready.threads.threads++; )
     474                                #if !defined(__CFA_NO_STATISTICS__)
     475                                        __tls_stats()->ready.threads.threads++;
     476                                #endif
    368477                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    369478                                // In this case, just run it again.
     
    380489        __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst);
    381490
    382         __STATS__(true, ready.threads.threads--; )
     491        #if !defined(__CFA_NO_STATISTICS__)
     492                __tls_stats()->ready.threads.threads--;
     493        #endif
    383494
    384495        /* paranoid */ verify( ! __preemption_enabled() );
     
    391502        thread$ * thrd_src = kernelTLS().this_thread;
    392503
    393         __STATS_DEF( thrd_src->last_proc = kernelTLS().this_processor; )
     504        __STATS( thrd_src->last_proc = kernelTLS().this_processor; )
    394505
    395506        // Run the thread on this processor
     
    443554        // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    444555        struct cluster * cl = thrd->curr_cluster;
    445         __STATS_DEF(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
     556        __STATS(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
    446557
    447558        // push the thread to the cluster ready-queue
     
    494605
    495606        ready_schedule_lock();
    496                 thread$ * thrd = pop_slow( this );
    497         ready_schedule_unlock();
    498 
    499         /* paranoid */ verify( ! __preemption_enabled() );
    500         return thrd;
    501 }
    502 
    503 // KERNEL ONLY
    504 static inline thread$ * __next_thread_search(cluster * this) with( *this ) {
    505         /* paranoid */ verify( ! __preemption_enabled() );
    506 
    507         ready_schedule_lock();
    508                 thread$ * thrd = pop_search( this );
     607                thread$ * thrd;
     608                for(25) {
     609                        thrd = pop_slow( this );
     610                        if(thrd) goto RET;
     611                }
     612                thrd = pop_search( this );
     613
     614                RET:
    509615        ready_schedule_unlock();
    510616
     
    748854
    749855static bool mark_idle(__cluster_proc_list & this, processor & proc) {
    750         __STATS__(true, ready.sleep.halts++; )
     856        #if !defined(__CFA_NO_STATISTICS__)
     857                __tls_stats()->ready.sleep.halts++;
     858        #endif
    751859
    752860        proc.idle_wctx.fd = 0;
     
    841949                unsigned tail = *ctx->cq.tail;
    842950                if(head == tail) return false;
    843                 ready_schedule_lock();
    844                 ret = __cfa_io_drain( proc );
    845                 ready_schedule_unlock();
     951                #if OLD_MAIN
     952                        ready_schedule_lock();
     953                        ret = __cfa_io_drain( proc );
     954                        ready_schedule_unlock();
     955                #else
     956                        ret = __cfa_io_drain( proc );
     957                #endif
    846958        #endif
    847959        return ret;
Note: See TracChangeset for help on using the changeset viewer.