GoAudio icon indicating copy to clipboard operation
GoAudio copied to clipboard

bitsToInt optimization

Open hollowness-inside opened this issue 1 year ago • 0 comments

Creating a new bytes reader with each function call is inefficient as it requires a lot of allocations and performs a lot of operations. The needed numeric types can be retrieved simply by utilizing bitwise operations. This approach is good in performance and the code looks simpler and cleaner.

I ran benchmarks on the Bits24ToIntReader function and the provided optimized. Here are my results:

goos: windows
goarch: amd64
pkg: bitsToInt
cpu: 12th Gen Intel(R) Core(TM) i7-12650H
BenchmarkReader-16       2183080               522.5 ns/op           576 B/op         36 allocs/op
BenchmarkBitwise-16     430430271                2.823 ns/op           0 B/op          0 allocs/op
BenchmarkCast-16        450972691                2.645 ns/op           0 B/op          0 allocs/op

And here are the functions that I benchmarked:

  • Original, with the use of bytes.NewReader
func Bits24ToIntReader(b []byte) int {
	if len(b) != 3 {
		panic("Expected size 3!")
	}
	// add some padding to turn a 24-bit integer into a 32-bit integer
	b = append([]byte{0x00}, b...)
	var payload int32
	buf := bytes.NewReader(b)
	err := binary.Read(buf, binary.LittleEndian, &payload)
	if err != nil {
		// TODO: make safe
		panic(err)
	}
	return int(payload) // easier to work with ints
}
  • Bitwise operations, shift and or
func Bits24ToIntBitwise(b []byte) int {
	_ = b[2]
	out := (int32(b[2]) << 24) | (int32(b[1]) << 16) | (int32(b[0]) << 8)
	return int(out)
}
  • Unsafe cast (but should be safe since we check whether the sufficient number of elements is present, right?)
func Bits24ToIntCast(b []byte) int {
	_ = b[2]
	out := *(*uint32)(unsafe.Pointer(&b[0])) << 8
	return int(out)
}

hollowness-inside avatar Apr 23 '24 13:04 hollowness-inside