Browse Source

Fixed the memory leaks using circular buffer.

Stephen McQuay 5 years ago
parent
commit
f161a60e37
2 changed files with 99 additions and 13 deletions
  1. 29
    10
      bandwidth.go
  2. 70
    3
      bandwidth_test.go

+ 29
- 10
bandwidth.go View File

@@ -4,7 +4,6 @@ package bandwidth
4 4
 
5 5
 import (
6 6
 	"errors"
7
-	"log"
8 7
 	"sort"
9 8
 	"time"
10 9
 )
@@ -27,6 +26,7 @@ type Bandwidth struct {
27 26
 	rxSnap []float64
28 27
 	txSnap []float64
29 28
 	dt     time.Duration
29
+	dts    []int
30 30
 
31 31
 	curRx int
32 32
 	curTx int
@@ -39,8 +39,8 @@ type Bandwidth struct {
39 39
 }
40 40
 
41 41
 // NewBandwidth Returns a populated and ready to launch Bandwidth. seconds is
42
-// a slice of seconds on which to report (e.g. 1, 10, 60 seconds). dt is how
43
-// often the values used to send to Rx and Tx are updated.
42
+// a slice of multiples of dt on which to report (e.g. 1x, 10x, 60x dt). dt is
43
+// also how often the values used to send to Rx and Tx are updated.
44 44
 func NewBandwidth(dts []int, dt time.Duration) (*Bandwidth, error) {
45 45
 	if len(dts) < 1 {
46 46
 		return nil, errors.New("must specify at least one interval lenght")
@@ -53,6 +53,7 @@ func NewBandwidth(dts []int, dt time.Duration) (*Bandwidth, error) {
53 53
 		Rx:       make(chan []float64),
54 54
 		Tx:       make(chan []float64),
55 55
 		dt:       dt,
56
+		dts:      dts,
56 57
 		Quit:     make(chan interface{}),
57 58
 		rxstream: make([]int, max),
58 59
 		txstream: make([]int, max),
@@ -71,18 +72,27 @@ outer:
71 72
 		case <-t.C:
72 73
 			bw.rxstream[bw.timeI] = bw.curRx
73 74
 			bw.txstream[bw.timeI] = bw.curTx
75
+
74 76
 			bw.rxSnap = bw.averages(bw.rxstream)
75 77
 			bw.txSnap = bw.averages(bw.txstream)
78
+
76 79
 			bw.curTx = 0
77 80
 			bw.curRx = 0
78
-			bw.timeI += 1
79
-			// testing hg branching
81
+
82
+			// n.b.: here we march forward through time by going backward in
83
+			// our slice.
84
+			bw.timeI = (bw.timeI - 1) % bw.max
85
+			// lol: because modulo does unexpected things for negative numbers.
86
+			if bw.timeI < 0 {
87
+				bw.timeI = bw.timeI + bw.max
88
+			}
89
+			// log.Printf("%d %+v", bw.timeI, bw.rxstream)
80 90
 		case bw.Rx <- bw.rxSnap:
81 91
 		case bw.Tx <- bw.txSnap:
82 92
 		case s := <-bw.AddRx:
83
-			bw.curTx += s
84
-		case s := <-bw.AddTx:
85 93
 			bw.curRx += s
94
+		case s := <-bw.AddTx:
95
+			bw.curTx += s
86 96
 		case <-bw.Quit:
87 97
 			break outer
88 98
 		}
@@ -94,8 +104,17 @@ outer:
94 104
 }
95 105
 
96 106
 func (bw *Bandwidth) averages(state []int) []float64 {
97
-	for i := 0; i < bw.max; i++ {
98
-		log.Println(bw.timeI + i)
107
+	r := []float64{}
108
+	var i int = 0
109
+	total := 0
110
+	for _, ti := range bw.dts {
111
+		for ; ; i++ {
112
+			if i == ti {
113
+				break
114
+			}
115
+			total += state[(bw.timeI+i)%bw.max]
116
+		}
117
+		r = append(r, float64(total)/float64(ti))
99 118
 	}
100
-	return nil
119
+	return r
101 120
 }

+ 70
- 3
bandwidth_test.go View File

@@ -38,7 +38,74 @@ func TestEmptySeconds(t *testing.T) {
38 38
 	}
39 39
 }
40 40
 
41
-func TestA(t *testing.T) {
42
-	bw, _ := NewBandwidth([]int{1, 10, 30}, 1*time.Second)
43
-	log.Printf("%+v", bw)
41
+func TestStreamSize(t *testing.T) {
42
+	bw, _ := NewBandwidth([]int{1, 2, 5}, 1*time.Second)
43
+	if len(bw.rxstream) != 5 {
44
+		t.Errorf("rxstream slice wrong length: %d, expected %d", len(bw.rxstream), 5)
45
+	}
46
+	if len(bw.txstream) != 5 {
47
+		t.Errorf("txstream slice wrong length: %d, expected %d", len(bw.rxstream), 5)
48
+	}
49
+}
50
+
51
+func TestOnes(t *testing.T) {
52
+	bw, _ := NewBandwidth([]int{1, 2, 5}, 1*time.Second)
53
+	for i := 0; i < bw.max; i++ {
54
+		bw.rxstream[i] = 1.0
55
+	}
56
+	avgs := bw.averages(bw.rxstream)
57
+	// try a large range of starting points:
58
+	for i := 0; i < 10; i++ {
59
+		bw.timeI = i
60
+		validate(t, avgs, []float64{1.0, 1.0, 1.0})
61
+	}
62
+}
63
+
64
+func TestManyOnes(t *testing.T) {
65
+	bw, _ := NewBandwidth([]int{1, 10, 60}, 1*time.Second)
66
+	for i := 0; i < bw.max; i++ {
67
+		bw.rxstream[i] = 1.0
68
+	}
69
+	avgs := bw.averages(bw.rxstream)
70
+	// try a large range of starting points:
71
+	for i := -70; i < 70; i++ {
72
+		bw.timeI = i
73
+		validate(t, avgs, []float64{1.0, 1.0, 1.0})
74
+	}
75
+}
76
+
77
+func TestLinear(t *testing.T) {
78
+	bw, _ := NewBandwidth([]int{1, 10, 60}, 1*time.Second)
79
+	for i := 0; i < bw.max; i++ {
80
+		bw.rxstream[i] = i
81
+	}
82
+	avgs := bw.averages(bw.rxstream)
83
+	validate(t, avgs, []float64{0.0, 4.5, 29.5})
84
+}
85
+
86
+func TestInverseLinear(t *testing.T) {
87
+	bw, _ := NewBandwidth([]int{1, 10, 60}, 1*time.Second)
88
+	for i := 0; i < bw.max; i++ {
89
+		bw.rxstream[i] = bw.max - i
90
+	}
91
+	avgs := bw.averages(bw.rxstream)
92
+	validate(t, avgs, []float64{60.0, 55.5, 30.5})
93
+}
94
+
95
+func TestSpecific(t *testing.T) {
96
+	bw, _ := NewBandwidth([]int{1, 2, 10}, 1*time.Second)
97
+	bw.rxstream[8] = 1.0
98
+	var avgs []float64
99
+
100
+	bw.timeI = 8
101
+	avgs = bw.averages(bw.rxstream)
102
+	validate(t, avgs, []float64{1.0, 0.5, 0.1})
103
+
104
+	bw.timeI = 7
105
+	avgs = bw.averages(bw.rxstream)
106
+	validate(t, avgs, []float64{0.0, 0.5, 0.1})
107
+
108
+	bw.timeI = 9
109
+	avgs = bw.averages(bw.rxstream)
110
+	validate(t, avgs, []float64{0.0, 0.0, 0.1})
44 111
 }

Loading…
Cancel
Save