pool_test.go 3.37 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 30 31 32 33 34
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
	if frees > 100 {
		t.Fatalf("expected less than 100 frees after GC, got %d", frees)
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35 36 37
func TestPool(t *testing.T) {
	// disable GC so we can control when it happens.
	defer debug.SetGCPercent(debug.SetGCPercent(-1))
38 39 40 41 42 43 44 45 46 47
	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
48
	}
49 50
	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
51
	}
52 53
	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
54
	}
55 56
	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
57
	}
58 59
	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
60
	}
61 62 63 64 65
	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
66
	}
67 68
	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
69
	}
70
	p.Put(a)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71 72 73

	debug.SetGCPercent(100) // to allow following GC to actually run
	runtime.GC()
74 75
	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
76 77 78
	}
}

79
func TestPoolStressByteSlicePool(t *testing.T) {
80 81
	var p BufferPool

82 83
	const P = 10
	chs := 10
Steven Allen's avatar
Steven Allen committed
84
	maxSize := 1 << 16
85 86 87 88 89 90 91 92 93 94 95
	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
96
				j := rand.Int() % maxSize
97
				ch <- p.Get(j)
98 99 100
			}

			for j := 0; j < N; j++ {
Steven Allen's avatar
Steven Allen committed
101
				r := 0
102 103
				for i := 0; i < chs; i++ {
					v := <-ch
104
					p.Put(v)
Steven Allen's avatar
Steven Allen committed
105
					r = rand.Int() % maxSize
106
					v = p.Get(r)
Steven Allen's avatar
Steven Allen committed
107
					if len(v) < r {
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
						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
131
func BenchmarkPool(b *testing.B) {
132
	var p BufferPool
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
133
	b.RunParallel(func(pb *testing.PB) {
Steven Allen's avatar
Steven Allen committed
134
		i := 7
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
135
		for pb.Next() {
136 137 138 139 140 141 142
			if i > 1<<20 {
				i = 7
			} else {
				i = i << 1
			}
			b := p.Get(i)
			p.Put(b)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
143 144 145 146 147
		}
	})
}

func BenchmarkPoolOverlflow(b *testing.B) {
148
	var p BufferPool
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
149 150
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
151 152 153
			bufs := make([][]byte, 2100)
			for pow := uint32(0); pow < 21; pow++ {
				for i := 0; i < 100; i++ {
Steven Allen's avatar
Steven Allen committed
154
					bufs = append(bufs, p.Get(1<<pow))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
155 156
				}
			}
157 158
			for _, b := range bufs {
				p.Put(b)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
159 160 161 162
			}
		}
	})
}
Steven Allen's avatar
Steven Allen committed
163 164 165 166 167 168 169 170 171 172

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