Skip to content

Commit

Permalink
Clamp saturation values to the range [0.0, 1.0]
Browse files Browse the repository at this point in the history
  • Loading branch information
kralicky committed May 13, 2024
1 parent b6783fe commit 42bb706
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
12 changes: 9 additions & 3 deletions pkg/envoy/resource_monitor_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,12 @@ func (s *sharedResourceMonitor) Run(ctx context.Context, envoyPid int) error {
log.Error(ctx).Err(err).Msg("failed to get memory saturation")
continue
}
saturation = float64(usage) / float64(limit)
saturation = max(0.0, min(1.0, float64(usage)/float64(limit)))
}
}

saturationStr := fmt.Sprintf("%.6f", saturation)
nextInterval := (monitorMaxTickInterval - (time.Duration(float64(monitorMaxTickInterval-monitorMinTickInterval) * saturation))).
Round(time.Millisecond)
nextInterval := computeScaledTickInterval(saturation)

if saturationStr != lastValue {
lastValue = saturationStr
Expand All @@ -354,6 +353,13 @@ func (s *sharedResourceMonitor) Run(ctx context.Context, envoyPid int) error {
}
}

// Returns a value between monitorMinTickInterval and monitorMaxTickInterval, based
// on the given saturation value in the range [0.0, 1.0].
func computeScaledTickInterval(saturation float64) time.Duration {
return monitorMaxTickInterval - (time.Duration(float64(monitorMaxTickInterval-monitorMinTickInterval) * max(0.0, min(1.0, saturation)))).
Round(time.Millisecond)
}

func (s *sharedResourceMonitor) updateActionStates(ctx context.Context, pct float64) {
for name, minThreshold := range computedActionThresholds {
var state int64
Expand Down
51 changes: 51 additions & 0 deletions pkg/envoy/resource_monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,25 +627,36 @@ func TestSharedResourceMonitor(t *testing.T) {

timeout := 1 * time.Second
interval := 10 * time.Millisecond
// 100/200
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.Equal(c, "0.500000", readMemorySaturation(c))
}, timeout, interval)

// 150/200
updateMemoryCurrent("150")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.Equal(c, "0.750000", readMemorySaturation(c))
}, timeout, interval)

// 150/300
updateMemoryMax("300")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.Equal(c, "0.500000", readMemorySaturation(c))
}, timeout, interval)

// 150/unlimited
updateMemoryMax("max")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.Equal(c, "0.000000", readMemorySaturation(c))
}, timeout, interval)

// 150/145 (over limit)
updateMemoryMax("145")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.Equal(c, "1.000000", readMemorySaturation(c))
}, timeout, interval)

// 150/150
updateMemoryMax("150")
assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.Equal(c, "1.000000", readMemorySaturation(c))
Expand Down Expand Up @@ -812,3 +823,43 @@ func TestBootstrapConfig(t *testing.T) {
}
`, tempDir), bootstrap.OverloadManager)
}

func TestComputeScaledTickInterval(t *testing.T) {
cases := []struct {
saturation float64
expected time.Duration
}{
0: {
saturation: 0.0,
expected: 10000 * time.Millisecond,
},
1: {
saturation: 1.0,
expected: 250 * time.Millisecond,
},
2: {
saturation: 0.5,
expected: 5125 * time.Millisecond,
},
3: {
// duration should round to the nearest millisecond
saturation: 0.3333,
expected: 6750 * time.Millisecond,
},
4: {
saturation: -1.0,
expected: 10000 * time.Millisecond,
},
5: {
// saturation > 1 should be clamped to 1
saturation: 1.5,
expected: 250 * time.Millisecond,
},
}

for i, c := range cases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
assert.Equal(t, c.expected, computeScaledTickInterval(c.saturation))
})
}
}

0 comments on commit 42bb706

Please sign in to comment.