github.com/segmentio/parquet-go@v0.0.0-20230712180008-5d42db8f0d47/sparse/gather_test.go (about) 1 package sparse_test 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math" 7 "strconv" 8 "testing" 9 "time" 10 "unsafe" 11 12 "github.com/segmentio/parquet-go/sparse" 13 ) 14 15 const ( 16 benchmarkGatherPerLoop = 1000 17 ) 18 19 func ExampleGatherUint32() { 20 type point2D struct{ X, Y uint32 } 21 22 buf := make([]point2D, 10) 23 dst := make([]uint32, 10) 24 src := sparse.UnsafeUint32Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 25 26 for i := range buf { 27 buf[i].X = math.MaxUint32 28 buf[i].Y = uint32(2 * i) 29 } 30 31 n := sparse.GatherUint32(dst, src) 32 33 for i, v := range dst[:n] { 34 fmt.Printf("points[%d].Y = %d\n", i, v) 35 } 36 37 // Output: 38 // points[0].Y = 0 39 // points[1].Y = 2 40 // points[2].Y = 4 41 // points[3].Y = 6 42 // points[4].Y = 8 43 // points[5].Y = 10 44 // points[6].Y = 12 45 // points[7].Y = 14 46 // points[8].Y = 16 47 // points[9].Y = 18 48 } 49 50 func ExampleGatherUint64() { 51 type point2D struct{ X, Y uint64 } 52 53 buf := make([]point2D, 10) 54 dst := make([]uint64, 10) 55 src := sparse.UnsafeUint64Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 56 57 for i := range buf { 58 buf[i].X = math.MaxUint64 59 buf[i].Y = uint64(2 * i) 60 } 61 62 n := sparse.GatherUint64(dst, src) 63 64 for i, v := range dst[:n] { 65 fmt.Printf("points[%d].Y = %v\n", i, v) 66 } 67 68 // Output: 69 // points[0].Y = 0 70 // points[1].Y = 2 71 // points[2].Y = 4 72 // points[3].Y = 6 73 // points[4].Y = 8 74 // points[5].Y = 10 75 // points[6].Y = 12 76 // points[7].Y = 14 77 // points[8].Y = 16 78 // points[9].Y = 18 79 } 80 81 func ExampleGatherUint128() { 82 type point2D struct{ X, Y [16]byte } 83 84 buf := make([]point2D, 10) 85 dst := make([][16]byte, 10) 86 src := sparse.UnsafeUint128Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 87 88 for i := range buf { 89 x := uint64(math.MaxUint64) 90 y := uint64(2 * i) 91 binary.LittleEndian.PutUint64(buf[i].X[:], x) 92 binary.LittleEndian.PutUint64(buf[i].Y[:], y) 93 } 94 95 n := sparse.GatherUint128(dst, src) 96 97 for i, v := range dst[:n] { 98 fmt.Printf("points[%d].Y = %v\n", i, binary.LittleEndian.Uint64(v[:])) 99 } 100 101 // Output: 102 // points[0].Y = 0 103 // points[1].Y = 2 104 // points[2].Y = 4 105 // points[3].Y = 6 106 // points[4].Y = 8 107 // points[5].Y = 10 108 // points[6].Y = 12 109 // points[7].Y = 14 110 // points[8].Y = 16 111 // points[9].Y = 18 112 } 113 114 func ExampleGatherString() { 115 buf := make([][2]string, 10) 116 dst := make([]string, 10) 117 src := sparse.UnsafeStringArray(unsafe.Pointer(&buf[0][1]), len(buf), unsafe.Sizeof(buf[0])) 118 119 for i := range buf { 120 buf[i][0] = "-" 121 buf[i][1] = strconv.Itoa(i) 122 } 123 124 n := sparse.GatherString(dst, src) 125 126 for i, v := range dst[:n] { 127 fmt.Printf("points[%d].Y = %v\n", i, v) 128 } 129 130 // Output: 131 // points[0].Y = 0 132 // points[1].Y = 1 133 // points[2].Y = 2 134 // points[3].Y = 3 135 // points[4].Y = 4 136 // points[5].Y = 5 137 // points[6].Y = 6 138 // points[7].Y = 7 139 // points[8].Y = 8 140 // points[9].Y = 9 141 } 142 143 func TestGatherUint32(t *testing.T) { 144 type point2D struct{ X, Y uint32 } 145 146 const N = 100 147 buf := make([]point2D, N+1) 148 dst := make([]uint32, N) 149 src := sparse.UnsafeUint32Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 150 151 for i := range buf { 152 buf[i].X = math.MaxUint32 153 buf[i].Y = uint32(2 * i) 154 } 155 156 if n := sparse.GatherUint32(dst, src); n != N { 157 t.Errorf("wrong number of values gathered: want=%d got=%d", N, n) 158 } 159 160 for i, v := range dst { 161 if v != uint32(2*i) { 162 t.Errorf("wrong value gathered at index %d: want=%d got=%d", i, 2*i, v) 163 } 164 } 165 } 166 167 func TestGatherUint64(t *testing.T) { 168 type point2D struct{ X, Y uint64 } 169 170 const N = 100 171 buf := make([]point2D, N+1) 172 dst := make([]uint64, N) 173 src := sparse.UnsafeUint64Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 174 175 for i := range buf { 176 buf[i].X = math.MaxUint64 177 buf[i].Y = uint64(2 * i) 178 } 179 180 if n := sparse.GatherUint64(dst, src); n != N { 181 t.Errorf("wrong number of values gathered: want=%d got=%d", N, n) 182 } 183 184 for i, v := range dst { 185 if v != uint64(2*i) { 186 t.Errorf("wrong value gathered at index %d: want=%d got=%d", i, 2*i, v) 187 } 188 } 189 } 190 191 func TestGatherUint128(t *testing.T) { 192 type point2D struct{ X, Y [16]byte } 193 194 const N = 100 195 buf := make([]point2D, N+1) 196 dst := make([][16]byte, N) 197 src := sparse.UnsafeUint128Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 198 199 for i := range buf { 200 x := uint64(math.MaxUint64) 201 y := uint64(2 * i) 202 binary.LittleEndian.PutUint64(buf[i].X[:], x) 203 binary.LittleEndian.PutUint64(buf[i].Y[:], y) 204 } 205 206 if n := sparse.GatherUint128(dst, src); n != N { 207 t.Errorf("wrong number of values gathered: want=%d got=%d", N, n) 208 } 209 210 for i, v := range dst { 211 if y := binary.LittleEndian.Uint64(v[:]); y != uint64(2*i) { 212 t.Errorf("wrong value gathered at index %d: want=%d got=%d", i, 2*i, y) 213 } 214 } 215 } 216 217 func BenchmarkGather32(b *testing.B) { 218 type point2D struct{ X, Y uint32 } 219 220 buf := make([]point2D, benchmarkGatherPerLoop) 221 dst := make([]uint32, benchmarkGatherPerLoop) 222 src := sparse.UnsafeUint32Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 223 224 b.SetBytes(4 * benchmarkGatherPerLoop) 225 benchmarkThroughput(b, "gather", func() int { 226 return sparse.GatherUint32(dst, src) 227 }) 228 } 229 230 func BenchmarkGather64(b *testing.B) { 231 type point2D struct{ X, Y uint64 } 232 233 buf := make([]point2D, benchmarkGatherPerLoop) 234 dst := make([]uint64, benchmarkGatherPerLoop) 235 src := sparse.UnsafeUint64Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 236 237 b.SetBytes(8 * benchmarkGatherPerLoop) 238 benchmarkThroughput(b, "gather", func() int { 239 return sparse.GatherUint64(dst, src) 240 }) 241 } 242 243 func BenchmarkGather128(b *testing.B) { 244 type point2D struct{ X, Y [16]byte } 245 246 buf := make([]point2D, benchmarkGatherPerLoop) 247 dst := make([][16]byte, benchmarkGatherPerLoop) 248 src := sparse.UnsafeUint128Array(unsafe.Pointer(&buf[0].Y), len(buf), unsafe.Sizeof(buf[0])) 249 250 b.SetBytes(16 * benchmarkGatherPerLoop) 251 benchmarkThroughput(b, "gather", func() int { 252 return sparse.GatherUint128(dst, src) 253 }) 254 } 255 256 func benchmarkThroughput(b *testing.B, m string, f func() int) { 257 start := time.Now() 258 count := 0 259 260 for i := 0; i < b.N; i++ { 261 count += f() 262 } 263 264 seconds := time.Since(start).Seconds() 265 b.ReportMetric(float64(count)/seconds, m+"/s") 266 }