Skip to content

encoding/base64: improve performance up to 20% total #36910

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

Closed
wants to merge 1 commit into from

Conversation

kirillx
Copy link
Contributor

@kirillx kirillx commented Jan 30, 2020

Improve base64 encoding/decoding performance by
suppressing compiler boundary checks on decode.

name old speed new speed delta
EncodeToString-8 570MB/s ± 1% 573MB/s ± 1% ~ (p=0.421 n=5+5)
DecodeString/2-8 88.6MB/s ± 3% 91.6MB/s ± 2% +3.37% (p=0.016 n=5+5)
DecodeString/4-8 162MB/s ± 1% 168MB/s ± 0% +4.12% (p=0.008 n=5+5)
DecodeString/8-8 203MB/s ± 0% 214MB/s ± 0% +5.18% (p=0.008 n=5+5)
DecodeString/64-8 471MB/s ± 1% 520MB/s ± 1% +10.50% (p=0.008 n=5+5)
DecodeString/8192-8 757MB/s ± 0% 895MB/s ± 1% +18.29% (p=0.008 n=5+5)

@googlebot googlebot added the cla: yes Used by googlebot to label PRs as having a valid CLA. The text of this label should not change. label Jan 30, 2020
@gopherbot
Copy link
Contributor

This PR (HEAD: 3525c07) has been imported to Gerrit for code review.

Please visit https://go-review.googlesource.com/c/go/+/217117 to see it.

Tip: You can toggle comments from me using the comments slash command (e.g. /comments off)
See the Wiki page for more info

@gopherbot
Copy link
Contributor

Message from Ian Lance Taylor:

Patch Set 1: Code-Review-2

Let's not start applying unsafe transformations to speed up this package. Let's instead think about how to improve the compiler so that these transformations are not required.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Kirill Korotaev:

Patch Set 1:

Well, for the 5 past years I'm looking into golang people are struggling to make compiler smarter yet simplest cases like this still do not work. You can check the huge history of the string<->[]byte conversion topic in issue tracking. Why having faster std library by using unsafe is considered so bad? we can remove unsafe usages one by one as compiler improves. Moreover, these places will be an exact pieces telling us where compiler is not so good and worth improving.

Other thoughts:
I believe to avoid string <-> []byte conversion penalty compiler has to perform const analysis similar to escape one. Ideally functions should have flags for all the arguments whether they escape or const, not a single one.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Ian Lance Taylor:

Patch Set 1:

Well, for the 5 past years I'm looking into golang people are struggling to make compiler smarter yet simplest cases like this still do not work. You can check the huge history of the string<->[]byte conversion topic in issue tracking. Why having faster std library by using unsafe is considered so bad? we can remove unsafe usages one by one as compiler improves. Moreover, these places will be an exact pieces telling us where compiler is not so good and worth improving.

Using unsafe in the standard library, outside of specialized areas like runtime, reflect, and syscall, is bad because it shows a deficiency in the language or the implementation. If we permit ourselves to use unsafe in ordinary packages like encoding/base64 then we are using a trick. We are telling other people "Go is a safe and fast language" while we use techniques that we don't expect other people to use. That's not a good way to approach language and library design. (We have admittedly given ourselves exceptions like strings.Builder, but we try hard to keep those to only the most important parts of the library.)

By all means use your faster version of encoding/base64 yourself, and make it available to other people. I just don't think that the standard library is the place for code like this.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Daniel Martí:

Patch Set 1:

If one needs base64 encoding or decoding that's super fast, at the cost of simplicity or security, they can already use third party libraries with unsafe or assembly. The standard library avoids those as much as possible, and I agree with Ian here.

Yes, it will take a while for the compiler to get really good at these optimizations, and that's fine.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Kirill Korotaev:

Patch Set 1:

Patch Set 1:

If one needs base64 encoding or decoding that's super fast, at the cost of simplicity or security, they can already use third party libraries with unsafe or assembly. The standard library avoids those as much as possible, and I agree with Ian here.

Ian, Daniel, are you ok if I remove unsafe usage and leave boundary checks optimisation only?


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Daniel Martí:

Patch Set 1:

Sure, I'd be fine with an optimization for the bounds checks. Just make sure to include benchmark numbers to prove that the performance improved; the code has been optimized multiple times in the past, so we can't just work on assumptions.

You should use benchstat with multiple runs, like -count=10. Also see perflock if the variance is too high.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@googlebot googlebot added cla: no Used by googlebot to label PRs as having an invalid CLA. The text of this label should not change. and removed cla: yes Used by googlebot to label PRs as having a valid CLA. The text of this label should not change. labels Mar 7, 2020
@gopherbot
Copy link
Contributor

This PR (HEAD: 6102ed7) has been imported to Gerrit for code review.

Please visit https://go-review.googlesource.com/c/go/+/217117 to see it.

Tip: You can toggle comments from me using the comments slash command (e.g. /comments off)
See the Wiki page for more info

