1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
11 "cmd/internal/traceviewer"
12 "internal/goexperiment"
13 traceparser "internal/trace"
23 // TestGoroutineInSyscall tests threads for timer goroutines
24 // that preexisted when the tracing started were not counted
25 // as threads in syscall. See golang.org/issues/22574.
26 func TestGoroutineInSyscall(t *testing.T) {
27 if goexperiment.ExecTracer2 {
28 t.Skip("skipping because this test is obsolete and incompatible with the new tracer")
30 // Start one goroutine blocked in syscall.
32 // TODO: syscall.Pipe used to cause the goroutine to
33 // remain blocked in syscall is not portable. Replace
34 // it with a more portable way so this test can run
35 // on non-unix architecture e.g. Windows.
37 if err := syscall.Pipe(p[:]); err != nil {
38 t.Fatalf("failed to create pipe: %v", err)
43 syscall.Write(p[1], []byte("a"))
52 syscall.Read(p[0], tmp[:])
56 // Start multiple timer goroutines.
57 allTimers := make([]*time.Timer, 2*runtime.GOMAXPROCS(0))
59 for _, timer := range allTimers {
64 var timerSetup sync.WaitGroup
65 for i := range allTimers {
68 defer timerSetup.Done()
69 allTimers[i] = time.AfterFunc(time.Hour, nil)
74 // Collect and parse trace.
75 buf := new(bytes.Buffer)
76 if err := trace.Start(buf); err != nil {
77 t.Fatalf("failed to start tracing: %v", err)
81 res, err := traceparser.Parse(buf, "")
82 if err == traceparser.ErrTimeOrder {
83 t.Skipf("skipping due to golang.org/issue/16755 (timestamps are unreliable): %v", err)
84 } else if err != nil {
85 t.Fatalf("failed to parse trace: %v", err)
88 // Check only one thread for the pipe read goroutine is
89 // considered in-syscall.
90 c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
91 c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
92 if ev.Name == "Threads" {
93 arg := ev.Arg.(*threadCountersArg)
94 if arg.InSyscall > 1 {
95 t.Errorf("%d threads in syscall at time %v; want less than 1 thread in syscall", arg.InSyscall, ev.Time)
100 param := &traceParams{
102 endTime: int64(1<<63 - 1),
104 if err := generateTrace(param, c); err != nil {
105 t.Fatalf("failed to generate ViewerData: %v", err)