Ignore:
Timestamp:
Jan 25, 2022, 4:16:00 PM (2 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
Children:
4fcbf26
Parents:
b200492
Message:

Added level of indirection to idle sleeps which helps statistics.

File:
1 edited

Legend:

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

    rb200492 r7cf3b1d  
    205205                                // Don't block if we are done
    206206                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    207 
    208                                 #if !defined(__CFA_NO_STATISTICS__)
    209                                         __tls_stats()->ready.sleep.halts++;
    210                                 #endif
    211207
    212208                                // Push self to idle stack
     
    732728// Wake a thread from the front if there are any
    733729static void __wake_one(cluster * this) {
     730        eventfd_t val;
     731
    734732        /* paranoid */ verify( ! __preemption_enabled() );
    735733        /* paranoid */ verify( ready_schedule_islocked() );
    736734
    737735        // Check if there is a sleeping processor
    738         // int fd = __atomic_load_n(&this->procs.fd, __ATOMIC_SEQ_CST);
    739         int fd = 0;
    740         if( __atomic_load_n(&this->procs.fd, __ATOMIC_SEQ_CST) != 0 ) {
    741                 fd = __atomic_exchange_n(&this->procs.fd, 0, __ATOMIC_RELAXED);
    742         }
    743 
    744         // If no one is sleeping, we are done
    745         if( fd == 0 ) return;
    746 
    747         // We found a processor, wake it up
    748         eventfd_t val;
    749         val = 1;
    750         eventfd_write( fd, val );
    751 
    752         #if !defined(__CFA_NO_STATISTICS__)
    753                 if( kernelTLS().this_stats ) {
    754                         __tls_stats()->ready.sleep.wakes++;
    755                 }
    756                 else {
    757                         __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED);
    758                 }
    759         #endif
     736        struct __fd_waitctx * fdp = __atomic_load_n(&this->procs.fdw, __ATOMIC_SEQ_CST);
     737
     738        // If no one is sleeping: we are done
     739        if( fdp == 0p ) return;
     740
     741        int fd = 1;
     742        if( __atomic_load_n(&fdp->fd, __ATOMIC_SEQ_CST) != 1 ) {
     743                fd = __atomic_exchange_n(&fdp->fd, 1, __ATOMIC_RELAXED);
     744        }
     745
     746        switch(fd) {
     747        case 0:
     748                // If the processor isn't ready to sleep then the exchange will already wake it up
     749                #if !defined(__CFA_NO_STATISTICS__)
     750                        if( kernelTLS().this_stats ) { __tls_stats()->ready.sleep.early++;
     751                        } else { __atomic_fetch_add(&this->stats->ready.sleep.early, 1, __ATOMIC_RELAXED); }
     752                #endif
     753                break;
     754        case 1:
     755                // If someone else already said they will wake them: we are done
     756                #if !defined(__CFA_NO_STATISTICS__)
     757                        if( kernelTLS().this_stats ) { __tls_stats()->ready.sleep.seen++;
     758                        } else { __atomic_fetch_add(&this->stats->ready.sleep.seen, 1, __ATOMIC_RELAXED); }
     759                #endif
     760                break;
     761        default:
     762                // If the processor was ready to sleep, we need to wake it up with an actual write
     763                val = 1;
     764                eventfd_write( fd, val );
     765
     766                #if !defined(__CFA_NO_STATISTICS__)
     767                        if( kernelTLS().this_stats ) { __tls_stats()->ready.sleep.wakes++;
     768                        } else { __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED); }
     769                #endif
     770                break;
     771        }
    760772
    761773        /* paranoid */ verify( ready_schedule_islocked() );
     
    770782
    771783        __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
     784
     785        this->idle_wctx.fd = 1;
    772786
    773787        eventfd_t val;
     
    779793
    780794static void idle_sleep(processor * this, io_future_t & future, iovec & iov) {
     795        // Tell everyone we are ready to go do sleep
     796        for() {
     797                int expected = this->idle_wctx.fd;
     798
     799                // Someone already told us to wake-up! No time for a nap.
     800                if(expected == 1) { return; }
     801
     802                // Try to mark that we are going to sleep
     803                if(__atomic_compare_exchange_n(&this->idle_wctx.fd, &expected, this->idle_fd, false,  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) {
     804                        // Every one agreed, taking a nap
     805                        break;
     806                }
     807        }
     808
     809
    781810        #if !defined(CFA_WITH_IO_URING_IDLE)
    782811                #if !defined(__CFA_NO_STATISTICS__)
     
    825854
    826855static bool mark_idle(__cluster_proc_list & this, processor & proc) {
     856        #if !defined(__CFA_NO_STATISTICS__)
     857                __tls_stats()->ready.sleep.halts++;
     858        #endif
     859
     860        proc.idle_wctx.fd = 0;
     861
    827862        /* paranoid */ verify( ! __preemption_enabled() );
    828863        if(!try_lock( this )) return false;
     
    832867                insert_first(this.idles, proc);
    833868
    834                 __atomic_store_n(&this.fd, proc.idle_fd, __ATOMIC_SEQ_CST);
     869                __atomic_store_n(&this.fdw, &proc.idle_wctx, __ATOMIC_SEQ_CST);
    835870        unlock( this );
    836871        /* paranoid */ verify( ! __preemption_enabled() );
     
    848883
    849884                {
    850                         int fd = 0;
    851                         if(!this.idles`isEmpty) fd = this.idles`first.idle_fd;
    852                         __atomic_store_n(&this.fd, fd, __ATOMIC_SEQ_CST);
     885                        struct __fd_waitctx * wctx = 0;
     886                        if(!this.idles`isEmpty) wctx = &this.idles`first.idle_wctx;
     887                        __atomic_store_n(&this.fdw, wctx, __ATOMIC_SEQ_CST);
    853888                }
    854889
Note: See TracChangeset for help on using the changeset viewer.