]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/trace/trace_unix_test.go
runtime: add execution tracer v2 behind GOEXPERIMENT=exectracer2
[gostls13.git] / src / cmd / trace / trace_unix_test.go
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.
4
5 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
6
7 package main
8
9 import (
10         "bytes"
11         "cmd/internal/traceviewer"
12         "internal/goexperiment"
13         traceparser "internal/trace"
14         "io"
15         "runtime"
16         "runtime/trace"
17         "sync"
18         "syscall"
19         "testing"
20         "time"
21 )
22
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")
29         }
30         // Start one goroutine blocked in syscall.
31         //
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.
36         var p [2]int
37         if err := syscall.Pipe(p[:]); err != nil {
38                 t.Fatalf("failed to create pipe: %v", err)
39         }
40
41         var wg sync.WaitGroup
42         defer func() {
43                 syscall.Write(p[1], []byte("a"))
44                 wg.Wait()
45
46                 syscall.Close(p[0])
47                 syscall.Close(p[1])
48         }()
49         wg.Add(1)
50         go func() {
51                 var tmp [1]byte
52                 syscall.Read(p[0], tmp[:])
53                 wg.Done()
54         }()
55
56         // Start multiple timer goroutines.
57         allTimers := make([]*time.Timer, 2*runtime.GOMAXPROCS(0))
58         defer func() {
59                 for _, timer := range allTimers {
60                         timer.Stop()
61                 }
62         }()
63
64         var timerSetup sync.WaitGroup
65         for i := range allTimers {
66                 timerSetup.Add(1)
67                 go func(i int) {
68                         defer timerSetup.Done()
69                         allTimers[i] = time.AfterFunc(time.Hour, nil)
70                 }(i)
71         }
72         timerSetup.Wait()
73
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)
78         }
79         trace.Stop()
80
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)
86         }
87
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)
96                         }
97                 }
98         }
99
100         param := &traceParams{
101                 parsed:  res,
102                 endTime: int64(1<<63 - 1),
103         }
104         if err := generateTrace(param, c); err != nil {
105                 t.Fatalf("failed to generate ViewerData: %v", err)
106         }
107 }