github.com/grailbio/base@v0.0.11/simd/bitwise_test.go (about)

     1  // Copyright 2018 GRAIL, Inc.  All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package simd_test
     6  
     7  import (
     8  	"bytes"
     9  	"math/rand"
    10  	"testing"
    11  
    12  	"github.com/grailbio/base/simd"
    13  )
    14  
    15  func andInplaceSlow(main, arg []byte) {
    16  	// Slow, but straightforward-to-verify implementation.
    17  	for idx := range main {
    18  		main[idx] = main[idx] & arg[idx]
    19  	}
    20  }
    21  
    22  func TestAnd(t *testing.T) {
    23  	// Generate some random strings and verify that bitwise-and results are as
    24  	// expected.
    25  	maxSize := 500
    26  	nIter := 200
    27  	argArr := simd.MakeUnsafe(maxSize)
    28  	for ii := range argArr {
    29  		argArr[ii] = byte(rand.Intn(256))
    30  	}
    31  	main1Arr := simd.MakeUnsafe(maxSize)
    32  	main2Arr := simd.MakeUnsafe(maxSize)
    33  	main3Arr := simd.MakeUnsafe(maxSize)
    34  	main4Arr := simd.MakeUnsafe(maxSize)
    35  	main5Arr := simd.MakeUnsafe(maxSize)
    36  	for iter := 0; iter < nIter; iter++ {
    37  		sliceStart := rand.Intn(maxSize)
    38  		sliceEnd := sliceStart + rand.Intn(maxSize-sliceStart)
    39  		argSlice := argArr[sliceStart:sliceEnd]
    40  		main1Slice := main1Arr[sliceStart:sliceEnd]
    41  		for ii := range main1Slice {
    42  			main1Slice[ii] = byte(rand.Intn(256))
    43  		}
    44  		main2Slice := main2Arr[sliceStart:sliceEnd]
    45  		main3Slice := main3Arr[sliceStart:sliceEnd]
    46  		main4Slice := main4Arr[sliceStart:sliceEnd]
    47  		main5Slice := main5Arr[sliceStart:sliceEnd]
    48  		copy(main3Slice, main1Slice)
    49  		copy(main5Slice, main1Slice)
    50  		andInplaceSlow(main1Slice, argSlice)
    51  		simd.AndUnsafe(main2Slice, argSlice, main3Slice)
    52  		if !bytes.Equal(main1Slice, main2Slice) {
    53  			t.Fatal("Mismatched AndUnsafe result.")
    54  		}
    55  		sentinel := byte(rand.Intn(256))
    56  		main4Arr[sliceEnd] = sentinel
    57  		simd.And(main4Slice, argSlice, main3Slice)
    58  		if !bytes.Equal(main1Slice, main4Slice) {
    59  			t.Fatal("Mismatched And result.")
    60  		}
    61  		if main4Arr[sliceEnd] != sentinel {
    62  			t.Fatal("And clobbered an extra byte.")
    63  		}
    64  		simd.AndUnsafeInplace(main3Slice, argSlice)
    65  		if !bytes.Equal(main1Slice, main3Slice) {
    66  			t.Fatal("Mismatched AndUnsafeInplace result.")
    67  		}
    68  		main5Arr[sliceEnd] = sentinel
    69  		simd.AndInplace(main5Slice, argSlice)
    70  		if !bytes.Equal(main1Slice, main5Slice) {
    71  			t.Fatal("Mismatched AndInplace result.")
    72  		}
    73  		if main5Arr[sliceEnd] != sentinel {
    74  			t.Fatal("AndInplace clobbered an extra byte.")
    75  		}
    76  	}
    77  }
    78  
    79  /*
    80  Benchmark results:
    81    MacBook Pro (15-inch, 2016)
    82    2.7 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3
    83  
    84  Benchmark_AndInplace/SIMDShort1Cpu-8                  20          91832421 ns/op
    85  Benchmark_AndInplace/SIMDShortHalfCpu-8               50          25323744 ns/op
    86  Benchmark_AndInplace/SIMDShortAllCpu-8               100          23869031 ns/op
    87  Benchmark_AndInplace/SIMDLong1Cpu-8                    1        1715379622 ns/op
    88  Benchmark_AndInplace/SIMDLongHalfCpu-8                 1        1372591170 ns/op
    89  Benchmark_AndInplace/SIMDLongAllCpu-8                  1        1427476449 ns/op
    90  Benchmark_AndInplace/SlowShort1Cpu-8                   2         550667201 ns/op
    91  Benchmark_AndInplace/SlowShortHalfCpu-8               10         145756965 ns/op
    92  Benchmark_AndInplace/SlowShortAllCpu-8                10         135311356 ns/op
    93  Benchmark_AndInplace/SlowLong1Cpu-8                    1        7711233274 ns/op
    94  Benchmark_AndInplace/SlowLongHalfCpu-8                 1        2144409827 ns/op
    95  Benchmark_AndInplace/SlowLongAllCpu-8                  1        2158206158 ns/op
    96  */
    97  
    98  func andSimdSubtask(dst, src []byte, nIter int) int {
    99  	for iter := 0; iter < nIter; iter++ {
   100  		simd.AndInplace(dst, src)
   101  	}
   102  	return int(dst[0])
   103  }
   104  
   105  func andSlowSubtask(dst, src []byte, nIter int) int {
   106  	for iter := 0; iter < nIter; iter++ {
   107  		andInplaceSlow(dst, src)
   108  	}
   109  	return int(dst[0])
   110  }
   111  
   112  func Benchmark_AndInplace(b *testing.B) {
   113  	funcs := []taggedMultiBenchFunc{
   114  		{
   115  			f:   andSimdSubtask,
   116  			tag: "SIMD",
   117  		},
   118  		{
   119  			f:   andSlowSubtask,
   120  			tag: "Slow",
   121  		},
   122  	}
   123  	for _, f := range funcs {
   124  		// This is relevant to .bam reads in packed form, so 150/2=75 is a good
   125  		// size for the short-array benchmark.
   126  		multiBenchmark(f.f, f.tag+"Short", 75, 75, 9999999, b)
   127  		multiBenchmark(f.f, f.tag+"Long", 249250621, 249250621, 50, b)
   128  	}
   129  }
   130  
   131  // Don't bother with separate benchmarks for Or/Xor/Invmask.
   132  
   133  func orInplaceSlow(main, arg []byte) {
   134  	for idx := range main {
   135  		main[idx] = main[idx] | arg[idx]
   136  	}
   137  }
   138  
   139  func TestOr(t *testing.T) {
   140  	maxSize := 500
   141  	nIter := 200
   142  	argArr := simd.MakeUnsafe(maxSize)
   143  	for ii := range argArr {
   144  		argArr[ii] = byte(rand.Intn(256))
   145  	}
   146  	main1Arr := simd.MakeUnsafe(maxSize)
   147  	main2Arr := simd.MakeUnsafe(maxSize)
   148  	main3Arr := simd.MakeUnsafe(maxSize)
   149  	main4Arr := simd.MakeUnsafe(maxSize)
   150  	main5Arr := simd.MakeUnsafe(maxSize)
   151  	for iter := 0; iter < nIter; iter++ {
   152  		sliceStart := rand.Intn(maxSize)
   153  		sliceEnd := sliceStart + rand.Intn(maxSize-sliceStart)
   154  		argSlice := argArr[sliceStart:sliceEnd]
   155  		main1Slice := main1Arr[sliceStart:sliceEnd]
   156  		for ii := range main1Slice {
   157  			main1Slice[ii] = byte(rand.Intn(256))
   158  		}
   159  		main2Slice := main2Arr[sliceStart:sliceEnd]
   160  		main3Slice := main3Arr[sliceStart:sliceEnd]
   161  		main4Slice := main4Arr[sliceStart:sliceEnd]
   162  		main5Slice := main5Arr[sliceStart:sliceEnd]
   163  		copy(main3Slice, main1Slice)
   164  		copy(main5Slice, main1Slice)
   165  		orInplaceSlow(main1Slice, argSlice)
   166  		simd.OrUnsafe(main2Slice, argSlice, main3Slice)
   167  		if !bytes.Equal(main1Slice, main2Slice) {
   168  			t.Fatal("Mismatched OrUnsafe result.")
   169  		}
   170  		sentinel := byte(rand.Intn(256))
   171  		main4Arr[sliceEnd] = sentinel
   172  		simd.Or(main4Slice, argSlice, main3Slice)
   173  		if !bytes.Equal(main1Slice, main4Slice) {
   174  			t.Fatal("Mismatched Or result.")
   175  		}
   176  		if main4Arr[sliceEnd] != sentinel {
   177  			t.Fatal("Or clobbered an extra byte.")
   178  		}
   179  		simd.OrUnsafeInplace(main3Slice, argSlice)
   180  		if !bytes.Equal(main1Slice, main3Slice) {
   181  			t.Fatal("Mismatched OrUnsafeInplace result.")
   182  		}
   183  		main5Arr[sliceEnd] = sentinel
   184  		simd.OrInplace(main5Slice, argSlice)
   185  		if !bytes.Equal(main1Slice, main5Slice) {
   186  			t.Fatal("Mismatched OrInplace result.")
   187  		}
   188  		if main5Arr[sliceEnd] != sentinel {
   189  			t.Fatal("OrInplace clobbered an extra byte.")
   190  		}
   191  	}
   192  }
   193  
   194  func xorInplaceSlow(main, arg []byte) {
   195  	for idx := range main {
   196  		main[idx] = main[idx] ^ arg[idx]
   197  	}
   198  }
   199  
   200  func TestXor(t *testing.T) {
   201  	maxSize := 500
   202  	nIter := 200
   203  	argArr := simd.MakeUnsafe(maxSize)
   204  	for ii := range argArr {
   205  		argArr[ii] = byte(rand.Intn(256))
   206  	}
   207  	main1Arr := simd.MakeUnsafe(maxSize)
   208  	main2Arr := simd.MakeUnsafe(maxSize)
   209  	main3Arr := simd.MakeUnsafe(maxSize)
   210  	main4Arr := simd.MakeUnsafe(maxSize)
   211  	main5Arr := simd.MakeUnsafe(maxSize)
   212  	for iter := 0; iter < nIter; iter++ {
   213  		sliceStart := rand.Intn(maxSize)
   214  		sliceEnd := sliceStart + rand.Intn(maxSize-sliceStart)
   215  		argSlice := argArr[sliceStart:sliceEnd]
   216  		main1Slice := main1Arr[sliceStart:sliceEnd]
   217  		for ii := range main1Slice {
   218  			main1Slice[ii] = byte(rand.Intn(256))
   219  		}
   220  		main2Slice := main2Arr[sliceStart:sliceEnd]
   221  		main3Slice := main3Arr[sliceStart:sliceEnd]
   222  		main4Slice := main4Arr[sliceStart:sliceEnd]
   223  		main5Slice := main5Arr[sliceStart:sliceEnd]
   224  		copy(main3Slice, main1Slice)
   225  		copy(main5Slice, main1Slice)
   226  		xorInplaceSlow(main1Slice, argSlice)
   227  		simd.XorUnsafe(main2Slice, argSlice, main3Slice)
   228  		if !bytes.Equal(main1Slice, main2Slice) {
   229  			t.Fatal("Mismatched XorUnsafe result.")
   230  		}
   231  		sentinel := byte(rand.Intn(256))
   232  		main4Arr[sliceEnd] = sentinel
   233  		simd.Xor(main4Slice, argSlice, main3Slice)
   234  		if !bytes.Equal(main1Slice, main4Slice) {
   235  			t.Fatal("Mismatched Xor result.")
   236  		}
   237  		if main4Arr[sliceEnd] != sentinel {
   238  			t.Fatal("Xor clobbered an extra byte.")
   239  		}
   240  		simd.XorUnsafeInplace(main3Slice, argSlice)
   241  		if !bytes.Equal(main1Slice, main3Slice) {
   242  			t.Fatal("Mismatched XorUnsafeInplace result.")
   243  		}
   244  		main5Arr[sliceEnd] = sentinel
   245  		simd.XorInplace(main5Slice, argSlice)
   246  		if !bytes.Equal(main1Slice, main5Slice) {
   247  			t.Fatal("Mismatched XorInplace result.")
   248  		}
   249  		if main5Arr[sliceEnd] != sentinel {
   250  			t.Fatal("XorInplace clobbered an extra byte.")
   251  		}
   252  	}
   253  }
   254  
   255  func invmaskInplaceSlow(main, invmask []byte) {
   256  	// Slow, but straightforward-to-verify implementation.
   257  	for idx := range main {
   258  		main[idx] = main[idx] &^ invmask[idx]
   259  	}
   260  }
   261  
   262  func TestInvmask(t *testing.T) {
   263  	maxSize := 500
   264  	nIter := 200
   265  	invmaskArr := simd.MakeUnsafe(maxSize)
   266  	for ii := range invmaskArr {
   267  		invmaskArr[ii] = byte(rand.Intn(256))
   268  	}
   269  	main1Arr := simd.MakeUnsafe(maxSize)
   270  	main2Arr := simd.MakeUnsafe(maxSize)
   271  	main3Arr := simd.MakeUnsafe(maxSize)
   272  	main4Arr := simd.MakeUnsafe(maxSize)
   273  	main5Arr := simd.MakeUnsafe(maxSize)
   274  	for iter := 0; iter < nIter; iter++ {
   275  		sliceStart := rand.Intn(maxSize)
   276  		sliceEnd := sliceStart + rand.Intn(maxSize-sliceStart)
   277  		invmaskSlice := invmaskArr[sliceStart:sliceEnd]
   278  		main1Slice := main1Arr[sliceStart:sliceEnd]
   279  		for ii := range main1Slice {
   280  			main1Slice[ii] = byte(rand.Intn(256))
   281  		}
   282  		main2Slice := main2Arr[sliceStart:sliceEnd]
   283  		main3Slice := main3Arr[sliceStart:sliceEnd]
   284  		main4Slice := main4Arr[sliceStart:sliceEnd]
   285  		main5Slice := main5Arr[sliceStart:sliceEnd]
   286  		copy(main3Slice, main1Slice)
   287  		copy(main5Slice, main1Slice)
   288  		invmaskInplaceSlow(main1Slice, invmaskSlice)
   289  		simd.InvmaskUnsafe(main2Slice, main3Slice, invmaskSlice)
   290  		if !bytes.Equal(main1Slice, main2Slice) {
   291  			t.Fatal("Mismatched InvmaskUnsafe result.")
   292  		}
   293  		sentinel := byte(rand.Intn(256))
   294  		main4Arr[sliceEnd] = sentinel
   295  		simd.Invmask(main4Slice, main3Slice, invmaskSlice)
   296  		if !bytes.Equal(main1Slice, main4Slice) {
   297  			t.Fatal("Mismatched Invmask result.")
   298  		}
   299  		if main4Arr[sliceEnd] != sentinel {
   300  			t.Fatal("Invmask clobbered an extra byte.")
   301  		}
   302  		simd.InvmaskUnsafeInplace(main3Slice, invmaskSlice)
   303  		if !bytes.Equal(main1Slice, main3Slice) {
   304  			t.Fatal("Mismatched InvmaskUnsafeInplace result.")
   305  		}
   306  		main5Arr[sliceEnd] = sentinel
   307  		simd.InvmaskInplace(main5Slice, invmaskSlice)
   308  		if !bytes.Equal(main1Slice, main5Slice) {
   309  			t.Fatal("Mismatched InvmaskInplace result.")
   310  		}
   311  		if main5Arr[sliceEnd] != sentinel {
   312  			t.Fatal("InvmaskInplace clobbered an extra byte.")
   313  		}
   314  	}
   315  }
   316  
   317  func andConst8InplaceSlow(main []byte, val byte) {
   318  	for idx, mainByte := range main {
   319  		main[idx] = mainByte & val
   320  	}
   321  }
   322  
   323  func TestAndConst8(t *testing.T) {
   324  	maxSize := 500
   325  	nIter := 200
   326  	main1Arr := simd.MakeUnsafe(maxSize)
   327  	main2Arr := simd.MakeUnsafe(maxSize)
   328  	main3Arr := simd.MakeUnsafe(maxSize)
   329  	main4Arr := simd.MakeUnsafe(maxSize)
   330  	main5Arr := simd.MakeUnsafe(maxSize)
   331  	for iter := 0; iter < nIter; iter++ {
   332  		sliceStart := rand.Intn(maxSize)
   333  		sliceEnd := sliceStart + rand.Intn(maxSize-sliceStart)
   334  		main1Slice := main1Arr[sliceStart:sliceEnd]
   335  		for ii := range main1Slice {
   336  			main1Slice[ii] = byte(rand.Intn(256))
   337  		}
   338  		main2Slice := main2Arr[sliceStart:sliceEnd]
   339  		main3Slice := main3Arr[sliceStart:sliceEnd]
   340  		main4Slice := main4Arr[sliceStart:sliceEnd]
   341  		main5Slice := main5Arr[sliceStart:sliceEnd]
   342  		andVal := byte(rand.Intn(256))
   343  		sentinel := byte(rand.Intn(256))
   344  		copy(main2Slice, main1Slice)
   345  		copy(main3Slice, main1Slice)
   346  		main2Arr[sliceEnd] = sentinel
   347  		main5Arr[sliceEnd] = sentinel
   348  		simd.AndConst8Unsafe(main4Slice, main1Slice, andVal)
   349  		simd.AndConst8(main5Slice, main1Slice, andVal)
   350  		andConst8InplaceSlow(main1Slice, andVal)
   351  		if !bytes.Equal(main1Slice, main4Slice) {
   352  			t.Fatal("Mismatched AndConst8Unsafe result.")
   353  		}
   354  		if !bytes.Equal(main1Slice, main5Slice) {
   355  			t.Fatal("Mismatched AndConst8 result.")
   356  		}
   357  		if main5Arr[sliceEnd] != sentinel {
   358  			t.Fatal("AndConst8 clobbered an extra byte.")
   359  		}
   360  		simd.AndConst8Inplace(main2Slice, andVal)
   361  		if !bytes.Equal(main1Slice, main2Slice) {
   362  			t.Fatal("Mismatched AndConst8Inplace result.")
   363  		}
   364  		if main2Arr[sliceEnd] != sentinel {
   365  			t.Fatal("AndConst8Inplace clobbered an extra byte.")
   366  		}
   367  		simd.AndConst8UnsafeInplace(main3Slice, andVal)
   368  		if !bytes.Equal(main1Slice, main3Slice) {
   369  			t.Fatal("Mismatched AndConst8UnsafeInplace result.")
   370  		}
   371  	}
   372  }
   373  
   374  func orConst8InplaceSlow(main []byte, val byte) {
   375  	for idx, mainByte := range main {
   376  		main[idx] = mainByte | val
   377  	}
   378  }
   379  
   380  func TestOrConst8(t *testing.T) {
   381  	maxSize := 500
   382  	nIter := 200
   383  	main1Arr := simd.MakeUnsafe(maxSize)
   384  	main2Arr := simd.MakeUnsafe(maxSize)
   385  	main3Arr := simd.MakeUnsafe(maxSize)
   386  	main4Arr := simd.MakeUnsafe(maxSize)
   387  	main5Arr := simd.MakeUnsafe(maxSize)
   388  	for iter := 0; iter < nIter; iter++ {
   389  		sliceStart := rand.Intn(maxSize)
   390  		sliceEnd := sliceStart + rand.Intn(maxSize-sliceStart)
   391  		main1Slice := main1Arr[sliceStart:sliceEnd]
   392  		for ii := range main1Slice {
   393  			main1Slice[ii] = byte(rand.Intn(256))
   394  		}
   395  		main2Slice := main2Arr[sliceStart:sliceEnd]
   396  		main3Slice := main3Arr[sliceStart:sliceEnd]
   397  		main4Slice := main4Arr[sliceStart:sliceEnd]
   398  		main5Slice := main5Arr[sliceStart:sliceEnd]
   399  		orVal := byte(rand.Intn(256))
   400  		sentinel := byte(rand.Intn(256))
   401  		copy(main2Slice, main1Slice)
   402  		copy(main3Slice, main1Slice)
   403  		main2Arr[sliceEnd] = sentinel
   404  		main5Arr[sliceEnd] = sentinel
   405  		simd.OrConst8Unsafe(main4Slice, main1Slice, orVal)
   406  		simd.OrConst8(main5Slice, main1Slice, orVal)
   407  		orConst8InplaceSlow(main1Slice, orVal)
   408  		if !bytes.Equal(main4Slice, main1Slice) {
   409  			t.Fatal("Mismatched OrConst8Unsafe result.")
   410  		}
   411  		if !bytes.Equal(main5Slice, main1Slice) {
   412  			t.Fatal("Mismatched OrConst8 result.")
   413  		}
   414  		if main5Arr[sliceEnd] != sentinel {
   415  			t.Fatal("OrConst8 clobbered an extra byte.")
   416  		}
   417  		simd.OrConst8Inplace(main2Slice, orVal)
   418  		if !bytes.Equal(main1Slice, main2Slice) {
   419  			t.Fatal("Mismatched OrConst8Inplace result.")
   420  		}
   421  		if main2Arr[sliceEnd] != sentinel {
   422  			t.Fatal("OrConst8Inplace clobbered an extra byte.")
   423  		}
   424  		simd.OrConst8UnsafeInplace(main3Slice, orVal)
   425  		if !bytes.Equal(main1Slice, main3Slice) {
   426  			t.Fatal("Mismatched OrConst8UnsafeInplace result.")
   427  		}
   428  	}
   429  }
   430  
   431  func xorConst8InplaceSlow(main []byte, val byte) {
   432  	for idx, mainByte := range main {
   433  		main[idx] = mainByte ^ val
   434  	}
   435  }
   436  
   437  func TestXorConst8(t *testing.T) {
   438  	maxSize := 500
   439  	nIter := 200
   440  	main1Arr := simd.MakeUnsafe(maxSize)
   441  	main2Arr := simd.MakeUnsafe(maxSize)
   442  	main3Arr := simd.MakeUnsafe(maxSize)
   443  	main4Arr := simd.MakeUnsafe(maxSize)
   444  	main5Arr := simd.MakeUnsafe(maxSize)
   445  	src2Arr := simd.MakeUnsafe(maxSize)
   446  	for iter := 0; iter < nIter; iter++ {
   447  		sliceStart := rand.Intn(maxSize)
   448  		sliceEnd := sliceStart + rand.Intn(maxSize-sliceStart)
   449  		main1Slice := main1Arr[sliceStart:sliceEnd]
   450  		for ii := range main1Slice {
   451  			main1Slice[ii] = byte(rand.Intn(256))
   452  		}
   453  		main2Slice := main2Arr[sliceStart:sliceEnd]
   454  		main3Slice := main3Arr[sliceStart:sliceEnd]
   455  		main4Slice := main4Arr[sliceStart:sliceEnd]
   456  		main5Slice := main5Arr[sliceStart:sliceEnd]
   457  		src2Slice := src2Arr[sliceStart:sliceEnd]
   458  		xorVal := byte(rand.Intn(256))
   459  		sentinel := byte(rand.Intn(256))
   460  		copy(main2Slice, main1Slice)
   461  		copy(main3Slice, main1Slice)
   462  		copy(src2Slice, main1Slice)
   463  		main2Arr[sliceEnd] = sentinel
   464  		main5Arr[sliceEnd] = sentinel
   465  		simd.XorConst8Unsafe(main4Slice, main1Slice, xorVal)
   466  		simd.XorConst8(main5Slice, main1Slice, xorVal)
   467  		xorConst8InplaceSlow(main1Slice, xorVal)
   468  		if !bytes.Equal(main1Slice, main4Slice) {
   469  			t.Fatal("Mismatched XorConst8Unsafe result.")
   470  		}
   471  		if !bytes.Equal(main1Slice, main5Slice) {
   472  			t.Fatal("Mismatched XorConst8 result.")
   473  		}
   474  		if main5Arr[sliceEnd] != sentinel {
   475  			t.Fatal("XorConst8 clobbered an extra byte.")
   476  		}
   477  		simd.XorConst8Inplace(main2Slice, xorVal)
   478  		if !bytes.Equal(main1Slice, main2Slice) {
   479  			t.Fatal("Mismatched XorConst8Inplace result.")
   480  		}
   481  		if main2Arr[sliceEnd] != sentinel {
   482  			t.Fatal("XorConst8Inplace clobbered an extra byte.")
   483  		}
   484  		simd.XorConst8Inplace(main2Slice, xorVal)
   485  		if !bytes.Equal(main2Slice, src2Slice) {
   486  			t.Fatal("XorConst8Inplace did not invert itself.")
   487  		}
   488  		simd.XorConst8UnsafeInplace(main3Slice, xorVal)
   489  		if !bytes.Equal(main1Slice, main3Slice) {
   490  			t.Fatal("Mismatched XorConst8UnsafeInplace result.")
   491  		}
   492  	}
   493  }
   494  
   495  /*
   496  Benchmark results:
   497    MacBook Pro (15-inch, 2016)
   498    2.7 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3
   499  
   500  Benchmark_XorConst8Inplace/SIMDShort1Cpu-8                    20          79730366 ns/op
   501  Benchmark_XorConst8Inplace/SIMDShortHalfCpu-8                100          21216542 ns/op
   502  Benchmark_XorConst8Inplace/SIMDShortAllCpu-8                 100          18902385 ns/op
   503  Benchmark_XorConst8Inplace/SIMDLong1Cpu-8                      1        1291770636 ns/op
   504  Benchmark_XorConst8Inplace/SIMDLongHalfCpu-8                   2         958003320 ns/op
   505  Benchmark_XorConst8Inplace/SIMDLongAllCpu-8                    2         967333286 ns/op
   506  Benchmark_XorConst8Inplace/SlowShort1Cpu-8                     3         417781174 ns/op
   507  Benchmark_XorConst8Inplace/SlowShortHalfCpu-8                 10         112255124 ns/op
   508  Benchmark_XorConst8Inplace/SlowShortAllCpu-8                  10         100138643 ns/op
   509  Benchmark_XorConst8Inplace/SlowLong1Cpu-8                      1        5476605564 ns/op
   510  Benchmark_XorConst8Inplace/SlowLongHalfCpu-8                   1        1480923705 ns/op
   511  Benchmark_XorConst8Inplace/SlowLongAllCpu-8                    1        1588216831 ns/op
   512  */
   513  
   514  func xorConst8InplaceSimdSubtask(dst, src []byte, nIter int) int {
   515  	for iter := 0; iter < nIter; iter++ {
   516  		simd.XorConst8Inplace(dst, 3)
   517  	}
   518  	return int(dst[0])
   519  }
   520  
   521  func xorConst8InplaceSlowSubtask(dst, src []byte, nIter int) int {
   522  	for iter := 0; iter < nIter; iter++ {
   523  		xorConst8InplaceSlow(dst, 3)
   524  	}
   525  	return int(dst[0])
   526  }
   527  
   528  func Benchmark_XorConst8Inplace(b *testing.B) {
   529  	funcs := []taggedMultiBenchFunc{
   530  		{
   531  			f:   xorConst8InplaceSimdSubtask,
   532  			tag: "SIMD",
   533  		},
   534  		{
   535  			f:   xorConst8InplaceSlowSubtask,
   536  			tag: "Slow",
   537  		},
   538  	}
   539  	for _, f := range funcs {
   540  		multiBenchmark(f.f, f.tag+"Short", 75, 0, 9999999, b)
   541  		multiBenchmark(f.f, f.tag+"Long", 249250621, 0, 50, b)
   542  	}
   543  }