Selaa lähdekoodia

Barrier opts & Tracing additions

Panagiotis Christopoulos Charitos 10 vuotta sitten
vanhempi
sitoutus
ea871ebb7e

+ 4 - 4
CMakeLists.txt

@@ -50,11 +50,11 @@ option(ANKI_WITH_GPERFTOOLS_PROF "Link with gperftools profiler" OFF)
 
 option(ANKI_STRIP "Srip the symbols from the executables" OFF)
 
-option(ANKI_ENABLE_COUNTERS "Enable performance counters. Small overhead" OFF)
-if(ANKI_ENABLE_COUNTERS)
-	set(_ANKI_ENABLE_COUNTERS 1)
+option(ANKI_ENABLE_TRACE "Enable performance tracing. Small overhead" OFF)
+if(ANKI_ENABLE_TRACE)
+	set(_ANKI_ENABLE_TRACE 1)
 else()
-	set(_ANKI_ENABLE_COUNTERS 0)
+	set(_ANKI_ENABLE_TRACE 0)
 endif()
 
 set(ANKI_CPU_ADDR_SPACE "0" CACHE STRING "The CPU architecture (0 or 32 or 64). If zero go native")

+ 1 - 1
include/anki/Config.h.cmake

@@ -106,7 +106,7 @@
 #endif
 
 // Enable performance counters
-#define ANKI_ENABLE_COUNTERS ${_ANKI_ENABLE_COUNTERS}
+#define ANKI_ENABLE_TRACE ${_ANKI_ENABLE_TRACE}
 
 //==============================================================================
 // Other                                                                       =

+ 0 - 119
include/anki/core/Counters.h

@@ -1,119 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <anki/util/StdTypes.h>
-#include <anki/util/Singleton.h>
-#include <anki/util/DArray.h>
-#include <anki/util/File.h>
-#include <anki/util/HighRezTimer.h>
-#include <anki/util/Atomic.h>
-#include <anki/util/Thread.h>
-#include <anki/core/Timestamp.h>
-
-namespace anki {
-
-/// Enumeration of counters
-enum class Counter
-{
-	FPS,
-	MAIN_RENDERER_TIME,
-	RENDERER_MS_TIME,
-	RENDERER_IS_TIME,
-	RENDERER_PPS_TIME,
-	RENDERER_SHADOW_PASSES,
-	RENDERER_LIGHTS_COUNT,
-	RENDERER_MERGED_DRAWCALLS,
-	SCENE_UPDATE_TIME,
-	SWAP_BUFFERS_TIME,
-	GL_CLIENT_WAIT_TIME,
-	GL_SERVER_WAIT_TIME,
-	GL_DRAWCALLS_COUNT,
-	GL_VERTICES_COUNT,
-	GL_QUEUES_SIZE,
-	GL_CLIENT_BUFFERS_SIZE,
-	GR_DYNAMIC_UNIFORMS_SIZE,
-	GR_DYNAMIC_STORAGE_SIZE,
-
-	COUNT
-};
-
-/// The counters manager. It's been used with a singleton
-class CountersManager
-{
-public:
-	CountersManager()
-	{}
-
-	~CountersManager();
-
-	ANKI_USE_RESULT Error create(
-		HeapAllocator<U8> alloc, const CString& cacheDir,
-		const Timestamp* globalTimestamp);
-
-	void increaseCounter(Counter counter, F64 val);
-	void increaseCounter(Counter counter, U64 val);
-
-	/// Write the counters of the frame. Should be called after swapbuffers
-	void resolveFrame();
-
-	/// Resolve all counters and closes the files. Should be called when app
-	/// terminates
-	void flush();
-
-	/// Start a timer of a specific counter
-	void startTimer(Counter counter);
-
-	/// Stop the timer and increase the counter
-	void stopTimerIncreaseCounter(Counter counter);
-
-private:
-	union Value
-	{
-		F64 m_float;
-		U64 m_int;
-	};
-
-	const Timestamp* m_globalTimestamp = nullptr;
-	HeapAllocator<U8> m_alloc;
-	File m_perframeFile;
-	File m_perrunFile;
-	DArray<Value> m_perframeValues;
-	DArray<Value> m_perrunValues;
-	DArray<HighRezTimer::Scalar> m_counterTimes;
-};
-
-/// The singleton of the counters manager
-using CountersManagerSingleton = Singleton<CountersManager>;
-
-// Macros that encapsulate the functionaly
-
-#if ANKI_ENABLE_COUNTERS
-#	define ANKI_COUNTER_INC(counter_, val_) \
-		CountersManagerSingleton::get().increaseCounter(Counter::counter_, val_)
-
-#	define ANKI_COUNTER_START_TIMER(counter_) \
-		CountersManagerSingleton::get().startTimer(Counter::counter_)
-
-#	define ANKI_COUNTER_STOP_TIMER_INC(counter_) \
-		CountersManagerSingleton::get(). \
-		stopTimerIncreaseCounter(Counter::counter_)
-
-#	define ANKI_COUNTERS_RESOLVE_FRAME() \
-		CountersManagerSingleton::get().resolveFrame()
-
-#	define ANKI_COUNTERS_FLUSH() \
-		CountersManagerSingleton::get().flush()
-#else // !ANKI_ENABLE_COUNTERS
-#	define ANKI_COUNTER_INC(counter_, val_) ((void)0)
-#	define ANKI_COUNTER_START_TIMER(counter_) ((void)0)
-#	define ANKI_COUNTER_STOP_TIMER_INC(counter_) ((void)0)
-#	define ANKI_COUNTERS_RESOLVE_FRAME() ((void)0)
-#	define ANKI_COUNTERS_FLUSH() ((void)0)
-#endif // ANKI_ENABLE_COUNTERS
-/// @}
-
-} // end namespace anki

+ 13 - 8
include/anki/core/Trace.h

@@ -36,7 +36,6 @@ enum class TraceEventType
 	RENDER_DRAWER,
 	GL_THREAD,
 	SWAP_BUFFERS,
-	IDLE,
 
 	COUNT
 };
@@ -46,7 +45,12 @@ enum class TraceCounterType
 {
 	GR_DRAWCALLS,
 	GR_DYNAMIC_UNIFORMS_SIZE,
-	RENDERER_LIGHT_COUNT,
+	GR_DYNAMIC_STORAGE_SIZE,
+	GR_VERTICES,
+	RENDERER_LIGHTS,
+	RENDERER_SHADOW_PASSES,
+	RENDERER_MERGED_DRAWCALLS,
+	SCENE_NODES_UPDATED,
 
 	COUNT
 };
