aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/trace/annotations_test.go
diff options
context:
space:
mode:
authorCarlos Amedee <carlos@golang.org>2024-04-02 18:16:07 -0400
committerCarlos Amedee <carlos@golang.org>2024-04-15 16:44:47 +0000
commit2c5849dc40152cef6b7c3465ba0a1d6eb8f3c985 (patch)
treeac6c040c7b5ee797ca0bf35d3762001f7745ec0a /src/cmd/trace/annotations_test.go
parent8e987fadb57fa1fc98975ca2fcb3a4751f7f55ff (diff)
downloadgo-2c5849dc40152cef6b7c3465ba0a1d6eb8f3c985.tar.xz
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>
Diffstat (limited to 'src/cmd/trace/annotations_test.go')
-rw-r--r--src/cmd/trace/annotations_test.go357
1 files changed, 0 insertions, 357 deletions
diff --git a/src/cmd/trace/annotations_test.go b/src/cmd/trace/annotations_test.go
index 36d3ec9d6d..5585e485f7 100644
--- a/src/cmd/trace/annotations_test.go
+++ b/src/cmd/trace/annotations_test.go
@@ -7,24 +7,10 @@
package main
import (
- "bytes"
- "context"
- "flag"
- "fmt"
- "internal/goexperiment"
- traceparser "internal/trace"
- "os"
- "reflect"
- "runtime/debug"
- "runtime/trace"
- "sort"
- "sync"
"testing"
"time"
)
-var saveTraces = flag.Bool("savetraces", false, "save traces collected by tests")
-
func TestOverlappingDuration(t *testing.T) {
cases := []struct {
start0, end0, start1, end1 int64
@@ -51,346 +37,3 @@ func TestOverlappingDuration(t *testing.T) {
}
}
}
-
-// prog0 starts three goroutines.
-//
-// 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()
-
- var wg sync.WaitGroup
-
- wg.Add(1)
- go func() { // goroutine 1
- defer wg.Done()
- trace.WithRegion(ctx, "taskless.region", func() {
- trace.Log(ctx, "key0", "val0")
- })
- }()
-
- wg.Add(1)
- go func() { // goroutine 2
- defer wg.Done()
- ctx, task := trace.NewTask(ctx, "task0")
- trace.WithRegion(ctx, "task0.region0", func() {
- wg.Add(1)
- go func() { // goroutine 3
- defer wg.Done()
- 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, task2 := trace.NewTask(ctx, "task1")
- trace.Log(ctx2, "key3", "val3")
- task2.End()
- }()
- wg.Wait()
-}
-
-func TestAnalyzeAnnotations(t *testing.T) {
- // TODO: classify taskless regions
-
- // Run prog0 and capture the execution trace.
- if err := traceProgram(t, prog0, "TestAnalyzeAnnotations"); err != nil {
- t.Fatalf("failed to trace the program: %v", err)
- }
-
- res, err := analyzeAnnotations()
- if err != nil {
- t.Fatalf("failed to analyzeAnnotations: %v", err)
- }
-
- // For prog0, we expect
- // - task with name = "task0", with three regions.
- // - task with name = "task1", with no region.
- wantTasks := map[string]struct {
- complete bool
- goroutines int
- regions []string
- }{
- "task0": {
- complete: true,
- goroutines: 2,
- regions: []string{"task0.region0", "", "task0.region1", "task0.region2"},
- },
- "task1": {
- complete: true,
- goroutines: 1,
- },
- }
-
- for _, task := range res.tasks {
- want, ok := wantTasks[task.name]
- if !ok {
- t.Errorf("unexpected task: %s", task)
- continue
- }
- 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)
- }
-
- delete(wantTasks, task.name)
- }
- if len(wantTasks) > 0 {
- t.Errorf("no more tasks; want %+v", wantTasks)
- }
-
- wantRegions := []string{
- "", // an auto-created region for the goroutine 3
- "taskless.region",
- "task0.region0",
- "task0.region1",
- "task0.region2",
- }
- var gotRegions []string
- for regionID := range res.regions {
- gotRegions = append(gotRegions, regionID.Type)
- }
-
- 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, 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() {
- })
- })
- })
-}
-
-func TestAnalyzeAnnotationTaskTree(t *testing.T) {
- // Run prog1 and capture the execution trace.
- if err := traceProgram(t, prog1, "TestAnalyzeAnnotationTaskTree"); err != nil {
- t.Fatalf("failed to trace the program: %v", err)
- }
-
- res, err := analyzeAnnotations()
- if err != nil {
- t.Fatalf("failed to analyzeAnnotations: %v", err)
- }
- tasks := res.tasks
-
- // For prog0, we expect
- // - task with name = "", with taskless.region in regions.
- // - task with name = "task0", with three regions.
- wantTasks := map[string]struct {
- parent string
- children []string
- regions []string
- }{
- "task1": {
- parent: "",
- children: []string{"task2"},
- regions: []string{"task1.region"},
- },
- "task2": {
- parent: "task1",
- children: []string{"task3"},
- regions: []string{"task2.region"},
- },
- "task3": {
- parent: "task2",
- children: nil,
- regions: []string{"task3.region"},
- },
- }
-
- for _, task := range tasks {
- want, ok := wantTasks[task.name]
- if !ok {
- t.Errorf("unexpected task: %s", task)
- continue
- }
- delete(wantTasks, task.name)
-
- if parentName(task) != want.parent ||
- !reflect.DeepEqual(childrenNames(task), want.children) ||
- !reflect.DeepEqual(regionNames(task), want.regions) {
- t.Errorf("got %v; want %+v", task, want)
- }
- }
-
- if len(wantTasks) > 0 {
- t.Errorf("no more tasks; want %+v", wantTasks)
- }
-}
-
-// prog2 starts two tasks; "taskWithGC" that overlaps with GC
-// and "taskWithoutGC" that doesn't. In order to run this reliably,
-// the caller needs to set up to prevent GC from running automatically.
-// prog2 returns the upper-bound gc time that overlaps with the first task.
-func prog2() (gcTime time.Duration) {
- ch := make(chan bool)
- ctx1, task := trace.NewTask(context.Background(), "taskWithGC")
- trace.WithRegion(ctx1, "taskWithGC.region1", func() {
- go func() {
- defer trace.StartRegion(ctx1, "taskWithGC.region2").End()
- <-ch
- }()
- s := time.Now()
- debug.FreeOSMemory() // task1 affected by gc
- gcTime = time.Since(s)
- close(ch)
- })
- task.End()
-
- ctx2, task2 := trace.NewTask(context.Background(), "taskWithoutGC")
- trace.WithRegion(ctx2, "taskWithoutGC.region1", func() {
- // do nothing.
- })
- task2.End()
- return gcTime
-}
-
-func TestAnalyzeAnnotationGC(t *testing.T) {
- err := traceProgram(t, func() {
- oldGC := debug.SetGCPercent(10000) // gc, and effectively disable GC
- defer debug.SetGCPercent(oldGC)
- prog2()
- }, "TestAnalyzeAnnotationGC")
- if err != nil {
- t.Fatalf("failed to trace the program: %v", err)
- }
-
- res, err := analyzeAnnotations()
- if err != nil {
- t.Fatalf("failed to analyzeAnnotations: %v", err)
- }
-
- // Check collected GC Start events are all sorted and non-overlapping.
- lastTS := int64(0)
- for i, ev := range res.gcEvents {
- if ev.Type != traceparser.EvGCStart {
- t.Errorf("unwanted event in gcEvents: %v", ev)
- }
- if i > 0 && lastTS > ev.Ts {
- t.Errorf("overlapping GC events:\n%d: %v\n%d: %v", i-1, res.gcEvents[i-1], i, res.gcEvents[i])
- }
- if ev.Link != nil {
- lastTS = ev.Link.Ts
- }
- }
-
- // Check whether only taskWithGC reports overlapping duration.
- for _, task := range res.tasks {
- got := task.overlappingGCDuration(res.gcEvents)
- switch task.name {
- case "taskWithoutGC":
- if got != 0 {
- t.Errorf("%s reported %v as overlapping GC time; want 0: %v", task.name, got, task)
- }
- case "taskWithGC":
- upperBound := task.duration()
- // TODO(hyangah): a tighter upper bound is gcTime, but
- // use of it will make the test flaky due to the issue
- // described in golang.org/issue/16755. Tighten the upper
- // bound when the issue with the timestamp computed
- // based on clockticks is resolved.
- if got <= 0 || got > upperBound {
- t.Errorf("%s reported %v as overlapping GC time; want (0, %v):\n%v", task.name, got, upperBound, task)
- buf := new(bytes.Buffer)
- fmt.Fprintln(buf, "GC Events")
- for _, ev := range res.gcEvents {
- fmt.Fprintf(buf, " %s -> %s\n", ev, ev.Link)
- }
- fmt.Fprintln(buf, "Events in Task")
- for i, ev := range task.events {
- fmt.Fprintf(buf, " %d: %s\n", i, ev)
- }
-
- t.Logf("\n%s", buf)
- }
- }
- }
-}
-
-// traceProgram runs the provided function while tracing is enabled,
-// parses the captured trace, and sets the global trace loader to
-// point to the parsed trace.
-//
-// If savetraces flag is set, the captured trace will be saved in the named file.
-func traceProgram(t *testing.T, f func(), name string) error {
- t.Helper()
- if goexperiment.ExecTracer2 {
- t.Skip("skipping because test programs are covered elsewhere for the new tracer")
- }
- buf := new(bytes.Buffer)
- if err := trace.Start(buf); err != nil {
- return err
- }
- f()
- trace.Stop()
-
- saveTrace(buf, name)
- res, err := traceparser.Parse(buf, name+".faketrace")
- if err == traceparser.ErrTimeOrder {
- t.Skipf("skipping due to golang.org/issue/16755: %v", err)
- } else if err != nil {
- return err
- }
-
- swapLoaderData(res, err)
- return nil
-}
-
-func regionNames(task *taskDesc) (ret []string) {
- for _, s := range task.regions {
- ret = append(ret, s.Name)
- }
- return ret
-}
-
-func parentName(task *taskDesc) string {
- if task.parent != nil {
- return task.parent.name
- }
- return ""
-}
-
-func childrenNames(task *taskDesc) (ret []string) {
- for _, s := range task.children {
- ret = append(ret, s.name)
- }
- return ret
-}
-
-func swapLoaderData(res traceparser.ParseResult, err error) {
- // swap loader's data.
- parseTrace() // fool loader.once.
-
- loader.res = res
- loader.err = err
-
- analyzeGoroutines(nil) // fool gsInit once.
- gs = traceparser.GoroutineStats(res.Events)
-
-}
-
-func saveTrace(buf *bytes.Buffer, name string) {
- if !*saveTraces {
- return
- }
- if err := os.WriteFile(name+".trace", buf.Bytes(), 0600); err != nil {
- panic(fmt.Errorf("failed to write trace file: %v", err))
- }
-}