Updated the SegmentedPool to allow for zeroing of allocations and for returning a pointer to allocated memory to allow for use in unsafe structs (#2)

This commit was merged in pull request #2.
This commit is contained in:
Jim
2026-03-20 17:51:15 +00:00
parent dfbdf905fe
commit c2150acb2c
15 changed files with 2788 additions and 674 deletions

View 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; }
}
}