sample app - memory & resource profiler
This commit is contained in:
parent
30e8180e28
commit
1e41088840
18 changed files with 412 additions and 91 deletions
|
@ -1,8 +1,9 @@
|
|||
BasedOnStyle: LLVM
|
||||
|
||||
AlignAfterOpenBracket : false
|
||||
AlignEscapedNewlinesLeft : true
|
||||
AlignConsecutiveAssignments : false
|
||||
AllowAllParametersOfDeclarationOnNextLine : true
|
||||
AllowAllParametersOfDeclarationOnNextLine : false
|
||||
AccessModifierOffset : -4
|
||||
AllowShortCaseLabelsOnASingleLine : true
|
||||
AllowShortFunctionsOnASingleLine : Inline
|
||||
|
|
|
@ -35,6 +35,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void* reallocate(void* ptr, size_t size) override
|
||||
{
|
||||
return m_source.reallocate(ptr, size);
|
||||
}
|
||||
|
||||
|
||||
IAllocator& getSourceAllocator() { return m_source; }
|
||||
|
||||
private:
|
||||
|
|
|
@ -17,4 +17,10 @@ namespace Lumix
|
|||
}
|
||||
|
||||
|
||||
void* DefaultAllocator::reallocate(void* ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
|
||||
} // ~namespace Lumix
|
||||
|
|
|
@ -16,6 +16,7 @@ public:
|
|||
|
||||
virtual void* allocate(size_t n) override;
|
||||
virtual void deallocate(void* p) override;
|
||||
virtual void* reallocate(void* ptr, size_t size) override;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,12 @@ namespace Lumix
|
|||
m_pool[m_pool_index++] = reinterpret_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
void* reallocate(void*, size_t) override
|
||||
{
|
||||
ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
IAllocator& m_allocator;
|
||||
int32_t m_pool_index;
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Lumix
|
|||
|
||||
virtual void* allocate(size_t size) = 0;
|
||||
virtual void deallocate(void* ptr) = 0;
|
||||
virtual void* reallocate(void* ptr, size_t size) = 0;
|
||||
|
||||
template <class T, typename... Args>
|
||||
T* newObject(Args&&... params)
|
||||
|
@ -25,6 +26,7 @@ namespace Lumix
|
|||
}
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
void deleteObject(T* ptr)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,12 @@ namespace Lumix
|
|||
}
|
||||
|
||||
|
||||
virtual void* reallocate(void*, size_t) override
|
||||
{
|
||||
ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
IAllocator& m_source;
|
||||
size_t m_bucket_size;
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Lumix
|
|||
bool isReady() const { return State::READY == m_state; }
|
||||
bool isUnloading() const { return State::UNLOADING == m_state; }
|
||||
bool isFailure() const { return State::FAILURE == m_state; }
|
||||
|
||||
uint32_t getRefCount() const { return m_ref_count; }
|
||||
|
||||
template <typename C, void (C::*Function)(State, State)>
|
||||
void onLoaded(C* instance)
|
||||
|
|
|
@ -22,6 +22,7 @@ class ResourceManager;
|
|||
class LUMIX_ENGINE_API ResourceManagerBase
|
||||
{
|
||||
friend class Resource;
|
||||
public:
|
||||
typedef PODHashMap<uint32_t, Resource*> ResourceTable;
|
||||
|
||||
public:
|
||||
|
@ -42,6 +43,7 @@ public:
|
|||
|
||||
void reload(const Path& path);
|
||||
void reload(Resource& resource);
|
||||
ResourceTable& getResourceTable() { return m_resources; }
|
||||
|
||||
ResourceManagerBase(IAllocator& allocator);
|
||||
virtual ~ResourceManagerBase(void);
|
||||
|
|
|
@ -34,6 +34,12 @@ namespace Lumix
|
|||
}
|
||||
}
|
||||
|
||||
virtual void* reallocate(void*, size_t) override
|
||||
{
|
||||
ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_end;
|
||||
uint8_t m_data[SIZE];
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Debug
|
|||
|
||||
class LUMIX_ENGINE_API Allocator : public IAllocator
|
||||
{
|
||||
private:
|
||||
public:
|
||||
class AllocationInfo
|
||||
{
|
||||
public:
|
||||
|
@ -36,9 +36,11 @@ namespace Debug
|
|||
|
||||
virtual void* allocate(size_t size) override;
|
||||
virtual void deallocate(void* ptr) override;
|
||||
virtual void* reallocate(void* ptr, size_t size) override;
|
||||
size_t getTotalSize() const { return m_total_size; }
|
||||
|
||||
IAllocator& getSourceAllocator() { return m_source; }
|
||||
AllocationInfo* getFirstAllocationInfo() const { return m_root; }
|
||||
|
||||
private:
|
||||
inline size_t getAllocationOffset();
|
||||
|
|
|
@ -99,6 +99,27 @@ namespace Debug
|
|||
}
|
||||
|
||||
|
||||
void* Allocator::reallocate(void* user_ptr, size_t size)
|
||||
{
|
||||
#ifndef _DEBUG
|
||||
return m_source.reallocate(ptr, size);
|
||||
#else
|
||||
if (user_ptr == nullptr) return allocate(size);
|
||||
if (size == 0) return nullptr;
|
||||
|
||||
void* new_data = allocate(size);
|
||||
if (!new_data) return nullptr;
|
||||
|
||||
AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
|
||||
memcpy(new_data, user_ptr, info->m_size < size ? info->m_size : size);
|
||||
|
||||
deallocate(user_ptr);
|
||||
|
||||
return new_data;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* Allocator::allocate(size_t size)
|
||||
{
|
||||
#ifndef _DEBUG
|
||||
|
|
|
@ -59,6 +59,27 @@ StackTree::~StackTree()
|
|||
}
|
||||
|
||||
|
||||
StackNode* StackTree::getParent(StackNode* node)
|
||||
{
|
||||
return node ? node->m_parent : nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool StackTree::getFunction(StackNode* node, char* out, int max_size)
|
||||
{
|
||||
HANDLE process = GetCurrentProcess();
|
||||
uint8_t symbol_mem[sizeof(SYMBOL_INFO) + 256 * sizeof(char)];
|
||||
SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(symbol_mem);
|
||||
memset(symbol_mem, 0, sizeof(symbol_mem));
|
||||
symbol->MaxNameLen = 255;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
BOOL success = SymFromAddr(process, (DWORD64)(node->m_instruction), 0, symbol);
|
||||
if (success) Lumix::copyString(out, max_size, symbol->Name);
|
||||
|
||||
return success == TRUE;
|
||||
}
|
||||
|
||||
|
||||
void StackTree::printCallstack(StackNode* node)
|
||||
{
|
||||
while (node)
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Debug
|
|||
class StackNode;
|
||||
|
||||
|
||||
class StackTree
|
||||
class LUMIX_ENGINE_API StackTree
|
||||
{
|
||||
public:
|
||||
StackTree();
|
||||
|
@ -22,6 +22,8 @@ namespace Debug
|
|||
|
||||
StackNode* record();
|
||||
void printCallstack(StackNode* node);
|
||||
static bool getFunction(StackNode* node, char* out, int max_size);
|
||||
static StackNode* getParent(StackNode* node);
|
||||
|
||||
private:
|
||||
StackNode* insertChildren(StackNode* node, void** instruction, void** stack);
|
||||
|
|
|
@ -33,9 +33,31 @@
|
|||
#include <cstdio>
|
||||
|
||||
|
||||
namespace bgfx
|
||||
namespace bx
|
||||
{
|
||||
|
||||
struct AllocatorI
|
||||
{
|
||||
virtual ~AllocatorI() = 0;
|
||||
virtual void* alloc(size_t _size, size_t _align, const char* _file, uint32_t _line) = 0;
|
||||
virtual void free(void* _ptr, size_t _align, const char* _file, uint32_t _line) = 0;
|
||||
};
|
||||
|
||||
inline AllocatorI::~AllocatorI()
|
||||
{
|
||||
}
|
||||
|
||||
struct ReallocatorI : public AllocatorI
|
||||
{
|
||||
virtual void* realloc(void* _ptr, size_t _size, size_t _align, const char* _file, uint32_t _line) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace bx
|
||||
|
||||
|
||||
namespace bgfx
|
||||
{
|
||||
|
||||
struct PlatformData
|
||||
{
|
||||
|
@ -48,7 +70,8 @@ struct PlatformData
|
|||
|
||||
|
||||
void setPlatformData(const PlatformData& _pd);
|
||||
}
|
||||
|
||||
} // namespace bgfx
|
||||
|
||||
|
||||
namespace Lumix
|
||||
|
@ -61,6 +84,47 @@ static const uint32_t RENDERABLE_HASH = crc32("renderable");
|
|||
static const uint32_t CAMERA_HASH = crc32("camera");
|
||||
|
||||
|
||||
struct BGFXAllocator : public bx::ReallocatorI
|
||||
{
|
||||
|
||||
BGFXAllocator(Lumix::IAllocator& source)
|
||||
: m_source(source)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual ~BGFXAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual void* alloc(size_t _size, size_t _align, const char* _file, uint32_t _line) override
|
||||
{
|
||||
return m_source.allocate(_size);
|
||||
}
|
||||
|
||||
|
||||
virtual void free(void* _ptr, size_t _align, const char* _file, uint32_t _line) override
|
||||
{
|
||||
m_source.deallocate(_ptr);
|
||||
}
|
||||
|
||||
|
||||
virtual void* realloc(void* _ptr,
|
||||
size_t _size,
|
||||
size_t _align,
|
||||
const char* _file,
|
||||
uint32_t _line) override
|
||||
{
|
||||
return m_source.reallocate(_ptr, _size);
|
||||
}
|
||||
|
||||
|
||||
Lumix::IAllocator& m_source;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct RendererImpl : public Renderer
|
||||
{
|
||||
struct CallbackStub : public bgfx::CallbackI
|
||||
|
@ -79,7 +143,10 @@ struct RendererImpl : public Renderer
|
|||
}
|
||||
|
||||
|
||||
virtual void traceVargs(const char* _filePath, uint16_t _line, const char* _format, va_list _argList) override
|
||||
virtual void traceVargs(const char* _filePath,
|
||||
uint16_t _line,
|
||||
const char* _format,
|
||||
va_list _argList) override
|
||||
{
|
||||
char tmp[2048];
|
||||
vsnprintf(tmp, sizeof(tmp), _format, _argList);
|
||||
|
@ -88,38 +155,32 @@ struct RendererImpl : public Renderer
|
|||
|
||||
|
||||
virtual void screenShot(const char*,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
const void*,
|
||||
uint32_t,
|
||||
bool) override
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
const void*,
|
||||
uint32_t,
|
||||
bool) override
|
||||
{
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
|
||||
virtual void captureBegin(uint32_t,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
bgfx::TextureFormat::Enum,
|
||||
bool) override
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
bgfx::TextureFormat::Enum,
|
||||
bool) override
|
||||
{
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
|
||||
virtual uint32_t cacheReadSize(uint64_t) override { return 0; }
|
||||
virtual bool cacheRead(uint64_t, void*, uint32_t) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool cacheRead(uint64_t, void*, uint32_t) override { return false; }
|
||||
virtual void cacheWrite(uint64_t, const void*, uint32_t) override {}
|
||||
virtual void captureEnd() override { ASSERT(false); }
|
||||
virtual void captureFrame(const void*, uint32_t) override
|
||||
{
|
||||
ASSERT(false);
|
||||
}
|
||||
virtual void captureFrame(const void*, uint32_t) override { ASSERT(false); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -133,6 +194,7 @@ struct RendererImpl : public Renderer
|
|||
, m_pipeline_manager(*this, m_allocator)
|
||||
, m_passes(m_allocator)
|
||||
, m_shader_defines(m_allocator)
|
||||
, m_bgfx_allocator(m_allocator)
|
||||
{
|
||||
bgfx::PlatformData d;
|
||||
if (s_hwnd)
|
||||
|
@ -141,7 +203,7 @@ struct RendererImpl : public Renderer
|
|||
d.nwh = s_hwnd;
|
||||
bgfx::setPlatformData(d);
|
||||
}
|
||||
bgfx::init(bgfx::RendererType::Count, 0, 0, &m_callback_stub);
|
||||
bgfx::init(bgfx::RendererType::Count, 0, 0, &m_callback_stub, &m_bgfx_allocator);
|
||||
bgfx::reset(800, 600);
|
||||
bgfx::setDebug(BGFX_DEBUG_TEXT);
|
||||
|
||||
|
@ -195,17 +257,11 @@ struct RendererImpl : public Renderer
|
|||
m_engine.registerComponentType("point_light", "Point light");
|
||||
m_engine.registerComponentType("terrain", "Terrain");
|
||||
|
||||
m_engine.registerProperty(
|
||||
"camera",
|
||||
m_engine.registerProperty("camera",
|
||||
allocator.newObject<StringPropertyDescriptor<RenderScene>>(
|
||||
"slot",
|
||||
&RenderScene::getCameraSlot,
|
||||
&RenderScene::setCameraSlot,
|
||||
allocator));
|
||||
m_engine.registerProperty(
|
||||
"camera",
|
||||
allocator.newObject<DecimalPropertyDescriptor<RenderScene>>(
|
||||
"FOV",
|
||||
"slot", &RenderScene::getCameraSlot, &RenderScene::setCameraSlot, allocator));
|
||||
m_engine.registerProperty("camera",
|
||||
allocator.newObject<DecimalPropertyDescriptor<RenderScene>>("FOV",
|
||||
&RenderScene::getCameraFOV,
|
||||
&RenderScene::setCameraFOV,
|
||||
1.0f,
|
||||
|
@ -526,6 +582,7 @@ struct RendererImpl : public Renderer
|
|||
PipelineManager m_pipeline_manager;
|
||||
uint32_t m_current_pass_hash;
|
||||
int m_view_counter;
|
||||
BGFXAllocator m_bgfx_allocator;
|
||||
|
||||
static HWND s_hwnd;
|
||||
};
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
, m_is_entity_template_list_opened(false)
|
||||
, m_selected_template_name(m_allocator)
|
||||
, m_is_gameview_opened(true)
|
||||
, m_profiler_ui(nullptr)
|
||||
, m_asset_browser(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -96,7 +98,7 @@ public:
|
|||
|
||||
showMainMenu();
|
||||
|
||||
m_profiler_ui.onGui();
|
||||
m_profiler_ui->onGui();
|
||||
m_asset_browser->onGui();
|
||||
m_log_ui->onGui();
|
||||
m_import_asset_dialog->onGui();
|
||||
|
@ -276,7 +278,7 @@ public:
|
|||
ImGui::MenuItem("Entity list", nullptr, &m_is_entity_list_shown);
|
||||
ImGui::MenuItem("Entity templates", nullptr, &m_is_entity_template_list_opened);
|
||||
ImGui::MenuItem("Log", nullptr, &m_log_ui->m_is_opened);
|
||||
ImGui::MenuItem("Profiler", nullptr, &m_profiler_ui.m_is_opened);
|
||||
ImGui::MenuItem("Profiler", nullptr, &m_profiler_ui->m_is_opened);
|
||||
ImGui::MenuItem("Properties", nullptr, &m_is_property_grid_shown);
|
||||
ImGui::MenuItem("Style editor", nullptr, &m_is_style_editor_shown);
|
||||
ImGui::EndMenu();
|
||||
|
@ -690,6 +692,7 @@ public:
|
|||
shutdownImGui();
|
||||
|
||||
delete m_terrain_editor;
|
||||
delete m_profiler_ui;
|
||||
delete m_asset_browser;
|
||||
delete m_log_ui;
|
||||
delete m_import_asset_dialog;
|
||||
|
@ -805,6 +808,7 @@ public:
|
|||
GetCurrentDirectory(sizeof(current_dir), current_dir);
|
||||
m_editor = Lumix::WorldEditor::create(current_dir, *m_engine);
|
||||
m_asset_browser = new AssetBrowser(*m_editor);
|
||||
m_profiler_ui = new ProfilerUI(&m_allocator, &m_editor->getEngine().getResourceManager());
|
||||
m_terrain_editor = new TerrainEditor(*m_editor);
|
||||
m_log_ui = new LogUI(m_editor->getAllocator());
|
||||
m_import_asset_dialog = new ImportAssetDialog(*m_editor);
|
||||
|
@ -918,7 +922,7 @@ public:
|
|||
AssetBrowser* m_asset_browser;
|
||||
TerrainEditor* m_terrain_editor;
|
||||
LogUI* m_log_ui;
|
||||
ProfilerUI m_profiler_ui;
|
||||
ProfilerUI* m_profiler_ui;
|
||||
ImportAssetDialog* m_import_asset_dialog;
|
||||
ShaderCompiler* m_shader_compiler;
|
||||
Lumix::string m_selected_template_name;
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#include "profiler_ui.h"
|
||||
#include "core/math_utils.h"
|
||||
#include "core/resource.h"
|
||||
#include "core/resource_manager.h"
|
||||
#include "core/resource_manager_base.h"
|
||||
#include "debug/allocator.h"
|
||||
#include "debug/stack_tree.h"
|
||||
#include "engine/engine.h"
|
||||
#include "ocornut-imgui/imgui.h"
|
||||
#include "string_builder.h"
|
||||
|
||||
|
@ -14,8 +20,11 @@ enum Column
|
|||
};
|
||||
|
||||
|
||||
ProfilerUI::ProfilerUI()
|
||||
ProfilerUI::ProfilerUI(Lumix::Debug::Allocator* allocator, Lumix::ResourceManager* resource_manager)
|
||||
: m_main_allocator(allocator)
|
||||
, m_resource_manager(resource_manager)
|
||||
{
|
||||
m_root = nullptr;
|
||||
m_is_opened = false;
|
||||
m_current_block = nullptr;
|
||||
Lumix::g_profiler.getFrameListeners().bind<ProfilerUI, &ProfilerUI::onFrame>(this);
|
||||
|
@ -166,61 +175,215 @@ void ProfilerUI::showProfileBlock(Block* block, int column)
|
|||
}
|
||||
|
||||
|
||||
static void showCallstack(Lumix::Debug::Allocator::AllocationInfo* info)
|
||||
{
|
||||
char fn_name[256];
|
||||
auto* node = info->m_stack_leaf;
|
||||
while (node)
|
||||
{
|
||||
if (Lumix::Debug::StackTree::getFunction(node, fn_name, sizeof(fn_name)))
|
||||
{
|
||||
ImGui::BulletText(fn_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::BulletText("N/A");
|
||||
}
|
||||
node = Lumix::Debug::StackTree::getParent(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char* getResourceStateString(Lumix::Resource::State state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case Lumix::Resource::State::EMPTY: return "Empty"; break;
|
||||
case Lumix::Resource::State::FAILURE: return "Failure"; break;
|
||||
case Lumix::Resource::State::LOADING: return "Loading"; break;
|
||||
case Lumix::Resource::State::READY: return "Ready"; break;
|
||||
case Lumix::Resource::State::UNLOADING: return "Unloading"; break;
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
|
||||
void ProfilerUI::onGuiResources()
|
||||
{
|
||||
if (!m_resource_manager) return;
|
||||
if (!ImGui::CollapsingHeader("Resources")) return;
|
||||
|
||||
uint32_t manager_types[] = {Lumix::ResourceManager::ANIMATION,
|
||||
Lumix::ResourceManager::MATERIAL,
|
||||
Lumix::ResourceManager::MODEL,
|
||||
Lumix::ResourceManager::PHYSICS,
|
||||
Lumix::ResourceManager::PIPELINE,
|
||||
Lumix::ResourceManager::SHADER,
|
||||
Lumix::ResourceManager::TEXTURE};
|
||||
const char* manager_names[] = {
|
||||
"Animations",
|
||||
"Materials",
|
||||
"Models",
|
||||
"Physics",
|
||||
"Pipelines",
|
||||
"Shaders",
|
||||
"Textures"
|
||||
};
|
||||
ASSERT(Lumix::lengthOf(manager_types) == Lumix::lengthOf(manager_names));
|
||||
ImGui::Indent();
|
||||
for (int i = 0; i < Lumix::lengthOf(manager_types); ++i)
|
||||
{
|
||||
if (!ImGui::CollapsingHeader(manager_names[i])) continue;
|
||||
|
||||
auto* material_manager = m_resource_manager->get(manager_types[i]);
|
||||
auto& resources = material_manager->getResourceTable();
|
||||
|
||||
ImGui::Columns(4);
|
||||
size_t sum = 0;
|
||||
for (auto iter = resources.begin(), end = resources.end(); iter != end; ++iter)
|
||||
{
|
||||
ImGui::Text(iter.value()->getPath().c_str());
|
||||
ImGui::NextColumn();
|
||||
ImGui::Text("%.3fKB", iter.value()->size() / 1024.0f);
|
||||
sum += iter.value()->size();
|
||||
ImGui::NextColumn();
|
||||
ImGui::Text(getResourceStateString(iter.value()->getState()));
|
||||
ImGui::NextColumn();
|
||||
ImGui::Text("%u", iter.value()->getRefCount());
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
ImGui::Text("All");
|
||||
ImGui::NextColumn();
|
||||
ImGui::Text("%.3fKB", sum / 1024.0f);
|
||||
ImGui::NextColumn();
|
||||
ImGui::NextColumn();
|
||||
|
||||
ImGui::Columns(1);
|
||||
ImGui::Separator();
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
|
||||
|
||||
void ProfilerUI::onGuiMemoryProfiler()
|
||||
{
|
||||
if (!m_main_allocator) return;
|
||||
if (!ImGui::CollapsingHeader("Memory")) return;
|
||||
|
||||
ImGui::Text("Total size: %.3fMB", (m_main_allocator->getTotalSize() / 1024) / 1024.0f);
|
||||
static int from = 0;
|
||||
static int to = 0x7fffFFFF;
|
||||
ImGui::SameLine();
|
||||
ImGui::DragIntRange2("Interval", &from, &to);
|
||||
auto* current_info = m_main_allocator->getFirstAllocationInfo();
|
||||
|
||||
int allocation_count = 0;
|
||||
while (current_info)
|
||||
{
|
||||
auto info = current_info;
|
||||
current_info = current_info->m_next;
|
||||
|
||||
if (info->m_size < from || info->m_size > to) continue;
|
||||
|
||||
if (info->m_size < 1024)
|
||||
{
|
||||
if (ImGui::TreeNode(info, "%dB", int(info->m_size)))
|
||||
{
|
||||
showCallstack(info);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
else if (info->m_size < 1024 * 1024)
|
||||
{
|
||||
if (ImGui::TreeNode(info, "%dKB", int(info->m_size / 1024)))
|
||||
{
|
||||
showCallstack(info);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImGui::TreeNode(info, "%.3fMB", (info->m_size / 1024) / 1024.0f))
|
||||
{
|
||||
showCallstack(info);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
++allocation_count;
|
||||
}
|
||||
|
||||
ImGui::Text("Total number of allocations: %d", allocation_count);
|
||||
}
|
||||
|
||||
|
||||
void ProfilerUI::onGuiCPUProfiler()
|
||||
{
|
||||
if (!ImGui::CollapsingHeader("CPU")) return;
|
||||
|
||||
bool b = Lumix::g_profiler.isRecording();
|
||||
if (ImGui::Checkbox("Recording", &b))
|
||||
{
|
||||
Lumix::g_profiler.toggleRecording();
|
||||
}
|
||||
if (m_root)
|
||||
{
|
||||
ImGui::Columns(2);
|
||||
showProfileBlock(m_root, NAME);
|
||||
ImGui::NextColumn();
|
||||
showProfileBlock(m_root, TIME);
|
||||
ImGui::NextColumn();
|
||||
ImGui::Columns(1);
|
||||
}
|
||||
|
||||
if (m_root)
|
||||
{
|
||||
float times[MAX_FRAMES];
|
||||
for (int i = 0; i < m_root->m_frames.size(); ++i)
|
||||
{
|
||||
times[i] = m_root->m_frames[i];
|
||||
}
|
||||
|
||||
auto* block = m_current_block ? m_current_block : m_root;
|
||||
float width = ImGui::GetWindowContentRegionWidth();
|
||||
int count = Lumix::Math::minValue(int(width / 5), block->m_hit_counts.size());
|
||||
int offset = block->m_hit_counts.size() - count;
|
||||
struct PlotData
|
||||
{
|
||||
Block* block;
|
||||
int offset;
|
||||
};
|
||||
auto getter = [](void* data, int idx) -> float
|
||||
{
|
||||
auto* plot_data = (PlotData*)data;
|
||||
return plot_data->block->m_frames[plot_data->offset + idx];
|
||||
};
|
||||
PlotData plot_data;
|
||||
plot_data.block = block;
|
||||
plot_data.offset = offset;
|
||||
ImGui::PlotHistogram("",
|
||||
getter,
|
||||
&plot_data,
|
||||
count,
|
||||
0,
|
||||
block->m_name,
|
||||
0,
|
||||
FLT_MAX,
|
||||
ImVec2(width, 100));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ProfilerUI::onGui()
|
||||
{
|
||||
if (!m_is_opened) return;
|
||||
|
||||
if (ImGui::Begin("Profiler", &m_is_opened))
|
||||
{
|
||||
bool b = Lumix::g_profiler.isRecording();
|
||||
if (ImGui::Checkbox("Recording", &b))
|
||||
{
|
||||
Lumix::g_profiler.toggleRecording();
|
||||
}
|
||||
if (m_root)
|
||||
{
|
||||
ImGui::Columns(2);
|
||||
showProfileBlock(m_root, NAME);
|
||||
ImGui::NextColumn();
|
||||
showProfileBlock(m_root, TIME);
|
||||
ImGui::NextColumn();
|
||||
ImGui::Columns(1);
|
||||
}
|
||||
|
||||
if (m_root)
|
||||
{
|
||||
float times[MAX_FRAMES];
|
||||
for (int i = 0; i < m_root->m_frames.size(); ++i)
|
||||
{
|
||||
times[i] = m_root->m_frames[i];
|
||||
}
|
||||
|
||||
auto* block = m_current_block ? m_current_block : m_root;
|
||||
float width = ImGui::GetWindowContentRegionWidth();
|
||||
int count = Lumix::Math::minValue(int(width / 5), block->m_hit_counts.size());
|
||||
int offset = block->m_hit_counts.size() - count;
|
||||
struct PlotData
|
||||
{
|
||||
Block* block;
|
||||
int offset;
|
||||
};
|
||||
auto getter = [](void* data, int idx) -> float {
|
||||
auto* plot_data = (PlotData*)data;
|
||||
return plot_data->block->m_frames[plot_data->offset + idx];
|
||||
};
|
||||
PlotData plot_data;
|
||||
plot_data.block = block;
|
||||
plot_data.offset = offset;
|
||||
ImGui::PlotHistogram("",
|
||||
getter,
|
||||
&plot_data,
|
||||
count,
|
||||
0,
|
||||
block->m_name,
|
||||
0,
|
||||
FLT_MAX,
|
||||
ImVec2(width, 100));
|
||||
}
|
||||
onGuiCPUProfiler();
|
||||
onGuiMemoryProfiler();
|
||||
onGuiResources();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
|
@ -8,14 +8,24 @@
|
|||
|
||||
namespace Lumix
|
||||
{
|
||||
class IAllocator;
|
||||
|
||||
class IAllocator;
|
||||
class ResourceManager;
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
|
||||
class Allocator;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class ProfilerUI
|
||||
{
|
||||
public:
|
||||
ProfilerUI();
|
||||
ProfilerUI(Lumix::Debug::Allocator* allocator, Lumix::ResourceManager* resource_manager);
|
||||
~ProfilerUI();
|
||||
|
||||
void onGui();
|
||||
|
@ -48,6 +58,9 @@ private:
|
|||
};
|
||||
|
||||
private:
|
||||
void onGuiCPUProfiler();
|
||||
void onGuiMemoryProfiler();
|
||||
void onGuiResources();
|
||||
void onFrame();
|
||||
void showProfileBlock(ProfilerUI::Block* block, int column);
|
||||
void cloneBlock(Block* my_block, Lumix::Profiler::Block* remote_block);
|
||||
|
@ -56,4 +69,6 @@ private:
|
|||
Lumix::DefaultAllocator m_allocator;
|
||||
Block* m_root;
|
||||
Block* m_current_block;
|
||||
Lumix::Debug::Allocator* m_main_allocator;
|
||||
Lumix::ResourceManager* m_resource_manager;
|
||||
};
|
Loading…
Reference in a new issue