Browse Source

Add memory consumption on stats. Fix a memory issue in the Vulkan backend

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
2842e4c177

+ 1 - 1
CMakeLists.txt

@@ -366,7 +366,7 @@ endif()
 
 # AnKi compiler flags (Mainly warnings)
 if(NOT MSVC)
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -W -Wextra -Wstrict-aliasing -Wwrite-strings -Wunused -Wunused-variable -Wno-unused-parameter -Wundef -Wno-ignored-attributes -Wunused-result -std=c++14")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -W -Wextra -Wstrict-aliasing -Wwrite-strings -Wunused -Wunused-variable -Wno-unused-parameter -Wundef -Wno-ignored-attributes -Wno-implicit-fallthrough -Wunused-result -std=c++14")
 else()
 	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996 /wd4244 /wd4262 /wd4267")
 endif()

+ 141 - 20
src/anki/core/App.cpp

@@ -74,6 +74,10 @@ public:
 	BufferedValue<Second> m_sceneUpdateTime;
 	BufferedValue<Second> m_visTestsTime;
 
+	PtrSize m_allocatedCpuMem = 0;
+	U64 m_allocCount = 0;
+	U64 m_freeCount = 0;
+
 	static const U32 BUFFERED_FRAMES = 16;
 	U32 m_bufferedFrames = 0;
 
@@ -101,15 +105,22 @@ public:
 		nk_style_push_style_item(
 			ctx, &ctx->style.window.fixed_background, nk_style_item_color(nk_rgba(255, 255, 255, 0)));
 
-		if(nk_begin(ctx, "Stats", nk_rect(5, 5, 200, 200), 0))
+		if(nk_begin(ctx, "Stats", nk_rect(5, 5, 500, 500), 0))
 		{
 			nk_layout_row_dynamic(ctx, 17, 1);
 
-			labelTime(ctx, m_frameTime, "Frame", flush);
-			labelTime(ctx, m_renderTime, "Renderer", flush);
-			labelTime(ctx, m_lightBinTime, "Light bin", flush);
-			labelTime(ctx, m_sceneUpdateTime, "Scene update", flush);
-			labelTime(ctx, m_visTestsTime, "Visibility", flush);
+			nk_label(ctx, "Time:", NK_TEXT_ALIGN_LEFT);
+			labelTime(ctx, m_frameTime.get(flush), "Total frame");
+			labelTime(ctx, m_renderTime.get(flush) - m_lightBinTime.get(flush), "Renderer");
+			labelTime(ctx, m_lightBinTime.get(false), "Light bin");
+			labelTime(ctx, m_sceneUpdateTime.get(flush), "Scene update");
+			labelTime(ctx, m_visTestsTime.get(flush), "Visibility");
+
+			nk_label(ctx, " ", NK_TEXT_ALIGN_LEFT);
+			nk_label(ctx, "Memory:", NK_TEXT_ALIGN_LEFT);
+			labelBytes(ctx, m_allocatedCpuMem, "Total CPU");
+			labelUint(ctx, m_allocCount, "Total allocations");
+			labelUint(ctx, m_freeCount, "Total frees");
 		}
 
 		nk_style_pop_style_item(ctx);
@@ -117,14 +128,103 @@ public:
 		canvas->popFont();
 	}
 
-	void labelTime(nk_context* ctx, BufferedValue<Second>& val, CString name, Bool flush)
+	void labelTime(nk_context* ctx, Second val, CString name)
+	{
+		StringAuto timestamp(getAllocator());
+		timestamp.sprintf("%s: %fms", name.cstr(), val * 1000.0);
+		nk_label(ctx, timestamp.cstr(), NK_TEXT_ALIGN_LEFT);
+	}
+
+	void labelBytes(nk_context* ctx, PtrSize val, CString name)
+	{
+		CString measure = "B";
+		if(val > 10_GB)
+		{
+			val /= 1_GB;
+			measure = "GB";
+		}
+		else if(val > 10_MB)
+		{
+			val /= 1_MB;
+			measure = "MB";
+		}
+		else if(val > 10_KB)
+		{
+			val /= 1_KB;
+			measure = "KB";
+		}
+
+		StringAuto timestamp(getAllocator());
+		timestamp.sprintf("%s: %'llu%s", name.cstr(), val, measure.cstr());
+		nk_label(ctx, timestamp.cstr(), NK_TEXT_ALIGN_LEFT);
+	}
+
+	void labelUint(nk_context* ctx, U64 val, CString name)
 	{
 		StringAuto timestamp(getAllocator());
-		timestamp.sprintf("%s: %fms", name.cstr(), val.get(flush) * 1000.0);
+		timestamp.sprintf("%s: %llu", name.cstr(), val);
 		nk_label(ctx, timestamp.cstr(), NK_TEXT_ALIGN_LEFT);
 	}
 };
 
+void* App::MemStats::allocCallback(void* userData, void* ptr, PtrSize size, PtrSize alignment)
+{
+	ANKI_ASSERT(userData);
+
+	static const PtrSize MAX_ALIGNMENT = 64;
+
+	struct alignas(MAX_ALIGNMENT) Header
+	{
+		PtrSize m_allocatedSize;
+		Array<U8, MAX_ALIGNMENT - sizeof(PtrSize)> _m_padding;
+	};
+	static_assert(sizeof(Header) == MAX_ALIGNMENT, "See file");
+	static_assert(alignof(Header) == MAX_ALIGNMENT, "See file");
+
+	void* out = nullptr;
+
+	if(ptr == nullptr)
+	{
+		// Need to allocate
+		ANKI_ASSERT(size > 0);
+		ANKI_ASSERT(alignment > 0 && alignment <= MAX_ALIGNMENT);
+
+		const PtrSize newAlignment = MAX_ALIGNMENT;
+		const PtrSize newSize = sizeof(Header) + size;
+
+		// Allocate
+		MemStats* self = static_cast<MemStats*>(userData);
+		Header* allocation = static_cast<Header*>(
+			self->m_originalAllocCallback(self->m_originalUserData, nullptr, newSize, newAlignment));
+		allocation->m_allocatedSize = size;
+		++allocation;
+		out = static_cast<void*>(allocation);
+
+		// Update stats
+		self->m_allocatedMem.fetchAdd(size);
+		self->m_allocCount.fetchAdd(1);
+	}
+	else
+	{
+		// Need to free
+
+		MemStats* self = static_cast<MemStats*>(userData);
+
+		Header* allocation = static_cast<Header*>(ptr);
+		--allocation;
+		ANKI_ASSERT(allocation->m_allocatedSize > 0);
+
+		// Update stats
+		self->m_freeCount.fetchAdd(1);
+		self->m_allocatedMem.fetchSub(allocation->m_allocatedSize);
+
+		// Free
+		self->m_originalAllocCallback(self->m_originalUserData, allocation, 0, 0);
+	}
+
+	return out;
+}
+
 App::App()
 {
 }
@@ -238,13 +338,12 @@ Error App::init(const ConfigSet& config, AllocAlignedCallback allocCb, void* all
 
 Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb, void* allocCbUserData)
 {
-	m_allocCb = allocCb;
-	m_allocCbData = allocCbUserData;
-	m_heapAlloc = HeapAllocator<U8>(allocCb, allocCbUserData);
 	ConfigSet config = config_;
-
 	m_displayStats = config.getNumber("core.displayStats");
 
+	initMemoryCallbacks(allocCb, allocCbUserData);
+	m_heapAlloc = HeapAllocator<U8>(m_allocCb, m_allocCbData);
+
 	ANKI_CHECK(initDirs(config));
 
 	// Print a message
@@ -312,7 +411,6 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	// Input
 	//
 	m_input = m_heapAlloc.newInstance<Input>();
-
 	ANKI_CHECK(m_input->init(m_window));
 
 	//
@@ -371,7 +469,7 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	// UI
 	//
 	m_ui = m_heapAlloc.newInstance<UiManager>();
-	ANKI_CHECK(m_ui->init(m_heapAlloc, m_resources, m_gr, m_stagingMem, m_input));
+	ANKI_CHECK(m_ui->init(m_allocCb, m_allocCbData, m_resources, m_gr, m_stagingMem, m_input));
 
 	ANKI_CHECK(m_ui->newInstance<StatsUi>(m_statsUi));
 
@@ -535,12 +633,18 @@ Error App::mainLoop()
 		}
 
 		// Stats
-		StatsUi& statsUi = static_cast<StatsUi&>(*m_statsUi);
-		statsUi.m_frameTime.set(frameTime);
-		statsUi.m_renderTime.set(m_renderer->getStats().m_renderingTime);
-		statsUi.m_lightBinTime.set(m_renderer->getStats().m_lightBinTime);
-		statsUi.m_sceneUpdateTime.set(m_scene->getStats().m_updateTime);
-		statsUi.m_visTestsTime.set(m_scene->getStats().m_visibilityTestsTime);
+		if(m_displayStats)
+		{
+			StatsUi& statsUi = static_cast<StatsUi&>(*m_statsUi);
+			statsUi.m_frameTime.set(frameTime);
+			statsUi.m_renderTime.set(m_renderer->getStats().m_renderingTime);
+			statsUi.m_lightBinTime.set(m_renderer->getStats().m_lightBinTime);
+			statsUi.m_sceneUpdateTime.set(m_scene->getStats().m_updateTime);
+			statsUi.m_visTestsTime.set(m_scene->getStats().m_visibilityTestsTime);
+			statsUi.m_allocatedCpuMem = m_memStats.m_allocatedMem.load();
+			statsUi.m_allocCount = m_memStats.m_allocCount.load();
+			statsUi.m_freeCount = m_memStats.m_freeCount.load();
+		}
 
 		++m_globalTimestamp;
 
@@ -570,4 +674,21 @@ void App::injectStatsUiElement(DynamicArrayAuto<UiQueueElement>& newUiElementArr
 	}
 }
 
+void App::initMemoryCallbacks(AllocAlignedCallback allocCb, void* allocCbUserData)
+{
+	if(m_displayStats)
+	{
+		m_memStats.m_originalAllocCallback = allocCb;
+		m_memStats.m_originalUserData = allocCbUserData;
+
+		m_allocCb = MemStats::allocCallback;
+		m_allocCbData = &m_memStats;
+	}
+	else
+	{
+		m_allocCb = allocCb;
+		m_allocCbData = allocCbUserData;
+	}
+}
+
 } // end namespace anki

+ 15 - 1
src/anki/core/App.h

@@ -9,7 +9,6 @@
 #include <anki/util/Allocator.h>
 #include <anki/util/String.h>
 #include <anki/util/Ptr.h>
-#include <anki/core/Timestamp.h>
 #include <anki/ui/UiImmediateModeBuilder.h>
 #if ANKI_OS == ANKI_OS_ANDROID
 #include <android_native_app_glue.h>
@@ -186,6 +185,21 @@ private:
 	Second m_timerTick;
 	U64 m_resourceCompletedAsyncTaskCount = 0;
 
+	class MemStats
+	{
+	public:
+		Atomic<PtrSize> m_allocatedMem = {0};
+		Atomic<U64> m_allocCount = {0};
+		Atomic<U64> m_freeCount = {0};
+
+		void* m_originalUserData = nullptr;
+		AllocAlignedCallback m_originalAllocCallback = nullptr;
+
+		static void* allocCallback(void* userData, void* ptr, PtrSize size, PtrSize alignment);
+	} m_memStats;
+
+	void initMemoryCallbacks(AllocAlignedCallback allocCb, void* allocCbUserData);
+
 	ANKI_USE_RESULT Error initInternal(const ConfigSet& config, AllocAlignedCallback allocCb, void* allocCbUserData);
 
 	ANKI_USE_RESULT Error initDirs(const ConfigSet& cfg);

+ 0 - 18
src/anki/core/Timestamp.h

@@ -1,18 +0,0 @@
-// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <anki/util/StdTypes.h>
-
-namespace anki
-{
-
-/// Timestamp type
-using Timestamp = U64;
-
-const U64 MAX_TIMESTAMP = MAX_U64;
-
-} // end namespace anki

+ 0 - 1
src/anki/gr/gl/GrManager.cpp

@@ -8,7 +8,6 @@
 #include <anki/gr/gl/RenderingThread.h>
 #include <anki/gr/gl/TextureImpl.h>
 #include <anki/gr/gl/GlState.h>
-#include <anki/core/Timestamp.h>
 
 #include <anki/gr/Buffer.h>
 #include <anki/gr/Texture.h>

+ 4 - 2
src/anki/gr/vulkan/CommandBufferFactory.cpp

@@ -138,8 +138,6 @@ Error CommandBufferThreadAllocator::newCommandBuffer(CommandBufferFlag cmdbFlags
 				{
 					out = mcmdb;
 				}
-
-				mcmdb->reset();
 			}
 			else
 			{
@@ -191,6 +189,10 @@ Error CommandBufferThreadAllocator::newCommandBuffer(CommandBufferFlag cmdbFlags
 
 		out = newCmdb;
 	}
+	else
+	{
+		out->reset();
+	}
 
 	ANKI_ASSERT(out && out->m_refcount.load() == 0);
 	outPtr.reset(out);

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

@@ -8,7 +8,6 @@
 #include <anki/renderer/Common.h>
 #include <anki/Math.h>
 #include <anki/collision/Aabb.h>
-#include <anki/core/Timestamp.h>
 
 namespace anki
 {

+ 2 - 2
src/anki/renderer/MainRenderer.cpp

@@ -58,8 +58,8 @@ Error MainRenderer::init(ThreadPool* threadpool,
 	m_rDrawToDefaultFb = m_renderingQuality == 1.0;
 
 	m_r.reset(m_alloc.newInstance<Renderer>());
-	ANKI_CHECK(m_r->init(
-		threadpool, resources, gr, stagingMem, ui, m_alloc, m_frameAlloc, config2, globTimestamp, m_rDrawToDefaultFb));
+	ANKI_CHECK(
+		m_r->init(threadpool, resources, gr, stagingMem, ui, m_alloc, config2, globTimestamp, m_rDrawToDefaultFb));
 
 	// Init other
 	if(!m_rDrawToDefaultFb)

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

@@ -7,7 +7,6 @@
 
 #include <anki/renderer/Common.h>
 #include <anki/resource/Forward.h>
-#include <anki/core/Timestamp.h>
 #include <anki/renderer/Renderer.h>
 
 namespace anki

+ 0 - 1
src/anki/renderer/RenderQueue.h

@@ -6,7 +6,6 @@
 #pragma once
 
 #include <anki/renderer/Common.h>
-#include <anki/core/Timestamp.h>
 #include <anki/resource/RenderingKey.h>
 #include <anki/ui/Canvas.h>
 

+ 0 - 2
src/anki/renderer/Renderer.cpp

@@ -45,7 +45,6 @@ Error Renderer::init(ThreadPool* threadpool,
 	StagingGpuMemoryManager* stagingMem,
 	UiManager* ui,
 	HeapAllocator<U8> alloc,
-	StackAllocator<U8> frameAlloc,
 	const ConfigSet& config,
 	Timestamp* globTimestamp,
 	Bool willDrawToDefaultFbo)
@@ -59,7 +58,6 @@ Error Renderer::init(ThreadPool* threadpool,
 	m_stagingMem = stagingMem;
 	m_ui = ui;
 	m_alloc = alloc;
-	m_frameAlloc = frameAlloc;
 	m_willDrawToDefaultFbo = willDrawToDefaultFbo;
 
 	Error err = initInternal(config);

+ 0 - 8
src/anki/renderer/Renderer.h

@@ -10,7 +10,6 @@
 #include <anki/Math.h>
 #include <anki/Gr.h>
 #include <anki/resource/Forward.h>
-#include <anki/core/Timestamp.h>
 #include <anki/core/StagingGpuMemoryManager.h>
 #include <anki/util/ThreadPool.h>
 #include <anki/collision/Forward.h>
@@ -185,7 +184,6 @@ public:
 		StagingGpuMemoryManager* stagingMem,
 		UiManager* ui,
 		HeapAllocator<U8> alloc,
-		StackAllocator<U8> frameAlloc,
 		const ConfigSet& config,
 		Timestamp* globTimestamp,
 		Bool willDrawToDefaultFbo);
@@ -280,11 +278,6 @@ anki_internal:
 		return m_alloc;
 	}
 
-	StackAllocator<U8> getFrameAllocator() const
-	{
-		return m_frameAlloc;
-	}
-
 	ResourceManager& getResourceManager()
 	{
 		return *m_resources;
@@ -354,7 +347,6 @@ private:
 	UiManager* m_ui = nullptr;
 	Timestamp* m_globTimestamp;
 	HeapAllocator<U8> m_alloc;
-	StackAllocator<U8> m_frameAlloc;
 
 	/// @name Rendering stages
 	/// @{

+ 0 - 1
src/anki/scene/SceneGraph.h

@@ -8,7 +8,6 @@
 #include <anki/scene/Common.h>
 #include <anki/scene/SceneNode.h>
 #include <anki/scene/Visibility.h>
-#include <anki/core/Timestamp.h>
 #include <anki/Math.h>
 #include <anki/util/Singleton.h>
 #include <anki/util/HighRezTimer.h>

+ 0 - 1
src/anki/scene/components/SceneComponent.h

@@ -6,7 +6,6 @@
 #pragma once
 
 #include <anki/scene/Common.h>
-#include <anki/core/Timestamp.h>
 #include <anki/util/Functions.h>
 #include <anki/util/BitMask.h>
 #include <anki/util/List.h>

+ 7 - 3
src/anki/ui/UiManager.cpp

@@ -16,15 +16,19 @@ UiManager::~UiManager()
 {
 }
 
-Error UiManager::init(
-	HeapAllocator<U8> alloc, ResourceManager* resources, GrManager* gr, StagingGpuMemoryManager* gpuMem, Input* input)
+Error UiManager::init(AllocAlignedCallback allocCallback,
+	void* allocCallbackUserData,
+	ResourceManager* resources,
+	GrManager* gr,
+	StagingGpuMemoryManager* gpuMem,
+	Input* input)
 {
 	ANKI_ASSERT(resources);
 	ANKI_ASSERT(gr);
 	ANKI_ASSERT(gpuMem);
 	ANKI_ASSERT(input);
 
-	m_alloc = alloc;
+	m_alloc = UiAllocator(allocCallback, allocCallbackUserData);
 	m_resources = resources;
 	m_gr = gr;
 	m_gpuMem = gpuMem;

+ 2 - 1
src/anki/ui/UiManager.h

@@ -27,7 +27,8 @@ public:
 
 	~UiManager();
 
-	ANKI_USE_RESULT Error init(HeapAllocator<U8> alloc,
+	ANKI_USE_RESULT Error init(AllocAlignedCallback allocCallback,
+		void* allocCallbackUserData,
 		ResourceManager* resources,
 		GrManager* gr,
 		StagingGpuMemoryManager* gpuMem,

+ 2 - 1
src/anki/util/Allocator.h

@@ -11,6 +11,7 @@
 #include <anki/util/Ptr.h>
 #include <cstddef> // For ptrdiff_t
 #include <utility> // For forward
+#include <new> // For placement new
 
 namespace anki
 {
@@ -89,7 +90,7 @@ public:
 			ANKI_UTIL_LOGF("Out of memory");
 		}
 
-		new(m_pool) TPool();
+		::new(m_pool) TPool();
 
 		m_pool->create(allocCb, allocCbUserData, std::forward<TArgs>(args)...);
 		m_pool->getRefcount().store(1);

+ 1 - 1
src/anki/util/Memory.h

@@ -32,7 +32,7 @@ void freeAligned(void* ptr);
 
 /// The function signature of a memory allocation/deallocation. See allocAligned function for the explanation of
 /// arguments
-using AllocAlignedCallback = void* (*)(void*, void*, PtrSize, PtrSize);
+using AllocAlignedCallback = void* (*)(void* userData, void* ptr, PtrSize size, PtrSize alignment);
 
 /// An internal type.
 using AllocationSignature = U32;

+ 9 - 1
src/anki/util/StdTypes.h

@@ -76,6 +76,9 @@ using Bool32 = I32; ///< A 32bit boolean
 
 using Second = F64; ///< The base time unit is second.
 
+using Timestamp = U64; ///< Timestamp type.
+const Timestamp MAX_TIMESTAMP = MAX_U64;
+
 /// Representation of error and a wrapper on top of error codes.
 class Error
 {
@@ -197,7 +200,12 @@ static constexpr unsigned long long int operator""_KB(unsigned long long int x)
 
 static constexpr unsigned long long int operator""_MB(unsigned long long int x)
 {
-	return x * 1024 * 1024;
+	return x * (1024 * 1024);
+}
+
+static constexpr unsigned long long int operator""_GB(unsigned long long int x)
+{
+	return x * (1024 * 1024 * 1024);
 }
 /// @}
 

+ 1 - 1
tests/ui/Ui.cpp

@@ -74,7 +74,7 @@ ANKI_TEST(Ui, Ui)
 	ANKI_TEST_EXPECT_NO_ERR(stagingMem->init(gr, cfg));
 
 	HeapAllocator<U8> alloc(allocAligned, nullptr);
-	ANKI_TEST_EXPECT_NO_ERR(ui->init(alloc, resource, gr, stagingMem, in));
+	ANKI_TEST_EXPECT_NO_ERR(ui->init(allocAligned, nullptr, resource, gr, stagingMem, in));
 
 	{
 		FontPtr font;