Source File
annotation.go
Belonging Package
runtime/trace
// Copyright 2018 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package traceimport (_)type traceContextKey struct{}// NewTask creates a task instance with the type taskType and returns// it along with a Context that carries the task.// If the input context contains a task, the new task is its subtask.//// The taskType is used to classify task instances. Analysis tools// like the Go execution tracer may assume there are only a bounded// number of unique task types in the system.//// The returned Task's [Task.End] method is used to mark the task's end.// The trace tool measures task latency as the time between task creation// and when the End method is called, and provides the latency// distribution per task type.// If the End method is called multiple times, only the first// call is used in the latency measurement.//// ctx, task := trace.NewTask(ctx, "awesomeTask")// trace.WithRegion(ctx, "preparation", prepWork)// // preparation of the task// go func() { // continue processing the task in a separate goroutine.// defer task.End()// trace.WithRegion(ctx, "remainingWork", remainingWork)// }()func ( context.Context, string) ( context.Context, *Task) {:= fromContext().id:= newID()userTaskCreate(, , ):= &Task{id: }return context.WithValue(, traceContextKey{}, ),// We allocate a new task even when// the tracing is disabled because the context and task// can be used across trace enable/disable boundaries,// which complicates the problem.//// For example, consider the following scenario:// - trace is enabled.// - trace.WithRegion is called, so a new context ctx// with a new region is created.// - trace is disabled.// - trace is enabled again.// - trace APIs with the ctx is called. Is the ID in the task// a valid one to use?//// TODO(hyangah): reduce the overhead at least when// tracing is disabled. Maybe the id can embed a tracing// round number and ignore ids generated from previous// tracing round.}func fromContext( context.Context) *Task {if , := .Value(traceContextKey{}).(*Task); {return}return &bgTask}// Task is a data type for tracing a user-defined, logical operation.type Task struct {id uint64// TODO(hyangah): record parent id?}// End marks the end of the operation represented by the [Task].func ( *Task) () {userTaskEnd(.id)}var lastTaskID uint64 = 0 // task id issued last timefunc newID() uint64 {// TODO(hyangah): use per-P cachereturn atomic.AddUint64(&lastTaskID, 1)}var bgTask = Task{id: uint64(0)}// Log emits a one-off event with the given category and message.// Category can be empty and the API assumes there are only a handful of// unique categories in the system.func ( context.Context, , string) {:= fromContext().iduserLog(, , )}// Logf is like [Log], but the value is formatted using the specified format spec.func ( context.Context, , string, ...any) {if IsEnabled() {// Ideally this should be just Log, but that will// add one more frame in the stack trace.:= fromContext().iduserLog(, , fmt.Sprintf(, ...))}}const (regionStartCode = uint64(0)regionEndCode = uint64(1))// WithRegion starts a region associated with its calling goroutine, runs fn,// and then ends the region. If the context carries a task, the region is// associated with the task. Otherwise, the region is attached to the background// task.//// The regionType is used to classify regions, so there should be only a// handful of unique region types.func ( context.Context, string, func()) {// NOTE:// WithRegion helps avoiding misuse of the API but in practice,// this is very restrictive:// - Use of WithRegion makes the stack traces captured from// region start and end are identical.// - Refactoring the existing code to use WithRegion is sometimes// hard and makes the code less readable.// e.g. code block nested deep in the loop with various// exit point with return values// - Refactoring the code to use this API with closure can// cause different GC behavior such as retaining some parameters// longer.// This causes more churns in code than I hoped, and sometimes// makes the code less readable.:= fromContext().iduserRegion(, regionStartCode, )defer userRegion(, regionEndCode, )()}// StartRegion starts a region and returns it.// The returned Region's [Region.End] method must be called// from the same goroutine where the region was started.// Within each goroutine, regions must nest. That is, regions started// after this region must be ended before this region can be ended.// Recommended usage is//// defer trace.StartRegion(ctx, "myTracedRegion").End()func ( context.Context, string) *Region {if !IsEnabled() {return noopRegion}:= fromContext().iduserRegion(, regionStartCode, )return &Region{, }}// Region is a region of code whose execution time interval is traced.type Region struct {id uint64regionType string}var noopRegion = &Region{}// End marks the end of the traced code region.func ( *Region) () {if == noopRegion {return}userRegion(.id, regionEndCode, .regionType)}// IsEnabled reports whether tracing is enabled.// The information is advisory only. The tracing status// may have changed by the time this function returns.func () bool {return tracing.enabled.Load()}//// Function bodies are defined in runtime/trace.go//// emits UserTaskCreate event.func userTaskCreate(, uint64, string)// emits UserTaskEnd event.func userTaskEnd( uint64)// emits UserRegion event.func userRegion(, uint64, string)// emits UserLog event.func userLog( uint64, , string)
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |