github.com/etecs-ru/ristretto@v0.9.1/z/allocator_test.go (about)

     1  /*
     2   * Copyright 2020 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package z
    18  
    19  import (
    20  	"math/rand"
    21  	"sort"
    22  	"sync"
    23  	"testing"
    24  	"unsafe"
    25  
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func TestAllocate(t *testing.T) {
    30  	a := NewAllocator(1024, "test")
    31  	defer a.Release()
    32  
    33  	check := func() {
    34  		t.Logf("Running checks\n")
    35  		require.Equal(t, 0, len(a.Allocate(0)))
    36  		require.Equal(t, 1, len(a.Allocate(1)))
    37  		require.Equal(t, 1<<20+1, len(a.Allocate(1<<20+1)))
    38  		require.Equal(t, 256<<20, len(a.Allocate(256<<20)))
    39  		require.Panics(t, func() { a.Allocate(maxAlloc + 1) })
    40  	}
    41  
    42  	check()
    43  	t.Logf("%s", a)
    44  	prev := a.Allocated()
    45  	t.Logf("Resetting\n")
    46  	a.Reset()
    47  	check()
    48  	t.Logf("%s", a)
    49  	require.Equal(t, int(prev), int(a.Allocated()))
    50  	t.Logf("Allocated: %d\n", prev)
    51  }
    52  
    53  func TestAllocateSize(t *testing.T) {
    54  	a := NewAllocator(1024, "test")
    55  	require.Equal(t, 1024, len(a.buffers[0]))
    56  	a.Release()
    57  
    58  	b := NewAllocator(1025, "test")
    59  	require.Equal(t, 2048, len(b.buffers[0]))
    60  	b.Release()
    61  }
    62  
    63  func TestAllocateReset(t *testing.T) {
    64  	a := NewAllocator(16, "test")
    65  	defer a.Release()
    66  
    67  	buf := make([]byte, 128)
    68  	rand.Read(buf)
    69  	for i := 0; i < 1000; i++ {
    70  		a.Copy(buf)
    71  	}
    72  
    73  	prev := a.Allocated()
    74  	a.Reset()
    75  	for i := 0; i < 100; i++ {
    76  		a.Copy(buf)
    77  	}
    78  	t.Logf("%s", a)
    79  	require.Equal(t, prev, a.Allocated())
    80  }
    81  
    82  func TestAllocateTrim(t *testing.T) {
    83  	a := NewAllocator(16, "test")
    84  	defer a.Release()
    85  
    86  	buf := make([]byte, 128)
    87  	rand.Read(buf)
    88  	for i := 0; i < 1000; i++ {
    89  		a.Copy(buf)
    90  	}
    91  
    92  	N := 2048
    93  	a.TrimTo(N)
    94  	require.LessOrEqual(t, int(a.Allocated()), N)
    95  }
    96  
    97  func TestPowTwo(t *testing.T) {
    98  	require.Equal(t, 2, log2(4))
    99  	require.Equal(t, 2, log2(7))
   100  	require.Equal(t, 3, log2(8))
   101  	require.Equal(t, 3, log2(15))
   102  	require.Equal(t, 4, log2(16))
   103  	require.Equal(t, 4, log2(31))
   104  	require.Equal(t, 10, log2(1024))
   105  	require.Equal(t, 10, log2(1025))
   106  	require.Equal(t, 10, log2(2047))
   107  	require.Equal(t, 11, log2(2048))
   108  }
   109  
   110  func TestAllocateAligned(t *testing.T) {
   111  	a := NewAllocator(1024, "test")
   112  	defer a.Release()
   113  
   114  	a.Allocate(1)
   115  	out := a.Allocate(1)
   116  	ptr := uintptr(unsafe.Pointer(&out[0]))
   117  	require.True(t, ptr%8 == 1)
   118  
   119  	out = a.AllocateAligned(5)
   120  	ptr = uintptr(unsafe.Pointer(&out[0]))
   121  	require.True(t, ptr%8 == 0)
   122  
   123  	out = a.AllocateAligned(3)
   124  	ptr = uintptr(unsafe.Pointer(&out[0]))
   125  	require.True(t, ptr%8 == 0)
   126  }
   127  
   128  func TestAllocateConcurrent(t *testing.T) {
   129  	a := NewAllocator(63, "test")
   130  	defer a.Release()
   131  
   132  	N := 10240
   133  	M := 16
   134  	var wg sync.WaitGroup
   135  
   136  	m := make(map[uintptr]struct{})
   137  	mu := new(sync.Mutex)
   138  	for i := 0; i < M; i++ {
   139  		wg.Add(1)
   140  		go func() {
   141  			defer wg.Done()
   142  			var bufs []uintptr
   143  			for j := 0; j < N; j++ {
   144  				buf := a.Allocate(16)
   145  				require.Equal(t, 16, len(buf))
   146  				bufs = append(bufs, uintptr(unsafe.Pointer(&buf[0])))
   147  			}
   148  
   149  			mu.Lock()
   150  			for _, b := range bufs {
   151  				if _, ok := m[b]; ok {
   152  					t.Fatalf("Did not expect to see the same ptr")
   153  				}
   154  				m[b] = struct{}{}
   155  			}
   156  			mu.Unlock()
   157  		}()
   158  	}
   159  	wg.Wait()
   160  	t.Logf("Size of allocator: %v. Allocator: %s\n", a.Size(), a)
   161  
   162  	require.Equal(t, N*M, len(m))
   163  	var sorted []uintptr
   164  	for ptr := range m {
   165  		sorted = append(sorted, ptr)
   166  	}
   167  
   168  	sort.Slice(sorted, func(i, j int) bool {
   169  		return sorted[i] < sorted[j]
   170  	})
   171  
   172  	var last uintptr
   173  	for _, ptr := range sorted {
   174  		if ptr-last < 16 {
   175  			t.Fatalf("Should not have less than 16: %v %v\n", ptr, last)
   176  		}
   177  		// fmt.Printf("ptr [%d]: %x %d\n", i, ptr, ptr-last)
   178  		last = ptr
   179  	}
   180  }
   181  
   182  func BenchmarkAllocate(b *testing.B) {
   183  	a := NewAllocator(15, "test")
   184  	b.RunParallel(func(pb *testing.PB) {
   185  		for pb.Next() {
   186  			buf := a.Allocate(1)
   187  			if len(buf) != 1 {
   188  				b.FailNow()
   189  			}
   190  		}
   191  	})
   192  	b.StopTimer()
   193  	b.Logf("%s", a)
   194  }