Browse Source

Some refactoring

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
681d669e70

+ 1 - 0
include/anki/Util.h

@@ -66,4 +66,5 @@
 #include <anki/util/StringList.h>
 #include <anki/util/System.h>
 #include <anki/util/Thread.h>
+#include <anki/util/ThreadPool.h>
 #include <anki/util/Visitor.h>

+ 1 - 0
include/anki/renderer/Clusterer.h

@@ -16,6 +16,7 @@ namespace anki
 // Forward
 class FrustumComponent;
 class SceneNode;
+class ThreadPool;
 
 /// @addtogroup renderer
 /// @{

+ 1 - 0
include/anki/renderer/MainRenderer.h

@@ -17,6 +17,7 @@ class ResourceManager;
 class ConfigSet;
 class SceneGraph;
 class SceneNode;
+class ThreadPool;
 
 /// @addtogroup renderer
 /// @{

+ 1 - 0
include/anki/renderer/Renderer.h

@@ -14,6 +14,7 @@
 #include <anki/resource/Forward.h>
 #include <anki/resource/ShaderResource.h>
 #include <anki/core/Timestamp.h>
+#include <anki/util/ThreadPool.h>
 
 namespace anki
 {

+ 0 - 1
include/anki/scene/SceneNode.h

@@ -12,7 +12,6 @@
 #include <anki/util/BitSet.h>
 #include <anki/util/List.h>
 #include <anki/util/Enum.h>
-#include <anki/util/Thread.h>
 #include <anki/scene/SceneComponent.h>
 
 namespace anki

+ 0 - 92
include/anki/util/Thread.h

@@ -10,8 +10,6 @@
 #include <anki/util/NonCopyable.h>
 #include <atomic>
 
-#define ANKI_DISABLE_THREADPOOL_THREADING 0
-
 namespace anki
 {
 
@@ -185,96 +183,6 @@ public:
 private:
 	void* m_impl = nullptr;
 };
-
-// Forward
-namespace detail
-{
-class ThreadPoolThread;
-}
-
-/// Parallel task dispatcher. You feed it with tasks and sends them for
-/// execution in parallel and then waits for all to finish
-class ThreadPool : public NonCopyable
-{
-	friend class detail::ThreadPoolThread;
-
-public:
-	static constexpr U MAX_THREADS = 32; ///< An absolute limit
-
-	/// A task assignment for a ThreadPool
-	class Task
-	{
-	public:
-		virtual ~Task()
-		{
-		}
-
-		virtual Error operator()(U32 taskId, PtrSize threadsCount) = 0;
-
-		/// Chose a starting and end index
-		static void choseStartEnd(U32 taskId,
-			PtrSize threadsCount,
-			PtrSize elementsCount,
-			PtrSize& start,
-			PtrSize& end)
-		{
-			F32 tid = taskId;
-			F32 div = F32(elementsCount) / threadsCount;
-			start = PtrSize(tid * div);
-			end = PtrSize((tid + 1.0) * div);
-		}
-	};
-
-	/// Constructor
-	ThreadPool(U32 threadsCount);
-
-	~ThreadPool();
-
-	/// Assign a task to a working thread
-	/// @param slot The slot of the task
-	/// @param task The task. If it's nullptr then a dummy task will be assigned
-	void assignNewTask(U32 slot, Task* task);
-
-	/// Wait for all tasks to finish.
-	/// @return The error code in one of the worker threads.
-	ANKI_USE_RESULT Error waitForAllThreadsToFinish()
-	{
-#if !ANKI_DISABLE_THREADPOOL_THREADING
-		m_barrier.wait();
-		m_tasksAssigned = 0;
-#endif
-		Error err = m_err;
-		m_err = ErrorCode::NONE;
-		return err;
-	}
-
-	PtrSize getThreadsCount() const
-	{
-		return m_threadsCount;
-	}
-
-private:
-	/// A dummy task for a ThreadPool
-	class DummyTask : public Task
-	{
-	public:
-		Error operator()(U32 taskId, PtrSize threadsCount)
-		{
-			(void)taskId;
-			(void)threadsCount;
-			return ErrorCode::NONE;
-		}
-	};
-
-#if !ANKI_DISABLE_THREADPOOL_THREADING
-	Barrier m_barrier; ///< Synchronization barrier
-	detail::ThreadPoolThread* m_threads = nullptr; ///< Threads array
-	U m_tasksAssigned = 0;
-#endif
-	U8 m_threadsCount = 0;
-	Error m_err = ErrorCode::NONE;
-	static DummyTask m_dummyTask;
-};
 /// @}
 
 } // end namespace anki

+ 8 - 4
include/anki/core/Threadpool.h → include/anki/util/ThreadHive.h

@@ -5,13 +5,17 @@
 
 #pragma once
 
-#include <anki/util/Thread.h>
-#include <anki/util/Singleton.h>
+#include <anki/util/ThreadPool.h>
 
 namespace anki
 {
 
-/// Singleton
-typedef Singleton<ThreadPool> ThreadPoolSingleton;
+/// @addtogroup util_thread
+/// @{
+
+class ThreadHive
+{
+};
+/// @}
 
 } // end namespace anki

+ 103 - 0
include/anki/util/ThreadPool.h

@@ -0,0 +1,103 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/util/Thread.h>
+
+namespace anki
+{
+
+// Forward
+namespace detail
+{
+class ThreadPoolThread;
+}
+
+/// @addtogroup util_thread
+/// @{
+
+/// A task assignment for a ThreadPool
+class ThreadPoolTask
+{
+public:
+	virtual ~ThreadPoolTask()
+	{
+	}
+
+	virtual Error operator()(U32 taskId, PtrSize threadsCount) = 0;
+
+	/// Chose a starting and end index
+	static void choseStartEnd(U32 taskId,
+		PtrSize threadsCount,
+		PtrSize elementsCount,
+		PtrSize& start,
+		PtrSize& end)
+	{
+		F32 tid = taskId;
+		F32 div = F32(elementsCount) / threadsCount;
+		start = PtrSize(tid * div);
+		end = PtrSize((tid + 1.0) * div);
+	}
+};
+
+/// Parallel task dispatcher. You feed it with tasks and sends them for
+/// execution in parallel and then waits for all to finish
+class ThreadPool : public NonCopyable
+{
+	friend class detail::ThreadPoolThread;
+
+public:
+	static constexpr U MAX_THREADS = 32; ///< An absolute limit
+
+	/// Constructor
+	ThreadPool(U32 threadsCount);
+
+	~ThreadPool();
+
+	/// Assign a task to a working thread
+	/// @param slot The slot of the task
+	/// @param task The task. If it's nullptr then a dummy task will be assigned
+	void assignNewTask(U32 slot, ThreadPoolTask* task);
+
+	/// Wait for all tasks to finish.
+	/// @return The error code in one of the worker threads.
+	ANKI_USE_RESULT Error waitForAllThreadsToFinish()
+	{
+		m_barrier.wait();
+		m_tasksAssigned = 0;
+		Error err = m_err;
+		m_err = ErrorCode::NONE;
+		return err;
+	}
+
+	PtrSize getThreadsCount() const
+	{
+		return m_threadsCount;
+	}
+
+private:
+	/// A dummy task for a ThreadPool
+	class DummyTask : public ThreadPoolTask
+	{
+	public:
+		Error operator()(U32 taskId, PtrSize threadsCount)
+		{
+			(void)taskId;
+			(void)threadsCount;
+			return ErrorCode::NONE;
+		}
+	};
+
+	Barrier m_barrier; ///< Synchronization barrier
+	detail::ThreadPoolThread* m_threads = nullptr; ///< Threads array
+	U m_tasksAssigned = 0;
+	U8 m_threadsCount = 0;
+	Error m_err = ErrorCode::NONE;
+	static DummyTask m_dummyTask;
+};
+/// @}
+
+} // end namespace anki

+ 1 - 0
src/core/App.cpp

@@ -9,6 +9,7 @@
 #include <anki/util/File.h>
 #include <anki/util/Filesystem.h>
 #include <anki/util/System.h>
+#include <anki/util/ThreadPool.h>
 #include <anki/core/Trace.h>
 
 #include <anki/core/NativeWindow.h>

+ 13 - 15
src/core/Trace.cpp

@@ -62,16 +62,8 @@ thread_local I g_traceEventsInFlight = 0;
 //==============================================================================
 TraceManager::~TraceManager()
 {
-	if(m_traceFile.isOpen())
-	{
-		Error err = m_traceFile.writeText(
-			"{\"name\": \"dummy\", "
-			"\"cat\": \"PERF\", \"ph\": \"X\", \"pid\": 1, \"tid\": %llu, "
-			"\"ts\": 0, \"dur\": 1}]}",
-			Thread::getCurrentThreadId());
-
-		ANKI_TRACE_FILE_ERROR();
-	}
+	// No need to close the json (no need to add ']'). Chrome will take care
+	// of that
 }
 
 //==============================================================================
@@ -89,9 +81,7 @@ Error TraceManager::create(HeapAllocator<U8> alloc, const CString& cacheDir)
 	fname.sprintf("%s/trace.json", &cacheDir[0]);
 
 	ANKI_CHECK(m_traceFile.open(fname.toCString(), File::OpenFlag::WRITE));
-	ANKI_CHECK(m_traceFile.writeText("{\n"
-									 "\"displayTimeUnit\": \"ms\",\n"
-									 "\"traceEvents\": [\n"));
+	ANKI_CHECK(m_traceFile.writeText("["));
 
 	// Create per frame file
 	StringAuto perFrameFname(alloc);
@@ -215,13 +205,21 @@ Error TraceManager::flushEvents()
 	{
 		const Entry& e = m_entries[i];
 
+		U64 startMicroSec = U64(e.m_timestamp * 1000000.0);
+		U64 durMicroSec = U64(e.m_duration * 1000000.0);
+
+		if(durMicroSec == 0)
+		{
+			continue;
+		}
+
 		ANKI_CHECK(m_traceFile.writeText(
 			"{\"name\": \"%s\", \"cat\": \"PERF\", \"ph\": \"X\", "
 			"\"pid\": 1, \"tid\": %llu, \"ts\": %llu, \"dur\": %llu},\n",
 			eventNames[e.m_event],
 			e.m_tid,
-			U64(e.m_timestamp * 1000000.0),
-			U64(e.m_duration * 1000000.0)));
+			startMicroSec,
+			durMicroSec));
 	}
 
 	for(U i = 0; i < U(TraceEventType::COUNT); ++i)

+ 6 - 5
src/renderer/Clusterer.cpp

@@ -8,6 +8,7 @@
 #include <anki/scene/MoveComponent.h>
 #include <anki/scene/SceneNode.h>
 #include <anki/util/Rtti.h>
