mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-26 00:34:45 +02:00
Common: Set a min size on threadpool work chunks.
This should avoid slicing loops, etc. into too many chunks. Generalize the memcpy a bit.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "Common/Thread/ThreadPool.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
|
||||
@@ -54,34 +56,18 @@ void WorkerThread::WorkFunc() {
|
||||
}
|
||||
}
|
||||
|
||||
void LoopWorkerThread::Process(std::function<void(int, int)> work, int start, int end) {
|
||||
void LoopWorkerThread::ProcessLoop(std::function<void(int, int)> work, int start, int end) {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
work_ = std::move(work);
|
||||
loopWork_ = std::move(work);
|
||||
work_ = [this]() {
|
||||
loopWork_(start_, end_);
|
||||
};
|
||||
start_ = start;
|
||||
end_ = end;
|
||||
jobsTarget = jobsDone + 1;
|
||||
signal.notify_one();
|
||||
}
|
||||
|
||||
void LoopWorkerThread::WorkFunc() {
|
||||
setCurrentThreadName("LoopWorker");
|
||||
std::unique_lock<std::mutex> guard(mutex);
|
||||
while (active) {
|
||||
// 'active == false' is one of the conditions for signaling,
|
||||
// do not "optimize" it
|
||||
while (active && jobsTarget <= jobsDone) {
|
||||
signal.wait(guard);
|
||||
}
|
||||
if (active) {
|
||||
work_(start_, end_);
|
||||
|
||||
std::lock_guard<std::mutex> doneGuard(doneMutex);
|
||||
jobsDone++;
|
||||
done.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////// ThreadPool
|
||||
|
||||
ThreadPool::ThreadPool(int numThreads) {
|
||||
@@ -108,23 +94,32 @@ void ThreadPool::StartWorkers() {
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::ParallelLoop(const std::function<void(int,int)> &loop, int lower, int upper) {
|
||||
void ThreadPool::ParallelLoop(const std::function<void(int,int)> &loop, int lower, int upper, int minSize) {
|
||||
// Don't parallelize tiny loops.
|
||||
if (minSize == -1)
|
||||
minSize = 4;
|
||||
|
||||
int range = upper - lower;
|
||||
if (range >= numThreads_ * 2) { // don't parallelize tiny loops (this could be better, maybe add optional parameter that estimates work per iteration)
|
||||
if (range >= minSize) {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
StartWorkers();
|
||||
|
||||
// could do slightly better load balancing for the generic case,
|
||||
// but doesn't matter since all our loops are power of 2
|
||||
int chunk = range / numThreads_;
|
||||
int chunk = std::max(minSize, range / numThreads_);
|
||||
int s = lower;
|
||||
for (auto& worker : workers) {
|
||||
worker->Process(loop, s, s+chunk);
|
||||
s+=chunk;
|
||||
for (auto &worker : workers) {
|
||||
// We'll do the last chunk on the current thread.
|
||||
if (s + chunk >= upper) {
|
||||
break;
|
||||
}
|
||||
worker->ProcessLoop(loop, s, s + chunk);
|
||||
s += chunk;
|
||||
}
|
||||
// This is the final chunk.
|
||||
loop(s, upper);
|
||||
for (auto& worker : workers) {
|
||||
if (s < upper)
|
||||
loop(s, upper);
|
||||
for (auto &worker : workers) {
|
||||
worker->WaitForCompletion();
|
||||
}
|
||||
} else {
|
||||
@@ -132,3 +127,9 @@ void ThreadPool::ParallelLoop(const std::function<void(int,int)> &loop, int lowe
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::ParallelMemcpy(void *dest, const void *src, int size) {
|
||||
static const int MIN_SIZE = 128 * 1024;
|
||||
ParallelLoop([&](int l, int h) {
|
||||
memmove((uint8_t *)dest + l, (const uint8_t *)src + l, h - l);
|
||||
}, 0, size, MIN_SIZE);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user