Optimize readElement.
The following benchmark results show the results for deserializing a block header: Before: BenchmarkReadBlockHeader 500000 5916 ns/op After: BenchmarkReadBlockHeader 1000000 2078 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27.
This commit is contained in:
parent
d21050a8aa
commit
bc85a31016
1 changed files with 105 additions and 1 deletions
106
common.go
106
common.go
|
@ -17,8 +17,112 @@ import (
|
||||||
const maxVarIntPayload = 9
|
const maxVarIntPayload = 9
|
||||||
|
|
||||||
// readElement reads the next sequence of bytes from r using little endian
|
// readElement reads the next sequence of bytes from r using little endian
|
||||||
// depending on the concrete type of element pointed to.
|
// depending on the concrete type of element pointed to. It also accepts a
|
||||||
|
// scratch buffer that is used for the primitive values rather than creating
|
||||||
|
// a new buffer on every call.
|
||||||
func readElement(r io.Reader, element interface{}) error {
|
func readElement(r io.Reader, element interface{}) error {
|
||||||
|
var scratch [8]byte
|
||||||
|
|
||||||
|
// Attempt to read the element based on the concrete type via fast
|
||||||
|
// type assertions first.
|
||||||
|
switch e := element.(type) {
|
||||||
|
case *int32:
|
||||||
|
b := scratch[0:4]
|
||||||
|
_, err := io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = int32(binary.LittleEndian.Uint32(b))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *uint32:
|
||||||
|
b := scratch[0:4]
|
||||||
|
_, err := io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = binary.LittleEndian.Uint32(b)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *int64:
|
||||||
|
b := scratch[0:8]
|
||||||
|
_, err := io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = int64(binary.LittleEndian.Uint64(b))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *uint64:
|
||||||
|
b := scratch[0:8]
|
||||||
|
_, err := io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = binary.LittleEndian.Uint64(b)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// Message header checksum.
|
||||||
|
case *[4]byte:
|
||||||
|
_, err := io.ReadFull(r, e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// Message header command.
|
||||||
|
case *[commandSize]uint8:
|
||||||
|
_, err := io.ReadFull(r, e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// IP address.
|
||||||
|
case *[16]byte:
|
||||||
|
_, err := io.ReadFull(r, e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *ShaHash:
|
||||||
|
_, err := io.ReadFull(r, e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *ServiceFlag:
|
||||||
|
b := scratch[0:8]
|
||||||
|
_, err := io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = ServiceFlag(binary.LittleEndian.Uint64(b))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *InvType:
|
||||||
|
b := scratch[0:4]
|
||||||
|
_, err := io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = InvType(binary.LittleEndian.Uint32(b))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *BitcoinNet:
|
||||||
|
b := scratch[0:4]
|
||||||
|
_, err := io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*e = BitcoinNet(binary.LittleEndian.Uint32(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to the slower binary.Read if a fast path was not available
|
||||||
|
// above.
|
||||||
return binary.Read(r, binary.LittleEndian, element)
|
return binary.Read(r, binary.LittleEndian, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue