Prologue
In my previous post, I talked about my fix for a long time go comamnd bug. Then I bet you
that the fix is unlikely to cause any issue.
I was wrong, and here’s the story.
The bug
One day in Gopher Slack #tools, dominikhonnef (an experienced/respectful Gopher) asked:
when testing compiler changes/bisecting compiler bugs, is it enough to do
go install cmd/compile? till now I’ve always done a full make.bash, but that’s a bit slow
We traded some sentences, and though I showed him another way instead of using make.bash, I didn’t pay much attention to that, since when make.bash in my M1 is pretty fast.
The day after, @bcmills (owner of cmd/go) said:
@dominikh, alternately, we could make
make.bashproperly saturate big machines… 😅
Then @dominikhonnef showed:
go 1.17: 203.46user 16.89system 0:35.27elapsed 624%CPU (0avgtext+0avgdata 863856maxresident)k
master: 204.67user 15.30system 0:56.85elapsed 386%CPU (0avgtext+0avgdata 833420maxresident)k
So make.bash becomes slower between go 1.17 and tip, there must be a regression introduced during go 1.18 development cycle.
More surprising, @dominikhonnef bisected to this commit:
commit a6ff433d6a927e8ad8eaa6828127233296d12ce5 (HEAD, refs/bisect/bad)
Author: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Date: Wed Aug 25 14:56:01 2021 +0700
cmd/go: pass -gcflags after other flags generated by the go command
Otherwise, any gc flags set by user using "-gcflags" won't have effect.
Fixes #47682
Change-Id: Icd365577cba1f64f6c7b8320d0c9019de9f062f6
Reviewed-on: https://go-review.googlesource.com/c/go/+/344909
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
which is authored by me. @dominikhonnef even went further and show that -c flag isn’t passed to the compiler anymore:
well, if looking at random output by
go build -xis anything to go by… there is no more-cbeing passed togo tool compile
I wonder why just swapping the order of flags causes a flag disappear?
Re-reading CL 344909, I realize that it did more things than just swapping the flags!
If you read Fixing section in my previous post, you will see not only the two flags was swapped, but also the misleading flags gcargs
was removed, and it was merged in to gcflags variable. However, that variable is used by function gcBackendConcurrency
to determine the backend compiler concurrency level for a package compilation. Here’s part of that function:
CheckFlags:
for _, flag := range gcflags {
// Concurrent compilation is presumed incompatible with any gcflags,
// except for known commonly used flags.
// If the user knows better, they can manually add their own -c to the gcflags.
switch flag {
case "-N", "-l", "-S", "-B", "-C", "-I":
// OK
default:
canDashC = false
break CheckFlags
}
}
Since when the gcflags now contains flags from gcargs, so more flags are present in gcflags than before, canDashC will be false.
The fix
I sent CL 351049 to fix the bug. It’s quite simple, just don’t merge those flags set like they were before, and we’re good.
Note
When writing test case for the bug, I found an issue that go command does not do concurrent compilation on darwin/arm64!
That’s the reason I don’t see the slow down when running make.bash in my M1 after CL 344909.
Updated 24/09/2021
I sent a followup CL 351849, hopefully making the code easier to understand/maintain and prevent subtle bug like this.
Epilogue
A lesson that I learn after this story, never do refactoring+fixing in the same CL (or commit). Fix the bug with one CL and do refactoring in the followup one.
Thanks for reading so far!
Till next time!