Source file
src/runtime/map_noswiss_test.go
1
2
3
4
5
6
7 package runtime_test
8
9 import (
10 "internal/abi"
11 "internal/goarch"
12 "runtime"
13 "slices"
14 "testing"
15 )
16
17 func TestHmapSize(t *testing.T) {
18
19
20
21 var hmapSize = uintptr(2*8 + 5*goarch.PtrSize)
22 if runtime.RuntimeHmapSize != hmapSize {
23 t.Errorf("sizeof(runtime.hmap{})==%d, want %d", runtime.RuntimeHmapSize, hmapSize)
24 }
25 }
26
27 func TestLoadFactor(t *testing.T) {
28 for b := uint8(0); b < 20; b++ {
29 count := 13 * (1 << b) / 2
30 if b == 0 {
31 count = 8
32 }
33 if runtime.OverLoadFactor(count, b) {
34 t.Errorf("OverLoadFactor(%d,%d)=true, want false", count, b)
35 }
36 if !runtime.OverLoadFactor(count+1, b) {
37 t.Errorf("OverLoadFactor(%d,%d)=false, want true", count+1, b)
38 }
39 }
40 }
41
42 func TestMapIterOrder(t *testing.T) {
43 sizes := []int{3, 7, 9, 15}
44 if abi.OldMapBucketCountBits >= 5 {
45
46 t.Fatalf("This test becomes flaky if abi.MapBucketCountBits(=%d) is 5 or larger", abi.OldMapBucketCountBits)
47 }
48 for _, n := range sizes {
49 for i := 0; i < 1000; i++ {
50
51 m := make(map[int]bool)
52 for i := 0; i < n; i++ {
53 m[i] = true
54 }
55
56 ord := func() []int {
57 var s []int
58 for key := range m {
59 s = append(s, key)
60 }
61 return s
62 }
63 first := ord()
64 ok := false
65 for try := 0; try < 100; try++ {
66 if !slices.Equal(first, ord()) {
67 ok = true
68 break
69 }
70 }
71 if !ok {
72 t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
73 break
74 }
75 }
76 }
77 }
78
79 const bs = abi.OldMapBucketCount
80
81
82
83
84
85 const (
86 belowOverflow = bs * 3 / 2
87 atOverflow = belowOverflow + bs/8
88 )
89
90 var mapBucketTests = [...]struct {
91 n int
92 noescape int
93 escape int
94 }{
95 {-(1 << 30), 1, 1},
96 {-1, 1, 1},
97 {0, 1, 1},
98 {1, 1, 1},
99 {bs, 1, 1},
100 {bs + 1, 2, 2},
101 {belowOverflow, 2, 2},
102 {atOverflow + 1, 4, 4},
103
104 {2 * belowOverflow, 4, 4},
105 {2*atOverflow + 1, 8, 8},
106
107 {4 * belowOverflow, 8, 8},
108 {4*atOverflow + 1, 16, 16},
109 }
110
111 func TestMapBuckets(t *testing.T) {
112
113
114
115
116
117
118 t.Run("mapliteral", func(t *testing.T) {
119 for _, tt := range mapBucketTests {
120 localMap := map[int]int{}
121 if runtime.MapBucketsPointerIsNil(localMap) {
122 t.Errorf("no escape: buckets pointer is nil for non-escaping map")
123 }
124 for i := 0; i < tt.n; i++ {
125 localMap[i] = i
126 }
127 if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
128 t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
129 }
130 escapingMap := runtime.Escape(map[int]int{})
131 if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
132 t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
133 }
134 for i := 0; i < tt.n; i++ {
135 escapingMap[i] = i
136 }
137 if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
138 t.Errorf("escape n=%d want %d buckets, got %d", tt.n, tt.escape, got)
139 }
140 }
141 })
142 t.Run("nohint", func(t *testing.T) {
143 for _, tt := range mapBucketTests {
144 localMap := make(map[int]int)
145 if runtime.MapBucketsPointerIsNil(localMap) {
146 t.Errorf("no escape: buckets pointer is nil for non-escaping map")
147 }
148 for i := 0; i < tt.n; i++ {
149 localMap[i] = i
150 }
151 if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
152 t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
153 }
154 escapingMap := runtime.Escape(make(map[int]int))
155 if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
156 t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
157 }
158 for i := 0; i < tt.n; i++ {
159 escapingMap[i] = i
160 }
161 if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
162 t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got)
163 }
164 }
165 })
166 t.Run("makemap", func(t *testing.T) {
167 for _, tt := range mapBucketTests {
168 localMap := make(map[int]int, tt.n)
169 if runtime.MapBucketsPointerIsNil(localMap) {
170 t.Errorf("no escape: buckets pointer is nil for non-escaping map")
171 }
172 for i := 0; i < tt.n; i++ {
173 localMap[i] = i
174 }
175 if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
176 t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
177 }
178 escapingMap := runtime.Escape(make(map[int]int, tt.n))
179 if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
180 t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
181 }
182 for i := 0; i < tt.n; i++ {
183 escapingMap[i] = i
184 }
185 if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
186 t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got)
187 }
188 }
189 })
190 t.Run("makemap64", func(t *testing.T) {
191 for _, tt := range mapBucketTests {
192 localMap := make(map[int]int, int64(tt.n))
193 if runtime.MapBucketsPointerIsNil(localMap) {
194 t.Errorf("no escape: buckets pointer is nil for non-escaping map")
195 }
196 for i := 0; i < tt.n; i++ {
197 localMap[i] = i
198 }
199 if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
200 t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
201 }
202 escapingMap := runtime.Escape(make(map[int]int, tt.n))
203 if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
204 t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
205 }
206 for i := 0; i < tt.n; i++ {
207 escapingMap[i] = i
208 }
209 if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
210 t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got)
211 }
212 }
213 })
214 }
215
View as plain text