Source file
src/runtime/mpagealloc_test.go
Documentation: runtime
1
2
3
4
5 package runtime_test
6
7 import (
8 "fmt"
9 . "runtime"
10 "testing"
11 )
12
13 func checkPageAlloc(t *testing.T, want, got *PageAlloc) {
14
15 wantStart, wantEnd := want.Bounds()
16 gotStart, gotEnd := got.Bounds()
17 if gotStart != wantStart {
18 t.Fatalf("start values not equal: got %d, want %d", gotStart, wantStart)
19 }
20 if gotEnd != wantEnd {
21 t.Fatalf("end values not equal: got %d, want %d", gotEnd, wantEnd)
22 }
23
24 for i := gotStart; i < gotEnd; i++ {
25
26 gb, wb := got.PallocData(i), want.PallocData(i)
27 if gb == nil && wb == nil {
28 continue
29 }
30 if (gb == nil && wb != nil) || (gb != nil && wb == nil) {
31 t.Errorf("chunk %d nilness mismatch", i)
32 }
33 if !checkPallocBits(t, gb.PallocBits(), wb.PallocBits()) {
34 t.Logf("in chunk %d (mallocBits)", i)
35 }
36 if !checkPallocBits(t, gb.Scavenged(), wb.Scavenged()) {
37 t.Logf("in chunk %d (scavenged)", i)
38 }
39 }
40
41 }
42
43 func TestPageAllocGrow(t *testing.T) {
44 if GOOS == "openbsd" && testing.Short() {
45 t.Skip("skipping because virtual memory is limited; see #36210")
46 }
47 type test struct {
48 chunks []ChunkIdx
49 inUse []AddrRange
50 }
51 tests := map[string]test{
52 "One": {
53 chunks: []ChunkIdx{
54 BaseChunkIdx,
55 },
56 inUse: []AddrRange{
57 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+1, 0)),
58 },
59 },
60 "Contiguous2": {
61 chunks: []ChunkIdx{
62 BaseChunkIdx,
63 BaseChunkIdx + 1,
64 },
65 inUse: []AddrRange{
66 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+2, 0)),
67 },
68 },
69 "Contiguous5": {
70 chunks: []ChunkIdx{
71 BaseChunkIdx,
72 BaseChunkIdx + 1,
73 BaseChunkIdx + 2,
74 BaseChunkIdx + 3,
75 BaseChunkIdx + 4,
76 },
77 inUse: []AddrRange{
78 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+5, 0)),
79 },
80 },
81 "Discontiguous": {
82 chunks: []ChunkIdx{
83 BaseChunkIdx,
84 BaseChunkIdx + 2,
85 BaseChunkIdx + 4,
86 },
87 inUse: []AddrRange{
88 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+1, 0)),
89 MakeAddrRange(PageBase(BaseChunkIdx+2, 0), PageBase(BaseChunkIdx+3, 0)),
90 MakeAddrRange(PageBase(BaseChunkIdx+4, 0), PageBase(BaseChunkIdx+5, 0)),
91 },
92 },
93 "Mixed": {
94 chunks: []ChunkIdx{
95 BaseChunkIdx,
96 BaseChunkIdx + 1,
97 BaseChunkIdx + 2,
98 BaseChunkIdx + 4,
99 },
100 inUse: []AddrRange{
101 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+3, 0)),
102 MakeAddrRange(PageBase(BaseChunkIdx+4, 0), PageBase(BaseChunkIdx+5, 0)),
103 },
104 },
105 "WildlyDiscontiguous": {
106 chunks: []ChunkIdx{
107 BaseChunkIdx,
108 BaseChunkIdx + 1,
109 BaseChunkIdx + 0x10,
110 BaseChunkIdx + 0x21,
111 },
112 inUse: []AddrRange{
113 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+2, 0)),
114 MakeAddrRange(PageBase(BaseChunkIdx+0x10, 0), PageBase(BaseChunkIdx+0x11, 0)),
115 MakeAddrRange(PageBase(BaseChunkIdx+0x21, 0), PageBase(BaseChunkIdx+0x22, 0)),
116 },
117 },
118 "ManyDiscontiguous": {
119
120 chunks: []ChunkIdx{
121 BaseChunkIdx, BaseChunkIdx + 2, BaseChunkIdx + 4, BaseChunkIdx + 6,
122 BaseChunkIdx + 8, BaseChunkIdx + 10, BaseChunkIdx + 12, BaseChunkIdx + 14,
123 BaseChunkIdx + 16, BaseChunkIdx + 18, BaseChunkIdx + 20, BaseChunkIdx + 22,
124 BaseChunkIdx + 24, BaseChunkIdx + 26, BaseChunkIdx + 28, BaseChunkIdx + 30,
125 BaseChunkIdx + 32, BaseChunkIdx + 34, BaseChunkIdx + 36, BaseChunkIdx + 38,
126 BaseChunkIdx + 40, BaseChunkIdx + 42, BaseChunkIdx + 44, BaseChunkIdx + 46,
127 BaseChunkIdx + 48, BaseChunkIdx + 50, BaseChunkIdx + 52, BaseChunkIdx + 54,
128 BaseChunkIdx + 56, BaseChunkIdx + 58, BaseChunkIdx + 60, BaseChunkIdx + 62,
129 BaseChunkIdx + 64,
130 },
131 inUse: []AddrRange{
132 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+1, 0)),
133 MakeAddrRange(PageBase(BaseChunkIdx+2, 0), PageBase(BaseChunkIdx+3, 0)),
134 MakeAddrRange(PageBase(BaseChunkIdx+4, 0), PageBase(BaseChunkIdx+5, 0)),
135 MakeAddrRange(PageBase(BaseChunkIdx+6, 0), PageBase(BaseChunkIdx+7, 0)),
136 MakeAddrRange(PageBase(BaseChunkIdx+8, 0), PageBase(BaseChunkIdx+9, 0)),
137 MakeAddrRange(PageBase(BaseChunkIdx+10, 0), PageBase(BaseChunkIdx+11, 0)),
138 MakeAddrRange(PageBase(BaseChunkIdx+12, 0), PageBase(BaseChunkIdx+13, 0)),
139 MakeAddrRange(PageBase(BaseChunkIdx+14, 0), PageBase(BaseChunkIdx+15, 0)),
140 MakeAddrRange(PageBase(BaseChunkIdx+16, 0), PageBase(BaseChunkIdx+17, 0)),
141 MakeAddrRange(PageBase(BaseChunkIdx+18, 0), PageBase(BaseChunkIdx+19, 0)),
142 MakeAddrRange(PageBase(BaseChunkIdx+20, 0), PageBase(BaseChunkIdx+21, 0)),
143 MakeAddrRange(PageBase(BaseChunkIdx+22, 0), PageBase(BaseChunkIdx+23, 0)),
144 MakeAddrRange(PageBase(BaseChunkIdx+24, 0), PageBase(BaseChunkIdx+25, 0)),
145 MakeAddrRange(PageBase(BaseChunkIdx+26, 0), PageBase(BaseChunkIdx+27, 0)),
146 MakeAddrRange(PageBase(BaseChunkIdx+28, 0), PageBase(BaseChunkIdx+29, 0)),
147 MakeAddrRange(PageBase(BaseChunkIdx+30, 0), PageBase(BaseChunkIdx+31, 0)),
148 MakeAddrRange(PageBase(BaseChunkIdx+32, 0), PageBase(BaseChunkIdx+33, 0)),
149 MakeAddrRange(PageBase(BaseChunkIdx+34, 0), PageBase(BaseChunkIdx+35, 0)),
150 MakeAddrRange(PageBase(BaseChunkIdx+36, 0), PageBase(BaseChunkIdx+37, 0)),
151 MakeAddrRange(PageBase(BaseChunkIdx+38, 0), PageBase(BaseChunkIdx+39, 0)),
152 MakeAddrRange(PageBase(BaseChunkIdx+40, 0), PageBase(BaseChunkIdx+41, 0)),
153 MakeAddrRange(PageBase(BaseChunkIdx+42, 0), PageBase(BaseChunkIdx+43, 0)),
154 MakeAddrRange(PageBase(BaseChunkIdx+44, 0), PageBase(BaseChunkIdx+45, 0)),
155 MakeAddrRange(PageBase(BaseChunkIdx+46, 0), PageBase(BaseChunkIdx+47, 0)),
156 MakeAddrRange(PageBase(BaseChunkIdx+48, 0), PageBase(BaseChunkIdx+49, 0)),
157 MakeAddrRange(PageBase(BaseChunkIdx+50, 0), PageBase(BaseChunkIdx+51, 0)),
158 MakeAddrRange(PageBase(BaseChunkIdx+52, 0), PageBase(BaseChunkIdx+53, 0)),
159 MakeAddrRange(PageBase(BaseChunkIdx+54, 0), PageBase(BaseChunkIdx+55, 0)),
160 MakeAddrRange(PageBase(BaseChunkIdx+56, 0), PageBase(BaseChunkIdx+57, 0)),
161 MakeAddrRange(PageBase(BaseChunkIdx+58, 0), PageBase(BaseChunkIdx+59, 0)),
162 MakeAddrRange(PageBase(BaseChunkIdx+60, 0), PageBase(BaseChunkIdx+61, 0)),
163 MakeAddrRange(PageBase(BaseChunkIdx+62, 0), PageBase(BaseChunkIdx+63, 0)),
164 MakeAddrRange(PageBase(BaseChunkIdx+64, 0), PageBase(BaseChunkIdx+65, 0)),
165 },
166 },
167 }
168 if PageAlloc64Bit != 0 {
169 tests["ExtremelyDiscontiguous"] = test{
170 chunks: []ChunkIdx{
171 BaseChunkIdx,
172 BaseChunkIdx + 0x100000,
173 },
174 inUse: []AddrRange{
175 MakeAddrRange(PageBase(BaseChunkIdx, 0), PageBase(BaseChunkIdx+1, 0)),
176 MakeAddrRange(PageBase(BaseChunkIdx+0x100000, 0), PageBase(BaseChunkIdx+0x100001, 0)),
177 },
178 }
179 }
180 for name, v := range tests {
181 v := v
182 t.Run(name, func(t *testing.T) {
183
184
185 x := make(map[ChunkIdx][]BitRange)
186 for _, c := range v.chunks {
187 x[c] = []BitRange{}
188 }
189 b := NewPageAlloc(x, nil)
190 defer FreePageAlloc(b)
191
192 got := b.InUse()
193 want := v.inUse
194
195
196 if len(got) != len(want) {
197 t.Fail()
198 } else {
199 for i := range want {
200 if !want[i].Equals(got[i]) {
201 t.Fail()
202 break
203 }
204 }
205 }
206 if t.Failed() {
207 t.Logf("found inUse mismatch")
208 t.Logf("got:")
209 for i, r := range got {
210 t.Logf("\t#%d [0x%x, 0x%x)", i, r.Base(), r.Limit())
211 }
212 t.Logf("want:")
213 for i, r := range want {
214 t.Logf("\t#%d [0x%x, 0x%x)", i, r.Base(), r.Limit())
215 }
216 }
217 })
218 }
219 }
220
221 func TestPageAllocAlloc(t *testing.T) {
222 if GOOS == "openbsd" && testing.Short() {
223 t.Skip("skipping because virtual memory is limited; see #36210")
224 }
225 type hit struct {
226 npages, base, scav uintptr
227 }
228 type test struct {
229 scav map[ChunkIdx][]BitRange
230 before map[ChunkIdx][]BitRange
231 after map[ChunkIdx][]BitRange
232 hits []hit
233 }
234 tests := map[string]test{
235 "AllFree1": {
236 before: map[ChunkIdx][]BitRange{
237 BaseChunkIdx: {},
238 },
239 scav: map[ChunkIdx][]BitRange{
240 BaseChunkIdx: {{0, 1}, {2, 2}},
241 },
242 hits: []hit{
243 {1, PageBase(BaseChunkIdx, 0), PageSize},
244 {1, PageBase(BaseChunkIdx, 1), 0},
245 {1, PageBase(BaseChunkIdx, 2), PageSize},
246 {1, PageBase(BaseChunkIdx, 3), PageSize},
247 {1, PageBase(BaseChunkIdx, 4), 0},
248 },
249 after: map[ChunkIdx][]BitRange{
250 BaseChunkIdx: {{0, 5}},
251 },
252 },
253 "ManyArena1": {
254 before: map[ChunkIdx][]BitRange{
255 BaseChunkIdx: {{0, PallocChunkPages}},
256 BaseChunkIdx + 1: {{0, PallocChunkPages}},
257 BaseChunkIdx + 2: {{0, PallocChunkPages - 1}},
258 },
259 scav: map[ChunkIdx][]BitRange{
260 BaseChunkIdx: {{0, PallocChunkPages}},
261 BaseChunkIdx + 1: {{0, PallocChunkPages}},
262 BaseChunkIdx + 2: {{0, PallocChunkPages}},
263 },
264 hits: []hit{
265 {1, PageBase(BaseChunkIdx+2, PallocChunkPages-1), PageSize},
266 },
267 after: map[ChunkIdx][]BitRange{
268 BaseChunkIdx: {{0, PallocChunkPages}},
269 BaseChunkIdx + 1: {{0, PallocChunkPages}},
270 BaseChunkIdx + 2: {{0, PallocChunkPages}},
271 },
272 },
273 "NotContiguous1": {
274 before: map[ChunkIdx][]BitRange{
275 BaseChunkIdx: {{0, PallocChunkPages}},
276 BaseChunkIdx + 0xff: {{0, 0}},
277 },
278 scav: map[ChunkIdx][]BitRange{
279 BaseChunkIdx: {{0, PallocChunkPages}},
280 BaseChunkIdx + 0xff: {{0, PallocChunkPages}},
281 },
282 hits: []hit{
283 {1, PageBase(BaseChunkIdx+0xff, 0), PageSize},
284 },
285 after: map[ChunkIdx][]BitRange{
286 BaseChunkIdx: {{0, PallocChunkPages}},
287 BaseChunkIdx + 0xff: {{0, 1}},
288 },
289 },
290 "AllFree2": {
291 before: map[ChunkIdx][]BitRange{
292 BaseChunkIdx: {},
293 },
294 scav: map[ChunkIdx][]BitRange{
295 BaseChunkIdx: {{0, 3}, {7, 1}},
296 },
297 hits: []hit{
298 {2, PageBase(BaseChunkIdx, 0), 2 * PageSize},
299 {2, PageBase(BaseChunkIdx, 2), PageSize},
300 {2, PageBase(BaseChunkIdx, 4), 0},
301 {2, PageBase(BaseChunkIdx, 6), PageSize},
302 {2, PageBase(BaseChunkIdx, 8), 0},
303 },
304 after: map[ChunkIdx][]BitRange{
305 BaseChunkIdx: {{0, 10}},
306 },
307 },
308 "Straddle2": {
309 before: map[ChunkIdx][]BitRange{
310 BaseChunkIdx: {{0, PallocChunkPages - 1}},
311 BaseChunkIdx + 1: {{1, PallocChunkPages - 1}},
312 },
313 scav: map[ChunkIdx][]BitRange{
314 BaseChunkIdx: {{PallocChunkPages - 1, 1}},
315 BaseChunkIdx + 1: {},
316 },
317 hits: []hit{
318 {2, PageBase(BaseChunkIdx, PallocChunkPages-1), PageSize},
319 },
320 after: map[ChunkIdx][]BitRange{
321 BaseChunkIdx: {{0, PallocChunkPages}},
322 BaseChunkIdx + 1: {{0, PallocChunkPages}},
323 },
324 },
325 "AllFree5": {
326 before: map[ChunkIdx][]BitRange{
327 BaseChunkIdx: {},
328 },
329 scav: map[ChunkIdx][]BitRange{
330 BaseChunkIdx: {{0, 8}, {9, 1}, {17, 5}},
331 },
332 hits: []hit{
333 {5, PageBase(BaseChunkIdx, 0), 5 * PageSize},
334 {5, PageBase(BaseChunkIdx, 5), 4 * PageSize},
335 {5, PageBase(BaseChunkIdx, 10), 0},
336 {5, PageBase(BaseChunkIdx, 15), 3 * PageSize},
337 {5, PageBase(BaseChunkIdx, 20), 2 * PageSize},
338 },
339 after: map[ChunkIdx][]BitRange{
340 BaseChunkIdx: {{0, 25}},
341 },
342 },
343 "AllFree64": {
344 before: map[ChunkIdx][]BitRange{
345 BaseChunkIdx: {},
346 },
347 scav: map[ChunkIdx][]BitRange{
348 BaseChunkIdx: {{21, 1}, {63, 65}},
349 },
350 hits: []hit{
351 {64, PageBase(BaseChunkIdx, 0), 2 * PageSize},
352 {64, PageBase(BaseChunkIdx, 64), 64 * PageSize},
353 {64, PageBase(BaseChunkIdx, 128), 0},
354 },
355 after: map[ChunkIdx][]BitRange{
356 BaseChunkIdx: {{0, 192}},
357 },
358 },
359 "AllFree65": {
360 before: map[ChunkIdx][]BitRange{
361 BaseChunkIdx: {},
362 },
363 scav: map[ChunkIdx][]BitRange{
364 BaseChunkIdx: {{129, 1}},
365 },
366 hits: []hit{
367 {65, PageBase(BaseChunkIdx, 0), 0},
368 {65, PageBase(BaseChunkIdx, 65), PageSize},
369 {65, PageBase(BaseChunkIdx, 130), 0},
370 },
371 after: map[ChunkIdx][]BitRange{
372 BaseChunkIdx: {{0, 195}},
373 },
374 },
375 "ExhaustPallocChunkPages-3": {
376 before: map[ChunkIdx][]BitRange{
377 BaseChunkIdx: {},
378 },
379 scav: map[ChunkIdx][]BitRange{
380 BaseChunkIdx: {{10, 1}},
381 },
382 hits: []hit{
383 {PallocChunkPages - 3, PageBase(BaseChunkIdx, 0), PageSize},
384 {PallocChunkPages - 3, 0, 0},
385 {1, PageBase(BaseChunkIdx, PallocChunkPages-3), 0},
386 {2, PageBase(BaseChunkIdx, PallocChunkPages-2), 0},
387 {1, 0, 0},
388 {PallocChunkPages - 3, 0, 0},
389 },
390 after: map[ChunkIdx][]BitRange{
391 BaseChunkIdx: {{0, PallocChunkPages}},
392 },
393 },
394 "AllFreePallocChunkPages": {
395 before: map[ChunkIdx][]BitRange{
396 BaseChunkIdx: {},
397 },
398 scav: map[ChunkIdx][]BitRange{
399 BaseChunkIdx: {{0, 1}, {PallocChunkPages - 1, 1}},
400 },
401 hits: []hit{
402 {PallocChunkPages, PageBase(BaseChunkIdx, 0), 2 * PageSize},
403 {PallocChunkPages, 0, 0},
404 {1, 0, 0},
405 },
406 after: map[ChunkIdx][]BitRange{
407 BaseChunkIdx: {{0, PallocChunkPages}},
408 },
409 },
410 "StraddlePallocChunkPages": {
411 before: map[ChunkIdx][]BitRange{
412 BaseChunkIdx: {{0, PallocChunkPages / 2}},
413 BaseChunkIdx + 1: {{PallocChunkPages / 2, PallocChunkPages / 2}},
414 },
415 scav: map[ChunkIdx][]BitRange{
416 BaseChunkIdx: {},
417 BaseChunkIdx + 1: {{3, 100}},
418 },
419 hits: []hit{
420 {PallocChunkPages, PageBase(BaseChunkIdx, PallocChunkPages/2), 100 * PageSize},
421 {PallocChunkPages, 0, 0},
422 {1, 0, 0},
423 },
424 after: map[ChunkIdx][]BitRange{
425 BaseChunkIdx: {{0, PallocChunkPages}},
426 BaseChunkIdx + 1: {{0, PallocChunkPages}},
427 },
428 },
429 "StraddlePallocChunkPages+1": {
430 before: map[ChunkIdx][]BitRange{
431 BaseChunkIdx: {{0, PallocChunkPages / 2}},
432 BaseChunkIdx + 1: {},
433 },
434 scav: map[ChunkIdx][]BitRange{
435 BaseChunkIdx: {{0, PallocChunkPages}},
436 BaseChunkIdx + 1: {{0, PallocChunkPages}},
437 },
438 hits: []hit{
439 {PallocChunkPages + 1, PageBase(BaseChunkIdx, PallocChunkPages/2), (PallocChunkPages + 1) * PageSize},
440 {PallocChunkPages, 0, 0},
441 {1, PageBase(BaseChunkIdx+1, PallocChunkPages/2+1), PageSize},
442 },
443 after: map[ChunkIdx][]BitRange{
444 BaseChunkIdx: {{0, PallocChunkPages}},
445 BaseChunkIdx + 1: {{0, PallocChunkPages/2 + 2}},
446 },
447 },
448 "AllFreePallocChunkPages*2": {
449 before: map[ChunkIdx][]BitRange{
450 BaseChunkIdx: {},
451 BaseChunkIdx + 1: {},
452 },
453 scav: map[ChunkIdx][]BitRange{
454 BaseChunkIdx: {},
455 BaseChunkIdx + 1: {},
456 },
457 hits: []hit{
458 {PallocChunkPages * 2, PageBase(BaseChunkIdx, 0), 0},
459 {PallocChunkPages * 2, 0, 0},
460 {1, 0, 0},
461 },
462 after: map[ChunkIdx][]BitRange{
463 BaseChunkIdx: {{0, PallocChunkPages}},
464 BaseChunkIdx + 1: {{0, PallocChunkPages}},
465 },
466 },
467 "NotContiguousPallocChunkPages*2": {
468 before: map[ChunkIdx][]BitRange{
469 BaseChunkIdx: {},
470 BaseChunkIdx + 0x40: {},
471 BaseChunkIdx + 0x41: {},
472 },
473 scav: map[ChunkIdx][]BitRange{
474 BaseChunkIdx: {{0, PallocChunkPages}},
475 BaseChunkIdx + 0x40: {},
476 BaseChunkIdx + 0x41: {},
477 },
478 hits: []hit{
479 {PallocChunkPages * 2, PageBase(BaseChunkIdx+0x40, 0), 0},
480 {21, PageBase(BaseChunkIdx, 0), 21 * PageSize},
481 {1, PageBase(BaseChunkIdx, 21), PageSize},
482 },
483 after: map[ChunkIdx][]BitRange{
484 BaseChunkIdx: {{0, 22}},
485 BaseChunkIdx + 0x40: {{0, PallocChunkPages}},
486 BaseChunkIdx + 0x41: {{0, PallocChunkPages}},
487 },
488 },
489 "StraddlePallocChunkPages*2": {
490 before: map[ChunkIdx][]BitRange{
491 BaseChunkIdx: {{0, PallocChunkPages / 2}},
492 BaseChunkIdx + 1: {},
493 BaseChunkIdx + 2: {{PallocChunkPages / 2, PallocChunkPages / 2}},
494 },
495 scav: map[ChunkIdx][]BitRange{
496 BaseChunkIdx: {{0, 7}},
497 BaseChunkIdx + 1: {{3, 5}, {121, 10}},
498 BaseChunkIdx + 2: {{PallocChunkPages/2 + 12, 2}},
499 },
500 hits: []hit{
501 {PallocChunkPages * 2, PageBase(BaseChunkIdx, PallocChunkPages/2), 15 * PageSize},
502 {PallocChunkPages * 2, 0, 0},
503 {1, 0, 0},
504 },
505 after: map[ChunkIdx][]BitRange{
506 BaseChunkIdx: {{0, PallocChunkPages}},
507 BaseChunkIdx + 1: {{0, PallocChunkPages}},
508 BaseChunkIdx + 2: {{0, PallocChunkPages}},
509 },
510 },
511 "StraddlePallocChunkPages*5/4": {
512 before: map[ChunkIdx][]BitRange{
513 BaseChunkIdx: {{0, PallocChunkPages}},
514 BaseChunkIdx + 1: {{0, PallocChunkPages * 3 / 4}},
515 BaseChunkIdx + 2: {{0, PallocChunkPages * 3 / 4}},
516 BaseChunkIdx + 3: {{0, 0}},
517 },
518 scav: map[ChunkIdx][]BitRange{
519 BaseChunkIdx: {{0, PallocChunkPages}},
520 BaseChunkIdx + 1: {{PallocChunkPages / 2, PallocChunkPages/4 + 1}},
521 BaseChunkIdx + 2: {{PallocChunkPages / 3, 1}},
522 BaseChunkIdx + 3: {{PallocChunkPages * 2 / 3, 1}},
523 },
524 hits: []hit{
525 {PallocChunkPages * 5 / 4, PageBase(BaseChunkIdx+2, PallocChunkPages*3/4), PageSize},
526 {PallocChunkPages * 5 / 4, 0, 0},
527 {1, PageBase(BaseChunkIdx+1, PallocChunkPages*3/4), PageSize},
528 },
529 after: map[ChunkIdx][]BitRange{
530 BaseChunkIdx: {{0, PallocChunkPages}},
531 BaseChunkIdx + 1: {{0, PallocChunkPages*3/4 + 1}},
532 BaseChunkIdx + 2: {{0, PallocChunkPages}},
533 BaseChunkIdx + 3: {{0, PallocChunkPages}},
534 },
535 },
536 "AllFreePallocChunkPages*7+5": {
537 before: map[ChunkIdx][]BitRange{
538 BaseChunkIdx: {},
539 BaseChunkIdx + 1: {},
540 BaseChunkIdx + 2: {},
541 BaseChunkIdx + 3: {},
542 BaseChunkIdx + 4: {},
543 BaseChunkIdx + 5: {},
544 BaseChunkIdx + 6: {},
545 BaseChunkIdx + 7: {},
546 },
547 scav: map[ChunkIdx][]BitRange{
548 BaseChunkIdx: {{50, 1}},
549 BaseChunkIdx + 1: {{31, 1}},
550 BaseChunkIdx + 2: {{7, 1}},
551 BaseChunkIdx + 3: {{200, 1}},
552 BaseChunkIdx + 4: {{3, 1}},
553 BaseChunkIdx + 5: {{51, 1}},
554 BaseChunkIdx + 6: {{20, 1}},
555 BaseChunkIdx + 7: {{1, 1}},
556 },
557 hits: []hit{
558 {PallocChunkPages*7 + 5, PageBase(BaseChunkIdx, 0), 8 * PageSize},
559 {PallocChunkPages*7 + 5, 0, 0},
560 {1, PageBase(BaseChunkIdx+7, 5), 0},
561 },
562 after: map[ChunkIdx][]BitRange{
563 BaseChunkIdx: {{0, PallocChunkPages}},
564 BaseChunkIdx + 1: {{0, PallocChunkPages}},
565 BaseChunkIdx + 2: {{0, PallocChunkPages}},
566 BaseChunkIdx + 3: {{0, PallocChunkPages}},
567 BaseChunkIdx + 4: {{0, PallocChunkPages}},
568 BaseChunkIdx + 5: {{0, PallocChunkPages}},
569 BaseChunkIdx + 6: {{0, PallocChunkPages}},
570 BaseChunkIdx + 7: {{0, 6}},
571 },
572 },
573 }
574 if PageAlloc64Bit != 0 {
575 const chunkIdxBigJump = 0x100000
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592 sumsPerPhysPage := ChunkIdx(PhysPageSize / PallocSumBytes)
593 baseChunkIdx := BaseChunkIdx &^ (sumsPerPhysPage - 1)
594 tests["DiscontiguousMappedSumBoundary"] = test{
595 before: map[ChunkIdx][]BitRange{
596 baseChunkIdx + sumsPerPhysPage - 1: {},
597 baseChunkIdx + chunkIdxBigJump: {},
598 },
599 scav: map[ChunkIdx][]BitRange{
600 baseChunkIdx + sumsPerPhysPage - 1: {},
601 baseChunkIdx + chunkIdxBigJump: {},
602 },
603 hits: []hit{
604 {PallocChunkPages - 1, PageBase(baseChunkIdx+sumsPerPhysPage-1, 0), 0},
605 {1, PageBase(baseChunkIdx+sumsPerPhysPage-1, PallocChunkPages-1), 0},
606 {1, PageBase(baseChunkIdx+chunkIdxBigJump, 0), 0},
607 {PallocChunkPages - 1, PageBase(baseChunkIdx+chunkIdxBigJump, 1), 0},
608 {1, 0, 0},
609 },
610 after: map[ChunkIdx][]BitRange{
611 baseChunkIdx + sumsPerPhysPage - 1: {{0, PallocChunkPages}},
612 baseChunkIdx + chunkIdxBigJump: {{0, PallocChunkPages}},
613 },
614 }
615
616
617
618
619
620
621
622
623 const chunkIdxSmallOffset = 0x503
624 tests["DiscontiguousBadSearchAddr"] = test{
625 before: map[ChunkIdx][]BitRange{
626
627
628
629
630
631
632
633
634
635 BaseChunkIdx + chunkIdxBigJump*0: {{0, PallocChunkPages - 1}},
636 BaseChunkIdx + chunkIdxBigJump*1 + chunkIdxSmallOffset: {
637 {0, PallocChunkPages - 10},
638 {PallocChunkPages - 1, 1},
639 },
640 BaseChunkIdx + chunkIdxBigJump*2: {},
641 },
642 scav: map[ChunkIdx][]BitRange{
643 BaseChunkIdx + chunkIdxBigJump*0: {},
644 BaseChunkIdx + chunkIdxBigJump*1 + chunkIdxSmallOffset: {},
645 BaseChunkIdx + chunkIdxBigJump*2: {},
646 },
647 hits: []hit{
648
649
650 {1, PageBase(BaseChunkIdx, PallocChunkPages-1), 0},
651
652
653
654
655
656
657
658 {100, PageBase(baseChunkIdx+chunkIdxBigJump*2, 0), 0},
659
660
661
662
663
664 {9, PageBase(baseChunkIdx+chunkIdxBigJump*1+chunkIdxSmallOffset, PallocChunkPages-10), 0},
665 },
666 after: map[ChunkIdx][]BitRange{
667 BaseChunkIdx + chunkIdxBigJump*0: {{0, PallocChunkPages}},
668 BaseChunkIdx + chunkIdxBigJump*1 + chunkIdxSmallOffset: {{0, PallocChunkPages}},
669 BaseChunkIdx + chunkIdxBigJump*2: {{0, 100}},
670 },
671 }
672 }
673 for name, v := range tests {
674 v := v
675 t.Run(name, func(t *testing.T) {
676 b := NewPageAlloc(v.before, v.scav)
677 defer FreePageAlloc(b)
678
679 for iter, i := range v.hits {
680 a, s := b.Alloc(i.npages)
681 if a != i.base {
682 t.Fatalf("bad alloc #%d: want base 0x%x, got 0x%x", iter+1, i.base, a)
683 }
684 if s != i.scav {
685 t.Fatalf("bad alloc #%d: want scav %d, got %d", iter+1, i.scav, s)
686 }
687 }
688 want := NewPageAlloc(v.after, v.scav)
689 defer FreePageAlloc(want)
690
691 checkPageAlloc(t, want, b)
692 })
693 }
694 }
695
696 func TestPageAllocExhaust(t *testing.T) {
697 if GOOS == "openbsd" && testing.Short() {
698 t.Skip("skipping because virtual memory is limited; see #36210")
699 }
700 for _, npages := range []uintptr{1, 2, 3, 4, 5, 8, 16, 64, 1024, 1025, 2048, 2049} {
701 npages := npages
702 t.Run(fmt.Sprintf("%d", npages), func(t *testing.T) {
703
704 bDesc := make(map[ChunkIdx][]BitRange)
705 for i := ChunkIdx(0); i < 4; i++ {
706 bDesc[BaseChunkIdx+i] = []BitRange{}
707 }
708 b := NewPageAlloc(bDesc, nil)
709 defer FreePageAlloc(b)
710
711
712 nAlloc := (PallocChunkPages * 4) / int(npages)
713 for i := 0; i < nAlloc; i++ {
714 addr := PageBase(BaseChunkIdx, uint(i)*uint(npages))
715 if a, _ := b.Alloc(npages); a != addr {
716 t.Fatalf("bad alloc #%d: want 0x%x, got 0x%x", i+1, addr, a)
717 }
718 }
719
720
721 if a, _ := b.Alloc(npages); a != 0 {
722 t.Fatalf("bad alloc #%d: want 0, got 0x%x", nAlloc, a)
723 }
724
725
726 allocPages := nAlloc * int(npages)
727 wantDesc := make(map[ChunkIdx][]BitRange)
728 for i := ChunkIdx(0); i < 4; i++ {
729 if allocPages >= PallocChunkPages {
730 wantDesc[BaseChunkIdx+i] = []BitRange{{0, PallocChunkPages}}
731 allocPages -= PallocChunkPages
732 } else if allocPages > 0 {
733 wantDesc[BaseChunkIdx+i] = []BitRange{{0, uint(allocPages)}}
734 allocPages = 0
735 } else {
736 wantDesc[BaseChunkIdx+i] = []BitRange{}
737 }
738 }
739 want := NewPageAlloc(wantDesc, nil)
740 defer FreePageAlloc(want)
741
742
743 checkPageAlloc(t, want, b)
744 })
745 }
746 }
747
748 func TestPageAllocFree(t *testing.T) {
749 if GOOS == "openbsd" && testing.Short() {
750 t.Skip("skipping because virtual memory is limited; see #36210")
751 }
752 tests := map[string]struct {
753 before map[ChunkIdx][]BitRange
754 after map[ChunkIdx][]BitRange
755 npages uintptr
756 frees []uintptr
757 }{
758 "Free1": {
759 npages: 1,
760 before: map[ChunkIdx][]BitRange{
761 BaseChunkIdx: {{0, PallocChunkPages}},
762 },
763 frees: []uintptr{
764 PageBase(BaseChunkIdx, 0),
765 PageBase(BaseChunkIdx, 1),
766 PageBase(BaseChunkIdx, 2),
767 PageBase(BaseChunkIdx, 3),
768 PageBase(BaseChunkIdx, 4),
769 },
770 after: map[ChunkIdx][]BitRange{
771 BaseChunkIdx: {{5, PallocChunkPages - 5}},
772 },
773 },
774 "ManyArena1": {
775 npages: 1,
776 before: map[ChunkIdx][]BitRange{
777 BaseChunkIdx: {{0, PallocChunkPages}},
778 BaseChunkIdx + 1: {{0, PallocChunkPages}},
779 BaseChunkIdx + 2: {{0, PallocChunkPages}},
780 },
781 frees: []uintptr{
782 PageBase(BaseChunkIdx, PallocChunkPages/2),
783 PageBase(BaseChunkIdx+1, 0),
784 PageBase(BaseChunkIdx+2, PallocChunkPages-1),
785 },
786 after: map[ChunkIdx][]BitRange{
787 BaseChunkIdx: {{0, PallocChunkPages / 2}, {PallocChunkPages/2 + 1, PallocChunkPages/2 - 1}},
788 BaseChunkIdx + 1: {{1, PallocChunkPages - 1}},
789 BaseChunkIdx + 2: {{0, PallocChunkPages - 1}},
790 },
791 },
792 "Free2": {
793 npages: 2,
794 before: map[ChunkIdx][]BitRange{
795 BaseChunkIdx: {{0, PallocChunkPages}},
796 },
797 frees: []uintptr{
798 PageBase(BaseChunkIdx, 0),
799 PageBase(BaseChunkIdx, 2),
800 PageBase(BaseChunkIdx, 4),
801 PageBase(BaseChunkIdx, 6),
802 PageBase(BaseChunkIdx, 8),
803 },
804 after: map[ChunkIdx][]BitRange{
805 BaseChunkIdx: {{10, PallocChunkPages - 10}},
806 },
807 },
808 "Straddle2": {
809 npages: 2,
810 before: map[ChunkIdx][]BitRange{
811 BaseChunkIdx: {{PallocChunkPages - 1, 1}},
812 BaseChunkIdx + 1: {{0, 1}},
813 },
814 frees: []uintptr{
815 PageBase(BaseChunkIdx, PallocChunkPages-1),
816 },
817 after: map[ChunkIdx][]BitRange{
818 BaseChunkIdx: {},
819 BaseChunkIdx + 1: {},
820 },
821 },
822 "Free5": {
823 npages: 5,
824 before: map[ChunkIdx][]BitRange{
825 BaseChunkIdx: {{0, PallocChunkPages}},
826 },
827 frees: []uintptr{
828 PageBase(BaseChunkIdx, 0),
829 PageBase(BaseChunkIdx, 5),
830 PageBase(BaseChunkIdx, 10),
831 PageBase(BaseChunkIdx, 15),
832 PageBase(BaseChunkIdx, 20),
833 },
834 after: map[ChunkIdx][]BitRange{
835 BaseChunkIdx: {{25, PallocChunkPages - 25}},
836 },
837 },
838 "Free64": {
839 npages: 64,
840 before: map[ChunkIdx][]BitRange{
841 BaseChunkIdx: {{0, PallocChunkPages}},
842 },
843 frees: []uintptr{
844 PageBase(BaseChunkIdx, 0),
845 PageBase(BaseChunkIdx, 64),
846 PageBase(BaseChunkIdx, 128),
847 },
848 after: map[ChunkIdx][]BitRange{
849 BaseChunkIdx: {{192, PallocChunkPages - 192}},
850 },
851 },
852 "Free65": {
853 npages: 65,
854 before: map[ChunkIdx][]BitRange{
855 BaseChunkIdx: {{0, PallocChunkPages}},
856 },
857 frees: []uintptr{
858 PageBase(BaseChunkIdx, 0),
859 PageBase(BaseChunkIdx, 65),
860 PageBase(BaseChunkIdx, 130),
861 },
862 after: map[ChunkIdx][]BitRange{
863 BaseChunkIdx: {{195, PallocChunkPages - 195}},
864 },
865 },
866 "FreePallocChunkPages": {
867 npages: PallocChunkPages,
868 before: map[ChunkIdx][]BitRange{
869 BaseChunkIdx: {{0, PallocChunkPages}},
870 },
871 frees: []uintptr{
872 PageBase(BaseChunkIdx, 0),
873 },
874 after: map[ChunkIdx][]BitRange{
875 BaseChunkIdx: {},
876 },
877 },
878 "StraddlePallocChunkPages": {
879 npages: PallocChunkPages,
880 before: map[ChunkIdx][]BitRange{
881 BaseChunkIdx: {{PallocChunkPages / 2, PallocChunkPages / 2}},
882 BaseChunkIdx + 1: {{0, PallocChunkPages / 2}},
883 },
884 frees: []uintptr{
885 PageBase(BaseChunkIdx, PallocChunkPages/2),
886 },
887 after: map[ChunkIdx][]BitRange{
888 BaseChunkIdx: {},
889 BaseChunkIdx + 1: {},
890 },
891 },
892 "StraddlePallocChunkPages+1": {
893 npages: PallocChunkPages + 1,
894 before: map[ChunkIdx][]BitRange{
895 BaseChunkIdx: {{0, PallocChunkPages}},
896 BaseChunkIdx + 1: {{0, PallocChunkPages}},
897 },
898 frees: []uintptr{
899 PageBase(BaseChunkIdx, PallocChunkPages/2),
900 },
901 after: map[ChunkIdx][]BitRange{
902 BaseChunkIdx: {{0, PallocChunkPages / 2}},
903 BaseChunkIdx + 1: {{PallocChunkPages/2 + 1, PallocChunkPages/2 - 1}},
904 },
905 },
906 "FreePallocChunkPages*2": {
907 npages: PallocChunkPages * 2,
908 before: map[ChunkIdx][]BitRange{
909 BaseChunkIdx: {{0, PallocChunkPages}},
910 BaseChunkIdx + 1: {{0, PallocChunkPages}},
911 },
912 frees: []uintptr{
913 PageBase(BaseChunkIdx, 0),
914 },
915 after: map[ChunkIdx][]BitRange{
916 BaseChunkIdx: {},
917 BaseChunkIdx + 1: {},
918 },
919 },
920 "StraddlePallocChunkPages*2": {
921 npages: PallocChunkPages * 2,
922 before: map[ChunkIdx][]BitRange{
923 BaseChunkIdx: {{0, PallocChunkPages}},
924 BaseChunkIdx + 1: {{0, PallocChunkPages}},
925 BaseChunkIdx + 2: {{0, PallocChunkPages}},
926 },
927 frees: []uintptr{
928 PageBase(BaseChunkIdx, PallocChunkPages/2),
929 },
930 after: map[ChunkIdx][]BitRange{
931 BaseChunkIdx: {{0, PallocChunkPages / 2}},
932 BaseChunkIdx + 1: {},
933 BaseChunkIdx + 2: {{PallocChunkPages / 2, PallocChunkPages / 2}},
934 },
935 },
936 "AllFreePallocChunkPages*7+5": {
937 npages: PallocChunkPages*7 + 5,
938 before: map[ChunkIdx][]BitRange{
939 BaseChunkIdx: {{0, PallocChunkPages}},
940 BaseChunkIdx + 1: {{0, PallocChunkPages}},
941 BaseChunkIdx + 2: {{0, PallocChunkPages}},
942 BaseChunkIdx + 3: {{0, PallocChunkPages}},
943 BaseChunkIdx + 4: {{0, PallocChunkPages}},
944 BaseChunkIdx + 5: {{0, PallocChunkPages}},
945 BaseChunkIdx + 6: {{0, PallocChunkPages}},
946 BaseChunkIdx + 7: {{0, PallocChunkPages}},
947 },
948 frees: []uintptr{
949 PageBase(BaseChunkIdx, 0),
950 },
951 after: map[ChunkIdx][]BitRange{
952 BaseChunkIdx: {},
953 BaseChunkIdx + 1: {},
954 BaseChunkIdx + 2: {},
955 BaseChunkIdx + 3: {},
956 BaseChunkIdx + 4: {},
957 BaseChunkIdx + 5: {},
958 BaseChunkIdx + 6: {},
959 BaseChunkIdx + 7: {{5, PallocChunkPages - 5}},
960 },
961 },
962 }
963 for name, v := range tests {
964 v := v
965 t.Run(name, func(t *testing.T) {
966 b := NewPageAlloc(v.before, nil)
967 defer FreePageAlloc(b)
968
969 for _, addr := range v.frees {
970 b.Free(addr, v.npages)
971 }
972 want := NewPageAlloc(v.after, nil)
973 defer FreePageAlloc(want)
974
975 checkPageAlloc(t, want, b)
976 })
977 }
978 }
979
980 func TestPageAllocAllocAndFree(t *testing.T) {
981 if GOOS == "openbsd" && testing.Short() {
982 t.Skip("skipping because virtual memory is limited; see #36210")
983 }
984 type hit struct {
985 alloc bool
986 npages uintptr
987 base uintptr
988 }
989 tests := map[string]struct {
990 init map[ChunkIdx][]BitRange
991 hits []hit
992 }{
993
994 "Chunks8": {
995 init: map[ChunkIdx][]BitRange{
996 BaseChunkIdx: {},
997 BaseChunkIdx + 1: {},
998 BaseChunkIdx + 2: {},
999 BaseChunkIdx + 3: {},
1000 BaseChunkIdx + 4: {},
1001 BaseChunkIdx + 5: {},
1002 BaseChunkIdx + 6: {},
1003 BaseChunkIdx + 7: {},
1004 },
1005 hits: []hit{
1006 {true, PallocChunkPages * 8, PageBase(BaseChunkIdx, 0)},
1007 {false, PallocChunkPages * 8, PageBase(BaseChunkIdx, 0)},
1008 {true, PallocChunkPages * 8, PageBase(BaseChunkIdx, 0)},
1009 {false, PallocChunkPages * 8, PageBase(BaseChunkIdx, 0)},
1010 {true, PallocChunkPages * 8, PageBase(BaseChunkIdx, 0)},
1011 {false, PallocChunkPages * 8, PageBase(BaseChunkIdx, 0)},
1012 {true, 1, PageBase(BaseChunkIdx, 0)},
1013 {false, 1, PageBase(BaseChunkIdx, 0)},
1014 {true, PallocChunkPages * 8, PageBase(BaseChunkIdx, 0)},
1015 },
1016 },
1017 }
1018 for name, v := range tests {
1019 v := v
1020 t.Run(name, func(t *testing.T) {
1021 b := NewPageAlloc(v.init, nil)
1022 defer FreePageAlloc(b)
1023
1024 for iter, i := range v.hits {
1025 if i.alloc {
1026 if a, _ := b.Alloc(i.npages); a != i.base {
1027 t.Fatalf("bad alloc #%d: want 0x%x, got 0x%x", iter+1, i.base, a)
1028 }
1029 } else {
1030 b.Free(i.base, i.npages)
1031 }
1032 }
1033 })
1034 }
1035 }
1036
View as plain text