Source file src/runtime/mksizeclasses.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package main
31
32 import (
33 "bytes"
34 "flag"
35 "fmt"
36 "go/format"
37 "io"
38 "io/ioutil"
39 "log"
40 "os"
41 )
42
43
44
45 var stdout = flag.Bool("stdout", false, "write to stdout instead of sizeclasses.go")
46
47 func main() {
48 flag.Parse()
49
50 var b bytes.Buffer
51 fmt.Fprintln(&b, "// Code generated by mksizeclasses.go; DO NOT EDIT.")
52 fmt.Fprintln(&b, "//go:generate go run mksizeclasses.go")
53 fmt.Fprintln(&b)
54 fmt.Fprintln(&b, "package runtime")
55 classes := makeClasses()
56
57 printComment(&b, classes)
58
59 printClasses(&b, classes)
60
61 out, err := format.Source(b.Bytes())
62 if err != nil {
63 log.Fatal(err)
64 }
65 if *stdout {
66 _, err = os.Stdout.Write(out)
67 } else {
68 err = ioutil.WriteFile("sizeclasses.go", out, 0666)
69 }
70 if err != nil {
71 log.Fatal(err)
72 }
73 }
74
75 const (
76
77 maxSmallSize = 32 << 10
78 smallSizeDiv = 8
79 smallSizeMax = 1024
80 largeSizeDiv = 128
81 pageShift = 13
82
83
84 pageSize = 1 << pageShift
85 )
86
87 type class struct {
88 size int
89 npages int
90
91 mul int
92 shift uint
93 shift2 uint
94 mask int
95 }
96
97 func powerOfTwo(x int) bool {
98 return x != 0 && x&(x-1) == 0
99 }
100
101 func makeClasses() []class {
102 var classes []class
103
104 classes = append(classes, class{})
105
106 align := 8
107 for size := align; size <= maxSmallSize; size += align {
108 if powerOfTwo(size) {
109 if size >= 2048 {
110 align = 256
111 } else if size >= 128 {
112 align = size / 8
113 } else if size >= 16 {
114 align = 16
115 }
116 }
117 if !powerOfTwo(align) {
118 panic("incorrect alignment")
119 }
120
121
122
123
124 allocsize := pageSize
125 for allocsize%size > allocsize/8 {
126 allocsize += pageSize
127 }
128 npages := allocsize / pageSize
129
130
131
132
133
134
135 if len(classes) > 1 && npages == classes[len(classes)-1].npages && allocsize/size == allocsize/classes[len(classes)-1].size {
136 classes[len(classes)-1].size = size
137 continue
138 }
139 classes = append(classes, class{size: size, npages: npages})
140 }
141
142
143
144
145
146
147
148 for i := range classes {
149 if i == 0 {
150 continue
151 }
152 c := &classes[i]
153 psize := c.npages * pageSize
154 new_size := (psize / (psize / c.size)) &^ (largeSizeDiv - 1)
155 if new_size > c.size {
156 c.size = new_size
157 }
158 }
159
160 if len(classes) != 67 {
161 panic("number of size classes has changed")
162 }
163
164 for i := range classes {
165 computeDivMagic(&classes[i])
166 }
167
168 return classes
169 }
170
171
172
173
174
175 func computeDivMagic(c *class) {
176
177 d := c.size
178 if d == 0 {
179 return
180 }
181
182
183 max := c.npages * pageSize
184
185 if powerOfTwo(d) {
186
187
188 if max >= 1<<16 {
189 panic("max too big for power of two size")
190 }
191 c.mask = 1<<16 - d
192 }
193
194
195 for d%2 == 0 {
196 c.shift++
197 d >>= 1
198 max >>= 1
199 }
200
201
202
203
204 nextk:
205 for k := uint(0); ; k++ {
206 mul := (int(1)<<k + d - 1) / d
207
208
209 for n := 0; n <= max; n++ {
210 if n*mul>>k != n/d {
211 continue nextk
212 }
213 }
214 if mul >= 1<<16 {
215 panic("mul too big")
216 }
217 if uint64(mul)*uint64(max) >= 1<<32 {
218 panic("mul*max too big")
219 }
220 c.mul = mul
221 c.shift2 = k
222 break
223 }
224
225
226 for n := 0; n <= max; n++ {
227 if n*c.mul>>c.shift2 != n/d {
228 fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
229 panic("bad multiply magic")
230 }
231
232
233 if uint32(n)*uint32(c.mul)>>uint8(c.shift2) != uint32(n/d) {
234 fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
235 panic("bad 32-bit multiply magic")
236 }
237 if uint64(n)*uint64(c.mul)>>uint8(c.shift2) != uint64(n/d) {
238 fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
239 panic("bad 64-bit multiply magic")
240 }
241 }
242 }
243
244 func printComment(w io.Writer, classes []class) {
245 fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-10s %-9s\n", "class", "bytes/obj", "bytes/span", "objects", "tail waste", "max waste")
246 prevSize := 0
247 for i, c := range classes {
248 if i == 0 {
249 continue
250 }
251 spanSize := c.npages * pageSize
252 objects := spanSize / c.size
253 tailWaste := spanSize - c.size*(spanSize/c.size)
254 maxWaste := float64((c.size-prevSize-1)*objects+tailWaste) / float64(spanSize)
255 prevSize = c.size
256 fmt.Fprintf(w, "// %5d %9d %10d %7d %10d %8.2f%%\n", i, c.size, spanSize, objects, tailWaste, 100*maxWaste)
257 }
258 fmt.Fprintf(w, "\n")
259 }
260
261 func printClasses(w io.Writer, classes []class) {
262 fmt.Fprintln(w, "const (")
263 fmt.Fprintf(w, "_MaxSmallSize = %d\n", maxSmallSize)
264 fmt.Fprintf(w, "smallSizeDiv = %d\n", smallSizeDiv)
265 fmt.Fprintf(w, "smallSizeMax = %d\n", smallSizeMax)
266 fmt.Fprintf(w, "largeSizeDiv = %d\n", largeSizeDiv)
267 fmt.Fprintf(w, "_NumSizeClasses = %d\n", len(classes))
268 fmt.Fprintf(w, "_PageShift = %d\n", pageShift)
269 fmt.Fprintln(w, ")")
270
271 fmt.Fprint(w, "var class_to_size = [_NumSizeClasses]uint16 {")
272 for _, c := range classes {
273 fmt.Fprintf(w, "%d,", c.size)
274 }
275 fmt.Fprintln(w, "}")
276
277 fmt.Fprint(w, "var class_to_allocnpages = [_NumSizeClasses]uint8 {")
278 for _, c := range classes {
279 fmt.Fprintf(w, "%d,", c.npages)
280 }
281 fmt.Fprintln(w, "}")
282
283 fmt.Fprintln(w, "type divMagic struct {")
284 fmt.Fprintln(w, " shift uint8")
285 fmt.Fprintln(w, " shift2 uint8")
286 fmt.Fprintln(w, " mul uint16")
287 fmt.Fprintln(w, " baseMask uint16")
288 fmt.Fprintln(w, "}")
289 fmt.Fprint(w, "var class_to_divmagic = [_NumSizeClasses]divMagic {")
290 for _, c := range classes {
291 fmt.Fprintf(w, "{%d,%d,%d,%d},", c.shift, c.shift2, c.mul, c.mask)
292 }
293 fmt.Fprintln(w, "}")
294
295
296 sc := make([]int, smallSizeMax/smallSizeDiv+1)
297 for i := range sc {
298 size := i * smallSizeDiv
299 for j, c := range classes {
300 if c.size >= size {
301 sc[i] = j
302 break
303 }
304 }
305 }
306 fmt.Fprint(w, "var size_to_class8 = [smallSizeMax/smallSizeDiv+1]uint8 {")
307 for _, v := range sc {
308 fmt.Fprintf(w, "%d,", v)
309 }
310 fmt.Fprintln(w, "}")
311
312
313 sc = make([]int, (maxSmallSize-smallSizeMax)/largeSizeDiv+1)
314 for i := range sc {
315 size := smallSizeMax + i*largeSizeDiv
316 for j, c := range classes {
317 if c.size >= size {
318 sc[i] = j
319 break
320 }
321 }
322 }
323 fmt.Fprint(w, "var size_to_class128 = [(_MaxSmallSize-smallSizeMax)/largeSizeDiv+1]uint8 {")
324 for _, v := range sc {
325 fmt.Fprintf(w, "%d,", v)
326 }
327 fmt.Fprintln(w, "}")
328 }
329
View as plain text