-
Notifications
You must be signed in to change notification settings - Fork 385
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
perf: use fmt.Fprintf to avoid unnecessary string+args + WriteString #3434
base: master
Are you sure you want to change the base?
Conversation
🛠 PR Checks SummaryAll Automated Checks passed. ✅ Manual Checks (for Reviewers):
Read More🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers. ✅ Automated Checks (for Contributors):🟢 Maintainers must be able to edit this pull request (more info) ☑️ Contributor Actions:
☑️ Reviewer Actions:
📚 Resources:Debug
|
Codecov ReportAttention: Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more cleaner than previous version. I left some comments
gnovm/pkg/gnolang/machine.go
Outdated
@@ -2131,25 +2131,25 @@ func (m *Machine) String() string { | |||
totalLength = vsLength + ssLength + xsLength + bsLength + obsLength + fsLength + exceptionsLength | |||
) | |||
|
|||
var builder strings.Builder | |||
builder := new(strings.Builder) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strings.Builder
is a value type, so you don't need to create it using the new keyword. Using new
will allocate memory on the heap, which may result in another unnecessary memory allocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, builder doesn't escape the heap. Go isn't like traditional languages where invoking "new" automatically allocates on the heap; escape analysis determines that and you can verifiably check that it doesn't escape and also run benchmarks to see that it doesn't escape using -gcflags='-l -m'
. I can however bring it to a much better compromise of
var sb strings.Builder
builder := &sb
which is a much better compromise than
fmt.Fprintf(&sb, ...)
in every spot and materially even faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I didn't know that flag option has exists. Then this seems to have no problem at all. 👍
ff8f2c3
to
932a525
Compare
Thank you for the code review and discourse @notJoon, I've made an update, kindly please help me take another stab. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 💯
932a525
to
902ba09
Compare
In a bid to remove unnecessary CPU and memory bloat for the gnovm which takes the order of minutes to run certain code, I noticed the pattern: io.StringWriter.WriteString(fmt.Sprintf(...)) in which fmt.Sprintf(...) has to create a string by inserting all arguments into the format specifiers then pass that into .WriteString which defeats the entire purpose of io.StringWriter.WriteString that *bytes.Buffer and *strings.Builder implement. Just from picking a single benchmark that already exists results in improvements in all dimensions: ```shell $ benchstat before.txt after.txt name old time/op new time/op delta StringLargeData-8 8.87ms ± 1% 8.28ms ± 3% -6.68% (p=0.000 n=17+19) name old alloc/op new alloc/op delta StringLargeData-8 8.44MB ± 0% 7.78MB ± 0% -7.75% (p=0.000 n=20+19) name old allocs/op new allocs/op delta StringLargeData-8 94.1k ± 0% 70.1k ± 0% -25.51% (p=0.000 n=15+20) ``` for heavily used code this is going to reduce on garbage collection cycles too. Fixes gnolang#3433
902ba09
to
6cd03c2
Compare
In a bid to remove unnecessary CPU and memory bloat for the gnovm which takes the order of minutes to run certain code, I noticed the pattern:
in which fmt.Sprintf(...) has to create a string by inserting all arguments into the format specifiers then pass that into .WriteString which defeats the entire purpose of io.StringWriter.WriteString that *bytes.Buffer and *strings.Builder implement.
Just from picking a single benchmark that already exists results in improvements in all dimensions:
for heavily used code this is going to reduce on garbage collection cycles too.
Fixes #3433