- File:
-
- 1 edited
-
libcfa/src/concurrency/kernel.cfa (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel.cfa
rc9c1c1cb r70b4aeb9 42 42 43 43 #if !defined(__CFA_NO_STATISTICS__) 44 #define __STATS _DEF( ...) __VA_ARGS__44 #define __STATS( ...) __VA_ARGS__ 45 45 #else 46 #define __STATS _DEF( ...)46 #define __STATS( ...) 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);125 124 static inline bool __must_unpark( thread$ * thrd ) __attribute((nonnull(1))); 126 125 static void __run_thread(processor * this, thread$ * dst); … … 188 187 MAIN_LOOP: 189 188 for() { 189 #define OLD_MAIN 1 190 #if OLD_MAIN 190 191 // Check if there is pending io 191 192 __maybe_io_drain( this ); … … 195 196 196 197 if( !readyThread ) { 197 __ IO_STATS__(true, io.flush.idle++; )198 __tls_stats()->io.flush.idle++; 198 199 __cfa_io_flush( this, 0 ); 199 200 200 readyThread = __next_thread( this->cltr );201 }202 203 if( !readyThread ) for(5) {204 __IO_STATS__(true, io.flush.idle++; )205 206 201 readyThread = __next_thread_slow( this->cltr ); 207 208 if( readyThread ) break;209 210 __cfa_io_flush( this, 0 );211 202 } 212 203 … … 220 211 221 212 // Confirm the ready-queue is empty 222 readyThread = __next_thread_s earch( this->cltr );213 readyThread = __next_thread_slow( this->cltr ); 223 214 if( readyThread ) { 224 215 // A thread was found, cancel the halt 225 216 mark_awake(this->cltr->procs, * this); 226 217 227 __STATS__(true, ready.sleep.cancels++; ) 218 #if !defined(__CFA_NO_STATISTICS__) 219 __tls_stats()->ready.sleep.cancels++; 220 #endif 228 221 229 222 // continue the mai loop … … 252 245 253 246 if(this->io.pending && !this->io.dirty) { 254 __ IO_STATS__(true, io.flush.dirty++; )247 __tls_stats()->io.flush.dirty++; 255 248 __cfa_io_flush( this, 0 ); 256 249 } 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 257 366 } 258 367 … … 365 474 break RUNNING; 366 475 case TICKET_UNBLOCK: 367 __STATS__(true, ready.threads.threads++; ) 476 #if !defined(__CFA_NO_STATISTICS__) 477 __tls_stats()->ready.threads.threads++; 478 #endif 368 479 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 369 480 // In this case, just run it again. … … 380 491 __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst); 381 492 382 __STATS__(true, ready.threads.threads--; ) 493 #if !defined(__CFA_NO_STATISTICS__) 494 __tls_stats()->ready.threads.threads--; 495 #endif 383 496 384 497 /* paranoid */ verify( ! __preemption_enabled() ); … … 391 504 thread$ * thrd_src = kernelTLS().this_thread; 392 505 393 __STATS _DEF( thrd_src->last_proc = kernelTLS().this_processor; )506 __STATS( thrd_src->last_proc = kernelTLS().this_processor; ) 394 507 395 508 // Run the thread on this processor … … 443 556 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 444 557 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; ) 446 559 447 560 // push the thread to the cluster ready-queue … … 494 607 495 608 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: 509 617 ready_schedule_unlock(); 510 618 … … 748 856 749 857 static 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 751 861 752 862 proc.idle_wctx.fd = 0; … … 841 951 unsigned tail = *ctx->cq.tail; 842 952 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 846 960 #endif 847 961 return ret;
Note:
See TracChangeset
for help on using the changeset viewer.