baseline.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /*
  2. * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
  3. * SPDX-License-Identifier: Apache-2.0
  4. */
  5. package simd
  6. import (
  7. "fmt"
  8. "runtime"
  9. "sort"
  10. "sync"
  11. )
  12. // Search finds the key using the naive way
  13. func Naive(xs []uint64, k uint64) int16 {
  14. var i int
  15. for i = 0; i < len(xs); i += 2 {
  16. x := xs[i]
  17. if x >= k {
  18. return int16(i / 2)
  19. }
  20. }
  21. return int16(i / 2)
  22. }
  23. func Clever(xs []uint64, k uint64) int16 {
  24. if len(xs) < 8 {
  25. return Naive(xs, k)
  26. }
  27. var twos, pk [4]uint64
  28. pk[0] = k
  29. pk[1] = k
  30. pk[2] = k
  31. pk[3] = k
  32. for i := 0; i < len(xs); i += 8 {
  33. twos[0] = xs[i]
  34. twos[1] = xs[i+2]
  35. twos[2] = xs[i+4]
  36. twos[3] = xs[i+6]
  37. if twos[0] >= pk[0] {
  38. return int16(i / 2)
  39. }
  40. if twos[1] >= pk[1] {
  41. return int16((i + 2) / 2)
  42. }
  43. if twos[2] >= pk[2] {
  44. return int16((i + 4) / 2)
  45. }
  46. if twos[3] >= pk[3] {
  47. return int16((i + 6) / 2)
  48. }
  49. }
  50. return int16(len(xs) / 2)
  51. }
  52. func Parallel(xs []uint64, k uint64) int16 {
  53. cpus := runtime.NumCPU()
  54. if cpus%2 != 0 {
  55. panic(fmt.Sprintf("odd number of CPUs %v", cpus))
  56. }
  57. sz := len(xs)/cpus + 1
  58. var wg sync.WaitGroup
  59. retChan := make(chan int16, cpus)
  60. for i := 0; i < len(xs); i += sz {
  61. end := i + sz
  62. if end >= len(xs) {
  63. end = len(xs)
  64. }
  65. chunk := xs[i:end]
  66. wg.Add(1)
  67. go func(hd int16, xs []uint64, k uint64, wg *sync.WaitGroup, ch chan int16) {
  68. for i := 0; i < len(xs); i += 2 {
  69. if xs[i] >= k {
  70. ch <- (int16(i) + hd) / 2
  71. break
  72. }
  73. }
  74. wg.Done()
  75. }(int16(i), chunk, k, &wg, retChan)
  76. }
  77. wg.Wait()
  78. close(retChan)
  79. var min int16 = (1 << 15) - 1
  80. for i := range retChan {
  81. if i < min {
  82. min = i
  83. }
  84. }
  85. if min == (1<<15)-1 {
  86. return int16(len(xs) / 2)
  87. }
  88. return min
  89. }
  90. func Binary(keys []uint64, key uint64) int16 {
  91. return int16(sort.Search(len(keys), func(i int) bool {
  92. if i*2 >= len(keys) {
  93. return true
  94. }
  95. return keys[i*2] >= key
  96. }))
  97. }
  98. //nolint:unused
  99. func cmp2_native(twos, pk [2]uint64) int16 {
  100. if twos[0] == pk[0] {
  101. return 0
  102. }
  103. if twos[1] == pk[1] {
  104. return 1
  105. }
  106. return 2
  107. }
  108. //nolint:unused
  109. func cmp4_native(fours, pk [4]uint64) int16 {
  110. for i := range fours {
  111. if fours[i] >= pk[i] {
  112. return int16(i)
  113. }
  114. }
  115. return 4
  116. }
  117. //nolint:unused
  118. func cmp8_native(a [8]uint64, pk [4]uint64) int16 {
  119. for i := range a {
  120. if a[i] >= pk[0] {
  121. return int16(i)
  122. }
  123. }
  124. return 8
  125. }