aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/trace
diff options
context:
space:
mode:
authorHana Kim <hakim@google.com>2018-04-19 14:58:42 -0400
committerHyang-Ah Hana Kim <hyangah@gmail.com>2018-04-24 16:33:15 +0000
commitc2d10243688194346f660591fe4159e30a8d20ec (patch)
tree9c3bf5c9b2f307ce2a655ef97fac72f2e1fe430f /src/cmd/trace
parentfb017c60bc60f8df771ac2a9119ec55ea915929c (diff)
downloadgo-c2d10243688194346f660591fe4159e30a8d20ec.tar.xz
runtime/trace: rename "Span" with "Region"
"Span" is a commonly used term in many distributed tracing systems (Dapper, OpenCensus, OpenTracing, ...). They use it to refer to a period of time, not necessarily tied into execution of underlying processor, thread, or goroutine, unlike the "Span" of runtime/trace package. Since distributed tracing and go runtime execution tracing are already similar enough to cause confusion, this CL attempts to avoid using the same word if possible. "Region" is being used in a certain tracing system to refer to a code region which is pretty close to what runtime/trace.Span currently refers to. So, replace that. https://software.intel.com/en-us/itc-user-and-reference-guide-defining-and-recording-functions-or-regions This CL also tweaks APIs a bit based on jbd and heschi's comments: NewContext -> NewTask and it now returns a Task object that exports End method. StartSpan -> StartRegion and it now returns a Region object that exports End method. Also, changed WithSpan to WithRegion and it now takes func() with no context. Another thought is to get rid of WithRegion. It is a nice concept but in practice, it seems problematic (a lot of code churn, and polluting stack trace). Already, the tracing concept is very low level, and we hope this API to be used with great care. Recommended usage will be defer trace.StartRegion(ctx, "someRegion").End() Left old APIs untouched in this CL. Once the usage of them are cleaned up, they will be removed in a separate CL. Change-Id: I73880635e437f3aad51314331a035dd1459b9f3a Reviewed-on: https://go-review.googlesource.com/108296 Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: JBD <jbd@google.com>
Diffstat (limited to 'src/cmd/trace')
-rw-r--r--src/cmd/trace/annotations.go204
-rw-r--r--src/cmd/trace/annotations_test.go110
-rw-r--r--src/cmd/trace/main.go2
-rw-r--r--src/cmd/trace/pprof.go34
-rw-r--r--src/cmd/trace/trace.go24
5 files changed, 187 insertions, 187 deletions
diff --git a/src/cmd/trace/annotations.go b/src/cmd/trace/annotations.go
index 0d2bdfcbba..5f672de3b4 100644
--- a/src/cmd/trace/annotations.go
+++ b/src/cmd/trace/annotations.go
@@ -18,8 +18,8 @@ import (
func init() {
http.HandleFunc("/usertasks", httpUserTasks)
http.HandleFunc("/usertask", httpUserTask)
- http.HandleFunc("/userspans", httpUserSpans)
- http.HandleFunc("/userspan", httpUserSpan)
+ http.HandleFunc("/userregions", httpUserRegions)
+ http.HandleFunc("/userregion", httpUserRegion)
}
// httpUserTasks reports all tasks found in the trace.
@@ -59,46 +59,46 @@ func httpUserTasks(w http.ResponseWriter, r *http.Request) {
}
}
-func httpUserSpans(w http.ResponseWriter, r *http.Request) {
+func httpUserRegions(w http.ResponseWriter, r *http.Request) {
res, err := analyzeAnnotations()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- allSpans := res.spans
+ allRegions := res.regions
- summary := make(map[spanTypeID]spanStats)
- for id, spans := range allSpans {
+ summary := make(map[regionTypeID]regionStats)
+ for id, regions := range allRegions {
stats, ok := summary[id]
if !ok {
- stats.spanTypeID = id
+ stats.regionTypeID = id
}
- for _, s := range spans {
+ for _, s := range regions {
stats.add(s)
}
summary[id] = stats
}
- // Sort spans by pc and name
- userSpans := make([]spanStats, 0, len(summary))
+ // Sort regions by pc and name
+ userRegions := make([]regionStats, 0, len(summary))
for _, stats := range summary {
- userSpans = append(userSpans, stats)
+ userRegions = append(userRegions, stats)
}
- sort.Slice(userSpans, func(i, j int) bool {
- if userSpans[i].Type != userSpans[j].Type {
- return userSpans[i].Type < userSpans[j].Type
+ sort.Slice(userRegions, func(i, j int) bool {
+ if userRegions[i].Type != userRegions[j].Type {
+ return userRegions[i].Type < userRegions[j].Type
}
- return userSpans[i].Frame.PC < userSpans[j].Frame.PC
+ return userRegions[i].Frame.PC < userRegions[j].Frame.PC
})
// Emit table.
- err = templUserSpanTypes.Execute(w, userSpans)
+ err = templUserRegionTypes.Execute(w, userRegions)
if err != nil {
http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
return
}
}
-func httpUserSpan(w http.ResponseWriter, r *http.Request) {
- filter, err := newSpanFilter(r)
+func httpUserRegion(w http.ResponseWriter, r *http.Request) {
+ filter, err := newRegionFilter(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@@ -108,13 +108,13 @@ func httpUserSpan(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- allSpans := res.spans
+ allRegions := res.regions
- var data []spanDesc
+ var data []regionDesc
var maxTotal int64
- for id, spans := range allSpans {
- for _, s := range spans {
+ for id, regions := range allRegions {
+ for _, s := range regions {
if !filter.match(id, s) {
continue
}
@@ -126,7 +126,7 @@ func httpUserSpan(w http.ResponseWriter, r *http.Request) {
}
sortby := r.FormValue("sortby")
- _, ok := reflect.TypeOf(spanDesc{}).FieldByNameFunc(func(s string) bool {
+ _, ok := reflect.TypeOf(regionDesc{}).FieldByNameFunc(func(s string) bool {
return s == sortby
})
if !ok {
@@ -138,9 +138,9 @@ func httpUserSpan(w http.ResponseWriter, r *http.Request) {
return ival > jval
})
- err = templUserSpanType.Execute(w, struct {
+ err = templUserRegionType.Execute(w, struct {
MaxTotal int64
- Data []spanDesc
+ Data []regionDesc
Name string
}{
MaxTotal: maxTotal,
@@ -193,9 +193,9 @@ func httpUserTask(w http.ResponseWriter, r *http.Request) {
if !filter.match(task) {
continue
}
- // merge events in the task.events and task.spans.Start
+ // merge events in the task.events and task.regions.Start
rawEvents := append([]*trace.Event{}, task.events...)
- for _, s := range task.spans {
+ for _, s := range task.regions {
if s.Start != nil {
rawEvents = append(rawEvents, s.Start)
}
@@ -254,12 +254,12 @@ func httpUserTask(w http.ResponseWriter, r *http.Request) {
}
type annotationAnalysisResult struct {
- tasks map[uint64]*taskDesc // tasks
- spans map[spanTypeID][]spanDesc // spans
- gcEvents []*trace.Event // GCStartevents, sorted
+ tasks map[uint64]*taskDesc // tasks
+ regions map[regionTypeID][]regionDesc // regions
+ gcEvents []*trace.Event // GCStartevents, sorted
}
-type spanTypeID struct {
+type regionTypeID struct {
Frame trace.Frame // top frame
Type string
}
@@ -278,7 +278,7 @@ func analyzeAnnotations() (annotationAnalysisResult, error) {
}
tasks := allTasks{}
- spans := map[spanTypeID][]spanDesc{}
+ regions := map[regionTypeID][]regionDesc{}
var gcEvents []*trace.Event
for _, ev := range events {
@@ -303,38 +303,38 @@ func analyzeAnnotations() (annotationAnalysisResult, error) {
gcEvents = append(gcEvents, ev)
}
}
- // combine span info.
+ // combine region info.
analyzeGoroutines(events)
for goid, stats := range gs {
// gs is a global var defined in goroutines.go as a result
// of analyzeGoroutines. TODO(hyangah): fix this not to depend
// on a 'global' var.
- for _, s := range stats.Spans {
+ for _, s := range stats.Regions {
if s.TaskID != 0 {
task := tasks.task(s.TaskID)
task.goroutines[goid] = struct{}{}
- task.spans = append(task.spans, spanDesc{UserSpanDesc: s, G: goid})
+ task.regions = append(task.regions, regionDesc{UserRegionDesc: s, G: goid})
}
var frame trace.Frame
if s.Start != nil {
frame = *s.Start.Stk[0]
}
- id := spanTypeID{Frame: frame, Type: s.Name}
- spans[id] = append(spans[id], spanDesc{UserSpanDesc: s, G: goid})
+ id := regionTypeID{Frame: frame, Type: s.Name}
+ regions[id] = append(regions[id], regionDesc{UserRegionDesc: s, G: goid})
}
}
- // sort spans in tasks based on the timestamps.
+ // sort regions in tasks based on the timestamps.
for _, task := range tasks {
- sort.SliceStable(task.spans, func(i, j int) bool {
- si, sj := task.spans[i].firstTimestamp(), task.spans[j].firstTimestamp()
+ sort.SliceStable(task.regions, func(i, j int) bool {
+ si, sj := task.regions[i].firstTimestamp(), task.regions[j].firstTimestamp()
if si != sj {
return si < sj
}
- return task.spans[i].lastTimestamp() < task.spans[i].lastTimestamp()
+ return task.regions[i].lastTimestamp() < task.regions[i].lastTimestamp()
})
}
- return annotationAnalysisResult{tasks: tasks, spans: spans, gcEvents: gcEvents}, nil
+ return annotationAnalysisResult{tasks: tasks, regions: regions, gcEvents: gcEvents}, nil
}
// taskDesc represents a task.
@@ -342,7 +342,7 @@ type taskDesc struct {
name string // user-provided task name
id uint64 // internal task id
events []*trace.Event // sorted based on timestamp.
- spans []spanDesc // associated spans, sorted based on the start timestamp and then the last timestamp.
+ regions []regionDesc // associated regions, sorted based on the start timestamp and then the last timestamp.
goroutines map[uint64]struct{} // involved goroutines
create *trace.Event // Task create event
@@ -367,8 +367,8 @@ func (task *taskDesc) String() string {
fmt.Fprintf(wb, "task %d:\t%s\n", task.id, task.name)
fmt.Fprintf(wb, "\tstart: %v end: %v complete: %t\n", task.firstTimestamp(), task.lastTimestamp(), task.complete())
fmt.Fprintf(wb, "\t%d goroutines\n", len(task.goroutines))
- fmt.Fprintf(wb, "\t%d spans:\n", len(task.spans))
- for _, s := range task.spans {
+ fmt.Fprintf(wb, "\t%d regions:\n", len(task.regions))
+ for _, s := range task.regions {
fmt.Fprintf(wb, "\t\t%s(goid=%d)\n", s.Name, s.G)
}
if task.parent != nil {
@@ -382,10 +382,10 @@ func (task *taskDesc) String() string {
return wb.String()
}
-// spanDesc represents a span.
-type spanDesc struct {
- *trace.UserSpanDesc
- G uint64 // id of goroutine where the span was defined
+// regionDesc represents a region.
+type regionDesc struct {
+ *trace.UserRegionDesc
+ G uint64 // id of goroutine where the region was defined
}
type allTasks map[uint64]*taskDesc
@@ -473,8 +473,8 @@ func (task *taskDesc) duration() time.Duration {
return time.Duration(task.lastTimestamp()-task.firstTimestamp()) * time.Nanosecond
}
-func (span *spanDesc) duration() time.Duration {
- return time.Duration(span.lastTimestamp()-span.firstTimestamp()) * time.Nanosecond
+func (region *regionDesc) duration() time.Duration {
+ return time.Duration(region.lastTimestamp()-region.firstTimestamp()) * time.Nanosecond
}
// overlappingGCDuration returns the sum of GC period overlapping with the task's lifetime.
@@ -493,7 +493,7 @@ func (task *taskDesc) overlappingGCDuration(evs []*trace.Event) (overlapping tim
}
// overlappingInstant returns true if the instantaneous event, ev, occurred during
-// any of the task's span if ev is a goroutine-local event, or overlaps with the
+// any of the task's region if ev is a goroutine-local event, or overlaps with the
// task's lifetime if ev is a global event.
func (task *taskDesc) overlappingInstant(ev *trace.Event) bool {
if isUserAnnotationEvent(ev) && task.id != ev.Args[0] {
@@ -510,13 +510,13 @@ func (task *taskDesc) overlappingInstant(ev *trace.Event) bool {
return true
}
- // Goroutine local event. Check whether there are spans overlapping with the event.
+ // Goroutine local event. Check whether there are regions overlapping with the event.
goid := ev.G
- for _, span := range task.spans {
- if span.G != goid {
+ for _, region := range task.regions {
+ if region.G != goid {
continue
}
- if span.firstTimestamp() <= ts && ts <= span.lastTimestamp() {
+ if region.firstTimestamp() <= ts && ts <= region.lastTimestamp() {
return true
}
}
@@ -524,7 +524,7 @@ func (task *taskDesc) overlappingInstant(ev *trace.Event) bool {
}
// overlappingDuration returns whether the durational event, ev, overlaps with
-// any of the task's span if ev is a goroutine-local event, or overlaps with
+// any of the task's region if ev is a goroutine-local event, or overlaps with
// the task's lifetime if ev is a global event. It returns the overlapping time
// as well.
func (task *taskDesc) overlappingDuration(ev *trace.Event) (time.Duration, bool) {
@@ -552,21 +552,21 @@ func (task *taskDesc) overlappingDuration(ev *trace.Event) (time.Duration, bool)
return o, o > 0
}
- // Goroutine local event. Check whether there are spans overlapping with the event.
+ // Goroutine local event. Check whether there are regions overlapping with the event.
var overlapping time.Duration
- var lastSpanEnd int64 // the end of previous overlapping span
- for _, span := range task.spans {
- if span.G != goid && span.G != goid2 {
+ var lastRegionEnd int64 // the end of previous overlapping region
+ for _, region := range task.regions {
+ if region.G != goid && region.G != goid2 {
continue
}
- spanStart, spanEnd := span.firstTimestamp(), span.lastTimestamp()
- if spanStart < lastSpanEnd { // skip nested spans
+ regionStart, regionEnd := region.firstTimestamp(), region.lastTimestamp()
+ if regionStart < lastRegionEnd { // skip nested regions
continue
}
- if o := overlappingDuration(spanStart, spanEnd, start, end); o > 0 {
+ if o := overlappingDuration(regionStart, regionEnd, start, end); o > 0 {
// overlapping.
- lastSpanEnd = spanEnd
+ lastRegionEnd = regionEnd
overlapping += o
}
}
@@ -602,22 +602,22 @@ func (task *taskDesc) lastEvent() *trace.Event {
return nil
}
-// firstTimestamp returns the timestamp of span start event.
-// If the span's start event is not present in the trace,
+// firstTimestamp returns the timestamp of region start event.
+// If the region's start event is not present in the trace,
// the first timestamp of the trace will be returned.
-func (span *spanDesc) firstTimestamp() int64 {
- if span.Start != nil {
- return span.Start.Ts
+func (region *regionDesc) firstTimestamp() int64 {
+ if region.Start != nil {
+ return region.Start.Ts
}
return firstTimestamp()
}
-// lastTimestamp returns the timestamp of span end event.
-// If the span's end event is not present in the trace,
+// lastTimestamp returns the timestamp of region end event.
+// If the region's end event is not present in the trace,
// the last timestamp of the trace will be returned.
-func (span *spanDesc) lastTimestamp() int64 {
- if span.End != nil {
- return span.End.Ts
+func (region *regionDesc) lastTimestamp() int64 {
+ if region.End != nil {
+ return region.End.Ts
}
return lastTimestamp()
}
@@ -721,7 +721,7 @@ func newTaskFilter(r *http.Request) (*taskFilter, error) {
func taskMatches(t *taskDesc, text string) bool {
for _, ev := range t.events {
switch ev.Type {
- case trace.EvUserTaskCreate, trace.EvUserSpan, trace.EvUserLog:
+ case trace.EvUserTaskCreate, trace.EvUserRegion, trace.EvUserLog:
for _, s := range ev.SArgs {
if strings.Contains(s, text) {
return true
@@ -732,12 +732,12 @@ func taskMatches(t *taskDesc, text string) bool {
return false
}
-type spanFilter struct {
+type regionFilter struct {
name string
- cond []func(spanTypeID, spanDesc) bool
+ cond []func(regionTypeID, regionDesc) bool
}
-func (f *spanFilter) match(id spanTypeID, s spanDesc) bool {
+func (f *regionFilter) match(id regionTypeID, s regionDesc) bool {
for _, c := range f.cond {
if !c(id, s) {
return false
@@ -746,42 +746,42 @@ func (f *spanFilter) match(id spanTypeID, s spanDesc) bool {
return true
}
-func newSpanFilter(r *http.Request) (*spanFilter, error) {
+func newRegionFilter(r *http.Request) (*regionFilter, error) {
if err := r.ParseForm(); err != nil {
return nil, err
}
var name []string
- var conditions []func(spanTypeID, spanDesc) bool
+ var conditions []func(regionTypeID, regionDesc) bool
param := r.Form
if typ, ok := param["type"]; ok && len(typ) > 0 {
name = append(name, "type="+typ[0])
- conditions = append(conditions, func(id spanTypeID, s spanDesc) bool {
+ conditions = append(conditions, func(id regionTypeID, s regionDesc) bool {
return id.Type == typ[0]
})
}
if pc, err := strconv.ParseUint(r.FormValue("pc"), 16, 64); err == nil {
name = append(name, fmt.Sprintf("pc=%x", pc))
- conditions = append(conditions, func(id spanTypeID, s spanDesc) bool {
+ conditions = append(conditions, func(id regionTypeID, s regionDesc) bool {
return id.Frame.PC == pc
})
}
if lat, err := time.ParseDuration(r.FormValue("latmin")); err == nil {
name = append(name, fmt.Sprintf("latency >= %s", lat))
- conditions = append(conditions, func(_ spanTypeID, s spanDesc) bool {
+ conditions = append(conditions, func(_ regionTypeID, s regionDesc) bool {
return s.duration() >= lat
})
}
if lat, err := time.ParseDuration(r.FormValue("latmax")); err == nil {
name = append(name, fmt.Sprintf("latency <= %s", lat))
- conditions = append(conditions, func(_ spanTypeID, s spanDesc) bool {
+ conditions = append(conditions, func(_ regionTypeID, s regionDesc) bool {
return s.duration() <= lat
})
}
- return &spanFilter{name: strings.Join(name, ","), cond: conditions}, nil
+ return &regionFilter{name: strings.Join(name, ","), cond: conditions}, nil
}
type durationHistogram struct {
@@ -893,22 +893,22 @@ func (h *durationHistogram) String() string {
return w.String()
}
-type spanStats struct {
- spanTypeID
+type regionStats struct {
+ regionTypeID
Histogram durationHistogram
}
-func (s *spanStats) UserSpanURL() func(min, max time.Duration) string {
+func (s *regionStats) UserRegionURL() func(min, max time.Duration) string {
return func(min, max time.Duration) string {
- return fmt.Sprintf("/userspan?type=%s&pc=%x&latmin=%v&latmax=%v", template.URLQueryEscaper(s.Type), s.Frame.PC, template.URLQueryEscaper(min), template.URLQueryEscaper(max))
+ return fmt.Sprintf("/userregion?type=%s&pc=%x&latmin=%v&latmax=%v", template.URLQueryEscaper(s.Type), s.Frame.PC, template.URLQueryEscaper(min), template.URLQueryEscaper(max))
}
}
-func (s *spanStats) add(span spanDesc) {
- s.Histogram.add(span.duration())
+func (s *regionStats) add(region regionDesc) {
+ s.Histogram.add(region.duration())
}
-var templUserSpanTypes = template.Must(template.New("").Parse(`
+var templUserRegionTypes = template.Must(template.New("").Parse(`
<html>
<style type="text/css">
.histoTime {
@@ -920,15 +920,15 @@ var templUserSpanTypes = template.Must(template.New("").Parse(`
<body>
<table border="1" sortable="1">
<tr>
-<th>Span type</th>
+<th>Region type</th>
<th>Count</th>
<th>Duration distribution (complete tasks)</th>
</tr>
{{range $}}
<tr>
<td>{{.Type}}<br>{{.Frame.Fn}}<br>{{.Frame.File}}:{{.Frame.Line}}</td>
- <td><a href="/userspan?type={{.Type}}&pc={{.Frame.PC}}">{{.Histogram.Count}}</a></td>
- <td>{{.Histogram.ToHTML (.UserSpanURL)}}</td>
+ <td><a href="/userregion?type={{.Type}}&pc={{.Frame.PC}}">{{.Histogram.Count}}</a></td>
+ <td>{{.Histogram.ToHTML (.UserRegionURL)}}</td>
</tr>
{{end}}
</table>
@@ -1109,15 +1109,15 @@ func describeEvent(ev *trace.Event) string {
return "goroutine stopped"
case trace.EvUserLog:
return formatUserLog(ev)
- case trace.EvUserSpan:
+ case trace.EvUserRegion:
if ev.Args[1] == 0 {
duration := "unknown"
if ev.Link != nil {
duration = (time.Duration(ev.Link.Ts-ev.Ts) * time.Nanosecond).String()
}
- return fmt.Sprintf("span %s started (duration: %v)", ev.SArgs[0], duration)
+ return fmt.Sprintf("region %s started (duration: %v)", ev.SArgs[0], duration)
}
- return fmt.Sprintf("span %s ended", ev.SArgs[0])
+ return fmt.Sprintf("region %s ended", ev.SArgs[0])
case trace.EvUserTaskCreate:
return fmt.Sprintf("task %v (id %d, parent %d) created", ev.SArgs[0], ev.Args[0], ev.Args[1])
// TODO: add child task creation events into the parent task events
@@ -1129,13 +1129,13 @@ func describeEvent(ev *trace.Event) string {
func isUserAnnotationEvent(ev *trace.Event) bool {
switch ev.Type {
- case trace.EvUserLog, trace.EvUserSpan, trace.EvUserTaskCreate, trace.EvUserTaskEnd:
+ case trace.EvUserLog, trace.EvUserRegion, trace.EvUserTaskCreate, trace.EvUserTaskEnd:
return true
}
return false
}
-var templUserSpanType = template.Must(template.New("").Funcs(template.FuncMap{
+var templUserRegionType = template.Must(template.New("").Funcs(template.FuncMap{
"prettyDuration": func(nsec int64) template.HTML {
d := time.Duration(nsec) * time.Nanosecond
return template.HTML(niceDuration(d))
@@ -1152,7 +1152,7 @@ var templUserSpanType = template.Must(template.New("").Funcs(template.FuncMap{
}
return template.HTML(fmt.Sprintf("%.2f%%", float64(dividened)/float64(divisor)*100))
},
- "unknownTime": func(desc spanDesc) int64 {
+ "unknownTime": func(desc regionDesc) int64 {
sum := desc.ExecTime + desc.IOTime + desc.BlockTime + desc.SyscallTime + desc.SchedWaitTime
if sum < desc.TotalTime {
return desc.TotalTime - sum
diff --git a/src/cmd/trace/annotations_test.go b/src/cmd/trace/annotations_test.go
index 96b83734d7..5d2b226b35 100644
--- a/src/cmd/trace/annotations_test.go
+++ b/src/cmd/trace/annotations_test.go
@@ -47,9 +47,9 @@ func TestOverlappingDuration(t *testing.T) {
// prog0 starts three goroutines.
//
-// goroutine 1: taskless span
-// goroutine 2: starts task0, do work in task0.span0, starts task1 which ends immediately.
-// goroutine 3: do work in task0.span1 and task0.span2, ends task0
+// goroutine 1: taskless region
+// goroutine 2: starts task0, do work in task0.region0, starts task1 which ends immediately.
+// goroutine 3: do work in task0.region1 and task0.region2, ends task0
func prog0() {
ctx := context.Background()
@@ -58,7 +58,7 @@ func prog0() {
wg.Add(1)
go func() { // goroutine 1
defer wg.Done()
- trace.WithSpan(ctx, "taskless.span", func(ctx context.Context) {
+ trace.WithRegion(ctx, "taskless.region", func() {
trace.Log(ctx, "key0", "val0")
})
}()
@@ -66,29 +66,29 @@ func prog0() {
wg.Add(1)
go func() { // goroutine 2
defer wg.Done()
- ctx, taskDone := trace.NewContext(ctx, "task0")
- trace.WithSpan(ctx, "task0.span0", func(ctx context.Context) {
+ ctx, task := trace.NewTask(ctx, "task0")
+ trace.WithRegion(ctx, "task0.region0", func() {
wg.Add(1)
go func() { // goroutine 3
defer wg.Done()
- defer taskDone()
- trace.WithSpan(ctx, "task0.span1", func(ctx context.Context) {
- trace.WithSpan(ctx, "task0.span2", func(ctx context.Context) {
+ defer task.End()
+ trace.WithRegion(ctx, "task0.region1", func() {
+ trace.WithRegion(ctx, "task0.region2", func() {
trace.Log(ctx, "key2", "val2")
})
trace.Log(ctx, "key1", "val1")
})
}()
})
- ctx2, taskDone2 := trace.NewContext(ctx, "task1")
+ ctx2, task2 := trace.NewTask(ctx, "task1")
trace.Log(ctx2, "key3", "val3")
- taskDone2()
+ task2.End()
}()
wg.Wait()
}
func TestAnalyzeAnnotations(t *testing.T) {
- // TODO: classify taskless spans
+ // TODO: classify taskless regions
// Run prog0 and capture the execution trace.
if err := traceProgram(t, prog0, "TestAnalyzeAnnotations"); err != nil {
@@ -101,17 +101,17 @@ func TestAnalyzeAnnotations(t *testing.T) {
}
// For prog0, we expect
- // - task with name = "task0", with three spans.
- // - task with name = "task1", with no span.
+ // - task with name = "task0", with three regions.
+ // - task with name = "task1", with no region.
wantTasks := map[string]struct {
complete bool
goroutines int
- spans []string
+ regions []string
}{
"task0": {
complete: true,
goroutines: 2,
- spans: []string{"task0.span0", "", "task0.span1", "task0.span2"},
+ regions: []string{"task0.region0", "", "task0.region1", "task0.region2"},
},
"task1": {
complete: true,
@@ -125,7 +125,7 @@ func TestAnalyzeAnnotations(t *testing.T) {
t.Errorf("unexpected task: %s", task)
continue
}
- if task.complete() != want.complete || len(task.goroutines) != want.goroutines || !reflect.DeepEqual(spanNames(task), want.spans) {
+ if task.complete() != want.complete || len(task.goroutines) != want.goroutines || !reflect.DeepEqual(regionNames(task), want.regions) {
t.Errorf("got task %v; want %+v", task, want)
}
@@ -135,37 +135,37 @@ func TestAnalyzeAnnotations(t *testing.T) {
t.Errorf("no more tasks; want %+v", wantTasks)
}
- wantSpans := []string{
- "", // an auto-created span for the goroutine 3
- "taskless.span",
- "task0.span0",
- "task0.span1",
- "task0.span2",
+ wantRegions := []string{
+ "", // an auto-created region for the goroutine 3
+ "taskless.region",
+ "task0.region0",
+ "task0.region1",
+ "task0.region2",
}
- var gotSpans []string
- for spanID := range res.spans {
- gotSpans = append(gotSpans, spanID.Type)
+ var gotRegions []string
+ for regionID := range res.regions {
+ gotRegions = append(gotRegions, regionID.Type)
}
- sort.Strings(wantSpans)
- sort.Strings(gotSpans)
- if !reflect.DeepEqual(gotSpans, wantSpans) {
- t.Errorf("got spans %q, want spans %q", gotSpans, wantSpans)
+ sort.Strings(wantRegions)
+ sort.Strings(gotRegions)
+ if !reflect.DeepEqual(gotRegions, wantRegions) {
+ t.Errorf("got regions %q, want regions %q", gotRegions, wantRegions)
}
}
// prog1 creates a task hierarchy consisting of three tasks.
func prog1() {
ctx := context.Background()
- ctx1, done1 := trace.NewContext(ctx, "task1")
- defer done1()
- trace.WithSpan(ctx1, "task1.span", func(ctx context.Context) {
- ctx2, done2 := trace.NewContext(ctx, "task2")
- defer done2()
- trace.WithSpan(ctx2, "task2.span", func(ctx context.Context) {
- ctx3, done3 := trace.NewContext(ctx, "task3")
- defer done3()
- trace.WithSpan(ctx3, "task3.span", func(ctx context.Context) {
+ ctx1, task1 := trace.NewTask(ctx, "task1")
+ defer task1.End()
+ trace.WithRegion(ctx1, "task1.region", func() {
+ ctx2, task2 := trace.NewTask(ctx1, "task2")
+ defer task2.End()
+ trace.WithRegion(ctx2, "task2.region", func() {
+ ctx3, task3 := trace.NewTask(ctx2, "task3")
+ defer task3.End()
+ trace.WithRegion(ctx3, "task3.region", func() {
})
})
})
@@ -184,27 +184,27 @@ func TestAnalyzeAnnotationTaskTree(t *testing.T) {
tasks := res.tasks
// For prog0, we expect
- // - task with name = "", with taskless.span in spans.
- // - task with name = "task0", with three spans.
+ // - task with name = "", with taskless.region in regions.
+ // - task with name = "task0", with three regions.
wantTasks := map[string]struct {
parent string
children []string
- spans []string
+ regions []string
}{
"task1": {
parent: "",
children: []string{"task2"},
- spans: []string{"task1.span"},
+ regions: []string{"task1.region"},
},
"task2": {
parent: "task1",
children: []string{"task3"},
- spans: []string{"task2.span"},
+ regions: []string{"task2.region"},
},
"task3": {
parent: "task2",
children: nil,
- spans: []string{"task3.span"},
+ regions: []string{"task3.region"},
},
}
@@ -218,7 +218,7 @@ func TestAnalyzeAnnotationTaskTree(t *testing.T) {
if parentName(task) != want.parent ||
!reflect.DeepEqual(childrenNames(task), want.children) ||
- !reflect.DeepEqual(spanNames(task), want.spans) {
+ !reflect.DeepEqual(regionNames(task), want.regions) {
t.Errorf("got %v; want %+v", task, want)
}
}
@@ -234,10 +234,10 @@ func TestAnalyzeAnnotationTaskTree(t *testing.T) {
// prog2 returns the upper-bound gc time that overlaps with the first task.
func prog2() (gcTime time.Duration) {
ch := make(chan bool)
- ctx1, done := trace.NewContext(context.Background(), "taskWithGC")
- trace.WithSpan(ctx1, "taskWithGC.span1", func(ctx context.Context) {
+ ctx1, task := trace.NewTask(context.Background(), "taskWithGC")
+ trace.WithRegion(ctx1, "taskWithGC.region1", func() {
go func() {
- defer trace.StartSpan(ctx, "taskWithGC.span2")()
+ defer trace.StartRegion(ctx1, "taskWithGC.region2").End()
<-ch
}()
s := time.Now()
@@ -245,13 +245,13 @@ func prog2() (gcTime time.Duration) {
gcTime = time.Since(s)
close(ch)
})
- done()
+ task.End()
- ctx2, done2 := trace.NewContext(context.Background(), "taskWithoutGC")
- trace.WithSpan(ctx2, "taskWithoutGC.span1", func(ctx context.Context) {
+ ctx2, task2 := trace.NewTask(context.Background(), "taskWithoutGC")
+ trace.WithRegion(ctx2, "taskWithoutGC.region1", func() {
// do nothing.
})
- done2()
+ task2.End()
return gcTime
}
@@ -343,8 +343,8 @@ func traceProgram(t *testing.T, f func(), name string) error {
return nil
}
-func spanNames(task *taskDesc) (ret []string) {
- for _, s := range task.spans {
+func regionNames(task *taskDesc) (ret []string) {
+ for _, s := range task.regions {
ret = append(ret, s.Name)
}
return ret
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
index 57608067f1..0c98b85c37 100644
--- a/src/cmd/trace/main.go
+++ b/src/cmd/trace/main.go
@@ -200,7 +200,7 @@ var templMain = template.Must(template.New("").Parse(`
<a href="/syscall">Syscall blocking profile</a> (<a href="/syscall?raw=1" download="syscall.profile">⬇</a>)<br>
<a href="/sched">Scheduler latency profile</a> (<a href="/sche?raw=1" download="sched.profile">⬇</a>)<br>
<a href="/usertasks">User-defined tasks</a><br>
-<a href="/userspans">User-defined spans</a><br>
+<a href="/userregions">User-defined regions</a><br>
</body>
</html>
`))
diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go
index c0972f2b46..3389d2799b 100644
--- a/src/cmd/trace/pprof.go
+++ b/src/cmd/trace/pprof.go
@@ -42,10 +42,10 @@ func init() {
http.HandleFunc("/syscall", serveSVGProfile(pprofByGoroutine(computePprofSyscall)))
http.HandleFunc("/sched", serveSVGProfile(pprofByGoroutine(computePprofSched)))
- http.HandleFunc("/spanio", serveSVGProfile(pprofBySpan(computePprofIO)))
- http.HandleFunc("/spanblock", serveSVGProfile(pprofBySpan(computePprofBlock)))
- http.HandleFunc("/spansyscall", serveSVGProfile(pprofBySpan(computePprofSyscall)))
- http.HandleFunc("/spansched", serveSVGProfile(pprofBySpan(computePprofSched)))
+ http.HandleFunc("/regionio", serveSVGProfile(pprofByRegion(computePprofIO)))
+ http.HandleFunc("/regionblock", serveSVGProfile(pprofByRegion(computePprofBlock)))
+ http.HandleFunc("/regionsyscall", serveSVGProfile(pprofByRegion(computePprofSyscall)))
+ http.HandleFunc("/regionsched", serveSVGProfile(pprofByRegion(computePprofSched)))
}
// Record represents one entry in pprof-like profiles.
@@ -75,13 +75,13 @@ func pprofByGoroutine(compute func(io.Writer, map[uint64][]interval, []*trace.Ev
}
}
-func pprofBySpan(compute func(io.Writer, map[uint64][]interval, []*trace.Event) error) func(w io.Writer, r *http.Request) error {
+func pprofByRegion(compute func(io.Writer, map[uint64][]interval, []*trace.Event) error) func(w io.Writer, r *http.Request) error {
return func(w io.Writer, r *http.Request) error {
- filter, err := newSpanFilter(r)
+ filter, err := newRegionFilter(r)
if err != nil {
return err
}
- gToIntervals, err := pprofMatchingSpans(filter)
+ gToIntervals, err := pprofMatchingRegions(filter)
if err != nil {
return err
}
@@ -123,9 +123,9 @@ func pprofMatchingGoroutines(id string, events []*trace.Event) (map[uint64][]int
return res, nil
}
-// pprofMatchingSpans returns the time intervals of matching spans
+// pprofMatchingRegions returns the time intervals of matching regions
// grouped by the goroutine id. If the filter is nil, returns nil without an error.
-func pprofMatchingSpans(filter *spanFilter) (map[uint64][]interval, error) {
+func pprofMatchingRegions(filter *regionFilter) (map[uint64][]interval, error) {
res, err := analyzeAnnotations()
if err != nil {
return nil, err
@@ -135,8 +135,8 @@ func pprofMatchingSpans(filter *spanFilter) (map[uint64][]interval, error) {
}
gToIntervals := make(map[uint64][]interval)
- for id, spans := range res.spans {
- for _, s := range spans {
+ for id, regions := range res.regions {
+ for _, s := range regions {
if filter.match(id, s) {
gToIntervals[s.G] = append(gToIntervals[s.G], interval{begin: s.firstTimestamp(), end: s.lastTimestamp()})
}
@@ -144,10 +144,10 @@ func pprofMatchingSpans(filter *spanFilter) (map[uint64][]interval, error) {
}
for g, intervals := range gToIntervals {
- // in order to remove nested spans and
- // consider only the outermost spans,
+ // in order to remove nested regions and
+ // consider only the outermost regions,
// first, we sort based on the start time
- // and then scan through to select only the outermost spans.
+ // and then scan through to select only the outermost regions.
sort.Slice(intervals, func(i, j int) bool {
x := intervals[i].begin
y := intervals[j].begin
@@ -158,13 +158,13 @@ func pprofMatchingSpans(filter *spanFilter) (map[uint64][]interval, error) {
})
var lastTimestamp int64
var n int
- // select only the outermost spans.
+ // select only the outermost regions.
for _, i := range intervals {
if lastTimestamp <= i.begin {
- intervals[n] = i // new non-overlapping span starts.
+ intervals[n] = i // new non-overlapping region starts.
lastTimestamp = i.end
n++
- } // otherwise, skip because this span overlaps with a previous span.
+ } // otherwise, skip because this region overlaps with a previous region.
}
gToIntervals[g] = intervals[:n]
}
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index e3bb40614d..19d6fa36a7 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -405,7 +405,7 @@ type traceContext struct {
threadStats, prevThreadStats threadStats
gstates, prevGstates [gStateCount]int64
- spanID int // last emitted span id. incremented in each emitSpan call.
+ regionID int // last emitted region id. incremented in each emitRegion call.
}
type heapStats struct {
@@ -738,7 +738,7 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
}
}
- // Display task and its spans if we are in task-oriented presentation mode.
+ // Display task and its regions if we are in task-oriented presentation mode.
if ctx.mode&modeTaskOriented != 0 {
taskRow := uint64(trace.GCP + 1)
for _, task := range ctx.tasks {
@@ -757,11 +757,11 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
}
ctx.emit(tEnd)
- // If we are in goroutine-oriented mode, we draw spans.
+ // If we are in goroutine-oriented mode, we draw regions.
// TODO(hyangah): add this for task/P-oriented mode (i.e., focustask view) too.
if ctx.mode&modeGoroutineOriented != 0 {
- for _, s := range task.spans {
- ctx.emitSpan(s)
+ for _, s := range task.regions {
+ ctx.emitRegion(s)
}
}
}
@@ -859,23 +859,23 @@ func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
return sl
}
-func (ctx *traceContext) emitSpan(s spanDesc) {
+func (ctx *traceContext) emitRegion(s regionDesc) {
if s.Name == "" {
return
}
- ctx.spanID++
- spanID := ctx.spanID
+ ctx.regionID++
+ regionID := ctx.regionID
id := s.TaskID
scopeID := fmt.Sprintf("%x", id)
sl0 := &ViewerEvent{
- Category: "Span",
+ Category: "Region",
Name: s.Name,
Phase: "b",
Time: float64(s.firstTimestamp()) / 1e3,
Tid: s.G,
- ID: uint64(spanID),
+ ID: uint64(regionID),
Scope: scopeID,
Cname: colorDeepMagenta,
}
@@ -885,12 +885,12 @@ func (ctx *traceContext) emitSpan(s spanDesc) {
ctx.emit(sl0)
sl1 := &ViewerEvent{
- Category: "Span",
+ Category: "Region",
Name: s.Name,
Phase: "e",
Time: float64(s.lastTimestamp()) / 1e3,
Tid: s.G,
- ID: uint64(spanID),
+ ID: uint64(regionID),
Scope: scopeID,
Cname: colorDeepMagenta,
}