Ignore:
File:
1 edited

Legend:

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

    rc9c1c1cb r70b4aeb9  
    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++; )
     198                                __tls_stats()->io.flush.idle++;
    198199                                __cfa_io_flush( this, 0 );
    199200
    200                                 readyThread = __next_thread( this->cltr );
    201                         }
    202 
    203                         if( !readyThread ) for(5) {
    204                                 __IO_STATS__(true, io.flush.idle++; )
    205 
    206201                                readyThread = __next_thread_slow( this->cltr );
    207 
    208                                 if( readyThread ) break;
    209 
    210                                 __cfa_io_flush( this, 0 );
    211202                        }
    212203
     
    220211
    221212                                // Confirm the ready-queue is empty
    222                                 readyThread = __next_thread_search( this->cltr );
     213                                readyThread = __next_thread_slow( this->cltr );
    223214                                if( readyThread ) {
    224215                                        // A thread was found, cancel the halt
    225216                                        mark_awake(this->cltr->procs, * this);
    226217
    227                                         __STATS__(true, ready.sleep.cancels++; )
     218                                        #if !defined(__CFA_NO_STATISTICS__)
     219                                                __tls_stats()->ready.sleep.cancels++;
     220                                        #endif
    228221
    229222                                        // continue the mai loop
     
    252245
    253246                        if(this->io.pending && !this->io.dirty) {
    254                                 __IO_STATS__(true, io.flush.dirty++; )
     247                                __tls_stats()->io.flush.dirty++;
    255248                                __cfa_io_flush( this, 0 );
    256249                        }
     250
     251                        #else
     252                                #warning new kernel loop
     253                        SEARCH: {
     254                                /* paranoid */ verify( ! __preemption_enabled() );
     255
     256                                // First, lock the scheduler since we are searching for a thread
     257                                ready_schedule_lock();
     258
     259                                // Try to get the next thread
     260                                readyThread = pop_fast( this->cltr );
     261                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     262
     263                                // If we can't find a thread, might as well flush any outstanding I/O
     264                                if(this->io.pending) { __cfa_io_flush( this, 0 ); }
     265
     266                                // Spin a little on I/O, just in case
     267                                for(5) {
     268                                        __maybe_io_drain( this );
     269                                        readyThread = pop_fast( this->cltr );
     270                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     271                                }
     272
     273                                // no luck, try stealing a few times
     274                                for(5) {
     275                                        if( __maybe_io_drain( this ) ) {
     276                                                readyThread = pop_fast( this->cltr );
     277                                        } else {
     278                                                readyThread = pop_slow( this->cltr );
     279                                        }
     280                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     281                                }
     282
     283                                // still no luck, search for a thread
     284                                readyThread = pop_search( this->cltr );
     285                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     286
     287                                // Don't block if we are done
     288                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) {
     289                                        ready_schedule_unlock();
     290                                        break MAIN_LOOP;
     291                                }
     292
     293                                __STATS( __tls_stats()->ready.sleep.halts++; )
     294
     295                                // Push self to idle stack
     296                                ready_schedule_unlock();
     297                                if(!mark_idle(this->cltr->procs, * this)) goto SEARCH;
     298                                ready_schedule_lock();
     299
     300                                // Confirm the ready-queue is empty
     301                                __maybe_io_drain( this );
     302                                readyThread = pop_search( this->cltr );
     303                                ready_schedule_unlock();
     304
     305                                if( readyThread ) {
     306                                        // A thread was found, cancel the halt
     307                                        mark_awake(this->cltr->procs, * this);
     308
     309                                        __STATS( __tls_stats()->ready.sleep.cancels++; )
     310
     311                                        // continue the main loop
     312                                        break SEARCH;
     313                                }
     314
     315                                __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
     316                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
     317
     318                                {
     319                                        eventfd_t val;
     320                                        ssize_t ret = read( this->idle_fd, &val, sizeof(val) );
     321                                        if(ret < 0) {
     322                                                switch((int)errno) {
     323                                                case EAGAIN:
     324                                                #if EAGAIN != EWOULDBLOCK
     325                                                        case EWOULDBLOCK:
     326                                                #endif
     327                                                case EINTR:
     328                                                        // No need to do anything special here, just assume it's a legitimate wake-up
     329                                                        break;
     330                                                default:
     331                                                        abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     332                                                }
     333                                        }
     334                                }
     335
     336                                        __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
     337
     338                                // We were woken up, remove self from idle
     339                                mark_awake(this->cltr->procs, * this);
     340
     341                                // DON'T just proceed, start looking again
     342                                continue MAIN_LOOP;
     343                        }
     344
     345                RUN_THREAD:
     346                        /* paranoid */ verify( ! __preemption_enabled() );
     347                        /* paranoid */ verify( readyThread );
     348
     349                        // Reset io dirty bit
     350                        this->io.dirty = false;
     351
     352                        // We found a thread run it
     353                        __run_thread(this, readyThread);
     354
     355                        // Are we done?
     356                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     357
     358                        if(this->io.pending && !this->io.dirty) {
     359                                __cfa_io_flush( this, 0 );
     360                        }
     361
     362                        ready_schedule_lock();
     363                        __maybe_io_drain( this );
     364                        ready_schedule_unlock();
     365                        #endif
    257366                }
    258367
     
    365474                                break RUNNING;
    366475                        case TICKET_UNBLOCK:
    367                                 __STATS__(true, ready.threads.threads++; )
     476                                #if !defined(__CFA_NO_STATISTICS__)
     477                                        __tls_stats()->ready.threads.threads++;
     478                                #endif
    368479                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    369480                                // In this case, just run it again.
     
    380491        __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst);
    381492
    382         __STATS__(true, ready.threads.threads--; )
     493        #if !defined(__CFA_NO_STATISTICS__)
     494                __tls_stats()->ready.threads.threads--;
     495        #endif
    383496
    384497        /* paranoid */ verify( ! __preemption_enabled() );
     
    391504        thread$ * thrd_src = kernelTLS().this_thread;
    392505
    393         __STATS_DEF( thrd_src->last_proc = kernelTLS().this_processor; )
     506        __STATS( thrd_src->last_proc = kernelTLS().this_processor; )
    394507
    395508        // Run the thread on this processor
     
    443556        // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    444557        struct cluster * cl = thrd->curr_cluster;
    445         __STATS_DEF(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
     558        __STATS(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
    446559
    447560        // push the thread to the cluster ready-queue
     
    494607
    495608        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 );
     609                thread$ * thrd;
     610                for(25) {
     611                        thrd = pop_slow( this );
     612                        if(thrd) goto RET;
     613                }
     614                thrd = pop_search( this );
     615
     616                RET:
    509617        ready_schedule_unlock();
    510618
     
    748856
    749857static bool mark_idle(__cluster_proc_list & this, processor & proc) {
    750         __STATS__(true, ready.sleep.halts++; )
     858        #if !defined(__CFA_NO_STATISTICS__)
     859                __tls_stats()->ready.sleep.halts++;
     860        #endif
    751861
    752862        proc.idle_wctx.fd = 0;
     
    841951                unsigned tail = *ctx->cq.tail;
    842952                if(head == tail) return false;
    843                 ready_schedule_lock();
    844                 ret = __cfa_io_drain( proc );
    845                 ready_schedule_unlock();
     953                #if OLD_MAIN
     954                        ready_schedule_lock();
     955                        ret = __cfa_io_drain( proc );
     956                        ready_schedule_unlock();
     957                #else
     958                        ret = __cfa_io_drain( proc );
     959                #endif
    846960        #endif
    847961        return ret;
Note: See TracChangeset for help on using the changeset viewer.