// ======================================================================== // // 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 "barrier.h" #include "condition.h" #if defined (__WIN32__) #define WIN32_LEAN_AND_MEAN #include namespace embree { struct BarrierSysImplementation { __forceinline BarrierSysImplementation () : i(0), enterCount(0), exitCount(0), barrierSize(0) { events[0] = CreateEvent(NULL, TRUE, FALSE, NULL); events[1] = CreateEvent(NULL, TRUE, FALSE, NULL); } __forceinline ~BarrierSysImplementation () { CloseHandle(events[0]); CloseHandle(events[1]); } __forceinline void init(size_t N) { barrierSize = N; enterCount = N; exitCount = N; } __forceinline void wait() { /* every thread entering the barrier decrements this count */ size_t i0 = i; ssize_t cnt0 = atomic_add(&enterCount,-1); /* all threads except the last one are wait in the barrier */ if (cnt0 > 1) { if (WaitForSingleObject(events[i0], INFINITE) != WAIT_OBJECT_0) THROW_RUNTIME_ERROR("WaitForSingleObjects failed"); } /* the last thread starts all threads waiting at the barrier */ else { i = 1-i; enterCount = barrierSize; if (SetEvent(events[i0]) == 0) THROW_RUNTIME_ERROR("SetEvent failed"); } /* every thread leaving the barrier decrements this count */ ssize_t cnt1 = atomic_add(&exitCount,-1); /* the last thread that left the barrier resets the event again */ if (cnt1 == 1) { exitCount = barrierSize; if (ResetEvent(events[i0]) == 0) THROW_RUNTIME_ERROR("ResetEvent failed"); } } public: HANDLE events[2]; volatile size_t i; volatile atomic_t enterCount; volatile atomic_t exitCount; size_t barrierSize; }; } #else namespace embree { struct BarrierSysImplementation { __forceinline BarrierSysImplementation () : count(0), barrierSize(0) {} __forceinline void init(size_t N) { count = 0; barrierSize = N; } __forceinline void wait() { mutex.lock(); count++; if (count == barrierSize) { count = 0; cond.broadcast(); mutex.unlock(); return; } cond.wait(mutex); mutex.unlock(); return; } public: MutexSys mutex; ConditionSys cond; volatile size_t count; volatile size_t barrierSize; }; } #endif namespace embree { BarrierSys::BarrierSys () { opaque = new BarrierSysImplementation; } BarrierSys::~BarrierSys () { delete (BarrierSysImplementation*) opaque; } void BarrierSys::init(size_t count) { ((BarrierSysImplementation*) opaque)->init(count); } void BarrierSys::wait() { ((BarrierSysImplementation*) opaque)->wait(); } LinearBarrierActive::LinearBarrierActive (size_t numThreads_i) { numThreads = numThreads_i; mode = 0; flag0 = 0; flag1 = 0; for (size_t i=0; i> 2; const unsigned int coreID = threadID >> 2; const unsigned int MODE = data[coreID].mode; // Drain store buffer for NGO stores //atomic_add((atomic_t*)&data[coreID].data[0],0); //data[coreID].prefetchEx(); if (threadID == 0) { data[0].setThreadStateToDone(MODE,threadID); // == wait for core 0 == data[0].waitForAllThreadsOnCore(MODE); // == wait for (possible) two children cores const unsigned int nextCoreID0 = 1; const unsigned int nextCoreID1 = 2; data[nextCoreID0].prefetch(); data[nextCoreID1].prefetch(); if (nextCoreID0 < MAX_CORES_SYNC) data[nextCoreID0].waitForAllThreadsOnCore(MODE); if (nextCoreID1 < MAX_CORES_SYNC) data[nextCoreID1].waitForAllThreadsOnCore(MODE); data[nextCoreID0].prefetchEx(); data[nextCoreID1].prefetchEx(); // == run signal to core 0 == data[0].switchModeAndSendRunSignal(MODE); // == propagate run signal to core 1,2 == if (nextCoreID0 < MAX_CORES_SYNC) data[nextCoreID0].switchModeAndSendRunSignal(MODE); if (nextCoreID1 < MAX_CORES_SYNC) data[nextCoreID1].switchModeAndSendRunSignal(MODE); } else { const unsigned int nextCoreID0 = 2*coreID + 1; const unsigned int nextCoreID1 = 2*coreID + 2; data[nextCoreID0].prefetch(); data[nextCoreID1].prefetch(); if (threadID % 4 == 0) { if (nextCoreID0 < MAX_CORES_SYNC) data[nextCoreID0].waitForAllThreadsOnCore(MODE); if (nextCoreID1 < MAX_CORES_SYNC) data[nextCoreID1].waitForAllThreadsOnCore(MODE); } data[coreID].setThreadStateToDone(MODE,threadID % 4); data[coreID].waitForThreadReceivesRunSignal(MODE,threadID % 4); // == propagte run signal to the two children == if (threadID % 4 == 0) { data[nextCoreID0].prefetchEx(); data[nextCoreID1].prefetchEx(); if (nextCoreID0 < MAX_CORES_SYNC) data[nextCoreID0].switchModeAndSendRunSignal(MODE); if (nextCoreID1 < MAX_CORES_SYNC) data[nextCoreID1].switchModeAndSendRunSignal(MODE); } } } void QuadTreeBarrier::syncWithReduction(const size_t threadID, const size_t MAX_THREADS_SYNC, void (* reductionFct)(const size_t currentThreadID, const size_t childThreadID, void *ptr), void *ptr) { if (unlikely(MAX_THREADS_SYNC == 1)) return; const unsigned int MAX_CORES_SYNC = MAX_THREADS_SYNC >> 2; const unsigned int coreID = threadID >> 2; const unsigned int MODE = data[coreID].mode; // Drain store buffer for NGO stores //atomic_add((atomic_t*)&data[coreID].data[0],0); data[coreID].prefetchEx(); if (threadID == 0) { data[0].setThreadStateToDone(MODE,threadID); // == wait for core 0 == data[0].waitForAllThreadsOnCore(MODE); (*reductionFct)(threadID,threadID+1,ptr); (*reductionFct)(threadID,threadID+2,ptr); (*reductionFct)(threadID,threadID+3,ptr); // == wait for (possible) two children cores const unsigned int nextCoreID0 = 1; const unsigned int nextCoreID1 = 2; const unsigned int nextThreadID0 = nextCoreID0 * 4; const unsigned int nextThreadID1 = nextCoreID1 * 4; data[nextCoreID0].prefetch(); data[nextCoreID1].prefetch(); if (nextCoreID0 < MAX_CORES_SYNC) { data[nextCoreID0].waitForAllThreadsOnCore(MODE); (*reductionFct)(threadID,nextThreadID0,ptr); } if (nextCoreID1 < MAX_CORES_SYNC) { data[nextCoreID1].waitForAllThreadsOnCore(MODE); (*reductionFct)(threadID,nextThreadID1,ptr); } data[nextCoreID0].prefetchEx(); data[nextCoreID1].prefetchEx(); // == run signal to core 0 == data[0].switchModeAndSendRunSignal(MODE); // == propagate run signal to core 1,2 == if (nextCoreID0 < MAX_CORES_SYNC) data[nextCoreID0].switchModeAndSendRunSignal(MODE); if (nextCoreID1 < MAX_CORES_SYNC) data[nextCoreID1].switchModeAndSendRunSignal(MODE); } else { const unsigned int nextCoreID0 = 2*coreID + 1; const unsigned int nextCoreID1 = 2*coreID + 2; const unsigned int nextThreadID0 = nextCoreID0 * 4; const unsigned int nextThreadID1 = nextCoreID1 * 4; data[nextCoreID0].prefetch(); data[nextCoreID1].prefetch(); if (threadID % 4 == 0) { data[coreID].waitForAllOtherThreadsOnCore(MODE,threadID); (*reductionFct)(threadID,threadID+1,ptr); (*reductionFct)(threadID,threadID+2,ptr); (*reductionFct)(threadID,threadID+3,ptr); if (nextCoreID0 < MAX_CORES_SYNC) { data[nextCoreID0].waitForAllThreadsOnCore(MODE); (*reductionFct)(threadID,nextThreadID0,ptr); } if (nextCoreID1 < MAX_CORES_SYNC) { data[nextCoreID1].waitForAllThreadsOnCore(MODE); (*reductionFct)(threadID,nextThreadID1,ptr); } } data[coreID].setThreadStateToDone(MODE,threadID % 4); data[coreID].waitForThreadReceivesRunSignal(MODE,threadID % 4); // == propagte run signal to the two children == if (threadID % 4 == 0) { data[nextCoreID0].prefetchEx(); data[nextCoreID1].prefetchEx(); if (nextCoreID0 < MAX_CORES_SYNC) data[nextCoreID0].switchModeAndSendRunSignal(MODE); if (nextCoreID1 < MAX_CORES_SYNC) data[nextCoreID1].switchModeAndSendRunSignal(MODE); } } } }