Optimize writeElement.
This commit modifies the writeElement function to have a "fast path" which uses type assertions for all of the types which btcwire write so the more expensive reflection-based binary.Write can be avoided. Also, this changes all cases that were writing raw ShaHash (32-byte) arrays (which requires a stack copy) instead simply passing the pointer. The following benchmark results show the results for serializing a block header after these changes: Before: BenchmarkWriteBlockHeader 500000 5566 ns/op After: BenchmarkWriteBlockHeader 1000000 991 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27.
This commit is contained in:
parent
7de20add63
commit
9ee6a8aeb6
5 changed files with 105 additions and 7 deletions
|
@ -107,7 +107,7 @@ func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
|
||||||
// writeBlockHeader writes a bitcoin block header to w.
|
// writeBlockHeader writes a bitcoin block header to w.
|
||||||
func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
|
func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
|
||||||
sec := uint32(bh.Timestamp.Unix())
|
sec := uint32(bh.Timestamp.Unix())
|
||||||
err := writeElements(w, bh.Version, bh.PrevBlock, bh.MerkleRoot,
|
err := writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
|
||||||
sec, bh.Bits, bh.Nonce)
|
sec, bh.Bits, bh.Nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
104
common.go
104
common.go
|
@ -17,9 +17,7 @@ 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. It also accepts a
|
// depending on the concrete type of element pointed to.
|
||||||
// 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
|
var scratch [8]byte
|
||||||
|
|
||||||
|
@ -140,6 +138,106 @@ func readElements(r io.Reader, elements ...interface{}) error {
|
||||||
|
|
||||||
// writeElement writes the little endian representation of element to w.
|
// writeElement writes the little endian representation of element to w.
|
||||||
func writeElement(w io.Writer, element interface{}) error {
|
func writeElement(w io.Writer, 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]
|
||||||
|
binary.LittleEndian.PutUint32(b, uint32(e))
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case uint32:
|
||||||
|
b := scratch[0:4]
|
||||||
|
binary.LittleEndian.PutUint32(b, e)
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case int64:
|
||||||
|
b := scratch[0:8]
|
||||||
|
binary.LittleEndian.PutUint64(b, uint64(e))
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case uint64:
|
||||||
|
b := scratch[0:8]
|
||||||
|
binary.LittleEndian.PutUint64(b, e)
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// Message header checksum.
|
||||||
|
case [4]byte:
|
||||||
|
_, err := w.Write(e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// Message header command.
|
||||||
|
case [commandSize]uint8:
|
||||||
|
_, err := w.Write(e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// IP address.
|
||||||
|
case [16]byte:
|
||||||
|
_, err := w.Write(e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case *ShaHash:
|
||||||
|
_, err := w.Write(e[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ServiceFlag:
|
||||||
|
b := scratch[0:8]
|
||||||
|
binary.LittleEndian.PutUint64(b, uint64(e))
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case InvType:
|
||||||
|
b := scratch[0:4]
|
||||||
|
binary.LittleEndian.PutUint32(b, uint32(e))
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case BitcoinNet:
|
||||||
|
b := scratch[0:4]
|
||||||
|
binary.LittleEndian.PutUint32(b, uint32(e))
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return binary.Write(w, binary.LittleEndian, element)
|
return binary.Write(w, binary.LittleEndian, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ func readInvVect(r io.Reader, pver uint32, iv *InvVect) error {
|
||||||
|
|
||||||
// writeInvVect serializes an InvVect to w depending on the protocol version.
|
// writeInvVect serializes an InvVect to w depending on the protocol version.
|
||||||
func writeInvVect(w io.Writer, pver uint32, iv *InvVect) error {
|
func writeInvVect(w io.Writer, pver uint32, iv *InvVect) error {
|
||||||
err := writeElements(w, iv.Type, iv.Hash)
|
err := writeElements(w, iv.Type, &iv.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeElement(w, msg.HashStop)
|
err = writeElement(w, &msg.HashStop)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ func (msg *MsgGetHeaders) BtcEncode(w io.Writer, pver uint32) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeElement(w, msg.HashStop)
|
err = writeElement(w, &msg.HashStop)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue