18 #if !defined(__PORTABLE_PLATFORM__)
19 #include "absl/synchronization/mutex.h"
20 #include "absl/time/clock.h"
21 #endif // __PORTABLE_PLATFORM__
33 int NextSubsolverToSchedule(
34 const std::vector<std::unique_ptr<SubSolver>>& subsolvers,
35 const std::vector<int64>& num_generated_tasks) {
37 for (
int i = 0; i < subsolvers.size(); ++i) {
38 if (subsolvers[i]->TaskIsAvailable()) {
39 if (best == -1 || num_generated_tasks[i] < num_generated_tasks[best]) {
44 if (best != -1)
VLOG(1) <<
"Scheduling " << subsolvers[best]->name();
48 void SynchronizeAll(
const std::vector<std::unique_ptr<SubSolver>>& subsolvers) {
49 for (
const auto& subsolver : subsolvers) subsolver->Synchronize();
54 void SequentialLoop(
const std::vector<std::unique_ptr<SubSolver>>& subsolvers) {
56 std::vector<int64> num_generated_tasks(subsolvers.size(), 0);
58 SynchronizeAll(subsolvers);
59 const int best = NextSubsolverToSchedule(subsolvers, num_generated_tasks);
60 if (best == -1)
break;
61 num_generated_tasks[best]++;
62 subsolvers[best]->GenerateTask(task_id++)();
66 #if defined(__PORTABLE_PLATFORM__)
71 const std::vector<std::unique_ptr<SubSolver>>& subsolvers,
77 const std::vector<std::unique_ptr<SubSolver>>& subsolvers,
int num_threads,
82 #else // __PORTABLE_PLATFORM__
85 const std::vector<std::unique_ptr<SubSolver>>& subsolvers,
int num_threads,
89 if (batch_size == 1) {
94 std::vector<int64> num_generated_tasks(subsolvers.size(), 0);
96 SynchronizeAll(subsolvers);
101 ThreadPool pool(
"DeterministicLoop", num_threads);
104 int num_in_batch = 0;
105 for (
int t = 0; t < batch_size; ++t) {
106 const int best = NextSubsolverToSchedule(subsolvers, num_generated_tasks);
107 if (best == -1)
break;
109 num_generated_tasks[best]++;
110 pool.
Schedule(subsolvers[best]->GenerateTask(task_id++));
112 if (num_in_batch == 0)
break;
117 const std::vector<std::unique_ptr<SubSolver>>& subsolvers,
120 if (num_threads == 1) {
127 absl::CondVar thread_available_condition;
128 int num_scheduled_and_not_done = 0;
130 ThreadPool pool(
"NonDeterministicLoop", num_threads);
137 std::vector<int64> num_generated_tasks(subsolvers.size(), 0);
139 bool all_done =
false;
141 absl::MutexLock mutex_lock(&mutex);
145 if (num_scheduled_and_not_done == 0) all_done =
true;
148 if (num_scheduled_and_not_done == num_threads) {
149 thread_available_condition.Wait(&mutex);
153 SynchronizeAll(subsolvers);
154 const int best = NextSubsolverToSchedule(subsolvers, num_generated_tasks);
162 absl::SleepFor(absl::Milliseconds(1));
167 num_generated_tasks[best]++;
169 absl::MutexLock mutex_lock(&mutex);
170 num_scheduled_and_not_done++;
172 std::function<void()> task = subsolvers[best]->GenerateTask(task_id++);
173 const std::string
name = subsolvers[best]->name();
174 pool.
Schedule([task, num_threads,
name, &mutex, &num_scheduled_and_not_done,
175 &thread_available_condition]() {
178 absl::MutexLock mutex_lock(&mutex);
180 num_scheduled_and_not_done--;
181 if (num_scheduled_and_not_done == num_threads - 1) {
182 thread_available_condition.SignalAll();
188 #endif // __PORTABLE_PLATFORM__