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