diff --git a/src/AdvChkSys.Benchmarks/ChunkMark.cs b/src/AdvChkSys.Benchmarks/ChunkMark.cs index 9e763a1..7c1bd1c 100644 --- a/src/AdvChkSys.Benchmarks/ChunkMark.cs +++ b/src/AdvChkSys.Benchmarks/ChunkMark.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -159,6 +160,9 @@ namespace ChunkMark } PrintSummary(); + PrintDetailedChunkInfo(); + // Save benchmark results to log file + SaveBenchmarkLog(); Console.ForegroundColor = _infoColor; // Using _infoColor here Console.WriteLine("\nDone. Press any key to exit."); @@ -196,10 +200,11 @@ namespace ChunkMark return; } + // Standard benchmark results table var table = new StringBuilder(); - table.AppendLine("┌────────────────┬─────────────┬────────────┬────────────┬────────────┐"); - table.AppendLine("│ Test │ Chunks │ Create │ Access │ Unload │"); - table.AppendLine("├────────────────┼─────────────┼────────────┼────────────┼────────────┤"); + table.AppendLine("┌────────────────┬─────────────┬────────────┬────────────┬────────────┬────────────┐"); + table.AppendLine("│ Test │ Chunks │ Create │ Access │ Unload │ Memory │"); + table.AppendLine("├────────────────┼─────────────┼────────────┼────────────┼────────────┼────────────┤"); foreach (var result in _results) { @@ -208,11 +213,12 @@ namespace ChunkMark 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); + string memoryUsed = FormatByteSize(result.MemoryUsed).PadRight(10).Substring(0, 10); - table.AppendLine($"│ {testName} │ {chunkInfo} │ {createTime} │ {accessTime} │ {unloadTime} │"); + table.AppendLine($"│ {testName} │ {chunkInfo} │ {createTime} │ {accessTime} │ {unloadTime} │ {memoryUsed} │"); } - table.AppendLine("└────────────────┴─────────────┴────────────┴────────────┴────────────┘"); + table.AppendLine("└────────────────┴─────────────┴────────────┴────────────┴────────────┴────────────┘"); Console.WriteLine(table.ToString()); // Calculate and display performance metrics @@ -224,12 +230,71 @@ namespace ChunkMark 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(); + var access2DRate = _results.Where(r => r.TestName.Contains("2D")).Select(r => r.ChunkCount / r.AccessTime).FirstOrDefault(); + var access3DRate = _results.Where(r => r.TestName.Contains("3D")).Select(r => r.ChunkCount / r.AccessTime).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"); + if (access2DRate > 0) + Console.WriteLine($"2D Chunk Access Rate: {access2DRate:N0} chunks/second"); + if (access3DRate > 0) + Console.WriteLine($"3D Chunk Access Rate: {access3DRate:N0} chunks/second"); } + + // Memory usage summary + Console.ForegroundColor = _memoryColor; + Console.WriteLine("\nMemory Usage Summary:"); + Console.ResetColor(); + + var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage(); + Console.WriteLine($"Current Memory Usage: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}"); + Console.WriteLine($"Active Chunks: {memoryReport.ActiveChunkCount:N0}"); + Console.WriteLine($"Available System Memory: {FormatByteSize(memoryReport.AvailableSystemMemoryBytes)}"); + Console.WriteLine($"Memory Usage: {memoryReport.MemoryUsagePercentage:F2}% of total system memory"); + + // System information + Console.ForegroundColor = _headerColor; + Console.WriteLine("\nSystem Information:"); + Console.ResetColor(); + Console.WriteLine($"CPU Threads: {Environment.ProcessorCount}"); + Console.WriteLine($"Total System Memory: {FormatByteSize(memoryReport.TotalSystemMemoryBytes)}"); + Console.WriteLine($"AdvChkSys Version: {AdvChkSys.AdvChkSys.Version}"); + + // Memory efficiency metrics + if (_results.Count > 0) + { + var result2D = _results.FirstOrDefault(r => r.TestName.Contains("2D")); + var result3D = _results.FirstOrDefault(r => r.TestName.Contains("3D")); + + if (result2D != null && result2D.ChunkCount > 0) + { + ulong bytesPerChunk2D = result2D.MemoryUsed / (ulong)result2D.ChunkCount; + Console.WriteLine($"2D Memory Efficiency: {FormatByteSize(bytesPerChunk2D)}/chunk"); + } + + if (result3D != null && result3D.ChunkCount > 0) + { + ulong bytesPerChunk3D = result3D.MemoryUsed / (ulong)result3D.ChunkCount; + Console.WriteLine($"3D Memory Efficiency: {FormatByteSize(bytesPerChunk3D)}/chunk"); + } + } + + // If stress test was run, show its results + var stressResult = _results.FirstOrDefault(r => r.TestName.Contains("Stress")); + if (stressResult != null) + { + Console.ForegroundColor = _headerColor; + Console.WriteLine("\nStress Test Results:"); + Console.ResetColor(); + Console.WriteLine($"Chunks Processed: {stressResult.ChunkCount:N0}"); + Console.WriteLine($"Processing Time: {stressResult.CreateTime:F2} seconds"); + Console.WriteLine($"Processing Rate: {stressResult.ChunkCount / stressResult.CreateTime:N0} chunks/second"); + Console.WriteLine($"Peak Memory Usage: {FormatByteSize(stressResult.MemoryUsed)}"); + } + + } private static void Benchmark2D(int cpuCount, int numChunks, int chunkSize, int maxLoaded) @@ -705,6 +770,146 @@ namespace ChunkMark return $"{formattedSize:F2} {sizes[order]}"; } + + private static void SaveBenchmarkLog() + { + // Create logs directory if it doesn't exist + string logsDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs"); + Directory.CreateDirectory(logsDirectory); + + // Generate a unique filename with timestamp + string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); + string logFileName = $"ChunkMark_{timestamp}.log"; + string logFilePath = Path.Combine(logsDirectory, logFileName); + + // Create a string builder to hold the log content + var logContent = new StringBuilder(); + + // Add header + logContent.AppendLine("================================================================="); + logContent.AppendLine($"ChunkMark Benchmark Results - {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); + logContent.AppendLine("================================================================="); + logContent.AppendLine(); + + // Add system information + var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage(); + logContent.AppendLine("System Information:"); + logContent.AppendLine($"CPU Threads: {Environment.ProcessorCount}"); + logContent.AppendLine($"Total System Memory: {FormatByteSize(memoryReport.TotalSystemMemoryBytes)}"); + logContent.AppendLine($"Available System Memory: {FormatByteSize(memoryReport.AvailableSystemMemoryBytes)}"); + logContent.AppendLine($"AdvChkSys Version: {AdvChkSys.AdvChkSys.Version}"); + logContent.AppendLine(); + + // Add benchmark results + logContent.AppendLine("Benchmark Results:"); + logContent.AppendLine("------------------------------------------------------------------"); + if (_results.Count == 0) + { + logContent.AppendLine("No benchmark results to display."); + } + else + { + // Header row + logContent.AppendLine( + $"{"Test",-15} | {"Chunks",-10} | {"Size",-12} | {"Create (s)",-10} | {"Access (s)",-10} | {"Unload (s)",-10} | {"Memory",-12}"); + logContent.AppendLine(new string('-', 90)); + + // Data rows + foreach (var result in _results) + { + logContent.AppendLine( + $"{result.TestName,-15} | {result.ChunkCount,-10:N0} | {result.ChunkSize,-12} | " + + $"{result.CreateTime,-10:F3} | {result.AccessTime,-10:F3} | {result.UnloadTime,-10:F3} | " + + $"{FormatByteSize(result.MemoryUsed),-12}"); + } + } + logContent.AppendLine(); + + // Add performance metrics + logContent.AppendLine("Performance Metrics:"); + logContent.AppendLine("------------------------------------------------------------------"); + if (_results.Count > 0) + { + 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(); + var access2DRate = _results.Where(r => r.TestName.Contains("2D")).Select(r => r.ChunkCount / r.AccessTime).FirstOrDefault(); + var access3DRate = _results.Where(r => r.TestName.Contains("3D")).Select(r => r.ChunkCount / r.AccessTime).FirstOrDefault(); + + if (create2DRate > 0) + logContent.AppendLine($"2D Chunk Creation Rate: {create2DRate:N0} chunks/second"); + if (create3DRate > 0) + logContent.AppendLine($"3D Chunk Creation Rate: {create3DRate:N0} chunks/second"); + if (access2DRate > 0) + logContent.AppendLine($"2D Chunk Access Rate: {access2DRate:N0} chunks/second"); + if (access3DRate > 0) + logContent.AppendLine($"3D Chunk Access Rate: {access3DRate:N0} chunks/second"); + } + logContent.AppendLine(); + + // Add memory usage summary + logContent.AppendLine("Memory Usage Summary:"); + logContent.AppendLine("------------------------------------------------------------------"); + logContent.AppendLine($"Current Memory Usage: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}"); + logContent.AppendLine($"Active Chunks: {memoryReport.ActiveChunkCount:N0}"); + logContent.AppendLine($"Memory Usage: {memoryReport.MemoryUsagePercentage:F2}% of total system memory"); + + // Memory efficiency metrics + if (_results.Count > 0) + { + var result2D = _results.FirstOrDefault(r => r.TestName.Contains("2D")); + var result3D = _results.FirstOrDefault(r => r.TestName.Contains("3D")); + + if (result2D != null && result2D.ChunkCount > 0) + { + ulong bytesPerChunk2D = result2D.MemoryUsed / (ulong)result2D.ChunkCount; + logContent.AppendLine($"2D Memory Efficiency: {FormatByteSize(bytesPerChunk2D)}/chunk"); + } + + if (result3D != null && result3D.ChunkCount > 0) + { + ulong bytesPerChunk3D = result3D.MemoryUsed / (ulong)result3D.ChunkCount; + logContent.AppendLine($"3D Memory Efficiency: {FormatByteSize(bytesPerChunk3D)}/chunk"); + } + } + + // Write the log to file + File.WriteAllText(logFilePath, logContent.ToString()); + + Console.ForegroundColor = _infoColor; + Console.WriteLine($"\nBenchmark results saved to: {logFilePath}"); + Console.ResetColor(); + } + + private static void PrintDetailedChunkInfo() + { + Console.ForegroundColor = _headerColor; + Console.WriteLine("\nDetailed Chunk Information:"); + Console.ResetColor(); + + var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage(); + + Console.WriteLine($"Active Chunks (reported by ChunkResourceManager): {memoryReport.ActiveChunkCount:N0}"); + + // Get counts from results + int total2DChunks = _results.Where(r => r.TestName.Contains("2D")).Sum(r => r.ChunkCount); + int total3DChunks = _results.Where(r => r.TestName.Contains("3D")).Sum(r => r.ChunkCount); + int totalChunks = total2DChunks + total3DChunks; + + Console.WriteLine($"Total 2D Chunks Created: {total2DChunks:N0}"); + Console.WriteLine($"Total 3D Chunks Created: {total3DChunks:N0}"); + Console.WriteLine($"Total Chunks Created: {totalChunks:N0}"); + + if (memoryReport.ActiveChunkCount != totalChunks) + { + Console.ForegroundColor = _infoColor; + Console.WriteLine("\nPossible reasons for the difference:"); + Console.WriteLine("1. Chunk eviction due to LRU cache capacity limits"); + Console.WriteLine("2. Chunks unloaded during benchmark cleanup"); + Console.WriteLine("3. All-air chunks using flyweight pattern (counted once)"); + Console.WriteLine("4. Garbage collection removing unreferenced chunks"); + Console.ResetColor(); + } + } } public class BenchmarkResult