From 1322d478928ab44ea120ebe8397d9e6db7547ee8 Mon Sep 17 00:00:00 2001 From: Evgenii Fedorov Date: Sun, 6 Oct 2024 21:33:48 +0200 Subject: [PATCH 1/4] Remove multiplication by 100 to put utilization in range [0,1] instead of [0,100] --- .../Windows/WindowsContainerSnapshotProvider.cs | 4 ++-- .../Windows/WindowsSnapshotProvider.cs | 4 ++-- .../Windows/WindowsContainerSnapshotProviderTests.cs | 12 ++++++------ .../Windows/WindowsSnapshotProviderTests.cs | 12 ++++++------ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs index 3f2c4b8638a..9f632704931 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs @@ -195,7 +195,7 @@ private double MemoryPercentage(Func getMemoryUsage) { if (now >= _refreshAfterMemory) { - _memoryPercentage = Math.Min(Hundred, memoryUsage / _memoryLimit * Hundred); // Don't change calculation order, otherwise we loose some precision + _memoryPercentage = Math.Min(Hundred, memoryUsage / _memoryLimit); _refreshAfterMemory = now.Add(_memoryRefreshInterval); } @@ -229,7 +229,7 @@ private double CpuPercentage() var timeTickDelta = (now.Ticks - _oldCpuTimeTicks) * _cpuLimit; if (usageTickDelta > 0 && timeTickDelta > 0) { - _cpuPercentage = Math.Min(Hundred, usageTickDelta / timeTickDelta * Hundred); // Don't change calculation order, otherwise precision is lost. + _cpuPercentage = Math.Min(Hundred, usageTickDelta / timeTickDelta); Log.CpuContainerUsageData( _logger, basicAccountingInfo.TotalKernelTime, basicAccountingInfo.TotalUserTime, _oldCpuUsageTicks, timeTickDelta, _cpuLimit, _cpuPercentage); diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs index 7197499afd9..94b72d9ff48 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs @@ -136,7 +136,7 @@ private double MemoryPercentage() { if (now >= _refreshAfterMemory) { - _memoryPercentage = Math.Min(Hundred, currentMemoryUsage / _totalMemory * Hundred); // Don't change calculation order, otherwise we loose some precision + _memoryPercentage = Math.Min(Hundred, currentMemoryUsage / _totalMemory); _refreshAfterMemory = now.Add(_memoryRefreshInterval); } @@ -168,7 +168,7 @@ private double CpuPercentage() var timeTickDelta = (now.Ticks - _oldCpuTimeTicks) * _cpuUnits; if (usageTickDelta > 0 && timeTickDelta > 0) { - _cpuPercentage = Math.Min(Hundred, usageTickDelta / (double)timeTickDelta * Hundred); // Don't change calculation order, otherwise we loose some precision + _cpuPercentage = Math.Min(Hundred, usageTickDelta / (double)timeTickDelta); Log.CpuUsageData(_logger, currentCpuTicks, _oldCpuUsageTicks, timeTickDelta, _cpuUnits, _cpuPercentage); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs index c013c77d7b4..c0ffa1d9fec 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs @@ -237,21 +237,21 @@ public void SnapshotProvider_EmitsCpuMetrics(string instrumentName) fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(10, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. + Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. // Step #2 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); // CPU usage should be the same as before, as we didn't recalculate it: - Assert.Equal(10, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. + Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. // Step #3 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); // CPU usage should be the same as before, as we're not simulating any CPU usage: - Assert.Equal(10, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. + Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. } [Theory] @@ -294,17 +294,17 @@ public void SnapshotProvider_EmitsMemoryMetrics(string instrumentName) // Step #0 - state in the beginning: metricCollector.RecordObservableInstruments(); Assert.NotNull(metricCollector.LastMeasurement?.Value); - Assert.Equal(10, metricCollector.LastMeasurement.Value); // Consuming 10% of the memory initially. + Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consuming 10% of the memory initially. // Step #1 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(options.MemoryConsumptionRefreshInterval - TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(10, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. + Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. // Step #2 - simulate 2 milliseconds passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(30, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards. + Assert.Equal(0.3, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards. } [Fact] diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs index 6a76d8a95f4..97ef23f7785 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs @@ -96,14 +96,14 @@ public void SnapshotProvider_EmitsCpuMetrics() // Step #1 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(5, metricCollector.LastMeasurement?.Value); // Consuming 5% of the CPU (2 CPUs, 1000 ticks, 1ms). + Assert.Equal(0.05, metricCollector.LastMeasurement?.Value); // Consuming 5% of the CPU (2 CPUs, 1000 ticks, 1ms). // Step #2 - simulate another 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); // CPU usage should be the same as before, as we're not simulating any CPU usage: - Assert.Equal(5, metricCollector.LastMeasurement?.Value); // Still consuming 5% of the CPU + Assert.Equal(0.05, metricCollector.LastMeasurement?.Value); // Still consuming 5% of the CPU } [ConditionalFact] @@ -124,7 +124,7 @@ public void SnapshotProvider_EmitsMemoryMetrics() // Step #0 - state in the beginning: metricCollector.RecordObservableInstruments(); Assert.NotNull(metricCollector.LastMeasurement); - Assert.Equal(10, metricCollector.LastMeasurement.Value); // Consuming 5% of the memory initially + Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consuming 5% of the memory initially memoryUsed = 900L; // Simulate 30% memory usage. @@ -132,13 +132,13 @@ public void SnapshotProvider_EmitsMemoryMetrics() fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(10, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. + Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. // Step #2 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(30, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards + Assert.Equal(0.3, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards memoryUsed = 3_100L; // Simulate more than 100% memory usage @@ -147,7 +147,7 @@ public void SnapshotProvider_EmitsMemoryMetrics() metricCollector.RecordObservableInstruments(); // Memory usage should be the same as before, as we're not simulating any CPU usage: - Assert.Equal(100, metricCollector.LastMeasurement.Value); // Consuming 100% of the memory + Assert.Equal(1, metricCollector.LastMeasurement.Value); // Consuming 100% of the memory } [ConditionalFact] From 6b3b13efcdb4d2513d02bf3baa89edd784e7a3e8 Mon Sep 17 00:00:00 2001 From: Evgenii Fedorov Date: Sun, 6 Oct 2024 21:59:37 +0200 Subject: [PATCH 2/4] Fix test --- .../Windows/WindowsSnapshotProviderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs index 97ef23f7785..5590a03d5c8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs @@ -147,7 +147,7 @@ public void SnapshotProvider_EmitsMemoryMetrics() metricCollector.RecordObservableInstruments(); // Memory usage should be the same as before, as we're not simulating any CPU usage: - Assert.Equal(1, metricCollector.LastMeasurement.Value); // Consuming 100% of the memory + Assert.Equal(1, Math.Round(metricCollector.LastMeasurement.Value)); // Consuming 100% of the memory } [ConditionalFact] From 878b0cc9b40266adf38b335ee5914b88a52a90a6 Mon Sep 17 00:00:00 2001 From: Evgenii Fedorov Date: Wed, 9 Oct 2024 09:32:02 +0200 Subject: [PATCH 3/4] Replace const Hundred with One --- .../Windows/WindowsContainerSnapshotProvider.cs | 6 +++--- .../Windows/WindowsSnapshotProvider.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs index 9f632704931..b27df104691 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows; internal sealed class WindowsContainerSnapshotProvider : ISnapshotProvider { - private const double Hundred = 100.0d; + private const double One = 1.0d; private readonly Lazy _memoryStatus; @@ -195,7 +195,7 @@ private double MemoryPercentage(Func getMemoryUsage) { if (now >= _refreshAfterMemory) { - _memoryPercentage = Math.Min(Hundred, memoryUsage / _memoryLimit); + _memoryPercentage = Math.Min(One, memoryUsage / _memoryLimit); _refreshAfterMemory = now.Add(_memoryRefreshInterval); } @@ -229,7 +229,7 @@ private double CpuPercentage() var timeTickDelta = (now.Ticks - _oldCpuTimeTicks) * _cpuLimit; if (usageTickDelta > 0 && timeTickDelta > 0) { - _cpuPercentage = Math.Min(Hundred, usageTickDelta / timeTickDelta); + _cpuPercentage = Math.Min(One, usageTickDelta / timeTickDelta); Log.CpuContainerUsageData( _logger, basicAccountingInfo.TotalKernelTime, basicAccountingInfo.TotalUserTime, _oldCpuUsageTicks, timeTickDelta, _cpuLimit, _cpuPercentage); diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs index 94b72d9ff48..22a8bf80b6e 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows; internal sealed class WindowsSnapshotProvider : ISnapshotProvider { - private const double Hundred = 100.0d; + private const double One = 1.0d; public SystemResources Resources { get; } @@ -136,7 +136,7 @@ private double MemoryPercentage() { if (now >= _refreshAfterMemory) { - _memoryPercentage = Math.Min(Hundred, currentMemoryUsage / _totalMemory); + _memoryPercentage = Math.Min(One, currentMemoryUsage / _totalMemory); _refreshAfterMemory = now.Add(_memoryRefreshInterval); } @@ -168,7 +168,7 @@ private double CpuPercentage() var timeTickDelta = (now.Ticks - _oldCpuTimeTicks) * _cpuUnits; if (usageTickDelta > 0 && timeTickDelta > 0) { - _cpuPercentage = Math.Min(Hundred, usageTickDelta / (double)timeTickDelta); + _cpuPercentage = Math.Min(One, usageTickDelta / (double)timeTickDelta); Log.CpuUsageData(_logger, currentCpuTicks, _oldCpuUsageTicks, timeTickDelta, _cpuUnits, _cpuPercentage); From 83c7b992ead013c6a7e317f1cc50c4f91a8ea1d0 Mon Sep 17 00:00:00 2001 From: evgenyfedorov2 <25526458+evgenyfedorov2@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:18:17 +0100 Subject: [PATCH 4/4] PR Comments --- .../ResourceMonitoringOptions.Windows.cs | 15 +++++++ .../WindowsContainerSnapshotProvider.cs | 10 ++++- .../Windows/WindowsSnapshotProvider.cs | 10 ++++- .../WindowsContainerSnapshotProviderTests.cs | 44 ++++++++++++------- .../Windows/WindowsSnapshotProviderTests.cs | 36 ++++++++++----- 5 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringOptions.Windows.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringOptions.Windows.cs index 1970dd22936..9e8636506c7 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringOptions.Windows.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringOptions.Windows.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring; @@ -18,4 +20,17 @@ public partial class ResourceMonitoringOptions #pragma warning disable CA2227 // Collection properties should be read only public ISet SourceIpAddresses { get; set; } = new HashSet(); #pragma warning restore CA2227 // Collection properties should be read only + + /// + /// Gets or sets a value indicating whether CPU and Memory utilization metric values should be in range [0, 1] instead of [0, 100]. + /// + /// + /// The default value is . + /// + /// + /// Use this property if you prefer to have the metric values in range [0, 1] instead of [0, 100]. + /// In the long term, the default value of this property will be changed to . + /// + [Experimental(diagnosticId: DiagnosticIds.Experiments.ResourceMonitoring, UrlFormat = DiagnosticIds.UrlFormat)] + public bool UseZeroToOneRangeForMetrics { get; set; } } diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs index b27df104691..3a7585ac3c8 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs @@ -15,6 +15,7 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows; internal sealed class WindowsContainerSnapshotProvider : ISnapshotProvider { private const double One = 1.0d; + private const double Hundred = 100.0d; private readonly Lazy _memoryStatus; @@ -32,6 +33,7 @@ internal sealed class WindowsContainerSnapshotProvider : ISnapshotProvider private readonly double _cpuLimit; private readonly TimeSpan _cpuRefreshInterval; private readonly TimeSpan _memoryRefreshInterval; + private readonly double _metricValueMultiplier; private long _oldCpuUsageTicks; private long _oldCpuTimeTicks; @@ -72,6 +74,8 @@ internal WindowsContainerSnapshotProvider( _logger = logger ?? NullLogger.Instance; Log.RunningInsideJobObject(_logger); + _metricValueMultiplier = options.UseZeroToOneRangeForMetrics ? One : Hundred; + _memoryStatus = new Lazy( memoryInfo.GetMemoryStatus, LazyThreadSafetyMode.ExecutionAndPublication); @@ -195,7 +199,8 @@ private double MemoryPercentage(Func getMemoryUsage) { if (now >= _refreshAfterMemory) { - _memoryPercentage = Math.Min(One, memoryUsage / _memoryLimit); + // Don't change calculation order, otherwise we loose some precision: + _memoryPercentage = Math.Min(_metricValueMultiplier, memoryUsage / _memoryLimit * _metricValueMultiplier); _refreshAfterMemory = now.Add(_memoryRefreshInterval); } @@ -229,7 +234,8 @@ private double CpuPercentage() var timeTickDelta = (now.Ticks - _oldCpuTimeTicks) * _cpuLimit; if (usageTickDelta > 0 && timeTickDelta > 0) { - _cpuPercentage = Math.Min(One, usageTickDelta / timeTickDelta); + // Don't change calculation order, otherwise precision is lost: + _cpuPercentage = Math.Min(_metricValueMultiplier, usageTickDelta / timeTickDelta * _metricValueMultiplier); Log.CpuContainerUsageData( _logger, basicAccountingInfo.TotalKernelTime, basicAccountingInfo.TotalUserTime, _oldCpuUsageTicks, timeTickDelta, _cpuLimit, _cpuPercentage); diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs index aae87ef7e0e..01535d01b19 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsSnapshotProvider.cs @@ -15,6 +15,7 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows; internal sealed class WindowsSnapshotProvider : ISnapshotProvider { private const double One = 1.0d; + private const double Hundred = 100.0d; public SystemResources Resources { get; } @@ -28,6 +29,7 @@ internal sealed class WindowsSnapshotProvider : ISnapshotProvider private readonly double _totalMemory; private readonly TimeSpan _cpuRefreshInterval; private readonly TimeSpan _memoryRefreshInterval; + private readonly double _metricValueMultiplier; private long _oldCpuUsageTicks; private long _oldCpuTimeTicks; @@ -56,6 +58,8 @@ internal WindowsSnapshotProvider( Log.RunningOutsideJobObject(_logger); + _metricValueMultiplier = options.UseZeroToOneRangeForMetrics ? One : Hundred; + _cpuUnits = getCpuUnitsFunc(); var totalMemory = getTotalMemoryInBytesFunc(); @@ -135,7 +139,8 @@ private double MemoryPercentage() { if (now >= _refreshAfterMemory) { - _memoryPercentage = Math.Min(One, currentMemoryUsage / _totalMemory); + // Don't change calculation order, otherwise we loose some precision: + _memoryPercentage = Math.Min(_metricValueMultiplier, currentMemoryUsage / _totalMemory * _metricValueMultiplier); _refreshAfterMemory = now.Add(_memoryRefreshInterval); } @@ -167,7 +172,8 @@ private double CpuPercentage() var timeTickDelta = (now.Ticks - _oldCpuTimeTicks) * _cpuUnits; if (usageTickDelta > 0 && timeTickDelta > 0) { - _cpuPercentage = Math.Min(One, usageTickDelta / (double)timeTickDelta); + // Don't change calculation order, otherwise we loose some precision: + _cpuPercentage = Math.Min(_metricValueMultiplier, usageTickDelta / (double)timeTickDelta * _metricValueMultiplier); Log.CpuUsageData(_logger, currentCpuTicks, _oldCpuUsageTicks, timeTickDelta, _cpuUnits, _cpuPercentage); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs index c0ffa1d9fec..487f57b950e 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsContainerSnapshotProviderTests.cs @@ -191,9 +191,11 @@ public void GetSnapshot_With_JobMemoryLimit_Set_To_Zero_ProducesCorrectSnapshot( } [Theory] - [InlineData(ResourceUtilizationInstruments.ProcessCpuUtilization)] - [InlineData(ResourceUtilizationInstruments.ContainerCpuLimitUtilization)] - public void SnapshotProvider_EmitsCpuMetrics(string instrumentName) + [InlineData(ResourceUtilizationInstruments.ProcessCpuUtilization, true)] + [InlineData(ResourceUtilizationInstruments.ProcessCpuUtilization, false)] + [InlineData(ResourceUtilizationInstruments.ContainerCpuLimitUtilization, true)] + [InlineData(ResourceUtilizationInstruments.ContainerCpuLimitUtilization, false)] + public void SnapshotProvider_EmitsCpuMetrics(string instrumentName, bool useZeroToOneRange) { // Simulating 10% CPU usage (2 CPUs, 2000 ticks initially, 4000 ticks after 1 ms): JOBOBJECT_BASIC_ACCOUNTING_INFORMATION updatedAccountingInfo = default; @@ -216,8 +218,12 @@ public void SnapshotProvider_EmitsCpuMetrics(string instrumentName) .Returns(meter); using var metricCollector = new MetricCollector(meter, instrumentName, fakeClock); - var options = new ResourceMonitoringOptions { CpuConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2) }; - + var options = new ResourceMonitoringOptions + { + CpuConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2), + UseZeroToOneRangeForMetrics = useZeroToOneRange + }; + var multiplier = useZeroToOneRange ? 1 : 100; var snapshotProvider = new WindowsContainerSnapshotProvider( _memoryInfoMock.Object, _systemInfoMock.Object, @@ -237,27 +243,29 @@ public void SnapshotProvider_EmitsCpuMetrics(string instrumentName) fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. + Assert.Equal(0.1 * multiplier, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. // Step #2 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); // CPU usage should be the same as before, as we didn't recalculate it: - Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. + Assert.Equal(0.1 * multiplier, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. // Step #3 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); // CPU usage should be the same as before, as we're not simulating any CPU usage: - Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. + Assert.Equal(0.1 * multiplier, metricCollector.LastMeasurement.Value); // Consumed 10% of the CPU. } [Theory] - [InlineData(ResourceUtilizationInstruments.ProcessMemoryUtilization)] - [InlineData(ResourceUtilizationInstruments.ContainerMemoryLimitUtilization)] - public void SnapshotProvider_EmitsMemoryMetrics(string instrumentName) + [InlineData(ResourceUtilizationInstruments.ProcessMemoryUtilization, true)] + [InlineData(ResourceUtilizationInstruments.ProcessMemoryUtilization, false)] + [InlineData(ResourceUtilizationInstruments.ContainerMemoryLimitUtilization, true)] + [InlineData(ResourceUtilizationInstruments.ContainerMemoryLimitUtilization, false)] + public void SnapshotProvider_EmitsMemoryMetrics(string instrumentName, bool useZeroToOneRange) { _appMemoryUsage = 200UL; ulong updatedAppMemoryUsage = 600UL; @@ -279,8 +287,12 @@ public void SnapshotProvider_EmitsMemoryMetrics(string instrumentName) .Returns(meter); using var metricCollector = new MetricCollector(meter, instrumentName, fakeClock); - var options = new ResourceMonitoringOptions { MemoryConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2) }; - + var options = new ResourceMonitoringOptions + { + MemoryConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2), + UseZeroToOneRangeForMetrics = useZeroToOneRange + }; + var multiplier = useZeroToOneRange ? 1 : 100; var snapshotProvider = new WindowsContainerSnapshotProvider( _memoryInfoMock.Object, _systemInfoMock.Object, @@ -294,17 +306,17 @@ public void SnapshotProvider_EmitsMemoryMetrics(string instrumentName) // Step #0 - state in the beginning: metricCollector.RecordObservableInstruments(); Assert.NotNull(metricCollector.LastMeasurement?.Value); - Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consuming 10% of the memory initially. + Assert.Equal(0.1 * multiplier, metricCollector.LastMeasurement.Value); // Consuming 10% of the memory initially. // Step #1 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(options.MemoryConsumptionRefreshInterval - TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. + Assert.Equal(0.1 * multiplier, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. // Step #2 - simulate 2 milliseconds passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(0.3, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards. + Assert.Equal(0.3 * multiplier, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards. } [Fact] diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs index 5590a03d5c8..d3be9fe6a24 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs @@ -71,12 +71,18 @@ public Task SnapshotProvider_EmitsLogRecord() return Verifier.Verify(logRecords[0]).UseDirectory(VerifiedDataDirectory); } - [ConditionalFact] - public void SnapshotProvider_EmitsCpuMetrics() + [ConditionalTheory] + [CombinatorialData] + public void SnapshotProvider_EmitsCpuMetrics(bool useZeroToOneRange) { var fakeClock = new FakeTimeProvider(); var cpuTicks = 500L; - var options = new ResourceMonitoringOptions { CpuConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2) }; + var options = new ResourceMonitoringOptions + { + CpuConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2), + UseZeroToOneRangeForMetrics = useZeroToOneRange + }; + var multiplier = useZeroToOneRange ? 1 : 100; using var meter = new Meter(nameof(SnapshotProvider_EmitsCpuMetrics)); var meterFactoryMock = new Mock(); meterFactoryMock.Setup(x => x.Create(It.IsAny())).Returns(meter); @@ -96,22 +102,28 @@ public void SnapshotProvider_EmitsCpuMetrics() // Step #1 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(0.05, metricCollector.LastMeasurement?.Value); // Consuming 5% of the CPU (2 CPUs, 1000 ticks, 1ms). + Assert.Equal(0.05 * multiplier, metricCollector.LastMeasurement?.Value); // Consuming 5% of the CPU (2 CPUs, 1000 ticks, 1ms). // Step #2 - simulate another 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); // CPU usage should be the same as before, as we're not simulating any CPU usage: - Assert.Equal(0.05, metricCollector.LastMeasurement?.Value); // Still consuming 5% of the CPU + Assert.Equal(0.05 * multiplier, metricCollector.LastMeasurement?.Value); // Still consuming 5% of the CPU } - [ConditionalFact] - public void SnapshotProvider_EmitsMemoryMetrics() + [ConditionalTheory] + [CombinatorialData] + public void SnapshotProvider_EmitsMemoryMetrics(bool useZeroToOneRange) { var fakeClock = new FakeTimeProvider(); long memoryUsed = 300L; - var options = new ResourceMonitoringOptions { MemoryConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2) }; + var options = new ResourceMonitoringOptions + { + MemoryConsumptionRefreshInterval = TimeSpan.FromMilliseconds(2), + UseZeroToOneRangeForMetrics = useZeroToOneRange + }; + var multiplier = useZeroToOneRange ? 1 : 100; using var meter = new Meter(nameof(SnapshotProvider_EmitsMemoryMetrics)); var meterFactoryMock = new Mock(); meterFactoryMock.Setup(x => x.Create(It.IsAny())) @@ -124,7 +136,7 @@ public void SnapshotProvider_EmitsMemoryMetrics() // Step #0 - state in the beginning: metricCollector.RecordObservableInstruments(); Assert.NotNull(metricCollector.LastMeasurement); - Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Consuming 5% of the memory initially + Assert.Equal(0.1 * multiplier, metricCollector.LastMeasurement.Value); // Consuming 5% of the memory initially memoryUsed = 900L; // Simulate 30% memory usage. @@ -132,13 +144,13 @@ public void SnapshotProvider_EmitsMemoryMetrics() fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(0.1, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. + Assert.Equal(0.1 * multiplier, metricCollector.LastMeasurement.Value); // Still consuming 10% as gauge wasn't updated. // Step #2 - simulate 1 millisecond passing and collect metrics again: fakeClock.Advance(TimeSpan.FromMilliseconds(1)); metricCollector.RecordObservableInstruments(); - Assert.Equal(0.3, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards + Assert.Equal(0.3 * multiplier, metricCollector.LastMeasurement.Value); // Consuming 30% of the memory afterwards memoryUsed = 3_100L; // Simulate more than 100% memory usage @@ -147,7 +159,7 @@ public void SnapshotProvider_EmitsMemoryMetrics() metricCollector.RecordObservableInstruments(); // Memory usage should be the same as before, as we're not simulating any CPU usage: - Assert.Equal(1, Math.Round(metricCollector.LastMeasurement.Value)); // Consuming 100% of the memory + Assert.Equal(1 * multiplier, Math.Round(metricCollector.LastMeasurement.Value)); // Consuming 100% of the memory } [ConditionalFact]