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