-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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/compile: add a go:noinline directive #12312
Comments
Usually the implementation comes later :) Seems reasonable but makes me nervous. I have a general issue about the proliferation of such things, as I fear the compiler guys will, as always, infect the language with annotations. |
I am worried about proliferation here too but I certainly see the need for it repeatedly. It's okay with me. It's also okay for compilers to completely ignore it, like any other comment. :-) |
Could we limit the new annotations somehow?
I also think //go:notinlined is a better name to avoid the confusion
mentioned by Keith.
|
Restating the same: worried about proliferation. |
@minux said on golang-dev (moving here to keep the discussion in one place):
There are two reasons this is not as good as an annotation:
|
I think having this feature be test-only would be nice. We don't see any clean way to do that, however. The compiler doesn't know what is test code and what isn't. We'd have to add a flag to the compiler and have the go tool set that flag for test builds. That seems like a lot of ugly to keep people from using this feature where it doesn't belong. |
We could use the toolchain experiment support (see cmd/internal/obj/go.go)
and add a noinline experiment which controls the new directive.
And then we can enable the experiment at build time by setting
GOEXPERIMENT=noinline.
|
@minux hmmm. How would work with using |
I assumed that after the completion of SSA branch, there won't
be a need for //go:noinline.
GOEXPERIMENT is being embedded into the compiler though.
so you only need to set it before running make.bash.
|
I think it'll be useful outside of the SSA branch. A very cursory glance at the master branch suggests it'd be useful in pprof test's allocateTransient2M, runtime test's testIfaceEqual, the runtime's atomic* functions, fixedbugs/issue10441.go, fixedbugs/issue12133.go, and fixedbugs/issue8036.go. There are probably more. And it'd be a shame to lose the SSA tests when it gets merged into master and GOEXPERIMENT can no longer be set. |
"Useful" is always true for a feature request. The question is, does the usefulness justify the cost? The cost here is continued proliferation of magic comments, which are becoming too numerous already. |
My concern here is that a name like go:noinline sounds like something a developer could depend on. Maybe all that's needed is a different name or a qualification that tells the average developer to stay away or at least that the directive cannot be relied on, something like one of these: //go:test noinline |
We already have:
Does the same argument not apply to all those? Especially to e.g. "noescape"? We going to rename those to //go:internal_no_seriously_i_mean_it nowritebarrier? It's a comment. Anybody is free to ignore it. And it's an inlining option... it should not change semantics of the program. If it did, we'd have a bigger problem. So nobody should ever want to use it anyway, as it can only make things slower. I think there's way too much discussion here (including this comment) for something trivial and internal-only which exists only to clean up some tests. |
Only //go:noescape and //go:nosplit are publicly documented.
//go:nowritebarrier is internal and only allowed in runtime,
I proposed in #12454 to limit //go:systemstack to runtime
as well.
The other //go: directive is //go:linkname, which is used by
runtime and cgo, and it's also publicly documented.
|
Let's figure out why do we need to mark a function not Right now, I think the only reason is because inlined function Is there any other reason I missed? If my assumption that //go:noinline is only used to solve |
@minux another reason is because you need code to take a particular form to trigger a compiler bug, and preventing inlining allows a more minimal/reasonable form. See e.g. this from fixedbugs/issue10441.go: func bar() {
f := func() {}
foo(&f)
}
func foo(f *func()) func() {
defer func() {}() // prevent inlining of foo
return *f
} And with that, I'm giving up arguing for this. I thought it was a simple, unobtrusive, low visibility, low impact fix to an annoyance felt by people working on the compiler. It has ballooned to the point that it no longer feels worth the words. |
Is that better achieved with the -l option?
Another compromise is to introduce a compiler option to enable
the new directive. It just shouldn't be available by default.
Actually, having //go:noinline will benefit some of my code, but
my analysis of those code shows all its use are to workaround
the stack trace problem I mentioned earlier. I'd rather have that
fixed than introducing an easier way for people to mask that
problem. As I stressed, we definitely need to fix the issue if we
want to enable more inlining.
|
I agree with Josh, and I am astonished at the amount of discussion generated for a flag that I actually expect most users to avoid except when it really is necessary for real live workarounds. Imagine instead if it were //go:inline , and trying to stop people from using that inappropriately. As a general rule, I will always favor an explicit comment-expressed directive over attempting to control the compiler by subtext. We have "noinline" now. We spell it "switch {}". Is that documented? Is that guaranteed to work in the future? Is a random Go programmer going to know what that means, and leave it alone? |
Introducing a new directive for testing the compiler is one thing, I don't think we should add more generally available directives People might not use //go:noinline very often, but outside of Right now there is no convincing argument that explains why |
As an example where compiler improvements have changed the intent of a test with respect to inlining, see race/testdata/regression_test.go: func NewImage() Image {
var pleaseDoNotInlineMe stack
pleaseDoNotInlineMe.push(1)
_ = pleaseDoNotInlineMe.pop()
return Image{}
} I tested with go1.2 and the stack push/pop prevented inline. However, I just built that code and it no longer does. The test is no longer testing what it was intended to test due to the implicit prevention of inlining. |
Minux, I understand that you disagree, and for good ideal reasons, but pragmatically I think we should move forward with //go:noinline. Again, compilers in other toolchains will always be free to ignore it, just as they are free to ignore any comments. As for the specific name, "noinline" matches the other directives. I don't think we should introduce a second naming convention at this point. |
I think there's sufficient support in favor of this proposal that it should be accepted. |
CL https://golang.org/cl/13911 mentions this issue. |
We're thinking about adding a
<go:noinline>
directive to help with testing. Currently, if you don't want a function inlined, you add a<switch{}>
or a defer or other not-obviously-a-nop construct to the function. We'd like to introduce a new directive called<go:noinline>
to mark such functions, as the old way depends on a consistent definition of nop-obviousness (which we probably don't want to commit to).We particularly need this feature on the SSA branch because if a function is inlined, the code contained in that function might switch from being SSA-compiled to old-compiler-compiled. Without some sort of noinline mark the SSA-specific tests might not be testing the SSA backend at all.
It is possible that once everything is running under SSA this directive will be less useful, but I think it will be generically useful going forward. Thus I'd like to discuss this now in anticipation of it being merged into mainline sometime soon (if it is accepted).
Implementation is pretty easy, https://go-review.googlesource.com/13911 if you're interested.
The text was updated successfully, but these errors were encountered: