github.com/matrixorigin/matrixone@v0.7.0/pkg/common/mpool/mpool_test.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mpool 16 17 import ( 18 "sync" 19 "sync/atomic" 20 "testing" 21 "unsafe" 22 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestMPool(t *testing.T) { 27 // Just test a mid sized 28 m, err := NewMPool("test-mpool-small", 0, Small) 29 require.True(t, err == nil, "new mpool failed %v", err) 30 31 nb0 := m.CurrNB() 32 hw0 := m.Stats().HighWaterMark.Load() 33 nalloc0 := m.Stats().NumAlloc.Load() 34 nfree0 := m.Stats().NumFree.Load() 35 36 // Small has 5 non-zero fixed pool. 37 require.True(t, nalloc0 == 5, "bad nalloc") 38 require.True(t, nfree0 == 0, "bad nfree") 39 40 for i := 1; i <= 10000; i++ { 41 a, err := m.Alloc(i * 10) 42 require.True(t, err == nil, "alloc failure, %v", err) 43 require.True(t, len(a) == i*10, "allocation i size error") 44 a[0] = 0xF0 45 require.True(t, a[1] == 0, "allocation result not zeroed.") 46 a[i*10-1] = 0xBA 47 a, err = m.Realloc(a, i*20) 48 require.True(t, err == nil, "realloc failure %v", err) 49 require.True(t, len(a) == i*20, "allocation i size error") 50 require.True(t, a[0] == 0xF0, "reallocation not copied") 51 require.True(t, a[i*10-1] == 0xBA, "reallocation not copied") 52 require.True(t, a[i*10] == 0, "reallocation not zeroed") 53 require.True(t, a[i*20-1] == 0, "reallocation not zeroed") 54 m.Free(a) 55 } 56 57 require.True(t, nb0 == m.CurrNB(), "leak") 58 // 30 -- we realloc, therefore, 10 + 20, need alloc first, then copy. 59 require.True(t, hw0+10000*30 == m.Stats().HighWaterMark.Load(), "hw") 60 // >, because some alloc is absorbed by fixed pool 61 require.True(t, nalloc0+10000*2 > m.Stats().NumAlloc.Load(), "alloc") 62 require.True(t, nalloc0-nfree0 == m.Stats().NumAlloc.Load()-m.Stats().NumFree.Load(), "free") 63 require.True(t, m.FixedPoolStats(0).NumAlloc.Load() > 0, "use 64b pool") 64 require.True(t, m.FixedPoolStats(0).NumGoAlloc.Load() == 0, "use 64b pool") 65 require.True(t, m.FixedPoolStats(6).NumAlloc.Load() == 0, "use 64b pool") 66 } 67 68 func TestFreelist(t *testing.T) { 69 // Too much for CI 70 t.Skip() 71 72 // a list of ten items 73 type item struct { 74 lastWriter int32 75 updateCount int64 76 } 77 var items [10]item 78 fl := make_freelist(10) 79 for i := 0; i < 10; i++ { 80 fl.put(unsafe.Pointer(&items[i])) 81 } 82 83 // let 20 threads run for it, each looping 1 million times. 84 type result struct { 85 okCount int64 86 missCount int64 87 } 88 var results [20]result 89 var wg sync.WaitGroup 90 for i := 0; i < 20; i++ { 91 wg.Add(1) 92 go func(ii int) { 93 defer wg.Done() 94 for j := 0; j < 1000000; j++ { 95 ptr := fl.get() 96 if ptr == nil { 97 results[ii].missCount += 1 98 } else { 99 results[ii].okCount += 1 100 pitem := (*item)(ptr) 101 pitem.lastWriter = int32(ii) 102 // this must be atomic -- the following could possibly 103 // lost an update count. 104 // pitem.updateCount += 1 105 atomic.AddInt64(&pitem.updateCount, 1) 106 fl.put(ptr) 107 } 108 } 109 }(i) 110 } 111 wg.Wait() 112 113 var totalOK1, totalOK2, totalMiss int64 114 for i := 0; i < 10; i++ { 115 require.True(t, items[i].lastWriter >= 0, "bad writer") 116 require.True(t, items[i].lastWriter < 20, "bad writer") 117 totalOK1 += items[i].updateCount 118 } 119 120 for i := 0; i < 20; i++ { 121 require.True(t, results[i].okCount >= 0, "bad result") 122 require.True(t, results[i].okCount < 1000000, "bad result") 123 require.True(t, results[i].missCount >= 0, "bad result") 124 require.True(t, results[i].missCount < 1000000, "bad result") 125 totalOK2 += results[i].okCount 126 totalMiss += results[i].missCount 127 } 128 129 require.True(t, totalOK1 == totalOK2, "wrong ok counter") 130 require.True(t, totalOK2+totalMiss == 20*1000000, "wrong counter") 131 } 132 133 func TestReportMemUsage(t *testing.T) { 134 // Just test a mid sized 135 m, err := NewMPool("testjson", 0, Small) 136 m.EnableDetailRecording() 137 138 require.True(t, err == nil, "new mpool failed %v", err) 139 mem, err := m.Alloc(1000000) 140 require.True(t, err == nil, "mpool alloc failed %v", err) 141 142 j1 := ReportMemUsage("") 143 j2 := ReportMemUsage("global") 144 j3 := ReportMemUsage("testjson") 145 t.Logf("mem usage: %s", j1) 146 t.Logf("global mem usage: %s", j2) 147 t.Logf("testjson mem usage: %s", j3) 148 149 m.Free(mem) 150 j1 = ReportMemUsage("") 151 j2 = ReportMemUsage("global") 152 j3 = ReportMemUsage("testjson") 153 t.Logf("mem usage: %s", j1) 154 t.Logf("global mem usage: %s", j2) 155 t.Logf("testjson mem usage: %s", j3) 156 157 DeleteMPool(m) 158 j1 = ReportMemUsage("") 159 j2 = ReportMemUsage("global") 160 j3 = ReportMemUsage("testjson") 161 t.Logf("mem usage: %s", j1) 162 t.Logf("global mem usage: %s", j2) 163 t.Logf("testjson mem usage: %s", j3) 164 } 165 166 func TestMP(t *testing.T) { 167 pool, err := NewMPool("default", 0, Large) 168 if err != nil { 169 panic(err) 170 } 171 var wg sync.WaitGroup 172 run := func() { 173 defer wg.Done() 174 for i := 0; i < 1000; i++ { 175 buf, err := pool.Alloc(10) 176 if err != nil { 177 panic(err) 178 } 179 pool.Free(buf) 180 } 181 } 182 for i := 0; i < 800; i++ { 183 wg.Add(1) 184 go run() 185 } 186 wg.Wait() 187 188 }