stress_test.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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. package atomic
  21. import (
  22. "errors"
  23. "math"
  24. "runtime"
  25. "sync"
  26. "sync/atomic"
  27. "testing"
  28. )
  29. const (
  30. _parallelism = 4
  31. _iterations = 1000
  32. )
  33. var _stressTests = map[string]func() func(){
  34. "i32/std": stressStdInt32,
  35. "i32": stressInt32,
  36. "i64/std": stressStdInt32,
  37. "i64": stressInt64,
  38. "u32/std": stressStdUint32,
  39. "u32": stressUint32,
  40. "u64/std": stressStdUint64,
  41. "u64": stressUint64,
  42. "f64": stressFloat64,
  43. "bool": stressBool,
  44. "string": stressString,
  45. "duration": stressDuration,
  46. "error": stressError,
  47. }
  48. func TestStress(t *testing.T) {
  49. for name, ff := range _stressTests {
  50. t.Run(name, func(t *testing.T) {
  51. defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
  52. start := make(chan struct{})
  53. var wg sync.WaitGroup
  54. wg.Add(_parallelism)
  55. f := ff()
  56. for i := 0; i < _parallelism; i++ {
  57. go func() {
  58. defer wg.Done()
  59. <-start
  60. for j := 0; j < _iterations; j++ {
  61. f()
  62. }
  63. }()
  64. }
  65. close(start)
  66. wg.Wait()
  67. })
  68. }
  69. }
  70. func BenchmarkStress(b *testing.B) {
  71. for name, ff := range _stressTests {
  72. b.Run(name, func(b *testing.B) {
  73. f := ff()
  74. b.Run("serial", func(b *testing.B) {
  75. for i := 0; i < b.N; i++ {
  76. f()
  77. }
  78. })
  79. b.Run("parallel", func(b *testing.B) {
  80. b.RunParallel(func(pb *testing.PB) {
  81. for pb.Next() {
  82. f()
  83. }
  84. })
  85. })
  86. })
  87. }
  88. }
  89. func stressStdInt32() func() {
  90. var atom int32
  91. return func() {
  92. atomic.LoadInt32(&atom)
  93. atomic.AddInt32(&atom, 1)
  94. atomic.AddInt32(&atom, -2)
  95. atomic.AddInt32(&atom, 1)
  96. atomic.AddInt32(&atom, -1)
  97. atomic.CompareAndSwapInt32(&atom, 1, 0)
  98. atomic.SwapInt32(&atom, 5)
  99. atomic.StoreInt32(&atom, 1)
  100. }
  101. }
  102. func stressInt32() func() {
  103. var atom Int32
  104. return func() {
  105. atom.Load()
  106. atom.Add(1)
  107. atom.Sub(2)
  108. atom.Inc()
  109. atom.Dec()
  110. atom.CAS(1, 0)
  111. atom.Swap(5)
  112. atom.Store(1)
  113. }
  114. }
  115. func stressStdInt64() func() {
  116. var atom int64
  117. return func() {
  118. atomic.LoadInt64(&atom)
  119. atomic.AddInt64(&atom, 1)
  120. atomic.AddInt64(&atom, -2)
  121. atomic.AddInt64(&atom, 1)
  122. atomic.AddInt64(&atom, -1)
  123. atomic.CompareAndSwapInt64(&atom, 1, 0)
  124. atomic.SwapInt64(&atom, 5)
  125. atomic.StoreInt64(&atom, 1)
  126. }
  127. }
  128. func stressInt64() func() {
  129. var atom Int64
  130. return func() {
  131. atom.Load()
  132. atom.Add(1)
  133. atom.Sub(2)
  134. atom.Inc()
  135. atom.Dec()
  136. atom.CAS(1, 0)
  137. atom.Swap(5)
  138. atom.Store(1)
  139. }
  140. }
  141. func stressStdUint32() func() {
  142. var atom uint32
  143. return func() {
  144. atomic.LoadUint32(&atom)
  145. atomic.AddUint32(&atom, 1)
  146. // Adding `MaxUint32` is the same as subtracting 1
  147. atomic.AddUint32(&atom, math.MaxUint32-1)
  148. atomic.AddUint32(&atom, 1)
  149. atomic.AddUint32(&atom, math.MaxUint32)
  150. atomic.CompareAndSwapUint32(&atom, 1, 0)
  151. atomic.SwapUint32(&atom, 5)
  152. atomic.StoreUint32(&atom, 1)
  153. }
  154. }
  155. func stressUint32() func() {
  156. var atom Uint32
  157. return func() {
  158. atom.Load()
  159. atom.Add(1)
  160. atom.Sub(2)
  161. atom.Inc()
  162. atom.Dec()
  163. atom.CAS(1, 0)
  164. atom.Swap(5)
  165. atom.Store(1)
  166. }
  167. }
  168. func stressStdUint64() func() {
  169. var atom uint64
  170. return func() {
  171. atomic.LoadUint64(&atom)
  172. atomic.AddUint64(&atom, 1)
  173. // Adding `MaxUint64` is the same as subtracting 1
  174. atomic.AddUint64(&atom, math.MaxUint64-1)
  175. atomic.AddUint64(&atom, 1)
  176. atomic.AddUint64(&atom, math.MaxUint64)
  177. atomic.CompareAndSwapUint64(&atom, 1, 0)
  178. atomic.SwapUint64(&atom, 5)
  179. atomic.StoreUint64(&atom, 1)
  180. }
  181. }
  182. func stressUint64() func() {
  183. var atom Uint64
  184. return func() {
  185. atom.Load()
  186. atom.Add(1)
  187. atom.Sub(2)
  188. atom.Inc()
  189. atom.Dec()
  190. atom.CAS(1, 0)
  191. atom.Swap(5)
  192. atom.Store(1)
  193. }
  194. }
  195. func stressFloat64() func() {
  196. var atom Float64
  197. return func() {
  198. atom.Load()
  199. atom.CAS(1.0, 0.1)
  200. atom.Add(1.1)
  201. atom.Sub(0.2)
  202. atom.Store(1.0)
  203. }
  204. }
  205. func stressBool() func() {
  206. var atom Bool
  207. return func() {
  208. atom.Load()
  209. atom.Store(false)
  210. atom.Swap(true)
  211. atom.CAS(true, false)
  212. atom.CAS(true, false)
  213. atom.Load()
  214. atom.Toggle()
  215. atom.Toggle()
  216. }
  217. }
  218. func stressString() func() {
  219. var atom String
  220. return func() {
  221. atom.Load()
  222. atom.Store("abc")
  223. atom.Load()
  224. atom.Store("def")
  225. atom.Load()
  226. atom.Store("")
  227. }
  228. }
  229. func stressDuration() func() {
  230. var atom = NewDuration(0)
  231. return func() {
  232. atom.Load()
  233. atom.Add(1)
  234. atom.Sub(2)
  235. atom.CAS(1, 0)
  236. atom.Swap(5)
  237. atom.Store(1)
  238. }
  239. }
  240. func stressError() func() {
  241. var atom = NewError(nil)
  242. var err1 = errors.New("err1")
  243. var err2 = errors.New("err2")
  244. return func() {
  245. atom.Load()
  246. atom.Store(err1)
  247. atom.Load()
  248. atom.Store(err2)
  249. atom.Load()
  250. atom.Store(nil)
  251. }
  252. }