GoAudio
GoAudio copied to clipboard
bitsToInt optimization
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,
shiftandor
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)
}