@@ -69,9 +73,7 @@ public:
 
 	void incCounter(TraceCounterType c, U64 val)
 	{
-		U idx = U(TraceEventType::COUNT) + U(c);
-		m_perFrameCounters[idx].fetchAdd(val);
-		m_perRunCounters[idx].fetchAdd(val);
+		m_perFrameCounters[U(c)].fetchAdd(val);
 	}
 
 	void startFrame()
@@ -94,7 +96,9 @@ private:
 	static const U BUFFERED_ENTRIES = 1024 * 10;
 	Array<Entry, BUFFERED_ENTRIES> m_entries;
 	Atomic<U32> m_count = {0};
-	File m_file;
+	File m_traceFile;
+	File m_perFrameFile;
+	File m_perRunFile;
 	HighRezTimer::Scalar m_startFrameTime;
 
 	Array<Atomic<U64>, U(TraceEventType::COUNT) + U(TraceCounterType::COUNT)>
@@ -102,7 +106,8 @@ private:
 	Array<Atomic<U64>, U(TraceEventType::COUNT) + U(TraceCounterType::COUNT)>
 		m_perRunCounters = {{}};
 
-	void flushCounters();
+	ANKI_USE_RESULT Error flushCounters();
+	ANKI_USE_RESULT Error flushEvents();
 };
 
 using TraceManagerSingleton = Singleton<TraceManager>;
@@ -110,7 +115,7 @@ using TraceManagerSingleton = Singleton<TraceManager>;
 /// @name Trace macros.
 /// @{
 
-#if ANKI_ENABLE_COUNTERS
+#if ANKI_ENABLE_TRACE
 
 #	define ANKI_TRACE_START_EVENT(name_) \
 	TraceManagerSingleton::get().startEvent()

+ 7 - 1
include/anki/util/Thread.h

@@ -185,7 +185,13 @@ public:
 	Bool wait();
 
 private:
-	void* m_impl = nullptr;
+	union
+	{
+		void* m_impl = nullptr;
+
+		/// Opt to save the indirection.
+		alignas(alignof(long int)) char m_posixImpl[32];
+	};
 };
 
 // Forward

+ 2 - 12
src/core/App.cpp

@@ -9,7 +9,6 @@
 #include <anki/util/File.h>
 #include <anki/util/Filesystem.h>
 #include <anki/util/System.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 
 #include <anki/core/NativeWindow.h>
@@ -134,7 +133,7 @@ void App::cleanup()
 	m_settingsDir.destroy(m_heapAlloc);
 	m_cacheDir.destroy(m_heapAlloc);
 
-#if ANKI_ENABLE_COUNTERS
+#if ANKI_ENABLE_TRACE
 	TraceManagerSingleton::destroy();
 #endif
 }
@@ -183,10 +182,7 @@ Error App::createInternal(const ConfigSet& config_,
 
 	m_timerTick = 1.0 / 60.0; // in sec. 1.0 / period
 
-#if ANKI_ENABLE_COUNTERS
-	ANKI_CHECK(CountersManagerSingleton::get().create(
-		m_heapAlloc, m_settingsDir.toCString(), &m_globalTimestamp));
-
+#if ANKI_ENABLE_TRACE
 	ANKI_CHECK(TraceManagerSingleton::get().create(
 		m_heapAlloc, m_settingsDir.toCString()));
 #endif
@@ -381,7 +377,6 @@ Error App::mainLoop(UserMainLoopCallback callback, void* userData)
 	HighRezTimer::Scalar prevUpdateTime = HighRezTimer::getCurrentTime();
 	HighRezTimer::Scalar crntTime = prevUpdateTime;
 
-	ANKI_COUNTER_START_TIMER(FPS);
 	while(!quit)
 	{
 		ANKI_TRACE_START_FRAME();
@@ -402,7 +397,6 @@ Error App::mainLoop(UserMainLoopCallback callback, void* userData)
 		ANKI_CHECK(m_renderer->render(*m_scene));
 
 		m_gr->swapBuffers();
-		ANKI_COUNTERS_RESOLVE_FRAME();
 
 		// Sleep
 		timer.stop();
@@ -416,10 +410,6 @@ Error App::mainLoop(UserMainLoopCallback callback, void* userData)
 		ANKI_TRACE_STOP_FRAME();
 	}
 
-	// Performance ends
-	ANKI_COUNTER_STOP_TIMER_INC(FPS);
-	ANKI_COUNTERS_FLUSH();
-
 	return ErrorCode::NONE;
 }
 

+ 1 - 1
src/core/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(ANKI_CORE_SOURCES App.cpp StdinListener.cpp Counters.cpp Config.cpp Trace.cpp)
+set(ANKI_CORE_SOURCES App.cpp StdinListener.cpp Config.cpp Trace.cpp)
 
 if(${ANKI_WINDOW_BACKEND} STREQUAL "GLXX11")
 	set(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowGlxX11.cpp)

+ 0 - 292
src/core/Counters.cpp

@@ -1,292 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <anki/Config.h>
-
-#if ANKI_ENABLE_COUNTERS
-
-#include <anki/core/Counters.h>
-#include <anki/core/App.h>
-#include <anki/util/Array.h>
-#include <cstring>
-
-namespace anki {
-
-//==============================================================================
-
-enum CounterFlag
-{
-	CF_PER_FRAME = 1 << 0,
-	CF_PER_RUN = 1 << 1,
-	CF_FPS = 1 << 2, ///< Only with CF_PER_RUN
-	CF_F64 = 1 << 3,
-	CF_U64 = 1 << 4
-};
-
-struct CounterInfo
-{
-	const char* m_name;
-	U32 m_flags;
-};
-
-static const Array<CounterInfo, U(Counter::COUNT)> cinfo = {{
-	{"FPS", CF_PER_RUN | CF_FPS | CF_F64},
-	{"MAIN_RENDERER_TIME", CF_PER_FRAME | CF_PER_RUN | CF_F64},
-	{"RENDERER_MS_TIME", CF_PER_FRAME | CF_PER_RUN | CF_F64},
-	{"RENDERER_IS_TIME", CF_PER_FRAME | CF_PER_RUN | CF_F64},
-	{"RENDERER_PPS_TIME", CF_PER_FRAME | CF_PER_RUN | CF_F64},
-	{"RENDERER_SHADOW_PASSES", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"RENDERER_LIGHTS_COUNT", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"RENDERER_MERGED_DRAWCALLS", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"SCENE_UPDATE_TIME", CF_PER_RUN | CF_F64},
-	{"SWAP_BUFFERS_TIME", CF_PER_RUN | CF_F64},
-	{"GL_CLIENT_WAIT_TIME", CF_PER_FRAME | CF_PER_RUN | CF_F64},
-	{"GL_SERVER_WAIT_TIME", CF_PER_FRAME | CF_PER_RUN | CF_F64},
-	{"GL_DRAWCALLS_COUNT", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"GL_VERTICES_COUNT", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"GL_QUEUES_SIZE", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"GL_CLIENT_BUFFERS_SIZE", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"GR_DYNAMIC_UNIFORMS_SIZE", CF_PER_FRAME | CF_PER_RUN | CF_U64},
-	{"GR_DYNAMIC_STORAGE_SIZE", CF_PER_FRAME | CF_PER_RUN | CF_U64}
-}};
-
-#define MAX_NAME "25"
-
-//==============================================================================
-Error CountersManager::create(
-	HeapAllocator<U8> alloc, const CString& cacheDir,
-	const Timestamp* globalTimestamp)
-{
-	m_globalTimestamp = globalTimestamp;
-
-	U count = static_cast<U>(Counter::COUNT);
-	m_alloc = alloc;
-
-	m_perframeValues.create(m_alloc, count);
-
-	m_perrunValues.create(m_alloc, count);
-
-	m_counterTimes.create(m_alloc, count);
-
-	memset(&m_perframeValues[0], 0, m_perframeValues.getByteSize());
-	memset(&m_perrunValues[0], 0, m_perrunValues.getByteSize());
-	memset(&m_counterTimes[0], 0, m_counterTimes.getByteSize());
-
-	// Open and write the headers to the files
-	StringAuto tmp(alloc);
-	tmp.sprintf("%s/frame_counters.csv", &cacheDir[0]);
-
-	ANKI_CHECK(m_perframeFile.open(tmp.toCString(), File::OpenFlag::WRITE));
-
-	ANKI_CHECK(m_perframeFile.writeText("FRAME"));
-
-	for(const CounterInfo& inf : cinfo)
-	{
-		if(inf.m_flags & CF_PER_FRAME)
-		{
-			ANKI_CHECK(m_perframeFile.writeText(", %s", inf.m_name));
-		}
-	}
-
-	// Open and write the headers to the other file
-	tmp.destroy(alloc);
-	tmp.sprintf("%s/run_counters.csv", &cacheDir[0]);
-
-	ANKI_CHECK(m_perrunFile.open(tmp.toCString(), File::OpenFlag::WRITE));
-
-	U i = 0;
-	for(const CounterInfo& inf : cinfo)
-	{
-		if(inf.m_flags & CF_PER_RUN)
-		{
-			if(i != 0)
-			{
-				ANKI_CHECK(
-					m_perrunFile.writeText(", %" MAX_NAME "s", inf.m_name));
-			}
-			else
-			{
-				ANKI_CHECK(
-					m_perrunFile.writeText("%" MAX_NAME "s", inf.m_name));
-			}
-
-			++i;
-		}
-	}
-	ANKI_CHECK(m_perrunFile.writeText("\n"));
-
-	return ErrorCode::NONE;
-}
-
-//==============================================================================
-CountersManager::~CountersManager()
-{
-	m_perframeValues.destroy(m_alloc);
-	m_perrunValues.destroy(m_alloc);
-	m_counterTimes.destroy(m_alloc);
-}
-
-//==============================================================================
-void CountersManager::increaseCounter(Counter counter, U64 val)
-{
-	ANKI_ASSERT(cinfo[U(counter)].m_flags & CF_U64);
-
-	if(cinfo[U(counter)].m_flags & CF_PER_FRAME)
-	{
-		m_perframeValues[U(counter)].m_int += val;
-	}
-
-	if(cinfo[U(counter)].m_flags & CF_PER_RUN)
-	{
-		m_perrunValues[U(counter)].m_int += val;
-	}
-}
-
-//==============================================================================
-void CountersManager::increaseCounter(Counter counter, F64 val)
-{
-	ANKI_ASSERT(cinfo[U(counter)].m_flags & CF_F64);
-
-	if(cinfo[U(counter)].m_flags & CF_PER_FRAME)
-	{
-		m_perframeValues[U(counter)].m_float += val;
-	}
-
-	if(cinfo[U(counter)].m_flags & CF_PER_RUN)
-	{
-		m_perrunValues[U(counter)].m_float += val;
-	}
-}
-
-//==============================================================================
-void CountersManager::startTimer(Counter counter)
-{
-	// The counter should be F64
-	ANKI_ASSERT(cinfo[U(counter)].m_flags & CF_F64);
-	// The timer should have been reseted
-	ANKI_ASSERT(m_counterTimes[U(counter)] == 0.0);
-
-	m_counterTimes[U(counter)] = HighRezTimer::getCurrentTime();
-}
-
-//==============================================================================
-void CountersManager::stopTimerIncreaseCounter(Counter counter)
-{
-	// The counter should be F64
-	ANKI_ASSERT(cinfo[U(counter)].m_flags & CF_F64);
-	// The timer should have started
-	ANKI_ASSERT(m_counterTimes[U(counter)] > 0.0);
-
-	auto prevTime = m_counterTimes[U(counter)];
-	m_counterTimes[U(counter)] = 0.0;
-
-	increaseCounter(
-		counter, (HighRezTimer::getCurrentTime() - prevTime) * 1000.0);
-}
-
-//==============================================================================
-void CountersManager::resolveFrame()
-{
-	Error err = ErrorCode::NONE;
-
-	// Write new line and frame no
-	err = m_perframeFile.writeText("\n%llu", *m_globalTimestamp);
-
-	U i = 0;
-	for(const CounterInfo& inf : cinfo)
-	{
-		if(inf.m_flags & CF_PER_FRAME)
-		{
-			if(inf.m_flags & CF_U64)
-			{
-				err = m_perframeFile.writeText(
-					", %llu", m_perframeValues[i].m_int);
-			}
-			else if(inf.m_flags & CF_F64)
-			{
-				err = m_perframeFile.writeText(
-					", %f", m_perframeValues[i].m_float);
-			}
-			else
-			{
-				ANKI_ASSERT(0);
-			}
-
-			m_perframeValues[i].m_int = 0;
-		}
-
-		i++;
-	}
-
-	(void)err;
-}
-
-//==============================================================================
-void CountersManager::flush()
-{
-	Error err = ErrorCode::NONE;
-
-	// Resolve per run counters
-	U i = 0;
-	U j = 0;
-	for(const CounterInfo& inf : cinfo)
-	{
-		if(inf.m_flags & CF_PER_RUN)
-		{
-			if(j != 0)
-			{
-				err = m_perrunFile.writeText(", ");
-			}
-
-			if(inf.m_flags & CF_U64)
-			{
-				err = m_perrunFile.writeText(
-					"%" MAX_NAME "llu", m_perrunValues[i].m_int);
-			}
-			else if(inf.m_flags & CF_F64)
-			{
-				if(inf.m_flags & CF_FPS)
-				{
-					F32 fps =
-						(F64)(*m_globalTimestamp)
-						/ (m_perrunValues[i].m_float / 1000.0);
-
-					err = m_perrunFile.writeText("%" MAX_NAME "f", fps);
-				}
-				else
-				{
-					err = m_perrunFile.writeText("%" MAX_NAME "f",
-						m_perrunValues[i].m_float);
-				}
-			}
-			else
-			{
-				ANKI_ASSERT(0);
-			}
-
-			m_perrunValues[i].m_int = 0;
-			++j;
-		}
-
-		++i;
-	}
-	err = m_perrunFile.writeText("\n");
-
-	// Close and flush files
-	m_perframeFile.close();
-	m_perrunFile.close();
-
-	if(err)
-	{
-		ANKI_LOGE("Error in counters file");
-	}
-}
-
-} // end namespace anki
-
-#undef MAX_NAME
-
-#endif // ANKI_ENABLE_COUNTERS
-

+ 5 - 8
src/core/NativeWindowSdl.cpp

@@ -4,14 +4,13 @@
 // http://www.anki3d.org/LICENSE
 
 #include <anki/core/NativeWindowSdl.h>
-#include <anki/core/Counters.h>
 #include <anki/util/Logger.h>
 #include <GL/glew.h>
 
 namespace anki {
 
-const U32 INIT_SUBSYSTEMS = 
-	SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS 
+const U32 INIT_SUBSYSTEMS =
+	SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS
 	| SDL_INIT_GAMECONTROLLER;
 
 //==============================================================================
@@ -25,11 +24,11 @@ Error NativeWindow::create(Initializer& init, HeapAllocator<U8>& alloc)
 		ANKI_LOGE("SDL_Init() failed");
 		return ErrorCode::FUNCTION_FAILED;
 	}
-	
+
 	//
 	// Set GL attributes
 	//
-	ANKI_LOGI("Creating SDL window (OpenGL context to be requested %u.%u)...", 
+	ANKI_LOGI("Creating SDL window (OpenGL context to be requested %u.%u)...",
 		init.m_majorVersion, init.m_minorVersion);
 
 	if(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, init.m_rgbaBits[0]) != 0
@@ -71,7 +70,7 @@ Error NativeWindow::create(Initializer& init, HeapAllocator<U8>& alloc)
 
 	m_impl->m_window = SDL_CreateWindow(
     	init.m_title,
-		SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
+		SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
 		init.m_width, init.m_height, flags);
 
 	if(m_impl->m_window == nullptr)
@@ -146,10 +145,8 @@ void NativeWindow::destroy()
 //==============================================================================
 void NativeWindow::swapBuffers()
 {
-	ANKI_COUNTER_START_TIMER(SWAP_BUFFERS_TIME);
 	ANKI_ASSERT(isCreated());
 	SDL_GL_SwapWindow(m_impl->m_window);
-	ANKI_COUNTER_STOP_TIMER_INC(SWAP_BUFFERS_TIME);
 }
 
 //==============================================================================

+ 94 - 38
src/core/Trace.cpp

@@ -5,6 +5,8 @@
 
 #include <anki/core/Trace.h>
 
+#if ANKI_ENABLE_TRACE
+
 namespace anki {
 
 //==============================================================================
@@ -25,14 +27,18 @@ static Array<const char*, U(TraceEventType::COUNT)> eventNames = {{
 	"RENDER_SM",
 	"RENDER_DRAWER",
 	"GL_THREAD",
-	"SWAP_BUFFERS",
-	"IDLE"
+	"SWAP_BUFFERS"
 }};
 
 static Array<const char*, U(TraceCounterType::COUNT)> counterNames = {{
 	"GR_DRAWCALLS",
-	"GR_DYNAMIC_UNIFORMS_SIZE"
-	"RENDERER_LIGHT_COUNT",
+	"GR_DYNAMIC_UNIFORMS_SIZE",
+	"GR_DYNAMIC_STORAGE_SIZE",
+	"GR_VERTICES",
+	"RENDERER_LIGHTS",
+	"RENDERER_SHADOW_PASSES",
+	"RENDERER_MERGED_DRAWCALLS",
+	"SCENE_NODES_UPDATED"
 }};
 
 #define ANKI_TRACE_FILE_ERROR() \
@@ -51,11 +57,11 @@ thread_local I g_traceEventsInFlight = 0;
 //==============================================================================
 TraceManager::~TraceManager()
 {
-	if(m_file.isOpen())
+	if(m_traceFile.isOpen())
 	{
-		Error err = m_file.writeText("{\"name\": \"dummy\", \"cat\": \"PERF\", "
-			"\"ph\": \"X\", \"pid\": 666, \"tid\": %llu, \"ts\": 0, "
-			"\"dur\": 1}]}", Thread::getCurrentThreadId());
+		Error err = m_traceFile.writeText("{\"name\": \"dummy\", "
+			"\"cat\": \"PERF\", \"ph\": \"X\", \"pid\": 666, \"tid\": %llu, "
+			"\"ts\": 0, \"dur\": 1}]}", Thread::getCurrentThreadId());
 
 		ANKI_TRACE_FILE_ERROR();
 	}
@@ -64,16 +70,35 @@ TraceManager::~TraceManager()
 //==============================================================================
 Error TraceManager::create(HeapAllocator<U8> alloc, const CString& cacheDir)
 {
-	// Open and write some stuff to the file
+	// Create trace file
 	StringAuto fname(alloc);
 	fname.sprintf("%s/trace.json", &cacheDir[0]);
 
-	ANKI_CHECK(m_file.open(fname.toCString(), File::OpenFlag::WRITE));
-	ANKI_CHECK(m_file.writeText(
+	ANKI_CHECK(m_traceFile.open(fname.toCString(), File::OpenFlag::WRITE));
+	ANKI_CHECK(m_traceFile.writeText(
 		"{\n"
 		"\"displayTimeUnit\": \"ms\",\n"
 		"\"traceEvents\": [\n"));
 
+	// Create per frame file
+	StringAuto perFrameFname(alloc);
+	perFrameFname.sprintf("%s/per_frame.csv", &cacheDir[0]);
+	ANKI_CHECK(m_perFrameFile.open(perFrameFname.toCString(),
+		File::OpenFlag::WRITE));
+
+	ANKI_CHECK(m_perFrameFile.writeText("FPS, "));
+	for(U i = 0; i < U(TraceCounterType::COUNT); ++i)
+	{
+		ANKI_CHECK(m_perFrameFile.writeText("%s, ", counterNames[i]));
+	}
+
+	for(U i = 0; i < U(TraceEventType::COUNT); ++i)
+	{
+		const char* fmt =
+			(i < U(TraceEventType::COUNT) - 1) ? "%s, " : "%s\n";
+		ANKI_CHECK(m_perFrameFile.writeText(fmt, eventNames[i]));
+	}
+
 	return ErrorCode::NONE;
 }
 
@@ -82,7 +107,7 @@ void TraceManager::startEvent()
 {
 	I i = ++g_traceEventsInFlight;
 	--i;
-	ANKI_ASSERT(i > 0 && <= MAX_EVENTS_DEPTH);
+	ANKI_ASSERT(i >= 0 && i <= I(MAX_EVENTS_DEPTH));
 
 	g_traceEventStartTime[i] = HighRezTimer::getCurrentTime();
 }
@@ -91,56 +116,60 @@ void TraceManager::startEvent()
 void TraceManager::stopEvent(TraceEventType type)
 {
 	I i = --g_traceEventsInFlight;
-	ANKI_ASSERT(i >= 0 && < MAX_EVENTS_DEPTH);
+	ANKI_ASSERT(i >= 0 && i < I(MAX_EVENTS_DEPTH));
 	auto startedTime = g_traceEventStartTime[i];
 
 	U id = m_count.fetchAdd(1);
 	if(id < BUFFERED_ENTRIES)
 	{
 		auto now = HighRezTimer::getCurrentTime();
-		m_entries[id] = Entry{type, startedTime, now - startedTime,
+		auto dur = now - startedTime;
+
+		m_entries[id] = Entry{type, startedTime, dur,
 			Thread::getCurrentThreadId()};
+
+		m_perFrameCounters[U(TraceCounterType::COUNT) + U(type)].fetchAdd(
+			U64(dur * 1000000000.0));
 	}
 	else
 	{
 		ANKI_LOGW("Increase the buffered trace entries");
+		m_perFrameCounters[U(TraceCounterType::COUNT) + U(type)].fetchAdd(0);
 	}
 }
 
 //==============================================================================
-void TraceManager::flushCounters()
+Error TraceManager::flushCounters()
 {
+	// Write the FPS counter
+	HighRezTimer::Scalar now = HighRezTimer::getCurrentTime();
+	HighRezTimer::Scalar time = now - m_startFrameTime;
+	F32 fps = 1.0 / time;
+	ANKI_CHECK(m_traceFile.writeText(
+		"{\"name\": \"FPS\", \"cat\": \"PERF\", \"ph\": \"C\", "
+		"\"pid\": 666, \"ts\": %llu, \"args\": {\"val\": %f}},\n",
+		U64(m_startFrameTime * 1000000.0), fps));
+
+	ANKI_CHECK(m_perFrameFile.writeText("%f, ", fps));
+
 	for(U i = 0; i < U(TraceCounterType::COUNT); ++i)
 	{
-		auto count =
-			m_perFrameCounters[U(TraceEventType::COUNT) + i].exchange(0);
+		auto count = m_perFrameCounters[i].exchange(0);
 
-
-		Error err = m_file.writeText(
+		ANKI_CHECK(m_traceFile.writeText(
 			"{\"name\": \"%s\", \"cat\": \"PERF\", \"ph\": \"C\", "
 			"\"pid\": 666, \"ts\": %llu, \"args\": {\"val\": %llu}},\n",
-			counterNames[i], U64(m_startFrameTime * 1000000.0), count);
+			counterNames[i], U64(m_startFrameTime * 1000000.0), count));
 
-		ANKI_TRACE_FILE_ERROR();
+		ANKI_CHECK(m_perFrameFile.writeText("%llu, ", count));
 	}
+
+	return ErrorCode::NONE;
 }
 
 //==============================================================================
-void TraceManager::stopFrame()
+Error TraceManager::flushEvents()
 {
-	flushCounters();
-
-	// Write the FPS counter
-	HighRezTimer::Scalar now = HighRezTimer::getCurrentTime();
-	HighRezTimer::Scalar time = now - m_startFrameTime;
-	F32 fps = 1.0 / time;
-	Error err = m_file.writeText(
-		"{\"name\": \"FPS\", \"cat\": \"PERF\", \"ph\": \"C\", "
-		"\"pid\": 666, \"ts\": %llu, \"args\": {\"val\": %f}},\n",
-		U64(m_startFrameTime * 1000000.0), fps);
-
-	ANKI_TRACE_FILE_ERROR();
-
 	// Write the events
 	U count = m_count.exchange(0);
 	count = min<U>(count, BUFFERED_ENTRIES);
@@ -149,14 +178,41 @@ void TraceManager::stopFrame()
 	{
 		const Entry& e = m_entries[i];
 
-		Error err = m_file.writeText(
+		ANKI_CHECK(m_traceFile.writeText(
 			"{\"name\": \"%s\", \"cat\": \"PERF\", \"ph\": \"X\", "
 			"\"pid\": 666, \"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));
+			U64(e.m_duration * 1000000.0)));
+	}
 
-		ANKI_TRACE_FILE_ERROR();
+	for(U i = 0; i < U(TraceEventType::COUNT); ++i)
+	{
+		const char* fmt =
+			(i < U(TraceEventType::COUNT) - 1) ? "%f, " : "%f\n";
+		U64 ns = m_perFrameCounters[
+			i + U(TraceCounterType::COUNT)].exchange(0);
+		ANKI_CHECK(m_perFrameFile.writeText(fmt, F64(ns) / 1000000.0));
+	}
+
+	return ErrorCode::NONE;
+}
+
+//==============================================================================
+void TraceManager::stopFrame()
+{
+	Error err = flushCounters();
+
+	if(!err)
+	{
+		err = flushEvents();
+	}
+
+	if(err)
+	{
+		ANKI_LOGE("Error writing the trace file");
 	}
 }
 
 } // end namespace anki
+
+#endif

+ 2 - 5
src/gr/gl/CommandBuffer.cpp

@@ -20,7 +20,6 @@
 #include <anki/gr/gl/TextureImpl.h>
 #include <anki/gr/Buffer.h>
 #include <anki/gr/gl/BufferImpl.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 
 namespace anki {
@@ -214,9 +213,8 @@ public:
 				m_info.m_baseInstance);
 
 			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
-			ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, U64(1));
-			ANKI_COUNTER_INC(GL_VERTICES_COUNT,
-				U64(m_info.m_instanceCount * m_info.m_count));
+			ANKI_TRACE_INC_COUNTER(GR_VERTICES,
+				m_info.m_instanceCount * m_info.m_count);
 		}
 
 		return ErrorCode::NONE;
@@ -258,7 +256,6 @@ public:
 				m_info.m_baseInstance);
 
 			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
-			ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, U64(1));
 		}
 
 		return ErrorCode::NONE;

+ 0 - 4
src/gr/gl/CommandBufferImpl.cpp

@@ -9,7 +9,6 @@
 #include <anki/gr/gl/RenderingThread.h>
 #include <anki/gr/gl/Error.h>
 #include <anki/util/Logger.h>
-#include <anki/core/Counters.h>
 #include <cstring>
 
 namespace anki {
@@ -84,9 +83,6 @@ CommandBufferImpl::InitHints CommandBufferImpl::computeInitHints() const
 	InitHints out;
 	out.m_chunkSize = m_alloc.getMemoryPool().getAllocatedSize() + 16;
 
-	ANKI_COUNTER_INC(GL_QUEUES_SIZE,
-		U64(m_alloc.getMemoryPool().getAllocatedSize()));
-
 	return out;
 }
 

+ 1 - 3
src/gr/gl/GlState.cpp

@@ -7,7 +7,6 @@
 #include <anki/gr/gl/BufferImpl.h>
 #include <anki/gr/GrManager.h>
 #include <anki/util/Logger.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 #include <anki/misc/ConfigSet.h>
 #include <algorithm>
@@ -222,11 +221,10 @@ void GlState::checkDynamicMemoryConsumption()
 			switch(usage)
 			{
 			case BufferUsage::UNIFORM:
-				ANKI_COUNTER_INC(GR_DYNAMIC_UNIFORMS_SIZE, U64(bytesUsed));
 				ANKI_TRACE_INC_COUNTER(GR_DYNAMIC_UNIFORMS_SIZE, bytesUsed);
 				break;
 			case BufferUsage::STORAGE:
-				ANKI_COUNTER_INC(GR_DYNAMIC_STORAGE_SIZE, U64(bytesUsed));
+				ANKI_TRACE_INC_COUNTER(GR_DYNAMIC_STORAGE_SIZE, bytesUsed);
 				break;
 			default:
 				break;

+ 0 - 3
src/gr/gl/RenderingThread.cpp

@@ -8,7 +8,6 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/util/Logger.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 
 namespace anki {
@@ -318,9 +317,7 @@ void RenderingThread::swapBuffers()
 		LockGuard<Mutex> lock(m_frameMtx);
 		while(m_frameWait)
 		{
-			ANKI_COUNTER_START_TIMER(GL_SERVER_WAIT_TIME);
 			m_frameCondVar.wait(m_frameMtx);
-			ANKI_COUNTER_STOP_TIMER_INC(GL_SERVER_WAIT_TIME);
 		}
 
 		m_frameWait = true;

+ 2 - 2
src/renderer/Drawer.cpp

@@ -13,7 +13,6 @@
 #include <anki/scene/SceneGraph.h>
 #include <anki/resource/TextureResource.h>
 #include <anki/renderer/Renderer.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 #include <anki/util/Logger.h>
 #include <anki/util/Thread.h>
@@ -402,7 +401,8 @@ Error RenderableDrawer::renderSingle(RenderContext& ctx)
 	// Rendered something, reset the cached transforms
 	if(ctx.m_cachedTrfCount > 1)
 	{
-		ANKI_COUNTER_INC(RENDERER_MERGED_DRAWCALLS, ctx.m_cachedTrfCount - 1);
+		ANKI_TRACE_INC_COUNTER(RENDERER_MERGED_DRAWCALLS,
+			ctx.m_cachedTrfCount - 1);
 	}
 	ctx.m_cachedTrfCount = 0;
 

+ 2 - 5
src/renderer/Is.cpp

@@ -11,7 +11,6 @@
 #include <anki/scene/Camera.h>
 #include <anki/scene/Light.h>
 #include <anki/scene/Visibility.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 #include <anki/util/Logger.h>
 #include <anki/misc/ConfigSet.h>
@@ -390,10 +389,8 @@ Error Is::lightPass(CommandBufferPtr& cmdb)
 	visiblePointLightsCount = min<U>(visiblePointLightsCount, m_maxPointLights);
 	visibleSpotLightsCount = min<U>(visibleSpotLightsCount, m_maxSpotLights);
 
-	ANKI_COUNTER_INC(RENDERER_LIGHTS_COUNT,
-		U64(visiblePointLightsCount + visibleSpotLightsCount));
-	ANKI_TRACE_INC_COUNTER(RENDERER_LIGHT_COUNT,
-		U64(visiblePointLightsCount + visibleSpotLightsCount));
+	ANKI_TRACE_INC_COUNTER(RENDERER_LIGHTS,
+		visiblePointLightsCount + visibleSpotLightsCount);
 
 	//
 	// Do shadows pass

+ 0 - 3
src/renderer/MainRenderer.cpp

@@ -15,7 +15,6 @@
 #include <anki/util/Logger.h>
 #include <anki/util/File.h>
 #include <anki/util/Filesystem.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 #include <anki/core/App.h>
 #include <anki/misc/ConfigSet.h>
@@ -106,7 +105,6 @@ Error MainRenderer::create(
 //==============================================================================
 Error MainRenderer::render(SceneGraph& scene)
 {
-	ANKI_COUNTER_START_TIMER(MAIN_RENDERER_TIME);
 	ANKI_TRACE_START_EVENT(RENDER);
 
 	GrManager& gl = m_r->getGrManager();
@@ -166,7 +164,6 @@ Error MainRenderer::render(SceneGraph& scene)
 		m_cbInitHints[i] = cmdbs[i]->computeInitHints();
 	}
 
-	ANKI_COUNTER_STOP_TIMER_INC(MAIN_RENDERER_TIME);
 	ANKI_TRACE_STOP_EVENT(RENDER);
 
 	return ErrorCode::NONE;

+ 0 - 7
src/renderer/Renderer.cpp

@@ -6,7 +6,6 @@
 #include <anki/renderer/Renderer.h>
 #include <anki/scene/Camera.h>
 #include <anki/scene/SceneGraph.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 #include <anki/misc/ConfigSet.h>
 
@@ -174,11 +173,9 @@ Error Renderer::render(SceneNode& frustumableNode, U frustumIdx,
 		ANKI_CHECK(m_ir->run(cmdb[0]));
 	}
 
-	ANKI_COUNTER_START_TIMER(RENDERER_MS_TIME);
 	ANKI_TRACE_START_EVENT(RENDER_MS);
 	ANKI_CHECK(m_ms->run(cmdb[0]));
 	ANKI_TRACE_STOP_EVENT(RENDER_MS);
-	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_MS_TIME);
 
 	m_lf->runOcclusionTests(cmdb[0]);
 
@@ -186,19 +183,15 @@ Error Renderer::render(SceneNode& frustumableNode, U frustumIdx,
 
 	m_tiler->run(cmdb[0]);
 
-	ANKI_COUNTER_START_TIMER(RENDERER_IS_TIME);
 	ANKI_CHECK(m_is->run(cmdb[1]));
-	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_IS_TIME);
 
 	ANKI_CHECK(m_fs->run(cmdb[1]));
 	m_lf->run(cmdb[1]);
 
-	ANKI_COUNTER_START_TIMER(RENDERER_PPS_TIME);
 	if(m_pps->getEnabled())
 	{
 		m_pps->run(cmdb[1]);
 	}
-	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_PPS_TIME);
 
 	if(m_dbg->getEnabled())
 	{

+ 2 - 3
src/renderer/Sm.cpp

@@ -6,7 +6,6 @@
 #include <anki/renderer/Sm.h>
 #include <anki/renderer/Renderer.h>
 #include <anki/core/App.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 #include <anki/scene/SceneGraph.h>
 #include <anki/scene/Camera.h>
@@ -221,7 +220,7 @@ Error Sm::doSpotLight(SceneNode& light, CommandBufferPtr& cmdBuff)
 	ANKI_CHECK(m_r->getSceneDrawer().render(
 		fr, RenderingStage::MATERIAL, Pass::SM, cmdbs));
 
-	ANKI_COUNTER_INC(RENDERER_SHADOW_PASSES, U64(1));
+	ANKI_TRACE_INC_COUNTER(RENDERER_SHADOW_PASSES, 1);
 	return ErrorCode::NONE;
 }
 
@@ -252,7 +251,7 @@ Error Sm::doOmniLight(SceneNode& light, CommandBufferPtr& cmdBuff)
 		return ErrorCode::NONE;
 	});
 
-	ANKI_COUNTER_INC(RENDERER_SHADOW_PASSES, U64(6));
+	ANKI_TRACE_INC_COUNTER(RENDERER_SHADOW_PASSES, 6);
 
 	return err;
 }

+ 46 - 15
src/scene/SceneGraph.cpp

@@ -7,7 +7,6 @@
 #include <anki/scene/Camera.h>
 #include <anki/scene/ModelNode.h>
 #include <anki/scene/Sector.h>
-#include <anki/core/Counters.h>
 #include <anki/core/Trace.h>
 #include <anki/physics/PhysicsWorld.h>
 #include <anki/resource/ResourceManager.h>
@@ -30,25 +29,55 @@ public:
 	F32 m_prevUpdateTime;
 	F32 m_crntTime;
 
+	ListAllocFree<SceneNode>::Iterator* m_crntNode;
+	SpinLock* m_crntNodeLock;
+	ListAllocFree<SceneNode>::Iterator m_nodesEnd;
+
 	Error operator()(U32 taskId, PtrSize threadsCount)
 	{
 		ANKI_TRACE_START_EVENT(SCENE_NODES_UPDATE);
-		PtrSize start, end;
-		choseStartEnd(
-			taskId, threadsCount, m_scene->getSceneNodesCount(), start, end);
 
-		// Start with the root nodes
-		Error err = m_scene->iterateSceneNodes(
-			start, end, [&](SceneNode& node) -> Error
+		ListAllocFree<SceneNode>::Iterator& it = *m_crntNode;
+		SpinLock& lock = *m_crntNodeLock;
+
+		Bool quit = false;
+		Error err = ErrorCode::NONE;
+		while(!quit && !err)
 		{
-			Error err = ErrorCode::NONE;
-			if(node.getParent() == nullptr)
+			// Fetch a few scene nodes
+			Array<SceneNode*, 5> nodes = {{nullptr, }};
+			lock.lock();
+			for(SceneNode*& node : nodes)
 			{
-				err = updateInternal(node, m_prevUpdateTime, m_crntTime);
+				if(it != m_nodesEnd)
+				{
+					node = &(*it);
+					++it;
+				}
 			}
+			lock.unlock();
 
-			return err;
-		});
+			// Process nodes
+			U count = 0;
+			for(U i = 0; i < nodes.getSize(); ++i)
+			{
+				if(nodes[i])
+				{
+					if(nodes[i]->getParent() == nullptr)
+					{
+						err = updateInternal(
+							*nodes[i], m_prevUpdateTime, m_crntTime);
+						ANKI_TRACE_INC_COUNTER(SCENE_NODES_UPDATED, 1);
+					}
+					++count;
+				}
+			}
+
+			if(ANKI_UNLIKELY(count == 0))
+			{
+				quit = true;
+			}
+		}
 
 		ANKI_TRACE_STOP_EVENT(SCENE_NODES_UPDATE);
 		return err;
