libgo: update to Go 1.11
[official-gcc.git] / libgo / go / runtime / trace / trace_test.go
blobfc81abc30ff25ac026bfe0546f2593dc972e08d9
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.
5 package trace_test
7 import (
8 "bytes"
9 "flag"
10 "internal/race"
11 "internal/trace"
12 "io"
13 "io/ioutil"
14 "net"
15 "os"
16 "runtime"
17 . "runtime/trace"
18 "strconv"
19 "sync"
20 "testing"
21 "time"
24 var (
25 saveTraces = flag.Bool("savetraces", false, "save traces collected by tests")
28 // TestEventBatch tests Flush calls that happen during Start
29 // don't produce corrupted traces.
30 func TestEventBatch(t *testing.T) {
31 if race.Enabled {
32 t.Skip("skipping in race mode")
34 if IsEnabled() {
35 t.Skip("skipping because -test.trace is set")
37 if testing.Short() {
38 t.Skip("skipping in short mode")
40 // During Start, bunch of records are written to reflect the current
41 // snapshot of the program, including state of each goroutines.
42 // And some string constants are written to the trace to aid trace
43 // parsing. This test checks Flush of the buffer occurred during
44 // this process doesn't cause corrupted traces.
45 // When a Flush is called during Start is complicated
46 // so we test with a range of number of goroutines hoping that one
47 // of them triggers Flush.
48 // This range was chosen to fill up a ~64KB buffer with traceEvGoCreate
49 // and traceEvGoWaiting events (12~13bytes per goroutine).
50 for g := 4950; g < 5050; g++ {
51 n := g
52 t.Run("G="+strconv.Itoa(n), func(t *testing.T) {
53 var wg sync.WaitGroup
54 wg.Add(n)
56 in := make(chan bool, 1000)
57 for i := 0; i < n; i++ {
58 go func() {
59 <-in
60 wg.Done()
61 }()
63 buf := new(bytes.Buffer)
64 if err := Start(buf); err != nil {
65 t.Fatalf("failed to start tracing: %v", err)
68 for i := 0; i < n; i++ {
69 in <- true
71 wg.Wait()
72 Stop()
74 _, err := trace.Parse(buf, "")
75 if err == trace.ErrTimeOrder {
76 t.Skipf("skipping trace: %v", err)
79 if err != nil {
80 t.Fatalf("failed to parse trace: %v", err)
86 func TestTraceStartStop(t *testing.T) {
87 if IsEnabled() {
88 t.Skip("skipping because -test.trace is set")
90 buf := new(bytes.Buffer)
91 if err := Start(buf); err != nil {
92 t.Fatalf("failed to start tracing: %v", err)
94 Stop()
95 size := buf.Len()
96 if size == 0 {
97 t.Fatalf("trace is empty")
99 time.Sleep(100 * time.Millisecond)
100 if size != buf.Len() {
101 t.Fatalf("trace writes after stop: %v -> %v", size, buf.Len())
103 saveTrace(t, buf, "TestTraceStartStop")
106 func TestTraceDoubleStart(t *testing.T) {
107 if IsEnabled() {
108 t.Skip("skipping because -test.trace is set")
110 Stop()
111 buf := new(bytes.Buffer)
112 if err := Start(buf); err != nil {
113 t.Fatalf("failed to start tracing: %v", err)
115 if err := Start(buf); err == nil {
116 t.Fatalf("succeed to start tracing second time")
118 Stop()
119 Stop()
122 func TestTrace(t *testing.T) {
123 if IsEnabled() {
124 t.Skip("skipping because -test.trace is set")
126 buf := new(bytes.Buffer)
127 if err := Start(buf); err != nil {
128 t.Fatalf("failed to start tracing: %v", err)
130 Stop()
131 saveTrace(t, buf, "TestTrace")
132 _, err := trace.Parse(buf, "")
133 if err == trace.ErrTimeOrder {
134 t.Skipf("skipping trace: %v", err)
136 if err != nil {
137 t.Fatalf("failed to parse trace: %v", err)
141 func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc) {
142 res, err := trace.Parse(r, "")
143 if err == trace.ErrTimeOrder {
144 t.Skipf("skipping trace: %v", err)
146 if err != nil {
147 t.Fatalf("failed to parse trace: %v", err)
149 gs := trace.GoroutineStats(res.Events)
150 for goid := range gs {
151 // We don't do any particular checks on the result at the moment.
152 // But still check that RelatedGoroutines does not crash, hang, etc.
153 _ = trace.RelatedGoroutines(res.Events, goid)
155 return res.Events, gs
158 func testBrokenTimestamps(t *testing.T, data []byte) {
159 // On some processors cputicks (used to generate trace timestamps)
160 // produce non-monotonic timestamps. It is important that the parser
161 // distinguishes logically inconsistent traces (e.g. missing, excessive
162 // or misordered events) from broken timestamps. The former is a bug
163 // in tracer, the latter is a machine issue.
164 // So now that we have a consistent trace, test that (1) parser does
165 // not return a logical error in case of broken timestamps
166 // and (2) broken timestamps are eventually detected and reported.
167 trace.BreakTimestampsForTesting = true
168 defer func() {
169 trace.BreakTimestampsForTesting = false
171 for i := 0; i < 1e4; i++ {
172 _, err := trace.Parse(bytes.NewReader(data), "")
173 if err == trace.ErrTimeOrder {
174 return
176 if err != nil {
177 t.Fatalf("failed to parse trace: %v", err)
182 func TestTraceStress(t *testing.T) {
183 if runtime.GOOS == "js" {
184 t.Skip("no os.Pipe on js")
186 if IsEnabled() {
187 t.Skip("skipping because -test.trace is set")
189 var wg sync.WaitGroup
190 done := make(chan bool)
192 // Create a goroutine blocked before tracing.
193 wg.Add(1)
194 go func() {
195 <-done
196 wg.Done()
199 // Create a goroutine blocked in syscall before tracing.
200 rp, wp, err := os.Pipe()
201 if err != nil {
202 t.Fatalf("failed to create pipe: %v", err)
204 defer func() {
205 rp.Close()
206 wp.Close()
208 wg.Add(1)
209 go func() {
210 var tmp [1]byte
211 rp.Read(tmp[:])
212 <-done
213 wg.Done()
215 time.Sleep(time.Millisecond) // give the goroutine above time to block
217 buf := new(bytes.Buffer)
218 if err := Start(buf); err != nil {
219 t.Fatalf("failed to start tracing: %v", err)
222 procs := runtime.GOMAXPROCS(10)
223 time.Sleep(50 * time.Millisecond) // test proc stop/start events
225 go func() {
226 runtime.LockOSThread()
227 for {
228 select {
229 case <-done:
230 return
231 default:
232 runtime.Gosched()
237 runtime.GC()
238 // Trigger GC from malloc.
239 n := int(1e3)
240 if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
241 // Reduce allocation to avoid running out of
242 // memory on the builder - see issue/12032.
243 n = 512
245 for i := 0; i < n; i++ {
246 _ = make([]byte, 1<<20)
249 // Create a bunch of busy goroutines to load all Ps.
250 for p := 0; p < 10; p++ {
251 wg.Add(1)
252 go func() {
253 // Do something useful.
254 tmp := make([]byte, 1<<16)
255 for i := range tmp {
256 tmp[i]++
258 _ = tmp
259 <-done
260 wg.Done()
264 // Block in syscall.
265 wg.Add(1)
266 go func() {
267 var tmp [1]byte
268 rp.Read(tmp[:])
269 <-done
270 wg.Done()
273 // Test timers.
274 timerDone := make(chan bool)
275 go func() {
276 time.Sleep(time.Millisecond)
277 timerDone <- true
279 <-timerDone
281 // A bit of network.
282 ln, err := net.Listen("tcp", "127.0.0.1:0")
283 if err != nil {
284 t.Fatalf("listen failed: %v", err)
286 defer ln.Close()
287 go func() {
288 c, err := ln.Accept()
289 if err != nil {
290 return
292 time.Sleep(time.Millisecond)
293 var buf [1]byte
294 c.Write(buf[:])
295 c.Close()
297 c, err := net.Dial("tcp", ln.Addr().String())
298 if err != nil {
299 t.Fatalf("dial failed: %v", err)
301 var tmp [1]byte
302 c.Read(tmp[:])
303 c.Close()
305 go func() {
306 runtime.Gosched()
307 select {}
310 // Unblock helper goroutines and wait them to finish.
311 wp.Write(tmp[:])
312 wp.Write(tmp[:])
313 close(done)
314 wg.Wait()
316 runtime.GOMAXPROCS(procs)
318 Stop()
319 saveTrace(t, buf, "TestTraceStress")
320 trace := buf.Bytes()
321 parseTrace(t, buf)
322 testBrokenTimestamps(t, trace)
325 // Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine.
326 // And concurrently with all that start/stop trace 3 times.
327 func TestTraceStressStartStop(t *testing.T) {
328 if runtime.GOOS == "js" {
329 t.Skip("no os.Pipe on js")
331 if IsEnabled() {
332 t.Skip("skipping because -test.trace is set")
334 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
335 outerDone := make(chan bool)
337 go func() {
338 defer func() {
339 outerDone <- true
342 var wg sync.WaitGroup
343 done := make(chan bool)
345 wg.Add(1)
346 go func() {
347 <-done
348 wg.Done()
351 rp, wp, err := os.Pipe()
352 if err != nil {
353 t.Errorf("failed to create pipe: %v", err)
354 return
356 defer func() {
357 rp.Close()
358 wp.Close()
360 wg.Add(1)
361 go func() {
362 var tmp [1]byte
363 rp.Read(tmp[:])
364 <-done
365 wg.Done()
367 time.Sleep(time.Millisecond)
369 go func() {
370 runtime.LockOSThread()
371 for {
372 select {
373 case <-done:
374 return
375 default:
376 runtime.Gosched()
381 runtime.GC()
382 // Trigger GC from malloc.
383 n := int(1e3)
384 if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
385 // Reduce allocation to avoid running out of
386 // memory on the builder - see issue/12032.
387 n = 512
389 for i := 0; i < n; i++ {
390 _ = make([]byte, 1<<20)
393 // Create a bunch of busy goroutines to load all Ps.
394 for p := 0; p < 10; p++ {
395 wg.Add(1)
396 go func() {
397 // Do something useful.
398 tmp := make([]byte, 1<<16)
399 for i := range tmp {
400 tmp[i]++
402 _ = tmp
403 <-done
404 wg.Done()
408 // Block in syscall.
409 wg.Add(1)
410 go func() {
411 var tmp [1]byte
412 rp.Read(tmp[:])
413 <-done
414 wg.Done()
417 runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
419 // Test timers.
420 timerDone := make(chan bool)
421 go func() {
422 time.Sleep(time.Millisecond)
423 timerDone <- true
425 <-timerDone
427 // A bit of network.
428 ln, err := net.Listen("tcp", "127.0.0.1:0")
429 if err != nil {
430 t.Errorf("listen failed: %v", err)
431 return
433 defer ln.Close()
434 go func() {
435 c, err := ln.Accept()
436 if err != nil {
437 return
439 time.Sleep(time.Millisecond)
440 var buf [1]byte
441 c.Write(buf[:])
442 c.Close()
444 c, err := net.Dial("tcp", ln.Addr().String())
445 if err != nil {
446 t.Errorf("dial failed: %v", err)
447 return
449 var tmp [1]byte
450 c.Read(tmp[:])
451 c.Close()
453 go func() {
454 runtime.Gosched()
455 select {}
458 // Unblock helper goroutines and wait them to finish.
459 wp.Write(tmp[:])
460 wp.Write(tmp[:])
461 close(done)
462 wg.Wait()
465 for i := 0; i < 3; i++ {
466 buf := new(bytes.Buffer)
467 if err := Start(buf); err != nil {
468 t.Fatalf("failed to start tracing: %v", err)
470 time.Sleep(time.Millisecond)
471 Stop()
472 saveTrace(t, buf, "TestTraceStressStartStop")
473 trace := buf.Bytes()
474 parseTrace(t, buf)
475 testBrokenTimestamps(t, trace)
477 <-outerDone
480 func TestTraceFutileWakeup(t *testing.T) {
481 if IsEnabled() {
482 t.Skip("skipping because -test.trace is set")
484 buf := new(bytes.Buffer)
485 if err := Start(buf); err != nil {
486 t.Fatalf("failed to start tracing: %v", err)
489 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
490 c0 := make(chan int, 1)
491 c1 := make(chan int, 1)
492 c2 := make(chan int, 1)
493 const procs = 2
494 var done sync.WaitGroup
495 done.Add(4 * procs)
496 for p := 0; p < procs; p++ {
497 const iters = 1e3
498 go func() {
499 for i := 0; i < iters; i++ {
500 runtime.Gosched()
501 c0 <- 0
503 done.Done()
505 go func() {
506 for i := 0; i < iters; i++ {
507 runtime.Gosched()
508 <-c0
510 done.Done()
512 go func() {
513 for i := 0; i < iters; i++ {
514 runtime.Gosched()
515 select {
516 case c1 <- 0:
517 case c2 <- 0:
520 done.Done()
522 go func() {
523 for i := 0; i < iters; i++ {
524 runtime.Gosched()
525 select {
526 case <-c1:
527 case <-c2:
530 done.Done()
533 done.Wait()
535 Stop()
536 saveTrace(t, buf, "TestTraceFutileWakeup")
537 events, _ := parseTrace(t, buf)
538 // Check that (1) trace does not contain EvFutileWakeup events and
539 // (2) there are no consecutive EvGoBlock/EvGCStart/EvGoBlock events
540 // (we call runtime.Gosched between all operations, so these would be futile wakeups).
541 gs := make(map[uint64]int)
542 for _, ev := range events {
543 switch ev.Type {
544 case trace.EvFutileWakeup:
545 t.Fatalf("found EvFutileWakeup event")
546 case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect:
547 if gs[ev.G] == 2 {
548 t.Fatalf("goroutine %v blocked on %v at %v right after start",
549 ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
551 if gs[ev.G] == 1 {
552 t.Fatalf("goroutine %v blocked on %v at %v while blocked",
553 ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
555 gs[ev.G] = 1
556 case trace.EvGoStart:
557 if gs[ev.G] == 1 {
558 gs[ev.G] = 2
560 default:
561 delete(gs, ev.G)
566 func saveTrace(t *testing.T, buf *bytes.Buffer, name string) {
567 if !*saveTraces {
568 return
570 if err := ioutil.WriteFile(name+".trace", buf.Bytes(), 0600); err != nil {
571 t.Errorf("failed to write trace file: %s", err)