wip
This commit is contained in:
@@ -39,17 +39,11 @@ namespace LibreHardwareMonitor.Hardware;
|
||||
public class Computer : IComputer
|
||||
{
|
||||
private const string DeferNetworkDetectionEnvironmentVariable = "LHM_NETWORK_DEFER_DETECTION";
|
||||
private const string DeferNetworkDetectionSetting = "network.deferDetection";
|
||||
private const string DeferNvidiaDetectionEnvironmentVariable = "LHM_NVIDIA_DEFER_DETECTION";
|
||||
private const string DeferNvidiaDetectionSetting = "nvidia.deferDetection";
|
||||
private const string DeferStorageDetectionEnvironmentVariable = "LHM_STORAGE_DEFER_DETECTION";
|
||||
private const string DeferStorageDetectionSetting = "storage.deferDetection";
|
||||
private const string DeferIntelGpuDetectionEnvironmentVariable = "LHM_INTEL_GPU_DEFER_DETECTION";
|
||||
private const string DeferIntelGpuDetectionSetting = "gpu.deferIntelDetection";
|
||||
private const string DeferControllerDetectionEnvironmentVariable = "LHM_CONTROLLER_DEFER_DETECTION";
|
||||
private const string DeferControllerDetectionSetting = "controller.deferDetection";
|
||||
private const string DeferPsuDetectionEnvironmentVariable = "LHM_PSU_DEFER_DETECTION";
|
||||
private const string DeferPsuDetectionSetting = "psu.deferDetection";
|
||||
|
||||
private readonly object _deferredGroupLock = new();
|
||||
private readonly List<IGroup> _groups = new();
|
||||
@@ -100,8 +94,6 @@ public class Computer : IComputer
|
||||
/// <inheritdoc />
|
||||
public event HardwareEventHandler HardwareRemoved;
|
||||
|
||||
public event EventHandler HardwareDiscoveryCompleted;
|
||||
|
||||
public Task HardwareDiscoveryTask
|
||||
{
|
||||
get
|
||||
@@ -679,7 +671,7 @@ public class Computer : IComputer
|
||||
"NvidiaGroup",
|
||||
() => new NvidiaGroup(_settings),
|
||||
() => _gpuEnabled,
|
||||
DeferNvidiaDetectionSetting,
|
||||
HardwareSettingsKeys.NvidiaDeferDetection,
|
||||
DeferNvidiaDetectionEnvironmentVariable);
|
||||
|
||||
// Intel GPU detection is the most expensive GPU probe but only depends on the (already-created) CPU group,
|
||||
@@ -689,7 +681,7 @@ public class Computer : IComputer
|
||||
"IntelGpuGroup",
|
||||
() => new IntelGpuGroup(GetIntelCpus(), _settings),
|
||||
() => _gpuEnabled && _cpuEnabled,
|
||||
DeferIntelGpuDetectionSetting,
|
||||
HardwareSettingsKeys.IntelGpuDeferDetection,
|
||||
DeferIntelGpuDetectionEnvironmentVariable);
|
||||
}
|
||||
|
||||
@@ -702,7 +694,7 @@ public class Computer : IComputer
|
||||
{
|
||||
// Controllers probe USB/serial buses (with worst-case timeouts), so the whole block can be deferred to a
|
||||
// single background task. It stays sequential there to avoid concurrent serial-port/USB scans.
|
||||
if (ShouldDeferDetection(DeferControllerDetectionSetting, DeferControllerDetectionEnvironmentVariable))
|
||||
if (ShouldDeferDetection(HardwareSettingsKeys.ControllerDeferDetection, DeferControllerDetectionEnvironmentVariable))
|
||||
{
|
||||
startupTrace?.Skip("ControllerGroups", "Deferred to background.");
|
||||
AddDeferredGroups(() => _controllerEnabled,
|
||||
@@ -734,7 +726,7 @@ public class Computer : IComputer
|
||||
"StorageGroup",
|
||||
() => new StorageGroup(_settings),
|
||||
() => _storageEnabled,
|
||||
DeferStorageDetectionSetting,
|
||||
HardwareSettingsKeys.StorageDeferDetection,
|
||||
DeferStorageDetectionEnvironmentVariable);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@@ -743,7 +735,7 @@ public class Computer : IComputer
|
||||
"NetworkGroup",
|
||||
() => new NetworkGroup(_settings),
|
||||
() => _networkEnabled,
|
||||
DeferNetworkDetectionSetting,
|
||||
HardwareSettingsKeys.NetworkDeferDetection,
|
||||
DeferNetworkDetectionEnvironmentVariable);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@@ -751,7 +743,7 @@ public class Computer : IComputer
|
||||
{
|
||||
// PSU detection probes HID devices, so it contends with the deferred controllers' USB/HID scans. Defer it
|
||||
// to a background task too, keeping all HID/USB probing off the critical path.
|
||||
if (ShouldDeferDetection(DeferPsuDetectionSetting, DeferPsuDetectionEnvironmentVariable))
|
||||
if (ShouldDeferDetection(HardwareSettingsKeys.PsuDeferDetection, DeferPsuDetectionEnvironmentVariable))
|
||||
{
|
||||
startupTrace?.Skip("PsuGroups", "Deferred to background.");
|
||||
AddDeferredGroups(() => _psuEnabled,
|
||||
@@ -889,7 +881,7 @@ public class Computer : IComputer
|
||||
cancellationTokenSource.Cancel();
|
||||
|
||||
// Mark the run cancelled before draining so the Task.WhenAll continuation in CompleteDeferredGroupRunWhenRegistered
|
||||
// cannot win the race and raise HardwareDiscoveryCompleted during teardown.
|
||||
// cannot win the race and complete HardwareDiscoveryTask during teardown.
|
||||
completionSource.TrySetCanceled();
|
||||
|
||||
// Wait for in-flight deferred construction to unwind before disposing the token source or returning to a caller
|
||||
@@ -925,17 +917,13 @@ public class Computer : IComputer
|
||||
|
||||
private void CompleteDeferredGroupRun(TaskCompletionSource<object> completionSource)
|
||||
{
|
||||
bool completed;
|
||||
lock (_deferredGroupLock)
|
||||
{
|
||||
if (!ReferenceEquals(completionSource, _deferredGroupCompletionSource))
|
||||
return;
|
||||
|
||||
completed = completionSource.TrySetResult(null);
|
||||
completionSource.TrySetResult(null);
|
||||
}
|
||||
|
||||
if (completed)
|
||||
HardwareDiscoveryCompleted?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void CompleteDeferredGroupRunWhenRegistered()
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace LibreHardwareMonitor.Hardware.Cpu;
|
||||
public class GenericCpu : Hardware
|
||||
{
|
||||
private const string DeferTscEstimationEnvironmentVariable = "LHM_CPU_DEFER_TSC_ESTIMATION";
|
||||
private const string DeferTscEstimationSetting = "cpu.deferTscEstimation";
|
||||
|
||||
protected readonly int _coreCount;
|
||||
protected readonly CpuId[][] _cpuId;
|
||||
@@ -271,7 +270,7 @@ public class GenericCpu : Hardware
|
||||
|
||||
private static bool ShouldDeferTscEstimation(ISettings settings)
|
||||
{
|
||||
return SettingsParsing.ShouldDefer(settings, DeferTscEstimationSetting, DeferTscEstimationEnvironmentVariable);
|
||||
return SettingsParsing.ShouldDefer(settings, HardwareSettingsKeys.CpuDeferTscEstimation, DeferTscEstimationEnvironmentVariable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace LibreHardwareMonitor.Hardware.Cpu;
|
||||
internal sealed class IntelCpu : GenericCpu
|
||||
{
|
||||
private const string DeferInitialUpdateEnvironmentVariable = "LHM_CPU_DEFER_INITIAL_UPDATE";
|
||||
private const string DeferInitialUpdateSetting = "cpu.deferInitialUpdate";
|
||||
|
||||
private readonly Sensor _busClock;
|
||||
private readonly Sensor _coreAvg;
|
||||
@@ -575,7 +574,7 @@ internal sealed class IntelCpu : GenericCpu
|
||||
|
||||
private static bool ShouldDeferInitialUpdate(ISettings settings)
|
||||
{
|
||||
return SettingsParsing.ShouldDefer(settings, DeferInitialUpdateSetting, DeferInitialUpdateEnvironmentVariable);
|
||||
return SettingsParsing.ShouldDefer(settings, HardwareSettingsKeys.CpuDeferInitialUpdate, DeferInitialUpdateEnvironmentVariable);
|
||||
}
|
||||
|
||||
public override string GetReport()
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware;
|
||||
|
||||
/// <summary>
|
||||
/// Setting keys understood by the hardware library.
|
||||
/// </summary>
|
||||
public static class HardwareSettingsKeys
|
||||
{
|
||||
/// <summary>Defers DIMM SPD/thermal-sensor detection until after initial memory hardware is registered.</summary>
|
||||
public const string MemoryDeferDimmDetection = "memory.deferDimmDetection";
|
||||
|
||||
/// <summary>Defers the first CPU update until the regular update loop.</summary>
|
||||
public const string CpuDeferInitialUpdate = "cpu.deferInitialUpdate";
|
||||
|
||||
/// <summary>Defers the CPU timestamp-counter frequency estimate to the background.</summary>
|
||||
public const string CpuDeferTscEstimation = "cpu.deferTscEstimation";
|
||||
|
||||
/// <summary>Defers Nvidia GPU detection to the background.</summary>
|
||||
public const string NvidiaDeferDetection = "nvidia.deferDetection";
|
||||
|
||||
/// <summary>Defers storage device detection to the background.</summary>
|
||||
public const string StorageDeferDetection = "storage.deferDetection";
|
||||
|
||||
/// <summary>Defers network adapter detection to the background.</summary>
|
||||
public const string NetworkDeferDetection = "network.deferDetection";
|
||||
|
||||
/// <summary>Defers Intel integrated GPU detection to the background.</summary>
|
||||
public const string IntelGpuDeferDetection = "gpu.deferIntelDetection";
|
||||
|
||||
/// <summary>Defers controller detection to the background.</summary>
|
||||
public const string ControllerDeferDetection = "controller.deferDetection";
|
||||
|
||||
/// <summary>Defers PSU detection to the background.</summary>
|
||||
public const string PsuDeferDetection = "psu.deferDetection";
|
||||
}
|
||||
@@ -130,18 +130,7 @@ internal sealed class HardwareStartupTrace : IDisposable
|
||||
if (string.IsNullOrWhiteSpace(configuredPath))
|
||||
configuredPath = settings.GetValue(PathSetting, "");
|
||||
|
||||
string fileName = $"LibreHardwareMonitor.HardwareStartupTiming-{DateTime.Now:yyyyMMdd-HHmmss-fff}.log";
|
||||
if (string.IsNullOrWhiteSpace(configuredPath))
|
||||
return Path.Combine(AppContext.BaseDirectory, fileName);
|
||||
|
||||
if (configuredPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)
|
||||
|| configuredPath.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal)
|
||||
|| Directory.Exists(configuredPath))
|
||||
{
|
||||
return Path.Combine(configuredPath, fileName);
|
||||
}
|
||||
|
||||
return configuredPath;
|
||||
return StartupTraceLogSupport.GetLogFileName("LibreHardwareMonitor.HardwareStartupTiming", configuredPath);
|
||||
}
|
||||
|
||||
private static int? GetHardwareCount<T>(T result)
|
||||
@@ -201,7 +190,7 @@ internal sealed class HardwareStartupTrace : IDisposable
|
||||
|
||||
foreach (Entry entry in _entries)
|
||||
{
|
||||
builder.Append(EscapeCsv(entry.Phase));
|
||||
builder.Append(StartupTraceLogSupport.EscapeCsv(entry.Phase));
|
||||
builder.Append(',');
|
||||
builder.Append(entry.Elapsed.TotalMilliseconds.ToString("F3", CultureInfo.InvariantCulture));
|
||||
builder.Append(',');
|
||||
@@ -209,23 +198,12 @@ internal sealed class HardwareStartupTrace : IDisposable
|
||||
builder.Append(',');
|
||||
builder.Append(entry.Status);
|
||||
builder.Append(',');
|
||||
builder.AppendLine(EscapeCsv(entry.Detail));
|
||||
builder.AppendLine(StartupTraceLogSupport.EscapeCsv(entry.Detail));
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static string EscapeCsv(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return "";
|
||||
|
||||
if (!value.Contains(",") && !value.Contains("\"") && !value.Contains("\r") && !value.Contains("\n"))
|
||||
return value;
|
||||
|
||||
return "\"" + value.Replace("\"", "\"\"") + "\"";
|
||||
}
|
||||
|
||||
private sealed class Entry
|
||||
{
|
||||
public Entry(string phase, TimeSpan elapsed, string status, int? hardwareCount, string detail)
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace LibreHardwareMonitor.Hardware.Memory;
|
||||
internal class MemoryGroup : IGroup, IHardwareChanged, IHardwareDiscoveryTask
|
||||
{
|
||||
private const string DeferDimmDetectionEnvironmentVariable = "LHM_MEMORY_DEFER_DIMM_DETECTION";
|
||||
private const string DeferDimmDetectionSetting = "memory.deferDimmDetection";
|
||||
private static readonly TimeSpan _retryInterval = TimeSpan.FromSeconds(2.5);
|
||||
private static readonly object _lock = new();
|
||||
private List<Hardware> _hardware = [];
|
||||
@@ -246,7 +245,7 @@ internal class MemoryGroup : IGroup, IHardwareChanged, IHardwareDiscoveryTask
|
||||
|
||||
private static bool ShouldDeferDimmDetection(ISettings settings)
|
||||
{
|
||||
return SettingsParsing.ShouldDefer(settings, DeferDimmDetectionSetting, DeferDimmDetectionEnvironmentVariable);
|
||||
return SettingsParsing.ShouldDefer(settings, HardwareSettingsKeys.MemoryDeferDimmDetection, DeferDimmDetectionEnvironmentVariable);
|
||||
}
|
||||
|
||||
private void AddDimms(List<SPDAccessor> accessors, ISettings settings, HardwareStartupTrace startupTrace)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace LibreHardwareMonitor.Hardware;
|
||||
/// <see cref="ISettings" /> and environment variables. Keeps the truthy vocabulary and the env-overrides-setting
|
||||
/// precedence in one place so the components cannot drift.
|
||||
/// </summary>
|
||||
internal static class SettingsParsing
|
||||
public static class SettingsParsing
|
||||
{
|
||||
/// <summary>Returns whether <paramref name="value" /> is one of the accepted truthy tokens (1/true/yes/on).</summary>
|
||||
public static bool IsTruthy(string value)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware;
|
||||
|
||||
/// <summary>
|
||||
/// Shared file-name and CSV helpers for startup timing logs.
|
||||
/// </summary>
|
||||
public static class StartupTraceLogSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// Escapes a single CSV field using double quotes when the value contains a comma, quote, or newline.
|
||||
/// </summary>
|
||||
public static string EscapeCsv(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return "";
|
||||
|
||||
if (!value.Contains(",") && !value.Contains("\"") && !value.Contains("\r") && !value.Contains("\n"))
|
||||
return value;
|
||||
|
||||
return "\"" + value.Replace("\"", "\"\"") + "\"";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a timestamped startup trace log file name from a file-name prefix and optional configured path.
|
||||
/// </summary>
|
||||
public static string GetLogFileName(string fileNamePrefix, string configuredPath)
|
||||
{
|
||||
string fileName = $"{fileNamePrefix}-{DateTime.Now:yyyyMMdd-HHmmss-fff}.log";
|
||||
if (string.IsNullOrWhiteSpace(configuredPath))
|
||||
return Path.Combine(AppContext.BaseDirectory, fileName);
|
||||
|
||||
if (configuredPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)
|
||||
|| configuredPath.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal)
|
||||
|| Directory.Exists(configuredPath))
|
||||
{
|
||||
return Path.Combine(configuredPath, fileName);
|
||||
}
|
||||
|
||||
return configuredPath;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user