NavisworksTransport/src/UI/WPF/Services/DataBindingPerformanceMonitor.cs

695 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace NavisworksTransport.UI.WPF.Services
{
/// <summary>
/// 数据绑定性能监控器 - 监控和分析WPF数据绑定的性能表现
/// 提供详细的性能指标收集和优化建议
/// </summary>
public class DataBindingPerformanceMonitor : IDisposable
{
#region
private static DataBindingPerformanceMonitor _instance;
private static readonly object _instanceLock = new object();
// 性能数据收集
private readonly ConcurrentDictionary<string, PropertyUpdateMetrics> _propertyMetrics;
private readonly ConcurrentDictionary<string, CollectionUpdateMetrics> _collectionMetrics;
private readonly ConcurrentQueue<BindingUpdateEvent> _updateEvents;
private readonly Timer _reportTimer;
private volatile bool _isDisposed = false;
private volatile bool _isMonitoringEnabled = true;
// 监控配置
private TimeSpan _reportInterval = TimeSpan.FromMinutes(5);
private int _maxEventHistory = 10000;
private int _performanceThresholdMs = 16; // 60FPS下每帧约16ms
/// <summary>
/// 获取性能监控器的单例实例
/// </summary>
public static DataBindingPerformanceMonitor Instance
{
get
{
if (_instance == null)
{
lock (_instanceLock)
{
if (_instance == null)
{
_instance = new DataBindingPerformanceMonitor();
}
}
}
return _instance;
}
}
/// <summary>
/// 是否启用性能监控
/// </summary>
public bool IsMonitoringEnabled
{
get => _isMonitoringEnabled;
set => _isMonitoringEnabled = value;
}
/// <summary>
/// 性能阈值(毫秒)- 超过此值的操作将被标记为慢操作
/// </summary>
public int PerformanceThresholdMs
{
get => _performanceThresholdMs;
set => _performanceThresholdMs = Math.Max(1, value);
}
/// <summary>
/// 当前监控的属性数量
/// </summary>
public int MonitoredPropertiesCount => _propertyMetrics.Count;
/// <summary>
/// 当前监控的集合数量
/// </summary>
public int MonitoredCollectionsCount => _collectionMetrics.Count;
#endregion
#region
private DataBindingPerformanceMonitor()
{
_propertyMetrics = new ConcurrentDictionary<string, PropertyUpdateMetrics>();
_collectionMetrics = new ConcurrentDictionary<string, CollectionUpdateMetrics>();
_updateEvents = new ConcurrentQueue<BindingUpdateEvent>();
// 定期生成性能报告
_reportTimer = new Timer(GeneratePerformanceReport, null, _reportInterval, _reportInterval);
LogManager.Info("数据绑定性能监控器已初始化");
}
#endregion
#region
/// <summary>
/// 记录属性变更事件的开始
/// </summary>
/// <param name="viewModelType">ViewModel类型</param>
/// <param name="propertyName">属性名称</param>
/// <returns>性能测量上下文</returns>
public IDisposable BeginPropertyUpdate(Type viewModelType, string propertyName)
{
if (!_isMonitoringEnabled || _isDisposed)
return new EmptyDisposable();
var key = $"{viewModelType.Name}.{propertyName}";
var stopwatch = Stopwatch.StartNew();
return new PropertyUpdateContext(this, key, stopwatch, Dispatcher.CurrentDispatcher);
}
/// <summary>
/// 记录集合变更事件的开始
/// </summary>
/// <param name="collectionType">集合类型</param>
/// <param name="operationType">操作类型Add, Remove, Clear等</param>
/// <param name="itemCount">影响的项目数量</param>
/// <returns>性能测量上下文</returns>
public IDisposable BeginCollectionUpdate(Type collectionType, string operationType, int itemCount = 1)
{
if (!_isMonitoringEnabled || _isDisposed)
return new EmptyDisposable();
var key = $"{collectionType.Name}.{operationType}";
var stopwatch = Stopwatch.StartNew();
return new CollectionUpdateContext(this, key, stopwatch, itemCount, Dispatcher.CurrentDispatcher);
}
/// <summary>
/// 记录绑定更新事件
/// </summary>
/// <param name="bindingPath">绑定路径</param>
/// <param name="updateType">更新类型</param>
/// <param name="durationMs">更新耗时(毫秒)</param>
public void RecordBindingUpdate(string bindingPath, string updateType, double durationMs)
{
if (!_isMonitoringEnabled || _isDisposed)
return;
var updateEvent = new BindingUpdateEvent
{
Timestamp = DateTime.UtcNow,
BindingPath = bindingPath,
UpdateType = updateType,
DurationMs = durationMs,
IsSlowUpdate = durationMs > _performanceThresholdMs,
ThreadId = Thread.CurrentThread.ManagedThreadId
};
_updateEvents.Enqueue(updateEvent);
// 限制事件历史记录数量
while (_updateEvents.Count > _maxEventHistory)
{
_updateEvents.TryDequeue(out _);
}
// 记录慢更新警告
if (updateEvent.IsSlowUpdate)
{
LogManager.Warning($"检测到慢数据绑定更新: {bindingPath} ({updateType}) - {durationMs:F2}ms");
}
}
#endregion
#region
/// <summary>
/// 完成属性更新监控
/// </summary>
internal void EndPropertyUpdate(string key, Stopwatch stopwatch, Dispatcher dispatcher)
{
if (_isDisposed) return;
stopwatch.Stop();
var durationMs = stopwatch.Elapsed.TotalMilliseconds;
var metrics = _propertyMetrics.GetOrAdd(key, _ => new PropertyUpdateMetrics(key));
metrics.RecordUpdate(durationMs, dispatcher == Dispatcher.CurrentDispatcher);
RecordBindingUpdate(key, "PropertyChanged", durationMs);
}
/// <summary>
/// 完成集合更新监控
/// </summary>
internal void EndCollectionUpdate(string key, Stopwatch stopwatch, int itemCount, Dispatcher dispatcher)
{
if (_isDisposed) return;
stopwatch.Stop();
var durationMs = stopwatch.Elapsed.TotalMilliseconds;
var metrics = _collectionMetrics.GetOrAdd(key, _ => new CollectionUpdateMetrics(key));
metrics.RecordUpdate(durationMs, itemCount, dispatcher == Dispatcher.CurrentDispatcher);
RecordBindingUpdate(key, "CollectionChanged", durationMs);
}
/// <summary>
/// 生成性能报告
/// </summary>
private void GeneratePerformanceReport(object state)
{
if (_isDisposed) return;
try
{
var report = GenerateDetailedReport();
LogManager.Info($"数据绑定性能报告:\n{report}");
// 清理过期数据
CleanupExpiredData();
}
catch (Exception ex)
{
LogManager.Error($"生成数据绑定性能报告失败: {ex.Message}");
}
}
/// <summary>
/// 清理过期数据
/// </summary>
private void CleanupExpiredData()
{
var cutoffTime = DateTime.UtcNow.Subtract(TimeSpan.FromHours(1));
// 清理属性指标中的过期数据
foreach (var metrics in _propertyMetrics.Values)
{
metrics.CleanupOldData(cutoffTime);
}
// 清理集合指标中的过期数据
foreach (var metrics in _collectionMetrics.Values)
{
metrics.CleanupOldData(cutoffTime);
}
}
#endregion
#region
/// <summary>
/// 生成详细的性能报告
/// </summary>
/// <returns>性能报告字符串</returns>
public string GenerateDetailedReport()
{
var report = new System.Text.StringBuilder();
report.AppendLine("=== 数据绑定性能监控报告 ===");
report.AppendLine($"报告时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
report.AppendLine($"监控状态: {(IsMonitoringEnabled ? "" : "")}");
report.AppendLine($"性能阈值: {PerformanceThresholdMs}ms");
report.AppendLine();
// 属性更新统计
report.AppendLine("属性更新性能统计:");
var topSlowProperties = _propertyMetrics.Values
.Where(m => m.UpdateCount > 0)
.OrderByDescending(m => m.AverageUpdateTime)
.Take(10)
.ToList();
if (topSlowProperties.Any())
{
foreach (var metrics in topSlowProperties)
{
report.AppendLine($" {metrics.PropertyKey}:");
report.AppendLine($" 更新次数: {metrics.UpdateCount}");
report.AppendLine($" 平均耗时: {metrics.AverageUpdateTime:F2}ms");
report.AppendLine($" 最大耗时: {metrics.MaxUpdateTime:F2}ms");
report.AppendLine($" 慢更新次数: {metrics.SlowUpdateCount}");
report.AppendLine($" 跨线程更新次数: {metrics.CrossThreadUpdateCount}");
}
}
else
{
report.AppendLine(" 暂无属性更新数据");
}
report.AppendLine();
// 集合更新统计
report.AppendLine("集合更新性能统计:");
var topSlowCollections = _collectionMetrics.Values
.Where(m => m.UpdateCount > 0)
.OrderByDescending(m => m.AverageUpdateTime)
.Take(10)
.ToList();
if (topSlowCollections.Any())
{
foreach (var metrics in topSlowCollections)
{
report.AppendLine($" {metrics.CollectionKey}:");
report.AppendLine($" 更新次数: {metrics.UpdateCount}");
report.AppendLine($" 平均耗时: {metrics.AverageUpdateTime:F2}ms");
report.AppendLine($" 最大耗时: {metrics.MaxUpdateTime:F2}ms");
report.AppendLine($" 处理项目总数: {metrics.TotalItemsProcessed}");
report.AppendLine($" 慢更新次数: {metrics.SlowUpdateCount}");
}
}
else
{
report.AppendLine(" 暂无集合更新数据");
}
report.AppendLine();
// 最近的慢更新事件
var recentSlowUpdates = _updateEvents
.Where(e => e.IsSlowUpdate && e.Timestamp > DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(10)))
.OrderByDescending(e => e.DurationMs)
.Take(5)
.ToList();
if (recentSlowUpdates.Any())
{
report.AppendLine("最近的慢更新事件 (10分钟内):");
foreach (var evt in recentSlowUpdates)
{
report.AppendLine($" {evt.BindingPath} ({evt.UpdateType}) - {evt.DurationMs:F2}ms @ {evt.Timestamp:HH:mm:ss}");
}
}
// 性能优化建议
report.AppendLine();
report.AppendLine("性能优化建议:");
var suggestions = GenerateOptimizationSuggestions();
if (suggestions.Any())
{
foreach (var suggestion in suggestions)
{
report.AppendLine($" • {suggestion}");
}
}
else
{
report.AppendLine(" 当前性能表现良好,暂无优化建议");
}
return report.ToString();
}
/// <summary>
/// 生成性能优化建议
/// </summary>
/// <returns>优化建议列表</returns>
public List<string> GenerateOptimizationSuggestions()
{
var suggestions = new List<string>();
// 检查频繁更新的属性
var frequentProperties = _propertyMetrics.Values
.Where(m => m.UpdateCount > 100 && m.AverageUpdateTime > _performanceThresholdMs)
.ToList();
if (frequentProperties.Any())
{
suggestions.Add($"发现{frequentProperties.Count}个高频慢更新属性,建议考虑使用延迟更新或批量更新机制");
}
// 检查大集合操作
var largeCollectionUpdates = _collectionMetrics.Values
.Where(m => m.AverageItemsPerUpdate > 1000 && m.AverageUpdateTime > _performanceThresholdMs * 5)
.ToList();
if (largeCollectionUpdates.Any())
{
suggestions.Add($"发现{largeCollectionUpdates.Count}个大集合更新操作,建议实现虚拟化或分页机制");
}
// 检查跨线程更新
var crossThreadUpdates = _propertyMetrics.Values
.Where(m => m.CrossThreadUpdateCount > m.UpdateCount * 0.1) // 超过10%的跨线程更新
.ToList();
if (crossThreadUpdates.Any())
{
suggestions.Add($"发现{crossThreadUpdates.Count}个属性存在频繁的跨线程更新,建议优化线程调度");
}
// 检查内存使用
var totalMetrics = _propertyMetrics.Count + _collectionMetrics.Count;
if (totalMetrics > 1000)
{
suggestions.Add("监控的绑定数量较多,建议定期清理不再使用的绑定以释放内存");
}
return suggestions;
}
/// <summary>
/// 获取性能概览数据
/// </summary>
/// <returns>性能概览</returns>
public PerformanceOverview GetPerformanceOverview()
{
var totalPropertyUpdates = _propertyMetrics.Values.Sum(m => m.UpdateCount);
var totalCollectionUpdates = _collectionMetrics.Values.Sum(m => m.UpdateCount);
var totalSlowUpdates = _updateEvents.Count(e => e.IsSlowUpdate);
var avgPropertyUpdateTime = _propertyMetrics.Values
.Where(m => m.UpdateCount > 0)
.DefaultIfEmpty(new PropertyUpdateMetrics("dummy"))
.Average(m => m.AverageUpdateTime);
var avgCollectionUpdateTime = _collectionMetrics.Values
.Where(m => m.UpdateCount > 0)
.DefaultIfEmpty(new CollectionUpdateMetrics("dummy"))
.Average(m => m.AverageUpdateTime);
return new PerformanceOverview
{
TotalPropertyUpdates = totalPropertyUpdates,
TotalCollectionUpdates = totalCollectionUpdates,
TotalSlowUpdates = totalSlowUpdates,
AveragePropertyUpdateTime = avgPropertyUpdateTime,
AverageCollectionUpdateTime = avgCollectionUpdateTime,
MonitoredPropertiesCount = MonitoredPropertiesCount,
MonitoredCollectionsCount = MonitoredCollectionsCount,
IsHealthy = totalSlowUpdates < (totalPropertyUpdates + totalCollectionUpdates) * 0.05 // 少于5%的慢更新
};
}
#endregion
#region
/// <summary>
/// 设置监控配置
/// </summary>
/// <param name="reportInterval">报告生成间隔</param>
/// <param name="maxEventHistory">最大事件历史记录数</param>
/// <param name="performanceThreshold">性能阈值(毫秒)</param>
public void ConfigureMonitoring(TimeSpan reportInterval, int maxEventHistory, int performanceThreshold)
{
_reportInterval = reportInterval;
_maxEventHistory = Math.Max(100, maxEventHistory);
_performanceThresholdMs = Math.Max(1, performanceThreshold);
// 重启定时器
_reportTimer?.Change(_reportInterval, _reportInterval);
LogManager.Info($"数据绑定监控配置已更新 - 报告间隔: {reportInterval}, 事件历史: {maxEventHistory}, 性能阈值: {performanceThreshold}ms");
}
/// <summary>
/// 重置所有监控数据
/// </summary>
public void ResetMonitoringData()
{
_propertyMetrics.Clear();
_collectionMetrics.Clear();
while (_updateEvents.TryDequeue(out _)) { }
LogManager.Info("数据绑定监控数据已重置");
}
#endregion
#region IDisposable实现
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
_isMonitoringEnabled = false;
_reportTimer?.Dispose();
// 生成最终报告
try
{
var finalReport = GenerateDetailedReport();
LogManager.Info($"数据绑定性能监控最终报告:\n{finalReport}");
}
catch (Exception ex)
{
LogManager.Error($"生成最终性能报告失败: {ex.Message}");
}
_propertyMetrics.Clear();
_collectionMetrics.Clear();
LogManager.Info("数据绑定性能监控器已释放");
}
#endregion
}
#region
/// <summary>
/// 属性更新上下文 - 用于测量属性更新性能
/// </summary>
internal class PropertyUpdateContext : IDisposable
{
private readonly DataBindingPerformanceMonitor _monitor;
private readonly string _key;
private readonly Stopwatch _stopwatch;
private readonly Dispatcher _dispatcher;
public PropertyUpdateContext(DataBindingPerformanceMonitor monitor, string key, Stopwatch stopwatch, Dispatcher dispatcher)
{
_monitor = monitor;
_key = key;
_stopwatch = stopwatch;
_dispatcher = dispatcher;
}
public void Dispose()
{
_monitor.EndPropertyUpdate(_key, _stopwatch, _dispatcher);
}
}
/// <summary>
/// 集合更新上下文 - 用于测量集合更新性能
/// </summary>
internal class CollectionUpdateContext : IDisposable
{
private readonly DataBindingPerformanceMonitor _monitor;
private readonly string _key;
private readonly Stopwatch _stopwatch;
private readonly int _itemCount;
private readonly Dispatcher _dispatcher;
public CollectionUpdateContext(DataBindingPerformanceMonitor monitor, string key, Stopwatch stopwatch, int itemCount, Dispatcher dispatcher)
{
_monitor = monitor;
_key = key;
_stopwatch = stopwatch;
_itemCount = itemCount;
_dispatcher = dispatcher;
}
public void Dispose()
{
_monitor.EndCollectionUpdate(_key, _stopwatch, _itemCount, _dispatcher);
}
}
/// <summary>
/// 空的IDisposable实现 - 用于禁用监控时的占位符
/// </summary>
internal class EmptyDisposable : IDisposable
{
public void Dispose() { }
}
/// <summary>
/// 属性更新性能指标
/// </summary>
public class PropertyUpdateMetrics
{
public string PropertyKey { get; }
public long UpdateCount { get; private set; }
public double TotalUpdateTime { get; private set; }
public double MaxUpdateTime { get; private set; }
public long SlowUpdateCount { get; private set; }
public long CrossThreadUpdateCount { get; private set; }
public DateTime LastUpdateTime { get; private set; }
public double AverageUpdateTime => UpdateCount > 0 ? TotalUpdateTime / UpdateCount : 0;
private readonly List<DateTime> _updateTimes = new List<DateTime>();
public PropertyUpdateMetrics(string propertyKey)
{
PropertyKey = propertyKey;
LastUpdateTime = DateTime.UtcNow;
}
public void RecordUpdate(double durationMs, bool isOnUIThread)
{
UpdateCount++;
TotalUpdateTime += durationMs;
MaxUpdateTime = Math.Max(MaxUpdateTime, durationMs);
LastUpdateTime = DateTime.UtcNow;
if (durationMs > 16) // 60FPS阈值
{
SlowUpdateCount++;
}
if (!isOnUIThread)
{
CrossThreadUpdateCount++;
}
_updateTimes.Add(DateTime.UtcNow);
}
public void CleanupOldData(DateTime cutoffTime)
{
_updateTimes.RemoveAll(t => t < cutoffTime);
}
}
/// <summary>
/// 集合更新性能指标
/// </summary>
public class CollectionUpdateMetrics
{
public string CollectionKey { get; }
public long UpdateCount { get; private set; }
public double TotalUpdateTime { get; private set; }
public double MaxUpdateTime { get; private set; }
public long TotalItemsProcessed { get; private set; }
public long SlowUpdateCount { get; private set; }
public DateTime LastUpdateTime { get; private set; }
public double AverageUpdateTime => UpdateCount > 0 ? TotalUpdateTime / UpdateCount : 0;
public double AverageItemsPerUpdate => UpdateCount > 0 ? (double)TotalItemsProcessed / UpdateCount : 0;
private readonly List<DateTime> _updateTimes = new List<DateTime>();
public CollectionUpdateMetrics(string collectionKey)
{
CollectionKey = collectionKey;
LastUpdateTime = DateTime.UtcNow;
}
public void RecordUpdate(double durationMs, int itemCount, bool isOnUIThread)
{
UpdateCount++;
TotalUpdateTime += durationMs;
MaxUpdateTime = Math.Max(MaxUpdateTime, durationMs);
TotalItemsProcessed += itemCount;
LastUpdateTime = DateTime.UtcNow;
if (durationMs > 50) // 集合操作的更宽松阈值
{
SlowUpdateCount++;
}
_updateTimes.Add(DateTime.UtcNow);
}
public void CleanupOldData(DateTime cutoffTime)
{
_updateTimes.RemoveAll(t => t < cutoffTime);
}
}
/// <summary>
/// 绑定更新事件
/// </summary>
public class BindingUpdateEvent
{
public DateTime Timestamp { get; set; }
public string BindingPath { get; set; }
public string UpdateType { get; set; }
public double DurationMs { get; set; }
public bool IsSlowUpdate { get; set; }
public int ThreadId { get; set; }
}
/// <summary>
/// 性能概览数据
/// </summary>
public class PerformanceOverview
{
public long TotalPropertyUpdates { get; set; }
public long TotalCollectionUpdates { get; set; }
public long TotalSlowUpdates { get; set; }
public double AveragePropertyUpdateTime { get; set; }
public double AverageCollectionUpdateTime { get; set; }
public int MonitoredPropertiesCount { get; set; }
public int MonitoredCollectionsCount { get; set; }
public bool IsHealthy { get; set; }
}
#endregion
}