Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

217 wiersze
4.8 KiB

  1. // Copyright 2016 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. package syncmap_test
  5. import (
  6. "fmt"
  7. "reflect"
  8. "sync/atomic"
  9. "testing"
  10. "golang.org/x/sync/syncmap"
  11. )
  12. type bench struct {
  13. setup func(*testing.B, mapInterface)
  14. perG func(b *testing.B, pb *testing.PB, i int, m mapInterface)
  15. }
  16. func benchMap(b *testing.B, bench bench) {
  17. for _, m := range [...]mapInterface{&DeepCopyMap{}, &RWMutexMap{}, &syncmap.Map{}} {
  18. b.Run(fmt.Sprintf("%T", m), func(b *testing.B) {
  19. m = reflect.New(reflect.TypeOf(m).Elem()).Interface().(mapInterface)
  20. if bench.setup != nil {
  21. bench.setup(b, m)
  22. }
  23. b.ResetTimer()
  24. var i int64
  25. b.RunParallel(func(pb *testing.PB) {
  26. id := int(atomic.AddInt64(&i, 1) - 1)
  27. bench.perG(b, pb, id*b.N, m)
  28. })
  29. })
  30. }
  31. }
  32. func BenchmarkLoadMostlyHits(b *testing.B) {
  33. const hits, misses = 1023, 1
  34. benchMap(b, bench{
  35. setup: func(_ *testing.B, m mapInterface) {
  36. for i := 0; i < hits; i++ {
  37. m.LoadOrStore(i, i)
  38. }
  39. // Prime the map to get it into a steady state.
  40. for i := 0; i < hits*2; i++ {
  41. m.Load(i % hits)
  42. }
  43. },
  44. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  45. for ; pb.Next(); i++ {
  46. m.Load(i % (hits + misses))
  47. }
  48. },
  49. })
  50. }
  51. func BenchmarkLoadMostlyMisses(b *testing.B) {
  52. const hits, misses = 1, 1023
  53. benchMap(b, bench{
  54. setup: func(_ *testing.B, m mapInterface) {
  55. for i := 0; i < hits; i++ {
  56. m.LoadOrStore(i, i)
  57. }
  58. // Prime the map to get it into a steady state.
  59. for i := 0; i < hits*2; i++ {
  60. m.Load(i % hits)
  61. }
  62. },
  63. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  64. for ; pb.Next(); i++ {
  65. m.Load(i % (hits + misses))
  66. }
  67. },
  68. })
  69. }
  70. func BenchmarkLoadOrStoreBalanced(b *testing.B) {
  71. const hits, misses = 128, 128
  72. benchMap(b, bench{
  73. setup: func(b *testing.B, m mapInterface) {
  74. if _, ok := m.(*DeepCopyMap); ok {
  75. b.Skip("DeepCopyMap has quadratic running time.")
  76. }
  77. for i := 0; i < hits; i++ {
  78. m.LoadOrStore(i, i)
  79. }
  80. // Prime the map to get it into a steady state.
  81. for i := 0; i < hits*2; i++ {
  82. m.Load(i % hits)
  83. }
  84. },
  85. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  86. for ; pb.Next(); i++ {
  87. j := i % (hits + misses)
  88. if j < hits {
  89. if _, ok := m.LoadOrStore(j, i); !ok {
  90. b.Fatalf("unexpected miss for %v", j)
  91. }
  92. } else {
  93. if v, loaded := m.LoadOrStore(i, i); loaded {
  94. b.Fatalf("failed to store %v: existing value %v", i, v)
  95. }
  96. }
  97. }
  98. },
  99. })
  100. }
  101. func BenchmarkLoadOrStoreUnique(b *testing.B) {
  102. benchMap(b, bench{
  103. setup: func(b *testing.B, m mapInterface) {
  104. if _, ok := m.(*DeepCopyMap); ok {
  105. b.Skip("DeepCopyMap has quadratic running time.")
  106. }
  107. },
  108. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  109. for ; pb.Next(); i++ {
  110. m.LoadOrStore(i, i)
  111. }
  112. },
  113. })
  114. }
  115. func BenchmarkLoadOrStoreCollision(b *testing.B) {
  116. benchMap(b, bench{
  117. setup: func(_ *testing.B, m mapInterface) {
  118. m.LoadOrStore(0, 0)
  119. },
  120. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  121. for ; pb.Next(); i++ {
  122. m.LoadOrStore(0, 0)
  123. }
  124. },
  125. })
  126. }
  127. func BenchmarkRange(b *testing.B) {
  128. const mapSize = 1 << 10
  129. benchMap(b, bench{
  130. setup: func(_ *testing.B, m mapInterface) {
  131. for i := 0; i < mapSize; i++ {
  132. m.Store(i, i)
  133. }
  134. },
  135. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  136. for ; pb.Next(); i++ {
  137. m.Range(func(_, _ interface{}) bool { return true })
  138. }
  139. },
  140. })
  141. }
  142. // BenchmarkAdversarialAlloc tests performance when we store a new value
  143. // immediately whenever the map is promoted to clean and otherwise load a
  144. // unique, missing key.
  145. //
  146. // This forces the Load calls to always acquire the map's mutex.
  147. func BenchmarkAdversarialAlloc(b *testing.B) {
  148. benchMap(b, bench{
  149. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  150. var stores, loadsSinceStore int64
  151. for ; pb.Next(); i++ {
  152. m.Load(i)
  153. if loadsSinceStore++; loadsSinceStore > stores {
  154. m.LoadOrStore(i, stores)
  155. loadsSinceStore = 0
  156. stores++
  157. }
  158. }
  159. },
  160. })
  161. }
  162. // BenchmarkAdversarialDelete tests performance when we periodically delete
  163. // one key and add a different one in a large map.
  164. //
  165. // This forces the Load calls to always acquire the map's mutex and periodically
  166. // makes a full copy of the map despite changing only one entry.
  167. func BenchmarkAdversarialDelete(b *testing.B) {
  168. const mapSize = 1 << 10
  169. benchMap(b, bench{
  170. setup: func(_ *testing.B, m mapInterface) {
  171. for i := 0; i < mapSize; i++ {
  172. m.Store(i, i)
  173. }
  174. },
  175. perG: func(b *testing.B, pb *testing.PB, i int, m mapInterface) {
  176. for ; pb.Next(); i++ {
  177. m.Load(i)
  178. if i%mapSize == 0 {
  179. m.Range(func(k, _ interface{}) bool {
  180. m.Delete(k)
  181. return false
  182. })
  183. m.Store(i, i)
  184. }
  185. }
  186. },
  187. })
  188. }