...

Source file src/go.uber.org/atomic/stress_test.go

Documentation: go.uber.org/atomic

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package atomic
    22  
    23  import (
    24  	"errors"
    25  	"math"
    26  	"runtime"
    27  	"sync"
    28  	"sync/atomic"
    29  	"testing"
    30  	"time"
    31  )
    32  
    33  const (
    34  	_parallelism = 4
    35  	_iterations  = 1000
    36  )
    37  
    38  var _stressTests = map[string]func() func(){
    39  	"i32/std":  stressStdInt32,
    40  	"i32":      stressInt32,
    41  	"i64/std":  stressStdInt64,
    42  	"i64":      stressInt64,
    43  	"u32/std":  stressStdUint32,
    44  	"u32":      stressUint32,
    45  	"u64/std":  stressStdUint64,
    46  	"u64":      stressUint64,
    47  	"f64":      stressFloat64,
    48  	"bool":     stressBool,
    49  	"string":   stressString,
    50  	"duration": stressDuration,
    51  	"error":    stressError,
    52  	"time":     stressTime,
    53  }
    54  
    55  func TestStress(t *testing.T) {
    56  	for name, ff := range _stressTests {
    57  		t.Run(name, func(t *testing.T) {
    58  			defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
    59  
    60  			start := make(chan struct{})
    61  			var wg sync.WaitGroup
    62  			wg.Add(_parallelism)
    63  			f := ff()
    64  			for i := 0; i < _parallelism; i++ {
    65  				go func() {
    66  					defer wg.Done()
    67  					<-start
    68  					for j := 0; j < _iterations; j++ {
    69  						f()
    70  					}
    71  				}()
    72  			}
    73  			close(start)
    74  			wg.Wait()
    75  		})
    76  	}
    77  }
    78  
    79  func BenchmarkStress(b *testing.B) {
    80  	for name, ff := range _stressTests {
    81  		b.Run(name, func(b *testing.B) {
    82  			f := ff()
    83  
    84  			b.Run("serial", func(b *testing.B) {
    85  				for i := 0; i < b.N; i++ {
    86  					f()
    87  				}
    88  			})
    89  
    90  			b.Run("parallel", func(b *testing.B) {
    91  				b.RunParallel(func(pb *testing.PB) {
    92  					for pb.Next() {
    93  						f()
    94  					}
    95  				})
    96  			})
    97  		})
    98  	}
    99  }
   100  
   101  func stressStdInt32() func() {
   102  	var atom int32
   103  	return func() {
   104  		atomic.LoadInt32(&atom)
   105  		atomic.AddInt32(&atom, 1)
   106  		atomic.AddInt32(&atom, -2)
   107  		atomic.AddInt32(&atom, 1)
   108  		atomic.AddInt32(&atom, -1)
   109  		atomic.CompareAndSwapInt32(&atom, 1, 0)
   110  		atomic.SwapInt32(&atom, 5)
   111  		atomic.StoreInt32(&atom, 1)
   112  	}
   113  }
   114  
   115  func stressInt32() func() {
   116  	var atom Int32
   117  	return func() {
   118  		atom.Load()
   119  		atom.Add(1)
   120  		atom.Sub(2)
   121  		atom.Inc()
   122  		atom.Dec()
   123  		atom.CAS(1, 0)
   124  		atom.Swap(5)
   125  		atom.Store(1)
   126  	}
   127  }
   128  
   129  func stressStdInt64() func() {
   130  	var atom int64
   131  	return func() {
   132  		atomic.LoadInt64(&atom)
   133  		atomic.AddInt64(&atom, 1)
   134  		atomic.AddInt64(&atom, -2)
   135  		atomic.AddInt64(&atom, 1)
   136  		atomic.AddInt64(&atom, -1)
   137  		atomic.CompareAndSwapInt64(&atom, 1, 0)
   138  		atomic.SwapInt64(&atom, 5)
   139  		atomic.StoreInt64(&atom, 1)
   140  	}
   141  }
   142  
   143  func stressInt64() func() {
   144  	var atom Int64
   145  	return func() {
   146  		atom.Load()
   147  		atom.Add(1)
   148  		atom.Sub(2)
   149  		atom.Inc()
   150  		atom.Dec()
   151  		atom.CAS(1, 0)
   152  		atom.Swap(5)
   153  		atom.Store(1)
   154  	}
   155  }
   156  
   157  func stressStdUint32() func() {
   158  	var atom uint32
   159  	return func() {
   160  		atomic.LoadUint32(&atom)
   161  		atomic.AddUint32(&atom, 1)
   162  		// Adding `MaxUint32` is the same as subtracting 1
   163  		atomic.AddUint32(&atom, math.MaxUint32-1)
   164  		atomic.AddUint32(&atom, 1)
   165  		atomic.AddUint32(&atom, math.MaxUint32)
   166  		atomic.CompareAndSwapUint32(&atom, 1, 0)
   167  		atomic.SwapUint32(&atom, 5)
   168  		atomic.StoreUint32(&atom, 1)
   169  	}
   170  }
   171  
   172  func stressUint32() func() {
   173  	var atom Uint32
   174  	return func() {
   175  		atom.Load()
   176  		atom.Add(1)
   177  		atom.Sub(2)
   178  		atom.Inc()
   179  		atom.Dec()
   180  		atom.CAS(1, 0)
   181  		atom.Swap(5)
   182  		atom.Store(1)
   183  	}
   184  }
   185  
   186  func stressStdUint64() func() {
   187  	var atom uint64
   188  	return func() {
   189  		atomic.LoadUint64(&atom)
   190  		atomic.AddUint64(&atom, 1)
   191  		// Adding `MaxUint64` is the same as subtracting 1
   192  		atomic.AddUint64(&atom, math.MaxUint64-1)
   193  		atomic.AddUint64(&atom, 1)
   194  		atomic.AddUint64(&atom, math.MaxUint64)
   195  		atomic.CompareAndSwapUint64(&atom, 1, 0)
   196  		atomic.SwapUint64(&atom, 5)
   197  		atomic.StoreUint64(&atom, 1)
   198  	}
   199  }
   200  
   201  func stressUint64() func() {
   202  	var atom Uint64
   203  	return func() {
   204  		atom.Load()
   205  		atom.Add(1)
   206  		atom.Sub(2)
   207  		atom.Inc()
   208  		atom.Dec()
   209  		atom.CAS(1, 0)
   210  		atom.Swap(5)
   211  		atom.Store(1)
   212  	}
   213  }
   214  
   215  func stressFloat64() func() {
   216  	var atom Float64
   217  	return func() {
   218  		atom.Load()
   219  		atom.CAS(1.0, 0.1)
   220  		atom.Add(1.1)
   221  		atom.Sub(0.2)
   222  		atom.Store(1.0)
   223  	}
   224  }
   225  
   226  func stressBool() func() {
   227  	var atom Bool
   228  	return func() {
   229  		atom.Load()
   230  		atom.Store(false)
   231  		atom.Swap(true)
   232  		atom.CAS(true, false)
   233  		atom.CAS(true, false)
   234  		atom.Load()
   235  		atom.Toggle()
   236  		atom.Toggle()
   237  	}
   238  }
   239  
   240  func stressString() func() {
   241  	var atom String
   242  	return func() {
   243  		atom.Load()
   244  		atom.Store("abc")
   245  		atom.Load()
   246  		atom.Store("def")
   247  		atom.Load()
   248  		atom.Store("")
   249  	}
   250  }
   251  
   252  func stressDuration() func() {
   253  	var atom = NewDuration(0)
   254  	return func() {
   255  		atom.Load()
   256  		atom.Add(1)
   257  		atom.Sub(2)
   258  		atom.CAS(1, 0)
   259  		atom.Swap(5)
   260  		atom.Store(1)
   261  	}
   262  }
   263  
   264  func stressError() func() {
   265  	var atom = NewError(nil)
   266  	var err1 = errors.New("err1")
   267  	var err2 = errors.New("err2")
   268  	return func() {
   269  		atom.Load()
   270  		atom.Store(err1)
   271  		atom.Load()
   272  		atom.Store(err2)
   273  		atom.Load()
   274  		atom.Store(nil)
   275  	}
   276  }
   277  
   278  func stressTime() func() {
   279  	var atom = NewTime(time.Date(2021, 6, 17, 9, 0, 0, 0, time.UTC))
   280  	var dayAgo = time.Date(2021, 6, 16, 9, 0, 0, 0, time.UTC)
   281  	var weekAgo = time.Date(2021, 6, 10, 9, 0, 0, 0, time.UTC)
   282  	return func() {
   283  		atom.Load()
   284  		atom.Store(dayAgo)
   285  		atom.Load()
   286  		atom.Store(weekAgo)
   287  		atom.Store(time.Time{})
   288  	}
   289  }
   290  

View as plain text