Memory allocation viewer (#375)

* Added an allocation viewer

* Removed header comment for ui_allocations_dialogue

I forgot to turn those off! Sorry.

* Fix imgui_club submodule

* Allocation viewer style fixes

* Add extra whitespace
This commit is contained in:
Taylor Whatley 2019-01-11 12:51:37 -05:00 committed by Nick Renieris
parent 61b5f51730
commit c068bf28f6
12 changed files with 88 additions and 9 deletions

3
.gitmodules vendored
View File

@ -52,3 +52,6 @@
[submodule "src/external/dlmalloc"]
path = src/external/dlmalloc
url = https://github.com/Vita3K/dlmalloc
[submodule "src/external/imgui_club"]
path = src/external/imgui_club
url = https://github.com/ocornut/imgui_club.git

View File

@ -64,7 +64,7 @@ static bool is_thumb_mode(uc_engine *uc) {
static void code_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
CPUState &state = *static_cast<CPUState *>(user_data);
const MemState &mem = *state.mem;
MemState &mem = *state.mem;
const uint8_t *const code = Ptr<const uint8_t>(static_cast<Address>(address)).get(mem);
const size_t buffer_size = GB(4) - address;
const bool thumb = is_thumb_mode(uc);
@ -72,7 +72,7 @@ static void code_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user
LOG_TRACE("{}: {} {}", log_hex((uint64_t)uc), log_hex(address), disassembly);
}
static void log_memory_access(uc_engine *uc, const char *type, Address address, int size, int64_t value, const MemState &mem) {
static void log_memory_access(uc_engine *uc, const char *type, Address address, int size, int64_t value, MemState &mem) {
const char *const name = mem_name(address, mem);
LOG_TRACE("{}: {} {} bytes, address {} ( {} ), value {}", log_hex((uint64_t)uc), type, size, log_hex(address), name, log_hex(value));
}
@ -80,15 +80,15 @@ static void log_memory_access(uc_engine *uc, const char *type, Address address,
static void read_hook(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) {
assert(value == 0);
const CPUState &state = *static_cast<const CPUState *>(user_data);
const MemState &mem = *state.mem;
CPUState &state = *static_cast<CPUState *>(user_data);
MemState &mem = *state.mem;
memcpy(&value, Ptr<const void>(static_cast<Address>(address)).get(mem), size);
log_memory_access(uc, "Read", static_cast<Address>(address), size, value, mem);
}
static void write_hook(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) {
const CPUState &state = *static_cast<const CPUState *>(user_data);
const MemState &mem = *state.mem;
CPUState &state = *static_cast<CPUState *>(user_data);
MemState &mem = *state.mem;
log_memory_access(uc, "Write", static_cast<Address>(address), size, value, mem);
}

View File

@ -17,6 +17,7 @@ src/ui_mutexes_dialog.cpp
src/ui_semaphores_dialog.cpp
src/ui_threads_dialog.cpp
src/ui_controls_dialog.cpp
src/ui_allocations_dialog.cpp
)
target_include_directories(gui PUBLIC include)

View File

@ -39,6 +39,7 @@ void DrawLwMutexesDialog(HostState &host);
void DrawLwCondvarsDialog(HostState &host);
void DrawCondvarsDialog(HostState &host);
void DrawEventFlagsDialog(HostState &host);
void DrawAllocationsDialog(HostState &host);
void DrawUI(HostState &host);
void DrawCommonDialog(HostState &host);
void DrawGameSelector(HostState &host, AppRunType *run_type);

View File

@ -20,6 +20,7 @@
#include <dialog/state.h>
struct ImFont;
struct MemoryEditor;
enum SelectorState {
SELECT_APP
@ -47,6 +48,7 @@ struct GuiState {
bool mutexes_dialog = false;
bool lwmutexes_dialog = false;
bool eventflags_dialog = false;
bool allocations_dialog = false;
// Optimisation menu
bool texture_cache = true;
@ -56,6 +58,8 @@ struct GuiState {
DialogState common_dialog;
GamesSelector game_selector;
MemoryEditor *memory_editor;
size_t memory_editor_start, memory_editor_count;
// imgui
ImFont *normal_font{};

View File

@ -0,0 +1,58 @@
#include <gui/functions.h>
#include <gui/gui_constants.h>
#include <imgui.h>
#include <imgui_memory_editor.h>
#include <host/state.h>
#include <spdlog/fmt/fmt.h>
void DrawAllocationsDialog(HostState &host) {
ImGui::Begin("Memory Allocations", &host.gui.allocations_dialog);
const std::lock_guard<std::mutex> lock(host.mem.generation_mutex);
for (const auto &pair : host.mem.generation_names) {
if (ImGui::TreeNode(fmt::format("{}: {}", pair.first, pair.second).c_str())) {
long index = -1, count = 1;
for (long a = 0; a < host.mem.allocated_pages.size(); a++) {
if (index != -1) {
if (host.mem.allocated_pages[a] != pair.first) break;
count++;
}
if (index == -1 && host.mem.allocated_pages[a] == pair.first) {
index = a;
}
}
if (index == -1) {
ImGui::Text("Generation no longer exists.");
} else {
ImGui::Text("Range %08lx - %08lx.", index * KB(4), (index + count) * KB(4));
ImGui::Text("Size: %li KB (%li page[s])", count * 4l, count);
if (index != 0) {
if (ImGui::Selectable("View/Edit")) {
host.gui.memory_editor_start = index * KB(4);
host.gui.memory_editor_count = count * KB(4);
if (!host.gui.memory_editor) host.gui.memory_editor = new MemoryEditor;
}
}
}
ImGui::TreePop();
}
}
if (host.gui.memory_editor) {
if (host.gui.memory_editor->Open) {
host.gui.memory_editor->DrawWindow("Editor", host.mem.memory.get() + host.gui.memory_editor_start,
host.gui.memory_editor_count, host.gui.memory_editor_start);
} else {
delete host.gui.memory_editor;
host.gui.memory_editor = nullptr;
}
}
ImGui::End();
}

View File

@ -116,5 +116,8 @@ void DrawUI(HostState &host) {
if (host.gui.controls_dialog) {
DrawControlsDialog(host);
}
if (host.gui.allocations_dialog) {
DrawAllocationsDialog(host);
}
ImGui::PopFont();
}

View File

@ -34,6 +34,7 @@ void DrawMainMenuBar(HostState &host) {
ImGui::MenuItem("Condition Variables", nullptr, &host.gui.condvars_dialog);
ImGui::MenuItem("Lightweight Condition Variables", nullptr, &host.gui.lwcondvars_dialog);
ImGui::MenuItem("Event Flags", nullptr, &host.gui.eventflags_dialog);
ImGui::MenuItem("Memory Allocations", nullptr, &host.gui.allocations_dialog);
ImGui::PopStyleColor();
ImGui::EndMenu();
}

View File

@ -19,6 +19,7 @@
#include <functional>
#include <map>
#include <mutex>
#include <memory>
#include <string>
#include <vector>
@ -34,6 +35,7 @@ struct MemState {
Generation generation = 0;
Memory memory;
Allocated allocated_pages;
std::mutex generation_mutex;
GenerationNames generation_names;
};
@ -54,4 +56,4 @@ Address alloc(MemState &state, size_t size, const char *name);
Address alloc_at(MemState &state, Address address, size_t size, const char *name);
void free(MemState &state, Address address);
uint32_t mem_available(MemState &state);
const char *mem_name(Address address, const MemState &state);
const char *mem_name(Address address, MemState &state);

View File

@ -48,6 +48,8 @@ static void alloc_inner(MemState &state, Address address, size_t page_count, All
const Generation generation = ++state.generation;
std::fill_n(block, page_count, generation);
const std::lock_guard<std::mutex> lock(state.generation_mutex);
state.generation_names[generation] = name;
#ifdef WIN32
@ -159,7 +161,7 @@ uint32_t mem_available(MemState &state) {
return address;
}
const char *mem_name(Address address, const MemState &state) {
const char *mem_name(Address address, MemState &state) {
const size_t page = address / state.page_size;
assert(page >= 0);
assert(page < state.allocated_pages.size());
@ -169,6 +171,7 @@ const char *mem_name(Address address, const MemState &state) {
return "UNALLOCATED";
}
const std::lock_guard<std::mutex> lock(state.generation_mutex);
const GenerationNames::const_iterator found = state.generation_names.find(generation);
assert(found != state.generation_names.end());
if (found == state.generation_names.end()) {

View File

@ -64,8 +64,10 @@ target_include_directories(microprofile PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/micr
set_property(TARGET microprofile PROPERTY CXX_STANDARD 11)
target_compile_definitions(microprofile PUBLIC MICROPROFILE_ENABLED=0 MICROPROFILE_GPU_TIMERS=0)
# The imgui target is including both imgui and imgui_club.
add_library(imgui STATIC imgui/imgui.cpp imgui/imgui_draw.cpp imgui/imgui_widgets.cpp)
target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/imgui")
target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/imgui"
"${CMAKE_CURRENT_SOURCE_DIR}/imgui_club/imgui_memory_editor/")
add_library(miniz STATIC miniz/miniz.c miniz/miniz.h)
target_include_directories(miniz PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/miniz")

1
src/external/imgui_club vendored Submodule

@ -0,0 +1 @@
Subproject commit 378e32ac92aa120512ee1aeb90522c9214e9b694