func TestPageAllocAlloc(t *testing.T) {
type hit struct {
- npages, base uintptr
+ npages, base, scav uintptr
}
tests := map[string]struct {
+ scav map[ChunkIdx][]BitRange
before map[ChunkIdx][]BitRange
after map[ChunkIdx][]BitRange
hits []hit
before: map[ChunkIdx][]BitRange{
BaseChunkIdx: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, 1}, {2, 2}},
+ },
hits: []hit{
- {1, PageBase(BaseChunkIdx, 0)},
- {1, PageBase(BaseChunkIdx, 1)},
- {1, PageBase(BaseChunkIdx, 2)},
- {1, PageBase(BaseChunkIdx, 3)},
- {1, PageBase(BaseChunkIdx, 4)},
+ {1, PageBase(BaseChunkIdx, 0), PageSize},
+ {1, PageBase(BaseChunkIdx, 1), 0},
+ {1, PageBase(BaseChunkIdx, 2), PageSize},
+ {1, PageBase(BaseChunkIdx, 3), PageSize},
+ {1, PageBase(BaseChunkIdx, 4), 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, 5}},
BaseChunkIdx + 1: {{0, PallocChunkPages}},
BaseChunkIdx + 2: {{0, PallocChunkPages - 1}},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, PallocChunkPages}},
+ BaseChunkIdx + 1: {{0, PallocChunkPages}},
+ BaseChunkIdx + 2: {{0, PallocChunkPages}},
+ },
hits: []hit{
- {1, PageBase(BaseChunkIdx+2, PallocChunkPages-1)},
+ {1, PageBase(BaseChunkIdx+2, PallocChunkPages-1), PageSize},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx + 0xff: {{0, 0}},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, PallocChunkPages}},
+ BaseChunkIdx + 0xff: {{0, PallocChunkPages}},
+ },
hits: []hit{
- {1, PageBase(BaseChunkIdx+0xff, 0)},
+ {1, PageBase(BaseChunkIdx+0xff, 0), PageSize},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
before: map[ChunkIdx][]BitRange{
BaseChunkIdx: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, 3}, {7, 1}},
+ },
hits: []hit{
- {2, PageBase(BaseChunkIdx, 0)},
- {2, PageBase(BaseChunkIdx, 2)},
- {2, PageBase(BaseChunkIdx, 4)},
- {2, PageBase(BaseChunkIdx, 6)},
- {2, PageBase(BaseChunkIdx, 8)},
+ {2, PageBase(BaseChunkIdx, 0), 2 * PageSize},
+ {2, PageBase(BaseChunkIdx, 2), PageSize},
+ {2, PageBase(BaseChunkIdx, 4), 0},
+ {2, PageBase(BaseChunkIdx, 6), PageSize},
+ {2, PageBase(BaseChunkIdx, 8), 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, 10}},
BaseChunkIdx: {{0, PallocChunkPages - 1}},
BaseChunkIdx + 1: {{1, PallocChunkPages - 1}},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{PallocChunkPages - 1, 1}},
+ BaseChunkIdx + 1: {},
+ },
hits: []hit{
- {2, PageBase(BaseChunkIdx, PallocChunkPages-1)},
+ {2, PageBase(BaseChunkIdx, PallocChunkPages-1), PageSize},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
before: map[ChunkIdx][]BitRange{
BaseChunkIdx: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, 8}, {9, 1}, {17, 5}},
+ },
hits: []hit{
- {5, PageBase(BaseChunkIdx, 0)},
- {5, PageBase(BaseChunkIdx, 5)},
- {5, PageBase(BaseChunkIdx, 10)},
- {5, PageBase(BaseChunkIdx, 15)},
- {5, PageBase(BaseChunkIdx, 20)},
+ {5, PageBase(BaseChunkIdx, 0), 5 * PageSize},
+ {5, PageBase(BaseChunkIdx, 5), 4 * PageSize},
+ {5, PageBase(BaseChunkIdx, 10), 0},
+ {5, PageBase(BaseChunkIdx, 15), 3 * PageSize},
+ {5, PageBase(BaseChunkIdx, 20), 2 * PageSize},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, 25}},
before: map[ChunkIdx][]BitRange{
BaseChunkIdx: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{21, 1}, {63, 65}},
+ },
hits: []hit{
- {64, PageBase(BaseChunkIdx, 0)},
- {64, PageBase(BaseChunkIdx, 64)},
- {64, PageBase(BaseChunkIdx, 128)},
+ {64, PageBase(BaseChunkIdx, 0), 2 * PageSize},
+ {64, PageBase(BaseChunkIdx, 64), 64 * PageSize},
+ {64, PageBase(BaseChunkIdx, 128), 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, 192}},
before: map[ChunkIdx][]BitRange{
BaseChunkIdx: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{129, 1}},
+ },
hits: []hit{
- {65, PageBase(BaseChunkIdx, 0)},
- {65, PageBase(BaseChunkIdx, 65)},
- {65, PageBase(BaseChunkIdx, 130)},
+ {65, PageBase(BaseChunkIdx, 0), 0},
+ {65, PageBase(BaseChunkIdx, 65), PageSize},
+ {65, PageBase(BaseChunkIdx, 130), 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, 195}},
before: map[ChunkIdx][]BitRange{
BaseChunkIdx: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{10, 1}},
+ },
hits: []hit{
- {PallocChunkPages - 3, PageBase(BaseChunkIdx, 0)},
- {PallocChunkPages - 3, 0},
- {1, PageBase(BaseChunkIdx, PallocChunkPages-3)},
- {2, PageBase(BaseChunkIdx, PallocChunkPages-2)},
- {1, 0},
- {PallocChunkPages - 3, 0},
+ {PallocChunkPages - 3, PageBase(BaseChunkIdx, 0), PageSize},
+ {PallocChunkPages - 3, 0, 0},
+ {1, PageBase(BaseChunkIdx, PallocChunkPages-3), 0},
+ {2, PageBase(BaseChunkIdx, PallocChunkPages-2), 0},
+ {1, 0, 0},
+ {PallocChunkPages - 3, 0, 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
before: map[ChunkIdx][]BitRange{
BaseChunkIdx: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, 1}, {PallocChunkPages - 1, 1}},
+ },
hits: []hit{
- {PallocChunkPages, PageBase(BaseChunkIdx, 0)},
- {PallocChunkPages, 0},
- {1, 0},
+ {PallocChunkPages, PageBase(BaseChunkIdx, 0), 2 * PageSize},
+ {PallocChunkPages, 0, 0},
+ {1, 0, 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx: {{0, PallocChunkPages / 2}},
BaseChunkIdx + 1: {{PallocChunkPages / 2, PallocChunkPages / 2}},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {},
+ BaseChunkIdx + 1: {{3, 100}},
+ },
hits: []hit{
- {PallocChunkPages, PageBase(BaseChunkIdx, PallocChunkPages/2)},
- {PallocChunkPages, 0},
- {1, 0},
+ {PallocChunkPages, PageBase(BaseChunkIdx, PallocChunkPages/2), 100 * PageSize},
+ {PallocChunkPages, 0, 0},
+ {1, 0, 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx: {{0, PallocChunkPages / 2}},
BaseChunkIdx + 1: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, PallocChunkPages}},
+ BaseChunkIdx + 1: {{0, PallocChunkPages}},
+ },
hits: []hit{
- {PallocChunkPages + 1, PageBase(BaseChunkIdx, PallocChunkPages/2)},
- {PallocChunkPages, 0},
- {1, PageBase(BaseChunkIdx+1, PallocChunkPages/2+1)},
+ {PallocChunkPages + 1, PageBase(BaseChunkIdx, PallocChunkPages/2), (PallocChunkPages + 1) * PageSize},
+ {PallocChunkPages, 0, 0},
+ {1, PageBase(BaseChunkIdx+1, PallocChunkPages/2+1), PageSize},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx: {},
BaseChunkIdx + 1: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {},
+ BaseChunkIdx + 1: {},
+ },
hits: []hit{
- {PallocChunkPages * 2, PageBase(BaseChunkIdx, 0)},
- {PallocChunkPages * 2, 0},
- {1, 0},
+ {PallocChunkPages * 2, PageBase(BaseChunkIdx, 0), 0},
+ {PallocChunkPages * 2, 0, 0},
+ {1, 0, 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx + 0x100: {},
BaseChunkIdx + 0x101: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, PallocChunkPages}},
+ BaseChunkIdx + 0x100: {},
+ BaseChunkIdx + 0x101: {},
+ },
hits: []hit{
- {PallocChunkPages * 2, PageBase(BaseChunkIdx+0x100, 0)},
- {21, PageBase(BaseChunkIdx, 0)},
- {1, PageBase(BaseChunkIdx, 21)},
+ {PallocChunkPages * 2, PageBase(BaseChunkIdx+0x100, 0), 0},
+ {21, PageBase(BaseChunkIdx, 0), 21 * PageSize},
+ {1, PageBase(BaseChunkIdx, 21), PageSize},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, 22}},
BaseChunkIdx + 1: {},
BaseChunkIdx + 2: {{PallocChunkPages / 2, PallocChunkPages / 2}},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, 7}},
+ BaseChunkIdx + 1: {{3, 5}, {121, 10}},
+ BaseChunkIdx + 2: {{PallocChunkPages/2 + 12, 2}},
+ },
hits: []hit{
- {PallocChunkPages * 2, PageBase(BaseChunkIdx, PallocChunkPages/2)},
- {PallocChunkPages * 2, 0},
- {1, 0},
+ {PallocChunkPages * 2, PageBase(BaseChunkIdx, PallocChunkPages/2), 15 * PageSize},
+ {PallocChunkPages * 2, 0, 0},
+ {1, 0, 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx + 2: {{0, PallocChunkPages * 3 / 4}},
BaseChunkIdx + 3: {{0, 0}},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{0, PallocChunkPages}},
+ BaseChunkIdx + 1: {{PallocChunkPages / 2, PallocChunkPages/4 + 1}},
+ BaseChunkIdx + 2: {{PallocChunkPages / 3, 1}},
+ BaseChunkIdx + 3: {{PallocChunkPages * 2 / 3, 1}},
+ },
hits: []hit{
- {PallocChunkPages * 5 / 4, PageBase(BaseChunkIdx+2, PallocChunkPages*3/4)},
- {PallocChunkPages * 5 / 4, 0},
- {1, PageBase(BaseChunkIdx+1, PallocChunkPages*3/4)},
+ {PallocChunkPages * 5 / 4, PageBase(BaseChunkIdx+2, PallocChunkPages*3/4), PageSize},
+ {PallocChunkPages * 5 / 4, 0, 0},
+ {1, PageBase(BaseChunkIdx+1, PallocChunkPages*3/4), PageSize},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
BaseChunkIdx + 6: {},
BaseChunkIdx + 7: {},
},
+ scav: map[ChunkIdx][]BitRange{
+ BaseChunkIdx: {{50, 1}},
+ BaseChunkIdx + 1: {{31, 1}},
+ BaseChunkIdx + 2: {{7, 1}},
+ BaseChunkIdx + 3: {{200, 1}},
+ BaseChunkIdx + 4: {{3, 1}},
+ BaseChunkIdx + 5: {{51, 1}},
+ BaseChunkIdx + 6: {{20, 1}},
+ BaseChunkIdx + 7: {{1, 1}},
+ },
hits: []hit{
- {PallocChunkPages*7 + 5, PageBase(BaseChunkIdx, 0)},
- {PallocChunkPages*7 + 5, 0},
- {1, PageBase(BaseChunkIdx+7, 5)},
+ {PallocChunkPages*7 + 5, PageBase(BaseChunkIdx, 0), 8 * PageSize},
+ {PallocChunkPages*7 + 5, 0, 0},
+ {1, PageBase(BaseChunkIdx+7, 5), 0},
},
after: map[ChunkIdx][]BitRange{
BaseChunkIdx: {{0, PallocChunkPages}},
for name, v := range tests {
v := v
t.Run(name, func(t *testing.T) {
- b := NewPageAlloc(v.before, nil)
+ b := NewPageAlloc(v.before, v.scav)
defer FreePageAlloc(b)
for iter, i := range v.hits {
- if a := b.Alloc(i.npages); a != i.base {
- t.Fatalf("bad alloc #%d: want 0x%x, got 0x%x", iter+1, i.base, a)
+ a, s := b.Alloc(i.npages)
+ if a != i.base {
+ t.Fatalf("bad alloc #%d: want base 0x%x, got 0x%x", iter+1, i.base, a)
+ }
+ if s != i.scav {
+ t.Fatalf("bad alloc #%d: want scav %d, got %d", iter+1, i.scav, s)
}
}
- want := NewPageAlloc(v.after, nil)
+ want := NewPageAlloc(v.after, v.scav)
defer FreePageAlloc(want)
checkPageAlloc(t, want, b)
nAlloc := (PallocChunkPages * 4) / int(npages)
for i := 0; i < nAlloc; i++ {
addr := PageBase(BaseChunkIdx, uint(i)*uint(npages))
- if a := b.Alloc(npages); a != addr {
+ if a, _ := b.Alloc(npages); a != addr {
t.Fatalf("bad alloc #%d: want 0x%x, got 0x%x", i+1, addr, a)
}
}
// Check to make sure the next allocation fails.
- if a := b.Alloc(npages); a != 0 {
+ if a, _ := b.Alloc(npages); a != 0 {
t.Fatalf("bad alloc #%d: want 0, got 0x%x", nAlloc, a)
}
for iter, i := range v.hits {
if i.alloc {
- if a := b.Alloc(i.npages); a != i.base {
+ if a, _ := b.Alloc(i.npages); a != i.base {
t.Fatalf("bad alloc #%d: want 0x%x, got 0x%x", iter+1, i.base, a)
}
} else {
}
}
+func TestMallocBitsPopcntRange(t *testing.T) {
+ type test struct {
+ i, n uint // bit range to popcnt over.
+ want uint // expected popcnt result on that range.
+ }
+ tests := map[string]struct {
+ init []BitRange // bit ranges to set to 1 in the bitmap.
+ tests []test // a set of popcnt tests to run over the bitmap.
+ }{
+ "None": {
+ tests: []test{
+ {0, 1, 0},
+ {5, 3, 0},
+ {2, 11, 0},
+ {PallocChunkPages/4 + 1, PallocChunkPages / 2, 0},
+ {0, PallocChunkPages, 0},
+ },
+ },
+ "All": {
+ init: []BitRange{{0, PallocChunkPages}},
+ tests: []test{
+ {0, 1, 1},
+ {5, 3, 3},
+ {2, 11, 11},
+ {PallocChunkPages/4 + 1, PallocChunkPages / 2, PallocChunkPages / 2},
+ {0, PallocChunkPages, PallocChunkPages},
+ },
+ },
+ "Half": {
+ init: []BitRange{{PallocChunkPages / 2, PallocChunkPages / 2}},
+ tests: []test{
+ {0, 1, 0},
+ {5, 3, 0},
+ {2, 11, 0},
+ {PallocChunkPages/2 - 1, 1, 0},
+ {PallocChunkPages / 2, 1, 1},
+ {PallocChunkPages/2 + 10, 1, 1},
+ {PallocChunkPages/2 - 1, 2, 1},
+ {PallocChunkPages / 4, PallocChunkPages / 4, 0},
+ {PallocChunkPages / 4, PallocChunkPages/4 + 1, 1},
+ {PallocChunkPages/4 + 1, PallocChunkPages / 2, PallocChunkPages/4 + 1},
+ {0, PallocChunkPages, PallocChunkPages / 2},
+ },
+ },
+ "OddBound": {
+ init: []BitRange{{0, 111}},
+ tests: []test{
+ {0, 1, 1},
+ {5, 3, 3},
+ {2, 11, 11},
+ {110, 2, 1},
+ {99, 50, 12},
+ {110, 1, 1},
+ {111, 1, 0},
+ {99, 1, 1},
+ {120, 1, 0},
+ {PallocChunkPages / 2, PallocChunkPages / 2, 0},
+ {0, PallocChunkPages, 111},
+ },
+ },
+ "Scattered": {
+ init: []BitRange{
+ {1, 3}, {5, 1}, {7, 1}, {10, 2}, {13, 1}, {15, 4},
+ {21, 1}, {23, 1}, {26, 2}, {30, 5}, {36, 2}, {40, 3},
+ {44, 6}, {51, 1}, {53, 2}, {58, 3}, {63, 1}, {67, 2},
+ {71, 10}, {84, 1}, {89, 7}, {99, 2}, {103, 1}, {107, 2},
+ {111, 1}, {113, 1}, {115, 1}, {118, 1}, {120, 2}, {125, 5},
+ },
+ tests: []test{
+ {0, 11, 6},
+ {0, 64, 39},
+ {13, 64, 40},
+ {64, 64, 34},
+ {0, 128, 73},
+ {1, 128, 74},
+ {0, PallocChunkPages, 75},
+ },
+ },
+ }
+ for name, v := range tests {
+ v := v
+ t.Run(name, func(t *testing.T) {
+ b := makePallocBits(v.init)
+ for _, h := range v.tests {
+ if got := b.PopcntRange(h.i, h.n); got != h.want {
+ t.Errorf("bad popcnt (i=%d, n=%d): got %d, want %d", h.i, h.n, got, h.want)
+ }
+ }
+ })
+ }
+}
+
// Ensures computing bit summaries works as expected by generating random
// bitmaps and checking against a reference implementation.
func TestPallocBitsSummarizeRandom(t *testing.T) {