package timing
import "gvisor.dev/gvisor/pkg/timing"
Package timing provides a way to record the timing of a series of operations across one or more goroutines.
Index ¶
- type Lease
- func (l *Lease) End()
- func (l *Lease) Fork(name string) *Timeline
- func (l *Lease) MultiFork(names []string) []*Timeline
- func (l *Lease) Reached(name string)
- func (l *Lease) Transfer() *Timeline
- type MidPoint
- type Timeline
- func OrphanTimeline(name string, startTime time.Time) *Timeline
- func (s *Timeline) End()
- func (s *Timeline) Fork(name string) *Timeline
- func (s *Timeline) Lease() *Lease
- func (s *Timeline) MultiFork(names []string) []*Timeline
- func (s *Timeline) Reached(name string)
- func (s *Timeline) ReachedAt(name string, when time.Time)
- type Timer
- func New(name string, startTime time.Time) *Timer
- func (t *Timer) Adopt(child *Timeline)
- func (t *Timer) End()
- func (t *Timer) Fork(name string) *Timeline
- func (t *Timer) Log()
- func (t *Timer) MultiFork(names []string) []*Timeline
- func (t *Timer) Reached(name string)
- func (t *Timer) ReachedAt(name string, when time.Time)
- func (t *Timer) StartTime() time.Time
Types ¶
type Lease ¶
type Lease struct {
// contains filtered or unexported fields
}
A Lease is a reference to a Timeline that is valid until the Lease is canceled. After calling Lease on a Timeline, the caller should no longer use the Timeline directly, and should instead use the Lease exclusively.
Leases should typically not cross function boundaries.
Leases are useful in complex functions where ownership of a Timeline needs to be *conditionally transferred* to a different goroutine at some late point in the function. Consider this example:
```
func SomeLongFunction(timeline *timing.Timeline) { defer timeline.End() // Convenient to defer `End` to hit all the `return` branches. timeline.Reached("some_point") if err := something(timeline); err != nil { return } timeline.Reached("some_other_point") if err := somethingElse(); err != nil { timeline.Reached("some_error") return } timeline.Reached("another_point") go doSomethingElse(timeline) // Don't want to call `End` anymore here! }
```
With a Lease:
```
func SomeLongFunction(timeline *timing.Timeline) { lease := timeline.Lease() defer lease.End() lease.Reached("some_point") if err := something(); err != nil { lease.Reached("some_error") return } if err := somethingElse(); err != nil { lease.Reached("some_other_error") return } lease.Reached("another_point") go doSomethingElse(lease.Transfer()) // `End` is not called anymore here. }
```
func (*Lease) End ¶
func (l *Lease) End()
End ends the Timeline if the Lease is valid. The lease is invalidated after this call. See `Timeline.End` for more details.
func (*Lease) Fork ¶
Fork forks the Timeline if the Lease is valid. See `Timeline.Fork` for more details.
func (*Lease) MultiFork ¶
MultiFork forks the Timeline if the Lease is valid. See `Timeline.MultiFork` for more details.
func (*Lease) Reached ¶
Reached records a new midpoint on the Timeline if the Lease is valid. See `Timeline.Reached` for more details.
func (*Lease) Transfer ¶
Transfer invalidates the current Lease and returns the underlying Timeline. Typically useful when transferring ownership of a Timeline to a different goroutine while giving up ownership in the current one. See `Lease` documentation for example usage.
type MidPoint ¶
type MidPoint struct {
// contains filtered or unexported fields
}
MidPoint is a named point in time on a Timeline. The starting and ending points of a Timeline are not MidPoints.
type Timeline ¶
type Timeline struct {
// contains filtered or unexported fields
}
Timeline is a series of points in time.
A Timeline always has a defined start time, and will eventually have an end time. For this reason, `End` must always be called on a Timeline.
A Timeline may have zero or more mid-points contained between the start and end times.
A Timeline may fork to represent other timelines running concurrently. Such children Timelines may or may not end later than the parent does.
A single Timeline struct should be owned by a single goroutine at a given time until it ends (i.e. its endpoint becomes defined), at which point ownership transfers to the goroutine that owns the Timer that created it.
A Timeline may be nil, in which case all methods are no-ops. This means all code that takes in a Timeline parameter does not need to check for nilness.
func OrphanTimeline ¶
OrphanTimeline creates a new Timeline that is not owned by any Timer. This is useful for operations that are part of a broader sequence of operations represented by a Timer, but where timing measurements are desired before this broader parent Timer is known. The returned Timeline must be parented with `timer.Adopt` in order to be useful.
func (*Timeline) End ¶
func (s *Timeline) End()
End marks the Timeline as having ended. It must be eventually called on all Timelines. After End is called, the ownership of the Timeline struct moves to the goroutine that owns the Timer that created it.
func (*Timeline) Fork ¶
Fork creates a new Timeline that is a child of this one. A midpoint is implicitly added to the current Timeline.
The returned Timeline is initially owned by the caller, but may be passed to another goroutine if desired.
A child timeline may but does not need to end before the parent does.
Forked timelines are useful to represent parallel operations like separate goroutines, and are actually required in such cases so that the goroutine can own its own Timeline, but non-concurrent code may also use Fork to represent its own linear operations as a tree if it so desires.
func (*Timeline) Lease ¶
Lease returns a Lease for the Timeline. The Lease is valid until it is canceled by calling `End` or `Transfer`. See `Lease` for example usage.
func (*Timeline) MultiFork ¶
MultiFork creates new Timelines that are children of this one. It returns as many Timelines as there are names in `names`. All of them share the same start time. A midpoint is implicitly added to the current Timeline. The same semantics as `Timeline.Fork` apply.
func (*Timeline) Reached ¶
Reached records a new midpoint on the Timeline.
func (*Timeline) ReachedAt ¶
ReachedAt records a new midpoint on the root Timeline of the Timer with the given timestamp.
type Timer ¶
type Timer struct {
// contains filtered or unexported fields
}
Timer is a root Timeline. It keeps track of one or more running Timelines, and can be pretty-printed to show timing information once all Timelines have ended.
A Timer struct may move between goroutines, but only one goroutine may own it at a time.
A Timer struct may be nil, in which case all methods are no-ops. This means all code that takes in a Timer parameter does not need to check for nilness.
func New ¶
New creates a new Timer. The given name is used to identify the Timer in pretty-printed output. The given startTime is used as the start time of the Timer's root Timeline.
func (*Timer) Adopt ¶
Adopt adopts a Timeline into this Timer. May only be called with Timelines created by `OrphanTimeline`, and may only be called once per such Timeline. The calling goroutine must own both the Timeline and the Timer.
func (*Timer) End ¶
func (t *Timer) End()
End waits for all Timelines owned by this Timer to end, then pretty-prints timing information. If not all Timelines have ended by the time End is called, End will spin in place until they do, and eventually print a warning log if it spins for too long (but will not give up). End is called implicitly by Log, so it is not necessary to call End explicitly unless there is a need to end the root timeline at a different time than when logging its data is desired.
func (*Timer) Fork ¶
Fork creates a new Timeline that is a child of the root Timeline of this Timer. The returned Timeline is initially owned by the caller, but may be passed to another goroutine if desired. This child Timeline may but does not need to end before the root timeline does. Forked timelines are useful to represent parallel operations like separate goroutines, and are actually required in such cases so that the goroutine can own its own Timeline, but non-concurrent code may also use Fork to represent its own linear operations as a tree if it so desires.
func (*Timer) Log ¶
func (t *Timer) Log()
Log pretty-prints timing information for the root Timeline of the Timer. If `t.End` has not yet been called, it will be called implicitly. This also means that this function will wait for all child Timelines to end before pretty-printing, and will spin in place until this is the case. If debug logging is enabled, this function will also log a flat list of events that can be easily machine-parsed to the debug log.
func (*Timer) MultiFork ¶
MultiFork creates new Timelines that are children of the root Timeline of this Timer. See Timeline.MultiFork for more details.
func (*Timer) Reached ¶
Reached records a new midpoint on the root Timeline of the Timer.
func (*Timer) ReachedAt ¶
ReachedAt records a new midpoint on the root Timeline of the Timer with the given timestamp.
func (*Timer) StartTime ¶
StartTime returns the start time of the Timer.
Source Files ¶
timing.go
- Version
- v0.0.0-20250514213907-8db5d40e4cb5 (latest)
- Published
- May 14, 2025
- Platform
- linux/amd64
- Imports
- 7 packages
- Last checked
- 3 hours ago –
Tools for package owners.