using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using ThreatSource.Simulation; using ThreatSource.Equipment; using ThreatSource.Missile; using ThreatSource.Utils; using ThreatSource.Data; using Xunit; using Xunit.Abstractions; namespace ThreatSource.Tests.Simulation { /// /// SimulationManager性能测试工具 /// 专门用于测试内存分配风暴和GC压力 /// public class SimulationManagerPerformanceTest { private readonly ITestOutputHelper _output; private readonly SimulationManager simulationManager; private readonly ThreatSourceDataManager dataManager; private readonly ThreatSourceFactory factory; private readonly List entityIds; // 性能测试参数 private const int TARGET_COUNT = 50; // 目标数量 private const int MISSILE_COUNT = 20; // 导弹数量 private const int TEST_DURATION_SECONDS = 30; // 测试持续时间 private const double TIME_STEP = 0.02; // 时间步长(50fps) // 性能统计 private long totalAllocations = 0; private long totalGCCollections = 0; private long peakMemoryUsage = 0; private double totalUpdateTime = 0; private int updateCount = 0; public SimulationManagerPerformanceTest(ITestOutputHelper output) { _output = output; simulationManager = new SimulationManager(); // 使用与其他测试相同的路径解析方式 string baseDir = AppDomain.CurrentDomain.BaseDirectory; string projectRoot = Path.GetFullPath(Path.Combine(baseDir, "../../../..")); string dataPath = Path.Combine(projectRoot, "ThreatSource/data"); dataManager = new ThreatSourceDataManager(dataPath); factory = new ThreatSourceFactory(dataManager, simulationManager); entityIds = new List(); } /// /// 运行完整的性能测试 - 作为单元测试 /// [Fact] public void RunPerformanceTest() { _output.WriteLine("=== SimulationManager性能测试 ==="); _output.WriteLine($"测试参数: {TARGET_COUNT}个目标, {MISSILE_COUNT}个导弹, {TEST_DURATION_SECONDS}秒测试"); _output.WriteLine($"时间步长: {TIME_STEP}s ({1.0/TIME_STEP:F0}fps)"); _output.WriteLine(""); // 1. 准备测试环境 SetupTestEnvironment(); // 2. 预热GC WarmupGC(); // 3. 记录基准内存状态 var baselineMemory = RecordMemoryBaseline(); // 4. 运行核心性能测试 var testResults = RunCorePerformanceTest(); // 5. 输出详细测试结果 OutputDetailedResults(baselineMemory, testResults); // 6. 清理测试环境 CleanupTestEnvironment(); // 7. 性能断言 AssertPerformanceThresholds(testResults); } /// /// 快速性能测试 - 用于持续集成 /// [Fact] public void QuickPerformanceTest() { const int quickTargetCount = 10; const int quickMissileCount = 5; const int quickTestDuration = 5; _output.WriteLine("=== SimulationManager快速性能测试 ==="); _output.WriteLine($"测试参数: {quickTargetCount}个目标, {quickMissileCount}个导弹, {quickTestDuration}秒测试"); // 设置小规模测试环境 SetupQuickTestEnvironment(quickTargetCount, quickMissileCount); WarmupGC(); var baselineMemory = RecordMemoryBaseline(); var testResults = RunQuickPerformanceTest(quickTestDuration); OutputDetailedResults(baselineMemory, testResults); CleanupTestEnvironment(); // 更宽松的性能要求 Assert.True(testResults.AverageUpdateTime < 50.0, $"平均帧时间过长: {testResults.AverageUpdateTime:F2}ms"); } /// /// 设置测试环境 - 创建大量实体 /// private void SetupTestEnvironment() { _output.WriteLine("设置测试环境..."); // 添加天气 var weather = factory.CreateWeather("sunny"); simulationManager.SetWeather(weather); // 创建目标 for (int i = 0; i < TARGET_COUNT; i++) { var targetId = $"Target_{i}"; var position = new Vector3D( Random.Shared.NextDouble() * 2000 - 1000, // -1000 to 1000 1.2, Random.Shared.NextDouble() * 2000 - 1000 // -1000 to 1000 ); var motionParams = new KinematicState { Position = position, Orientation = new Orientation(0, 0, 0), Speed = Random.Shared.NextDouble() * 5.0 // 0-5 m/s }; var target = factory.CreateEquipment(targetId, "mbt_001", motionParams); simulationManager.RegisterEntity(targetId, target); target.Activate(); entityIds.Add(targetId); } // 创建导弹 for (int i = 0; i < MISSILE_COUNT; i++) { var missileId = $"Missile_{i}"; var targetId = $"Target_{Random.Shared.Next(TARGET_COUNT)}"; // 随机选择目标 var position = new Vector3D( Random.Shared.NextDouble() * 4000 + 2000, // 2000-6000米距离 Random.Shared.NextDouble() * 100 + 10, // 10-110米高度 Random.Shared.NextDouble() * 200 - 100 // -100到100米侧向 ); var motionParams = new KinematicState { Position = position, Orientation = new Orientation(Math.PI/2, Random.Shared.NextDouble() * 0.1 - 0.05, 0), Speed = Random.Shared.NextDouble() * 200 + 300 // 300-500 m/s }; // 随机选择导弹类型 string[] missileTypes = { "lsgm_001", "itg_001", "mmw_001", "tsm_001" }; string missileType = missileTypes[Random.Shared.Next(missileTypes.Length)]; var missile = factory.CreateMissile(missileId, missileType, targetId, motionParams); simulationManager.RegisterEntity(missileId, missile); missile.Activate(); entityIds.Add(missileId); } _output.WriteLine($"已创建 {TARGET_COUNT} 个目标和 {MISSILE_COUNT} 个导弹"); } /// /// 设置快速测试环境 /// private void SetupQuickTestEnvironment(int targetCount, int missileCount) { _output.WriteLine("设置快速测试环境..."); var weather = factory.CreateWeather("sunny"); simulationManager.SetWeather(weather); // 创建目标 for (int i = 0; i < targetCount; i++) { var targetId = $"Target_{i}"; var motionParams = new KinematicState { Position = new Vector3D(i * 100, 1.2, 0), Orientation = new Orientation(0, 0, 0), Speed = 2.0 }; var target = factory.CreateEquipment(targetId, "mbt_001", motionParams); simulationManager.RegisterEntity(targetId, target); target.Activate(); entityIds.Add(targetId); } // 创建导弹 for (int i = 0; i < missileCount; i++) { var missileId = $"Missile_{i}"; var targetId = $"Target_{i % targetCount}"; var motionParams = new KinematicState { Position = new Vector3D(2000 + i * 100, 50, 0), Orientation = new Orientation(Math.PI/2, 0.05, 0), Speed = 400 }; var missile = factory.CreateMissile(missileId, "lsgm_001", targetId, motionParams); simulationManager.RegisterEntity(missileId, missile); missile.Activate(); entityIds.Add(missileId); } _output.WriteLine($"已创建 {targetCount} 个目标和 {missileCount} 个导弹"); } /// /// GC预热 /// private void WarmupGC() { _output.WriteLine("GC预热中..."); // 强制进行几次GC以稳定内存状态 for (int i = 0; i < 3; i++) { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); Thread.Sleep(100); } _output.WriteLine("GC预热完成"); } /// /// 记录内存基准线 /// private MemorySnapshot RecordMemoryBaseline() { var baseline = new MemorySnapshot { WorkingSet = GC.GetTotalMemory(true), Gen0Collections = GC.CollectionCount(0), Gen1Collections = GC.CollectionCount(1), Gen2Collections = GC.CollectionCount(2) }; _output.WriteLine("内存基准线:"); _output.WriteLine($" 工作集内存: {baseline.WorkingSet / 1024.0 / 1024.0:F2} MB"); _output.WriteLine($" GC统计: Gen0={baseline.Gen0Collections}, Gen1={baseline.Gen1Collections}, Gen2={baseline.Gen2Collections}"); _output.WriteLine(""); return baseline; } /// /// 运行核心性能测试 /// private TestResults RunCorePerformanceTest() { return RunPerformanceTestCore(TEST_DURATION_SECONDS); } /// /// 运行快速性能测试 /// private TestResults RunQuickPerformanceTest(int duration) { return RunPerformanceTestCore(duration); } /// /// 核心性能测试逻辑 /// private TestResults RunPerformanceTestCore(int durationSeconds) { _output.WriteLine("开始核心性能测试..."); var results = new TestResults(); var stopwatch = Stopwatch.StartNew(); var memorySnapshots = new List(); var updateTimes = new List(); // 启动仿真 simulationManager.StartSimulation(TIME_STEP); var testStartTime = DateTime.UtcNow; var nextSnapshotTime = testStartTime.AddSeconds(1); while (stopwatch.Elapsed.TotalSeconds < durationSeconds) { var updateStopwatch = Stopwatch.StartNew(); // 这是我们要测试的核心代码路径 simulationManager.Update(TIME_STEP); updateStopwatch.Stop(); var updateTime = updateStopwatch.Elapsed.TotalMilliseconds; updateTimes.Add(updateTime); totalUpdateTime += updateTime; updateCount++; // 每秒记录一次内存快照 if (DateTime.UtcNow >= nextSnapshotTime) { var snapshot = new MemorySnapshot { Timestamp = DateTime.UtcNow, WorkingSet = GC.GetTotalMemory(false), Gen0Collections = GC.CollectionCount(0), Gen1Collections = GC.CollectionCount(1), Gen2Collections = GC.CollectionCount(2) }; memorySnapshots.Add(snapshot); nextSnapshotTime = nextSnapshotTime.AddSeconds(1); // 实时输出进度 _output.WriteLine($"[{stopwatch.Elapsed.TotalSeconds:F1}s] " + $"内存: {snapshot.WorkingSet / 1024.0 / 1024.0:F1}MB, " + $"平均帧时间: {updateTimes.TakeLast(50).Average():F2}ms"); } // 模拟真实帧率 var frameTime = (int)(TIME_STEP * 1000); var elapsed = (int)updateStopwatch.Elapsed.TotalMilliseconds; if (elapsed < frameTime) { Thread.Sleep(frameTime - elapsed); } } stopwatch.Stop(); simulationManager.StopSimulation(); results.TotalTestTime = stopwatch.Elapsed.TotalSeconds; results.MemorySnapshots = memorySnapshots; results.UpdateTimes = updateTimes; results.TotalUpdates = updateCount; results.AverageUpdateTime = totalUpdateTime / updateCount; _output.WriteLine("核心性能测试完成"); return results; } /// /// 输出详细测试结果 /// private void OutputDetailedResults(MemorySnapshot baseline, TestResults results) { _output.WriteLine(""); _output.WriteLine("=== 详细性能测试结果 ==="); // 基本统计 _output.WriteLine(""); _output.WriteLine("【基本统计】"); _output.WriteLine($"测试时长: {results.TotalTestTime:F1} 秒"); _output.WriteLine($"总更新次数: {results.TotalUpdates}"); _output.WriteLine($"平均FPS: {results.TotalUpdates / results.TotalTestTime:F1}"); _output.WriteLine($"平均帧时间: {results.AverageUpdateTime:F2} ms"); // 帧时间分析 _output.WriteLine(""); _output.WriteLine("【帧时间分析】"); var sortedTimes = results.UpdateTimes.OrderBy(x => x).ToList(); _output.WriteLine($"最小帧时间: {sortedTimes.First():F2} ms"); _output.WriteLine($"最大帧时间: {sortedTimes.Last():F2} ms"); _output.WriteLine($"95%分位数: {sortedTimes[(int)(sortedTimes.Count * 0.95)]:F2} ms"); _output.WriteLine($"99%分位数: {sortedTimes[(int)(sortedTimes.Count * 0.99)]:F2} ms"); // 内存分析 _output.WriteLine(""); _output.WriteLine("【内存使用分析】"); var finalSnapshot = results.MemorySnapshots.Last(); var memoryIncrease = finalSnapshot.WorkingSet - baseline.WorkingSet; var peakMemory = results.MemorySnapshots.Max(s => s.WorkingSet); _output.WriteLine($"起始内存: {baseline.WorkingSet / 1024.0 / 1024.0:F2} MB"); _output.WriteLine($"结束内存: {finalSnapshot.WorkingSet / 1024.0 / 1024.0:F2} MB"); _output.WriteLine($"峰值内存: {peakMemory / 1024.0 / 1024.0:F2} MB"); _output.WriteLine($"内存增长: {memoryIncrease / 1024.0 / 1024.0:F2} MB"); _output.WriteLine($"平均内存增长率: {(memoryIncrease / results.TotalTestTime) / 1024.0 / 1024.0:F2} MB/s"); // GC分析 _output.WriteLine(""); _output.WriteLine("【垃圾回收分析】"); var gen0Increase = finalSnapshot.Gen0Collections - baseline.Gen0Collections; var gen1Increase = finalSnapshot.Gen1Collections - baseline.Gen1Collections; var gen2Increase = finalSnapshot.Gen2Collections - baseline.Gen2Collections; _output.WriteLine($"Gen0 GC次数: {gen0Increase} ({gen0Increase / results.TotalTestTime:F1} 次/秒)"); _output.WriteLine($"Gen1 GC次数: {gen1Increase} ({gen1Increase / results.TotalTestTime:F1} 次/秒)"); _output.WriteLine($"Gen2 GC次数: {gen2Increase} ({gen2Increase / results.TotalTestTime:F1} 次/秒)"); _output.WriteLine($"总GC次数: {gen0Increase + gen1Increase + gen2Increase}"); // 性能评级 _output.WriteLine(""); _output.WriteLine("【性能评级】"); var frameTimeGrade = GetPerformanceGrade(results.AverageUpdateTime, 20.0, 50.0); // 20ms=50fps, 50ms=20fps var memoryGrade = GetPerformanceGrade(memoryIncrease / 1024.0 / 1024.0, 10.0, 50.0); // 10MB, 50MB var gcGrade = GetPerformanceGrade(gen0Increase / results.TotalTestTime, 1.0, 5.0); // 1次/秒, 5次/秒 _output.WriteLine($"帧时间表现: {frameTimeGrade}"); _output.WriteLine($"内存管理: {memoryGrade}"); _output.WriteLine($"GC频率: {gcGrade}"); // 热点分析提示 _output.WriteLine(""); _output.WriteLine("【潜在问题分析】"); if (results.AverageUpdateTime > 20.0) { _output.WriteLine("⚠️ 平均帧时间超过20ms,可能存在性能瓶颈"); } if (gen0Increase / results.TotalTestTime > 2.0) { _output.WriteLine("⚠️ Gen0 GC频率过高,存在内存分配风暴"); } if (memoryIncrease > 50 * 1024 * 1024) { _output.WriteLine("⚠️ 内存增长过多,可能存在内存泄漏"); } if (sortedTimes.Last() > sortedTimes[(int)(sortedTimes.Count * 0.95)] * 2) { _output.WriteLine("⚠️ 存在显著的帧时间波动,GC暂停可能较严重"); } } /// /// 性能断言 - 确保性能在可接受范围内 /// private void AssertPerformanceThresholds(TestResults results) { // 这些阈值是基于现有代码的性能问题设定的 // 优化后这些阈值应该更严格 Assert.True(results.AverageUpdateTime < 100.0, $"平均帧时间过长: {results.AverageUpdateTime:F2}ms"); var finalSnapshot = results.MemorySnapshots.Last(); var baseline = results.MemorySnapshots.First(); var gcIncrease = (finalSnapshot.Gen0Collections - baseline.Gen0Collections) / results.TotalTestTime; // 如果GC频率超过10次/秒,说明内存分配风暴很严重 Assert.True(gcIncrease < 10.0, $"Gen0 GC频率过高: {gcIncrease:F1} 次/秒"); } /// /// 获取性能评级 /// private string GetPerformanceGrade(double value, double goodThreshold, double badThreshold) { if (value <= goodThreshold) return "优秀 ✅"; if (value <= badThreshold) return "一般 ⚠️"; return "较差 ❌"; } /// /// 清理测试环境 /// private void CleanupTestEnvironment() { _output.WriteLine(""); _output.WriteLine("清理测试环境..."); foreach (var entityId in entityIds) { simulationManager.UnregisterEntity(entityId); } entityIds.Clear(); simulationManager.StopSimulation(); // 强制GC清理 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); _output.WriteLine("清理完成"); } } /// /// 内存快照数据 /// public class MemorySnapshot { public DateTime Timestamp { get; set; } public long WorkingSet { get; set; } public int Gen0Collections { get; set; } public int Gen1Collections { get; set; } public int Gen2Collections { get; set; } } /// /// 测试结果数据 /// public class TestResults { public double TotalTestTime { get; set; } public List MemorySnapshots { get; set; } = new(); public List UpdateTimes { get; set; } = new(); public int TotalUpdates { get; set; } public double AverageUpdateTime { get; set; } } }