Timer metrics are metrics that measure nanosecond-precision operations within
the sentry, and present the results in an aggregated manner using distribution
bucketing.
They have a more convenient API than using distribution metrics directly, but
otherwise are just a convenient wrapper on top of them.
This requires exposing `runtime.nanotime()` from the Go runtime in order to
get the current time without causing system calls.
Intended usage:
```go
m := NewTimerMetric(...)
...
op := m.Start() // Starts measuring time from this point
... do something interesting...
op.Finish() // End the stopwatch.
```
Operation structs are meant to be self-contained to be able to be passed
around in code. Additionally, the timer metrics support multiple fields,
specifiable both at operation `Start` and `Finish` time.
This can be useful for measuring operations that can go down multiple
distinct branches, and creating aggregates that can selectively
differentiate between them. For example:
```go
m := NewTimerMetric("/packet_processing_time", ..., "protocol", "path")
...
func HandleTCPPacket(pkt TCPPacket) {
op := m.Start("tcp")
if fast path {
... do fast TCP handling...
op.Finish("fast")
return
}
doSlowTCPHandling(pkt, op) // `op` can be passed around
}
func doSlowTCPHandling(pkt TCPPacket, op TimerOperation) {
... do slow TCP handling...
op.Finish("slow")
}
func HandleUDPPacket(pkt UDPPacket) {
op := m.Start("udp")
... do UDP packet handling...
op.Finish("")
}
```
PiperOrigin-RevId: 436641265
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
This CL introduces a 'checklinkname' analyzer, which provides rudimentary
type-checking that verifies that function signatures on the local and remote
sides of //go:linkname directives match expected values.
If the Go standard library changes the definitions of any of these function,
checklinkname will flag the change as a finding, providing an error informing
the gVisor team to adapt to the upstream changes. This allows us to eliminate
the majority of gVisor's forward-looking negative build tags, as we can catch
mismatches in testing [1].
The remaining forward-looking negative build tags are covering shared struct
definitions, which I hope to add to checklinkname in a future CL.
[1] Of course, semantics/requirements can change without the signature
changing, so we still must be careful, but this covers the common case.
PiperOrigin-RevId: 387873847