mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-06 23:39:31 +03:00
Windbg Extension improvments
- Add settings command - Fix help - Fix Arenas
This commit is contained in:
parent
f9bdcef9c5
commit
090ef45120
6 changed files with 124 additions and 36 deletions
|
@ -295,6 +295,7 @@ if(WIN32 AND MI_WIN_DBG_EXTS)
|
||||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_arenas.cpp)
|
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_arenas.cpp)
|
||||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_help.cpp)
|
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_help.cpp)
|
||||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_options.cpp)
|
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_options.cpp)
|
||||||
|
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_settings.cpp)
|
||||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_stats.cpp)
|
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_stats.cpp)
|
||||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_utils.cpp)
|
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_utils.cpp)
|
||||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg.cpp)
|
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg.cpp)
|
||||||
|
|
|
@ -79,6 +79,7 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK DebugExtensionInitialize(PULON
|
||||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_options\">Dump Options</link>\n");
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_options\">Dump Options</link>\n");
|
||||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_arenas\">Dump Arenas</link>\n");
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_arenas\">Dump Arenas</link>\n");
|
||||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_stats\">Dump Statistics</link>\n");
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_stats\">Dump Statistics</link>\n");
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_show_extension_settings\">Show Extension Settings</link>\n");
|
||||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_show_help\">Show Help commands</link>\n");
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_show_help\">Show Help commands</link>\n");
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,30 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||||
|
|
||||||
#include "mimalloc_windbg_utils.h"
|
#include "mimalloc_windbg_utils.h"
|
||||||
|
|
||||||
|
void PrintArenaSummary(double totalSlices, double totalCommittedSlices, double totalCommittedPages, double totalAbandonedPages) {
|
||||||
|
double pctCommitted = (totalSlices > 0) ? (totalCommittedSlices * 100.0 / totalSlices) : 0.0;
|
||||||
|
const auto arenaStats = std::format(" Total Slices: {}\n Committed Slices: {} ({}%)", totalSlices, totalCommittedSlices, pctCommitted);
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nAggregated Arena Statistics:\n%s\n", arenaStats.c_str());
|
||||||
|
|
||||||
|
const auto pageStats = std::format(" Committed Pages: {}\n Abandoned Pages: {}", totalCommittedPages, totalAbandonedPages);
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nAggregated Page Statistics:\n%s\n", pageStats.c_str());
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintAnomalyDetectionIfNeeded(double potentialFragmentation, double highAbandonedPagesRatio) {
|
||||||
|
if (potentialFragmentation < MinCommittedSlicesPct) {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, " Warning: Low committed slices percentage (%.2f%%). Potential fragmentation detected.\n", potentialFragmentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highAbandonedPagesRatio > MaxAbandonedPagesRatio) {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, " Warning: High ratio of abandoned pages (%.2f%%). Possible memory leak or delayed decommitment.\n", highAbandonedPagesRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (potentialFragmentation < MinCommittedSlicesPct || highAbandonedPagesRatio > MaxAbandonedPagesRatio) {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Command: !mi_dump_arenas
|
Command: !mi_dump_arenas
|
||||||
- Arenas are a fundamental component of mimalloc’s memory management.
|
- Arenas are a fundamental component of mimalloc’s memory management.
|
||||||
|
@ -115,30 +139,13 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_arenas(PDEBUG_CLIENT c
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nTotal Arenas: %d\n", arenaCount);
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nTotal Arenas: %d\n", arenaCount);
|
||||||
|
|
||||||
// Summary that aids in detecting fragmentation or undercommitment.
|
// Summary that aids in detecting fragmentation or undercommitment.
|
||||||
double pctCommitted = (totalSlices > 0) ? (totalCommittedSlices * 100.0 / totalSlices) : 0.0;
|
PrintArenaSummary(totalSlices, totalCommittedSlices, totalCommittedPages, totalAbandonedPages);
|
||||||
const auto arenaStats = std::format(" Total Slices: {}\n Committed Slices: {} ({}%)", totalSlices, totalCommittedSlices, pctCommitted);
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nAggregated Arena Statistics:\n%s\n", arenaStats.c_str());
|
|
||||||
|
|
||||||
const auto pageStats = std::format(" Committed Pages: {}\n Abandoned Pages: {}", totalCommittedPages, totalAbandonedPages);
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nAggregated Page Statistics:\n%s\n", pageStats.c_str());
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
|
||||||
|
|
||||||
for (size_t i = 0; i < arenaCount; ++i) {
|
for (size_t i = 0; i < arenaCount; ++i) {
|
||||||
ULONG64 arenaAddr = subprocMainAddr + offsetof(mi_subproc_t, arenas) + (i * sizeof(std::atomic<mi_arena_t*>));
|
ULONG64 arenaAddr = subprocMainAddr + offsetof(mi_subproc_t, arenas) + (i * sizeof(std::atomic<mi_arena_t*>));
|
||||||
PrintLink(arenaAddr, std::format("!mi_dump_arena 0x{:016X}", arenaAddr), std::format("Arena {}", i));
|
PrintLink(arenaAddr, std::format("!mi_dump_arena 0x{:016X}", arenaAddr), std::format("Arena {}", i));
|
||||||
|
|
||||||
if (potentialFragmentation[i] < MinCommittedSlicesPct) {
|
PrintAnomalyDetectionIfNeeded(potentialFragmentation[i], highAbandonedPagesRatio[i]);
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, " Warning: Low committed slices percentage (%.2f%%). Potential fragmentation detected.\n", potentialFragmentation[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highAbandonedPagesRatio[i] > MaxAbandonedPagesRatio) {
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, " Warning: High ratio of abandoned pages (%.2f%%). Possible memory leak or delayed decommitment.\n",
|
|
||||||
highAbandonedPagesRatio[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (potentialFragmentation[i] < MinCommittedSlicesPct || highAbandonedPagesRatio[i] > MaxAbandonedPagesRatio) {
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
@ -235,13 +242,7 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_arena(PDEBUG_CLIENT cl
|
||||||
totalAbandonedPages += abandonedPages;
|
totalAbandonedPages += abandonedPages;
|
||||||
|
|
||||||
// Summary that aids in detecting fragmentation or undercommitment.
|
// Summary that aids in detecting fragmentation or undercommitment.
|
||||||
double pctCommitted = (totalSlices > 0) ? (totalCommittedSlices * 100.0 / totalSlices) : 0.0;
|
PrintArenaSummary(totalSlices, totalCommittedSlices, totalCommittedPages, totalAbandonedPages);
|
||||||
const auto arenaStats = std::format(" Total Slices: {}\n Committed Slices: {} ({}%)", totalSlices, totalCommittedSlices, pctCommitted);
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nAggregated Arena Statistics:\n%s\n", arenaStats.c_str());
|
|
||||||
|
|
||||||
const auto pageStats = std::format(" Committed Pages: {}\n Abandoned Pages: {}", totalCommittedPages, totalAbandonedPages);
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\nAggregated Page Statistics:\n%s\n", pageStats.c_str());
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
|
||||||
|
|
||||||
// --- Anomaly Detection ---
|
// --- Anomaly Detection ---
|
||||||
float pctCommittedSlices = (arena.slice_count > 0) ? (committed * 100.0 / arena.slice_count) : 0.0;
|
float pctCommittedSlices = (arena.slice_count > 0) ? (committed * 100.0 / arena.slice_count) : 0.0;
|
||||||
|
@ -251,14 +252,8 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_arena(PDEBUG_CLIENT cl
|
||||||
abandonedPagesRatio = (abandonedPages * 100.0) / committedPages;
|
abandonedPagesRatio = (abandonedPages * 100.0) / committedPages;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pctCommittedSlices < MinCommittedSlicesPct) {
|
PrintAnomalyDetectionIfNeeded(pctCommittedSlices, abandonedPagesRatio);
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, " Warning: Low committed slices percentage (%.2f%%). Potential fragmentation detected.\n", pctCommittedSlices);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abandonedPagesRatio > MaxAbandonedPagesRatio) {
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, " Warning: High ratio of abandoned pages (%.2f%%). Possible memory leak or delayed decommitment.\n", abandonedPagesRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
|
@ -15,9 +15,17 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_show_help(PDEBUG_CLIENT cli
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
|
||||||
// Print Help
|
// Print Help
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Hello from MiMalloc WinDbg Extension!\n");
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Hello from MiMalloc WinDbg Extension!\n");
|
||||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Start here:\n");
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Start here:\n");
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_options\">Dump Options</link>\n");
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_arenas\">Dump Arenas</link>\n");
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_stats\">Dump Statistics</link>\n");
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_show_extension_settings\">Show Extension Settings</link>\n");
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_show_help\">Show Help commands</link>\n");
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
83
src/prim/windows/windbg/mimalloc_windbg_settings.cpp
Normal file
83
src/prim/windows/windbg/mimalloc_windbg_settings.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
Copyright (c) Microsoft Research
|
||||||
|
This is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the MIT license. A copy of the license can be found in the file
|
||||||
|
"LICENSE" at the root of this distribution.
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "mimalloc_windbg_utils.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Command: !mi_show_extension_settings
|
||||||
|
*/
|
||||||
|
extern "C" __declspec(dllexport) HRESULT CALLBACK mi_show_extension_settings(PDEBUG_CLIENT client, PCSTR args) {
|
||||||
|
UNREFERENCED_PARAMETER(args);
|
||||||
|
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL,
|
||||||
|
std::format("{:<30} {:<10} {}\n", "MinCommittedSlicesPct", MinCommittedSlicesPct, "When below threshold, potential fragmentation.").c_str());
|
||||||
|
|
||||||
|
g_DebugControl->ControlledOutput(
|
||||||
|
DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL,
|
||||||
|
std::format("{:<30} {:<10} {}\n", "MaxAbandonedPagesRatio", MaxAbandonedPagesRatio, "When abandoned pages exceeds ratio of committed pages, potential leak.").c_str());
|
||||||
|
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
|
||||||
|
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL,
|
||||||
|
"Use <b>!mi_set_extension_setting <setting> <value></b> to set a new value for the setting.\n");
|
||||||
|
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Command: !mi_set_extension_setting
|
||||||
|
*/
|
||||||
|
extern "C" __declspec(dllexport) HRESULT CALLBACK mi_set_extension_setting(PDEBUG_CLIENT client, PCSTR args) {
|
||||||
|
if (!args || !*args) {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "Usage: !mi_set_extension_setting <setting> <value>\n");
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||||
|
|
||||||
|
char fieldName[64];
|
||||||
|
char valueStr[64];
|
||||||
|
|
||||||
|
// Parse the input arguments
|
||||||
|
if (sscanf_s(args, "%63s %63s", fieldName, (unsigned)_countof(fieldName), valueStr, (unsigned)_countof(valueStr)) != 2) {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Invalid input format. Expected: !mi_set_extension_setting <setting> <value>\n");
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
// Update the setting based on the field name
|
||||||
|
if (strcmp(fieldName, "MinCommittedSlicesPct") == 0) {
|
||||||
|
double doubleValue = 0.0;
|
||||||
|
if (sscanf_s(valueStr, "%lf", &doubleValue) != 1 || doubleValue < 0 || doubleValue > 100) {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Value must be an value between 0 and 100.\n");
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
MinCommittedSlicesPct = doubleValue;
|
||||||
|
} else if (strcmp(fieldName, "MaxAbandonedPagesRatio") == 0) {
|
||||||
|
double doubleValue = 0.0;
|
||||||
|
if (sscanf_s(valueStr, "%lf", &doubleValue) != 1 || doubleValue < 0.0 || doubleValue > 1.0) {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Value must be a value between 0.0 and 1.0.\n");
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaxAbandonedPagesRatio = doubleValue;
|
||||||
|
} else {
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Invalid field name. Allowed fields: MinCommittedSlicesPct, MaxAbandonedPagesRatio\n");
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Successfully updated %s to %s\n", fieldName, valueStr);
|
||||||
|
return S_OK;
|
||||||
|
}
|
|
@ -25,8 +25,8 @@ extern IDebugControl4* g_DebugControl;
|
||||||
extern IDebugSymbols3* g_DebugSymbols;
|
extern IDebugSymbols3* g_DebugSymbols;
|
||||||
extern IDebugDataSpaces* g_DataSpaces;
|
extern IDebugDataSpaces* g_DataSpaces;
|
||||||
|
|
||||||
constexpr double MinCommittedSlicesPct = 60.0; // if below threshold, potential fragmentation.
|
static inline double MinCommittedSlicesPct = 60.0; // if below threshold, potential fragmentation.
|
||||||
constexpr double MaxAbandonedPagesRatio = 0.4; // If abandoned pages exceed 40% of committed pages.
|
static inline double MaxAbandonedPagesRatio = 0.4; // If abandoned pages exceed 40% of committed pages.
|
||||||
|
|
||||||
HRESULT FindMimallocBase();
|
HRESULT FindMimallocBase();
|
||||||
HRESULT GetSymbolOffset(const char* symbolName, ULONG64& outOffset);
|
HRESULT GetSymbolOffset(const char* symbolName, ULONG64& outOffset);
|
||||||
|
|
Loading…
Add table
Reference in a new issue