github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/trace/trace_unix_test.go (about) 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 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package main 8 9 import ( 10 "bytes" 11 traceparser "internal/trace" 12 "io/ioutil" 13 "runtime" 14 "runtime/trace" 15 "sync" 16 "syscall" 17 "testing" 18 "time" 19 ) 20 21 // TestGoroutineInSyscall tests threads for timer goroutines 22 // that preexisted when the tracing started were not counted 23 // as threads in syscall. See golang.org/issues/22574. 24 func TestGoroutineInSyscall(t *testing.T) { 25 // Start one goroutine blocked in syscall. 26 // 27 // TODO: syscall.Pipe used to cause the goroutine to 28 // remain blocked in syscall is not portable. Replace 29 // it with a more portable way so this test can run 30 // on non-unix architecture e.g. Windows. 31 var p [2]int 32 if err := syscall.Pipe(p[:]); err != nil { 33 t.Fatalf("failed to create pipe: %v", err) 34 } 35 36 var wg sync.WaitGroup 37 defer func() { 38 syscall.Write(p[1], []byte("a")) 39 wg.Wait() 40 41 syscall.Close(p[0]) 42 syscall.Close(p[1]) 43 }() 44 wg.Add(1) 45 go func() { 46 var tmp [1]byte 47 syscall.Read(p[0], tmp[:]) 48 wg.Done() 49 }() 50 51 // Start multiple timer goroutines. 52 allTimers := make([]*time.Timer, 2*runtime.GOMAXPROCS(0)) 53 defer func() { 54 for _, timer := range allTimers { 55 timer.Stop() 56 } 57 }() 58 59 var timerSetup sync.WaitGroup 60 for i := range allTimers { 61 timerSetup.Add(1) 62 go func(i int) { 63 defer timerSetup.Done() 64 allTimers[i] = time.AfterFunc(time.Hour, nil) 65 }(i) 66 } 67 timerSetup.Wait() 68 69 // Collect and parse trace. 70 buf := new(bytes.Buffer) 71 if err := trace.Start(buf); err != nil { 72 t.Fatalf("failed to start tracing: %v", err) 73 } 74 trace.Stop() 75 76 res, err := traceparser.Parse(buf, "") 77 if err == traceparser.ErrTimeOrder { 78 t.Skipf("skipping due to golang.org/issue/16755 (timestamps are unreliable): %v", err) 79 } else if err != nil { 80 t.Fatalf("failed to parse trace: %v", err) 81 } 82 83 // Check only one thread for the pipe read goroutine is 84 // considered in-syscall. 85 c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1) 86 c.consumeViewerEvent = func(ev *ViewerEvent, _ bool) { 87 if ev.Name == "Threads" { 88 arg := ev.Arg.(*threadCountersArg) 89 if arg.InSyscall > 1 { 90 t.Errorf("%d threads in syscall at time %v; want less than 1 thread in syscall", arg.InSyscall, ev.Time) 91 } 92 } 93 } 94 95 param := &traceParams{ 96 parsed: res, 97 endTime: int64(1<<63 - 1), 98 } 99 if err := generateTrace(param, c); err != nil { 100 t.Fatalf("failed to generate ViewerData: %v", err) 101 } 102 }