github.com/moontrade/unsafe@v0.9.1/memory/heap/class_test.go (about)

     1  package heap
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strconv"
     7  	"strings"
     8  	"testing"
     9  )
    10  
    11  const (
    12  	SMALL_DIV  int = 4
    13  	SMALL_MAX  int = 508
    14  	MEDIUM_DIV int = 256
    15  	MEDIUM_MAX int = 16380
    16  	LARGE_MAX  int = 65536 * 256
    17  	HUGE_MAX   int = 65536 * 256
    18  )
    19  
    20  // divRoundUp returns ceil(n / a).
    21  func divRoundUpInt(n, a int) int {
    22  	// a is generally a power of two. This will get inlined and
    23  	// the compiler will optimize the division.
    24  	return (n + a - 1) / a
    25  }
    26  
    27  func nextPowerOf2(v uint32) uint32 {
    28  	v--
    29  	v |= v >> 1
    30  	v |= v >> 2
    31  	v |= v >> 4
    32  	v |= v >> 8
    33  	v |= v >> 16
    34  	return v + 1
    35  }
    36  
    37  var quark = []int{
    38  	12, 28, 60, 124,
    39  }
    40  
    41  var nano = []int{
    42  	12, 28, 44, 60, 124, 252, 508, 1020,
    43  }
    44  var nano16 = []int{
    45  	14, 30, 46, 62, 126, 254, 510, 1020,
    46  }
    47  
    48  var micro = []int{
    49  	8, 12, 16, 20, 28, 36, 44, 60, 76, 92,
    50  	124, 160, 208, 252, 380, 508, 764, 1020,
    51  	2044, 4092, 8188,
    52  }
    53  
    54  type Nano struct {
    55  	Free [8]uint16
    56  }
    57  
    58  var small = []int{
    59  	12, 16, 20, 24, 28, 36, 44, 60, 76, 92, 124, 156, 188, 220, 252, 300, 364, 428, 508, 764,
    60  	1020, 1280, 1532, 2044, 4092, 8188, 16380,
    61  }
    62  
    63  var medium = []int{
    64  	12, 16, 20, 24, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 192, 216, 232, 256, 384, 512, 768, 1024,
    65  	2048, 4096, 8192, 16384, 32768, 65536,
    66  }
    67  
    68  var large = []int{
    69  	12, 16, 20, 24, 28, 36, 44, 60, 76, 92, 124, 156, 188, 220, 252, 300, 364, 428, 508, 764,
    70  	1020, 1280, 1532, 2044, 4092, 8188, 16380, 32764,
    71  	65534, 131098, 262140, 524284, 1048572, 2097148, 4194300, 8388604, 16777212,
    72  }
    73  
    74  func TestGenerate(t *testing.T) {
    75  	//{
    76  	//	g := *NewSizeClassGen(
    77  	//		4,
    78  	//		4,
    79  	//		SMALL_MAX,
    80  	//		256,
    81  	//		4096,
    82  	//		4096,
    83  	//		32768,
    84  	//		small,
    85  	//		//[]int{
    86  	//		//	12, 16, 24, 32, 48, 64, 80, 96, 128, 256, 384, 512, 1024,
    87  	//		//	2048, 4096,
    88  	//		//	8192, 16384, 32768},
    89  	//	)
    90  	//
    91  	//	runtime.SetFinalizer(&g, func(s *SizeClassGen) {
    92  	//		fmt.Println("SetFinalizer")
    93  	//	})
    94  	//	runtime.GC()
    95  	//}
    96  	//runtime.GC()
    97  	fmt.Println("Small Size class count:", len(small))
    98  	g := NewSizeClassGen(
    99  		4,
   100  		SMALL_DIV,
   101  		SMALL_MAX,
   102  		MEDIUM_DIV,
   103  		small[len(small)-1]+4,
   104  		0,
   105  		0,
   106  		NewSizeClasses(small...),
   107  		//[]int{
   108  		//	12, 16, 24, 32, 48, 64, 80, 96, 128, 256, 384, 512, 1024,
   109  		//	2048, 4096,
   110  		//	8192, 16384, 32768},
   111  	)
   112  
   113  	a := divRoundUpInt(3976-g.Medium.Min, MEDIUM_DIV)
   114  	fmt.Println(a)
   115  	fmt.Println(a * MEDIUM_DIV)
   116  	fmt.Println(a*MEDIUM_DIV + g.Medium.Min)
   117  
   118  	fmt.Println("")
   119  	PrintSizeClassesStructInitializer(g.Classes)
   120  	fmt.Println("")
   121  	g.Small.PrintSizeClassesStructInitializer()
   122  	fmt.Println("")
   123  	g.Medium.PrintSizeClassesStructInitializer()
   124  	fmt.Println("")
   125  	//g.Small.PrintIndexes()
   126  	//g.Small.PrintClasses()
   127  	//g.Medium.PrintIndexes()
   128  	//g.Medium.PrintClasses()
   129  
   130  	//g.printSizeClass(0)
   131  	//g.printSizeClass(1)
   132  	//g.printSizeClass(9)
   133  	//g.printSizeClass(12)
   134  	//g.printSizeClass(13)
   135  	//g.printSizeClass(21)
   136  	//g.printSizeClass(29)
   137  	//g.printSizeClass(33)
   138  	//g.printSizeClass(36)
   139  	//g.printSizeClass(43)
   140  	//g.printSizeClass(59)
   141  	//g.printSizeClass(78)
   142  	//g.printSizeClass(256)
   143  	//g.printSizeClass(768)
   144  	//g.printSizeClass(1024)
   145  	//g.printSizeClass(1025)
   146  	g.printSizeClass(3976)
   147  }
   148  
   149  func (s *SizeClassGen) printSizeClass(size int) {
   150  
   151  	cls := s.Get(size)
   152  	if cls == nil {
   153  		fmt.Println("Size:", size, "  is out of bounds!")
   154  		return
   155  	}
   156  	fmt.Println("["+strconv.Itoa(cls.Index)+"]"+" Size:", size, " Class:", cls.Size, " Shift:", cls.Shift)
   157  }
   158  
   159  type SizeClass struct {
   160  	Index int
   161  	Shift int
   162  	Size  int
   163  }
   164  
   165  func NewSizeClasses(sizes ...int) []SizeClass {
   166  	sort.Ints(sizes)
   167  	classes := make([]SizeClass, len(sizes))
   168  	for i := 0; i < len(sizes); i++ {
   169  		classes[i] = SizeClass{
   170  			Index: i,
   171  			Shift: 31 - i,
   172  			Size:  sizes[i],
   173  		}
   174  	}
   175  	return classes
   176  }
   177  
   178  type SizeClassGen struct {
   179  	wordSize       int
   180  	Classes        []SizeClass
   181  	Small          *ClassRange
   182  	Medium         *ClassRange
   183  	Large          *ClassRange
   184  	smallBoundary  int
   185  	mediumBoundary int
   186  	largeBoundary  int
   187  }
   188  
   189  func NewSizeClassGen(
   190  	wordSize int,
   191  	smallSizeDiv int,
   192  	smallSizeMax int,
   193  	mediumSizeDiv int,
   194  	mediumSizeMax int,
   195  	largeSizeDiv int,
   196  	largeSizeMax int,
   197  	classes []SizeClass) *SizeClassGen {
   198  
   199  	if smallSizeMax < 8 || smallSizeDiv < 2 {
   200  		return nil
   201  	}
   202  
   203  	s := &SizeClassGen{wordSize: wordSize, Classes: classes}
   204  	s.Small = NewClassRange("small", 0, smallSizeMax, smallSizeDiv, classes)
   205  
   206  	if mediumSizeMax > 0 && closestFit(smallSizeMax+mediumSizeDiv, classes).Size > 0 {
   207  		s.Medium = NewClassRange("medium", smallSizeMax, mediumSizeMax, mediumSizeDiv, classes)
   208  	}
   209  	if mediumSizeMax > 0 && largeSizeMax > 0 && closestFit(mediumSizeMax+largeSizeDiv, classes).Size > 0 {
   210  		s.Large = NewClassRange("large", mediumSizeMax, largeSizeMax, largeSizeDiv, classes)
   211  	}
   212  	s.smallBoundary = smallSizeMax + 1
   213  	if s.Medium != nil {
   214  		s.mediumBoundary = mediumSizeMax + 1
   215  	} else {
   216  		s.mediumBoundary = 0
   217  	}
   218  	if s.Large != nil {
   219  		s.largeBoundary = largeSizeMax + 1
   220  	} else {
   221  		s.largeBoundary = 0
   222  	}
   223  
   224  	return s
   225  }
   226  
   227  func (s *SizeClassGen) Get(size int) *SizeClass {
   228  	if size < s.smallBoundary {
   229  		return s.Small.Get(size)
   230  	} else if size < s.mediumBoundary {
   231  		return s.Medium.Get(size)
   232  	} else if size < s.largeBoundary {
   233  		return s.Large.Get(size)
   234  	}
   235  	return nil
   236  }
   237  
   238  type ClassRange struct {
   239  	Name string
   240  	Div  int
   241  	Min  int
   242  	Max  int
   243  	//Map     []int
   244  	Classes []SizeClass
   245  }
   246  
   247  func NewClassRange(name string, min, max, div int, classes []SizeClass) *ClassRange {
   248  	max = max / div * div
   249  	r := &ClassRange{
   250  		Name: name,
   251  		Min:  min,
   252  		Max:  max,
   253  		Div:  div,
   254  		//Map:     make([]int, (max-min)/div),
   255  		Classes: make([]SizeClass, (max-min)/div),
   256  	}
   257  	for index := 0; index < len(r.Classes); index++ {
   258  		size := min + (index * div)
   259  		//if size == 0 {
   260  		//	small[0] = 0
   261  		//	continue
   262  		//}
   263  		//size = divRoundUpInt(size, div)*div + min
   264  
   265  		// Find closes size
   266  		classIndex := closestFit(size, classes)
   267  		r.Classes[index] = classIndex
   268  	}
   269  	return r
   270  }
   271  
   272  func (c *ClassRange) Get(size int) *SizeClass {
   273  	index := divRoundUpInt(size-c.Min, c.Div)
   274  	return &c.Classes[index]
   275  }
   276  
   277  func (c *ClassRange) PrintSizeClassesStructInitializer() {
   278  	PrintSizeClassesStructInitializer(c.Classes)
   279  }
   280  
   281  func PrintSizeClassesStructInitializer(classes []SizeClass) {
   282  	b := strings.Builder{}
   283  	for i, cls := range classes {
   284  		if i%3 == 0 && i > 0 {
   285  			b.WriteString("\n")
   286  		}
   287  
   288  		b.WriteString("{")
   289  		b.WriteString(strconv.Itoa(cls.Index))
   290  		b.WriteString(",")
   291  		b.WriteString(strconv.Itoa(cls.Shift))
   292  		b.WriteString(",")
   293  		b.WriteString(strconv.Itoa(cls.Size))
   294  		b.WriteString("},")
   295  
   296  		//if i < 4 {
   297  		//	if i == 2 {
   298  		//		b.WriteString("\n")
   299  		//	}
   300  		//	//if i == 2 {
   301  		//	//	b.WriteString("\n")
   302  		//	//}
   303  		//} else if i%3 == 0 {
   304  		//	b.WriteString("\n")
   305  		//}
   306  	}
   307  	fmt.Println(b.String())
   308  }
   309  
   310  func (c *ClassRange) PrintClasses() {
   311  	PrintSizeClassesStructInitializer(c.Classes)
   312  }
   313  
   314  func closestFit(size int, classes []SizeClass) SizeClass {
   315  	for i := 0; i < len(classes); i++ {
   316  		cls := classes[i]
   317  		if size <= cls.Size {
   318  			return cls
   319  		}
   320  	}
   321  	return SizeClass{}
   322  }