Stan44 becedccadd updated memory memory handling to be more safe.
added some missing function.
added XML documentation formatting.
added MemoryUsageReporter to track memory usage.
added ChunkMark Benchmarking tool to benchmark the performance of the chunk manager.
added ChunkMark MemoryReporter to track memory usage.

fixed some bugs.
2025-05-10 02:36:54 -05:00

720 lines
34 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using AdvChkSys;
using AdvChkSys.Chunk;
using AdvChkSys.Manager;
using AdvChkSys.Constraints;
using AdvChkSys.Diagnostics;
namespace ChunkMark
{
public static class Program
{
private static readonly ConsoleColor _headerColor = ConsoleColor.Cyan;
private static readonly ConsoleColor _resultColor = ConsoleColor.Green;
private static readonly ConsoleColor _memoryColor = ConsoleColor.Yellow;
private static readonly ConsoleColor _errorColor = ConsoleColor.Red;
private static readonly ConsoleColor _infoColor = ConsoleColor.Gray;
private static List<BenchmarkResult> _results = new List<BenchmarkResult>();
private static bool _verboseMode = false;
public static void Main(string[] args)
{
int cpuCount = Environment.ProcessorCount;
int num2DChunks = 10000;
int chunk2DSize = 32;
int num3DChunks = 500;
int chunk3DWidth = 16, chunk3DHeight = 16, chunk3DDepth = 16;
int maxLoaded = 100000;
bool run2D = true, run3D = true;
bool runMemoryTest = false;
bool runStressTest = false;
// Parse args
foreach (var arg in args)
{
if (arg.StartsWith("--cpus=")) cpuCount = int.Parse(arg.Substring(7));
if (arg.StartsWith("--2d-chunks=")) num2DChunks = int.Parse(arg.Substring(12));
if (arg.StartsWith("--2d-size=")) chunk2DSize = int.Parse(arg.Substring(10));
if (arg.StartsWith("--3d-chunks=")) num3DChunks = int.Parse(arg.Substring(12));
if (arg.StartsWith("--3d-width=")) chunk3DWidth = int.Parse(arg.Substring(11));
if (arg.StartsWith("--3d-height=")) chunk3DHeight = int.Parse(arg.Substring(12));
if (arg.StartsWith("--3d-depth=")) chunk3DDepth = int.Parse(arg.Substring(11));
if (arg.StartsWith("--3d-size="))
{
int val = int.Parse(arg.Substring(10));
chunk3DWidth = chunk3DHeight = chunk3DDepth = val;
}
if (arg.StartsWith("--max-loaded=")) maxLoaded = int.Parse(arg.Substring(13));
if (arg == "--2d-only") { run3D = false; }
if (arg == "--3d-only") { run2D = false; }
if (arg == "--memory-test") { runMemoryTest = true; }
if (arg == "--stress-test") { runStressTest = true; }
if (arg == "--verbose") { _verboseMode = true; }
}
PrintHeader();
if (run2D)
Benchmark2D(cpuCount, num2DChunks, chunk2DSize, maxLoaded);
if (run3D)
{
while (true)
{
if (!CanAllocateChunks(num3DChunks, chunk3DWidth, chunk3DHeight, chunk3DDepth, 0.82))
{
long bytesPerChunk = (long)chunk3DWidth * chunk3DHeight * chunk3DDepth;
long totalBytes = bytesPerChunk * num3DChunks;
long available = GetAvailableMemoryBytes();
long safeLimit = (long)(available * 0.82);
Console.ForegroundColor = _errorColor;
Console.WriteLine($"ERROR: Requested 3D chunks would use {totalBytes / (1024 * 1024):N0} MB, but only {safeLimit / (1024 * 1024):N0} MB is safely available.");
Console.WriteLine("Please input new values for 3D chunks and size within your system's memory capacity.");
Console.ResetColor();
Console.ForegroundColor = _infoColor; // Using _infoColor here
Console.Write("Enter number of 3D chunks (or blank to exit): ");
Console.ResetColor();
var chunksInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(chunksInput))
{
Console.WriteLine("Exiting benchmark.");
break;
}
if (!int.TryParse(chunksInput, out num3DChunks) || num3DChunks <= 0)
{
Console.WriteLine("Invalid input. Exiting.");
break;
}
Console.ForegroundColor = _infoColor; // Using _infoColor here
Console.Write("Enter 3D chunk width: ");
Console.ResetColor();
var widthInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(widthInput) || !int.TryParse(widthInput, out chunk3DWidth) || chunk3DWidth <= 0)
{
Console.WriteLine("Invalid input. Exiting.");
break;
}
Console.ForegroundColor = _infoColor; // Using _infoColor here
Console.Write("Enter 3D chunk height: ");
Console.ResetColor();
var heightInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(heightInput) || !int.TryParse(heightInput, out chunk3DHeight) || chunk3DHeight <= 0)
{
Console.WriteLine("Invalid input. Exiting.");
break;
}
Console.ForegroundColor = _infoColor; // Using _infoColor here
Console.Write("Enter 3D chunk depth: ");
Console.ResetColor();
var depthInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(depthInput) || !int.TryParse(depthInput, out chunk3DDepth) || chunk3DDepth <= 0)
{
Console.WriteLine("Invalid input. Exiting.");
break;
}
Console.WriteLine();
// Loop will re-check with new values
}
else
{
try
{
Benchmark3D(cpuCount, num3DChunks, chunk3DWidth, chunk3DHeight, chunk3DDepth, maxLoaded);
}
catch (OutOfMemoryException)
{
Console.ForegroundColor = _errorColor;
Console.WriteLine("ERROR: Out of memory during 3D chunk allocation. Reduce chunk size or count.");
Console.ResetColor();
}
break;
}
}
}
if (runMemoryTest)
{
RunMemoryTest(cpuCount, chunk2DSize, chunk3DWidth, chunk3DHeight, chunk3DDepth);
}
if (runStressTest)
{
RunStressTest(cpuCount, chunk2DSize, chunk3DWidth, chunk3DHeight, chunk3DDepth);
}
PrintSummary();
Console.ForegroundColor = _infoColor; // Using _infoColor here
Console.WriteLine("\nDone. Press any key to exit.");
Console.ResetColor();
Console.ReadKey();
}
private static void PrintHeader()
{
Console.ForegroundColor = _headerColor;
Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
Console.WriteLine("║ ChunkMark: AdvChkSys Benchmark ║");
Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
Console.ResetColor();
Console.WriteLine($"Library version: {AdvChkSys.AdvChkSys.Version}");
Console.WriteLine($"CPU threads: {Environment.ProcessorCount}");
Console.WriteLine($"System memory: {FormatByteSize(AdvChkSys.AdvChkSys.GetMemoryUsage().TotalSystemMemoryBytes)}");
Console.WriteLine($"Available memory: {FormatByteSize(AdvChkSys.AdvChkSys.GetMemoryUsage().AvailableSystemMemoryBytes)}");
Console.WriteLine();
}
private static void PrintSummary()
{
Console.WriteLine();
Console.ForegroundColor = _headerColor;
Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
Console.WriteLine("║ Benchmark Summary ║");
Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
Console.ResetColor();
if (_results.Count == 0)
{
Console.WriteLine("No benchmark results to display.");
return;
}
var table = new StringBuilder();
table.AppendLine("┌────────────────┬─────────────┬────────────┬────────────┬────────────┐");
table.AppendLine("│ Test │ Chunks │ Create │ Access │ Unload │");
table.AppendLine("├────────────────┼─────────────┼────────────┼────────────┼────────────┤");
foreach (var result in _results)
{
string testName = result.TestName.PadRight(14).Substring(0, 14);
string chunkInfo = result.ChunkCount.ToString("N0").PadRight(11).Substring(0, 11);
string createTime = $"{result.CreateTime:F3} s".PadRight(10).Substring(0, 10);
string accessTime = $"{result.AccessTime:F3} s".PadRight(10).Substring(0, 10);
string unloadTime = $"{result.UnloadTime:F3} s".PadRight(10).Substring(0, 10);
table.AppendLine($"│ {testName} │ {chunkInfo} │ {createTime} │ {accessTime} │ {unloadTime} │");
}
table.AppendLine("└────────────────┴─────────────┴────────────┴────────────┴────────────┘");
Console.WriteLine(table.ToString());
// Calculate and display performance metrics
if (_results.Count > 0)
{
Console.ForegroundColor = _resultColor;
Console.WriteLine("Performance Metrics:");
Console.ResetColor();
var create2DRate = _results.Where(r => r.TestName.Contains("2D")).Select(r => r.ChunkCount / r.CreateTime).FirstOrDefault();
var create3DRate = _results.Where(r => r.TestName.Contains("3D")).Select(r => r.ChunkCount / r.CreateTime).FirstOrDefault();
if (create2DRate > 0)
Console.WriteLine($"2D Chunk Creation Rate: {create2DRate:N0} chunks/second");
if (create3DRate > 0)
Console.WriteLine($"3D Chunk Creation Rate: {create3DRate:N0} chunks/second");
}
}
private static void Benchmark2D(int cpuCount, int numChunks, int chunkSize, int maxLoaded)
{
Console.ForegroundColor = _headerColor;
Console.WriteLine($"[2D] {numChunks:N0} chunks of size {chunkSize}x{chunkSize}, maxLoaded={maxLoaded:N0}");
Console.ResetColor();
var constraints = new WorldConstraints
{
MinChunkX = 0,
MaxChunkX = 9999,
MinChunkY = 0,
MaxChunkY = 9999,
MaxLoadedChunks = maxLoaded
};
var manager = new ChunkManager2D<byte>(constraints, maxLoaded);
// Memory before test
var memoryBefore = AdvChkSys.AdvChkSys.GetMemoryUsage();
if (_verboseMode)
{
Console.ForegroundColor = _memoryColor;
Console.WriteLine($" Memory before: {FormatByteSize(memoryBefore.EstimatedChunkMemoryBytes)}");
Console.ResetColor();
}
// Create and fill
var sw = Stopwatch.StartNew();
Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
{
int x = i % 1000, y = i / 1000;
var chunk = manager.LoadOrCreateChunk(x, y, chunkSize, chunkSize);
for (int cx = 0; cx < chunkSize; cx++)
for (int cy = 0; cy < chunkSize; cy++)
chunk[cx, cy] = (byte)((cx + cy) % 256);
});
sw.Stop();
double createTime = sw.Elapsed.TotalSeconds;
Console.WriteLine($" Created and filled {numChunks:N0} chunks in {createTime:F3} s");
// Memory after creation
var memoryAfterCreate = AdvChkSys.AdvChkSys.GetMemoryUsage();
if (_verboseMode)
{
Console.ForegroundColor = _memoryColor;
Console.WriteLine($" Memory after creation: {FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes)} " +
$"(+{FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
Console.ResetColor();
}
// Access (sum all cells)
sw.Restart();
long total = 0;
Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, () => 0L,
(i, state, localSum) =>
{
int x = i % 1000, y = i / 1000;
var chunk = manager.GetChunk(x, y);
if (chunk != null)
{
for (int cx = 0; cx < chunkSize; cx++)
for (int cy = 0; cy < chunkSize; cy++)
localSum += chunk[cx, cy];
}
return localSum;
},
localSum => Interlocked.Add(ref total, localSum)
);
sw.Stop();
double accessTime = sw.Elapsed.TotalSeconds;
Console.WriteLine($" Accessed {numChunks:N0} chunks in {accessTime:F3} s (sum: {total:N0})");
// Unload
sw.Restart();
Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
{
int x = i % 1000, y = i / 1000;
manager.UnloadChunk(x, y);
});
sw.Stop();
double unloadTime = sw.Elapsed.TotalSeconds;
Console.WriteLine($" Unloaded {numChunks:N0} chunks in {unloadTime:F3} s");
// Memory after test
var memoryAfter = AdvChkSys.AdvChkSys.GetMemoryUsage();
if (_verboseMode)
{
Console.ForegroundColor = _memoryColor;
Console.WriteLine($" Memory after unload: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes)} " +
$"(change: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
Console.ResetColor();
}
// Store results
_results.Add(new BenchmarkResult
{
TestName = "2D Chunks",
ChunkCount = numChunks,
ChunkSize = $"{chunkSize}x{chunkSize}",
CreateTime = createTime,
AccessTime = accessTime,
UnloadTime = unloadTime,
MemoryUsed = memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes
});
// Force GC to clean up
GC.Collect();
GC.WaitForPendingFinalizers();
}
private static void Benchmark3D(int cpuCount, int numChunks, int width, int height, int depth, int maxLoaded)
{
Console.ForegroundColor = _headerColor;
Console.WriteLine($"[3D] {numChunks:N0} chunks of size {width}x{height}x{depth}, maxLoaded={maxLoaded:N0}");
Console.ResetColor();
var constraints = new WorldConstraints
{
MinChunkX = 0,
MaxChunkX = 9999,
MinChunkY = 0,
MaxChunkY = 9999,
MaxLoadedChunks = maxLoaded
};
var manager = new ChunkManager3D<byte>(constraints, maxLoaded);
// Memory before test
var memoryBefore = AdvChkSys.AdvChkSys.GetMemoryUsage();
if (_verboseMode)
{
Console.ForegroundColor = _memoryColor;
Console.WriteLine($" Memory before: {FormatByteSize(memoryBefore.EstimatedChunkMemoryBytes)}");
Console.ResetColor();
}
// Create and fill
var sw = Stopwatch.StartNew();
Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
{
int x = i % 100, y = i / 100 % 100, z = i / 10000;
var chunk = manager.LoadOrCreateChunk(x, y, z, width, height, depth);
for (int cx = 0; cx < width; cx++)
for (int cy = 0; cy < height; cy++)
for (int cz = 0; cz < depth; cz++)
chunk[cx, cy, cz] = (byte)((cx + cy + cz) % 256);
});
sw.Stop();
double createTime = sw.Elapsed.TotalSeconds;
Console.WriteLine($" Created and filled {numChunks:N0} chunks in {createTime:F3} s");
// Memory after creation
var memoryAfterCreate = AdvChkSys.AdvChkSys.GetMemoryUsage();
if (_verboseMode)
{
Console.ForegroundColor = _memoryColor;
Console.WriteLine($" Memory after creation: {FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes)} " +
$"(+{FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
Console.ResetColor();
}
// Access (sum all cells)
sw.Restart();
long total = 0;
Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, () => 0L,
(i, state, localSum) =>
{
int x = i % 100, y = i / 100 % 100, z = i / 10000;
var chunk = manager.GetChunk(x, y, z);
if (chunk != null)
{
for (int cx = 0; cx < width; cx++)
for (int cy = 0; cy < height; cy++)
for (int cz = 0; cz < depth; cz++)
localSum += chunk[cx, cy, cz];
}
return localSum;
},
localSum => Interlocked.Add(ref total, localSum)
);
sw.Stop();
double accessTime = sw.Elapsed.TotalSeconds;
Console.WriteLine($" Accessed {numChunks:N0} chunks in {accessTime:F3} s (sum: {total:N0})");
// Unload
sw.Restart();
Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
{
int x = i % 100, y = i / 100 % 100, z = i / 10000;
manager.UnloadChunk(x, y, z);
});
sw.Stop();
double unloadTime = sw.Elapsed.TotalSeconds;
Console.WriteLine($" Unloaded {numChunks:N0} chunks in {unloadTime:F3} s");
// Memory after test
var memoryAfter = AdvChkSys.AdvChkSys.GetMemoryUsage();
if (_verboseMode)
{
Console.ForegroundColor = _memoryColor;
Console.WriteLine($" Memory after unload: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes)} " +
$"(change: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
Console.ResetColor();
}
// Store results
_results.Add(new BenchmarkResult
{
TestName = "3D Chunks",
ChunkCount = numChunks,
ChunkSize = $"{width}x{height}x{depth}",
CreateTime = createTime,
AccessTime = accessTime,
UnloadTime = unloadTime,
MemoryUsed = memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes
});
// Force GC to clean up
GC.Collect();
GC.WaitForPendingFinalizers();
}
private static void RunMemoryTest(int cpuCount, int chunk2DSize, int chunk3DWidth, int chunk3DHeight, int chunk3DDepth)
{
Console.ForegroundColor = _headerColor;
Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
Console.WriteLine("║ Memory Usage Test ║");
Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
Console.ResetColor();
// Initial memory state
var initialMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
Console.WriteLine($"Initial memory state: {FormatByteSize(initialMemory.EstimatedChunkMemoryBytes)}");
// Test 2D memory scaling
Console.ForegroundColor = _headerColor;
Console.WriteLine("\n[2D Memory Scaling Test]");
Console.ResetColor();
var manager2D = new ChunkManager2D<byte>(null, 1000000);
var memoryPoints2D = new List<(int chunkCount, ulong memoryUsed)>();
for (int i = 1; i <= 10; i++)
{
int chunkCount = i * 1000;
Console.WriteLine($" Loading {chunkCount:N0} 2D chunks...");
for (int j = (i - 1) * 1000; j < i * 1000; j++)
{
int x = j % 1000, y = j / 1000;
var chunk = manager2D.LoadOrCreateChunk(x, y, chunk2DSize, chunk2DSize);
// Fill with some data
for (int cx = 0; cx < chunk2DSize; cx++)
for (int cy = 0; cy < chunk2DSize; cy++)
chunk[cx, cy] = (byte)((cx + cy) % 256);
}
var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
memoryPoints2D.Add((chunkCount, memoryReport.EstimatedChunkMemoryBytes));
Console.WriteLine($" Memory used: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}");
}
// Clean up 2D chunks
manager2D = null;
GC.Collect();
GC.WaitForPendingFinalizers();
// Test 3D memory scaling
Console.ForegroundColor = _headerColor;
Console.WriteLine("\n[3D Memory Scaling Test]");
Console.ResetColor();
var manager3D = new ChunkManager3D<byte>(null, 1000000);
var memoryPoints3D = new List<(int chunkCount, ulong memoryUsed)>();
for (int i = 1; i <= 5; i++)
{
int chunkCount = i * 10;
Console.WriteLine($" Loading {chunkCount:N0} 3D chunks...");
for (int j = (i - 1) * 10; j < i * 10; j++)
{
int x = j % 10, y = j / 10 % 10, z = j / 100;
var chunk = manager3D.LoadOrCreateChunk(x, y, z, chunk3DWidth, chunk3DHeight, chunk3DDepth);
// Fill with some data
for (int cx = 0; cx < chunk3DWidth; cx++)
for (int cy = 0; cy < chunk3DHeight; cy++)
for (int cz = 0; cz < chunk3DDepth; cz++)
chunk[cx, cy, cz] = (byte)((cx + cy + cz) % 256);
}
var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
memoryPoints3D.Add((chunkCount, memoryReport.EstimatedChunkMemoryBytes));
Console.WriteLine($" Memory used: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}");
}
// Clean up 3D chunks
manager3D = null;
GC.Collect();
GC.WaitForPendingFinalizers();
// Display memory scaling results
Console.ForegroundColor = _headerColor;
Console.WriteLine("\n[Memory Scaling Results]");
Console.ResetColor();
Console.WriteLine("2D Memory Scaling:");
for (int i = 0; i < memoryPoints2D.Count; i++)
{
var point = memoryPoints2D[i];
ulong bytesPerChunk = i > 0
? (point.memoryUsed - memoryPoints2D[i - 1].memoryUsed) / (ulong)(point.chunkCount - memoryPoints2D[i - 1].chunkCount)
: point.memoryUsed / (ulong)point.chunkCount;
Console.WriteLine($" {point.chunkCount:N0} chunks: {FormatByteSize(point.memoryUsed)} " +
$"(~{FormatByteSize(bytesPerChunk)}/chunk)");
}
Console.WriteLine("\n3D Memory Scaling:");
for (int i = 0; i < memoryPoints3D.Count; i++)
{
var point = memoryPoints3D[i];
ulong bytesPerChunk = i > 0
? (point.memoryUsed - memoryPoints3D[i - 1].memoryUsed) / (ulong)(point.chunkCount - memoryPoints3D[i - 1].chunkCount)
: point.memoryUsed / (ulong)point.chunkCount;
Console.WriteLine($" {point.chunkCount:N0} chunks: {FormatByteSize(point.memoryUsed)} " +
$"(~{FormatByteSize(bytesPerChunk)}/chunk)");
}
// Final memory state
var finalMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
Console.WriteLine($"\nFinal memory state: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes)}");
Console.WriteLine($"Memory change: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes - initialMemory.EstimatedChunkMemoryBytes)}");
}
private static void RunStressTest(int cpuCount, int chunk2DSize, int chunk3DWidth, int chunk3DHeight, int chunk3DDepth)
{
Console.ForegroundColor = _headerColor;
Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
Console.WriteLine("║ Stress Test ║");
Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
Console.ResetColor();
// Initial memory state
var initialMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
// Create managers with small cache size to force evictions
var manager2D = new ChunkManager2D<byte>(null, 100);
var manager3D = new ChunkManager3D<byte>(null, 50);
Console.WriteLine("Running load/unload stress test (rapid chunk cycling)...");
var sw = Stopwatch.StartNew();
int iterations = 5;
int chunksPerIteration = 500;
for (int iter = 0; iter < iterations; iter++)
{
Console.WriteLine($" Iteration {iter + 1}/{iterations}...");
// 2D stress
Parallel.For(0, chunksPerIteration, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
{
int x = i % 100, y = i / 100;
// Load chunk
var chunk = manager2D.LoadOrCreateChunk(x, y, chunk2DSize, chunk2DSize);
// Fill with data
for (int cx = 0; cx < chunk2DSize; cx++)
for (int cy = 0; cy < chunk2DSize; cy++)
chunk[cx, cy] = (byte)((cx + cy + i) % 256);
// Access chunk
long sum = 0;
for (int cx = 0; cx < chunk2DSize; cx++)
for (int cy = 0; cy < chunk2DSize; cy++)
sum += chunk[cx, cy];
// Force some evictions by loading other chunks
for (int j = 0; j < 3; j++)
{
int otherX = (i + j * 200) % 1000;
int otherY = (i + j * 200) / 1000;
var otherChunk = manager2D.LoadOrCreateChunk(otherX, otherY, chunk2DSize, chunk2DSize);
otherChunk[0, 0] = (byte)(i + j);
}
});
// 3D stress
Parallel.For(0, chunksPerIteration / 10, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
{
int x = i % 10, y = i / 10 % 10, z = i / 100;
// Load chunk
var chunk = manager3D.LoadOrCreateChunk(x, y, z, chunk3DWidth, chunk3DHeight, chunk3DDepth);
// Fill with data (just a portion to save time)
for (int cx = 0; cx < chunk3DWidth; cx++)
for (int cy = 0; cy < chunk3DHeight / 4; cy++)
for (int cz = 0; cz < chunk3DDepth; cz++)
chunk[cx, cy, cz] = (byte)((cx + cy + cz + i) % 256);
// Access chunk
long sum = 0;
for (int cx = 0; cx < chunk3DWidth; cx++)
for (int cy = 0; cy < chunk3DHeight / 4; cy++)
for (int cz = 0; cz < chunk3DDepth; cz++)
sum += chunk[cx, cy, cz];
// Force some evictions by loading other chunks
for (int j = 0; j < 2; j++)
{
int otherX = (i + j * 20) % 30;
int otherY = (i + j * 20) / 30 % 30;
int otherZ = (i + j * 20) / 900;
var otherChunk = manager3D.LoadOrCreateChunk(otherX, otherY, otherZ, chunk3DWidth, chunk3DHeight, chunk3DDepth);
otherChunk[0, 0, 0] = (byte)(i + j);
}
});
// Check memory after each iteration
var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
Console.ForegroundColor = _memoryColor;
Console.WriteLine($" Memory: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)} " +
$"({memoryReport.MemoryUsagePercentage:F2}% of system memory)");
Console.ResetColor();
// Force GC between iterations
GC.Collect();
GC.WaitForPendingFinalizers();
}
sw.Stop();
Console.WriteLine($"Stress test completed in {sw.Elapsed.TotalSeconds:F2} seconds");
// Final memory state
var finalMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
Console.WriteLine($"Final memory state: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes)}");
Console.WriteLine($"Memory change: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes - initialMemory.EstimatedChunkMemoryBytes)}");
// Clean up
manager2D = null;
manager3D = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
private static bool CanAllocateChunks(int numChunks, int width, int height, int depth, double safetyFactor)
{
long bytesPerChunk = (long)width * height * depth;
long totalBytes = bytesPerChunk * numChunks;
long available = GetAvailableMemoryBytes();
long safeLimit = (long)(available * safetyFactor);
return totalBytes <= safeLimit;
}
private static long GetAvailableMemoryBytes()
{
return (long)AdvChkSys.AdvChkSys.GetMemoryUsage().AvailableSystemMemoryBytes;
}
private static string FormatByteSize(ulong bytes)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double formattedSize = bytes;
int order = 0;
while (formattedSize >= 1024 && order < sizes.Length - 1)
{
order++;
formattedSize /= 1024;
}
return $"{formattedSize:F2} {sizes[order]}";
}
}
public class BenchmarkResult
{
public string TestName { get; set; } = "";
public int ChunkCount { get; set; }
public string ChunkSize { get; set; } = "";
public double CreateTime { get; set; }
public double AccessTime { get; set; }
public double UnloadTime { get; set; }
public ulong MemoryUsed { get; set; }
}
}