Skip to content

Commit 2c5849d

Browse files
committed
runtime, cmd/trace: remove code paths that include v1 tracer
This change makes the new execution tracer described in #60773, the default tracer. This change attempts to make the smallest amount of changes for a single CL. Updates #66703 For #60773 Change-Id: I3742f3419c54f07d7c020ae5e1c18d29d8bcae6d Reviewed-on: https://go-review.googlesource.com/c/go/+/576256 Reviewed-by: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 8e987fa commit 2c5849d

27 files changed

+68
-3974
lines changed

src/cmd/trace/annotations_test.go

-357
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,10 @@
77
package main
88

99
import (
10-
"bytes"
11-
"context"
12-
"flag"
13-
"fmt"
14-
"internal/goexperiment"
15-
traceparser "internal/trace"
16-
"os"
17-
"reflect"
18-
"runtime/debug"
19-
"runtime/trace"
20-
"sort"
21-
"sync"
2210
"testing"
2311
"time"
2412
)
2513

26-
var saveTraces = flag.Bool("savetraces", false, "save traces collected by tests")
27-
2814
func TestOverlappingDuration(t *testing.T) {
2915
cases := []struct {
3016
start0, end0, start1, end1 int64
@@ -51,346 +37,3 @@ func TestOverlappingDuration(t *testing.T) {
5137
}
5238
}
5339
}
54-
55-
// prog0 starts three goroutines.
56-
//
57-
// goroutine 1: taskless region
58-
// goroutine 2: starts task0, do work in task0.region0, starts task1 which ends immediately.
59-
// goroutine 3: do work in task0.region1 and task0.region2, ends task0
60-
func prog0() {
61-
ctx := context.Background()
62-
63-
var wg sync.WaitGroup
64-
65-
wg.Add(1)
66-
go func() { // goroutine 1
67-
defer wg.Done()
68-
trace.WithRegion(ctx, "taskless.region", func() {
69-
trace.Log(ctx, "key0", "val0")
70-
})
71-
}()
72-
73-
wg.Add(1)
74-
go func() { // goroutine 2
75-
defer wg.Done()
76-
ctx, task := trace.NewTask(ctx, "task0")
77-
trace.WithRegion(ctx, "task0.region0", func() {
78-
wg.Add(1)
79-
go func() { // goroutine 3
80-
defer wg.Done()
81-
defer task.End()
82-
trace.WithRegion(ctx, "task0.region1", func() {
83-
trace.WithRegion(ctx, "task0.region2", func() {
84-
trace.Log(ctx, "key2", "val2")
85-
})
86-
trace.Log(ctx, "key1", "val1")
87-
})
88-
}()
89-
})
90-
ctx2, task2 := trace.NewTask(ctx, "task1")
91-
trace.Log(ctx2, "key3", "val3")
92-
task2.End()
93-
}()
94-
wg.Wait()
95-
}
96-
97-
func TestAnalyzeAnnotations(t *testing.T) {
98-
// TODO: classify taskless regions
99-
100-
// Run prog0 and capture the execution trace.
101-
if err := traceProgram(t, prog0, "TestAnalyzeAnnotations"); err != nil {
102-
t.Fatalf("failed to trace the program: %v", err)
103-
}
104-
105-
res, err := analyzeAnnotations()
106-
if err != nil {
107-
t.Fatalf("failed to analyzeAnnotations: %v", err)
108-
}
109-
110-
// For prog0, we expect
111-
// - task with name = "task0", with three regions.
112-
// - task with name = "task1", with no region.
113-
wantTasks := map[string]struct {
114-
complete bool
115-
goroutines int
116-
regions []string
117-
}{
118-
"task0": {
119-
complete: true,
120-
goroutines: 2,
121-
regions: []string{"task0.region0", "", "task0.region1", "task0.region2"},
122-
},
123-
"task1": {
124-
complete: true,
125-
goroutines: 1,
126-
},
127-
}
128-
129-
for _, task := range res.tasks {
130-
want, ok := wantTasks[task.name]
131-
if !ok {
132-
t.Errorf("unexpected task: %s", task)
133-
continue
134-
}
135-
if task.complete() != want.complete || len(task.goroutines) != want.goroutines || !reflect.DeepEqual(regionNames(task), want.regions) {
136-
t.Errorf("got task %v; want %+v", task, want)
137-
}
138-
139-
delete(wantTasks, task.name)
140-
}
141-
if len(wantTasks) > 0 {
142-
t.Errorf("no more tasks; want %+v", wantTasks)
143-
}
144-
145-
wantRegions := []string{
146-
"", // an auto-created region for the goroutine 3
147-
"taskless.region",
148-
"task0.region0",
149-
"task0.region1",
150-
"task0.region2",
151-
}
152-
var gotRegions []string
153-
for regionID := range res.regions {
154-
gotRegions = append(gotRegions, regionID.Type)
155-
}
156-
157-
sort.Strings(wantRegions)
158-
sort.Strings(gotRegions)
159-
if !reflect.DeepEqual(gotRegions, wantRegions) {
160-
t.Errorf("got regions %q, want regions %q", gotRegions, wantRegions)
161-
}
162-
}
163-
164-
// prog1 creates a task hierarchy consisting of three tasks.
165-
func prog1() {
166-
ctx := context.Background()
167-
ctx1, task1 := trace.NewTask(ctx, "task1")
168-
defer task1.End()
169-
trace.WithRegion(ctx1, "task1.region", func() {
170-
ctx2, task2 := trace.NewTask(ctx1, "task2")
171-
defer task2.End()
172-
trace.WithRegion(ctx2, "task2.region", func() {
173-
ctx3, task3 := trace.NewTask(ctx2, "task3")
174-
defer task3.End()
175-
trace.WithRegion(ctx3, "task3.region", func() {
176-
})
177-
})
178-
})
179-
}
180-
181-
func TestAnalyzeAnnotationTaskTree(t *testing.T) {
182-
// Run prog1 and capture the execution trace.
183-
if err := traceProgram(t, prog1, "TestAnalyzeAnnotationTaskTree"); err != nil {
184-
t.Fatalf("failed to trace the program: %v", err)
185-
}
186-
187-
res, err := analyzeAnnotations()
188-
if err != nil {
189-
t.Fatalf("failed to analyzeAnnotations: %v", err)
190-
}
191-
tasks := res.tasks
192-
193-
// For prog0, we expect
194-
// - task with name = "", with taskless.region in regions.
195-
// - task with name = "task0", with three regions.
196-
wantTasks := map[string]struct {
197-
parent string
198-
children []string
199-
regions []string
200-
}{
201-
"task1": {
202-
parent: "",
203-
children: []string{"task2"},
204-
regions: []string{"task1.region"},
205-
},
206-
"task2": {
207-
parent: "task1",
208-
children: []string{"task3"},
209-
regions: []string{"task2.region"},
210-
},
211-
"task3": {
212-
parent: "task2",
213-
children: nil,
214-
regions: []string{"task3.region"},
215-
},
216-
}
217-
218-
for _, task := range tasks {
219-
want, ok := wantTasks[task.name]
220-
if !ok {
221-
t.Errorf("unexpected task: %s", task)
222-
continue
223-
}
224-
delete(wantTasks, task.name)
225-
226-
if parentName(task) != want.parent ||
227-
!reflect.DeepEqual(childrenNames(task), want.children) ||
228-
!reflect.DeepEqual(regionNames(task), want.regions) {
229-
t.Errorf("got %v; want %+v", task, want)
230-
}
231-
}
232-
233-
if len(wantTasks) > 0 {
234-
t.Errorf("no more tasks; want %+v", wantTasks)
235-
}
236-
}
237-
238-
// prog2 starts two tasks; "taskWithGC" that overlaps with GC
239-
// and "taskWithoutGC" that doesn't. In order to run this reliably,
240-
// the caller needs to set up to prevent GC from running automatically.
241-
// prog2 returns the upper-bound gc time that overlaps with the first task.
242-
func prog2() (gcTime time.Duration) {
243-
ch := make(chan bool)
244-
ctx1, task := trace.NewTask(context.Background(), "taskWithGC")
245-
trace.WithRegion(ctx1, "taskWithGC.region1", func() {
246-
go func() {
247-
defer trace.StartRegion(ctx1, "taskWithGC.region2").End()
248-
<-ch
249-
}()
250-
s := time.Now()
251-
debug.FreeOSMemory() // task1 affected by gc
252-
gcTime = time.Since(s)
253-
close(ch)
254-
})
255-
task.End()
256-
257-
ctx2, task2 := trace.NewTask(context.Background(), "taskWithoutGC")
258-
trace.WithRegion(ctx2, "taskWithoutGC.region1", func() {
259-
// do nothing.
260-
})
261-
task2.End()
262-
return gcTime
263-
}
264-
265-
func TestAnalyzeAnnotationGC(t *testing.T) {
266-
err := traceProgram(t, func() {
267-
oldGC := debug.SetGCPercent(10000) // gc, and effectively disable GC
268-
defer debug.SetGCPercent(oldGC)
269-
prog2()
270-
}, "TestAnalyzeAnnotationGC")
271-
if err != nil {
272-
t.Fatalf("failed to trace the program: %v", err)
273-
}
274-
275-
res, err := analyzeAnnotations()
276-
if err != nil {
277-
t.Fatalf("failed to analyzeAnnotations: %v", err)
278-
}
279-
280-
// Check collected GC Start events are all sorted and non-overlapping.
281-
lastTS := int64(0)
282-
for i, ev := range res.gcEvents {
283-
if ev.Type != traceparser.EvGCStart {
284-
t.Errorf("unwanted event in gcEvents: %v", ev)
285-
}
286-
if i > 0 && lastTS > ev.Ts {
287-
t.Errorf("overlapping GC events:\n%d: %v\n%d: %v", i-1, res.gcEvents[i-1], i, res.gcEvents[i])
288-
}
289-
if ev.Link != nil {
290-
lastTS = ev.Link.Ts
291-
}
292-
}
293-
294-
// Check whether only taskWithGC reports overlapping duration.
295-
for _, task := range res.tasks {
296-
got := task.overlappingGCDuration(res.gcEvents)
297-
switch task.name {
298-
case "taskWithoutGC":
299-
if got != 0 {
300-
t.Errorf("%s reported %v as overlapping GC time; want 0: %v", task.name, got, task)
301-
}
302-
case "taskWithGC":
303-
upperBound := task.duration()
304-
// TODO(hyangah): a tighter upper bound is gcTime, but
305-
// use of it will make the test flaky due to the issue
306-
// described in golang.org/issue/16755. Tighten the upper
307-
// bound when the issue with the timestamp computed
308-
// based on clockticks is resolved.
309-
if got <= 0 || got > upperBound {
310-
t.Errorf("%s reported %v as overlapping GC time; want (0, %v):\n%v", task.name, got, upperBound, task)
311-
buf := new(bytes.Buffer)
312-
fmt.Fprintln(buf, "GC Events")
313-
for _, ev := range res.gcEvents {
314-
fmt.Fprintf(buf, " %s -> %s\n", ev, ev.Link)
315-
}
316-
fmt.Fprintln(buf, "Events in Task")
317-
for i, ev := range task.events {
318-
fmt.Fprintf(buf, " %d: %s\n", i, ev)
319-
}
320-
321-
t.Logf("\n%s", buf)
322-
}
323-
}
324-
}
325-
}
326-
327-
// traceProgram runs the provided function while tracing is enabled,
328-
// parses the captured trace, and sets the global trace loader to
329-
// point to the parsed trace.
330-
//
331-
// If savetraces flag is set, the captured trace will be saved in the named file.
332-
func traceProgram(t *testing.T, f func(), name string) error {
333-
t.Helper()
334-
if goexperiment.ExecTracer2 {
335-
t.Skip("skipping because test programs are covered elsewhere for the new tracer")
336-
}
337-
buf := new(bytes.Buffer)
338-
if err := trace.Start(buf); err != nil {
339-
return err
340-
}
341-
f()
342-
trace.Stop()
343-
344-
saveTrace(buf, name)
345-
res, err := traceparser.Parse(buf, name+".faketrace")
346-
if err == traceparser.ErrTimeOrder {
347-
t.Skipf("skipping due to golang.org/issue/16755: %v", err)
348-
} else if err != nil {
349-
return err
350-
}
351-
352-
swapLoaderData(res, err)
353-
return nil
354-
}
355-
356-
func regionNames(task *taskDesc) (ret []string) {
357-
for _, s := range task.regions {
358-
ret = append(ret, s.Name)
359-
}
360-
return ret
361-
}
362-
363-
func parentName(task *taskDesc) string {
364-
if task.parent != nil {
365-
return task.parent.name
366-
}
367-
return ""
368-
}
369-
370-
func childrenNames(task *taskDesc) (ret []string) {
371-
for _, s := range task.children {
372-
ret = append(ret, s.name)
373-
}
374-
return ret
375-
}
376-
377-
func swapLoaderData(res traceparser.ParseResult, err error) {
378-
// swap loader's data.
379-
parseTrace() // fool loader.once.
380-
381-
loader.res = res
382-
loader.err = err
383-
384-
analyzeGoroutines(nil) // fool gsInit once.
385-
gs = traceparser.GoroutineStats(res.Events)
386-
387-
}
388-
389-
func saveTrace(buf *bytes.Buffer, name string) {
390-
if !*saveTraces {
391-
return
392-
}
393-
if err := os.WriteFile(name+".trace", buf.Bytes(), 0600); err != nil {
394-
panic(fmt.Errorf("failed to write trace file: %v", err))
395-
}
396-
}

0 commit comments

Comments
 (0)