lab.nexedi.com/kirr/go123@v0.0.0-20240207185015-8299741fa871/mem/buffer_test.go (about) 1 // Copyright (C) 2017 Nexedi SA and Contributors. 2 // Kirill Smelkov <kirr@nexedi.com> 3 // 4 // This program is free software: you can Use, Study, Modify and Redistribute 5 // it under the terms of the GNU General Public License version 3, or (at your 6 // option) any later version, as published by the Free Software Foundation. 7 // 8 // You can also Link and Combine this program with other software covered by 9 // the terms of any of the Free Software licenses or any of the Open Source 10 // Initiative approved licenses and Convey the resulting work. Corresponding 11 // source of such a combination shall include the source code for all other 12 // software used. 13 // 14 // This program is distributed WITHOUT ANY WARRANTY; without even the implied 15 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 // 17 // See COPYING file for full licensing terms. 18 // See https://www.nexedi.com/licensing for rationale and options. 19 20 // As of go19 sync.Pool under race-detector randomly drops items on the floor 21 // https://github.com/golang/go/blob/ca360c39/src/sync/pool.go#L92 22 // so it is not possible to verify we will get what we've just put there. 23 //go:build !race 24 // +build !race 25 26 package mem 27 28 import ( 29 "reflect" 30 "testing" 31 "unsafe" 32 ) 33 34 //go:linkname runtime_procPin runtime.procPin 35 //go:linkname runtime_procUnpin runtime.procUnpin 36 func runtime_procPin() int 37 func runtime_procUnpin() 38 39 40 func sliceDataPtr(b []byte) unsafe.Pointer { 41 return unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data) 42 } 43 44 func TestBufAllocFree(t *testing.T) { 45 // sync.Pool uses per-P free-lists. We check that after release we will 46 // allocate released object. This works only if P is not changed underneath. 47 runtime_procPin() 48 defer runtime_procUnpin() 49 50 for i := uint(0); i < 25; i++ { 51 size := 1<<i - 1 52 xcap := 1<<i 53 buf := BufAlloc(size) 54 if i < order0 { 55 xcap = 1 << order0 56 } 57 if int(i) >= order0+len(bufPoolv) { 58 xcap = size 59 } 60 61 if len(buf.Data) != size { 62 t.Fatalf("%v: len=%v ; want %v", i, len(buf.Data), size) 63 } 64 if cap(buf.Data) != xcap { 65 t.Fatalf("%v: cap=%v ; want %v", i, cap(buf.Data), xcap) 66 } 67 68 checkref := func(rc int32) { 69 t.Helper() 70 if buf.refcnt != rc { 71 t.Fatalf("%v: refcnt=%v ; want %v", i, buf.refcnt, rc) 72 } 73 } 74 75 checkref(0) 76 77 // free and allocate another buf -> it must be it 78 data := buf.Data 79 buf.Release() 80 checkref(-1) 81 buf2 := BufAlloc(size) 82 83 // not from pool - memory won't be reused 84 if int(i) >= order0+len(bufPoolv) { 85 if buf2 == buf || sliceDataPtr(buf2.Data) == sliceDataPtr(data) { 86 t.Fatalf("%v: buffer reused but should not", i) 87 } 88 continue 89 } 90 91 // from pool -> it must be the same 92 if !(buf2 == buf && sliceDataPtr(buf2.Data) == sliceDataPtr(data)) { 93 t.Fatalf("%v: buffer not reused on free/realloc", i) 94 } 95 checkref(0) 96 97 // add more ref and release original buf - it must stay alive 98 buf.Incref() 99 checkref(1) 100 buf.Release() 101 checkref(0) 102 103 // another alloc must be different 104 buf2 = BufAlloc(size) 105 checkref(0) 106 107 if buf2 == buf || sliceDataPtr(buf2.Data) == sliceDataPtr(data) { 108 t.Fatalf("%v: buffer reused but should not", i) 109 } 110 111 // release buf again -> should go to pool 112 buf.Release() 113 checkref(-1) 114 buf2 = BufAlloc(size) 115 if !(buf2 == buf && sliceDataPtr(buf2.Data) == sliceDataPtr(data)) { 116 t.Fatalf("%v: buffer not reused on free/realloc", i) 117 } 118 checkref(0) 119 } 120 }