Some synchronization patterns require the ability to simultaneously wake and
sleep a goroutine. For the sleep package, this is the case when a waker must be
asserted when a subsequent fetch is imminent.
Currently, this operation results in significant P churn in the runtime, which
ping-pongs execution between multiple system threads and cores and consumes a
significant amount of host CPU (and because of the context switches, this can
be significant worse with mitigations for side channel vulnerabilities).
The solution is to introduce a dedicated mechanism for a synchronous switch
which does not wake another runtime P (see golang/go#32113). This can be used
by the `AssertAndFetch` API in the sleep package.
The benchmark results for this package are very similiar to raw channel
operations for all cases, with the exception of operations that do not wait.
The primary advantage is more precise control over scheduling. This will be
used in a subsequent change.
```
BenchmarkGoAssertNonWaiting
BenchmarkGoAssertNonWaiting-8 261364384 4.976 ns/op
BenchmarkGoSingleSelect
BenchmarkGoSingleSelect-8 20946358 57.77 ns/op
BenchmarkGoMultiSelect
BenchmarkGoMultiSelect-8 6071697 197.0 ns/op
BenchmarkGoWaitOnSingleSelect
BenchmarkGoWaitOnSingleSelect-8 4978051 235.4 ns/op
BenchmarkGoWaitOnMultiSelect
BenchmarkGoWaitOnMultiSelect-8 2309224 520.2 ns/op
BenchmarkSleeperAssertNonWaiting
BenchmarkSleeperAssertNonWaiting-8 447325033 2.657 ns/op
BenchmarkSleeperSingleSelect
BenchmarkSleeperSingleSelect-8 21488844 55.19 ns/op
BenchmarkSleeperMultiSelect
BenchmarkSleeperMultiSelect-8 21851674 54.89 ns/op
BenchmarkSleeperWaitOnSingleSelect
BenchmarkSleeperWaitOnSingleSelect-8 2860327 416.4 ns/op
BenchmarkSleeperWaitOnSingleSelectSync
BenchmarkSleeperWaitOnSingleSelectSync-8 2741733 427.1 ns/op
BenchmarkSleeperWaitOnMultiSelect
BenchmarkSleeperWaitOnMultiSelect-8 2867484 418.1 ns/op
BenchmarkSleeperWaitOnMultiSelectSync
BenchmarkSleeperWaitOnMultiSelectSync-8 2789158 427.9 ns/op
```
PiperOrigin-RevId: 415581417
Consider the following benchmark, which is equivalent to
BenchmarkSleeperWaitOnSingleSelect with names changed to more closely reflect
the behavior of BenchmarkGoWaitOnSingleSelect:
var (
empty Sleeper
emptyCond Waker
full Sleeper
fullCond Waker
)
empty.AddWaker(&emptyCond)
full.AddWaker(&fullCond)
go func() {
for i := 0; i < b.N; i++ {
empty.Fetch(true)
fullCond.Assert()
}
}()
for i := 0; i < b.N; i++ {
emptyCond.Assert()
full.Fetch(true)
}
The unfairness arises because runtime.chansend and runtime.chanrecv don't
actually work this way. If runtime.chansend blocks, it has already enqueued the
element to be sent on runtime.hchan.sendq, which runtime.chanrecv dequeues
before calling goready(); in sleep-like terms, by the time empty.Fetch()
returns, fullCond.Assert() has already happened and been fetched by the other
goroutine. The same property applies to runtime.chanrecv/runtime.hchan.recvq.
This property has no correspondence to the actual usage of the sleep package,
so change the channel benchmarks to explicitly exchange control using buffered
channels instead. Also remove some stale comments and align the syncevent
benchmarks with the sleep ones.
BenchmarkSleeperWaitOnSingleSelect
BenchmarkSleeperWaitOnSingleSelect-12 2118603 472.5 ns/op
BenchmarkGoWaitOnSingleSelect
BenchmarkGoWaitOnSingleSelect-12 2224262 517.7 ns/op
BenchmarkSleeperWaitOnMultiSelect
BenchmarkSleeperWaitOnMultiSelect-12 2630569 459.8 ns/op
BenchmarkGoWaitOnMultiSelect
BenchmarkGoWaitOnMultiSelect-12 807918 1312 ns/op
BenchmarkWaiterPingPong
BenchmarkWaiterPingPong-12 2955579 385.8 ns/op
BenchmarkSleeperPingPong
BenchmarkSleeperPingPong-12 2454367 474.3 ns/op
BenchmarkChannelPingPong
BenchmarkChannelPingPong-12 2302662 513.5 ns/op
BenchmarkWaiterPingPongMulti
BenchmarkWaiterPingPongMulti-12 3023676 388.8 ns/op
BenchmarkSleeperPingPongMulti
BenchmarkSleeperPingPongMulti-12 2574064 471.5 ns/op
BenchmarkChannelPingPongMulti
BenchmarkChannelPingPongMulti-12 1000000 1088 ns/op
PiperOrigin-RevId: 407760956
In a subsequent change, the Sleeper API will be plumbed through and used for
arbitrary task wakeups. This requires a non-static association of Wakers and
Sleepers, which means that a fixed ID no longer works. This is a relatively
simple change that removes the ID from the Waker association, and simply uses
the Waker pointer itself.
That change also makes minor improvements to the tests to ensure that the
benchmarks are more representative by removing goroutine start from the hot
path (and uses Wakers for required synchronization), adds assertion checks to
AddWaker, and clears relevant fields during Done (to allow assertions to pass).
PiperOrigin-RevId: 407719630
None of the dependencies have changed in 1.15. It may be possible to simplify
some of the wrappers in rawfile following 1.13, but that can come in a later
change.
PiperOrigin-RevId: 313863264
All inbound segments for connections in ESTABLISHED state are delivered to the
endpoint's queue but for every segment delivered we also queue the endpoint for
processing to a selected processor. This ensures that when there are a large
number of connections in ESTABLISHED state the inbound packets are all handled
by a small number of goroutines and significantly reduces the amount of work the
goscheduler has to perform.
We let connections in other states follow the current path where the
endpoint's goroutine directly handles the segments.
Updates #231
PiperOrigin-RevId: 289728325
Funcion signatures are not validated during compilation. Since
they are not exported, they can change at any time. The guard
ensures that they are verified at least on every version upgrade.
PiperOrigin-RevId: 250733742
gopark's signature was changed from having a string reason to a
uint8.
See: https://github.com/golang/go/commit/4d7cf3fedbc382215df5ff6167ee9782a9cc9375
This broke execution tracing of the sentry.
Switching to the right signature makes tracing work again.
Updates #220
PiperOrigin-RevId: 249565311
Change-Id: If77fd276cecb37d4003c8222f6de510b8031a074
Based on the guidelines at
https://opensource.google.com/docs/releasing/authors/.
1. $ rg -l "Google LLC" | xargs sed -i 's/Google LLC.*/The gVisor Authors./'
2. Manual fixup of "Google Inc" references.
3. Add AUTHORS file. Authors may request to be added to this file.
4. Point netstack AUTHORS to gVisor AUTHORS. Drop CONTRIBUTORS.
Fixes#209
PiperOrigin-RevId: 245823212
Change-Id: I64530b24ad021a7d683137459cafc510f5ee1de9
Nothing reads them and they can simply get stale.
Generated with:
$ sed -i "s/licenses(\(.*\)).*/licenses(\1)/" **/BUILD
PiperOrigin-RevId: 231818945
Change-Id: Ibc3f9838546b7e94f13f217060d31f4ada9d4bf0
This change also adds extensive testing to the p9 package via mocks. The sanity
checks and type checks are moved from the gofer into the core package, where
they can be more easily validated.
PiperOrigin-RevId: 218296768
Change-Id: I4fc3c326e7bf1e0e140a454cbacbcc6fd617ab55
The //go:linkname directive requires the presence of
assembly files in the package. Even an empty file will do.
There was an empty assembly file commit_arm64.s, but
that is limited to GOARCH=arm64. Renaming to empty.s will
remove the unnecessary build constraint and allow building
netstack for other architectures than amd64 and arm64.
Without this, building directly with go (not bazel)
for e.g., GOARCH=arm gives:
sleep/sleep_unsafe.go:88:6: missing function body
sleep/sleep_unsafe.go:91:6: missing function body
Change-Id: I29d1d13e1ff31506a174d4595b8cd57fa58bf52b
PiperOrigin-RevId: 214820299
We have been unnecessarily creating too many savable types implicitly.
PiperOrigin-RevId: 206334201
Change-Id: Idc5a3a14bfb7ee125c4f2bb2b1c53164e46f29a8