+#include <anki/util/ThreadPool.h>
 
 namespace anki
 {
@@ -17,7 +18,7 @@ namespace anki
 //==============================================================================
 
 //==============================================================================
-class UpdatePlanesPerspectiveCameraTask : public ThreadPool::Task
+class UpdatePlanesPerspectiveCameraTask : public ThreadPoolTask
 {
 public:
 	Clusterer* m_clusterer = nullptr;
@@ -548,7 +549,7 @@ void Clusterer::update(U32 threadId, PtrSize threadsCount, Bool frustumChanged)
 		// Re-calculate the planes in local space
 
 		// First the top looking planes
-		ThreadPool::Task::choseStartEnd(
+		ThreadPoolTask::choseStartEnd(
 			threadId, threadsCount, m_planesYW.getSize(), start, end);
 
 		for(U i = start; i < end; i++)
@@ -559,7 +560,7 @@ void Clusterer::update(U32 threadId, PtrSize threadsCount, Bool frustumChanged)
 		}
 
 		// Then the right looking planes
-		ThreadPool::Task::choseStartEnd(
+		ThreadPoolTask::choseStartEnd(
 			threadId, threadsCount, m_planesXW.getSize(), start, end);
 
 		for(U j = start; j < end; j++)
@@ -574,7 +575,7 @@ void Clusterer::update(U32 threadId, PtrSize threadsCount, Bool frustumChanged)
 		// Only transform planes
 
 		// First the top looking planes
-		ThreadPool::Task::choseStartEnd(
+		ThreadPoolTask::choseStartEnd(
 			threadId, threadsCount, m_planesYW.getSize(), start, end);
 
 		for(U i = start; i < end; i++)
@@ -583,7 +584,7 @@ void Clusterer::update(U32 threadId, PtrSize threadsCount, Bool frustumChanged)
 		}
 
 		// Then the right looking planes
-		ThreadPool::Task::choseStartEnd(
+		ThreadPoolTask::choseStartEnd(
 			threadId, threadsCount, m_planesXW.getSize(), start, end);
 
 		for(U j = start; j < end; j++)

+ 0 - 1
src/renderer/Drawer.cpp

@@ -15,7 +15,6 @@
 #include <anki/renderer/Renderer.h>
 #include <anki/core/Trace.h>
 #include <anki/util/Logger.h>
-#include <anki/util/Thread.h>
 
 namespace anki
 {

+ 1 - 1
src/renderer/Fs.cpp

@@ -92,7 +92,7 @@ Error Fs::buildCommandBuffers(
 
 	U problemSize = vis.getCount(VisibilityGroupType::RENDERABLES_FS);
 	PtrSize start, end;
-	ThreadPool::Task::choseStartEnd(
+	ThreadPoolTask::choseStartEnd(
 		threadId, threadCount, problemSize, start, end);
 
 	if(start == end)

+ 2 - 2
src/renderer/Is.cpp

@@ -304,7 +304,7 @@ public:
 };
 
 /// Write the lights to the GPU buffers.
-class WriteLightsTask : public ThreadPool::Task
+class WriteLightsTask : public ThreadPoolTask
 {
 public:
 	TaskCommonData* m_data = nullptr;
@@ -612,7 +612,7 @@ void Is::binLights(U32 threadId, PtrSize threadsCount, TaskCommonData& task)
 	//
 	// Initialize the temp clusters
 	//
-	ThreadPool::Task::choseStartEnd(
+	ThreadPoolTask::choseStartEnd(
 		threadId, threadsCount, clusterCount, start, end);
 
 	for(U i = start; i < end; ++i)

+ 2 - 1
src/renderer/Ms.cpp

@@ -6,6 +6,7 @@
 #include <anki/renderer/Ms.h>
 #include <anki/renderer/Renderer.h>
 #include <anki/util/Logger.h>
+#include <anki/util/ThreadPool.h>
 #include <anki/scene/SceneGraph.h>
 #include <anki/scene/FrustumComponent.h>
 #include <anki/misc/ConfigSet.h>
@@ -127,7 +128,7 @@ Error Ms::buildCommandBuffers(
 
 	U problemSize = vis.getCount(VisibilityGroupType::RENDERABLES_MS);
 	PtrSize start, end;
-	ThreadPool::Task::choseStartEnd(
+	ThreadPoolTask::choseStartEnd(
 		threadId, threadCount, problemSize, start, end);
 
 	if(start != end)

+ 1 - 1
src/renderer/Renderer.cpp

@@ -419,7 +419,7 @@ Error Renderer::buildCommandBuffers(RenderingContext& ctx)
 	m_fs->prepareBuildCommandBuffers(ctx);
 
 	// Build
-	class Task : public ThreadPool::Task
+	class Task : public ThreadPoolTask
 	{
 	public:
 		Renderer* m_r ANKI_DBG_NULLIFY_PTR;

+ 3 - 2
src/renderer/Sm.cpp

@@ -12,6 +12,7 @@
 #include <anki/scene/FrustumComponent.h>
 #include <anki/scene/MoveComponent.h>
 #include <anki/misc/ConfigSet.h>
+#include <anki/util/ThreadPool.h>
 
 namespace anki
 {
@@ -254,7 +255,7 @@ Error Sm::doSpotLight(SceneNode& light,
 	VisibilityTestResults& vis = frc.getVisibilityTestResults();
 	U problemSize = vis.getCount(VisibilityGroupType::RENDERABLES_MS);
 	PtrSize start, end;
-	ThreadPool::Task::choseStartEnd(
+	ThreadPoolTask::choseStartEnd(
 		threadId, threadCount, problemSize, start, end);
 
 	if(start == end)
@@ -292,7 +293,7 @@ Error Sm::doOmniLight(SceneNode& light,
 			VisibilityTestResults& vis = frc.getVisibilityTestResults();
 			U problemSize = vis.getCount(VisibilityGroupType::RENDERABLES_MS);
 			PtrSize start, end;
-			ThreadPool::Task::choseStartEnd(
+			ThreadPoolTask::choseStartEnd(
 				threadId, threadCount, problemSize, start, end);
 
 			if(start != end)

+ 2 - 1
src/scene/SceneGraph.cpp

@@ -13,6 +13,7 @@
 #include <anki/renderer/MainRenderer.h>
 #include <anki/renderer/Renderer.h>
 #include <anki/misc/ConfigSet.h>
+#include <anki/util/ThreadPool.h>
 
 namespace anki
 {
@@ -25,7 +26,7 @@ namespace
 {
 
 //==============================================================================
-class UpdateSceneNodesTask : public ThreadPool::Task
+class UpdateSceneNodesTask : public ThreadPoolTask
 {
 public:
 	SceneGraph* m_scene = nullptr;

+ 2 - 1
src/scene/Visibility.cpp

@@ -15,6 +15,7 @@
 #include <anki/renderer/MainRenderer.h>
 #include <anki/util/Logger.h>
 #include <anki/core/Trace.h>
+#include <anki/util/ThreadPool.h>
 
 namespace anki
 {
@@ -91,7 +92,7 @@ public:
 };
 
 /// Task.
-class VisibilityTestTask : public ThreadPool::Task
+class VisibilityTestTask : public ThreadPoolTask
 {
 public:
 	VisibilityContext* m_ctx = nullptr;

+ 1 - 1
src/util/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(ANKI_UTIL_SOURCES Assert.cpp Functions.cpp File.cpp Filesystem.cpp Memory.cpp System.cpp HighRezTimer.cpp Thread.cpp Hash.cpp Logger.cpp String.cpp)
+set(ANKI_UTIL_SOURCES Assert.cpp Functions.cpp File.cpp Filesystem.cpp Memory.cpp System.cpp HighRezTimer.cpp ThreadPool.cpp Hash.cpp Logger.cpp String.cpp)
 
 if(LINUX OR ANDROID OR MACOS)
 	set(ANKI_UTIL_SOURCES ${ANKI_UTIL_SOURCES} HighRezTimerPosix.cpp FilesystemPosix.cpp ThreadPosix.cpp)

+ 4 - 28
src/util/Thread.cpp → src/util/ThreadPool.cpp

@@ -3,13 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <anki/util/Thread.h>
-#include <anki/util/Assert.h>
+#include <anki/util/ThreadPool.h>
 #include <anki/util/Logger.h>
-#include <anki/util/Functions.h>
 #include <cstdlib>
 #include <new>
-#include <cstdio>
 
 namespace anki
 {
@@ -18,18 +15,16 @@ namespace anki
 // ThreadPoolThread                                                            =
 //==============================================================================
 
-#if !ANKI_DISABLE_THREADPOOL_THREADING
-
 namespace detail
 {
 
-/// The thread that executes a ThreadPool::Task
+/// The thread that executes a ThreadPoolTask
 class ThreadPoolThread
 {
 public:
 	U32 m_id; ///< An ID
 	Thread m_thread; ///< Runs the workingFunc
-	ThreadPool::Task* m_task; ///< Its NULL if there is no pending task
+	ThreadPoolTask* m_task; ///< Its NULL if there is no pending task
 	ThreadPool* m_threadpool;
 	Bool8 m_quit = false;
 
@@ -77,8 +72,6 @@ private:
 
 } // end namespace detail
 
-#endif
-
 //==============================================================================
 // ThreadPool                                                                  =
 //==============================================================================
@@ -88,16 +81,11 @@ ThreadPool::DummyTask ThreadPool::m_dummyTask;
 
 //==============================================================================
 ThreadPool::ThreadPool(U32 threadsCount)
-#if !ANKI_DISABLE_THREADPOOL_THREADING
 	: m_barrier(threadsCount + 1)
-#endif
 {
 	m_threadsCount = threadsCount;
 	ANKI_ASSERT(m_threadsCount <= MAX_THREADS && m_threadsCount > 0);
 
-#if ANKI_DISABLE_THREADPOOL_THREADING
-	ANKI_LOGW("ThreadPool works in synchronous mode");
-#else
 	m_threads = reinterpret_cast<detail::ThreadPoolThread*>(
 		malloc(sizeof(detail::ThreadPoolThread) * m_threadsCount));
 
@@ -111,13 +99,11 @@ ThreadPool::ThreadPool(U32 threadsCount)
 		::new(&m_threads[threadsCount])
 			detail::ThreadPoolThread(threadsCount, this);
 	}
-#endif
 }
 
 //==============================================================================
 ThreadPool::~ThreadPool()
 {
-#if !ANKI_DISABLE_THREADPOOL_THREADING
 	// Terminate threads
 	U count = m_threadsCount;
 	while(count-- != 0)
@@ -145,11 +131,10 @@ ThreadPool::~ThreadPool()
 	{
 		free(m_threads);
 	}
-#endif
 }
 
 //==============================================================================
-void ThreadPool::assignNewTask(U32 slot, Task* task)
+void ThreadPool::assignNewTask(U32 slot, ThreadPoolTask* task)
 {
 	ANKI_ASSERT(slot < getThreadsCount());
 	if(task == nullptr)
@@ -157,7 +142,6 @@ void ThreadPool::assignNewTask(U32 slot, Task* task)
 		task = &m_dummyTask;
 	}
 
-#if !ANKI_DISABLE_THREADPOOL_THREADING
 	m_threads[slot].m_task = task;
 	++m_tasksAssigned;
 
@@ -166,14 +150,6 @@ void ThreadPool::assignNewTask(U32 slot, Task* task)
 		// Last task is assigned. Wake all threads
 		m_barrier.wait();
 	}
-#else
-	Error err = (*task)(slot, m_threadsCount);
-
-	if(err)
-	{
-		m_err = err;
-	}
-#endif
 }
 
 } // end namespace anki