libgo: update to Go 1.11
[official-gcc.git] / libgo / go / runtime / trace / annotation.go
blob3545ef3bba5719bb6a24bb03f19cbe67047341b4
1 package trace
3 import (
4 "context"
5 "fmt"
6 "sync/atomic"
7 _ "unsafe"
10 type traceContextKey struct{}
12 // NewTask creates a task instance with the type taskType and returns
13 // it along with a Context that carries the task.
14 // If the input context contains a task, the new task is its subtask.
16 // The taskType is used to classify task instances. Analysis tools
17 // like the Go execution tracer may assume there are only a bounded
18 // number of unique task types in the system.
20 // The returned end function is used to mark the task's end.
21 // The trace tool measures task latency as the time between task creation
22 // and when the end function is called, and provides the latency
23 // distribution per task type.
24 // If the end function is called multiple times, only the first
25 // call is used in the latency measurement.
27 // ctx, task := trace.NewTask(ctx, "awesome task")
28 // trace.WithRegion(ctx, prepWork)
29 // // preparation of the task
30 // go func() { // continue processing the task in a separate goroutine.
31 // defer task.End()
32 // trace.WithRegion(ctx, remainingWork)
33 // }
34 func NewTask(pctx context.Context, taskType string) (ctx context.Context, task *Task) {
35 pid := fromContext(pctx).id
36 id := newID()
37 userTaskCreate(id, pid, taskType)
38 s := &Task{id: id}
39 return context.WithValue(pctx, traceContextKey{}, s), s
41 // We allocate a new task and the end function even when
42 // the tracing is disabled because the context and the detach
43 // function can be used across trace enable/disable boundaries,
44 // which complicates the problem.
46 // For example, consider the following scenario:
47 // - trace is enabled.
48 // - trace.WithRegion is called, so a new context ctx
49 // with a new region is created.
50 // - trace is disabled.
51 // - trace is enabled again.
52 // - trace APIs with the ctx is called. Is the ID in the task
53 // a valid one to use?
55 // TODO(hyangah): reduce the overhead at least when
56 // tracing is disabled. Maybe the id can embed a tracing
57 // round number and ignore ids generated from previous
58 // tracing round.
61 func fromContext(ctx context.Context) *Task {
62 if s, ok := ctx.Value(traceContextKey{}).(*Task); ok {
63 return s
65 return &bgTask
68 // Task is a data type for tracing a user-defined, logical operation.
69 type Task struct {
70 id uint64
71 // TODO(hyangah): record parent id?
74 // End marks the end of the operation represented by the Task.
75 func (t *Task) End() {
76 userTaskEnd(t.id)
79 var lastTaskID uint64 = 0 // task id issued last time
81 func newID() uint64 {
82 // TODO(hyangah): use per-P cache
83 return atomic.AddUint64(&lastTaskID, 1)
86 var bgTask = Task{id: uint64(0)}
88 // Log emits a one-off event with the given category and message.
89 // Category can be empty and the API assumes there are only a handful of
90 // unique categories in the system.
91 func Log(ctx context.Context, category, message string) {
92 id := fromContext(ctx).id
93 userLog(id, category, message)
96 // Logf is like Log, but the value is formatted using the specified format spec.
97 func Logf(ctx context.Context, category, format string, args ...interface{}) {
98 if IsEnabled() {
99 // Ideally this should be just Log, but that will
100 // add one more frame in the stack trace.
101 id := fromContext(ctx).id
102 userLog(id, category, fmt.Sprintf(format, args...))
106 const (
107 regionStartCode = uint64(0)
108 regionEndCode = uint64(1)
111 // WithRegion starts a region associated with its calling goroutine, runs fn,
112 // and then ends the region. If the context carries a task, the region is
113 // associated with the task. Otherwise, the region is attached to the background
114 // task.
116 // The regionType is used to classify regions, so there should be only a
117 // handful of unique region types.
118 func WithRegion(ctx context.Context, regionType string, fn func()) {
119 // NOTE:
120 // WithRegion helps avoiding misuse of the API but in practice,
121 // this is very restrictive:
122 // - Use of WithRegion makes the stack traces captured from
123 // region start and end are identical.
124 // - Refactoring the existing code to use WithRegion is sometimes
125 // hard and makes the code less readable.
126 // e.g. code block nested deep in the loop with various
127 // exit point with return values
128 // - Refactoring the code to use this API with closure can
129 // cause different GC behavior such as retaining some parameters
130 // longer.
131 // This causes more churns in code than I hoped, and sometimes
132 // makes the code less readable.
134 id := fromContext(ctx).id
135 userRegion(id, regionStartCode, regionType)
136 defer userRegion(id, regionEndCode, regionType)
137 fn()
140 // StartRegion starts a region and returns a function for marking the
141 // end of the region. The returned Region's End function must be called
142 // from the same goroutine where the region was started.
143 // Within each goroutine, regions must nest. That is, regions started
144 // after this region must be ended before this region can be ended.
145 // Recommended usage is
147 // defer trace.StartRegion(ctx, "myTracedRegion").End()
149 func StartRegion(ctx context.Context, regionType string) *Region {
150 if !IsEnabled() {
151 return noopRegion
153 id := fromContext(ctx).id
154 userRegion(id, regionStartCode, regionType)
155 return &Region{id, regionType}
158 // Region is a region of code whose execution time interval is traced.
159 type Region struct {
160 id uint64
161 regionType string
164 var noopRegion = &Region{}
166 // End marks the end of the traced code region.
167 func (r *Region) End() {
168 if r == noopRegion {
169 return
171 userRegion(r.id, regionEndCode, r.regionType)
174 // IsEnabled returns whether tracing is enabled.
175 // The information is advisory only. The tracing status
176 // may have changed by the time this function returns.
177 func IsEnabled() bool {
178 enabled := atomic.LoadInt32(&tracing.enabled)
179 return enabled == 1
183 // Function bodies are defined in runtime/trace.go
186 // emits UserTaskCreate event.
187 func userTaskCreate(id, parentID uint64, taskType string)
189 // emits UserTaskEnd event.
190 func userTaskEnd(id uint64)
192 // emits UserRegion event.
193 func userRegion(id, mode uint64, regionType string)
195 // emits UserLog event.
196 func userLog(id uint64, category, message string)