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