// Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package runtime_test import ( "internal/goos" "math/rand" . "runtime" "testing" ) func checkPageCache(t *testing.T, got, want PageCache) { if got.Base() != want.Base() { t.Errorf("bad pageCache base: got 0x%x, want 0x%x", got.Base(), want.Base()) } if got.Cache() != want.Cache() { t.Errorf("bad pageCache bits: got %016x, want %016x", got.Base(), want.Base()) } if got.Scav() != want.Scav() { t.Errorf("bad pageCache scav: got %016x, want %016x", got.Scav(), want.Scav()) } } func TestPageCacheAlloc(t *testing.T) { base := PageBase(BaseChunkIdx, 0) type hit struct { npages uintptr base uintptr scav uintptr } tests := map[string]struct { cache PageCache hits []hit }{ "Empty": { cache: NewPageCache(base, 0, 0), hits: []hit{ {1, 0, 0}, {2, 0, 0}, {3, 0, 0}, {4, 0, 0}, {5, 0, 0}, {11, 0, 0}, {12, 0, 0}, {16, 0, 0}, {27, 0, 0}, {32, 0, 0}, {43, 0, 0}, {57, 0, 0}, {64, 0, 0}, {121, 0, 0}, }, }, "Lo1": { cache: NewPageCache(base, 0x1, 0x1), hits: []hit{ {1, base, PageSize}, {1, 0, 0}, {10, 0, 0}, }, }, "Hi1": { cache: NewPageCache(base, 0x1<<63, 0x1), hits: []hit{ {1, base + 63*PageSize, 0}, {1, 0, 0}, {10, 0, 0}, }, }, "Swiss1": { cache: NewPageCache(base, 0x20005555, 0x5505), hits: []hit{ {2, 0, 0}, {1, base, PageSize}, {1, base + 2*PageSize, PageSize}, {1, base + 4*PageSize, 0}, {1, base + 6*PageSize, 0}, {1, base + 8*PageSize, PageSize}, {1, base + 10*PageSize, PageSize}, {1, base + 12*PageSize, PageSize}, {1, base + 14*PageSize, PageSize}, {1, base + 29*PageSize, 0}, {1, 0, 0}, {10, 0, 0}, }, }, "Lo2": { cache: NewPageCache(base, 0x3, 0x2<<62), hits: []hit{ {2, base, 0}, {2, 0, 0}, {1, 0, 0}, }, }, "Hi2": { cache: NewPageCache(base, 0x3<<62, 0x3<<62), hits: []hit{ {2, base + 62*PageSize, 2 * PageSize}, {2, 0, 0}, {1, 0, 0}, }, }, "Swiss2": { cache: NewPageCache(base, 0x3333<<31, 0x3030<<31), hits: []hit{ {2, base + 31*PageSize, 0}, {2, base + 35*PageSize, 2 * PageSize}, {2, base + 39*PageSize, 0}, {2, base + 43*PageSize, 2 * PageSize}, {2, 0, 0}, }, }, "Hi53": { cache: NewPageCache(base, ((uint64(1)<<53)-1)<<10, ((uint64(1)<<16)-1)<<10), hits: []hit{ {53, base + 10*PageSize, 16 * PageSize}, {53, 0, 0}, {1, 0, 0}, }, }, "Full53": { cache: NewPageCache(base, ^uint64(0), ((uint64(1)<<16)-1)<<10), hits: []hit{ {53, base, 16 * PageSize}, {53, 0, 0}, {1, base + 53*PageSize, 0}, }, }, "Full64": { cache: NewPageCache(base, ^uint64(0), ^uint64(0)), hits: []hit{ {64, base, 64 * PageSize}, {64, 0, 0}, {1, 0, 0}, }, }, "FullMixed": { cache: NewPageCache(base, ^uint64(0), ^uint64(0)), hits: []hit{ {5, base, 5 * PageSize}, {7, base + 5*PageSize, 7 * PageSize}, {1, base + 12*PageSize, 1 * PageSize}, {23, base + 13*PageSize, 23 * PageSize}, {63, 0, 0}, {3, base + 36*PageSize, 3 * PageSize}, {3, base + 39*PageSize, 3 * PageSize}, {3, base + 42*PageSize, 3 * PageSize}, {12, base + 45*PageSize, 12 * PageSize}, {11, 0, 0}, {4, base + 57*PageSize, 4 * PageSize}, {4, 0, 0}, {6, 0, 0}, {36, 0, 0}, {2, base + 61*PageSize, 2 * PageSize}, {3, 0, 0}, {1, base + 63*PageSize, 1 * PageSize}, {4, 0, 0}, {2, 0, 0}, {62, 0, 0}, {1, 0, 0}, }, }, } for name, test := range tests { test := test t.Run(name, func(t *testing.T) { c := test.cache for i, h := range test.hits { b, s := c.Alloc(h.npages) if b != h.base { t.Fatalf("bad alloc base #%d: got 0x%x, want 0x%x", i, b, h.base) } if s != h.scav { t.Fatalf("bad alloc scav #%d: got %d, want %d", i, s, h.scav) } } }) } } func TestPageCacheFlush(t *testing.T) { if GOOS == "openbsd" && testing.Short() { t.Skip("skipping because virtual memory is limited; see #36210") } bits64ToBitRanges := func(bits uint64, base uint) []BitRange { var ranges []BitRange start, size := uint(0), uint(0) for i := 0; i < 64; i++ { if bits&(1<