| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | package main |
| |
|
| | import ( |
| | "bytes" |
| | "flag" |
| | "fmt" |
| | "io" |
| | "math" |
| | "math/bits" |
| | ) |
| |
|
| | |
| |
|
| | func generateSizeClasses(classes []class) []byte { |
| | flag.Parse() |
| |
|
| | var b bytes.Buffer |
| | fmt.Fprintln(&b, "// Code generated by mksizeclasses.go; DO NOT EDIT.") |
| | fmt.Fprintln(&b, "//go:generate go -C ../../../runtime/_mkmalloc run mksizeclasses.go") |
| | fmt.Fprintln(&b) |
| | fmt.Fprintln(&b, "package gc") |
| |
|
| | printComment(&b, classes) |
| |
|
| | printClasses(&b, classes) |
| |
|
| | return b.Bytes() |
| | } |
| |
|
| | type class struct { |
| | size int |
| | npages int |
| | } |
| |
|
| | func powerOfTwo(x int) bool { |
| | return x != 0 && x&(x-1) == 0 |
| | } |
| |
|
| | func makeClasses() []class { |
| | var classes []class |
| |
|
| | classes = append(classes, class{}) |
| |
|
| | align := minHeapAlign |
| | for size := align; size <= maxSmallSize; size += align { |
| | if powerOfTwo(size) { |
| | if size >= 2048 { |
| | align = 256 |
| | } else if size >= 128 { |
| | align = size / 8 |
| | } else if size >= 32 { |
| | align = 16 |
| | } |
| | } |
| | if !powerOfTwo(align) { |
| | panic("incorrect alignment") |
| | } |
| |
|
| | |
| | |
| | |
| | allocsize := pageSize |
| | for allocsize%size > allocsize/8 { |
| | allocsize += pageSize |
| | } |
| | npages := allocsize / pageSize |
| |
|
| | |
| | |
| | |
| | |
| | |
| | if len(classes) > 1 && npages == classes[len(classes)-1].npages && allocsize/size == allocsize/classes[len(classes)-1].size { |
| | classes[len(classes)-1].size = size |
| | continue |
| | } |
| | classes = append(classes, class{size: size, npages: npages}) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | for i := range classes { |
| | if i == 0 { |
| | continue |
| | } |
| | c := &classes[i] |
| | psize := c.npages * pageSize |
| | new_size := (psize / (psize / c.size)) &^ (largeSizeDiv - 1) |
| | if new_size > c.size { |
| | c.size = new_size |
| | } |
| | } |
| |
|
| | if len(classes) != 68 { |
| | panic("number of size classes has changed") |
| | } |
| |
|
| | for i := range classes { |
| | computeDivMagic(&classes[i]) |
| | } |
| |
|
| | return classes |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func computeDivMagic(c *class) { |
| | |
| | d := c.size |
| | if d == 0 { |
| | return |
| | } |
| |
|
| | |
| | max := c.npages * pageSize |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | N := bits.Len(uint(max)) |
| | var F int |
| | if powerOfTwo(d) { |
| | F = int(math.Log2(float64(d))) |
| | if d != 1<<F { |
| | panic("imprecise log2") |
| | } |
| | } else { |
| | for L := 0; ; L++ { |
| | if d <= ((1<<(N+L))%d)+(1<<L) { |
| | F = N + L |
| | break |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | if F > 32 { |
| | fmt.Printf("d=%d max=%d N=%d F=%d\n", c.size, max, N, F) |
| | panic("size class requires more than 32 bits of precision") |
| | } |
| |
|
| | |
| | |
| | m := ^uint32(0)/uint32(c.size) + 1 |
| | for n := 0; n <= max; n++ { |
| | if uint32((uint64(n)*uint64(m))>>32) != uint32(n/c.size) { |
| | fmt.Printf("d=%d max=%d m=%d n=%d\n", d, max, m, n) |
| | panic("bad 32-bit multiply magic") |
| | } |
| | } |
| | } |
| |
|
| | func printComment(w io.Writer, classes []class) { |
| | fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-10s %-9s %-9s\n", "class", "bytes/obj", "bytes/span", "objects", "tail waste", "max waste", "min align") |
| | prevSize := 0 |
| | var minAligns [pageShift + 1]int |
| | for i, c := range classes { |
| | if i == 0 { |
| | continue |
| | } |
| | spanSize := c.npages * pageSize |
| | objects := spanSize / c.size |
| | tailWaste := spanSize - c.size*(spanSize/c.size) |
| | maxWaste := float64((c.size-prevSize-1)*objects+tailWaste) / float64(spanSize) |
| | alignBits := bits.TrailingZeros(uint(c.size)) |
| | if alignBits > pageShift { |
| | |
| | alignBits = pageShift |
| | } |
| | for i := range minAligns { |
| | if i > alignBits { |
| | minAligns[i] = 0 |
| | } else if minAligns[i] == 0 { |
| | minAligns[i] = c.size |
| | } |
| | } |
| | prevSize = c.size |
| | fmt.Fprintf(w, "// %5d %9d %10d %7d %10d %8.2f%% %9d\n", i, c.size, spanSize, objects, tailWaste, 100*maxWaste, 1<<alignBits) |
| | } |
| | fmt.Fprintf(w, "\n") |
| |
|
| | fmt.Fprintf(w, "// %-9s %-4s %-12s\n", "alignment", "bits", "min obj size") |
| | for bits, size := range minAligns { |
| | if size == 0 { |
| | break |
| | } |
| | if bits+1 < len(minAligns) && size == minAligns[bits+1] { |
| | continue |
| | } |
| | fmt.Fprintf(w, "// %9d %4d %12d\n", 1<<bits, bits, size) |
| | } |
| | fmt.Fprintf(w, "\n") |
| | } |
| |
|
| | func maxObjsPerSpan(classes []class) int { |
| | most := 0 |
| | for _, c := range classes[1:] { |
| | n := c.npages * pageSize / c.size |
| | most = max(most, n) |
| | } |
| | return most |
| | } |
| |
|
| | func maxNPages(classes []class) int { |
| | most := 0 |
| | for _, c := range classes[1:] { |
| | most = max(most, c.npages) |
| | } |
| | return most |
| | } |
| |
|
| | func printClasses(w io.Writer, classes []class) { |
| | sizeToSizeClass := func(size int) int { |
| | for j, c := range classes { |
| | if c.size >= size { |
| | return j |
| | } |
| | } |
| | panic("unreachable") |
| | } |
| |
|
| | fmt.Fprintln(w, "const (") |
| | fmt.Fprintf(w, "MinHeapAlign = %d\n", minHeapAlign) |
| | fmt.Fprintf(w, "MaxSmallSize = %d\n", maxSmallSize) |
| | fmt.Fprintf(w, "SmallSizeDiv = %d\n", smallSizeDiv) |
| | fmt.Fprintf(w, "SmallSizeMax = %d\n", smallSizeMax) |
| | fmt.Fprintf(w, "LargeSizeDiv = %d\n", largeSizeDiv) |
| | fmt.Fprintf(w, "NumSizeClasses = %d\n", len(classes)) |
| | fmt.Fprintf(w, "PageShift = %d\n", pageShift) |
| | fmt.Fprintf(w, "MaxObjsPerSpan = %d\n", maxObjsPerSpan(classes)) |
| | fmt.Fprintf(w, "MaxSizeClassNPages = %d\n", maxNPages(classes)) |
| | fmt.Fprintf(w, "TinySize = %d\n", tinySize) |
| | fmt.Fprintf(w, "TinySizeClass = %d\n", sizeToSizeClass(tinySize)) |
| | fmt.Fprintln(w, ")") |
| |
|
| | fmt.Fprint(w, "var SizeClassToSize = [NumSizeClasses]uint16 {") |
| | for _, c := range classes { |
| | fmt.Fprintf(w, "%d,", c.size) |
| | } |
| | fmt.Fprintln(w, "}") |
| |
|
| | fmt.Fprint(w, "var SizeClassToNPages = [NumSizeClasses]uint8 {") |
| | for _, c := range classes { |
| | fmt.Fprintf(w, "%d,", c.npages) |
| | } |
| | fmt.Fprintln(w, "}") |
| |
|
| | fmt.Fprint(w, "var SizeClassToDivMagic = [NumSizeClasses]uint32 {") |
| | for _, c := range classes { |
| | if c.size == 0 { |
| | fmt.Fprintf(w, "0,") |
| | continue |
| | } |
| | fmt.Fprintf(w, "^uint32(0)/%d+1,", c.size) |
| | } |
| | fmt.Fprintln(w, "}") |
| |
|
| | |
| | sc := make([]int, smallSizeMax/smallSizeDiv+1) |
| | for i := range sc { |
| | size := i * smallSizeDiv |
| | sc[i] = sizeToSizeClass(size) |
| | } |
| | fmt.Fprint(w, "var SizeToSizeClass8 = [SmallSizeMax/SmallSizeDiv+1]uint8 {") |
| | for _, v := range sc { |
| | fmt.Fprintf(w, "%d,", v) |
| | } |
| | fmt.Fprintln(w, "}") |
| |
|
| | |
| | sc = make([]int, (maxSmallSize-smallSizeMax)/largeSizeDiv+1) |
| | for i := range sc { |
| | size := smallSizeMax + i*largeSizeDiv |
| | sc[i] = sizeToSizeClass(size) |
| | } |
| | fmt.Fprint(w, "var SizeToSizeClass128 = [(MaxSmallSize-SmallSizeMax)/LargeSizeDiv+1]uint8 {") |
| | for _, v := range sc { |
| | fmt.Fprintf(w, "%d,", v) |
| | } |
| | fmt.Fprintln(w, "}") |
| | } |
| |
|