void fiber_manager_schedule(fiber_manager_t* manager, fiber_t* the_fiber) { assert(manager); assert(the_fiber); assert(the_fiber->state == FIBER_STATE_READY); wsd_work_stealing_deque_push_bottom(manager->schedule_from, the_fiber); }
static int fiber_load_balance(fiber_manager_t* manager) { size_t i = 2 * (manager->id + 1); const size_t end = i + 2 * (fiber_manager_num_threads - 1); const size_t mod = 2 * fiber_manager_num_threads; size_t local_count = wsd_work_stealing_deque_size(manager->schedule_from); for(; i < end; ++i) { const size_t index = i % mod; wsd_work_stealing_deque_t* const remote_queue = fiber_mananger_thread_queues[index]; assert(remote_queue != manager->queue_one); assert(remote_queue != manager->queue_two); if(!remote_queue) { continue; } size_t remote_count = wsd_work_stealing_deque_size(remote_queue); while(remote_count > local_count) { fiber_t* const stolen = (fiber_t*)wsd_work_stealing_deque_steal(remote_queue); if(stolen == WSD_EMPTY || stolen == WSD_ABORT) { break; } assert(stolen->state == FIBER_STATE_READY); wsd_work_stealing_deque_push_bottom(manager->schedule_from, stolen); --remote_count; ++local_count; } } return 1; }
void fiber_scheduler_load_balance(fiber_scheduler_t* sched) { fiber_scheduler_wsd_t* const scheduler = (fiber_scheduler_wsd_t*)sched; size_t max_steal = 50; size_t i = 2 * (scheduler->id + 1); const size_t end = i + 2 * (fiber_scheduler_num_threads - 1); const size_t mod = 2 * fiber_scheduler_num_threads; size_t local_count = wsd_work_stealing_deque_size(scheduler->schedule_from); for(; i < end; ++i) { const size_t index = i % mod; wsd_work_stealing_deque_t* const remote_queue = fiber_scheduler_thread_queues[index]; assert(remote_queue != scheduler->queue_one); assert(remote_queue != scheduler->queue_two); if(!remote_queue) { continue; } size_t remote_count = wsd_work_stealing_deque_size(remote_queue); while(remote_count > local_count && max_steal > 0) { fiber_t* const stolen = (fiber_t*)wsd_work_stealing_deque_steal(remote_queue); if(stolen == WSD_EMPTY || stolen == WSD_ABORT) { ++scheduler->failed_steal_count; break; } wsd_work_stealing_deque_push_bottom(scheduler->schedule_from, stolen); --remote_count; ++local_count; --max_steal; ++scheduler->steal_count; } } }
void fiber_manager_do_maintenance() { fiber_manager_t* const manager = fiber_manager_get(); if(manager->to_schedule) { assert(manager->to_schedule->state == FIBER_STATE_READY); wsd_work_stealing_deque_push_bottom(manager->store_to, manager->to_schedule); manager->to_schedule = NULL; } if(manager->mpsc_to_push.fifo) { mpsc_fifo_push(manager->mpsc_to_push.fifo, manager->mpsc_to_push.node); memset(&manager->mpsc_to_push, 0, sizeof(manager->mpsc_to_push)); } if(manager->mutex_to_unlock) { fiber_mutex_t* const to_unlock = manager->mutex_to_unlock; manager->mutex_to_unlock = NULL; fiber_mutex_unlock_internal(to_unlock); } }
fiber_t* fiber_scheduler_next(fiber_scheduler_t* sched) { fiber_scheduler_wsd_t* const scheduler = (fiber_scheduler_wsd_t*)sched; assert(scheduler); if(wsd_work_stealing_deque_size(scheduler->schedule_from) == 0) { wsd_work_stealing_deque_t* const temp = scheduler->schedule_from; scheduler->schedule_from = scheduler->store_to; scheduler->store_to = temp; } while(wsd_work_stealing_deque_size(scheduler->schedule_from) > 0) { fiber_t* const new_fiber = (fiber_t*)wsd_work_stealing_deque_pop_bottom(scheduler->schedule_from); if(new_fiber != WSD_EMPTY && new_fiber != WSD_ABORT) { if(new_fiber->state == FIBER_STATE_SAVING_STATE_TO_WAIT) { wsd_work_stealing_deque_push_bottom(scheduler->store_to, new_fiber); } else { return new_fiber; } } } return NULL; }
void fiber_scheduler_schedule(fiber_scheduler_t* scheduler, fiber_t* the_fiber) { assert(scheduler); assert(the_fiber); wsd_work_stealing_deque_push_bottom(((fiber_scheduler_wsd_t*)scheduler)->schedule_from, the_fiber); }
int main(int argc, char* argv[]) { wsd_circular_array_t* wsd_a = wsd_circular_array_create(8); test_assert(wsd_a); test_assert(wsd_circular_array_size(wsd_a) == 256); wsd_circular_array_put(wsd_a, 1, (void*)1); test_assert((void*)1 == wsd_circular_array_get(wsd_a, 1)); wsd_circular_array_destroy(wsd_a); wsd_work_stealing_deque_t* wsd_d = wsd_work_stealing_deque_create(); int i; for(i = 0; i < 1000; ++i) { wsd_work_stealing_deque_push_bottom(wsd_d, (void*)(intptr_t)i); } for(i = 1000; i > 0; --i) { void* item = wsd_work_stealing_deque_pop_bottom(wsd_d); test_assert((intptr_t)item == i-1); } wsd_work_stealing_deque_destroy(wsd_d); wsd_d2 = wsd_work_stealing_deque_create(); pthread_t reader[NUM_THREADS]; for(i = 1; i < NUM_THREADS; ++i) { pthread_create(&reader[i], NULL, &run_func, (void*)(intptr_t)i); } for(i = 0; i < SHARED_COUNT; ++i) { wsd_work_stealing_deque_push_bottom(wsd_d2, (void*)(intptr_t)i); if((i & 7) == 0) { void* val = wsd_work_stealing_deque_pop_bottom(wsd_d2); if(val != WSD_EMPTY && val != WSD_ABORT) { __sync_add_and_fetch(&results[0][(intptr_t)val], 1); __sync_add_and_fetch(&total, (intptr_t)val); ++run_func_count[0]; } } } void* val = 0; do { val = wsd_work_stealing_deque_pop_bottom(wsd_d2); if(val != WSD_EMPTY && val != WSD_ABORT) { __sync_add_and_fetch(&results[0][(intptr_t)val], 1); __sync_add_and_fetch(&total, (intptr_t)val); ++run_func_count[0]; } } while(val != WSD_EMPTY); done = 1; for(i = 1; i < NUM_THREADS; ++i) { pthread_join(reader[i], NULL); } uint64_t expected_total = 0; for(i = 0; i < SHARED_COUNT; ++i) { int sum = 0; int j; for(j = 0; j < NUM_THREADS; ++j) { sum += results[j][i]; } test_assert(sum == 1); expected_total += i; } test_assert(total == expected_total); for(i = 0; i < NUM_THREADS; ++i) { test_assert(run_func_count[i] > 0); } return 0; }