refactor: replace []byte(fmt.Sprintf) with fmt.Appendf
Description
Optimize code using a more modern writing style. Official support from Go, for more details visit https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize.
What has Changed?
What specific problem were you aiming to address, and how did you successfully resolve it? If tests were not uploaded for this pull request or if coverage decreased, please provide an explanation for the change.
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.
I have...
- [x] included the correct type prefix in the PR title
- [ ] added
!to the type prefix if API or client breaking change - [x] targeted the correct branch (see PR Targeting)
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for building modules
- [ ] included the necessary unit and integration tests
- [ ] included comments for documenting Go code
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.
I have...
- [ ] confirmed the correct type prefix in the PR title
- [ ] confirmed
!in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
Deployment Notes
Are there any specific considerations to take into account when deploying these changes? This may include new dependencies, scripts that need to be executed, or any aspects that can only be evaluated in a deployed environment.
Screenshots and Videos
Please provide any relevant before and after screenshots by uploading them here. Additionally, demo videos can be highly beneficial in demonstrating the process.
This seems slower than the current code based on benchmark tests and a same number of allocations:
import (
"fmt"
"testing"
)
var denom = "atom"
// Benchmark using fmt.Sprintf + conversion to []byte
func BenchmarkSprintfToByte(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = []byte(fmt.Sprintf("%s/", denom))
}
}
// Benchmark using fmt.Appendf (Go 1.21+)
func BenchmarkFmtAppendf(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = fmt.Appendf(nil, "%s/", denom)
}
}
// Benchmark using a plain append for one alloc
func BenchmarkAppendLiteral(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = append([]byte(denom), '/')
}
}
Result:
go test -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: github.com/elys-network/elys
cpu: Apple M2
BenchmarkSprintfToByte-8 22679624 56.99 ns/op 21 B/op 2 allocs/op
BenchmarkFmtAppendf-8 20122227 59.30 ns/op 24 B/op 2 allocs/op
BenchmarkAppendLiteral-8 452519115 2.651 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/elys-network/elys 5.382s
Using the append literal seems a lot faster @yetyear
This seems slower than the current code based on benchmark tests and a same number of allocations:
import ( "fmt" "testing" ) var denom = "atom" // Benchmark using fmt.Sprintf + conversion to []byte func BenchmarkSprintfToByte(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { _ = []byte(fmt.Sprintf("%s/", denom)) } } // Benchmark using fmt.Appendf (Go 1.21+) func BenchmarkFmtAppendf(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { _ = fmt.Appendf(nil, "%s/", denom) } } // Benchmark using a plain append for one alloc func BenchmarkAppendLiteral(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { _ = append([]byte(denom), '/') } }Result:
go test -bench=. -benchmem goos: darwin goarch: arm64 pkg: github.com/elys-network/elys cpu: Apple M2 BenchmarkSprintfToByte-8 22679624 56.99 ns/op 21 B/op 2 allocs/op BenchmarkFmtAppendf-8 20122227 59.30 ns/op 24 B/op 2 allocs/op BenchmarkAppendLiteral-8 452519115 2.651 ns/op 0 B/op 0 allocs/op PASS ok github.com/elys-network/elys 5.382sUsing the append literal seems a lot faster @yetyear
I conducted a test, and it is related to the length of the string. For example, the performance test below:
package main
import (
"fmt"
"testing"
)
var demoStr = "testStr"
func init() {
for range 10 {
demoStr += demoStr
}
}
// Benchmark using fmt.Sprintf + conversion to []byte
func BenchmarkSprintfToByte(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = []byte(fmt.Sprintf("%s/", demoStr))
}
}
// Benchmark using fmt.Appendf (Go 1.21+)
func BenchmarkFmtAppendf(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = fmt.Appendf(nil, "%s/", demoStr)
}
}
// Benchmark using a plain append for one alloc
func BenchmarkAppendLiteral(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = append([]byte(demoStr), '/')
}
}
The result:
goos: darwin
goarch: arm64
pkg: demo/fmtappendf
cpu: Apple M2
BenchmarkSprintfToByte-8 1119710 927.7 ns/op 8216 B/op 2 allocs/op
BenchmarkSprintfToByte-8 1398566 859.2 ns/op 8217 B/op 2 allocs/op
BenchmarkSprintfToByte-8 1407386 852.1 ns/op 8217 B/op 2 allocs/op
BenchmarkSprintfToByte-8 1410823 849.3 ns/op 8217 B/op 2 allocs/op
BenchmarkSprintfToByte-8 1383681 854.2 ns/op 8217 B/op 2 allocs/op
BenchmarkFmtAppendf-8 1397036 853.7 ns/op 8217 B/op 2 allocs/op
BenchmarkFmtAppendf-8 1410096 863.1 ns/op 8216 B/op 2 allocs/op
BenchmarkFmtAppendf-8 1391970 960.4 ns/op 8216 B/op 2 allocs/op
BenchmarkFmtAppendf-8 1382676 863.9 ns/op 8216 B/op 2 allocs/op
BenchmarkFmtAppendf-8 1374649 859.2 ns/op 8216 B/op 2 allocs/op
BenchmarkAppendLiteral-8 1615996 743.3 ns/op 8192 B/op 1 allocs/op
BenchmarkAppendLiteral-8 1607259 763.0 ns/op 8192 B/op 1 allocs/op
BenchmarkAppendLiteral-8 1565144 1016 ns/op 8192 B/op 1 allocs/op
BenchmarkAppendLiteral-8 1588842 850.6 ns/op 8192 B/op 1 allocs/op
BenchmarkAppendLiteral-8 1383158 1134 ns/op 8192 B/op 1 allocs/op
PASS
ok test/fmtappendf 32.094s
I don't think it's a good idea to change it to the third way here. Do you have any more suggestions?