@@ -262,8 +291,6 @@ Error SceneGraph::update(F32 prevUpdateTime, F32 crntTime,
 
 	m_timestamp = *m_globalTimestamp;
 
-	ANKI_COUNTER_START_TIMER(SCENE_UPDATE_TIME);
-
 	// Reset the framepool
 	m_frameAlloc.getMemoryPool().reset();
 
@@ -287,6 +314,8 @@ Error SceneGraph::update(F32 prevUpdateTime, F32 crntTime,
 
 	// Then the rest
 	Array<UpdateSceneNodesTask, ThreadPool::MAX_THREADS> jobs2;
+	ListAllocFree<SceneNode>::Iterator nodeIt = m_nodes.getBegin();
+	SpinLock nodeItLock;
 
 	for(U i = 0; i < threadPool.getThreadsCount(); i++)
 	{
@@ -295,6 +324,9 @@ Error SceneGraph::update(F32 prevUpdateTime, F32 crntTime,
 		job.m_scene = this;
 		job.m_prevUpdateTime = prevUpdateTime;
 		job.m_crntTime = crntTime;
+		job.m_crntNode = &nodeIt;
+		job.m_crntNodeLock = &nodeItLock;
+		job.m_nodesEnd = m_nodes.getEnd();
 
 		threadPool.assignNewTask(i, &job);
 	}
@@ -309,7 +341,6 @@ Error SceneGraph::update(F32 prevUpdateTime, F32 crntTime,
 		renderer.getOffscreenRenderer()));
 	ANKI_TRACE_STOP_EVENT(SCENE_VISIBILITY_TESTS);
 
-	ANKI_COUNTER_STOP_TIMER_INC(SCENE_UPDATE_TIME);
 	ANKI_TRACE_STOP_EVENT(SCENE_UPDATE);
 	return ErrorCode::NONE;
 }

+ 27 - 23
src/util/ThreadPosix.cpp

@@ -128,7 +128,7 @@ Thread::Id Thread::getCurrentThreadId()
 //==============================================================================
 Mutex::Mutex()
 {
-	pthread_mutex_t* mtx = 
+	pthread_mutex_t* mtx =
 		reinterpret_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t)));
 	if(mtx == nullptr)
 	{
@@ -198,7 +198,7 @@ void Mutex::unlock()
 //==============================================================================
 ConditionVariable::ConditionVariable()
 {
-	pthread_cond_t* cond = 
+	pthread_cond_t* cond =
 		reinterpret_cast<pthread_cond_t*>(malloc(sizeof(pthread_cond_t)));
 	if(cond == nullptr)
 	{
@@ -260,54 +260,58 @@ void ConditionVariable::wait(Mutex& amtx)
 // Barrier                                                                     =
 //==============================================================================
 
+#define ANKI_BARR_GET() \
+	(*reinterpret_cast<pthread_barrier_t*>(&this->m_posixImpl[0]))
+
 //==============================================================================
 Barrier::Barrier(U32 count)
 {
+	static_assert(sizeof(m_posixImpl) >= sizeof(pthread_barrier_t),
+		"Wrong assumption");
+	static_assert(alignof(Barrier) >= alignof(pthread_barrier_t),
+		"Wrong assumption");
+
 	ANKI_ASSERT(count > 1);
 
-	pthread_barrier_t* barrier = 
-		reinterpret_cast<pthread_barrier_t*>(malloc(sizeof(pthread_barrier_t)));
-	if(barrier == nullptr)
+	pthread_barrierattr_t attr;
+	I err = pthread_barrierattr_init(&attr);
+	if(err)
 	{
-		ANKI_LOGF("Out of memory");
+		ANKI_LOGF("pthread_barrierattr_init() failed");
+	}
+
+	err = pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
+	if(err)
+	{
+		pthread_barrierattr_destroy(&attr);
+		ANKI_LOGF("pthread_barrierattr_setpshared() failed");
 	}
 
-	I err = pthread_barrier_init(barrier, nullptr, count);
+	err = pthread_barrier_init(&ANKI_BARR_GET(), &attr, count);
 	if(err)
 	{
-		free(barrier);
+		pthread_barrierattr_destroy(&attr);
 		ANKI_LOGF("pthread_barrier_init() failed");
 	}
 
-	m_impl = barrier;
+	pthread_barrierattr_destroy(&attr);
 }
 
 //==============================================================================
 Barrier::~Barrier()
 {
-	ANKI_ASSERT(m_impl);
-	pthread_barrier_t* barrier = reinterpret_cast<pthread_barrier_t*>(m_impl);
-
-	I err = pthread_barrier_destroy(barrier);
+	I err = pthread_barrier_destroy(&ANKI_BARR_GET());
 	if(err)
 	{
 		ANKI_LOGE("pthread_barrier_destroy() failed");
 	}
-
-	free(barrier);
-	m_impl = nullptr;
 }
 
 //==============================================================================
 Bool Barrier::wait()
 {
-	ANKI_ASSERT(m_impl);
-
-	pthread_barrier_t* barrier = 
-		reinterpret_cast<pthread_barrier_t*>(m_impl);
-
-	I err = pthread_barrier_wait(barrier);
-	if(err != PTHREAD_BARRIER_SERIAL_THREAD && err != 0)
+	I err = pthread_barrier_wait(&ANKI_BARR_GET());
+	if(ANKI_UNLIKELY(err != PTHREAD_BARRIER_SERIAL_THREAD && err != 0))
 	{
 		ANKI_LOGF("pthread_barrier_wait() failed");
 	}

+ 4 - 5
testapp/Main.cpp

@@ -28,7 +28,6 @@
 #include "anki/event/LightEvent.h"
 #include "anki/event/AnimationEvent.h"
 #include "anki/event/JitterMoveEvent.h"
-#include "anki/core/Counters.h"
 #include "anki/core/Config.h"
 #include "anki/physics/PhysicsWorld.h"
 #include "anki/scene/LensFlareComponent.h"
@@ -488,7 +487,7 @@ Error initSubsystems(int argc, char* argv[])
 	config.set("is.sm.poissonEnabled", true);
 	config.set("is.sm.resolution", 1024);
 	config.set("lf.maxFlares", 32);
-	config.set("pps.enabled", true);
+	config.set("pps.enabled", false);
 	config.set("pps.bloom.enabled", true);
 	config.set("pps.bloom.renderingQuality", 0.5);
 	config.set("pps.bloom.blurringDist", 1.0);
@@ -508,14 +507,14 @@ Error initSubsystems(int argc, char* argv[])
 	config.set("pps.sslf.enabled", true);
 	config.set("pps.sharpen", true);
 	config.set("renderingQuality", 1.0);
-	config.set("width", 1280);
-	config.set("height", 720);
+	config.set("width", 128);
+	config.set("height", 128);
 	config.set("lodDistance", 20.0);
 	config.set("samples", 1);
 	config.set("tessellation", true);
 	//config.set("maxTextureSize", 256);
 	config.set("ir.rendererSize", 64);
-	config.set("fullscreenDesktopResolution", true);
+	config.set("fullscreenDesktopResolution", false);
 	config.set("debugContext", false);
 	if(getenv("ANKI_DATA_PATH"))
 	{