| 195 | } |
| 196 | |
| 197 | void thread_pool_worker::balance_work() { |
| 198 | const auto task_count = m_private_queue.size(); |
| 199 | if (task_count < 2) { // no point in donating tasks |
| 200 | return; |
| 201 | } |
| 202 | |
| 203 | // we assume all threads but us are idle, we also save at least one task for ourselves |
| 204 | const auto max_idle_worker_count = std::min(m_pool_size - 1, task_count - 1); |
| 205 | if (max_idle_worker_count == 0) { |
| 206 | return; // a thread-pool with a single thread |
| 207 | } |
| 208 | |
| 209 | m_parent_pool.find_idle_workers(m_index, m_idle_worker_list, max_idle_worker_count); |
| 210 | const auto idle_count = m_idle_worker_list.size(); |
| 211 | if (idle_count == 0) { |
| 212 | return; |
| 213 | } |
| 214 | |
| 215 | assert(idle_count <= task_count); |
| 216 | const auto total_worker_count = (idle_count + 1); // count ourselves, otherwise we'll donate everything. |
| 217 | const auto donation_count = task_count / total_worker_count; |
| 218 | auto extra = task_count - donation_count * total_worker_count; |
| 219 | |
| 220 | size_t begin = 0; |
| 221 | size_t end = donation_count; |
| 222 | |
| 223 | for (const auto idle_worker_index : m_idle_worker_list) { |
| 224 | assert(idle_worker_index != m_index); |
| 225 | assert(idle_worker_index < m_pool_size); |
| 226 | assert(begin < task_count); |
| 227 | |
| 228 | if (extra != 0) { |
| 229 | end++; |
| 230 | extra--; |
| 231 | } |
| 232 | |
| 233 | assert(end <= task_count); |
| 234 | |
| 235 | auto donation_begin_it = m_private_queue.begin() + begin; |
| 236 | auto donation_end_it = m_private_queue.begin() + end; |
| 237 | |
| 238 | assert(donation_begin_it < m_private_queue.end()); |
| 239 | assert(donation_end_it <= m_private_queue.end()); |
| 240 | |
| 241 | m_parent_pool.worker_at(idle_worker_index).enqueue_foreign(donation_begin_it, donation_end_it); |
| 242 | |
| 243 | begin = end; |
| 244 | end += donation_count; |
| 245 | } |
| 246 | |
| 247 | assert(m_private_queue.size() == task_count); |
| 248 | |
| 249 | // clear everything we've donated. |
| 250 | assert(std::all_of(m_private_queue.begin(), m_private_queue.begin() + begin, [](auto& task) { |
| 251 | return !static_cast<bool>(task); |
| 252 | })); |
| 253 | |
| 254 | assert(std::all_of(m_private_queue.begin() + begin, m_private_queue.end(), [](auto& task) { |
nothing calls this directly
no test coverage detected