Skip to content
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: go:linkname prevents inlining #20019

Open
dvyukov opened this issue Apr 18, 2017 · 16 comments
Open

cmd/compile: go:linkname prevents inlining #20019

dvyukov opened this issue Apr 18, 2017 · 16 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. Performance
Milestone

Comments

@dvyukov
Copy link
Member

dvyukov commented Apr 18, 2017

go version devel +33c3477039 Tue Apr 18 03:56:16 2017 +0000 linux/amd64

sync_runtime_procPin is marked with //go:linkname sync_runtime_procPin sync.runtime_procPin. Runtime marks it as inlinable (which is good). However, sync fails to inline it with cannot inline runtime_canSpin: no function body.
There are more functions exposed from runtime to sync, sync/atomic, reflect, time, os.
Can we inline them?

@dvyukov
Copy link
Member Author

dvyukov commented Apr 18, 2017

@valyala
Copy link
Contributor

valyala commented Apr 18, 2017

cc'ing @josharian

@josharian
Copy link
Contributor

At first glance, looks like an import/export issue--the function body is not associated correctly (or perhaps not exported at all) when linkname is present.

cc @mdempsky @griesemer

@josharian josharian added this to the Go1.9Maybe milestone Apr 18, 2017
@dvyukov
Copy link
Member Author

dvyukov commented Apr 18, 2017

It's possible to quickly estimate the benefits -- make procPin/Unpin public in runtime and directly call from sync.Pool. @valyala care to prototype?

@cherrymui
Copy link
Member

@josharian If I understand correctly, linkname is resolved at link time (as the name suggests). The runtime package doesn't export those names.

@valyala
Copy link
Contributor

valyala commented Apr 18, 2017

It's possible to quickly estimate the benefits -- make procPin/Unpin public in runtime and directly call from sync.Pool. @valyala care to prototype?

@dvyukov , sure:

GOMAXPROCS=4:

name            old time/op  new time/op  delta
Pool-4          10.5ns ± 9%   8.8ns ± 9%  -15.59%  (p=0.000 n=10+10)
PoolOverflow-4  2.10µs ± 3%  1.95µs ± 2%   -7.29%  (p=0.000 n=10+10)

GOMAXPROCS=1:

name          old time/op  new time/op  delta
Pool          20.3ns ± 2%  16.9ns ± 3%  -17.06%  (p=0.000 n=10+10)
PoolOverflow  4.96µs ± 2%  4.75µs ± 1%   -4.16%  (p=0.000 n=10+9)

@josharian
Copy link
Contributor

@cherrymui but I believe we do have inlining information in the export data for non-exported function, specifically for (multi-level) inlining.

@cherrymui
Copy link
Member

@josharian you're right, thanks!
But the package that have functions implemented by another package may not import that package. sync/atomic doesn't import runtime, and the compiler doesn't even read runtime.a when compiling sync/atomic. For this to work, we'll need to add import _ "runtime" in sync/atomic?

@josharian
Copy link
Contributor

@cherrymui true. And that doesn't seem too much to ask, if you're already using go:linkname. :) Although this also reproduces with package sync (in pool.go), which does already import package runtime.

@mdempsky
Copy link
Member

I think the issue is just in bimport.go and trivially fixable. @dvyukov do you have an easy standalone test case for this?

@dvyukov
Copy link
Member Author

dvyukov commented Apr 18, 2017

@mdempsky no, I don't. I was looking at sync_runtime_procPin.

@mdempsky
Copy link
Member

Thanks. I can repro the issue, but realized it's more involved than simply tweaking bimport.go.

Currently, we associate function inlining bodies only at the individual Node level. To fix this, we'll need to cross-reference them via LSyms.

@josharian
Copy link
Contributor

Not sure that's worth it at the moment.

@bradfitz bradfitz modified the milestones: Go1.9Maybe, Go1.10 Jul 20, 2017
@bradfitz bradfitz modified the milestones: Go1.10, Go1.11 Nov 28, 2017
@bradfitz bradfitz modified the milestones: Go1.11, Unplanned May 18, 2018
@CAFxX
Copy link
Contributor

CAFxX commented Jan 29, 2019

If this is fixed I believe we can also rewrite Get/Put so that the fast path (get from/put into l.private) is inlined. Would it maybe be possible to put ProcPin/ProcUnpin in internal?

@ugorji
Copy link
Contributor

ugorji commented Dec 29, 2020

Gentle ping.

@mdempsky
Copy link
Member

Would it maybe be possible to put ProcPin/ProcUnpin in internal?

In general, my preference would be towards more internal packages, rather than more use of //go:linkname. So that has my support, if it's applicable for this particular problem. (I'd even argue that we should move most of the current runtime package to a new internal/runtime package so it can simply export anything needed by the rest of the standard library, and then the existing runtime package just contains the public APIs, implemented on top of the internal ones.)

As for enabling inlining of //go:linknamed functions, I still think that's doable, at least for "push"-style linknames (i.e., when a lower-level package like runtime explicitly declares a function to be made available in a higher-level package like sync or net). I don't have any immediate plans to tackle this though. I'd encourage trying to use inline packages first; and if that proves impractical, I'll reassess.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jul 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. Performance
Projects
None yet
Development

No branches or pull requests

9 participants