Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce encoding and decoding allocations #16

Merged
merged 4 commits into from
Nov 3, 2021

Conversation

2opremio
Copy link

@2opremio 2opremio commented Nov 2, 2021

I reduced the allocation count by:

  1. Adding a scratch buffer to the Encoder/decoder. The scratch
    buffer is used as a temporary buffer. Before that, temporary
    buffers were allocated (in the heap since they escaped the stack)
    for basic type encoding/decoding (e.g. DecodeInt() EncodeInt()

  2. Making DecodeFixedOpaque() decode in-place instead of
    allocating the result. Apart from reducing allocations,
    this removes the need of copying (as shown by decodeFixedArray().

The pre-existing (and admitedly very limited) benchmarks show a sizeable improvement:

Before:

goos: darwin
goarch: amd64
pkg: github.com/stellar/go-xdr/xdr3
cpu: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
BenchmarkUnmarshal
BenchmarkUnmarshal-8   	 1445005	       853.5 ns/op	  18.75 MB/s	     152 B/op	      11 allocs/op
BenchmarkMarshal
BenchmarkMarshal-8     	 1591068	       643.0 ns/op	  24.88 MB/s	     104 B/op	      10 allocs/op
PASS

After:

goos: darwin
goarch: amd64
pkg: github.com/stellar/go-xdr/xdr3
cpu: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
BenchmarkUnmarshal
BenchmarkUnmarshal-8   	 2297332	       519.6 ns/op	  30.79 MB/s	     144 B/op	       8 allocs/op
BenchmarkMarshal
BenchmarkMarshal-8     	 2757748	       425.0 ns/op	  37.65 MB/s	      96 B/op	       7 allocs/op
PASS

Decoding goes down to 8 allocations from 11 allocations per operation.

Encoding goes down to 7 allocations from 10 allocations per operation.

More context at stellar/go#4022 (comment)

I reduced the allocation count by

1. Adding a scratch buffer to the Encoder/decoder. The scratch
   buffer is used as a temporary buffer. Before that, temporary
   buffers were allocated (in the heap since they escaped the stack)
   for basic type encoding/decoding (e.g. `DecodeInt()` `EncodeInt()`

2. Making `DecodeFixedOpaque()` decode in-place instead of
   allocating the result. Apart from reducing allocations,
   this removes the need of copying (as shown by `decodeFixedArray()`.

The pre-existing (and admitedly very limited) benchmarks show a sizeable improvement:

Before:

```
goos: darwin
goarch: amd64
pkg: github.com/stellar/go-xdr/xdr3
cpu: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
BenchmarkUnmarshal
BenchmarkUnmarshal-8   	 1445005	       853.5 ns/op	  18.75 MB/s	     152 B/op	      11 allocs/op
BenchmarkMarshal
BenchmarkMarshal-8     	 1591068	       643.0 ns/op	  24.88 MB/s	     104 B/op	      10 allocs/op
PASS
```

After:

```
goos: darwin
goarch: amd64
pkg: github.com/stellar/go-xdr/xdr3
cpu: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
BenchmarkUnmarshal
BenchmarkUnmarshal-8   	 1753954	       661.4 ns/op	  24.19 MB/s	     144 B/op	       8 allocs/op
BenchmarkMarshal
BenchmarkMarshal-8     	 2103310	       537.1 ns/op	  29.79 MB/s	     104 B/op	       8 allocs/op
PASS
```

Both decoding and encoding both go down to 8 allocations from 11 (decoding) and 10 (encoding) allocations per operation.

More context at stellar/go#4022 (comment)
2opremio added a commit to 2opremio/go-2 that referenced this pull request Nov 2, 2021
Copy link
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! I have one ask (❗), and a suggestion (💡), and some questions (❔) and thoughts (💭). Other than the ask it looks good to me. I think @bartekn should review this too, and he may have thoughts on the testing method.

xdr3/decode.go Outdated Show resolved Hide resolved
xdr3/decode.go Show resolved Hide resolved
xdr3/decode.go Outdated Show resolved Hide resolved
Comment on lines +295 to +298
b := enc.scratchBuf[:pad]
for i := 0; i < pad; i++ {
b[i] = 0x0
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 I wonder what bugs using a shared scratch buffer will open up. Would it impact performance to use a function to get at the buf which zeroed the buf everytime? Maybe not worth it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would surely impact performance, but I don't know to what extent

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concurrency problems came to mind when I added the buffer, but that would require multiple goroutines to share the same encoder/decoder, which I don't think makes sense at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 I don't think this needs to support concurrency. It's unlikely a reader would support that anyway.

Copy link

@tamirms tamirms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great!

@2opremio 2opremio force-pushed the reduce-allocations branch 3 times, most recently from 94b38a1 to 87cb50a Compare November 3, 2021 13:20
Copy link

@bartekn bartekn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@2opremio 2opremio merged commit 8017fc4 into stellar:master Nov 3, 2021
@2opremio 2opremio deleted the reduce-allocations branch November 3, 2021 14:48
2opremio added a commit to 2opremio/go-2 that referenced this pull request Nov 3, 2021
Copy link
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Awesome work.

2opremio added a commit to stellar/go that referenced this pull request Nov 3, 2021
sreuland pushed a commit to sreuland/go that referenced this pull request Aug 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants