void ezSimpleTestGroup::RunSubTest(ezInt32 iIdentifier) { { EZ_PROFILE(m_SimpleTests[iIdentifier].m_ProfilingId); m_SimpleTests[iIdentifier].m_Func(); } }
ezResult ezTaskSystem::CancelTask(ezTask* pTask, ezOnTaskRunning::Enum OnTaskRunning) { if (pTask->IsTaskFinished()) return EZ_SUCCESS; EZ_PROFILE(s_ProfileCancelTask); EZ_ASSERT(pTask->m_BelongsToGroup.m_pTaskGroup->m_uiGroupCounter == pTask->m_BelongsToGroup.m_uiGroupCounter, "The task to be removed is in an invalid group."); // we set the cancel flag, to make sure that tasks that support canceling will terminate asap pTask->m_bCancelExecution = true; { EZ_LOCK(s_TaskSystemMutex); // if the task is still in the queue of its group, it had not yet been scheduled if (!pTask->m_bTaskIsScheduled && pTask->m_BelongsToGroup.m_pTaskGroup->m_Tasks.RemoveSwap(pTask)) { // we set the task to finished, even though it was not executed pTask->m_bIsFinished = true; return EZ_SUCCESS; } // check if the task has already been scheduled for execution // if so, remove it from the work queue { for (ezUInt32 i = 0; i < ezTaskPriority::ENUM_COUNT; ++i) { auto it = s_Tasks[i].GetIterator(); while (it.IsValid()) { if (it->m_pTask == pTask) { s_Tasks[i].Erase(it); // we set the task to finished, even though it was not executed pTask->m_bIsFinished = true; // tell the system that one task of that group is 'finished', to ensure its dependencies will get scheduled TaskHasFinished(it->m_pTask, it->m_pBelongsToGroup); return EZ_SUCCESS; } ++it; } } } } // if we made it here, the task was already running // thus we just wait for it to finish if (OnTaskRunning == ezOnTaskRunning::WaitTillFinished) WaitForTask(pTask); return EZ_FAILURE; }
void ezTask::Run() { // actually this should not be possible to happen if (m_bIsFinished || m_bCancelExecution) { m_bIsFinished = true; return; } { EZ_ASSERT(m_bProfilingIDGenerated, "Profiling id must be valid at this point."); EZ_PROFILE(m_ProfilingID); Execute(); } m_bIsFinished = true; }
void ezTaskSystem::WaitForTask(ezTask* pTask) { if (pTask->IsTaskFinished()) return; EZ_PROFILE(s_ProfileWaitForTask); const bool bIsMainThread = ezThreadUtils::IsMainThread(); ezTaskPriority::Enum FirstPriority = ezTaskPriority::EarlyThisFrame; ezTaskPriority::Enum LastPriority = ezTaskPriority::LateNextFrame; if (bIsMainThread) { // if this is the main thread, we need to execute the main-thread tasks // otherwise a dependency on which pTask is waiting, might not get fulfilled FirstPriority = ezTaskPriority::ThisFrameMainThread; LastPriority = ezTaskPriority::SomeFrameMainThread; } while (!pTask->IsTaskFinished()) { // we only execute short tasks here, because you should never WAIT for a long running task // and a short task should never have a dependency on a long running task either // so we assume that only short running tasks need to be executed to fulfill the task's dependencies // Since there are threads to deal with long running tasks in parallel, even if we were waiting for such // a task, it will get finished at some point if (!ExecuteTask(FirstPriority, LastPriority, pTask)) { // if there was nothing for us to do, that probably means that the task is either currently being processed by some other thread // or it is in a priority list that we did not want to work on (maybe because we are on the main thread) // in this case try it again with non-main-thread tasks if (!pTask->IsTaskFinished() && !ExecuteTask(ezTaskPriority::EarlyThisFrame, ezTaskPriority::LateNextFrame, pTask)) { // if there is STILL nothing for us to do, it might be a long running task OR it is already being processed // we won't fall back to processing long running tasks, because that might stall the application // instead we assume the task (or any dependency) is currently processed by another thread // and to prevent a busy loop, we just give up our time-slice and try again later ezThreadUtils::YieldTimeSlice(); } } } }