Source file src/runtime/internal/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  	"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  }
   247  

View as plain text