Source file src/internal/runtime/atomic/atomic_andor_test.go

     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  	"internal/runtime/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  	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  
    95  func 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  
   132  func 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  
   170  func 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  
   178  func 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  
   190  func 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  
   198  func 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  
   210  func 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  
   218  func 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  
   230  func 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  
   238  func 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  

View as plain text