@kirillx kirillx changed the title encoding/base64: improve performance up to 40% total encoding/base64: improve performance up to 20% total Mar 7, 2020
@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@googlebot googlebot added cla: yes Used by googlebot to label PRs as having a valid CLA. The text of this label should not change. and removed cla: no Used by googlebot to label PRs as having an invalid CLA. The text of this label should not change. labels Mar 7, 2020
Unfortunately compiler is not capable to realise that boundary checks
are not necessary on each src[si+N] access.
Selection of sub-slice helps.

benchmark                        old MB/s     new MB/s     speedup
BenchmarkEncodeToString-8        598.08       595.89       1.00x
BenchmarkDecodeString/2-8        96.32        98.97        1.03x
BenchmarkDecodeString/4-8        174.19       180.41       1.04x
BenchmarkDecodeString/8-8        215.03       225.91       1.05x
BenchmarkDecodeString/64-8       496.53       548.24       1.10x
BenchmarkDecodeString/8192-8     778.83       916.62       1.18x
@gopherbot
Copy link
Contributor

Message from Gobot Gobot:

Patch Set 2:

Congratulations on opening your first change. Thank you for your contribution!

Next steps:
Within the next week or so, a maintainer will review your change and provide
feedback. See https://golang.org/doc/contribute.html#review for more info and
tips to get your patch through code review.

Most changes in the Go project go through a few rounds of revision. This can be
surprising to people new to the project. The careful, iterative review process
is our way of helping mentor contributors and ensuring that their contributions
have a lasting impact.

During May-July and Nov-Jan the Go project is in a code freeze, during which
little code gets reviewed or merged. If a reviewer responds with a comment like
R=go1.11, it means that this CL will be reviewed as part of the next development
cycle. See https://golang.org/s/release for more details.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

This PR (HEAD: 2c87abc) has been imported to Gerrit for code review.

Please visit https://go-review.googlesource.com/c/go/+/217117 to see it.

Tip: You can toggle comments from me using the comments slash command (e.g. /comments off)
See the Wiki page for more info

@gopherbot
Copy link
Contributor

Message from Kirill Korotaev:

Patch Set 3:

Ian, Daniel,
I have updated PR and left boundary checks optimisation only (no unsafe!). It gives up to 20% gain on large buffers.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Kirill Korotaev:

Patch Set 3: Code-Review+1

Ian?


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Daniel Martí:

Patch Set 3:

The change seems fine, but please use benchstat to prove your results and include its output in your commit message.

See #23471 and https://godoc.org/golang.org/x/perf/cmd/benchstat.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Daniel Martí:

Patch Set 3:

Also, please don't approve your own change.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Kirill Korotaev:

Patch Set 4:

Patch Set 3:

The change seems fine, but please use benchstat to prove your results and include its output in your commit message.

Daniel, added the same benchmark results to PR message as well.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Ian Lance Taylor:

Patch Set 4: Run-TryBot+1 -Code-Review


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Gobot Gobot:

Patch Set 4:

TryBots beginning. Status page: https://farmer.golang.org/try?commit=0ad445f0


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

Message from Gobot Gobot:

Patch Set 4: TryBot-Result+1

TryBots are happy.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

gopherbot pushed a commit that referenced this pull request Apr 22, 2020
Improve base64 encoding/decoding performance by
suppressing compiler boundary checks on decode.

name                 old speed      new speed      delta
EncodeToString-8      570MB/s ± 1%   573MB/s ± 1%     ~     (p=0.421 n=5+5)
DecodeString/2-8     88.6MB/s ± 3%  91.6MB/s ± 2%   +3.37%  (p=0.016 n=5+5)
DecodeString/4-8      162MB/s ± 1%   168MB/s ± 0%   +4.12%  (p=0.008 n=5+5)
DecodeString/8-8      203MB/s ± 0%   214MB/s ± 0%   +5.18%  (p=0.008 n=5+5)
DecodeString/64-8     471MB/s ± 1%   520MB/s ± 1%  +10.50%  (p=0.008 n=5+5)
DecodeString/8192-8   757MB/s ± 0%   895MB/s ± 1%  +18.29%  (p=0.008 n=5+5)

Change-Id: I135243c11aa4c974a4a4e95c5c2abb0635d52c8c
GitHub-Last-Rev: 2c87abc
GitHub-Pull-Request: #36910
Reviewed-on: https://go-review.googlesource.com/c/go/+/217117
Run-TryBot: Ian Lance Taylor <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
@gopherbot
Copy link
Contributor

Message from Ian Lance Taylor:

Patch Set 4: Code-Review+2

Thanks, much nicer.


Please don’t reply on this GitHub thread. Visit golang.org/cl/217117.
After addressing review feedback, remember to publish your drafts!

@gopherbot
Copy link
Contributor

This PR is being closed because golang.org/cl/217117 has been merged.

@gopherbot gopherbot closed this May 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Used by googlebot to label PRs as having a valid CLA. The text of this label should not change.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants