Parcourir la source

counters for measuring optimizations

Panagiotis Christopoulos Charitos il y a 12 ans
Parent
commit
50a42f05f7

+ 20 - 3
include/anki/core/Counters.h

@@ -11,29 +11,46 @@ enum Counter
 	C_RENDERER_IS_TIME,
 	C_RENDERER_PPS_TIME,
 	C_RENDERER_DRAWCALLS_COUNT,
+	C_RENDERER_VERTICES_COUNT,
 	C_SCENE_UPDATE_TIME,
 	C_SWAP_BUFFERS_TIME,
 
 	C_COUNT
 };
 
-/// XXX
+/// The counters manager. It's been used with a singleton
 class CountersManager
 {
 public:
+	CountersManager();
+	~CountersManager();
+
 	void increaseCounter(Counter counter, F64 val);
 	void increaseCounter(Counter counter, U64 val);
 
-	/// Write the counters of the frame
+	/// 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();
+
 private:
 	File perframeFile;
+	File globalFile;
+	Vector<U64> counters;
 };
 
 /// The singleton of the counters manager
 typedef Singleton<CountersManager> CountersManagerSingleton;
 
-#define ANKI_COUNTER_INC(counter, val)
+#define ANKI_COUNTER_INC(counter_, val_) \
+	CountersManagerSingleton::get().increaseCounter(counter_, val_)
+
+#define ANKI_COUNTERS_RESOLVE_FRAME() \
+	CountersManagerSingleton::get().resolveFrame()
+
+#define ANKI_COUNTERS_FLUSH() \
+	CountersManagerSingleton::get().flush()
 
 } // end namespace anki

+ 6 - 0
include/anki/util/Filesystem.h

@@ -44,12 +44,18 @@ public:
 	/// Open a file
 	void open(const char* filename, U8 openMask);
 
+	/// Close the file
+	void close();
+
 	/// Read data from the file
 	PtrSize read(void* buff, PtrSize size);
 
 	/// Write data to the file
 	PtrSize write(void* buff, PtrSize size);
 
+	/// Wrtite text
+	void writeString(const char* format, ...);
+
 public:
 	U8 openFlags; ///< Mainly for assertions
 	void* file; ///< A native type

+ 1 - 1
src/core/CMakeLists.txt

@@ -1,4 +1,4 @@
-SET(ANKI_CORE_SOURCES App.cpp Async.cpp Logger.cpp StdinListener.cpp ThreadPool.cpp Timestamp.cpp)
+SET(ANKI_CORE_SOURCES App.cpp Async.cpp Logger.cpp StdinListener.cpp ThreadPool.cpp Timestamp.cpp Counters.cpp)
 
 IF(ANKI_WINDOW_BACKEND STREQUAL "GLXX11")
 	SET(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowGlxX11.cpp)

+ 81 - 2
src/core/Counters.cpp

@@ -1,4 +1,8 @@
 #include "anki/core/Counters.h"
+#include "anki/core/Timestamp.h"
+#include "anki/util/Filesystem.h"
+#include "anki/util/Array.h"
+#include <cstring>
 
 namespace anki {
 
@@ -18,13 +22,88 @@ struct CounterInfo
 	U32 flags;
 };
 
-static const CounterInfo counters[C_COUNT - 1] = {
+static const Array<CounterInfo, C_COUNT> cinfo = {{
 	{"C_RENDERER_MS_TIME", CF_PER_FRAME | CF_F64},
 	{"C_RENDERER_IS_TIME", CF_PER_FRAME | CF_F64},
 	{"C_RENDERER_PPS_TIME", CF_PER_FRAME | CF_F64},
 	{"C_RENDERER_DRAWCALLS_COUNT", CF_GLOBAL | CF_U64},
+	{"C_RENDERER_VERTICES_COUNT", CF_GLOBAL | CF_U64},
 	{"C_SCENE_UPDATE_TIME", CF_PER_FRAME | CF_F64},
 	{"C_SWAP_BUFFERS_TIME", CF_PER_FRAME | CF_F64}
-};
+}};
+
+//==============================================================================
+CountersManager::CountersManager()
+{
+	counters.resize(C_COUNT, 0);
+
+	// Open and write the headers to the files
+	perframeFile.open("./perframe_counters.csv", File::OF_WRITE);
+
+	perframeFile.writeString("FRAME");
+
+	for(const CounterInfo& inf : cinfo)
+	{
+		if(inf.flags & CF_PER_FRAME)
+		{
+			perframeFile.writeString(", %s", inf.name);
+		}
+	}
+}
+
+//==============================================================================
+CountersManager::~CountersManager()
+{}
+
+//==============================================================================
+void CountersManager::increaseCounter(Counter counter, F64 val)
+{
+	counters[counter] += val;
+}
+
+//==============================================================================
+void CountersManager::increaseCounter(Counter counter, U64 val)
+{
+	F64 f;
+	memcpy(&f, &val, sizeof(F64));
+	*(F64*)(&counters[counter]) += f;
+}
+
+//==============================================================================
+void CountersManager::resolveFrame()
+{
+	// Write new line and frame no
+	perframeFile.writeString("\n%llu", getGlobTimestamp());
+
+	U i = 0;
+	for(const CounterInfo& inf : cinfo)
+	{
+		if(inf.flags & CF_PER_FRAME)
+		{
+			if(inf.flags & CF_U64)
+			{
+				perframeFile.writeString(", %llu", counters[i]);
+			}
+			else if(inf.flags & CF_F64)
+			{
+				perframeFile.writeString(", %f", *((F64*)&counters[i]));
+			}
+			else
+			{
+				ANKI_ASSERT(0);
+			}
+
+			counters[i] = 0;
+		}
+
+		i++;
+	}
+}
+
+//==============================================================================
+void CountersManager::flush()
+{
+	perframeFile.close();
+}
 
 } // end namespace anki

