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  }