benchmark_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. package hashmap
  2. import (
  3. "strconv"
  4. "sync"
  5. "sync/atomic"
  6. "testing"
  7. )
  8. const benchmarkItemCount = 1 << 10 // 1024
  9. func setupHashMap(b *testing.B) *HashMap {
  10. m := &HashMap{}
  11. for i := uintptr(0); i < benchmarkItemCount; i++ {
  12. m.Set(i, i)
  13. }
  14. b.ResetTimer()
  15. return m
  16. }
  17. func setupHashMapString(b *testing.B) (*HashMap, []string) {
  18. m := &HashMap{}
  19. keys := make([]string, benchmarkItemCount)
  20. for i := 0; i < benchmarkItemCount; i++ {
  21. s := strconv.Itoa(i)
  22. m.Set(s, s)
  23. keys[i] = s
  24. }
  25. b.ResetTimer()
  26. return m, keys
  27. }
  28. func setupHashMapHashedKey(b *testing.B) *HashMap {
  29. m := &HashMap{}
  30. log := log2(uintptr(benchmarkItemCount))
  31. for i := uintptr(0); i < benchmarkItemCount; i++ {
  32. hash := i << (strconv.IntSize - log)
  33. m.SetHashedKey(hash, i)
  34. }
  35. b.ResetTimer()
  36. return m
  37. }
  38. func setupGoMap(b *testing.B) map[uintptr]uintptr {
  39. m := make(map[uintptr]uintptr)
  40. for i := uintptr(0); i < benchmarkItemCount; i++ {
  41. m[i] = i
  42. }
  43. b.ResetTimer()
  44. return m
  45. }
  46. func setupGoSyncMap(b *testing.B) *sync.Map {
  47. m := &sync.Map{}
  48. for i := uintptr(0); i < benchmarkItemCount; i++ {
  49. m.Store(i, i)
  50. }
  51. b.ResetTimer()
  52. return m
  53. }
  54. func setupGoMapString(b *testing.B) (map[string]string, []string) {
  55. m := make(map[string]string)
  56. keys := make([]string, benchmarkItemCount)
  57. for i := 0; i < benchmarkItemCount; i++ {
  58. s := strconv.Itoa(i)
  59. m[s] = s
  60. keys[i] = s
  61. }
  62. b.ResetTimer()
  63. return m, keys
  64. }
  65. func BenchmarkReadHashMapUint(b *testing.B) {
  66. m := setupHashMap(b)
  67. b.RunParallel(func(pb *testing.PB) {
  68. for pb.Next() {
  69. for i := uintptr(0); i < benchmarkItemCount; i++ {
  70. j, _ := m.GetUintKey(i)
  71. if j != i {
  72. b.Fail()
  73. }
  74. }
  75. }
  76. })
  77. }
  78. func BenchmarkReadHashMapWithWritesUint(b *testing.B) {
  79. m := setupHashMap(b)
  80. var writer uintptr
  81. b.RunParallel(func(pb *testing.PB) {
  82. // use 1 thread as writer
  83. if atomic.CompareAndSwapUintptr(&writer, 0, 1) {
  84. for pb.Next() {
  85. for i := uintptr(0); i < benchmarkItemCount; i++ {
  86. m.Set(i, i)
  87. }
  88. }
  89. } else {
  90. for pb.Next() {
  91. for i := uintptr(0); i < benchmarkItemCount; i++ {
  92. j, _ := m.GetUintKey(i)
  93. if j != i {
  94. b.Fail()
  95. }
  96. }
  97. }
  98. }
  99. })
  100. }
  101. func BenchmarkReadHashMapString(b *testing.B) {
  102. m, keys := setupHashMapString(b)
  103. b.RunParallel(func(pb *testing.PB) {
  104. for pb.Next() {
  105. for i := 0; i < benchmarkItemCount; i++ {
  106. s := keys[i]
  107. sVal, _ := m.GetStringKey(s)
  108. if sVal != s {
  109. b.Fail()
  110. }
  111. }
  112. }
  113. })
  114. }
  115. func BenchmarkReadHashMapInterface(b *testing.B) {
  116. m := setupHashMap(b)
  117. b.RunParallel(func(pb *testing.PB) {
  118. for pb.Next() {
  119. for i := uintptr(0); i < benchmarkItemCount; i++ {
  120. j, _ := m.Get(i)
  121. if j != i {
  122. b.Fail()
  123. }
  124. }
  125. }
  126. })
  127. }
  128. func BenchmarkReadHashMapHashedKey(b *testing.B) {
  129. m := setupHashMapHashedKey(b)
  130. log := log2(uintptr(benchmarkItemCount))
  131. b.RunParallel(func(pb *testing.PB) {
  132. for pb.Next() {
  133. for i := uintptr(0); i < benchmarkItemCount; i++ {
  134. hash := i << (strconv.IntSize - log)
  135. j, _ := m.GetHashedKey(hash)
  136. if j != i {
  137. b.Fail()
  138. }
  139. }
  140. }
  141. })
  142. }
  143. func BenchmarkReadGoMapUintUnsafe(b *testing.B) {
  144. m := setupGoMap(b)
  145. b.RunParallel(func(pb *testing.PB) {
  146. for pb.Next() {
  147. for i := uintptr(0); i < benchmarkItemCount; i++ {
  148. j := m[i]
  149. if j != i {
  150. b.Fail()
  151. }
  152. }
  153. }
  154. })
  155. }
  156. func BenchmarkReadGoMapUintMutex(b *testing.B) {
  157. m := setupGoMap(b)
  158. l := &sync.RWMutex{}
  159. b.RunParallel(func(pb *testing.PB) {
  160. for pb.Next() {
  161. for i := uintptr(0); i < benchmarkItemCount; i++ {
  162. l.RLock()
  163. j := m[i]
  164. l.RUnlock()
  165. if j != i {
  166. b.Fail()
  167. }
  168. }
  169. }
  170. })
  171. }
  172. func BenchmarkReadGoMapWithWritesUintMutex(b *testing.B) {
  173. m := setupGoMap(b)
  174. l := &sync.RWMutex{}
  175. var writer uintptr
  176. b.RunParallel(func(pb *testing.PB) {
  177. // use 1 thread as writer
  178. if atomic.CompareAndSwapUintptr(&writer, 0, 1) {
  179. for pb.Next() {
  180. for i := uintptr(0); i < benchmarkItemCount; i++ {
  181. l.Lock()
  182. m[i] = i
  183. l.Unlock()
  184. }
  185. }
  186. } else {
  187. for pb.Next() {
  188. for i := uintptr(0); i < benchmarkItemCount; i++ {
  189. l.RLock()
  190. j := m[i]
  191. l.RUnlock()
  192. if j != i {
  193. b.Fail()
  194. }
  195. }
  196. }
  197. }
  198. })
  199. }
  200. func BenchmarkReadGoSyncMapUint(b *testing.B) {
  201. m := setupGoSyncMap(b)
  202. b.RunParallel(func(pb *testing.PB) {
  203. for pb.Next() {
  204. for i := uintptr(0); i < benchmarkItemCount; i++ {
  205. j, _ := m.Load(i)
  206. if j != i {
  207. b.Fail()
  208. }
  209. }
  210. }
  211. })
  212. }
  213. func BenchmarkReadGoSyncMapWithWritesUint(b *testing.B) {
  214. m := setupGoSyncMap(b)
  215. var writer uintptr
  216. b.RunParallel(func(pb *testing.PB) {
  217. // use 1 thread as writer
  218. if atomic.CompareAndSwapUintptr(&writer, 0, 1) {
  219. for pb.Next() {
  220. for i := uintptr(0); i < benchmarkItemCount; i++ {
  221. m.Store(i, i)
  222. }
  223. }
  224. } else {
  225. for pb.Next() {
  226. for i := uintptr(0); i < benchmarkItemCount; i++ {
  227. j, _ := m.Load(i)
  228. if j != i {
  229. b.Fail()
  230. }
  231. }
  232. }
  233. }
  234. })
  235. }
  236. func BenchmarkReadGoMapStringUnsafe(b *testing.B) {
  237. m, keys := setupGoMapString(b)
  238. b.RunParallel(func(pb *testing.PB) {
  239. for pb.Next() {
  240. for i := 0; i < benchmarkItemCount; i++ {
  241. s := keys[i]
  242. sVal := m[s]
  243. if s != sVal {
  244. b.Fail()
  245. }
  246. }
  247. }
  248. })
  249. }
  250. func BenchmarkReadGoMapStringMutex(b *testing.B) {
  251. m, keys := setupGoMapString(b)
  252. l := &sync.RWMutex{}
  253. b.RunParallel(func(pb *testing.PB) {
  254. for pb.Next() {
  255. for i := 0; i < benchmarkItemCount; i++ {
  256. s := keys[i]
  257. l.RLock()
  258. sVal := m[s]
  259. l.RUnlock()
  260. if s != sVal {
  261. b.Fail()
  262. }
  263. }
  264. }
  265. })
  266. }
  267. func BenchmarkWriteHashMapUint(b *testing.B) {
  268. m := &HashMap{}
  269. for n := 0; n < b.N; n++ {
  270. for i := uintptr(0); i < benchmarkItemCount; i++ {
  271. m.Set(i, i)
  272. }
  273. }
  274. }
  275. func BenchmarkWriteHashMapHashedKey(b *testing.B) {
  276. m := &HashMap{}
  277. log := log2(uintptr(benchmarkItemCount))
  278. for n := 0; n < b.N; n++ {
  279. for i := uintptr(0); i < benchmarkItemCount; i++ {
  280. hash := i << (strconv.IntSize - log)
  281. m.SetHashedKey(hash, i)
  282. }
  283. }
  284. }
  285. func BenchmarkWriteGoMapMutexUint(b *testing.B) {
  286. m := make(map[uintptr]uintptr)
  287. l := &sync.RWMutex{}
  288. for n := 0; n < b.N; n++ {
  289. for i := uintptr(0); i < benchmarkItemCount; i++ {
  290. l.Lock()
  291. m[i] = i
  292. l.Unlock()
  293. }
  294. }
  295. }
  296. func BenchmarkWriteGoSyncMapUint(b *testing.B) {
  297. m := &sync.Map{}
  298. for n := 0; n < b.N; n++ {
  299. for i := uintptr(0); i < benchmarkItemCount; i++ {
  300. m.Store(i, i)
  301. }
  302. }
  303. }