282 lines
7.9 KiB
Markdown
282 lines
7.9 KiB
Markdown
# 威胁源仿真库性能优化 - 下一步行动计划
|
||
|
||
## 基于最新测试结果的分析 (2024-12)
|
||
|
||
### 测试环境
|
||
- **配置**: 50个目标, 20个导弹, 30秒测试
|
||
- **模式**: Release模式,50fps目标
|
||
- **平台**: .NET Core (具体版本待确认)
|
||
|
||
## 当前性能状况
|
||
|
||
### ✅ 已达到优秀水平的指标
|
||
1. **帧时间**: 平均0.36ms (目标<1ms)
|
||
2. **内存管理**: 增长率0.22MB/s,无泄漏迹象
|
||
3. **基本GC性能**: Gen0频率1.3次/秒,在可接受范围
|
||
|
||
### ⚠️ 需要重点关注的问题
|
||
|
||
#### 1. GC暂停问题 (关键)
|
||
- **症状**: 最大帧时间20.57ms,99%分位数5.71ms
|
||
- **影响**: 造成明显的性能尖刺,用户可感知的卡顿
|
||
- **可能原因**:
|
||
- Gen1/Gen2 GC的阻塞式回收
|
||
- 大对象堆(LOH)的压缩操作
|
||
- 终结器队列阻塞
|
||
|
||
#### 2. 异常的GC模式
|
||
- **症状**: Gen1(1.1次/秒)和Gen2(1.1次/秒)频率异常高
|
||
- **正常情况**: 应该是Gen0 >> Gen1 >> Gen2的递减关系
|
||
- **可能原因**:
|
||
- 存在大量中等生命周期对象(几帧到几秒)
|
||
- LOH对象分配导致Gen2触发
|
||
- 跨代引用较多
|
||
|
||
## 详细优化策略
|
||
|
||
### 第一优先级:GC暂停诊断和优化
|
||
|
||
#### 1.1 添加GC监控工具
|
||
```csharp
|
||
public class GCMonitor
|
||
{
|
||
private static volatile bool _monitoring = false;
|
||
private static readonly StringBuilder _gcLog = new StringBuilder();
|
||
|
||
public static void StartMonitoring()
|
||
{
|
||
if (_monitoring) return;
|
||
_monitoring = true;
|
||
|
||
// 注册GC通知
|
||
GC.RegisterForFullGCNotification(10, 10);
|
||
|
||
Task.Run(MonitorGCEvents);
|
||
}
|
||
|
||
private static void MonitorGCEvents()
|
||
{
|
||
while (_monitoring)
|
||
{
|
||
// 监控即将发生的GC
|
||
if (GC.WaitForFullGCApproach() == GCNotificationStatus.Succeeded)
|
||
{
|
||
var sw = Stopwatch.StartNew();
|
||
var beforeMemory = GC.GetTotalMemory(false);
|
||
|
||
// 等待GC完成
|
||
if (GC.WaitForFullGCComplete() == GCNotificationStatus.Succeeded)
|
||
{
|
||
sw.Stop();
|
||
var afterMemory = GC.GetTotalMemory(false);
|
||
|
||
Debug.WriteLine($"[GC] 耗时: {sw.ElapsedMilliseconds}ms, " +
|
||
$"回收: {(beforeMemory - afterMemory) / 1024.0:F1}KB, " +
|
||
$"剩余: {afterMemory / 1024.0:F1}KB");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 1.2 大对象分配检查
|
||
需要审查以下可能分配大对象的代码:
|
||
- `InfraredTargetRecognizer.cs` - 图像处理数组
|
||
- `MillimeterWaveGuidanceSystem.cs` - 信号处理缓冲区
|
||
- `SimulationManager.cs` - 批量数据处理
|
||
|
||
#### 1.3 服务器GC模式考虑
|
||
如果是桌面应用,考虑启用服务器GC:
|
||
```xml
|
||
<PropertyGroup>
|
||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
|
||
</PropertyGroup>
|
||
```
|
||
|
||
### 第二优先级:对象生命周期优化
|
||
|
||
#### 2.1 诊断中等生命周期对象
|
||
```csharp
|
||
// 添加到SimulationManager
|
||
private readonly Dictionary<string, WeakReference> _objectTracker = new();
|
||
|
||
public void TrackObject(string category, object obj)
|
||
{
|
||
#if DEBUG
|
||
_objectTracker[$"{category}_{DateTime.Now.Ticks}"] = new WeakReference(obj);
|
||
#endif
|
||
}
|
||
|
||
public void ReportObjectLifetime()
|
||
{
|
||
#if DEBUG
|
||
int aliveCount = _objectTracker.Values.Count(wr => wr.IsAlive);
|
||
Debug.WriteLine($"[对象追踪] 活跃对象: {aliveCount}/{_objectTracker.Count}");
|
||
#endif
|
||
}
|
||
```
|
||
|
||
#### 2.2 优化制导系统历史数据
|
||
当前的Queue<T>使用可能导致中等生命周期对象:
|
||
```csharp
|
||
// 替换现有的Queue历史记录
|
||
public class OptimizedGuidanceHistory
|
||
{
|
||
private readonly double[] _snrHistory;
|
||
private readonly bool[] _detectionHistory;
|
||
private int _currentIndex = 0;
|
||
private int _count = 0;
|
||
|
||
public OptimizedGuidanceHistory(int capacity)
|
||
{
|
||
_snrHistory = new double[capacity];
|
||
_detectionHistory = new bool[capacity];
|
||
}
|
||
|
||
public void AddSample(double snr, bool detected)
|
||
{
|
||
_snrHistory[_currentIndex] = snr;
|
||
_detectionHistory[_currentIndex] = detected;
|
||
|
||
_currentIndex = (_currentIndex + 1) % _snrHistory.Length;
|
||
if (_count < _snrHistory.Length) _count++;
|
||
}
|
||
|
||
// 零分配的统计计算
|
||
public (double avgSnr, double successRate) GetStatistics()
|
||
{
|
||
if (_count == 0) return (0.0, 0.0);
|
||
|
||
double sumSnr = 0.0;
|
||
int successCount = 0;
|
||
|
||
for (int i = 0; i < _count; i++)
|
||
{
|
||
sumSnr += _snrHistory[i];
|
||
if (_detectionHistory[i]) successCount++;
|
||
}
|
||
|
||
return (sumSnr / _count, (double)successCount / _count);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 第三优先级:进一步性能提升
|
||
|
||
#### 3.1 批量处理优化
|
||
```csharp
|
||
// 批量更新实体,减少虚函数调用开销
|
||
private void BatchUpdateEntities(List<SimulationElement> elements, double deltaTime)
|
||
{
|
||
// 按类型分组,利用CPU缓存局部性
|
||
var missiles = new List<BaseMissile>();
|
||
var targets = new List<Tank>();
|
||
var sensors = new List<SensorBase>();
|
||
|
||
foreach (var element in elements)
|
||
{
|
||
switch (element)
|
||
{
|
||
case BaseMissile missile: missiles.Add(missile); break;
|
||
case Tank tank: targets.Add(tank); break;
|
||
case SensorBase sensor: sensors.Add(sensor); break;
|
||
}
|
||
}
|
||
|
||
// 分类型批量更新
|
||
Parallel.ForEach(missiles, missile => missile.Update(deltaTime));
|
||
Parallel.ForEach(targets, target => target.Update(deltaTime));
|
||
Parallel.ForEach(sensors, sensor => sensor.Update(deltaTime));
|
||
}
|
||
```
|
||
|
||
#### 3.2 SIMD优化距离计算
|
||
```csharp
|
||
public static class VectorizedMath
|
||
{
|
||
public static void CalculateDistancesBatch(
|
||
ReadOnlySpan<Vector3D> positions1,
|
||
ReadOnlySpan<Vector3D> positions2,
|
||
Span<double> results)
|
||
{
|
||
for (int i = 0; i < positions1.Length; i++)
|
||
{
|
||
var delta = positions1[i] - positions2[i];
|
||
results[i] = Math.Sqrt(delta.X * delta.X + delta.Y * delta.Y + delta.Z * delta.Z);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 性能测试增强建议
|
||
|
||
### 增加更详细的诊断
|
||
```csharp
|
||
[Test]
|
||
public void DetailedPerformanceTest()
|
||
{
|
||
// 启用GC监控
|
||
GCMonitor.StartMonitoring();
|
||
|
||
// 记录每种GC的详细信息
|
||
var gcCounts = new int[3];
|
||
|
||
for (int frame = 0; frame < 1500; frame++)
|
||
{
|
||
var before = new[] { GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2) };
|
||
|
||
simulationManager.Update(0.02);
|
||
|
||
var after = new[] { GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2) };
|
||
|
||
for (int gen = 0; gen < 3; gen++)
|
||
{
|
||
if (after[gen] > before[gen])
|
||
{
|
||
Debug.WriteLine($"[帧{frame}] Gen{gen} GC触发");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 成功标准
|
||
|
||
### 短期目标 (2-4周)
|
||
- [ ] GC最大暂停时间 < 10ms
|
||
- [ ] 99%分位数帧时间 < 2ms
|
||
- [ ] Gen1/Gen2 GC频率 < 0.5次/秒
|
||
|
||
### 中期目标 (1-2个月)
|
||
- [ ] 支持100个目标 + 50个导弹的场景
|
||
- [ ] 平均帧时间保持 < 0.5ms
|
||
- [ ] 内存增长率 < 0.1MB/s
|
||
|
||
### 工具和方法
|
||
1. **Visual Studio诊断工具** - 内存使用分析
|
||
2. **dotMemory** - 对象分配和生命周期分析
|
||
3. **PerfView** - ETW事件跟踪,GC详细分析
|
||
4. **BenchmarkDotNet** - 微基准测试
|
||
|
||
## 实施时间表
|
||
|
||
### 第1-2周:诊断阶段
|
||
- 集成GC监控工具
|
||
- 使用PerfView分析GC行为
|
||
- 识别大对象和中等生命周期对象的来源
|
||
|
||
### 第3-4周:优化实施
|
||
- 实施识别出的具体优化
|
||
- 增强性能测试套件
|
||
- 验证优化效果
|
||
|
||
### 第5-6周:验证和调优
|
||
- 大规模场景测试
|
||
- 性能回归测试
|
||
- 文档更新
|
||
|
||
---
|
||
|
||
**注意**: 当前的性能表现已经相当不错,建议采用谨慎的增量优化策略,避免过度优化导致代码复杂度上升。 |