Files
igl/external/embree/common/sys/taskscheduler_mic.cpp
T

195 lines
5.7 KiB
C++
Executable File

// ======================================================================== //
// Copyright 2009-2014 Intel Corporation //
// //
// Licensed under the Apache License, Version 2.0 (the "License"); //
// you may not use this file except in compliance with the License. //
// You may obtain a copy of the License at //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// Unless required by applicable law or agreed to in writing, software //
// distributed under the License is distributed on an "AS IS" BASIS, //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and //
// limitations under the License. //
// ======================================================================== //
#include "taskscheduler_mic.h"
#include "sys/sync/mutex.h"
namespace embree
{
__aligned(64) AtomicMutex mtx;
//#define DBG(x) { mtx.lock(); x ; mtx.unlock(); }
#define DBG(x)
TaskSchedulerMIC::TaskSchedulerMIC()
{
for (size_t i=0; i<NUM_TASKS; i++) tasks[i] = NULL;
head_task_list = 0;
}
/*! waits for an event out of a task */
void TaskSchedulerMIC::wait(size_t threadIndex, size_t threadCount, Event* event)
{
DBG(
PING;
DBG_PRINT(threadIndex);
DBG_PRINT(threadCount);
);
}
/*! processes next task */
void TaskSchedulerMIC::work(size_t threadIndex, size_t threadCount, Task *task)
{
DBG(std::cout << "START WORK task " << task << " threadIndex " << threadIndex << std::endl << std::flush);
/* take next task from task list */
TaskScheduler::Event* event = task->event;
DBG(
std::cout << "GOT TASK " << (void*)task << " : threadIndex " << threadIndex << " threadCount " << threadCount << std::endl << std::flush;
);
while (true)
{
if (unlikely((int)task->started < 0)) break;
int elt = --task->started;
if (unlikely(elt < 0)) break;
#if defined(__MIC__)
if (task->run) task->run(task->runData,threadIndex,threadCount,task->elts-1-elt,task->elts,task->event);
#else
if (task->run) task->run(task->runData,threadIndex,threadCount,elt,task->elts,task->event);
#endif
}
barrier.waitForThreads(threadIndex,threadCount);
DBG(std::cout << "END WORK task " << task << " threadIndex " << threadIndex << std::endl << std::flush);
}
void TaskSchedulerMIC::add(ssize_t threadIndex, QUEUE queue, Task* task)
{
DBG( PING; std::cout << "add task " << task << " threadIndex " << threadIndex << std::endl << std::flush );
if (task->elts == 1)
{
int elt = --task->started;
if (task->run) task->run(task->runData,0,1,elt,task->elts,task->event);
if (task->complete)
task->complete(task->completeData,0,1,task->event);
}
else
{
__memory_barrier();
unsigned int liveIndex = (head_task_list++)&(NUM_TASKS-1);
__memory_barrier();
if (tasks[liveIndex]) THROW_RUNTIME_ERROR("task list full");
__memory_barrier();
assert(tasks[liveIndex] == NULL);
tasks[liveIndex] = task;
DBG( std::cout << "ADD TASK: head " << head_task_list << " liveIndex " << liveIndex << " threadIndex " << threadIndex << std::endl );
DBG( std::cout << "WAIT APP THREAD..." << std::endl << std::flush);
__memory_barrier();
while (tasks[liveIndex] != NULL) {
__pause_cpu(1023);
}
DBG( std::cout << "WAIT APP THREAD...DONE" << std::endl << std::flush);
}
}
void TaskSchedulerMIC::run(size_t threadIndex, size_t threadCount)
{
DBG( std::cout<< "run function for thread " << threadIndex << " " << std::endl << std::flush);
unsigned int tail_task_list = 0;
while(1)
{
DBG( std::cout<< "ENTERING WAIT STATE " << threadIndex << " head_task_list " << head_task_list << " tail_task_list " << tail_task_list << std::endl << std::flush);
/* wait for available task */
while(head_task_list == tail_task_list && !terminateThreads)
{
__pause_cpu(1023);
}
DBG( std::cout<< "WOKE " << threadIndex << std::endl);
unsigned int task_index = tail_task_list & (NUM_TASKS-1);
Task *task = tasks[task_index];
if (task == NULL)
{
DBG(std::cout << "thread activated but no task found = threadIndex " << threadIndex << std::endl << std::flush);
}
else
{
DBG(std::cout << "thread work = threadIndex " << threadIndex << std::endl << std::flush);
work(threadIndex,threadCount,task);
if (threadIndex == 0)
{
DBG(
std::cout << "COMPLETE threadIndex " << threadIndex << std::endl << std::flush;
);
DBG(
std::cout << "COMPLETE FCT START threadIndex " << threadIndex << std::endl << std::flush;
);
if (task->complete)
task->complete(task->completeData,threadIndex,threadCount,task->event);
DBG(
std::cout << "COMPLETE FCT DONE threadIndex " << threadIndex << std::endl << std::flush;
);
//if (task->event) task->event->dec();
DBG(
std::cout << "EVENT DONE threadIndex " << threadIndex << std::endl << std::flush;
);
__memory_barrier();
tasks[task_index] = NULL;
__memory_barrier();
}
__memory_barrier();
tail_task_list++;
}
/* terminate thread */
if (terminateThreads)
{
DBG(std::cout << "terminate thread " << threadIndex << std::endl << std::flush);
return;
}
}
}
void TaskSchedulerMIC::terminate() {
terminateThreads = true;
}
}