1 // Copyright 2014 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.
23 saveTraces = flag.Bool("savetraces", false, "save traces collected by tests")
26 func TestTraceStartStop(t *testing.T) {
27 buf := new(bytes.Buffer)
28 if err := Start(buf); err != nil {
29 t.Fatalf("failed to start tracing: %v", err)
34 t.Fatalf("trace is empty")
36 time.Sleep(100 * time.Millisecond)
37 if size != buf.Len() {
38 t.Fatalf("trace writes after stop: %v -> %v", size, buf.Len())
40 saveTrace(t, buf, "TestTraceStartStop")
43 func TestTraceDoubleStart(t *testing.T) {
45 buf := new(bytes.Buffer)
46 if err := Start(buf); err != nil {
47 t.Fatalf("failed to start tracing: %v", err)
49 if err := Start(buf); err == nil {
50 t.Fatalf("succeed to start tracing second time")
56 func TestTrace(t *testing.T) {
57 buf := new(bytes.Buffer)
58 if err := Start(buf); err != nil {
59 t.Fatalf("failed to start tracing: %v", err)
62 saveTrace(t, buf, "TestTrace")
63 _, err := trace.Parse(buf, "")
64 if err == trace.ErrTimeOrder {
65 t.Skipf("skipping trace: %v", err)
68 t.Fatalf("failed to parse trace: %v", err)
72 func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc) {
73 events, err := trace.Parse(r, "")
74 if err == trace.ErrTimeOrder {
75 t.Skipf("skipping trace: %v", err)
78 t.Fatalf("failed to parse trace: %v", err)
80 gs := trace.GoroutineStats(events)
81 for goid := range gs {
82 // We don't do any particular checks on the result at the moment.
83 // But still check that RelatedGoroutines does not crash, hang, etc.
84 _ = trace.RelatedGoroutines(events, goid)
89 func testBrokenTimestamps(t *testing.T, data []byte) {
90 // On some processors cputicks (used to generate trace timestamps)
91 // produce non-monotonic timestamps. It is important that the parser
92 // distinguishes logically inconsistent traces (e.g. missing, excessive
93 // or misordered events) from broken timestamps. The former is a bug
94 // in tracer, the latter is a machine issue.
95 // So now that we have a consistent trace, test that (1) parser does
96 // not return a logical error in case of broken timestamps
97 // and (2) broken timestamps are eventually detected and reported.
98 trace.BreakTimestampsForTesting = true
100 trace.BreakTimestampsForTesting = false
102 for i := 0; i < 1e4; i++ {
103 _, err := trace.Parse(bytes.NewReader(data), "")
104 if err == trace.ErrTimeOrder {
108 t.Fatalf("failed to parse trace: %v", err)
113 func TestTraceStress(t *testing.T) {
114 var wg sync.WaitGroup
115 done := make(chan bool)
117 // Create a goroutine blocked before tracing.
124 // Create a goroutine blocked in syscall before tracing.
125 rp, wp, err := os.Pipe()
127 t.Fatalf("failed to create pipe: %v", err)
140 time.Sleep(time.Millisecond) // give the goroutine above time to block
142 buf := new(bytes.Buffer)
143 if err := Start(buf); err != nil {
144 t.Fatalf("failed to start tracing: %v", err)
147 procs := runtime.GOMAXPROCS(10)
148 time.Sleep(50 * time.Millisecond) // test proc stop/start events
151 runtime.LockOSThread()
163 // Trigger GC from malloc.
165 if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
166 // Reduce allocation to avoid running out of
167 // memory on the builder - see issue/12032.
170 for i := 0; i < n; i++ {
171 _ = make([]byte, 1<<20)
174 // Create a bunch of busy goroutines to load all Ps.
175 for p := 0; p < 10; p++ {
178 // Do something useful.
179 tmp := make([]byte, 1<<16)
199 timerDone := make(chan bool)
201 time.Sleep(time.Millisecond)
207 ln, err := net.Listen("tcp", "127.0.0.1:0")
209 t.Fatalf("listen failed: %v", err)
213 c, err := ln.Accept()
217 time.Sleep(time.Millisecond)
222 c, err := net.Dial("tcp", ln.Addr().String())
224 t.Fatalf("dial failed: %v", err)
235 // Unblock helper goroutines and wait them to finish.
241 runtime.GOMAXPROCS(procs)
244 saveTrace(t, buf, "TestTraceStress")
247 testBrokenTimestamps(t, trace)
250 // Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine.
251 // And concurrently with all that start/stop trace 3 times.
252 func TestTraceStressStartStop(t *testing.T) {
253 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
254 outerDone := make(chan bool)
261 var wg sync.WaitGroup
262 done := make(chan bool)
270 rp, wp, err := os.Pipe()
272 t.Errorf("failed to create pipe: %v", err)
286 time.Sleep(time.Millisecond)
289 runtime.LockOSThread()
301 // Trigger GC from malloc.
303 if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
304 // Reduce allocation to avoid running out of
305 // memory on the builder - see issue/12032.
308 for i := 0; i < n; i++ {
309 _ = make([]byte, 1<<20)
312 // Create a bunch of busy goroutines to load all Ps.
313 for p := 0; p < 10; p++ {
316 // Do something useful.
317 tmp := make([]byte, 1<<16)
336 runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
339 timerDone := make(chan bool)
341 time.Sleep(time.Millisecond)
347 ln, err := net.Listen("tcp", "127.0.0.1:0")
349 t.Errorf("listen failed: %v", err)
354 c, err := ln.Accept()
358 time.Sleep(time.Millisecond)
363 c, err := net.Dial("tcp", ln.Addr().String())
365 t.Errorf("dial failed: %v", err)
377 // Unblock helper goroutines and wait them to finish.
384 for i := 0; i < 3; i++ {
385 buf := new(bytes.Buffer)
386 if err := Start(buf); err != nil {
387 t.Fatalf("failed to start tracing: %v", err)
389 time.Sleep(time.Millisecond)
391 saveTrace(t, buf, "TestTraceStressStartStop")
394 testBrokenTimestamps(t, trace)
399 func TestTraceFutileWakeup(t *testing.T) {
400 buf := new(bytes.Buffer)
401 if err := Start(buf); err != nil {
402 t.Fatalf("failed to start tracing: %v", err)
405 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
406 c0 := make(chan int, 1)
407 c1 := make(chan int, 1)
408 c2 := make(chan int, 1)
410 var done sync.WaitGroup
412 for p := 0; p < procs; p++ {
415 for i := 0; i < iters; i++ {
422 for i := 0; i < iters; i++ {
429 for i := 0; i < iters; i++ {
439 for i := 0; i < iters; i++ {
452 saveTrace(t, buf, "TestTraceFutileWakeup")
453 events, _ := parseTrace(t, buf)
454 // Check that (1) trace does not contain EvFutileWakeup events and
455 // (2) there are no consecutive EvGoBlock/EvGCStart/EvGoBlock events
456 // (we call runtime.Gosched between all operations, so these would be futile wakeups).
457 gs := make(map[uint64]int)
458 for _, ev := range events {
460 case trace.EvFutileWakeup:
461 t.Fatalf("found EvFutileWakeup event")
462 case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect:
464 t.Fatalf("goroutine %v blocked on %v at %v right after start",
465 ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
468 t.Fatalf("goroutine %v blocked on %v at %v while blocked",
469 ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
472 case trace.EvGoStart:
482 func saveTrace(t *testing.T, buf *bytes.Buffer, name string) {
486 if err := ioutil.WriteFile(name+".trace", buf.Bytes(), 0600); err != nil {
487 t.Errorf("failed to write trace file: %s", err)