diff options
Diffstat (limited to 'libgo/go/sync/pool_test.go')
-rw-r--r-- | libgo/go/sync/pool_test.go | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/libgo/go/sync/pool_test.go b/libgo/go/sync/pool_test.go new file mode 100644 index 0000000..f88dab4 --- /dev/null +++ b/libgo/go/sync/pool_test.go @@ -0,0 +1,159 @@ +// 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. + +package sync_test + +import ( + "runtime" + "runtime/debug" + . "sync" + "sync/atomic" + "testing" + "time" + "unsafe" +) + +func TestPool(t *testing.T) { + // disable GC so we can control when it happens. + defer debug.SetGCPercent(debug.SetGCPercent(-1)) + var p Pool + if p.Get() != nil { + t.Fatal("expected empty") + } + p.Put("a") + p.Put("b") + if g := p.Get(); g != "b" { + t.Fatalf("got %#v; want b", g) + } + if g := p.Get(); g != "a" { + t.Fatalf("got %#v; want a", g) + } + if g := p.Get(); g != nil { + t.Fatalf("got %#v; want nil", g) + } + + p.Put("c") + debug.SetGCPercent(100) // to allow following GC to actually run + runtime.GC() + if g := p.Get(); g != nil { + t.Fatalf("got %#v; want nil after GC", g) + } +} + +func TestPoolNew(t *testing.T) { + // disable GC so we can control when it happens. + defer debug.SetGCPercent(debug.SetGCPercent(-1)) + + i := 0 + p := Pool{ + New: func() interface{} { + i++ + return i + }, + } + if v := p.Get(); v != 1 { + t.Fatalf("got %v; want 1", v) + } + if v := p.Get(); v != 2 { + t.Fatalf("got %v; want 2", v) + } + p.Put(42) + if v := p.Get(); v != 42 { + t.Fatalf("got %v; want 42", v) + } + if v := p.Get(); v != 3 { + t.Fatalf("got %v; want 3", v) + } +} + +// Test that Pool does not hold pointers to previously cached +// resources +func TestPoolGC(t *testing.T) { + var p Pool + var fin uint32 + const N = 100 + for i := 0; i < N; i++ { + v := new(int) + runtime.SetFinalizer(v, func(vv *int) { + atomic.AddUint32(&fin, 1) + }) + p.Put(v) + } + for i := 0; i < N; i++ { + p.Get() + } + for i := 0; i < 5; i++ { + runtime.GC() + time.Sleep(time.Millisecond) + // 1 pointer can remain on stack or elsewhere + if atomic.LoadUint32(&fin) >= N-1 { + return + } + + // gccgo has a less precise heap. + if runtime.Compiler == "gccgo" && atomic.LoadUint32(&fin) >= N-5 { + return + } + } + t.Fatalf("only %v out of %v resources are finalized", + atomic.LoadUint32(&fin), N) +} + +func TestPoolStress(t *testing.T) { + const P = 10 + N := int(1e6) + if testing.Short() { + N /= 100 + } + var p Pool + done := make(chan bool) + for i := 0; i < P; i++ { + go func() { + var v interface{} = 0 + for j := 0; j < N; j++ { + if v == nil { + v = 0 + } + p.Put(v) + v = p.Get() + if v != nil && v.(int) != 0 { + t.Fatalf("expect 0, got %v", v) + } + } + done <- true + }() + } + for i := 0; i < P; i++ { + <-done + } +} + +func BenchmarkPool(b *testing.B) { + procs := runtime.GOMAXPROCS(-1) + var dec func() bool + if unsafe.Sizeof(b.N) == 8 { + n := int64(b.N) + dec = func() bool { + return atomic.AddInt64(&n, -1) >= 0 + } + } else { + n := int32(b.N) + dec = func() bool { + return atomic.AddInt32(&n, -1) >= 0 + } + } + var p Pool + var wg WaitGroup + for i := 0; i < procs; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for dec() { + p.Put(1) + p.Get() + } + }() + } + wg.Wait() +} |