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
go build produces binaries that run with varying performance #66866
Comments
Please don't post screenshots, can't copy paste from them, have links to commits, codeblocks and other textual form, ... We really need more repeated runs of each binary to be statistically analyzed, for all that I know adding or removing empty print lines has negligeable effect and you are seeing random variance which would also happen if you built a binary once and ran it 5 times. |
We've seen this before, performance varying a lot based on how code is laid out in memory. We do try some things to mitigate this, like aligning various pieces of code. TL;DR If this effect is what I think it is, there's not much the Go project can do. You'll have to get your CPU vendor to stop making chips that have random(ish) performance variation. |
@Jorropo Thank you for pointing out the benchstat tool! I'll give it a try! @randall77 Thank you for pointing out that it could be CPU related. I've run some tests on 4 different PCs after I've read your post.
I'm having a hard time convincing myself that it's AMD's fault since I was making the benchmark in C before switching to Go and I have never had this problem with the C implementation. Also, simply adding a line I'll continue investigate this problem for a bit and I will open a new issue or even a PR but only if I come to find something tangible. By the way, goroutines are awesome! ❤️ Thank you! Cheers! |
I don't mean to be annoying. I make this last post for the sake of completeness. Output of
Output of
Output of
Here a screenshot of the command I used to run the benchmark and the output it yield: Explanation of the command:
Sadly, I could not include the execution of I noticed that any code I put in my BenchmarkMain function never affects performance. I've try in many ways, but performance always stayed the same. Only code use in the Main function seem to have an effect on performance. I provided the benchmark function and instructions to reproduce in this commit: PerfectlyFluffy/perfect28@7e84474 I think this is the best I can do to help with this issue. At this point it appears to be obvious that I did all of this for nothing, but I had a lot of fun. Cheers, |
Go version
go version go1.22.2 linux/amd64
Output of
go env
in your module/workspace:What did you do?
Excuse me for my not very good English. I'm programming a benchmark as my first open source contribution. Sources are available at https://github.com/PerfectlyFluffy/perfect28 in case you would want to get a closer look or even debug/test it. It have less than 400 lines of code, so it's quick to review.
What did you see happen?
Inconsistent performance. Since my program is a benchmark, it not only benchmark CPU's, it also benchmark go itself. This is why I noticed this sneaky problem. I have reproduced the problem on Arch Linux/go1.22.2, Debian/go1.19.8 (the problem was present in 1.19.8, but it was 50-60% less severe) and Fedora/go1.21.9. My CPU is a 5950X from AMD.
It's hard to explain, but I will try my best. Here is a screenshot to make it more visual:
On the preceding screenshot, we can get to the conclusion that my goal was to get rid of a loopclosure warning. Performance was good before I changed the code. I run this command each time I change my code to verify if performance is good or not : go build && time ./perfect28 --loop=1000000000000, here is the result when performance is good (before code changed):
I then modified lines 35 and 40 and ran the command again and I got this result:
Noticing a difference of 20 seconds in execution time, I uncommented line 15 to fix this degradation problem and ran the command again which gave me back good performance:
I conclude that any code change can have a big impact on performance, even change that are not expected to impact performance like calls to
fmt.Print()
orsync.WaitGroup.Add(x)
for example. When you rungo build
, you can end with either a good binary or a bad one. For this reason I always do a performance test before I commit my code to make sure I have good performance.This screenshot show that any change can have an impact on performance:
What I did was add line 18 => test => mark the time. Add line 19 => test => mark the time, and so on. I don't let the benchmark finish because I know that a binary is good when 5% is done under 3s.
What did you expect to see?
I expect performance of binaries not to degrade randomly based on how many line of code a program has.
I hope the information I provided will prove to be useful and that it will help find the root cause of the problem. Let me know if I can help in any ways!
I really enjoy coding Go apps! Thank you for your hard work! I appreciate it very much!
Cheers!
Dave
Edit: Typo
The text was updated successfully, but these errors were encountered: