Updated the SegmentedPool to allow for zeroing of allocations and for returning a pointer to allocated memory to allow for use in unsafe structs
This commit is contained in:
170
UnmangedMMU/Diagnostics/SegmentedPoolDiagnostics.cs
Normal file
170
UnmangedMMU/Diagnostics/SegmentedPoolDiagnostics.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using static UnmanagedMMU.SegmentedPool;
|
||||
|
||||
namespace UnmanagedMMU.Diagnostics
|
||||
{
|
||||
/// <summary>
|
||||
/// Static helper class for generating diagnostics and suggestions for SegmentedPool.
|
||||
/// Separates report generation logic from the pool implementation.
|
||||
/// </summary>
|
||||
public static class SegmentedPoolDiagnostics
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a formatted report string including suggestions.
|
||||
/// </summary>
|
||||
public static string GenerateReport(PoolState state)
|
||||
{
|
||||
string status = state.BaseAligned ? "OK" : "FAIL";
|
||||
string segmentStatus = $"{state.ActiveSegmentCount} active, {state.FreeSegmentCount} free";
|
||||
|
||||
double efficiency = (state.TotalUsed + state.PaddingBytes) > 0
|
||||
? (100.0 * state.TotalUsed / (state.TotalUsed + state.PaddingBytes))
|
||||
: 100.0;
|
||||
|
||||
string efficiencyLabel = GetEfficiencyLabel(efficiency, state.SegmentAlignment);
|
||||
|
||||
string suggestionLine = state.Suggestion;
|
||||
if (!string.IsNullOrEmpty(suggestionLine))
|
||||
{
|
||||
suggestionLine = $"\n {suggestionLine}";
|
||||
}
|
||||
|
||||
return $"=== SegmentedPool Diagnostics ===\n" +
|
||||
$" Configuration\n" +
|
||||
$" Segment Alignment: {state.SegmentAlignment} bytes (Min Base Alignment)\n" +
|
||||
$" Segment Size: {FormatBytes(state.SegmentSize)}\n" +
|
||||
$" Segment Summary\n" +
|
||||
$" Total Segments: {state.TotalSegmentCount} ({segmentStatus})\n" +
|
||||
$" Potential Savings: {FormatBytes(state.PotentialSavings)} (via Trim())\n" +
|
||||
$" Current Segment\n" +
|
||||
$" Base Address: 0x{(nuint)state.CurrentBase:x}\n" +
|
||||
$" Offset: {state.CurrentOffset} bytes\n" +
|
||||
$" Base Alignment: {status} (To {state.SegmentAlignment} bytes)\n" +
|
||||
$" Memory Statistics\n" +
|
||||
$" Total Reserved: {FormatBytes(state.TotalReserved)}\n" +
|
||||
$" Total Used: {FormatBytes(state.TotalUsed)}\n" +
|
||||
$" Efficiency: {efficiency:F0}% ({efficiencyLabel})\n" +
|
||||
$" Padding Overhead: {FormatBytes(state.PaddingBytes)}\n" +
|
||||
$" Allocation Breakdown\n" +
|
||||
$" Data Bytes: {FormatBytes(state.TotalUsed)}\n" +
|
||||
$" Alignment Padding: {FormatBytes(state.PaddingBytes)}\n" +
|
||||
$" Total Segment Space: {FormatBytes(state.CurrentOffset)}\n" +
|
||||
$" Action Required:{suggestionLine}";
|
||||
}
|
||||
|
||||
private static string GetEfficiencyLabel(double efficiency, nuint segmentAlignment)
|
||||
{
|
||||
int threshold = segmentAlignment switch
|
||||
{
|
||||
8 => 50,
|
||||
16 => 60,
|
||||
32 => 75,
|
||||
64 => 85,
|
||||
_ => 90
|
||||
};
|
||||
|
||||
if (efficiency >= 100) return "Perfect";
|
||||
if (efficiency >= threshold) return "Good";
|
||||
return "High Overhead";
|
||||
}
|
||||
|
||||
private static string FormatBytes(nuint bytes)
|
||||
{
|
||||
if (bytes >= 1073741824) return $"{bytes / 1073741824} GiB";
|
||||
if (bytes >= 1048576) return $"{bytes / 1048576} MiB";
|
||||
if (bytes >= 1024) return $"{bytes / 1024} KiB";
|
||||
return $"{bytes} B";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates actionable suggestions based on pool metrics.
|
||||
/// Comprehensive coverage of all pool states.
|
||||
/// </summary>
|
||||
public static string GenerateSuggestions(PoolState state, DiagnosticConfig config)
|
||||
{
|
||||
// === CRITICAL ISSUES ===
|
||||
|
||||
// 1. Base alignment broken (should never happen)
|
||||
if (!state.BaseAligned)
|
||||
{
|
||||
return "CRITICAL: Segment base not aligned to configured boundary. This indicates a memory management bug.";
|
||||
}
|
||||
|
||||
// === HIGH PRIORITY ===
|
||||
|
||||
// 2. Pool exhausted (Next alloc blocks)
|
||||
if (state.FreeSegmentCount == 0)
|
||||
{
|
||||
return "INFO: No free segments available. Next allocation will block. Call Reset() to recycle segments or increase initialSegments.";
|
||||
}
|
||||
|
||||
// 3. Significant Memory Waste (Trim Opportunity)
|
||||
if (state.PotentialSavings > 0)
|
||||
{
|
||||
double wasteRatio = (double)state.PotentialSavings / state.TotalReserved;
|
||||
if (wasteRatio > 0.50)
|
||||
{
|
||||
return $"ACTION: {state.FreeSegmentCount - 16} excess segments can be freed. Calling Trim() will recover {FormatBytes(state.PotentialSavings)} ({(wasteRatio * 100):F0}% of reserved memory).";
|
||||
}
|
||||
if (state.PotentialSavings > 1024 * 1024)
|
||||
{
|
||||
return $"ACTION: Excess free segments ({state.FreeSegmentCount}). Calling Trim() will recover {FormatBytes(state.PotentialSavings)}. Current usage: {FormatBytes(state.TotalUsed)} of {FormatBytes(state.TotalReserved)}. Efficiency: {(state.TotalUsed / state.TotalReserved) * 100:F0}%.";
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Efficiency Issues (Alignment Mismatch)
|
||||
double efficiency = (state.TotalUsed + state.PaddingBytes) > 0
|
||||
? (100.0 * state.TotalUsed / (state.TotalUsed + state.PaddingBytes))
|
||||
: 100.0;
|
||||
|
||||
int threshold = state.SegmentAlignment switch
|
||||
{
|
||||
8 => 50,
|
||||
16 => 60,
|
||||
32 => 75,
|
||||
64 => 85,
|
||||
_ => 90
|
||||
};
|
||||
|
||||
if (efficiency < threshold)
|
||||
{
|
||||
if (state.SegmentAlignment <= 32)
|
||||
{
|
||||
return $"Suggestion: Current alignment ({state.SegmentAlignment}B) is low. Increase to 32B for better efficiency.";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"Suggestion: Verify allocation alignment matches segment base ({state.SegmentAlignment}B). Efficiency is {efficiency:F0}%.";
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Segment Nearly Full
|
||||
if (config.SegmentSize > 0 && state.CurrentOffset > config.SegmentSize * 0.90)
|
||||
{
|
||||
return "INFO: Current segment nearly full. Consider Reset() to reuse this segment instead of allocating a new one.";
|
||||
}
|
||||
|
||||
// === LOW PRIORITY / OPTIONAL ===
|
||||
|
||||
// 6. Low Utilization (Memory Bloat)
|
||||
if (state.TotalReserved > 16 * 1024 * 1024)
|
||||
{
|
||||
double usageRatio = (double)state.TotalUsed / state.TotalReserved;
|
||||
if (usageRatio < 0.10)
|
||||
{
|
||||
return $"INFO: Low memory utilization ({usageRatio:P0}). Consider Reset() or Trim() to reduce footprint.";
|
||||
}
|
||||
}
|
||||
|
||||
return "Pool operating normally.";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration details passed to diagnostics for context-aware suggestions.
|
||||
/// </summary>
|
||||
public readonly struct DiagnosticConfig
|
||||
{
|
||||
public nuint SegmentSize { get; init; }
|
||||
public nuint TotalReserved { get; init; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user