1
+ // 2019/07/26 - modified by Chun-Xun Lin
2
+ // - Combine explore_task & wait_for_task
3
+ // - Remove CAS operations
4
+ // - Update _num_thieves after pre_wait
5
+ // - TODO: Check will underutilization happen?
6
+ // - TODO: Find out uppper bound (does cycle exist?)
7
+ // - TODO: Does performance drop due to the busy looping after pre_wait?
8
+ //
1
9
// 2019/07/25 - modified by Tsung-Wei Huang & Chun-Xun Lin
2
10
// - fixed the potential underutilization
3
11
// - use CAS in both last thief & active worker to make the notification less aggressive
@@ -348,8 +356,6 @@ inline void Executor::_explore_task(unsigned thief, std::optional<Node*>& t) {
348
356
const size_t F = (_workers.size () + 1 ) << 1 ;
349
357
const size_t Y = 100 ;
350
358
351
- steal_loop:
352
-
353
359
size_t f = 0 ;
354
360
size_t y = 0 ;
355
361
@@ -388,25 +394,6 @@ inline void Executor::_explore_task(unsigned thief, std::optional<Node*>& t) {
388
394
}*/
389
395
}
390
396
391
- // We need to ensure at least one thieve if there is an active worker
392
- if (auto N = --_num_thieves; N == 0 ) {
393
- if (t != std::nullopt ) {
394
- _notifier.notify (false );
395
- }
396
- else if (_num_actives > 0 ) {
397
- // watch dog
398
- // To prevent race with another thief inside the wait_for_task
399
- // ++_num_thieves;
400
- size_t zero {0 };
401
- size_t one {1 };
402
- if (_num_thieves.compare_exchange_strong (zero, one, std::memory_order_seq_cst, std::memory_order_relaxed)) {
403
- goto steal_loop;
404
- }
405
- else {
406
- assert (zero <= _workers.size ());
407
- }
408
- }
409
- }
410
397
}
411
398
412
399
// Procedure: _exploit_task
@@ -439,16 +426,19 @@ inline void Executor::_exploit_task(unsigned i, std::optional<Node*>& t) {
439
426
// Function: _wait_for_tasks
440
427
inline bool Executor::_wait_for_tasks (unsigned me, std::optional<Node*>& t) {
441
428
442
- ++_num_thieves;
443
- assert (_num_thieves <= _workers.size ());
444
429
445
430
begin_steal:
446
431
432
+ ++_num_thieves;
433
+ assert (_num_thieves <= _workers.size ());
434
+
447
435
if (_explore_task (me, t); t) {
436
+ if (auto N = _num_thieves.fetch_sub (1 ); N == 1 ) {
437
+ _notifier.notify (false );
438
+ }
448
439
return true ;
449
440
}
450
441
451
-
452
442
assert (!t);
453
443
454
444
_notifier.prepare_wait (&_waiters[me]);
@@ -457,6 +447,9 @@ inline bool Executor::_wait_for_tasks(unsigned me, std::optional<Node*>& t) {
457
447
if (!_queue.empty ()) {
458
448
_notifier.cancel_wait (&_waiters[me]);
459
449
t = _queue.steal ();
450
+ if (auto N = _num_thieves.fetch_sub (1 ); t && N == 1 ) {
451
+ _notifier.notify (false );
452
+ }
460
453
// t = (vtm == me) ? _queue.steal() : _workers[vtm].queue.steal();
461
454
return true ;
462
455
}
@@ -474,17 +467,23 @@ inline bool Executor::_wait_for_tasks(unsigned me, std::optional<Node*>& t) {
474
467
if (_done) {
475
468
_notifier.cancel_wait (&_waiters[me]);
476
469
_notifier.notify (true );
470
+ --_num_thieves;
477
471
return false ;
478
472
}
479
473
480
- if (_num_actives && _num_thieves.load (std::memory_order_relaxed) == 0 ) {
481
- size_t zero {0 };
482
- size_t one {1 };
483
- if (_num_thieves.compare_exchange_strong (zero, one, std::memory_order_seq_cst, std::memory_order_relaxed)) {
484
- _notifier.cancel_wait (&_waiters[me]);
485
- goto begin_steal;
486
- }
474
+ if (_num_thieves.fetch_sub (1 ) == 1 && _num_actives) {
475
+ _notifier.cancel_wait (&_waiters[me]);
476
+ goto begin_steal;
487
477
}
478
+
479
+ // if(_num_actives && _num_thieves.load(std::memory_order_relaxed) == 0) {
480
+ // size_t zero {0};
481
+ // size_t one {1};
482
+ // if(_num_thieves.compare_exchange_strong(zero, one, std::memory_order_seq_cst, std::memory_order_relaxed)) {
483
+ // _notifier.cancel_wait(&_waiters[me]);
484
+ // goto begin_steal;
485
+ // }
486
+ // }
488
487
489
488
// Now I really need to relinguish my self to others
490
489
_notifier.commit_wait (&_waiters[me]);
0 commit comments