clean up and AMD parity check
This commit is contained in:
@@ -25,20 +25,20 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
_startupTrace = StartupTracer.Create();
|
_startupTrace = StartupTracer.Create();
|
||||||
_startupTrace.Mark("App.Constructor.Begin");
|
_startupTrace.Mark("App.Constructor.Begin");
|
||||||
MeasureStartup("App.WireExceptionHandlers", () =>
|
_startupTrace.Measure("App.WireExceptionHandlers", () =>
|
||||||
{
|
{
|
||||||
UnhandledException += App_UnhandledException;
|
UnhandledException += App_UnhandledException;
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
||||||
});
|
});
|
||||||
MeasureStartup("App.InitializeComponent", InitializeComponent);
|
_startupTrace.Measure("App.InitializeComponent", InitializeComponent);
|
||||||
_startupTrace.Mark("App.Constructor.Complete");
|
_startupTrace.Mark("App.Constructor.Complete");
|
||||||
_startupTrace.Flush();
|
_startupTrace.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||||
{
|
{
|
||||||
MeasureStartup("App.OnLaunched", LaunchMainWindow);
|
_startupTrace.Measure("App.OnLaunched", LaunchMainWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LaunchMainWindow()
|
private void LaunchMainWindow()
|
||||||
@@ -50,16 +50,16 @@ public partial class App : Application
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_startupTrace.Mark("App.LaunchMainWindow.Begin");
|
_startupTrace.Mark("App.LaunchMainWindow.Begin");
|
||||||
_serviceProvider = MeasureStartup("App.BuildServiceProvider", () =>
|
_serviceProvider = _startupTrace.Measure("App.BuildServiceProvider", () =>
|
||||||
new ServiceCollection().AddAppServices(_startupTrace).BuildServiceProvider());
|
new ServiceCollection().AddAppServices(_startupTrace).BuildServiceProvider());
|
||||||
MainWindow mainWindow = MeasureStartup("App.CreateMainWindow", () => new MainWindow(
|
MainWindow mainWindow = _startupTrace.Measure("App.CreateMainWindow", () => new MainWindow(
|
||||||
_serviceProvider.GetRequiredService<MainWindowViewModel>(),
|
_serviceProvider.GetRequiredService<MainWindowViewModel>(),
|
||||||
_startupTrace,
|
_startupTrace,
|
||||||
_serviceProvider.GetRequiredService<IMainWindowRuntimeFactory>(),
|
_serviceProvider.GetRequiredService<IMainWindowRuntimeFactory>(),
|
||||||
_serviceProvider));
|
_serviceProvider));
|
||||||
_window = mainWindow;
|
_window = mainWindow;
|
||||||
MeasureStartup("App.ActivateWindow", mainWindow.Activate);
|
_startupTrace.Measure("App.ActivateWindow", mainWindow.Activate);
|
||||||
MeasureStartup("App.StartMonitoringAfterActivation", mainWindow.StartMonitoringAfterActivation);
|
_startupTrace.Measure("App.StartMonitoringAfterActivation", mainWindow.StartMonitoringAfterActivation);
|
||||||
_startupTrace.Mark("App.LaunchMainWindow.Complete");
|
_startupTrace.Mark("App.LaunchMainWindow.Complete");
|
||||||
_startupTrace.Flush();
|
_startupTrace.Flush();
|
||||||
}
|
}
|
||||||
@@ -72,16 +72,6 @@ public partial class App : Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MeasureStartup(string phase, Action action)
|
|
||||||
{
|
|
||||||
_startupTrace.Measure(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private T MeasureStartup<T>(string phase, Func<T> action)
|
|
||||||
{
|
|
||||||
return _startupTrace.Measure(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs args)
|
private static void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs args)
|
||||||
{
|
{
|
||||||
WriteExceptionLog("WinUI unhandled exception", args.Exception);
|
WriteExceptionLog("WinUI unhandled exception", args.Exception);
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ public sealed partial class MainWindow : Window
|
|||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_startupTrace.Mark("MainWindow.Constructor.Begin");
|
_startupTrace.Mark("MainWindow.Constructor.Begin");
|
||||||
|
|
||||||
MeasureStartup("MainWindow.InitializeComponent", InitializeComponent);
|
_startupTrace.Measure("MainWindow.InitializeComponent", InitializeComponent);
|
||||||
|
|
||||||
MainWindowRuntime runtime = MeasureStartup(
|
MainWindowRuntime runtime = _startupTrace.Measure(
|
||||||
"MainWindow.CreateRuntimeServices",
|
"MainWindow.CreateRuntimeServices",
|
||||||
() => runtimeFactory.Create(this, ViewModel, () => Content.XamlRoot, HideShowMainWindow));
|
() => runtimeFactory.Create(this, ViewModel, () => Content.XamlRoot, HideShowMainWindow));
|
||||||
_appWindow = runtime.AppWindow;
|
_appWindow = runtime.AppWindow;
|
||||||
@@ -78,7 +78,7 @@ public sealed partial class MainWindow : Window
|
|||||||
_columnMeasurer = runtime.ColumnMeasurer;
|
_columnMeasurer = runtime.ColumnMeasurer;
|
||||||
|
|
||||||
_trayIconService.IsMainIconEnabled = ViewModel.MinimizeToTray;
|
_trayIconService.IsMainIconEnabled = ViewModel.MinimizeToTray;
|
||||||
MeasureStartup("MainWindow.ApplySavedDeviceColumnWidth", _columnMeasurer.ApplySavedWidth, () => FormattableString.Invariant($"width={_columnMeasurer.DeviceColumnWidth:F0}"));
|
_startupTrace.Measure("MainWindow.ApplySavedDeviceColumnWidth", _columnMeasurer.ApplySavedWidth, () => FormattableString.Invariant($"width={_columnMeasurer.DeviceColumnWidth:F0}"));
|
||||||
_columnMeasurer.SettleTriggered += (_, _) => UpdateSensorColumnWidths();
|
_columnMeasurer.SettleTriggered += (_, _) => UpdateSensorColumnWidths();
|
||||||
|
|
||||||
TryApplyMicaBackdrop();
|
TryApplyMicaBackdrop();
|
||||||
@@ -86,16 +86,16 @@ public sealed partial class MainWindow : Window
|
|||||||
RootGrid.LayoutUpdated += RootGrid_LayoutUpdated;
|
RootGrid.LayoutUpdated += RootGrid_LayoutUpdated;
|
||||||
Bind(ContentGrid, UIElement.IsHitTestVisibleProperty, ViewModel, nameof(ViewModel.IsHardwareInteractionEnabled));
|
Bind(ContentGrid, UIElement.IsHitTestVisibleProperty, ViewModel, nameof(ViewModel.IsHardwareInteractionEnabled));
|
||||||
|
|
||||||
MeasureStartup("MainWindow.PopulateMenuSubmenus", PopulateMenuSubmenus);
|
_startupTrace.Measure("MainWindow.PopulateMenuSubmenus", PopulateMenuSubmenus);
|
||||||
MeasureStartup("MainWindow.PopulateSensorHeader", PopulateSensorHeader);
|
_startupTrace.Measure("MainWindow.PopulateSensorHeader", PopulateSensorHeader);
|
||||||
MeasureStartup("MainWindow.AttachPlotView", () => PlotControl.AttachViewModel(ViewModel));
|
_startupTrace.Measure("MainWindow.AttachPlotView", () => PlotControl.AttachViewModel(ViewModel));
|
||||||
|
|
||||||
MeasureStartup("MainWindow.RestoreWindowBounds", _placementService.Restore);
|
_startupTrace.Measure("MainWindow.RestoreWindowBounds", _placementService.Restore);
|
||||||
MeasureStartup("MainWindow.MaximizeWindow", _placementService.Maximize);
|
_startupTrace.Measure("MainWindow.MaximizeWindow", _placementService.Maximize);
|
||||||
MeasureStartup("MainWindow.ApplyTheme", ApplyTheme);
|
_startupTrace.Measure("MainWindow.ApplyTheme", ApplyTheme);
|
||||||
MeasureStartup("MainWindow.UpdatePlotLayout", UpdatePlotLayout);
|
_startupTrace.Measure("MainWindow.UpdatePlotLayout", UpdatePlotLayout);
|
||||||
|
|
||||||
_timer = MeasureStartup("MainWindow.CreateTimer", () =>
|
_timer = _startupTrace.Measure("MainWindow.CreateTimer", () =>
|
||||||
{
|
{
|
||||||
DispatcherQueueTimer timer = DispatcherQueue.CreateTimer();
|
DispatcherQueueTimer timer = DispatcherQueue.CreateTimer();
|
||||||
timer.Interval = ViewModel.UpdateInterval;
|
timer.Interval = ViewModel.UpdateInterval;
|
||||||
@@ -103,7 +103,7 @@ public sealed partial class MainWindow : Window
|
|||||||
return timer;
|
return timer;
|
||||||
});
|
});
|
||||||
|
|
||||||
MeasureStartup("MainWindow.WireEvents", () =>
|
_startupTrace.Measure("MainWindow.WireEvents", () =>
|
||||||
{
|
{
|
||||||
ViewModel.PropertyChanged += (_, args) =>
|
ViewModel.PropertyChanged += (_, args) =>
|
||||||
{
|
{
|
||||||
@@ -173,11 +173,11 @@ public sealed partial class MainWindow : Window
|
|||||||
{
|
{
|
||||||
_startupTrace.Mark("MainWindow.StartMonitoringAfterActivation.Begin");
|
_startupTrace.Mark("MainWindow.StartMonitoringAfterActivation.Begin");
|
||||||
ApplyInitialWindowState();
|
ApplyInitialWindowState();
|
||||||
await MeasureStartupAsync("MainWindowViewModel.StartAsync", ViewModel.StartAsync);
|
await _startupTrace.MeasureAsync("MainWindowViewModel.StartAsync", ViewModel.StartAsync);
|
||||||
SyncTraySensors();
|
SyncTraySensors();
|
||||||
SyncGadgetSensors();
|
SyncGadgetSensors();
|
||||||
UpdateGadgetVisibility();
|
UpdateGadgetVisibility();
|
||||||
MeasureStartup("MainWindow.StartTimer", _timer.Start);
|
_startupTrace.Measure("MainWindow.StartTimer", _timer.Start);
|
||||||
_startupTrace.Mark("MainWindow.StartMonitoringAfterActivation.Complete");
|
_startupTrace.Mark("MainWindow.StartMonitoringAfterActivation.Complete");
|
||||||
RequestStartupTraceComplete();
|
RequestStartupTraceComplete();
|
||||||
_startupTrace.Flush();
|
_startupTrace.Flush();
|
||||||
@@ -218,47 +218,6 @@ public sealed partial class MainWindow : Window
|
|||||||
_startupTrace.Flush();
|
_startupTrace.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MeasureStartup(string phase, Action action)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_startupTrace.Measure(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MeasureStartup(string phase, Action action, Func<string> getDetail)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_startupTrace.Measure(phase, action, getDetail);
|
|
||||||
}
|
|
||||||
|
|
||||||
private T MeasureStartup<T>(string phase, Func<T> action)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
return action();
|
|
||||||
|
|
||||||
return _startupTrace.Measure(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task MeasureStartupAsync(string phase, Func<Task> action)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
{
|
|
||||||
await action();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _startupTrace.MeasureAsync(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PopulateMenuSubmenus()
|
private void PopulateMenuSubmenus()
|
||||||
{
|
{
|
||||||
PopulateRadioSubMenu(TemperatureUnitMenu, [
|
PopulateRadioSubMenu(TemperatureUnitMenu, [
|
||||||
@@ -547,7 +506,7 @@ public sealed partial class MainWindow : Window
|
|||||||
|
|
||||||
private void RebuildSensorTree()
|
private void RebuildSensorTree()
|
||||||
{
|
{
|
||||||
MeasureStartup("MainWindow.RebuildSensorTree", RebuildSensorTreeCore, GetRootSizeDetail);
|
_startupTrace.Measure("MainWindow.RebuildSensorTree", RebuildSensorTreeCore, GetRootSizeDetail);
|
||||||
_columnMeasurer.ScheduleSettle();
|
_columnMeasurer.ScheduleSettle();
|
||||||
SyncTraySensors();
|
SyncTraySensors();
|
||||||
SyncGadgetSensors();
|
SyncGadgetSensors();
|
||||||
@@ -842,7 +801,7 @@ public sealed partial class MainWindow : Window
|
|||||||
|
|
||||||
private void UpdateSensorColumnWidths()
|
private void UpdateSensorColumnWidths()
|
||||||
{
|
{
|
||||||
MeasureStartup("MainWindow.UpdateSensorColumnWidths", _columnMeasurer.UpdateWidths, () => FormattableString.Invariant($"rows={_columnMeasurer.RowCount}, cacheEntries={_columnMeasurer.CacheEntryCount}, deviceWidth={_columnMeasurer.DeviceColumnWidth:F0}, settled={_columnMeasurer.IsSettled}"));
|
_startupTrace.Measure("MainWindow.UpdateSensorColumnWidths", _columnMeasurer.UpdateWidths, () => FormattableString.Invariant($"rows={_columnMeasurer.RowCount}, cacheEntries={_columnMeasurer.CacheEntryCount}, deviceWidth={_columnMeasurer.DeviceColumnWidth:F0}, settled={_columnMeasurer.IsSettled}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextBlock CreateHeaderText(string text, int column, Visibility visibility, string? bindingPath = null)
|
private TextBlock CreateHeaderText(string text, int column, Visibility visibility, string? bindingPath = null)
|
||||||
|
|||||||
@@ -228,34 +228,26 @@ public sealed class HardwareMonitorService : IHardwareMonitorService
|
|||||||
ForceDriveWakeup = Settings.GetValue("forceDriveWakeupItem", false);
|
ForceDriveWakeup = Settings.GetValue("forceDriveWakeupItem", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly string[] WinUiDeferredDetectionDefaults =
|
||||||
|
{
|
||||||
|
DeferDimmDetectionSetting,
|
||||||
|
DeferCpuInitialUpdateSetting,
|
||||||
|
DeferTscEstimationSetting,
|
||||||
|
DeferNvidiaDetectionSetting,
|
||||||
|
DeferStorageDetectionSetting,
|
||||||
|
DeferNetworkDetectionSetting,
|
||||||
|
DeferIntelGpuDetectionSetting,
|
||||||
|
DeferControllerDetectionSetting,
|
||||||
|
DeferPsuDetectionSetting,
|
||||||
|
};
|
||||||
|
|
||||||
private void ApplyWinUiHardwareDefaults()
|
private void ApplyWinUiHardwareDefaults()
|
||||||
{
|
{
|
||||||
if (!Settings.Contains(DeferDimmDetectionSetting))
|
foreach (string setting in WinUiDeferredDetectionDefaults)
|
||||||
Settings.SetValue(DeferDimmDetectionSetting, true);
|
{
|
||||||
|
if (!Settings.Contains(setting))
|
||||||
if (!Settings.Contains(DeferCpuInitialUpdateSetting))
|
Settings.SetValue(setting, true);
|
||||||
Settings.SetValue(DeferCpuInitialUpdateSetting, true);
|
}
|
||||||
|
|
||||||
if (!Settings.Contains(DeferTscEstimationSetting))
|
|
||||||
Settings.SetValue(DeferTscEstimationSetting, true);
|
|
||||||
|
|
||||||
if (!Settings.Contains(DeferNvidiaDetectionSetting))
|
|
||||||
Settings.SetValue(DeferNvidiaDetectionSetting, true);
|
|
||||||
|
|
||||||
if (!Settings.Contains(DeferStorageDetectionSetting))
|
|
||||||
Settings.SetValue(DeferStorageDetectionSetting, true);
|
|
||||||
|
|
||||||
if (!Settings.Contains(DeferNetworkDetectionSetting))
|
|
||||||
Settings.SetValue(DeferNetworkDetectionSetting, true);
|
|
||||||
|
|
||||||
if (!Settings.Contains(DeferIntelGpuDetectionSetting))
|
|
||||||
Settings.SetValue(DeferIntelGpuDetectionSetting, true);
|
|
||||||
|
|
||||||
if (!Settings.Contains(DeferControllerDetectionSetting))
|
|
||||||
Settings.SetValue(DeferControllerDetectionSetting, true);
|
|
||||||
|
|
||||||
if (!Settings.Contains(DeferPsuDetectionSetting))
|
|
||||||
Settings.SetValue(DeferPsuDetectionSetting, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetHardwareEnabled(string settingName, bool value, Action<bool> setter)
|
private void SetHardwareEnabled(string settingName, bool value, Action<bool> setter)
|
||||||
|
|||||||
@@ -99,6 +99,12 @@ internal sealed class FileStartupTracer : IStartupTracer
|
|||||||
|
|
||||||
public void Measure(string phase, Action action, Func<string>? getDetail)
|
public void Measure(string phase, Action action, Func<string>? getDetail)
|
||||||
{
|
{
|
||||||
|
if (IsComplete)
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TimeSpan start = _totalStopwatch.Elapsed;
|
TimeSpan start = _totalStopwatch.Elapsed;
|
||||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||||
try
|
try
|
||||||
@@ -117,18 +123,16 @@ internal sealed class FileStartupTracer : IStartupTracer
|
|||||||
|
|
||||||
public T Measure<T>(string phase, Func<T> action)
|
public T Measure<T>(string phase, Func<T> action)
|
||||||
{
|
{
|
||||||
return Measure(phase, action, null);
|
if (IsComplete)
|
||||||
}
|
return action();
|
||||||
|
|
||||||
public T Measure<T>(string phase, Func<T> action, Func<T, string>? getDetail)
|
|
||||||
{
|
|
||||||
TimeSpan start = _totalStopwatch.Elapsed;
|
TimeSpan start = _totalStopwatch.Elapsed;
|
||||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T result = action();
|
T result = action();
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
AddEntry(phase, start, stopwatch.Elapsed, "OK", GetDetail(result, getDetail));
|
AddEntry(phase, start, stopwatch.Elapsed, "OK", "");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -141,42 +145,19 @@ internal sealed class FileStartupTracer : IStartupTracer
|
|||||||
|
|
||||||
public async Task MeasureAsync(string phase, Func<Task> action)
|
public async Task MeasureAsync(string phase, Func<Task> action)
|
||||||
{
|
{
|
||||||
await MeasureAsync(phase, action, null);
|
if (IsComplete)
|
||||||
}
|
{
|
||||||
|
await action();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task MeasureAsync(string phase, Func<Task> action, Func<string>? getDetail)
|
|
||||||
{
|
|
||||||
TimeSpan start = _totalStopwatch.Elapsed;
|
TimeSpan start = _totalStopwatch.Elapsed;
|
||||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await action();
|
await action();
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
AddEntry(phase, start, stopwatch.Elapsed, "OK", GetDetail(getDetail));
|
AddEntry(phase, start, stopwatch.Elapsed, "OK", "");
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
stopwatch.Stop();
|
|
||||||
AddEntry(phase, start, stopwatch.Elapsed, "ERROR", $"{ex.GetType().FullName}: {ex.Message}");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<T> MeasureAsync<T>(string phase, Func<Task<T>> action)
|
|
||||||
{
|
|
||||||
return await MeasureAsync(phase, action, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<T> MeasureAsync<T>(string phase, Func<Task<T>> action, Func<T, string>? getDetail)
|
|
||||||
{
|
|
||||||
TimeSpan start = _totalStopwatch.Elapsed;
|
|
||||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
T result = await action();
|
|
||||||
stopwatch.Stop();
|
|
||||||
AddEntry(phase, start, stopwatch.Elapsed, "OK", GetDetail(result, getDetail));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -212,21 +193,6 @@ internal sealed class FileStartupTracer : IStartupTracer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetDetail<T>(T result, Func<T, string>? getDetail)
|
|
||||||
{
|
|
||||||
if (getDetail == null)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return getDetail(result) ?? "";
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return $"Detail unavailable: {ex.GetType().FullName}: {ex.Message}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddEntry(string phase, TimeSpan elapsed, string status, string detail)
|
private void AddEntry(string phase, TimeSpan elapsed, string status, string detail)
|
||||||
{
|
{
|
||||||
AddEntry(phase, _totalStopwatch.Elapsed, elapsed, status, detail);
|
AddEntry(phase, _totalStopwatch.Elapsed, elapsed, status, detail);
|
||||||
|
|||||||
@@ -27,13 +27,5 @@ internal interface IStartupTracer : IDisposable
|
|||||||
|
|
||||||
T Measure<T>(string phase, Func<T> action);
|
T Measure<T>(string phase, Func<T> action);
|
||||||
|
|
||||||
T Measure<T>(string phase, Func<T> action, Func<T, string>? getDetail);
|
|
||||||
|
|
||||||
Task MeasureAsync(string phase, Func<Task> action);
|
Task MeasureAsync(string phase, Func<Task> action);
|
||||||
|
|
||||||
Task MeasureAsync(string phase, Func<Task> action, Func<string>? getDetail);
|
|
||||||
|
|
||||||
Task<T> MeasureAsync<T>(string phase, Func<Task<T>> action);
|
|
||||||
|
|
||||||
Task<T> MeasureAsync<T>(string phase, Func<Task<T>> action, Func<T, string>? getDetail);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,31 +48,11 @@ internal sealed class NoOpStartupTracer : IStartupTracer
|
|||||||
return action();
|
return action();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Measure<T>(string phase, Func<T> action, Func<T, string>? getDetail)
|
|
||||||
{
|
|
||||||
return action();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task MeasureAsync(string phase, Func<Task> action)
|
public Task MeasureAsync(string phase, Func<Task> action)
|
||||||
{
|
{
|
||||||
return action();
|
return action();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task MeasureAsync(string phase, Func<Task> action, Func<string>? getDetail)
|
|
||||||
{
|
|
||||||
return action();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T> MeasureAsync<T>(string phase, Func<Task<T>> action)
|
|
||||||
{
|
|
||||||
return action();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T> MeasureAsync<T>(string phase, Func<Task<T>> action, Func<T, string>? getDetail)
|
|
||||||
{
|
|
||||||
return action();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -873,12 +873,12 @@ public sealed class MainWindowViewModel : ViewModelBase, IDisposable
|
|||||||
IsHardwareLoading = true;
|
IsHardwareLoading = true;
|
||||||
_startupTrace.Mark("MainWindowViewModel.StartAsync.Begin");
|
_startupTrace.Mark("MainWindowViewModel.StartAsync.Begin");
|
||||||
StatusText = "Initializing hardware sensors...";
|
StatusText = "Initializing hardware sensors...";
|
||||||
await MeasureStartupAsync("MainWindowViewModel.HardwareMonitor.OpenAsync", () => _hardwareMonitor.OpenAsync(raiseTreeRebuilt: false));
|
await _startupTrace.MeasureAsync("MainWindowViewModel.HardwareMonitor.OpenAsync", () => _hardwareMonitor.OpenAsync(raiseTreeRebuilt: false));
|
||||||
MeasureStartup("MainWindowViewModel.UpdateRoot", UpdateRoot, GetRootDetail);
|
_startupTrace.Measure("MainWindowViewModel.UpdateRoot", UpdateRoot, GetRootDetail);
|
||||||
StatusText = "Reading sensor values...";
|
StatusText = "Reading sensor values...";
|
||||||
await MeasureStartupAsync("MainWindowViewModel.InitialSensorValueUpdate", () => RefreshSensorValuesAsync(trackPlotPoints: true, logSensors: false));
|
await _startupTrace.MeasureAsync("MainWindowViewModel.InitialSensorValueUpdate", () => RefreshSensorValuesAsync(trackPlotPoints: true, logSensors: false));
|
||||||
MeasureStartup("MainWindowViewModel.StartWebServerFromSettings", StartWebServerFromSettings);
|
_startupTrace.Measure("MainWindowViewModel.StartWebServerFromSettings", StartWebServerFromSettings);
|
||||||
MeasureStartup("MainWindowViewModel.UpdateStatus", UpdateStatus, GetRootDetail);
|
_startupTrace.Measure("MainWindowViewModel.UpdateStatus", UpdateStatus, GetRootDetail);
|
||||||
_isStarted = true;
|
_isStarted = true;
|
||||||
_startupTrace.Mark("MainWindowViewModel.StartAsync.Complete", GetRootDetail());
|
_startupTrace.Mark("MainWindowViewModel.StartAsync.Complete", GetRootDetail());
|
||||||
}
|
}
|
||||||
@@ -956,47 +956,6 @@ public sealed class MainWindowViewModel : ViewModelBase, IDisposable
|
|||||||
return $"{hardwareCount} hardware device(s), {sensorCount} sensor(s)";
|
return $"{hardwareCount} hardware device(s), {sensorCount} sensor(s)";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MeasureStartup(string phase, Action action)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_startupTrace.Measure(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MeasureStartup(string phase, Action action, Func<string> getDetail)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_startupTrace.Measure(phase, action, getDetail);
|
|
||||||
}
|
|
||||||
|
|
||||||
private T MeasureStartup<T>(string phase, Func<T> action)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
return action();
|
|
||||||
|
|
||||||
return _startupTrace.Measure(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task MeasureStartupAsync(string phase, Func<Task> action)
|
|
||||||
{
|
|
||||||
if (_startupTrace.IsComplete)
|
|
||||||
{
|
|
||||||
await action();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _startupTrace.MeasureAsync(phase, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NotifyColumnVisibilityChanged()
|
private void NotifyColumnVisibilityChanged()
|
||||||
{
|
{
|
||||||
OnPropertyChanged(nameof(ValueColumnVisibility));
|
OnPropertyChanged(nameof(ValueColumnVisibility));
|
||||||
@@ -1038,11 +997,11 @@ public sealed class MainWindowViewModel : ViewModelBase, IDisposable
|
|||||||
|
|
||||||
private void UpdateRoot()
|
private void UpdateRoot()
|
||||||
{
|
{
|
||||||
MeasureStartup("MainWindowViewModel.RootItems.Clear", RootItems.Clear);
|
_startupTrace.Measure("MainWindowViewModel.RootItems.Clear", RootItems.Clear);
|
||||||
SensorTreeItemViewModel root = MeasureStartup("MainWindowViewModel.GetHardwareRoot", () => _hardwareMonitor.Root);
|
SensorTreeItemViewModel root = _startupTrace.Measure("MainWindowViewModel.GetHardwareRoot", () => _hardwareMonitor.Root);
|
||||||
MeasureStartup("MainWindowViewModel.ConfigureRoot", () => root.Configure(TemperatureUnit, ShowHiddenSensors, ShowValueColumn, ShowMinColumn, ShowMaxColumn), GetRootDetail);
|
_startupTrace.Measure("MainWindowViewModel.ConfigureRoot", () => root.Configure(TemperatureUnit, ShowHiddenSensors, ShowValueColumn, ShowMinColumn, ShowMaxColumn), GetRootDetail);
|
||||||
MeasureStartup("MainWindowViewModel.RootItems.Add", () => RootItems.Add(root), GetRootDetail);
|
_startupTrace.Measure("MainWindowViewModel.RootItems.Add", () => RootItems.Add(root), GetRootDetail);
|
||||||
MeasureStartup("MainWindowViewModel.ApplySensorValuesTimeWindow", ApplySensorValuesTimeWindow, GetRootDetail);
|
_startupTrace.Measure("MainWindowViewModel.ApplySensorValuesTimeWindow", ApplySensorValuesTimeWindow, GetRootDetail);
|
||||||
RefreshStatusCounts();
|
RefreshStatusCounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ using LibreHardwareMonitor.Hardware.PowerMonitor;
|
|||||||
using LibreHardwareMonitor.Hardware.Psu.Corsair;
|
using LibreHardwareMonitor.Hardware.Psu.Corsair;
|
||||||
using LibreHardwareMonitor.Hardware.Psu.Msi;
|
using LibreHardwareMonitor.Hardware.Psu.Msi;
|
||||||
using LibreHardwareMonitor.Hardware.Storage;
|
using LibreHardwareMonitor.Hardware.Storage;
|
||||||
|
using static LibreHardwareMonitor.Hardware.HardwareStartupTrace;
|
||||||
|
|
||||||
namespace LibreHardwareMonitor.Hardware;
|
namespace LibreHardwareMonitor.Hardware;
|
||||||
|
|
||||||
@@ -769,19 +770,6 @@ public class Computer : IComputer
|
|||||||
AddMeasuredGroup(startupTrace, "BatteryGroup", () => new BatteryGroup(_settings));
|
AddMeasuredGroup(startupTrace, "BatteryGroup", () => new BatteryGroup(_settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Measure(HardwareStartupTrace startupTrace, string phase, Action action)
|
|
||||||
{
|
|
||||||
if (startupTrace != null)
|
|
||||||
startupTrace.Measure(phase, action);
|
|
||||||
else
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T Measure<T>(HardwareStartupTrace startupTrace, string phase, Func<T> action)
|
|
||||||
{
|
|
||||||
return startupTrace != null ? startupTrace.Measure(phase, action) : action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddMeasuredGroup(HardwareStartupTrace startupTrace, string phase, Func<IGroup> createGroup)
|
private void AddMeasuredGroup(HardwareStartupTrace startupTrace, string phase, Func<IGroup> createGroup)
|
||||||
{
|
{
|
||||||
Add(Measure(startupTrace, phase, createGroup));
|
Add(Measure(startupTrace, phase, createGroup));
|
||||||
|
|||||||
@@ -93,7 +93,9 @@ internal sealed class Amd0FCpu : AmdCpu
|
|||||||
Mutexes.ReleasePciBus();
|
Mutexes.ReleasePciBus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasTimeStampCounter)
|
// TimeStampCounterFrequency is 0 while deferred TSC estimation is still pending; skip the clock math until it
|
||||||
|
// lands so the core/bus clocks keep their previous value instead of momentarily reporting 0 MHz (see IntelCpu).
|
||||||
|
if (HasTimeStampCounter && TimeStampCounterFrequency > 0)
|
||||||
{
|
{
|
||||||
double newBusClock = 0;
|
double newBusClock = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -396,7 +396,11 @@ internal sealed class Amd17Cpu : AmdCpu
|
|||||||
}
|
}
|
||||||
|
|
||||||
double timeStampCounterMultiplier = GetTimeStampCounterMultiplier();
|
double timeStampCounterMultiplier = GetTimeStampCounterMultiplier();
|
||||||
if (timeStampCounterMultiplier > 0)
|
|
||||||
|
// When TSC estimation is deferred to the background, TimeStampCounterFrequency is 0 until the estimate
|
||||||
|
// lands (or GenericCpu.Update self-corrects it from real TSC deltas). Skip the bus-clock math until then so
|
||||||
|
// the sensor keeps its previous value instead of momentarily reporting 0 MHz (mirrors IntelCpu).
|
||||||
|
if (timeStampCounterMultiplier > 0 && _cpu.TimeStampCounterFrequency > 0)
|
||||||
{
|
{
|
||||||
_busClock.Value = (float)(_cpu.TimeStampCounterFrequency / timeStampCounterMultiplier);
|
_busClock.Value = (float)(_cpu.TimeStampCounterFrequency / timeStampCounterMultiplier);
|
||||||
_cpu.ActivateSensor(_busClock);
|
_cpu.ActivateSensor(_busClock);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using static LibreHardwareMonitor.Hardware.HardwareStartupTrace;
|
||||||
|
|
||||||
namespace LibreHardwareMonitor.Hardware.Cpu;
|
namespace LibreHardwareMonitor.Hardware.Cpu;
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ internal class CpuGroup : IGroup
|
|||||||
_threads[index] = coreThreads;
|
_threads[index] = coreThreads;
|
||||||
|
|
||||||
GenericCpu cpu = Measure(startupTrace,
|
GenericCpu cpu = Measure(startupTrace,
|
||||||
$"CpuGroup.Processor{index}.{GetCpuConstructorName(threads[0])}",
|
$"CpuGroup.Processor{index}.CreateCpu",
|
||||||
() => CreateCpu(index, coreThreads, settings, startupTrace),
|
() => CreateCpu(index, coreThreads, settings, startupTrace),
|
||||||
DescribeCpu);
|
DescribeCpu);
|
||||||
if (cpu != null)
|
if (cpu != null)
|
||||||
@@ -137,36 +138,6 @@ internal class CpuGroup : IGroup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetCpuConstructorName(CpuId thread)
|
|
||||||
{
|
|
||||||
switch (thread.Vendor)
|
|
||||||
{
|
|
||||||
case Vendor.Intel:
|
|
||||||
return nameof(IntelCpu);
|
|
||||||
case Vendor.AMD:
|
|
||||||
switch (thread.Family)
|
|
||||||
{
|
|
||||||
case 0x0F:
|
|
||||||
return nameof(Amd0FCpu);
|
|
||||||
case 0x10:
|
|
||||||
case 0x11:
|
|
||||||
case 0x12:
|
|
||||||
case 0x14:
|
|
||||||
case 0x15:
|
|
||||||
case 0x16:
|
|
||||||
return "UnsupportedAmdCpu";
|
|
||||||
case 0x17:
|
|
||||||
case 0x19:
|
|
||||||
case 0x1A:
|
|
||||||
return nameof(Amd17Cpu);
|
|
||||||
default:
|
|
||||||
return nameof(GenericCpu);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nameof(GenericCpu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string DescribeProcessorThreads(CpuId[][] processorThreads)
|
private static string DescribeProcessorThreads(CpuId[][] processorThreads)
|
||||||
{
|
{
|
||||||
int threadCount = 0;
|
int threadCount = 0;
|
||||||
@@ -178,12 +149,7 @@ internal class CpuGroup : IGroup
|
|||||||
|
|
||||||
private static string DescribeCpu(GenericCpu cpu)
|
private static string DescribeCpu(GenericCpu cpu)
|
||||||
{
|
{
|
||||||
return cpu != null ? $"{cpu.Name}, {cpu.Sensors.Length} sensor(s)" : "Unsupported CPU family";
|
return cpu != null ? $"{cpu.GetType().Name}: {cpu.Name}, {cpu.Sensors.Length} sensor(s)" : "Unsupported CPU family";
|
||||||
}
|
|
||||||
|
|
||||||
private static T Measure<T>(HardwareStartupTrace startupTrace, string phase, Func<T> action, Func<T, string> getDetail)
|
|
||||||
{
|
|
||||||
return startupTrace != null ? startupTrace.Measure(phase, action, getDetail) : action();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CpuId[][] GetProcessorThreads()
|
private static CpuId[][] GetProcessorThreads()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using static LibreHardwareMonitor.Hardware.HardwareStartupTrace;
|
||||||
|
|
||||||
namespace LibreHardwareMonitor.Hardware.Cpu;
|
namespace LibreHardwareMonitor.Hardware.Cpu;
|
||||||
|
|
||||||
@@ -182,19 +183,6 @@ public class GenericCpu : Hardware
|
|||||||
return new Identifier(s, processorIndex.ToString(CultureInfo.InvariantCulture));
|
return new Identifier(s, processorIndex.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Measure(HardwareStartupTrace startupTrace, string phase, Action action)
|
|
||||||
{
|
|
||||||
if (startupTrace != null)
|
|
||||||
startupTrace.Measure(phase, action);
|
|
||||||
else
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T Measure<T>(HardwareStartupTrace startupTrace, string phase, Func<T> action, Func<T, string> getDetail)
|
|
||||||
{
|
|
||||||
return startupTrace != null ? startupTrace.Measure(phase, action, getDetail) : action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EstimateTimeStampCounterFrequency(CancellationToken cancellationToken, out double frequency, out double error)
|
private static void EstimateTimeStampCounterFrequency(CancellationToken cancellationToken, out double frequency, out double error)
|
||||||
{
|
{
|
||||||
// preload the function
|
// preload the function
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using LibreHardwareMonitor.PawnIo;
|
using LibreHardwareMonitor.PawnIo;
|
||||||
|
using static LibreHardwareMonitor.Hardware.HardwareStartupTrace;
|
||||||
|
|
||||||
namespace LibreHardwareMonitor.Hardware.Cpu;
|
namespace LibreHardwareMonitor.Hardware.Cpu;
|
||||||
|
|
||||||
@@ -572,19 +573,6 @@ internal sealed class IntelCpu : GenericCpu
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Measure(HardwareStartupTrace startupTrace, string phase, Action action)
|
|
||||||
{
|
|
||||||
if (startupTrace != null)
|
|
||||||
startupTrace.Measure(phase, action);
|
|
||||||
else
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T Measure<T>(HardwareStartupTrace startupTrace, string phase, Func<T> action)
|
|
||||||
{
|
|
||||||
return startupTrace != null ? startupTrace.Measure(phase, action) : action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool ShouldDeferInitialUpdate(ISettings settings)
|
private static bool ShouldDeferInitialUpdate(ISettings settings)
|
||||||
{
|
{
|
||||||
return SettingsParsing.ShouldDefer(settings, DeferInitialUpdateSetting, DeferInitialUpdateEnvironmentVariable);
|
return SettingsParsing.ShouldDefer(settings, DeferInitialUpdateSetting, DeferInitialUpdateEnvironmentVariable);
|
||||||
|
|||||||
@@ -92,6 +92,30 @@ internal sealed class HardwareStartupTrace : IDisposable
|
|||||||
AddEntry(phase, TimeSpan.Zero, "SKIPPED", null, reason);
|
AddEntry(phase, TimeSpan.Zero, "SKIPPED", null, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs <paramref name="action" /> under <paramref name="trace" />, or directly when tracing is disabled
|
||||||
|
/// (<paramref name="trace" /> is null). Lets callers measure optional startup phases without repeating a null check.
|
||||||
|
/// </summary>
|
||||||
|
public static void Measure(HardwareStartupTrace trace, string phase, Action action)
|
||||||
|
{
|
||||||
|
if (trace != null)
|
||||||
|
trace.Measure(phase, action);
|
||||||
|
else
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Measure(HardwareStartupTrace, string, Action)" />
|
||||||
|
public static T Measure<T>(HardwareStartupTrace trace, string phase, Func<T> action)
|
||||||
|
{
|
||||||
|
return trace != null ? trace.Measure(phase, action) : action();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Measure(HardwareStartupTrace, string, Action)" />
|
||||||
|
public static T Measure<T>(HardwareStartupTrace trace, string phase, Func<T> action, Func<T, string> getDetail)
|
||||||
|
{
|
||||||
|
return trace != null ? trace.Measure(phase, action, getDetail) : action();
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsEnabled(ISettings settings)
|
private static bool IsEnabled(ISettings settings)
|
||||||
{
|
{
|
||||||
string settingValue = settings.GetValue(EnabledSetting, "false");
|
string settingValue = settings.GetValue(EnabledSetting, "false");
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using RAMSPDToolkit.SPD;
|
|||||||
using RAMSPDToolkit.SPD.Enums;
|
using RAMSPDToolkit.SPD.Enums;
|
||||||
using RAMSPDToolkit.SPD.Interop.Shared;
|
using RAMSPDToolkit.SPD.Interop.Shared;
|
||||||
using RAMSPDToolkit.Windows.Driver;
|
using RAMSPDToolkit.Windows.Driver;
|
||||||
|
using static LibreHardwareMonitor.Hardware.HardwareStartupTrace;
|
||||||
|
|
||||||
namespace LibreHardwareMonitor.Hardware.Memory;
|
namespace LibreHardwareMonitor.Hardware.Memory;
|
||||||
|
|
||||||
@@ -273,22 +274,4 @@ internal class MemoryGroup : IGroup, IHardwareChanged, IHardwareDiscoveryTask
|
|||||||
foreach (Hardware hardware in additions)
|
foreach (Hardware hardware in additions)
|
||||||
HardwareAdded?.Invoke(hardware);
|
HardwareAdded?.Invoke(hardware);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Measure(HardwareStartupTrace startupTrace, string phase, Action action)
|
|
||||||
{
|
|
||||||
if (startupTrace != null)
|
|
||||||
startupTrace.Measure(phase, action);
|
|
||||||
else
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T Measure<T>(HardwareStartupTrace startupTrace, string phase, Func<T> action)
|
|
||||||
{
|
|
||||||
return startupTrace != null ? startupTrace.Measure(phase, action) : action();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T Measure<T>(HardwareStartupTrace startupTrace, string phase, Func<T> action, Func<T, string> getDetail)
|
|
||||||
{
|
|
||||||
return startupTrace != null ? startupTrace.Measure(phase, action, getDetail) : action();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ Removed from `AddDeferredGroup`/`AddDeferredGroups` (unreachable since `StartDef
|
|||||||
- **`CpuGroup`** was **not** parallelized — only refactored to extract `CreateCpu`. Returning `null` for unsupported AMD families preserves the original "add nothing" behavior.
|
- **`CpuGroup`** was **not** parallelized — only refactored to extract `CreateCpu`. Returning `null` for unsupported AMD families preserves the original "add nothing" behavior.
|
||||||
- **`TreeRebuildCoalescer`** correctly coalesces a burst into ~one rebuild (single debounced worker, re-arms on a late change).
|
- **`TreeRebuildCoalescer`** correctly coalesces a burst into ~one rebuild (single debounced worker, re-arms on a late change).
|
||||||
- **Disposed-`CancellationToken` reads** after cancellation are safe (`IsCancellationRequested` does not throw post-dispose).
|
- **Disposed-`CancellationToken` reads** after cancellation are safe (`IsCancellationRequested` does not throw post-dispose).
|
||||||
- **Startup tracing** is fully no-op when disabled (`HardwareStartupTrace.Create` returns `null`; the `Measure` wrappers and `MainWindowViewModel.MeasureStartup` short-circuit).
|
- **Startup tracing** is fully no-op when disabled (`HardwareStartupTrace.Create` returns `null` and the static `HardwareStartupTrace.Measure` helpers run the action directly; on the WinUI side `NoOpStartupTracer` does the same, and `FileStartupTracer` short-circuits once startup is complete).
|
||||||
- **WinUI tree updates are marshaled**: the VM's `HardwareMonitor_TreeRebuilt` handler marshals to the UI via `DispatcherQueue.TryEnqueue`. (Only `Logger` was unmarshaled — fixed in F3.)
|
- **WinUI tree updates are marshaled**: the VM's `HardwareMonitor_TreeRebuilt` handler marshals to the UI via `DispatcherQueue.TryEnqueue`. (Only `Logger` was unmarshaled — fixed in F3.)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user