-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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
runtime: trim unnecessary fields from scase #40410
Comments
As it stands, eliminating just one of these will likely help considerably, as it will make this struct SSA-able. |
It looks like per-scase releasetime is intended to help when the select is awoken because of a channel closing. However, it turns out this code has corner cases that would be addressed by replacing it with a single When However, there's no guarantee that the re-poll will actually pick the same case that triggered the wakeup. It's possible that between the channel close wakeup and the goroutine getting to run, other cases might become ready too. If one of these other cases ends up getting selected on the re-poll, we'll never end up recording a block event. As an extreme but somewhat contrived example (involving selecting on the same channel twice), this program spends a total of 1 second blocked waiting for the The more realistic example, this program also spends 1 second blocked waiting for the |
Change https://golang.org/cl/245019 mentions this issue: |
Change https://golang.org/cl/245124 mentions this issue: |
Change https://golang.org/cl/245126 mentions this issue: |
Change https://golang.org/cl/245123 mentions this issue: |
Change https://golang.org/cl/245125 mentions this issue: |
Change https://golang.org/cl/245122 mentions this issue: |
Uploaded a WIP patch series that implements this. The change to separate the Easy fix is probably to create and populate the |
Some notes to self on more cleanup still to do:
|
We currently allow The easiest solution would be to just reduce the max cases from 65536 to 65535. Then they'll trivially fit into The harder solution is to take advantage of the invariant |
I think reducing to 65535 would be OK. The point of |
The current wakeup protocol for channel communications is that the second goroutine sets gp.param to the sudog when a value is successfully communicated over the channel, and to nil when the wakeup is due to closing the channel. Setting nil to indicate channel closure works okay for chansend and chanrecv, because they're only communicating with one channel, so they know it must be the channel that was closed. However, it means selectgo has to re-poll all of the channels to figure out which one was closed. This commit adds a "success" field to sudog, and changes the wakeup protocol to always set gp.param to sg, and to use sg.success to indicate successful communication vs channel closure. While here, this also reorganizes the chansend code slightly so that the sudog is still released to the pool if the send blocks and then is awoken because the channel closed. Updates #40410. Change-Id: I6cd9a20ebf9febe370a15af1b8afe24c5539efc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/245019 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@golang.org>
selectgo will report at most one block event, so there's no need to keep a releasetime for every select case. It suffices to simply track the releasetime of the case responsible for the wakeup. Updates #40410. Change-Id: I72679cd43dde80d7e6dbab21a78952a4372d1e79 Reviewed-on: https://go-review.googlesource.com/c/go/+/245122 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
Currently, selectgo does an initial pass over the cases array to look for entries with nil channels, so they can be easily recognized and skipped later on. But this still involves actually visiting the cases. This commit changes selectgo to omit cases with nil channels when constructing pollorder, so that they'll be skipped over entirely later on. It also checks for caseDefault up front, which will facilitate changing it to use a "block bool" parameter instead. Updates #40410. Change-Id: Icaebcb8f08df03cc33b6d8087616fb5585f7fedd Reviewed-on: https://go-review.googlesource.com/c/go/+/245123 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
Per-case PCs are only needed for race detector builds, so this allows skipping allocating stack space for them for non-race builds. It's possible to arrange the PCs and order arrays consecutively in memory so that we could just reuse the order0 pointer to identify both. However, there's more risk of that silently going wrong, so this commit passes them as separate arguments for now. We can revisit this in the future. Updates #40410. Change-Id: I8468bc25749e559891cb0cb007d1cc4a40fdd0f8 Reviewed-on: https://go-review.googlesource.com/c/go/+/245124 Reviewed-by: Keith Randall <khr@golang.org>
Remove some unnecessary code. Most significantly, we can skip testing "if ch == nil { block() }", because this is already the semantics implied by normal send/receive operations. Updates #40410. Change-Id: I4acd33383cc876719fc3b998d85244d4ac1ff9d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/245126 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Change https://golang.org/cl/279735 mentions this issue: |
Change https://golang.org/cl/279734 mentions this issue: |
Change https://golang.org/cl/279733 mentions this issue: |
Change https://golang.org/cl/279732 mentions this issue: |
This is the gofrontend version of https://golang.org/cl/245122. Original CL description: selectgo will report at most one block event, so there's no need to keep a releasetime for every select case. It suffices to simply track the releasetime of the case responsible for the wakeup. Updates golang/go#40410. This is being brought over to gofrontend as a step toward upgrading to Go1.16beta1. Change-Id: I60688303cdae72f89cfa9777402933ecee2503f7 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/279732 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This is the gofrontend version of https://golang.org/cl/245123. Original CL description: Currently, selectgo does an initial pass over the cases array to look for entries with nil channels, so they can be easily recognized and skipped later on. But this still involves actually visiting the cases. This commit changes selectgo to omit cases with nil channels when constructing pollorder, so that they'll be skipped over entirely later on. It also checks for caseDefault up front, which will facilitate changing it to use a "block bool" parameter instead. Updates golang/go#40410 This is being brought over to gofrontend as a step toward upgrading to Go1.16beta1, setting up for more compiler changes related to select handling. Change-Id: I1a7a305636fb35e2a747d79dc83292888ceeac69 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/279733 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This is the gofrontend version of https://golang.org/cl/245019. Original CL description: The current wakeup protocol for channel communications is that the second goroutine sets gp.param to the sudog when a value is successfully communicated over the channel, and to nil when the wakeup is due to closing the channel. Setting nil to indicate channel closure works okay for chansend and chanrecv, because they're only communicating with one channel, so they know it must be the channel that was closed. However, it means selectgo has to re-poll all of the channels to figure out which one was closed. This commit adds a "success" field to sudog, and changes the wakeup protocol to always set gp.param to sg, and to use sg.success to indicate successful communication vs channel closure. While here, this also reorganizes the chansend code slightly so that the sudog is still released to the pool if the send blocks and then is awoken because the channel closed. For golang/go#40410 This is being brought over to gofrontend as a step toward upgrading to Go1.16beta1, setting up for more compiler changes related to select handling. Change-Id: I8d36d7be40cae2e0fdcbdf73959a95dc815f3f1c Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/279734 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This is the gofrontend version of https://golang.org/cl/245125. Original CL description: Currently, we include a "kind" field on scase to distinguish the three kinds of cases in a select statement: sends, receives, and defaults. This commit removes by kind field by instead arranging for the compiler to always place sends before receives, and to provide their counts separately. It also passes an explicit "block bool" parameter to avoid needing to include a default case in the array. It's safe to shuffle cases like this because the runtime will randomize the order they're polled in anyway. For golang/go#40410. This is being brought over to gofrontend as a step toward upgrading to Go1.16beta1. Change-Id: I39a0a83c25e15fbd3cdfac7f31e01df9f2cddd3f Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/279735 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This is the gofrontend version of https://golang.org/cl/245125. Original CL description: Currently, we include a "kind" field on scase to distinguish the three kinds of cases in a select statement: sends, receives, and defaults. This commit removes by kind field by instead arranging for the compiler to always place sends before receives, and to provide their counts separately. It also passes an explicit "block bool" parameter to avoid needing to include a default case in the array. It's safe to shuffle cases like this because the runtime will randomize the order they're polled in anyway. For golang/go#40410. This is being brought over to gofrontend as a step toward upgrading to Go1.16beta1. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/279735
Currently the
runtime.scase
structure is 5 words (6 words on 32-bit machines):I think this can be trimmed down to just 2:
c
andelem
. Here's how:The
pc
field is only needed for race-instrumented builds. Instead of embedding it directly into thescase
array (and using stack space even for non-instrumented builds), we can split it out into a separate array that's prepended to thepollorder
/lockorder
arrays for race-instrumented builds, and omitted entirely for race-instrumented builds. (We'd prepend it becauseuintptr
has stricter alignment thanuint16
.)The
releasetime
field is only needed for the case that actually succeeds. Rather than adding it to eachscase
, we can just have an extracasreleasetime
local variable that parallelscas
andcasi
. (I think: I'm least confident about this as I'm not familiar with the runtime's blocking profiling.)The
kind
field currently disambiguates four cases: send, recv, default, and nil. We can eliminate this field with a sequence of three optimizations:There can be only one default case. So instead of emitting a dummy scase to represent the default case,
selectgo
can just take an extra boolean parameter indicating whether the call should block or not. When in non-blocking mode,selectgo
should just return-1
as the case index, and callers can handle this accordingly. This would simplifyselectgo
, because it wouldn't need to search for and remember where thecaseDefault
case is.caseNil
is used internally withinselectgo
to simplify skipping over send/recv cases withc
is nil. But instead of doing it this way,selectgo
could simply omit nil-c cases from thepollorder
andlockorder
arrays when they're constructed. Then the rest of code will naturally skip over them.That leaves just send and recv cases. Because the runtime is going to randomize the order that cases will be processed anyway, the compiler can simply arrange that send cases always precede receive cases (or vice versa), and split
ncases
intonsends
andnrecvs
. Thenselectgo
can discern send and recv cases by just comparing the case index (e.g., if sends are ordered before receives, thencasi < nsends
would indicatecas
is a send operation).Requiring sends before recvs will be slightly more work for
reflect.Select
, but it shouldn't be too bad. It already has to translate from[]reflect.SelectCase
to[]runtime.scase
(and currently it goes through an extra step and extra heap allocations withruntime.runtimeSelect
). It should be easy to construct the latter by placing sends at the front of the slice and receives at the rear (remember: order in[]runtime.scase
doesn't matter), and just tracking a correspondence of array indices to translateselectgo
's return value back./cc @aclements
The text was updated successfully, but these errors were encountered: