]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/internal/atomic/atomic_andor_test.go
runtime/internal/atomic: add 386/amd64 And/Or operators
[gostls13.git] / src / runtime / internal / atomic / atomic_andor_test.go
1 //go:build 386 || amd64 || ppc64 || ppc64le || riscv64 || wasm
2
3 //
4 // Copyright 2023 The Go Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file.
7
8 // TODO(61395): move these tests to atomic_test.go once And/Or have
9 // implementations for all architectures.
10 package atomic_test
11
12 import (
13         "runtime/internal/atomic"
14         "testing"
15 )
16
17 func TestAnd32(t *testing.T) {
18         // Basic sanity check.
19         x := uint32(0xffffffff)
20         for i := uint32(0); i < 32; i++ {
21                 old := x
22                 v := atomic.And32(&x, ^(1 << i))
23                 if r := uint32(0xffffffff) << (i + 1); x != r || v != old {
24                         t.Fatalf("clearing bit %#x: want %#x, got new %#x and old %#v", uint32(1<<i), r, x, v)
25                 }
26         }
27
28         // Set every bit in array to 1.
29         a := make([]uint32, 1<<12)
30         for i := range a {
31                 a[i] = 0xffffffff
32         }
33
34         // Clear array bit-by-bit in different goroutines.
35         done := make(chan bool)
36         for i := 0; i < 32; i++ {
37                 m := ^uint32(1 << i)
38                 go func() {
39                         for i := range a {
40                                 atomic.And(&a[i], m)
41                         }
42                         done <- true
43                 }()
44         }
45         for i := 0; i < 32; i++ {
46                 <-done
47         }
48
49         // Check that the array has been totally cleared.
50         for i, v := range a {
51                 if v != 0 {
52                         t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint32(0), v)
53                 }
54         }
55 }
56
57 func TestAnd64(t *testing.T) {
58         // Basic sanity check.
59         x := uint64(0xffffffffffffffff)
60         for i := uint64(0); i < 64; i++ {
61                 old := x
62                 v := atomic.And64(&x, ^(1 << i))
63                 if r := uint64(0xffffffffffffffff) << (i + 1); x != r || v != old {
64                         t.Fatalf("clearing bit %#x: want %#x, got new %#x and old %#v", uint64(1<<i), r, x, v)
65                 }
66         }
67
68         // Set every bit in array to 1.
69         a := make([]uint64, 1<<12)
70         for i := range a {
71                 a[i] = 0xffffffffffffffff
72         }
73
74         // Clear array bit-by-bit in different goroutines.
75         done := make(chan bool)
76         for i := 0; i < 64; i++ {
77                 m := ^uint64(1 << i)
78                 go func() {
79                         for i := range a {
80                                 atomic.And64(&a[i], m)
81                         }
82                         done <- true
83                 }()
84         }
85         for i := 0; i < 64; i++ {
86                 <-done
87         }
88
89         // Check that the array has been totally cleared.
90         for i, v := range a {
91                 if v != 0 {
92                         t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint64(0), v)
93                 }
94         }
95 }
96
97 func TestOr32(t *testing.T) {
98         // Basic sanity check.
99         x := uint32(0)
100         for i := uint32(0); i < 32; i++ {
101                 old := x
102                 v := atomic.Or32(&x, 1<<i)
103                 if r := (uint32(1) << (i + 1)) - 1; x != r || v != old {
104                         t.Fatalf("setting bit %#x: want %#x, got new %#x and old %#v", uint32(1<<i), r, x, v)
105                 }
106         }
107
108         // Start with every bit in array set to 0.
109         a := make([]uint32, 1<<12)
110
111         // Set every bit in array bit-by-bit in different goroutines.
112         done := make(chan bool)
113         for i := 0; i < 32; i++ {
114                 m := uint32(1 << i)
115                 go func() {
116                         for i := range a {
117                                 atomic.Or32(&a[i], m)
118                         }
119                         done <- true
120                 }()
121         }
122         for i := 0; i < 32; i++ {
123                 <-done
124         }
125
126         // Check that the array has been totally set.
127         for i, v := range a {
128                 if v != 0xffffffff {
129                         t.Fatalf("a[%v] not fully set: want %#x, got %#x", i, uint32(0xffffffff), v)
130                 }
131         }
132 }
133
134 func TestOr64(t *testing.T) {
135         // Basic sanity check.
136         x := uint64(0)
137         for i := uint64(0); i < 64; i++ {
138                 old := x
139                 v := atomic.Or64(&x, 1<<i)
140                 if r := (uint64(1) << (i + 1)) - 1; x != r || v != old {
141                         t.Fatalf("setting bit %#x: want %#x, got new %#x and old %#v", uint64(1<<i), r, x, v)
142                 }
143         }
144
145         // Start with every bit in array set to 0.
146         a := make([]uint64, 1<<12)
147
148         // Set every bit in array bit-by-bit in different goroutines.
149         done := make(chan bool)
150         for i := 0; i < 64; i++ {
151                 m := uint64(1 << i)
152                 go func() {
153                         for i := range a {
154                                 atomic.Or64(&a[i], m)
155                         }
156                         done <- true
157                 }()
158         }
159         for i := 0; i < 64; i++ {
160                 <-done
161         }
162
163         // Check that the array has been totally set.
164         for i, v := range a {
165                 if v != 0xffffffffffffffff {
166                         t.Fatalf("a[%v] not fully set: want %#x, got %#x", i, uint64(0xffffffffffffffff), v)
167                 }
168         }
169 }
170
171 func BenchmarkAnd32(b *testing.B) {
172         var x [128]uint32 // give x its own cache line
173         sink = &x
174         for i := 0; i < b.N; i++ {
175                 atomic.And32(&x[63], uint32(i))
176         }
177 }
178
179 func BenchmarkAnd32Parallel(b *testing.B) {
180         var x [128]uint32 // give x its own cache line
181         sink = &x
182         b.RunParallel(func(pb *testing.PB) {
183                 i := uint32(0)
184                 for pb.Next() {
185                         atomic.And32(&x[63], i)
186                         i++
187                 }
188         })
189 }
190
191 func BenchmarkAnd64(b *testing.B) {
192         var x [128]uint64 // give x its own cache line
193         sink = &x
194         for i := 0; i < b.N; i++ {
195                 atomic.And64(&x[63], uint64(i))
196         }
197 }
198
199 func BenchmarkAnd64Parallel(b *testing.B) {
200         var x [128]uint64 // give x its own cache line
201         sink = &x
202         b.RunParallel(func(pb *testing.PB) {
203                 i := uint64(0)
204                 for pb.Next() {
205                         atomic.And64(&x[63], i)
206                         i++
207                 }
208         })
209 }
210
211 func BenchmarkOr32(b *testing.B) {
212         var x [128]uint32 // give x its own cache line
213         sink = &x
214         for i := 0; i < b.N; i++ {
215                 atomic.Or32(&x[63], uint32(i))
216         }
217 }
218
219 func BenchmarkOr32Parallel(b *testing.B) {
220         var x [128]uint32 // give x its own cache line
221         sink = &x
222         b.RunParallel(func(pb *testing.PB) {
223                 i := uint32(0)
224                 for pb.Next() {
225                         atomic.Or32(&x[63], i)
226                         i++
227                 }
228         })
229 }
230
231 func BenchmarkOr64(b *testing.B) {
232         var x [128]uint64 // give x its own cache line
233         sink = &x
234         for i := 0; i < b.N; i++ {
235                 atomic.Or64(&x[63], uint64(i))
236         }
237 }
238
239 func BenchmarkOr64Parallel(b *testing.B) {
240         var x [128]uint64 // give x its own cache line
241         sink = &x
242         b.RunParallel(func(pb *testing.PB) {
243                 i := uint64(0)
244                 for pb.Next() {
245                         atomic.Or64(&x[63], i)
246                         i++
247                 }
248         })
249 }