1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
13 var spanDesc = map[uintptr]struct {
17 0xc0000000: {2, false},
18 0xc0006000: {1, false},
19 0xc0010000: {8, false},
20 0xc0022000: {7, false},
21 0xc0034000: {4, true},
22 0xc0040000: {5, false},
23 0xc0050000: {5, true},
24 0xc0060000: {5000, false},
27 // Wrap the Treap one more time because go:notinheap doesn't
28 // actually follow a structure across package boundaries.
35 func maskMatchName(mask, match runtime.TreapIterType) string {
36 return fmt.Sprintf("%0*b-%0*b", runtime.TreapIterBits, uint8(mask), runtime.TreapIterBits, uint8(match))
39 func TestTreapFilter(t *testing.T) {
40 var iterTypes = [...]struct {
41 mask, match runtime.TreapIterType
42 filter runtime.TreapIterFilter // expected filter
45 {runtime.TreapIterScav, 0, 0x5},
46 {runtime.TreapIterScav, runtime.TreapIterScav, 0xa},
47 {runtime.TreapIterScav | runtime.TreapIterHuge, runtime.TreapIterHuge, 0x4},
48 {runtime.TreapIterScav | runtime.TreapIterHuge, 0, 0x1},
49 {0, runtime.TreapIterScav, 0x0},
51 for _, it := range iterTypes {
52 t.Run(maskMatchName(it.mask, it.match), func(t *testing.T) {
53 if f := runtime.TreapFilter(it.mask, it.match); f != it.filter {
54 t.Fatalf("got %#x, want %#x", f, it.filter)
60 // This test ensures that the treap implementation in the runtime
61 // maintains all stated invariants after different sequences of
62 // insert, removeSpan, find, and erase. Invariants specific to the
63 // treap data structure are checked implicitly: after each mutating
64 // operation, treap-related invariants are checked for the entire
66 func TestTreap(t *testing.T) {
67 // Set up a bunch of spans allocated into mheap_.
68 // Also, derive a set of typeCounts of each type of span
69 // according to runtime.TreapIterType so we can verify against
71 spans := make([]runtime.Span, 0, len(spanDesc))
72 typeCounts := [1 << runtime.TreapIterBits][1 << runtime.TreapIterBits]int{}
73 for base, de := range spanDesc {
74 s := runtime.AllocSpan(base, de.pages, de.scav)
76 spans = append(spans, s)
78 for i := runtime.TreapIterType(0); i < 1<<runtime.TreapIterBits; i++ {
79 for j := runtime.TreapIterType(0); j < 1<<runtime.TreapIterBits; j++ {
80 if s.MatchesIter(i, j) {
86 t.Run("TypeCountsSanity", func(t *testing.T) {
87 // Just sanity check type counts for a few values.
88 check := func(mask, match runtime.TreapIterType, count int) {
89 tc := typeCounts[mask][match]
91 name := maskMatchName(mask, match)
92 t.Fatalf("failed a sanity check for mask/match %s counts: got %d, wanted %d", name, tc, count)
95 check(0, 0, len(spanDesc))
96 check(runtime.TreapIterScav, 0, 6)
97 check(runtime.TreapIterScav, runtime.TreapIterScav, 2)
99 t.Run("Insert", func(t *testing.T) {
101 // Test just a very basic insert/remove for sanity.
103 tr.RemoveSpan(spans[0])
105 t.Run("FindTrivial", func(t *testing.T) {
107 // Test just a very basic find operation for sanity.
110 if i.Span() != spans[0] {
111 t.Fatal("found unknown span in treap")
113 tr.RemoveSpan(spans[0])
115 t.Run("FindFirstFit", func(t *testing.T) {
116 // Run this 10 times, recreating the treap each time.
117 // Because of the non-deterministic structure of a treap,
118 // we'll be able to test different structures this way.
119 for i := 0; i < 10; i++ {
120 tr := runtime.Treap{}
121 for _, s := range spans {
125 if i.Span().Base() != 0xc0010000 {
126 t.Fatalf("expected span at lowest address which could fit 5 pages, instead found span at %x", i.Span().Base())
128 for _, s := range spans {
133 t.Run("Iterate", func(t *testing.T) {
134 for mask := runtime.TreapIterType(0); mask < 1<<runtime.TreapIterBits; mask++ {
135 for match := runtime.TreapIterType(0); match < 1<<runtime.TreapIterBits; match++ {
136 iterName := maskMatchName(mask, match)
137 t.Run(iterName, func(t *testing.T) {
138 t.Run("StartToEnd", func(t *testing.T) {
139 // Ensure progressing an iterator actually goes over the whole treap
140 // from the start and that it iterates over the elements in order.
141 // Furthermore, ensure that it only iterates over the relevant parts
143 // Finally, ensures that Start returns a valid iterator.
145 for _, s := range spans {
149 lastBase := uintptr(0)
150 for i := tr.Start(mask, match); i.Valid(); i = i.Next() {
152 if lastBase > i.Span().Base() {
153 t.Fatalf("not iterating in correct order: encountered base %x before %x", lastBase, i.Span().Base())
155 lastBase = i.Span().Base()
156 if !i.Span().MatchesIter(mask, match) {
157 t.Fatalf("found non-matching span while iteration over mask/match %s: base %x", iterName, i.Span().Base())
160 if nspans != typeCounts[mask][match] {
161 t.Fatal("failed to iterate forwards over full treap")
163 for _, s := range spans {
167 t.Run("EndToStart", func(t *testing.T) {
168 // See StartToEnd tests.
170 for _, s := range spans {
174 lastBase := ^uintptr(0)
175 for i := tr.End(mask, match); i.Valid(); i = i.Prev() {
177 if lastBase < i.Span().Base() {
178 t.Fatalf("not iterating in correct order: encountered base %x before %x", lastBase, i.Span().Base())
180 lastBase = i.Span().Base()
181 if !i.Span().MatchesIter(mask, match) {
182 t.Fatalf("found non-matching span while iteration over mask/match %s: base %x", iterName, i.Span().Base())
185 if nspans != typeCounts[mask][match] {
186 t.Fatal("failed to iterate backwards over full treap")
188 for _, s := range spans {
195 t.Run("Prev", func(t *testing.T) {
196 // Test the iterator invariant that i.prev().next() == i.
198 for _, s := range spans {
201 i := tr.Start(0, 0).Next().Next()
204 t.Fatal("i.prev() is invalid")
206 if p.Next().Span() != i.Span() {
207 t.Fatal("i.prev().next() != i")
209 for _, s := range spans {
213 t.Run("Next", func(t *testing.T) {
214 // Test the iterator invariant that i.next().prev() == i.
216 for _, s := range spans {
219 i := tr.Start(0, 0).Next().Next()
222 t.Fatal("i.next() is invalid")
224 if n.Prev().Span() != i.Span() {
225 t.Fatal("i.next().prev() != i")
227 for _, s := range spans {
232 t.Run("EraseOne", func(t *testing.T) {
233 // Test that erasing one iterator correctly retains
234 // all relationships between elements.
236 for _, s := range spans {
239 i := tr.Start(0, 0).Next().Next().Next()
244 if n.Prev().Span() != p.Span() {
245 t.Fatal("p, n := i.Prev(), i.Next(); n.prev() != p after i was erased")
247 if p.Next().Span() != n.Span() {
248 t.Fatal("p, n := i.Prev(), i.Next(); p.next() != n after i was erased")
251 for _, s := range spans {
255 t.Run("EraseAll", func(t *testing.T) {
256 // Test that erasing iterators actually removes nodes from the treap.
258 for _, s := range spans {
261 for i := tr.Start(0, 0); i.Valid(); {
266 if size := tr.Size(); size != 0 {
267 t.Fatalf("should have emptied out treap, %d spans left", size)