+ 80 - 48
src/scene/Visibility.cpp

@@ -7,6 +7,31 @@
 
 namespace anki {
 
+//==============================================================================
+/// Sort spatial scene nodes on distance
+struct SortSubspatialsFunctor
+{
+	Vec3 origin; ///< The pos of the frustum
+	Spatial* sp;
+
+	Bool operator()(U32 a, U32 b)
+	{
+		ANKI_ASSERT(a != b 
+			&& a < sp->getSubSpatialsCount()
+			&& b < sp->getSubSpatialsCount());
+
+		const Spatial* spa = *(sp->getSubSpatialsBegin() + a);
+		const Spatial* spb = *(sp->getSubSpatialsBegin() + b);
+
+		F32 dist0 = origin.getDistanceSquared(
+			spa->getSpatialOrigin());
+		F32 dist1 = origin.getDistanceSquared(
+			spb->getSpatialOrigin());
+
+		return dist0 < dist1;
+	}
+};
+
 //==============================================================================
 struct VisibilityTestJob: ThreadJob
 {
@@ -14,10 +39,58 @@ struct VisibilityTestJob: ThreadJob
 	SceneGraph::Types<SceneNode>::Container::iterator nodes;
 	SceneNode* frustumableSn = nullptr;
 	Tiler* tiler = nullptr;
-	SceneAllocator<U8> frameAlloc;
+	SceneFrameAllocator<U8> frameAlloc;
 
 	VisibilityTestResults* visible;
 
+	/// Handle sub spatials
+	Bool handleSubspatials(
+		const Frustumable& fr,
+		Spatial& sp,
+		U32*& subSpatialIndices,
+		U32& subSpatialIndicesCount)
+	{
+		Bool fatherSpVisible = true;
+		subSpatialIndices = nullptr;
+		subSpatialIndicesCount = 0;
+
+		// Have subspatials?
+		if(sp.getSubSpatialsCount())
+		{
+			subSpatialIndices = ANKI_NEW_ARRAY_0(
+				U32, frameAlloc, sp.getSubSpatialsCount());
+
+			U i = 0;
+			for(auto it = sp.getSubSpatialsBegin();
+				it != sp.getSubSpatialsEnd(); ++it)
+			{
+				Spatial* subsp = *it;
+	
+				// Check
+				if(fr.insideFrustum(*subsp))
+				{
+					subSpatialIndices[subSpatialIndicesCount++] = i;
+					subsp->enableBits(Spatial::SF_VISIBLE_CAMERA);
+				}
+				++i;
+			}
+
+			// Sort them
+			SortSubspatialsFunctor functor;
+			functor.origin = fr.getFrustumableOrigin();
+			functor.sp = &sp;
+			std::sort(subSpatialIndices, 
+				subSpatialIndices + subSpatialIndicesCount,
+				functor);
+
+			// The subSpatialIndicesCount == 0 then the camera is looking 
+			// something in between all sub spatials
+			fatherSpVisible = subSpatialIndicesCount != 0;
+		}
+
+		return fatherSpVisible;
+	}
+
 	/// Do the tests
 	void operator()(U threadId, U threadsCount)
 	{
@@ -54,30 +127,10 @@ struct VisibilityTestJob: ThreadJob
 			// Hierarchical spatial => check subspatials
 			U32* subSpatialIndices = nullptr;
 			U32 subSpatialIndicesCount = 0;
-			if(sp->getSubSpatialsCount())
+			if(!handleSubspatials(*frustumable, *sp, subSpatialIndices, 
+				subSpatialIndicesCount))
 			{
-				subSpatialIndices = ANKI_NEW_ARRAY_0(
-					U32, frameAlloc, sp->getSubSpatialsCount());
-
-				U i = 0;
-				for(auto it = sp->getSubSpatialsBegin();
-					it != sp->getSubSpatialsEnd(); ++it)
-				{
-					Spatial* subsp = *it;
-		
-					if(frustumable->insideFrustum(*subsp))
-					{
-						subSpatialIndices[subSpatialIndicesCount++] = i;
-						subsp->enableBits(Spatial::SF_VISIBLE_CAMERA);
-					}
-					++i;
-				}
-
-				if(ANKI_UNLIKELY(subSpatialIndicesCount == 0))
-				{
-					// The camera is looking something in between all submeshes
-					continue;
-				}
+				continue;
 			}
 
 			// renderable
@@ -146,31 +199,10 @@ struct VisibilityTestJob: ThreadJob
 			// Hierarchical spatial => check subspatials
 			U32* subSpatialIndices = nullptr;
 			U32 subSpatialIndicesCount = 0;
-			if(sp->getSubSpatialsCount())
+			if(!handleSubspatials(ref, *sp, subSpatialIndices, 
+				subSpatialIndicesCount))
 			{
-				subSpatialIndices = ANKI_NEW_ARRAY_0(
-					U32, frameAlloc, sp->getSubSpatialsCount());
-
-				U i = 0;
-				for(auto it = sp->getSubSpatialsBegin();
-					it != sp->getSubSpatialsEnd(); ++it)
-				{
-					Spatial* subsp = *it;
-		
-					if(ref.insideFrustum(*subsp))
-					{
-						subSpatialIndices[subSpatialIndicesCount++] = i;
-						subsp->enableBits(Spatial::SF_VISIBLE_CAMERA);
-					}
-					++i;
-				}
-
-				if(ANKI_UNLIKELY(subSpatialIndicesCount == 0))
-				{
-					// The camera is looking something in between all 
-					// subspatials
-					continue;
-				}
+				continue;
 			}
 
 			sp->enableBits(Spatial::SF_VISIBLE_LIGHT);

+ 45 - 0
src/util/Filesystem.cpp

@@ -3,6 +3,7 @@
 #include "anki/util/Assert.h"
 #include <fstream>
 #include <cstring>
+#include <cstdarg>
 
 namespace anki {
 
@@ -62,6 +63,26 @@ void File::open(const char* filename, U8 flags)
 	fileType = FT_C;
 }
 
+//==============================================================================
+void File::close()
+{
+	ANKI_ASSERT(file);
+
+	switch(fileType)
+	{
+	case FT_C:
+		fclose((FILE*)file);
+		break;
+	case FT_ZIP:
+		ANKI_ASSERT(0 && "Not implemented");
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+
+	file = nullptr;
+}
+
 //==============================================================================
 PtrSize File::read(void* buff, PtrSize size)
 {
@@ -110,6 +131,30 @@ PtrSize File::write(void* buff, PtrSize size)
 	return writeSize;
 }
 
+//==============================================================================
+void File::writeString(const char* format, ...)
+{
+	ANKI_ASSERT(file);
+	ANKI_ASSERT(format);
+
+	va_list args;
+	va_start(args, format);
+
+	switch(fileType)
+	{
+	case FT_C:
+		vfprintf((FILE*)file, format, args);
+		break;
+	case FT_ZIP:
+		ANKI_ASSERT(0 && "Not implemented");
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+
+	va_end(args);
+}
+
 //==============================================================================
 // Functions                                                                   =
 //==============================================================================

+ 8 - 1
testapp/Main.cpp

@@ -30,6 +30,7 @@
 #include "anki/scene/Scene.h"
 #include "anki/event/LightEvent.h"
 #include "anki/event/MovableEvent.h"
+#include "anki/core/Counters.h"
 
 using namespace anki;
 
@@ -465,10 +466,11 @@ void mainLoop()
 		}
 
 		win->swapBuffers();
+		ANKI_COUNTERS_RESOLVE_FRAME();
 
 		// Sleep
 		//
-#if 0
+#if 1
 		timer.stop();
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		{
@@ -488,6 +490,8 @@ void mainLoop()
 	MainRendererSingleton::get().takeScreenshot("screenshot.tga");
 #endif
 
+	ANKI_COUNTERS_FLUSH();
+
 	HighRezTimer::Scalar timePassed = mainLoopTimer.getElapsedTime();
 	ANKI_LOGI("Exiting main loop (" << timePassed
 		<< " sec) FPS: " << 1000.0 / timePassed);
@@ -564,6 +568,9 @@ void initSubsystems(int argc, char* argv[])
 
 	// Parallel jobs
 	ThreadPoolSingleton::get().init(getCpuCoresCount());
+
+	// Init counters
+	CountersManagerSingleton::get();
 }
 
 //==============================================================================