Skip to content

Commit 97a8d79

Browse files
author
Rachel Lin
committed
added RangeAverage method
1 parent 641f75c commit 97a8d79

2 files changed

Lines changed: 102 additions & 1 deletion

File tree

slidingwindow.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ func (sw *SlidingWindow) Average(window time.Duration) float64 {
9393
return float64(total) / float64(sampleCount)
9494
}
9595

96+
// RangeAverage returns the unweighted mean of the window
97+
// from start to end
98+
func (sw *SlidingWindow) RangeAverage(start, end time.Duration) float64 {
99+
total, sampleCount := sw.RangeTotal(start, end)
100+
if sampleCount == 0 {
101+
return 0
102+
}
103+
return float64(total) / float64(sampleCount)
104+
}
105+
96106
// Reset the samples in this sliding time window.
97107
func (sw *SlidingWindow) Reset() {
98108
sw.Lock()
@@ -139,3 +149,30 @@ func (sw *SlidingWindow) Total(window time.Duration) (int64, int) {
139149

140150
return total, sampleCount
141151
}
152+
153+
// RangeTotal returns the sum of all values from start to end, as well as
154+
// the number of samples.
155+
func (sw *SlidingWindow) RangeTotal(start, end time.Duration) (int64, int) {
156+
if start > end {
157+
start = end
158+
}
159+
window := end - start
160+
sampleCount := int(window / sw.granularity)
161+
if sampleCount > sw.size {
162+
sampleCount = sw.size
163+
}
164+
sw.RLock()
165+
defer sw.RUnlock()
166+
167+
var total int64
168+
endPos := sw.pos - sw.size + int( end / sw.granularity)
169+
for i := 1; i <= sampleCount; i++ {
170+
pos := endPos - i
171+
if pos < 0 {
172+
pos += len(sw.samples)
173+
}
174+
175+
total += sw.samples[pos]
176+
}
177+
return total, sampleCount
178+
}

slidingwindow_test.go

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestNew(t *testing.T) {
1919
t.Errorf("expected multiplier error, not %q", err)
2020
}
2121

22-
_, err = New(0, time.Second)
22+
_, err = New(0, 5*time.Second)
2323
if err == nil || err.Error() != "window cannot be 0" {
2424
t.Errorf("expected window size cannot be 0 error, not %q", err)
2525
}
@@ -75,6 +75,29 @@ func TestAverage(t *testing.T) {
7575
}
7676
}
7777

78+
func TestRangeAverage(t *testing.T) {
79+
sw := &SlidingWindow{
80+
window: 10 * time.Second,
81+
granularity: time.Second,
82+
samples: []int64{1, 2, 5, 0, 0, 0, 0, 0, 4, 0},
83+
pos: 2,
84+
size: 10,
85+
}
86+
87+
if v := sw.RangeAverage(0, 0); v != 0 {
88+
t.Errorf("expected the average with a window of 0 seconds be 0, not %f", v)
89+
}
90+
if v := sw.RangeAverage(9 * time.Second, 10 * time.Second); v != 2 {
91+
t.Errorf("expected the average from second 9 to 10 to be 2, not %f", v)
92+
}
93+
if v := sw.RangeAverage(8 * time.Second, 10 * time.Second); v != 1.5 {
94+
t.Errorf("expected the average from second 8 to 10 to be 1.5, not %f", v)
95+
}
96+
if v := sw.RangeAverage(4 * time.Second, 9 * time.Second); v != 1 {
97+
t.Errorf("expected the average from second 4 to 9 to be 1, not %f", v)
98+
}
99+
}
100+
78101
func TestReset(t *testing.T) {
79102
sw := MustNew(2*time.Second, time.Second)
80103
defer sw.Stop()
@@ -131,3 +154,44 @@ func TestTotal(t *testing.T) {
131154
t.Errorf("expected the total over the last 10 seconds to be 12, not %d", v)
132155
}
133156
}
157+
158+
func TestRangeTotal(t *testing.T) {
159+
sw := &SlidingWindow{
160+
window: 10 * time.Second,
161+
granularity: time.Second,
162+
samples: []int64{1, 2, 5, 0, 0, 0, 0, 0, 4, 8},
163+
pos: 10,
164+
size: 10,
165+
}
166+
167+
if v, _ := sw.RangeTotal(time.Second, 2 * time.Second); v != 2 {
168+
t.Errorf("expected the total from second 1 to 2 to be 2, not %d", v)
169+
}
170+
if v, _ := sw.RangeTotal(time.Second, 3 * time.Second); v != 7 {
171+
t.Errorf("expected the total from second 1 to 3 to be 7, not %d", v)
172+
}
173+
if v, _ := sw.RangeTotal(time.Second * 3, time.Second * 8); v != 0 {
174+
t.Errorf("expected the total from second 3 to 8 to be 0, not %d", v)
175+
}
176+
if v, _ := sw.RangeTotal(0, time.Second * 2); v != 3 {
177+
t.Errorf("expected the total from second 0 to 2 to be 3, not %d", v)
178+
}
179+
if v, _ := sw.RangeTotal(9 * time.Second, 10 * time.Second); v != 8 {
180+
t.Errorf("expected the total from second 9 to 10 to be 8, not %d", v)
181+
}
182+
183+
sw = &SlidingWindow{
184+
window: 10 * time.Second,
185+
granularity: time.Second,
186+
samples: []int64{1, 2, 5, 0, 0, 0, 0, 0, 4, 8},
187+
pos: 2,
188+
size: 10,
189+
}
190+
191+
if v, _ := sw.RangeTotal(9 * time.Second, 10 * time.Second); v != 2 {
192+
t.Errorf("expected the total from second 9 to 10 to be 2, not %d", v)
193+
}
194+
if v, _ := sw.RangeTotal(7 * time.Second, 9 * time.Second); v != 9 {
195+
t.Errorf("expected the total from second 7 to 9 to be 9, not %d", v)
196+
}
197+
}

0 commit comments

Comments
 (0)