open-location-code icon indicating copy to clipboard operation
open-location-code copied to clipboard

Reduce runtime of go Encode() implementation by 20%

Open willbeason opened this issue 2 years ago • 3 comments

This is a performance optimization change for Encode().

As-is, Encode() always calls a stringconcat (by "+"-ing strings together). This call is unnecessary as we know the structure of the location codes ahead of time, and non-performant as stringconcat is slow compared to slicebytetostring.

To do this, I made the initial byte slice allocated represent the entire final code and immediately fill in the separator. This means later, when we format the code, we don't need to concatenate the Separator in as it is already there.

I introduce a special case for the location pair after the separator rather than having those bytes computed in the loop: otherwise we need to have an if-statement within the loop. As a bonus, having these computed first let us remove the two unnecessary divides that formerly happened at the end of the final loop. (I am unsure if this last point is noticeable - I could not detect a significant difference.)

I haven't bothered with optimizing the case for codes which need padding before the separator (or which do not use the full 15 non-separator characters) - given that the benchmark does not deal with such cases, I assumed such cases are far less used.

Performance difference on my machine:

Before:

will@Janeway:~/GolandProjects/open-location-code/go$ go test --run=NONE --bench=Encode --benchtime=10s -cpuprofile=/home/will/cpu2.out
goos: linux
goarch: amd64
pkg: github.com/google/open-location-code/go
cpu: AMD Ryzen Threadripper 3970X 32-Core Processor 
BenchmarkEncode-64    	163811120	        72.50 ns/op	      16 B/op	       1 allocs/op
PASS
ok  	github.com/google/open-location-code/go	22.076s

After:

will@Janeway:~/GolandProjects/open-location-code/go$ go test --run=NONE --bench=Encode --benchtime=10s -cpuprofile=/home/will/after.out
goos: linux
goarch: amd64
pkg: github.com/google/open-location-code/go
cpu: AMD Ryzen Threadripper 3970X 32-Core Processor 
BenchmarkEncode-64    	198057280	        56.89 ns/op	      16 B/op	       1 allocs/op
PASS
ok  	github.com/google/open-location-code/go	20.486s

I've attached cpu profiles of before/after as well.

before after

willbeason avatar Nov 08 '23 23:11 willbeason

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

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

google-cla[bot] avatar Nov 08 '23 23:11 google-cla[bot]

Okay, signed CLA.

willbeason avatar Nov 08 '23 23:11 willbeason

Playing around with the code, I found a second optimization that improves performance an additional 10%. I'll include it as a follow-up, separate PR as it could potentially be controversial.

willbeason avatar Nov 09 '23 04:11 willbeason