pool_test.go 3.96 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3 4 5 6 7
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pool is no-op under race detector, so all these tests do not work.
// +build !race

8
package pool
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9 10

import (
11
	"bytes"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12
	"fmt"
13
	"math/rand"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14 15 16 17 18
	"runtime"
	"runtime/debug"
	"testing"
)

Steven Allen's avatar
Steven Allen committed
19 20 21 22 23 24 25 26 27 28 29
func TestAllocations(t *testing.T) {
	var m1, m2 runtime.MemStats
	runtime.ReadMemStats(&m1)
	runtime.GC()
	for i := 0; i < 10000; i++ {
		b := Get(1010)
		Put(b)
	}
	runtime.GC()
	runtime.ReadMemStats(&m2)
	frees := m2.Frees - m1.Frees
30
	if frees > 1000 {
Steven Allen's avatar
Steven Allen committed
31 32 33 34
		t.Fatalf("expected less than 100 frees after GC, got %d", frees)
	}
}

35 36 37 38 39 40 41 42 43 44 45
func TestRange(t *testing.T) {
	min := nextLogBase2(1)
	max := nextLogBase2(uint32(MaxLength))
	if int(max) != len(GlobalPool.pools)-1 {
		t.Errorf("expected %d pools, found %d", max, len(GlobalPool.pools))
	}
	if min != 0 {
		t.Errorf("unused min pool")
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
46 47 48
func TestPool(t *testing.T) {
	// disable GC so we can control when it happens.
	defer debug.SetGCPercent(debug.SetGCPercent(-1))
49 50 51 52 53 54 55 56 57 58
	var p BufferPool

	a := make([]byte, 21)
	a[0] = 1
	b := make([]byte, 2050)
	b[0] = 2
	p.Put(a)
	p.Put(b)
	if g := p.Get(16); &g[0] != &a[0] {
		t.Fatalf("got [%d,...]; want [1,...]", g[0])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
59
	}
60 61
	if g := p.Get(2048); &g[0] != &b[0] {
		t.Fatalf("got [%d,...]; want [2,...]", g[0])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
62
	}
63 64
	if g := p.Get(16); cap(g) != 16 || !bytes.Equal(g[:16], make([]byte, 16)) {
		t.Fatalf("got existing slice; want new slice")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65
	}
66 67
	if g := p.Get(2048); cap(g) != 2048 || !bytes.Equal(g[:2048], make([]byte, 2048)) {
		t.Fatalf("got existing slice; want new slice")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
68
	}
69 70
	if g := p.Get(1); cap(g) != 1 || !bytes.Equal(g[:1], make([]byte, 1)) {
		t.Fatalf("got existing slice; want new slice")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71
	}
72 73 74 75 76
	d := make([]byte, 1023)
	d[0] = 3
	p.Put(d)
	if g := p.Get(1024); cap(g) != 1024 || !bytes.Equal(g, make([]byte, 1024)) {
		t.Fatalf("got existing slice; want new slice")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77
	}
78 79
	if g := p.Get(512); cap(g) != 1023 || g[0] != 3 {
		t.Fatalf("got [%d,...]; want [3,...]", g[0])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
80
	}
81
	p.Put(a)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
82 83 84

	debug.SetGCPercent(100) // to allow following GC to actually run
	runtime.GC()
Steven Allen's avatar
Steven Allen committed
85 86
	// For some reason, you need to run GC twice on go 1.16 if you want it to reliably work.
	runtime.GC()
87 88
	if g := p.Get(10); &g[0] == &a[0] {
		t.Fatalf("got a; want new slice after GC")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89 90 91
	}
}

92
func TestPoolStressByteSlicePool(t *testing.T) {
93 94
	var p BufferPool

95 96
	const P = 10
	chs := 10
Steven Allen's avatar
Steven Allen committed
97
	maxSize := 1 << 16
98 99 100 101 102 103 104 105 106 107 108
	N := int(1e4)
	if testing.Short() {
		N /= 100
	}
	done := make(chan bool)
	errs := make(chan error)
	for i := 0; i < P; i++ {
		go func() {
			ch := make(chan []byte, chs+1)

			for i := 0; i < chs; i++ {
Steven Allen's avatar
Steven Allen committed
109
				j := rand.Int() % maxSize
110
				ch <- p.Get(j)
111 112 113
			}

			for j := 0; j < N; j++ {
Steven Allen's avatar
Steven Allen committed
114
				r := 0
115 116
				for i := 0; i < chs; i++ {
					v := <-ch
117
					p.Put(v)
Steven Allen's avatar
Steven Allen committed
118
					r = rand.Int() % maxSize
119
					v = p.Get(r)
Steven Allen's avatar
Steven Allen committed
120
					if len(v) < r {
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
						errs <- fmt.Errorf("expect len(v) >= %d, got %d", j, len(v))
					}
					ch <- v
				}

				if r%1000 == 0 {
					runtime.GC()
				}
			}
			done <- true
		}()
	}

	for i := 0; i < P; {
		select {
		case <-done:
			i++
		case err := <-errs:
			t.Error(err)
		}
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
144
func BenchmarkPool(b *testing.B) {
145
	var p BufferPool
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
146
	b.RunParallel(func(pb *testing.PB) {
Steven Allen's avatar
Steven Allen committed
147
		i := 7
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
148
		for pb.Next() {
149 150 151 152 153 154
			if i > 1<<20 {
				i = 7
			} else {
				i = i << 1
			}
			b := p.Get(i)
Steven Allen's avatar
Steven Allen committed
155
			b[0] = byte(i)
156
			p.Put(b)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
157 158 159 160
		}
	})
}

Steven Allen's avatar
Steven Allen committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
func BenchmarkAlloc(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		i := 7
		for pb.Next() {
			if i > 1<<20 {
				i = 7
			} else {
				i = i << 1
			}
			b := make([]byte, i)
			b[1] = byte(i)
		}
	})
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
176
func BenchmarkPoolOverlflow(b *testing.B) {
177
	var p BufferPool
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
178 179
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
180 181 182
			bufs := make([][]byte, 2100)
			for pow := uint32(0); pow < 21; pow++ {
				for i := 0; i < 100; i++ {
Steven Allen's avatar
Steven Allen committed
183
					bufs = append(bufs, p.Get(1<<pow))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
184 185
				}
			}
186 187
			for _, b := range bufs {
				p.Put(b)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
188 189 190 191
			}
		}
	})
}
Steven Allen's avatar
Steven Allen committed
192 193 194 195 196 197 198 199 200 201

func ExampleGet() {
	buf := Get(100)
	fmt.Println("length", len(buf))
	fmt.Println("capacity", cap(buf))
	Put(buf)
	// Output:
	// length 100
	// capacity 128
}