github.com/vc42/parquet-go@v0.0.0-20240320194221-1a9adb5f23f5/sparse/gather_test.go (about)

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