- File:
-
- 1 edited
-
libcfa/src/concurrency/ready_queue.cfa (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/ready_queue.cfa
r5cb51502 rd2fadeb 17 17 // #define __CFA_DEBUG_PRINT_READY_QUEUE__ 18 18 19 // #define USE_SNZI20 19 // #define USE_MPSC 20 21 #define USE_RELAXED_FIFO 22 // #define USE_WORK_STEALING 21 23 22 24 #include "bits/defs.hfa" … … 29 31 #include <unistd.h> 30 32 31 #include "snzi.hfa"32 33 #include "ready_subqueue.hfa" 33 34 34 35 static const size_t cache_line_size = 64; 36 37 #if !defined(__CFA_NO_STATISTICS__) 38 #define __STATS(...) __VA_ARGS__ 39 #else 40 #define __STATS(...) 41 #endif 35 42 36 43 // No overriden function, no environment variable, no define … … 40 47 #endif 41 48 42 #define BIAS 4 49 #if defined(USE_RELAXED_FIFO) 50 #define BIAS 4 51 #define READYQ_SHARD_FACTOR 4 52 #define SEQUENTIAL_SHARD 1 53 #elif defined(USE_WORK_STEALING) 54 #define READYQ_SHARD_FACTOR 2 55 #define SEQUENTIAL_SHARD 2 56 #else 57 #error no scheduling strategy selected 58 #endif 59 60 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)); 61 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)); 62 static inline struct $thread * search(struct cluster * cltr); 63 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred); 64 43 65 44 66 // returns the maximum number of processors the RWLock support … … 94 116 //======================================================================= 95 117 // Lock-Free registering/unregistering of threads 96 unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {118 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) { 97 119 __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc); 98 120 … … 108 130 /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size)); 109 131 /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0); 110 returni;132 proc->id = i; 111 133 } 112 134 } … … 135 157 /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size)); 136 158 /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0); 137 returnn;138 } 139 140 void unregister ( struct __processor_id_t * proc ) with(*__scheduler_lock) {159 proc->id = n; 160 } 161 162 void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) { 141 163 unsigned id = proc->id; 142 164 /*paranoid*/ verify(id < ready); … … 193 215 194 216 //======================================================================= 195 // Cforall Re qdy Queue used for scheduling217 // Cforall Ready Queue used for scheduling 196 218 //======================================================================= 197 219 void ?{}(__ready_queue_t & this) with (this) { 198 220 lanes.data = 0p; 221 lanes.tscs = 0p; 199 222 lanes.count = 0; 200 223 } 201 224 202 225 void ^?{}(__ready_queue_t & this) with (this) { 203 verify( 1 == lanes.count ); 204 #ifdef USE_SNZI 205 verify( !query( snzi ) ); 206 #endif 226 verify( SEQUENTIAL_SHARD == lanes.count ); 207 227 free(lanes.data); 228 free(lanes.tscs); 208 229 } 209 230 210 231 //----------------------------------------------------------------------- 211 __attribute__((hot)) bool query(struct cluster * cltr) { 212 #ifdef USE_SNZI 213 return query(cltr->ready_queue.snzi); 214 #endif 215 return true; 216 } 217 218 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) { 219 unsigned i; 220 bool local; 221 #if defined(BIAS) 232 #if defined(USE_RELAXED_FIFO) 233 //----------------------------------------------------------------------- 234 // get index from random number with or without bias towards queues 235 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) { 236 unsigned i; 237 bool local; 222 238 unsigned rlow = r % BIAS; 223 239 unsigned rhigh = r / BIAS; … … 225 241 // (BIAS - 1) out of BIAS chances 226 242 // Use perferred queues 227 i = preferred + (rhigh % 4);243 i = preferred + (rhigh % READYQ_SHARD_FACTOR); 228 244 local = true; 229 245 } … … 234 250 local = false; 235 251 } 236 #else 237 i = r; 238 local = false; 239 #endif 240 return [i, local]; 241 } 242 243 //----------------------------------------------------------------------- 244 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 245 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 246 247 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 248 249 // write timestamp 250 thrd->link.ts = rdtscl(); 251 252 bool first = false; 253 __attribute__((unused)) bool local; 254 __attribute__((unused)) int preferred; 255 #if defined(BIAS) 256 preferred = 257 //* 258 external ? -1 : kernelTLS().this_processor->cltr_id; 259 /*/ 260 thrd->link.preferred * 4; 261 //*/ 262 #endif 263 264 // Try to pick a lane and lock it 265 unsigned i; 266 do { 267 // Pick the index of a lane 268 // unsigned r = __tls_rand(); 269 unsigned r = __tls_rand_fwd(); 270 [i, local] = idx_from_r(r, preferred); 271 272 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 273 252 return [i, local]; 253 } 254 255 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 256 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 257 258 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 259 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 260 261 // write timestamp 262 thrd->link.ts = rdtscl(); 263 264 bool local; 265 int preferred = external ? -1 : kernelTLS().this_processor->rdq.id; 266 267 // Try to pick a lane and lock it 268 unsigned i; 269 do { 270 // Pick the index of a lane 271 unsigned r = __tls_rand_fwd(); 272 [i, local] = idx_from_r(r, preferred); 273 274 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 275 276 #if !defined(__CFA_NO_STATISTICS__) 277 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED); 278 else if(local) __tls_stats()->ready.push.local.attempt++; 279 else __tls_stats()->ready.push.share.attempt++; 280 #endif 281 282 #if defined(USE_MPSC) 283 // mpsc always succeeds 284 } while( false ); 285 #else 286 // If we can't lock it retry 287 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 288 #endif 289 290 // Actually push it 291 push(lanes.data[i], thrd); 292 293 #if !defined(USE_MPSC) 294 // Unlock and return 295 __atomic_unlock( &lanes.data[i].lock ); 296 #endif 297 298 // Mark the current index in the tls rng instance as having an item 299 __tls_rand_advance_bck(); 300 301 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 302 303 // Update statistics 274 304 #if !defined(__CFA_NO_STATISTICS__) 275 if(external) { 276 if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.local, 1, __ATOMIC_RELAXED); 277 __atomic_fetch_add(&cltr->stats->ready.pick.ext.attempt, 1, __ATOMIC_RELAXED); 305 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED); 306 else if(local) __tls_stats()->ready.push.local.success++; 307 else __tls_stats()->ready.push.share.success++; 308 #endif 309 } 310 311 // Pop from the ready queue from a given cluster 312 __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) { 313 /* paranoid */ verify( lanes.count > 0 ); 314 /* paranoid */ verify( kernelTLS().this_processor ); 315 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count ); 316 317 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 318 int preferred = kernelTLS().this_processor->rdq.id; 319 320 321 // As long as the list is not empty, try finding a lane that isn't empty and pop from it 322 for(25) { 323 // Pick two lists at random 324 unsigned ri = __tls_rand_bck(); 325 unsigned rj = __tls_rand_bck(); 326 327 unsigned i, j; 328 __attribute__((unused)) bool locali, localj; 329 [i, locali] = idx_from_r(ri, preferred); 330 [j, localj] = idx_from_r(rj, preferred); 331 332 i %= count; 333 j %= count; 334 335 // try popping from the 2 picked lists 336 struct $thread * thrd = try_pop(cltr, i, j __STATS(, *(locali || localj ? &__tls_stats()->ready.pop.local : &__tls_stats()->ready.pop.help))); 337 if(thrd) { 338 return thrd; 339 } 340 } 341 342 // All lanes where empty return 0p 343 return 0p; 344 } 345 346 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) { 347 return search(cltr); 348 } 349 #endif 350 #if defined(USE_WORK_STEALING) 351 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 352 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 353 354 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 355 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 356 357 // write timestamp 358 thrd->link.ts = rdtscl(); 359 360 // Try to pick a lane and lock it 361 unsigned i; 362 do { 363 #if !defined(__CFA_NO_STATISTICS__) 364 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED); 365 else __tls_stats()->ready.push.local.attempt++; 366 #endif 367 368 if(unlikely(external)) { 369 i = __tls_rand() % lanes.count; 278 370 } 279 371 else { 280 if(local) __tls_stats()->ready.pick.push.local++; 281 __tls_stats()->ready.pick.push.attempt++; 372 processor * proc = kernelTLS().this_processor; 373 unsigned r = proc->rdq.its++; 374 i = proc->rdq.id + (r % READYQ_SHARD_FACTOR); 282 375 } 376 377 378 #if defined(USE_MPSC) 379 // mpsc always succeeds 380 } while( false ); 381 #else 382 // If we can't lock it retry 383 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 283 384 #endif 284 385 285 #if defined(USE_MPSC) 286 // mpsc always succeeds 287 } while( false ); 288 #else 289 // If we can't lock it retry 290 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 386 // Actually push it 387 push(lanes.data[i], thrd); 388 389 #if !defined(USE_MPSC) 390 // Unlock and return 391 __atomic_unlock( &lanes.data[i].lock ); 392 #endif 393 394 #if !defined(__CFA_NO_STATISTICS__) 395 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED); 396 else __tls_stats()->ready.push.local.success++; 397 #endif 398 399 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 400 } 401 402 // Pop from the ready queue from a given cluster 403 __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) { 404 /* paranoid */ verify( lanes.count > 0 ); 405 /* paranoid */ verify( kernelTLS().this_processor ); 406 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count ); 407 408 processor * proc = kernelTLS().this_processor; 409 410 if(proc->rdq.target == -1u) { 411 proc->rdq.target = __tls_rand() % lanes.count; 412 unsigned it1 = proc->rdq.itr; 413 unsigned it2 = proc->rdq.itr + 1; 414 unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR); 415 unsigned idx2 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR); 416 unsigned long long tsc1 = ts(lanes.data[idx1]); 417 unsigned long long tsc2 = ts(lanes.data[idx2]); 418 proc->rdq.cutoff = min(tsc1, tsc2); 419 } 420 else if(lanes.tscs[proc->rdq.target].tv < proc->rdq.cutoff) { 421 $thread * t = try_pop(cltr, proc->rdq.target __STATS(, __tls_stats()->ready.pop.help)); 422 proc->rdq.target = -1u; 423 if(t) return t; 424 } 425 426 for(READYQ_SHARD_FACTOR) { 427 unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR); 428 if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t; 429 } 430 return 0p; 431 } 432 433 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) { 434 for(25) { 435 unsigned i = __tls_rand() % lanes.count; 436 $thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal)); 437 if(t) return t; 438 } 439 440 return search(cltr); 441 } 442 #endif 443 444 //======================================================================= 445 // Various Ready Queue utilities 446 //======================================================================= 447 // these function work the same or almost the same 448 // whether they are using work-stealing or relaxed fifo scheduling 449 450 //----------------------------------------------------------------------- 451 // try to pop from a lane given by index w 452 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) { 453 __STATS( stats.attempt++; ) 454 455 // Get relevant elements locally 456 __intrusive_lane_t & lane = lanes.data[w]; 457 458 // If list looks empty retry 459 if( is_empty(lane) ) { 460 __STATS( stats.espec++; ) 461 return 0p; 462 } 463 464 // If we can't get the lock retry 465 if( !__atomic_try_acquire(&lane.lock) ) { 466 __STATS( stats.elock++; ) 467 return 0p; 468 } 469 470 // If list is empty, unlock and retry 471 if( is_empty(lane) ) { 472 __atomic_unlock(&lane.lock); 473 __STATS( stats.eempty++; ) 474 return 0p; 475 } 476 477 // Actually pop the list 478 struct $thread * thrd; 479 thrd = pop(lane); 480 481 /* paranoid */ verify(thrd); 482 /* paranoid */ verify(lane.lock); 483 484 // Unlock and return 485 __atomic_unlock(&lane.lock); 486 487 // Update statistics 488 __STATS( stats.success++; ) 489 490 #if defined(USE_WORK_STEALING) 491 lanes.tscs[w].tv = thrd->link.ts; 291 492 #endif 292 493 293 // Actually push it 294 #ifdef USE_SNZI 295 bool lane_first = 296 #endif 297 298 push(lanes.data[i], thrd); 299 300 #ifdef USE_SNZI 301 // If this lane used to be empty we need to do more 302 if(lane_first) { 303 // Check if the entire queue used to be empty 304 first = !query(snzi); 305 306 // Update the snzi 307 arrive( snzi, i ); 308 } 309 #endif 310 311 #if !defined(USE_MPSC) 312 // Unlock and return 313 __atomic_unlock( &lanes.data[i].lock ); 314 #endif 315 316 // Mark the current index in the tls rng instance as having an item 317 __tls_rand_advance_bck(); 318 319 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 320 321 // Update statistics 322 #if !defined(__CFA_NO_STATISTICS__) 323 if(external) { 324 if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.lsuccess, 1, __ATOMIC_RELAXED); 325 __atomic_fetch_add(&cltr->stats->ready.pick.ext.success, 1, __ATOMIC_RELAXED); 326 } 327 else { 328 if(local) __tls_stats()->ready.pick.push.lsuccess++; 329 __tls_stats()->ready.pick.push.success++; 330 } 331 #endif 332 333 // return whether or not the list was empty before this push 334 return first; 335 } 336 337 static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j); 338 static struct $thread * try_pop(struct cluster * cltr, unsigned i); 339 340 // Pop from the ready queue from a given cluster 341 __attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) { 342 /* paranoid */ verify( lanes.count > 0 ); 343 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 344 int preferred; 345 #if defined(BIAS) 346 // Don't bother trying locally too much 347 preferred = kernelTLS().this_processor->cltr_id; 348 #endif 349 350 351 // As long as the list is not empty, try finding a lane that isn't empty and pop from it 352 #ifdef USE_SNZI 353 while( query(snzi) ) { 354 #else 355 for(25) { 356 #endif 357 // Pick two lists at random 358 // unsigned ri = __tls_rand(); 359 // unsigned rj = __tls_rand(); 360 unsigned ri = __tls_rand_bck(); 361 unsigned rj = __tls_rand_bck(); 362 363 unsigned i, j; 364 __attribute__((unused)) bool locali, localj; 365 [i, locali] = idx_from_r(ri, preferred); 366 [j, localj] = idx_from_r(rj, preferred); 367 368 #if !defined(__CFA_NO_STATISTICS__) 369 if(locali && localj) { 370 __tls_stats()->ready.pick.pop.local++; 371 } 372 #endif 373 374 i %= count; 375 j %= count; 376 377 // try popping from the 2 picked lists 378 struct $thread * thrd = try_pop(cltr, i, j); 379 if(thrd) { 380 #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__) 381 if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++; 382 #endif 383 return thrd; 384 } 385 } 386 387 // All lanes where empty return 0p 388 return 0p; 389 } 390 391 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) { 494 // return the popped thread 495 return thrd; 496 } 497 498 //----------------------------------------------------------------------- 499 // try to pop from any lanes making sure you don't miss any threads push 500 // before the start of the function 501 static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) { 392 502 /* paranoid */ verify( lanes.count > 0 ); 393 503 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); … … 395 505 for(i; count) { 396 506 unsigned idx = (offset + i) % count; 397 struct $thread * thrd = try_pop(cltr, idx );507 struct $thread * thrd = try_pop(cltr, idx __STATS(, __tls_stats()->ready.pop.search)); 398 508 if(thrd) { 399 509 return thrd; … … 405 515 } 406 516 407 408 517 //----------------------------------------------------------------------- 409 // Given 2 indexes, pick the list with the oldest push an try to pop from it 410 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) { 411 #if !defined(__CFA_NO_STATISTICS__) 412 __tls_stats()->ready.pick.pop.attempt++; 413 #endif 414 415 // Pick the bet list 416 int w = i; 417 if( __builtin_expect(!is_empty(lanes.data[j]), true) ) { 418 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j; 419 } 420 421 return try_pop(cltr, w); 422 } 423 424 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) { 425 // Get relevant elements locally 426 __intrusive_lane_t & lane = lanes.data[w]; 427 428 // If list looks empty retry 429 if( is_empty(lane) ) return 0p; 430 431 // If we can't get the lock retry 432 if( !__atomic_try_acquire(&lane.lock) ) return 0p; 433 434 435 // If list is empty, unlock and retry 436 if( is_empty(lane) ) { 437 __atomic_unlock(&lane.lock); 438 return 0p; 439 } 440 441 // Actually pop the list 442 struct $thread * thrd; 443 thrd = pop(lane); 444 445 /* paranoid */ verify(thrd); 446 /* paranoid */ verify(lane.lock); 447 448 #ifdef USE_SNZI 449 // If this was the last element in the lane 450 if(emptied) { 451 depart( snzi, w ); 452 } 453 #endif 454 455 // Unlock and return 456 __atomic_unlock(&lane.lock); 457 458 // Update statistics 459 #if !defined(__CFA_NO_STATISTICS__) 460 __tls_stats()->ready.pick.pop.success++; 461 #endif 462 463 // Update the thread bias 464 thrd->link.preferred = w / 4; 465 466 // return the popped thread 467 return thrd; 468 } 469 //----------------------------------------------------------------------- 470 471 bool remove_head(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 472 for(i; lanes.count) { 473 __intrusive_lane_t & lane = lanes.data[i]; 474 475 bool removed = false; 476 477 __atomic_acquire(&lane.lock); 478 if(head(lane)->link.next == thrd) { 479 $thread * pthrd; 480 pthrd = pop(lane); 481 482 /* paranoid */ verify( pthrd == thrd ); 483 484 removed = true; 485 #ifdef USE_SNZI 486 if(emptied) { 487 depart( snzi, i ); 488 } 489 #endif 490 } 491 __atomic_unlock(&lane.lock); 492 493 if( removed ) return true; 494 } 495 return false; 496 } 497 498 //----------------------------------------------------------------------- 499 518 // Check that all the intrusive queues in the data structure are still consistent 500 519 static void check( __ready_queue_t & q ) with (q) { 501 520 #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC) … … 522 541 } 523 542 543 //----------------------------------------------------------------------- 544 // Given 2 indexes, pick the list with the oldest push an try to pop from it 545 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) { 546 // Pick the bet list 547 int w = i; 548 if( __builtin_expect(!is_empty(lanes.data[j]), true) ) { 549 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j; 550 } 551 552 return try_pop(cltr, w __STATS(, stats)); 553 } 554 524 555 // Call this function of the intrusive list was moved using memcpy 525 556 // fixes the list so that the pointers back to anchors aren't left dangling … … 541 572 } 542 573 574 static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) { 575 processor * it = &list`first; 576 for(unsigned i = 0; i < count; i++) { 577 /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count); 578 it->rdq.id = value; 579 it->rdq.target = -1u; 580 value += READYQ_SHARD_FACTOR; 581 it = &(*it)`next; 582 } 583 } 584 585 static void reassign_cltr_id(struct cluster * cltr) { 586 unsigned preferred = 0; 587 assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle); 588 assign_list(preferred, cltr->procs.idles , cltr->procs.idle ); 589 } 590 591 static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) { 592 #if defined(USE_WORK_STEALING) 593 lanes.tscs = alloc(lanes.count, lanes.tscs`realloc); 594 for(i; lanes.count) { 595 lanes.tscs[i].tv = ts(lanes.data[i]); 596 } 597 #endif 598 } 599 543 600 // Grow the ready queue 544 unsigned ready_queue_grow(struct cluster * cltr, int target) { 545 unsigned preferred; 601 void ready_queue_grow(struct cluster * cltr) { 546 602 size_t ncount; 603 int target = cltr->procs.total; 547 604 548 605 /* paranoid */ verify( ready_mutate_islocked() ); … … 554 611 // grow the ready queue 555 612 with( cltr->ready_queue ) { 556 #ifdef USE_SNZI557 ^(snzi){};558 #endif559 560 613 // Find new count 561 614 // Make sure we always have atleast 1 list 562 615 if(target >= 2) { 563 ncount = target * 4; 564 preferred = ncount - 4; 616 ncount = target * READYQ_SHARD_FACTOR; 565 617 } else { 566 ncount = 1; 567 preferred = 0; 618 ncount = SEQUENTIAL_SHARD; 568 619 } 569 620 … … 583 634 // Update original 584 635 lanes.count = ncount; 585 586 #ifdef USE_SNZI 587 // Re-create the snzi 588 snzi{ log2( lanes.count / 8 ) }; 589 for( idx; (size_t)lanes.count ) { 590 if( !is_empty(lanes.data[idx]) ) { 591 arrive(snzi, idx); 592 } 593 } 594 #endif 595 } 636 } 637 638 fix_times(cltr); 639 640 reassign_cltr_id(cltr); 596 641 597 642 // Make sure that everything is consistent … … 601 646 602 647 /* paranoid */ verify( ready_mutate_islocked() ); 603 return preferred;604 648 } 605 649 606 650 // Shrink the ready queue 607 void ready_queue_shrink(struct cluster * cltr , int target) {651 void ready_queue_shrink(struct cluster * cltr) { 608 652 /* paranoid */ verify( ready_mutate_islocked() ); 609 653 __cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n"); … … 612 656 /* paranoid */ check( cltr->ready_queue ); 613 657 658 int target = cltr->procs.total; 659 614 660 with( cltr->ready_queue ) { 615 #ifdef USE_SNZI616 ^(snzi){};617 #endif618 619 661 // Remember old count 620 662 size_t ocount = lanes.count; … … 622 664 // Find new count 623 665 // Make sure we always have atleast 1 list 624 lanes.count = target >= 2 ? target * 4: 1;666 lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD; 625 667 /* paranoid */ verify( ocount >= lanes.count ); 626 /* paranoid */ verify( lanes.count == target * 4|| target < 2 );668 /* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 ); 627 669 628 670 // for printing count the number of displaced threads … … 667 709 fix(lanes.data[idx]); 668 710 } 669 670 #ifdef USE_SNZI 671 // Re-create the snzi 672 snzi{ log2( lanes.count / 8 ) }; 673 for( idx; (size_t)lanes.count ) { 674 if( !is_empty(lanes.data[idx]) ) { 675 arrive(snzi, idx); 676 } 677 } 678 #endif 679 } 711 } 712 713 fix_times(cltr); 714 715 reassign_cltr_id(cltr); 680 716 681 717 // Make sure that everything is consistent
Note:
See TracChangeset
for help on using the changeset viewer.