You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Noticed a day ago as I was dissecting performance issues in cosmos-sdk. The code inside for example encoding.go and import.go creates a bytes.Buffer per call, then discards it after exiting which shows up with buffer.Grow-> runtime.growslice in CPU and memory profiles.
Go's sync package provides sync.Pool https://golang.org/pkg/sync/#Pool which can be used to reuse and reset buffers and that will produce great performance at scale for example please do this
diff --git a/encoding.go b/encoding.go
index 6068fe1..a80087b 100644
--- a/encoding.go+++ b/encoding.go@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"math/bits"
+ "sync"
)
// decodeBytes decodes a varint length-prefixed byte slice, returning it along with the number
@@ -78,10 +79,19 @@ func encodeBytes(w io.Writer, bz []byte) error {
return err
}
+var bufPool = &sync.Pool{+ New: func() interface{} {+ return new(bytes.Buffer)+ },+}+
// encodeBytesSlice length-prefixes the byte slice and returns it.
func encodeBytesSlice(bz []byte) ([]byte, error) {
- var buf bytes.Buffer- err := encodeBytes(&buf, bz)+ buf := bufPool.Get().(*bytes.Buffer)+ buf.Reset()+ defer bufPool.Put(buf)++ err := encodeBytes(buf, bz)
return buf.Bytes(), err
}
diff --git a/import.go b/import.go
index 1933fdd..083e6eb 100644
--- a/import.go+++ b/import.go@@ -119,8 +119,11 @@ func (i *Importer) Add(exportNode *ExportNode) error {
return err
}
- var buf bytes.Buffer- err = node.writeBytes(&buf)+ buf := bufPool.Get().(*bytes.Buffer)+ buf.Reset()+ defer bufPool.Put(buf)++ err = node.writeBytes(buf)
This value is going to compound when used with lots of code in the cosmos-sdk running over a period of time and even starting up. Our goal is to squeeze out every single ounce of performance and reclaim as much as we can, given that the cosmos-sdk is being used at scale now.
I highly encourage and adoption of this pattern all around this package.
If there are cases where the bytes are stored and kept in memory for a long time, then perhaps we can't reuse buffers but majority of them will perhaps be conversions between bytes and integers.
@robert-zaremba please go for it, I still have to finish creating benchmarking the cosmos-sdk and on the quest to finish that I discover things that need to be fixed then report them, but otherwise I'll get side tracked. All yours :-)
Noticed a day ago as I was dissecting performance issues in cosmos-sdk. The code inside for example encoding.go and import.go creates a bytes.Buffer per call, then discards it after exiting which shows up with buffer.Grow-> runtime.growslice in CPU and memory profiles.
Go's sync package provides sync.Pool https://golang.org/pkg/sync/#Pool which can be used to reuse and reset buffers and that will produce great performance at scale for example please do this
and
Experimental result
and with some experiments this yields a 9+% speed up just for LeafOp
This value is going to compound when used with lots of code in the cosmos-sdk running over a period of time and even starting up. Our goal is to squeeze out every single ounce of performance and reclaim as much as we can, given that the cosmos-sdk is being used at scale now.
I highly encourage and adoption of this pattern all around this package.
Kindly paging some folks who might be interested in this: @alessio @robert-zaremba @ethanfrey @marbar3778 @okwme @erikgrinaker @zmanian @ebuchman.
The text was updated successfully, but these errors were encountered: