Fix #36137: cycles render not using all GPU's when the number of GPU's is larger

than the number of CPU threads
This commit is contained in:
Brecht Van Lommel
2013-08-30 23:09:22 +00:00
parent f477c0e535
commit 6785874e7a
4 changed files with 202 additions and 9 deletions

View File

@@ -37,7 +37,7 @@ CCL_NAMESPACE_BEGIN
class CUDADevice : public Device
{
public:
TaskPool task_pool;
DedicatedTaskPool task_pool;
CUdevice cuDevice;
CUcontext cuContext;
CUmodule cuModule;
@@ -976,7 +976,7 @@ public:
void task_wait()
{
task_pool.wait_work();
task_pool.wait();
}
void task_cancel()

View File

@@ -314,7 +314,7 @@ public:
class OpenCLDevice : public Device
{
public:
TaskPool task_pool;
DedicatedTaskPool task_pool;
cl_context cxContext;
cl_command_queue cqCommandQueue;
cl_platform_id cpPlatform;
@@ -1100,7 +1100,7 @@ public:
void task_wait()
{
task_pool.wait_work();
task_pool.wait();
}
void task_cancel()

View File

@@ -168,7 +168,7 @@ void TaskPool::num_increase()
thread_mutex TaskScheduler::mutex;
int TaskScheduler::users = 0;
vector<thread*> TaskScheduler::threads;
volatile bool TaskScheduler::do_exit = false;
bool TaskScheduler::do_exit = false;
list<TaskScheduler::Entry> TaskScheduler::queue;
thread_mutex TaskScheduler::queue_mutex;
@@ -298,5 +298,153 @@ void TaskScheduler::clear(TaskPool *pool)
pool->num_decrease(done);
}
/* Dedicated Task Pool */
DedicatedTaskPool::DedicatedTaskPool()
{
do_cancel = false;
do_exit = false;
num = 0;
worker_thread = new thread(function_bind(&DedicatedTaskPool::thread_run, this));
}
DedicatedTaskPool::~DedicatedTaskPool()
{
stop();
worker_thread->join();
delete worker_thread;
}
void DedicatedTaskPool::push(Task *task, bool front)
{
num_increase();
/* add task to queue */
queue_mutex.lock();
if(front)
queue.push_front(task);
else
queue.push_back(task);
queue_cond.notify_one();
queue_mutex.unlock();
}
void DedicatedTaskPool::push(const TaskRunFunction& run, bool front)
{
push(new Task(run), front);
}
void DedicatedTaskPool::wait()
{
thread_scoped_lock num_lock(num_mutex);
while(num)
num_cond.wait(num_lock);
}
void DedicatedTaskPool::cancel()
{
do_cancel = true;
clear();
wait();
do_cancel = false;
}
void DedicatedTaskPool::stop()
{
clear();
do_exit = true;
queue_cond.notify_all();
wait();
assert(num == 0);
}
bool DedicatedTaskPool::cancelled()
{
return do_cancel;
}
void DedicatedTaskPool::num_decrease(int done)
{
num_mutex.lock();
num -= done;
assert(num >= 0);
if(num == 0)
num_cond.notify_all();
num_mutex.unlock();
}
void DedicatedTaskPool::num_increase()
{
thread_scoped_lock num_lock(num_mutex);
num++;
num_cond.notify_all();
}
bool DedicatedTaskPool::thread_wait_pop(Task*& task)
{
thread_scoped_lock queue_lock(queue_mutex);
while(queue.empty() && !do_exit)
queue_cond.wait(queue_lock);
if(queue.empty()) {
assert(do_exit);
return false;
}
task = queue.front();
queue.pop_front();
return true;
}
void DedicatedTaskPool::thread_run()
{
Task *task;
/* keep popping off tasks */
while(thread_wait_pop(task)) {
/* run task */
task->run();
/* delete task */
delete task;
/* notify task was done */
num_decrease(1);
}
}
void DedicatedTaskPool::clear()
{
thread_scoped_lock queue_lock(queue_mutex);
/* erase all tasks from the queue */
list<Task*>::iterator it = queue.begin();
int done = 0;
while(it != queue.end()) {
done++;
delete *it;
it = queue.erase(it);
}
queue_lock.unlock();
/* notify done */
num_decrease(done);
}
CCL_NAMESPACE_END

View File

@@ -50,7 +50,7 @@ public:
* pool, we can wait for all tasks to be done, or cancel them before they are
* done.
*
* The run callback that actually executes the task may be create like this:
* The run callback that actually executes the task may be created like this:
* function_bind(&MyClass::task_execute, this, _1, _2) */
class TaskPool
@@ -77,8 +77,8 @@ protected:
thread_mutex num_mutex;
thread_condition_variable num_cond;
volatile int num;
volatile bool do_cancel;
int num;
bool do_cancel;
};
/* Task Scheduler
@@ -109,7 +109,7 @@ protected:
static thread_mutex mutex;
static int users;
static vector<thread*> threads;
static volatile bool do_exit;
static bool do_exit;
static list<Entry> queue;
static thread_mutex queue_mutex;
@@ -122,6 +122,51 @@ protected:
static void clear(TaskPool *pool);
};
/* Dedicated Task Pool
*
* Like a TaskPool, but will launch one dedicated thread to execute all tasks.
*
* The run callback that actually executes the task may be created like this:
* function_bind(&MyClass::task_execute, this, _1, _2) */
class DedicatedTaskPool
{
public:
DedicatedTaskPool();
~DedicatedTaskPool();
void push(Task *task, bool front = false);
void push(const TaskRunFunction& run, bool front = false);
void wait(); /* wait until all tasks are done */
void cancel(); /* cancel all tasks, keep worker thread running */
void stop(); /* stop worker thread */
bool cancelled(); /* for worker thread, test if cancelled */
protected:
void num_decrease(int done);
void num_increase();
void thread_run();
bool thread_wait_pop(Task*& entry);
void clear();
thread_mutex num_mutex;
thread_condition_variable num_cond;
list<Task*> queue;
thread_mutex queue_mutex;
thread_condition_variable queue_cond;
int num;
bool do_cancel;
bool do_exit;
thread *worker_thread;
};
CCL_NAMESPACE_END
#endif