Skip to content

Commit

Permalink
Make capping happen after scale of the CPU usage in ResourceUtilizati…
Browse files Browse the repository at this point in the history
…on (#5388)
  • Loading branch information
Weikai1997 authored Sep 4, 2024
1 parent 45e8ca3 commit dc1ba70
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ public static ResourceUtilization CalculateUtilization(in Snapshot first, in Sna
long newUsageTicks = second.KernelTimeSinceStart.Ticks + second.UserTimeSinceStart.Ticks;
long totalUsageTickDelta = newUsageTicks - oldUsageTicks;

var utilization = Math.Max(0.0, totalUsageTickDelta / totalSystemTicks * Hundred);
var cpuUtilization = Math.Min(Hundred, utilization);
double cpuUtilization = Math.Max(0.0, totalUsageTickDelta / totalSystemTicks * Hundred);

return new ResourceUtilization(cpuUtilization, second.MemoryUsageInBytes, systemResources, second);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public ResourceUtilization(double cpuUsedPercentage, ulong memoryUsedInBytes, Sy
guaranteedCpuUnits = 1;
}

CpuUsedPercentage = Throw.IfLessThan(cpuUsedPercentage / guaranteedCpuUnits, 0.0);
CpuUsedPercentage = Math.Min(Hundred, Throw.IfLessThan(cpuUsedPercentage / guaranteedCpuUnits, 0.0));
MemoryUsedInBytes = Throw.IfLessThan(memoryUsedInBytes, 0);
SystemResources = systemResources;
MemoryUsedPercentage = Math.Min(Hundred, (double)MemoryUsedInBytes / systemResources.GuaranteedMemoryInBytes * Hundred);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ public sealed class CalculatorTests
[Fact]
public void BasicCalculation()
{
var secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));
TimeSpan secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));

// Now, what's the total number of available ticks between the two samples (for a single core)
var totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;
long totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;

var second = new Snapshot(
Snapshot second = new(
totalTimeSinceStart: secondSnapshotTimeSpan,

// assign 25% to kernel time
Expand All @@ -44,7 +44,7 @@ public void BasicCalculation()
memoryUsageInBytes: 500);

// Now, when we run the calculator, CPU should be at 50%.
var record = Calculator.CalculateUtilization(_firstSnapshot, second, _resources);
ResourceUtilization record = Calculator.CalculateUtilization(_firstSnapshot, second, _resources);
Assert.Equal(50.0, record.CpuUsedPercentage);

// Because we set it basically, memory should also clearly be at 50%.
Expand All @@ -61,14 +61,14 @@ public void BasicCalculation()
[Fact]
public void BasicCalculation_WithHalfCpuUnits()
{
var limitedResources = new SystemResources(0.5, 0.5, TotalMemoryInBytes, TotalMemoryInBytes);
SystemResources limitedResources = new(guaranteedCpuUnits: 0.5, maximumCpuUnits: 0.5, TotalMemoryInBytes, TotalMemoryInBytes);

var secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));
TimeSpan secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));

// Now, what's the total number of available ticks between the two samples (for a single core)
var totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;
long totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;

var second = new Snapshot(
Snapshot second = new(
totalTimeSinceStart: secondSnapshotTimeSpan,

// assign 25% to kernel time
Expand All @@ -80,7 +80,7 @@ public void BasicCalculation_WithHalfCpuUnits()

// Using the limited resources, CPU time is now cut in half. So, when we run
// the calculator, the CPU utilization should be at 100%.
var record = Calculator.CalculateUtilization(_firstSnapshot, second, limitedResources);
ResourceUtilization record = Calculator.CalculateUtilization(_firstSnapshot, second, limitedResources);
Assert.Equal(100.0, record.CpuUsedPercentage);
}

Expand All @@ -91,7 +91,7 @@ public void BasicCalculation_WithHalfCpuUnits()
public void Zeroes()
{
// No changes in the second snapshot
var secondSnapshot = new Snapshot(
Snapshot secondSnapshot = new(
totalTimeSinceStart: _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5)),
memoryUsageInBytes: 0,
kernelTimeSinceStart: _firstSnapshot.KernelTimeSinceStart,
Expand All @@ -100,7 +100,7 @@ public void Zeroes()
// Now, let's set each of kernel and user time to no time elapsed.

// Now, when we run the calculator, CPU should be at 0%.
var record = Calculator.CalculateUtilization(_firstSnapshot, secondSnapshot, _resources);
ResourceUtilization record = Calculator.CalculateUtilization(_firstSnapshot, secondSnapshot, _resources);
Assert.Equal(0.0, record.CpuUsedPercentage);

// Because we set it basically, memory should also clearly be at 0%.
Expand All @@ -118,19 +118,19 @@ public void Zeroes()
[Fact]
public void TimeGoesBackwards()
{
var firstSnapshot = new Snapshot(
Snapshot firstSnapshot = new(
totalTimeSinceStart: TimeSpan.FromTicks(new FakeTimeProvider().GetUtcNow().Ticks),
kernelTimeSinceStart: TimeSpan.FromTicks(1000),
userTimeSinceStart: TimeSpan.FromTicks(1000),
memoryUsageInBytes: 0);
var secondSnapshot = new Snapshot(
Snapshot secondSnapshot = new(
totalTimeSinceStart: firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5)),
memoryUsageInBytes: 0,
kernelTimeSinceStart: TimeSpan.FromTicks(firstSnapshot.KernelTimeSinceStart.Ticks - 1),
userTimeSinceStart: TimeSpan.FromTicks(firstSnapshot.UserTimeSinceStart.Ticks - 1));

// Now, when we run the calculator, CPU should be at 0%.
var record = Calculator.CalculateUtilization(firstSnapshot, secondSnapshot, _resources);
ResourceUtilization record = Calculator.CalculateUtilization(firstSnapshot, secondSnapshot, _resources);
Assert.Equal(0.0, record.CpuUsedPercentage);
}

Expand All @@ -141,19 +141,19 @@ public void TimeGoesBackwards()
[Fact]
public void FullyUtilized()
{
var secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));
TimeSpan secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));

// Now, what's the total number of available ticks between the two samples.
var totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;
long totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;

var secondSnapshot = new Snapshot(
Snapshot secondSnapshot = new(
totalTimeSinceStart: secondSnapshotTimeSpan,
kernelTimeSinceStart: TimeSpan.FromTicks(totalAvailableTicks / 2),
userTimeSinceStart: TimeSpan.FromTicks(totalAvailableTicks / 2),
memoryUsageInBytes: 1000);

// Now, when we run the calculator, CPU should 100%.
var record = Calculator.CalculateUtilization(_firstSnapshot, secondSnapshot, _resources);
ResourceUtilization record = Calculator.CalculateUtilization(_firstSnapshot, secondSnapshot, _resources);
Assert.Equal(100.0, record.CpuUsedPercentage);

// Assert that memory is at 100%.
Expand All @@ -166,15 +166,18 @@ public void FullyUtilized()
/// Ensure that stats work appropriately if the resources are overutilized.
/// </summary>
/// <remarks>The highest possible CPU and memory percentages should be 100%.</remarks>
[Fact]
public void OverUtilized()
[Theory]
[InlineData(1, 100.0)]
[InlineData(2, 100.0)]
public void OverUtilized(double cpuUnits, double expectedCpuUsage)
{
var secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));
SystemResources limitedResources = new(cpuUnits, cpuUnits, TotalMemoryInBytes, TotalMemoryInBytes);
TimeSpan secondSnapshotTimeSpan = _firstSnapshot.TotalTimeSinceStart.Add(TimeSpan.FromSeconds(5));

// Now, what's the total number of available ticks between the two samples.
var totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;
long totalAvailableTicks = secondSnapshotTimeSpan.Ticks - _firstSnapshot.TotalTimeSinceStart.Ticks;

var secondSnapshot = new Snapshot(
Snapshot secondSnapshot = new(
totalTimeSinceStart: secondSnapshotTimeSpan,

// Set each of kernel and uesr time to all the available ticks between
Expand All @@ -184,8 +187,8 @@ public void OverUtilized()
memoryUsageInBytes: 1500);

// Now, when we run the calculator, CPU should be at 100%.
var record = Calculator.CalculateUtilization(_firstSnapshot, secondSnapshot, _resources);
Assert.Equal(100.0, record.CpuUsedPercentage);
ResourceUtilization record = Calculator.CalculateUtilization(_firstSnapshot, secondSnapshot, _resources);
Assert.Equal(expectedCpuUsage, record.CpuUsedPercentage);

// Assert that memory is at 100%
Assert.Equal(100.0, record.MemoryUsedPercentage);
Expand Down

0 comments on commit dc1ba70

Please sign in to comment.