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