-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
cmd/link: emitting DWARF doubles time spent in linker #26318
Comments
As a point of comparison, I ran both a perflock benchcmd -n 10 BuildCmdGoAll sh -c "rm -f /tmp/x1 && go build -o /tmp/x1 -a cmd/go" > dwarf
perflock benchcmd -n 10 BuildCmdGoAll sh -c "rm -f /tmp/x1 && go build -o /tmp/x1 -a -gcflags -dwarf=false -ldflags -w cmd/go" > nodwarf
perflock benchcmd -n 10 LinkCmdGo sh -c "rm -f /tmp/x1 && go build -o /tmp/x1 cmd/go" >> dwarf
perflock benchcmd -n 10 LinkCmdGo sh -c "rm -f /tmp/x1 && go build -o /tmp/x1 -ldflags -w cmd/go" >> nodwarf
benchsave nodwarf dwarf From my linux/amd64 laptop:
(https://perf.golang.org/search?q=upload:20180711.1) This at least probably explains how we missed this. We were exceedingly careful about compiler performance and kept an eye on overall build performance, but weren't looking at the effects on just the link step. Perhaps compilebench should include a linker benchmark. Looking at the profiles, about half of the additional link time comes from compression. An easy thing to try would be to reduce the compression level to favor speed. About a quarter of the time comes from |
This is pretty promising. Using
And the impact on binary size is minimal.
|
Change https://golang.org/cl/123356 mentions this issue: |
DWARF compression accounts for roughly 30% of the linker's time. This CL switches from DefaultCompression to BestSpeed, which virtually eliminates this time. This roughly halves the overhead of handling DWARF in the linker: name \ time/op nodwarf dwarf dwarf-speed BuildCmdGoAll 10.0s ±11% 10.6s ± 5% 10.8s ± 5% nodwarf +6.41% +8.03% dwarf ~ LinkCmdGo 626ms ± 5% 1096ms ± 2% 860ms ± 2% nodwarf +75.17% +37.36% dwarf -21.59% Previously, enabling DWARF had a 75% overhead in link time for cmd/go. This change reduces this overhead to 37% (a 22% reduction). The effect on binary size is minimal compared to DefaultCompression, and still substantially better than no compression: cmd/go bytes nodwarf 10106953 dwarf 12159049 nodwarf+20% dwarf-speed 12408905 nodwarf+23% dwarf-nozlib 17766473 nodwarf+76% Updates #26318. Change-Id: I33bb7caa038a2753c29104501663daf4839e7054 Reviewed-on: https://go-review.googlesource.com/123356 Run-TryBot: Austin Clements <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
@aclements benchcmd looks really nice. Where does it come from? Some light googling and github searches didn't turn it up. |
Here's a comparison of building vs just linking jujud between Go 1.10 and tip (including BestSpeed DWARF compression):
So, we're winning on non-incremental builds, probably because of indexed export info, but the link step in isolation is 26% slower. Not great, though certainly better than 2X or the 40% reported in #26074 (comment). |
Change https://golang.org/cl/126656 mentions this issue: |
People sometimes want to turn on a particular go command flag by default. In Go 1.11 we have at least two different cases where users may need this. 1. Linking can be noticeably slower on underpowered systems due to DWARF, and users may want to set -ldflags=-w by default. 2. For modules, some users or CI systems will want vendoring always, so they want -getmode=vendor (soon to be -mod=vendor) by default. This CL generalizes the problem to “set default flags for the go command.” $GOFLAGS can be a space-separated list of flag settings, but each space-separated entry in the list must be a standalone flag. That is, you must do 'GOFLAGS=-ldflags=-w' not 'GOFLAGS=-ldflags -w'. The latter would mean to pass -w to go commands that understand it (if any do; if not, it's an error to mention it). For #26074. For #26318. Fixes #26585. Change-Id: I428f79c1fbfb9e41e54d199c68746405aed2319c Reviewed-on: https://go-review.googlesource.com/126656 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rob Pike <[email protected]>
Here is what I see today.
WIth DWARF the average is
WIthout DWARF:
So today the slowdown of using DWARF is around 30%, which is a lot better than 200%. Looking at the CPU profile when linking cmd/go I see 4.76% of CPU time in These numbers seem plausible to me and I think we've answered the question posed by this issue, so closing. |
On Linux:
Just plain "go list -json cmd/go", which essentially does the prep for a build, takes about 0.12r, so the upper bound on time spent in link here is about 0.45r without DWARF and 0.93r with DWARF. That is, emitting DWARF doubles the amount of time it takes for the linker to execute. We don't pay this cost for "go test" or "go run", because we turn DWARF off for those already.
The Mac shows a similar ~2X slowdown. I thought maybe #12259 was related but given that Linux clearly is unaffected by that issue, it appears to be a general DWARF problem.
I've put the proposal to turn off DWARF by default (#26074) on hold pending better understanding of where all the time is going (this issue). If we decide that DWARF really is a 2X cost, then we need to go back to #26074 and decide whether that's worth paying on every build when most people make no use of the DWARF info.
/cc @dr2chase @cherrymui @thanm @ianlancetaylor @randall77 @aclements @RLH
The text was updated successfully, but these errors were encountered: