Changeset 376c632a for libcfa/src
- Timestamp:
- Feb 1, 2022, 10:10:46 AM (4 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum, stuck-waitfor-destruct
- Children:
- 7b2c8c3c
- Parents:
- f681823 (diff), 89a5a1f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- libcfa/src/concurrency
- Files:
-
- 5 edited
-
io.cfa (modified) (1 diff)
-
kernel.cfa (modified) (13 diffs)
-
kernel/fwd.hfa (modified) (1 diff)
-
stats.cfa (modified) (3 diffs)
-
stats.hfa (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/io.cfa
rf681823 r376c632a 306 306 ctx->proc->io.pending = true; 307 307 ctx->proc->io.dirty = true; 308 if(sq.to_submit > 30 || !lazy) { 308 if(sq.to_submit > 30) { 309 __tls_stats()->io.flush.full++; 310 __cfa_io_flush( ctx->proc, 0 ); 311 } 312 if(!lazy) { 313 __tls_stats()->io.flush.eager++; 309 314 __cfa_io_flush( ctx->proc, 0 ); 310 315 } -
libcfa/src/concurrency/kernel.cfa
rf681823 r376c632a 42 42 43 43 #if !defined(__CFA_NO_STATISTICS__) 44 #define __STATS ( ...) __VA_ARGS__44 #define __STATS_DEF( ...) __VA_ARGS__ 45 45 #else 46 #define __STATS ( ...)46 #define __STATS_DEF( ...) 47 47 #endif 48 48 … … 122 122 static thread$ * __next_thread(cluster * this); 123 123 static thread$ * __next_thread_slow(cluster * this); 124 static thread$ * __next_thread_search(cluster * this); 124 125 static inline bool __must_unpark( thread$ * thrd ) __attribute((nonnull(1))); 125 126 static void __run_thread(processor * this, thread$ * dst); … … 187 188 MAIN_LOOP: 188 189 for() { 189 #define OLD_MAIN 1190 #if OLD_MAIN191 190 // Check if there is pending io 192 191 __maybe_io_drain( this ); … … 196 195 197 196 if( !readyThread ) { 197 __IO_STATS__(true, io.flush.idle++; ) 198 198 __cfa_io_flush( this, 0 ); 199 199 200 readyThread = __next_thread( this->cltr ); 201 } 202 203 if( !readyThread ) for(5) { 204 __IO_STATS__(true, io.flush.idle++; ) 205 200 206 readyThread = __next_thread_slow( this->cltr ); 207 208 if( readyThread ) break; 209 210 __cfa_io_flush( this, 0 ); 201 211 } 202 212 … … 210 220 211 221 // Confirm the ready-queue is empty 212 readyThread = __next_thread_s low( this->cltr );222 readyThread = __next_thread_search( this->cltr ); 213 223 if( readyThread ) { 214 224 // A thread was found, cancel the halt 215 225 mark_awake(this->cltr->procs, * this); 216 226 217 #if !defined(__CFA_NO_STATISTICS__) 218 __tls_stats()->ready.sleep.cancels++; 219 #endif 227 __STATS__(true, ready.sleep.cancels++; ) 220 228 221 229 // continue the mai loop … … 244 252 245 253 if(this->io.pending && !this->io.dirty) { 254 __IO_STATS__(true, io.flush.dirty++; ) 246 255 __cfa_io_flush( this, 0 ); 247 256 } 248 249 #else250 #warning new kernel loop251 SEARCH: {252 /* paranoid */ verify( ! __preemption_enabled() );253 254 // First, lock the scheduler since we are searching for a thread255 ready_schedule_lock();256 257 // Try to get the next thread258 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/O262 if(this->io.pending) { __cfa_io_flush( this, 0 ); }263 264 // Spin a little on I/O, just in case265 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 times272 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 thread282 readyThread = pop_search( this->cltr );283 if(readyThread) { ready_schedule_unlock(); break SEARCH; }284 285 // Don't block if we are done286 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 stack294 ready_schedule_unlock();295 if(!mark_idle(this->cltr->procs, * this)) goto SEARCH;296 ready_schedule_lock();297 298 // Confirm the ready-queue is empty299 __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 halt305 mark_awake(this->cltr->procs, * this);306 307 __STATS( __tls_stats()->ready.sleep.cancels++; )308 309 // continue the main loop310 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 != EWOULDBLOCK323 case EWOULDBLOCK:324 #endif325 case EINTR:326 // No need to do anything special here, just assume it's a legitimate wake-up327 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 idle337 mark_awake(this->cltr->procs, * this);338 339 // DON'T just proceed, start looking again340 continue MAIN_LOOP;341 }342 343 RUN_THREAD:344 /* paranoid */ verify( ! __preemption_enabled() );345 /* paranoid */ verify( readyThread );346 347 // Reset io dirty bit348 this->io.dirty = false;349 350 // We found a thread run it351 __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 #endif364 257 } 365 258 … … 472 365 break RUNNING; 473 366 case TICKET_UNBLOCK: 474 #if !defined(__CFA_NO_STATISTICS__) 475 __tls_stats()->ready.threads.threads++; 476 #endif 367 __STATS__(true, ready.threads.threads++; ) 477 368 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 478 369 // In this case, just run it again. … … 489 380 __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst); 490 381 491 #if !defined(__CFA_NO_STATISTICS__) 492 __tls_stats()->ready.threads.threads--; 493 #endif 382 __STATS__(true, ready.threads.threads--; ) 494 383 495 384 /* paranoid */ verify( ! __preemption_enabled() ); … … 502 391 thread$ * thrd_src = kernelTLS().this_thread; 503 392 504 __STATS ( thrd_src->last_proc = kernelTLS().this_processor; )393 __STATS_DEF( thrd_src->last_proc = kernelTLS().this_processor; ) 505 394 506 395 // Run the thread on this processor … … 554 443 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 555 444 struct cluster * cl = thrd->curr_cluster; 556 __STATS (bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )445 __STATS_DEF(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; ) 557 446 558 447 // push the thread to the cluster ready-queue … … 605 494 606 495 ready_schedule_lock(); 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: 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 ); 615 509 ready_schedule_unlock(); 616 510 … … 854 748 855 749 static bool mark_idle(__cluster_proc_list & this, processor & proc) { 856 #if !defined(__CFA_NO_STATISTICS__) 857 __tls_stats()->ready.sleep.halts++; 858 #endif 750 __STATS__(true, ready.sleep.halts++; ) 859 751 860 752 proc.idle_wctx.fd = 0; … … 949 841 unsigned tail = *ctx->cq.tail; 950 842 if(head == tail) return false; 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 843 ready_schedule_lock(); 844 ret = __cfa_io_drain( proc ); 845 ready_schedule_unlock(); 958 846 #endif 959 847 return ret; -
libcfa/src/concurrency/kernel/fwd.hfa
rf681823 r376c632a 396 396 if( !(in_kernel) ) enable_interrupts(); \ 397 397 } 398 #if defined(CFA_HAVE_LINUX_IO_URING_H) 399 #define __IO_STATS__(in_kernel, ...) { \ 400 if( !(in_kernel) ) disable_interrupts(); \ 401 with( *__tls_stats() ) { \ 402 __VA_ARGS__ \ 403 } \ 404 if( !(in_kernel) ) enable_interrupts(); \ 405 } 406 #else 407 #define __IO_STATS__(in_kernel, ...) 408 #endif 398 409 #else 399 410 #define __STATS__(in_kernel, ...) 411 #define __IO_STATS__(in_kernel, ...) 400 412 #endif 401 413 } -
libcfa/src/concurrency/stats.cfa
rf681823 r376c632a 45 45 stats->io.submit.slow = 0; 46 46 stats->io.flush.external = 0; 47 stats->io.flush.dirty = 0; 48 stats->io.flush.full = 0; 49 stats->io.flush.idle = 0; 50 stats->io.flush.eager = 0; 47 51 stats->io.calls.flush = 0; 48 52 stats->io.calls.submitted = 0; … … 107 111 tally_one( &cltr->io.submit.slow , &proc->io.submit.slow ); 108 112 tally_one( &cltr->io.flush.external , &proc->io.flush.external ); 113 tally_one( &cltr->io.flush.dirty , &proc->io.flush.dirty ); 114 tally_one( &cltr->io.flush.full , &proc->io.flush.full ); 115 tally_one( &cltr->io.flush.idle , &proc->io.flush.idle ); 116 tally_one( &cltr->io.flush.eager , &proc->io.flush.eager ); 109 117 tally_one( &cltr->io.calls.flush , &proc->io.calls.flush ); 110 118 tally_one( &cltr->io.calls.submitted , &proc->io.calls.submitted ); … … 184 192 if(io.alloc.fail || io.alloc.revoke || io.alloc.block) 185 193 sstr | "- failures : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk"; 186 if(io.flush.external)187 sstr | "- flush external : " | eng3(io.flush.external);194 // if(io.flush.external) 195 // sstr | "- flush external : " | eng3(io.flush.external); 188 196 189 197 double avgsubs = ((double)io.calls.submitted) / io.calls.flush; 190 198 double avgcomp = ((double)io.calls.completed) / io.calls.drain; 191 199 sstr | "- syscll : " 192 | " sub " | eng3(io.calls. flush) | "/" | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)"193 | " - cmp " | eng3(io.calls. drain) | "/" | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)"200 | " sub " | eng3(io.calls.submitted) | "/" | eng3(io.calls.flush) | "(" | ws(3, 3, avgsubs) | "/flush)" 201 | " - cmp " | eng3(io.calls.completed) | "/" | eng3(io.calls.drain) | "(" | ws(3, 3, avgcomp) | "/drain)" 194 202 | " - " | eng3(io.calls.errors.busy) | " EBUSY"; 203 sstr | " - sub: " | eng3(io.flush.full) | "full, " | eng3(io.flush.dirty) | "drty, " | eng3(io.flush.idle) | "idle, " | eng3(io.flush.eager) | "eagr, " | eng3(io.flush.external) | "ext"; 195 204 sstr | "- ops blk: " 196 205 | " sk rd: " | eng3(io.ops.sockread) | "epll: " | eng3(io.ops.epllread) -
libcfa/src/concurrency/stats.hfa
rf681823 r376c632a 91 91 struct { 92 92 volatile uint64_t external; 93 volatile uint64_t dirty; 94 volatile uint64_t full; 95 volatile uint64_t idle; 96 volatile uint64_t eager; 93 97 } flush; 94 98 struct {
Note:
See TracChangeset
for help on using the changeset viewer.