dotproduct_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // dotproduct_test.go
  2. package dotproduct
  3. import (
  4. "runtime"
  5. "sync/atomic"
  6. "testing"
  7. "unsafe"
  8. "golang.org/x/sys/cpu"
  9. )
  10. func TestAVX2hasAVX(t *testing.T) {
  11. if runtime.GOARCH == "amd64" {
  12. if cpu.X86.HasAVX2 && !cpu.X86.HasAVX {
  13. t.Fatal("HasAVX expected true, got false")
  14. } else if !cpu.X86.HasAVX2 {
  15. t.Log("HasAVX2=False")
  16. }
  17. }
  18. }
  19. func TestAVX512HasAVX2AndAVX(t *testing.T) {
  20. if runtime.GOARCH == "amd64" {
  21. if cpu.X86.HasAVX512 && !cpu.X86.HasAVX {
  22. t.Fatal("HasAVX expected true, got false")
  23. }
  24. if cpu.X86.HasAVX512 && !cpu.X86.HasAVX2 {
  25. t.Fatal("HasAVX2 expected true, got false")
  26. }
  27. if !cpu.X86.HasAVX512 {
  28. t.Log("HasAVX512=False")
  29. }
  30. }
  31. }
  32. func DotProduct(a []int32, b []int32, N int32) (sum int32) {
  33. //N := len(a)
  34. for i := int32(0); i < N; i++ {
  35. sum += a[i] * b[i]
  36. }
  37. return
  38. }
  39. func TestSumAsm(t *testing.T) {
  40. if runtime.GOARCH == "amd64" {
  41. d3 := make([]uint64, 24)
  42. var sumGo uint64
  43. for i := 0; i < 24; i++ {
  44. d3[i] = uint64(i + 1)
  45. sumGo = sumGo + d3[i]
  46. }
  47. sumAsm := Sum(d3)
  48. t.Log("sumGo ", sumGo, ", sumAsm ", sumAsm)
  49. } else {
  50. t.Skip("test case *TestSumAsm* not applicable")
  51. }
  52. }
  53. func TestDotProductAsm(t *testing.T) {
  54. if runtime.GOARCH == "amd64" {
  55. const len32 = 24
  56. d1 := make([]int32, len32)
  57. d2 := make([]int32, len32)
  58. for i := 0; i < len32; i++ {
  59. d1[i] = int32(i + 1)
  60. d2[i] = int32(2 * i)
  61. }
  62. sumGo := DotProduct(d1, d2, len32)
  63. sumAsm := DotProductAsm(d1, d2, len32)
  64. t.Log("DotProductGo ", sumGo, ", DotProductAsm ", sumAsm)
  65. } else {
  66. t.Skip("test case *TestDotProductAsm* not applicable")
  67. }
  68. }
  69. func TestDotProductAsmAvx(t *testing.T) {
  70. if runtime.GOARCH == "amd64" && cpu.X86.HasAVX2 {
  71. const len32 = 32
  72. d1 := make([]int32, len32)
  73. d2 := make([]int32, len32)
  74. for i := 0; i < len32; i++ {
  75. d1[i] = int32(i + 1)
  76. d2[i] = int32(2 * i)
  77. }
  78. sumGo := DotProduct(d1, d2, len32)
  79. sumAvx := DotProductAsmAvx(d1, d2, len32)
  80. t.Log("DotProductGo ", sumGo, ", DotProductAvx ", sumAvx)
  81. } else {
  82. t.Skip("test case *TestDotProductAsmAvx* not applicable")
  83. }
  84. }
  85. func BenchmarkSum(b *testing.B) {
  86. const len32 = 4096
  87. d1 := make([]uint64, len32)
  88. for i := 0; i < len32; i++ {
  89. d1[i] = uint64(i + 1)
  90. }
  91. var sum2 uint64 = 0
  92. b.SetBytes(int64(len32 * unsafe.Sizeof(uint64(0))))
  93. b.ResetTimer()
  94. for i := 0; i < b.N; i++ {
  95. sum2 += SumGo(d1) % len32
  96. }
  97. }
  98. func BenchmarkSumParallel(b *testing.B) {
  99. const len32 = 4096
  100. d1 := make([]uint64, len32)
  101. for i := 0; i < len32; i++ {
  102. d1[i] = uint64(i + 1)
  103. }
  104. b.SetBytes(int64(len32 * unsafe.Sizeof(uint64(0))))
  105. b.ResetTimer()
  106. b.RunParallel(func(pb *testing.PB) {
  107. for pb.Next() {
  108. var sum2 uint64 = 0
  109. sum2 += SumGo(d1) % len32
  110. }
  111. })
  112. }
  113. func BenchmarkSumAsm(b *testing.B) {
  114. if runtime.GOARCH == "amd64" {
  115. const len32 = 4096
  116. d1 := make([]uint64, len32)
  117. for i := 0; i < len32; i++ {
  118. d1[i] = uint64(i + 1)
  119. }
  120. var sum2 uint64 = 0
  121. b.SetBytes(int64(len32 * unsafe.Sizeof(uint64(0))))
  122. b.ResetTimer()
  123. for i := 0; i < b.N; i++ {
  124. sum2 += Sum(d1) % len32
  125. }
  126. } else {
  127. b.Skip("test case *BenchmarkSumAsm* not applicable")
  128. }
  129. }
  130. func BenchmarkSumAsmParallel(b *testing.B) {
  131. if runtime.GOARCH == "amd64" {
  132. const len32 = 4096
  133. d1 := make([]uint64, len32)
  134. for i := 0; i < len32; i++ {
  135. d1[i] = uint64(i + 1)
  136. }
  137. //glob := b.N
  138. b.SetBytes(int64(len32 * unsafe.Sizeof(uint64(0))))
  139. b.ResetTimer()
  140. b.RunParallel(func(pb *testing.PB) {
  141. for pb.Next() {
  142. var sum2 uint64 = 0
  143. //for i := 0; i < 24; i++ {
  144. sum2 += Sum(d1) % len32
  145. //}
  146. }
  147. })
  148. } else {
  149. b.Skip("test case *BenchmarkSumAsm* not applicable")
  150. }
  151. }
  152. func SumGo(a []uint64) (sum uint64) {
  153. N := len(a)
  154. for i := 0; i < N; i++ {
  155. sum += a[i]
  156. }
  157. return
  158. }
  159. func BenchmarkDotProduct(b *testing.B) {
  160. const len32 = 1024
  161. d1 := make([]int32, len32)
  162. d2 := make([]int32, len32)
  163. for i := 0; i < len32; i++ {
  164. d1[i] = int32(i + 1)
  165. d2[i] = int32(2 * i)
  166. }
  167. var sum2 int32 = 0
  168. b.SetBytes(int64(len32 * unsafe.Sizeof(int32(0))))
  169. b.ResetTimer()
  170. for i := 0; i < b.N; i++ {
  171. sum2 += DotProduct(d1, d2, len32) % len32
  172. }
  173. }
  174. func BenchmarkDotProductAsm(b *testing.B) {
  175. if runtime.GOARCH == "amd64" {
  176. const len32 = 1024
  177. d1 := make([]int32, len32)
  178. d2 := make([]int32, len32)
  179. for i := 0; i < len32; i++ {
  180. d1[i] = int32(i + 1)
  181. d2[i] = int32(2 * i)
  182. }
  183. var sum2 int32 = 0
  184. b.SetBytes(int64(len32 * unsafe.Sizeof(int32(0))))
  185. b.ResetTimer()
  186. for i := 0; i < b.N; i++ {
  187. sum2 += DotProductAsm(d1, d2, len32) % len32
  188. }
  189. } else {
  190. b.Skip("test case *BenchmarkDotProductAsm* not applicable")
  191. }
  192. }
  193. func BenchmarkDotProductAsmAvx2(b *testing.B) {
  194. if runtime.GOARCH == "amd64" && cpu.X86.HasAVX2 {
  195. const len32 = 1024
  196. d1 := make([]int32, len32)
  197. d2 := make([]int32, len32)
  198. for i := 0; i < len32; i++ {
  199. d1[i] = int32(i + 1)
  200. d2[i] = int32(2 * i)
  201. }
  202. var sum2 int32 = 0
  203. b.SetBytes(int64(len32 * unsafe.Sizeof(int32(0))))
  204. b.ResetTimer()
  205. for i := 0; i < b.N; i++ {
  206. sum2 += DotProductAsmAvx(d1, d2, len32) % len32
  207. }
  208. } else {
  209. b.Skip("test case *BenchmarkDotProductAsmAvx2* not applicable")
  210. }
  211. }
  212. func BenchmarkDotProductAsmAvx2Parallel(b *testing.B) {
  213. if runtime.GOARCH == "amd64" && cpu.X86.HasAVX2 {
  214. const len32 = 1024
  215. d1 := make([]int32, len32)
  216. d2 := make([]int32, len32)
  217. for i := 0; i < len32; i++ {
  218. d1[i] = int32(i + 1)
  219. d2[i] = int32(2 * i)
  220. }
  221. b.SetBytes(int64(len32 * unsafe.Sizeof(int32(0))))
  222. b.ResetTimer()
  223. b.RunParallel(func(pb *testing.PB) {
  224. for pb.Next() {
  225. var sum2 int32 = 0
  226. //for i := 0; i < 24; i++ {
  227. sum2 += DotProductAsmAvx(d1, d2, len32) % len32
  228. //}
  229. }
  230. })
  231. } else {
  232. b.Skip("test case *BenchmarkDotProductAsmAvx2* not applicable")
  233. }
  234. }
  235. func BenchmarkHowItWorksParallel(b *testing.B) {
  236. procs := uint32(0)
  237. iters := uint64(0)
  238. //b.SetParallelism(3) //number of goroutine to each b.RunParallel
  239. b.SetBytes(int64(4 * unsafe.Sizeof(uint64(0))))
  240. b.ResetTimer()
  241. b.RunParallel(func(pb *testing.PB) {
  242. atomic.AddUint32(&procs, 1)
  243. for pb.Next() {
  244. atomic.AddUint64(&iters, 1)
  245. }
  246. })
  247. b.Log("goroutine count :", procs, ", retrial count :", iters)
  248. }