github.com/aloncn/graphics-go@v0.0.1/src/runtime/trace/trace_stack_test.go (about)

     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.
     4  
     5  package trace_test
     6  
     7  import (
     8  	"bytes"
     9  	"internal/testenv"
    10  	"internal/trace"
    11  	"net"
    12  	"os"
    13  	"runtime"
    14  	. "runtime/trace"
    15  	"sync"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  // TestTraceSymbolize tests symbolization and that events has proper stacks.
    21  // In particular that we strip bottom uninteresting frames like goexit,
    22  // top uninteresting frames (runtime guts).
    23  func TestTraceSymbolize(t *testing.T) {
    24  	testenv.MustHaveGoBuild(t)
    25  
    26  	buf := new(bytes.Buffer)
    27  	if err := Start(buf); err != nil {
    28  		t.Fatalf("failed to start tracing: %v", err)
    29  	}
    30  	defer Stop() // in case of early return
    31  
    32  	// Now we will do a bunch of things for which we verify stacks later.
    33  	// It is impossible to ensure that a goroutine has actually blocked
    34  	// on a channel, in a select or otherwise. So we kick off goroutines
    35  	// that need to block first in the hope that while we are executing
    36  	// the rest of the test, they will block.
    37  	go func() {
    38  		select {}
    39  	}()
    40  	go func() {
    41  		var c chan int
    42  		c <- 0
    43  	}()
    44  	go func() {
    45  		var c chan int
    46  		<-c
    47  	}()
    48  	done1 := make(chan bool)
    49  	go func() {
    50  		<-done1
    51  	}()
    52  	done2 := make(chan bool)
    53  	go func() {
    54  		done2 <- true
    55  	}()
    56  	c1 := make(chan int)
    57  	c2 := make(chan int)
    58  	go func() {
    59  		select {
    60  		case <-c1:
    61  		case <-c2:
    62  		}
    63  	}()
    64  	var mu sync.Mutex
    65  	mu.Lock()
    66  	go func() {
    67  		mu.Lock()
    68  		mu.Unlock()
    69  	}()
    70  	var wg sync.WaitGroup
    71  	wg.Add(1)
    72  	go func() {
    73  		wg.Wait()
    74  	}()
    75  	cv := sync.NewCond(&sync.Mutex{})
    76  	go func() {
    77  		cv.L.Lock()
    78  		cv.Wait()
    79  		cv.L.Unlock()
    80  	}()
    81  	ln, err := net.Listen("tcp", "127.0.0.1:0")
    82  	if err != nil {
    83  		t.Fatalf("failed to listen: %v", err)
    84  	}
    85  	go func() {
    86  		c, err := ln.Accept()
    87  		if err != nil {
    88  			t.Fatalf("failed to accept: %v", err)
    89  		}
    90  		c.Close()
    91  	}()
    92  	rp, wp, err := os.Pipe()
    93  	if err != nil {
    94  		t.Fatalf("failed to create a pipe: %v", err)
    95  	}
    96  	defer rp.Close()
    97  	defer wp.Close()
    98  	pipeReadDone := make(chan bool)
    99  	go func() {
   100  		var data [1]byte
   101  		rp.Read(data[:])
   102  		pipeReadDone <- true
   103  	}()
   104  
   105  	time.Sleep(time.Millisecond)
   106  	runtime.GC()
   107  	runtime.Gosched()
   108  	time.Sleep(time.Millisecond) // the last chance for the goroutines above to block
   109  	done1 <- true
   110  	<-done2
   111  	select {
   112  	case c1 <- 0:
   113  	case c2 <- 0:
   114  	}
   115  	mu.Unlock()
   116  	wg.Done()
   117  	cv.Signal()
   118  	c, err := net.Dial("tcp", ln.Addr().String())
   119  	if err != nil {
   120  		t.Fatalf("failed to dial: %v", err)
   121  	}
   122  	c.Close()
   123  	var data [1]byte
   124  	wp.Write(data[:])
   125  	<-pipeReadDone
   126  
   127  	Stop()
   128  	events, _, err := parseTrace(t, buf)
   129  	if err != nil {
   130  		t.Fatalf("failed to parse trace: %v", err)
   131  	}
   132  	err = trace.Symbolize(events, os.Args[0])
   133  	if err != nil {
   134  		t.Fatalf("failed to symbolize trace: %v", err)
   135  	}
   136  
   137  	// Now check that the stacks are correct.
   138  	type frame struct {
   139  		Fn   string
   140  		Line int
   141  	}
   142  	type eventDesc struct {
   143  		Type byte
   144  		Stk  []frame
   145  	}
   146  	want := []eventDesc{
   147  		{trace.EvGCStart, []frame{
   148  			{"runtime.GC", 0},
   149  			{"runtime/trace_test.TestTraceSymbolize", 106},
   150  			{"testing.tRunner", 0},
   151  		}},
   152  		{trace.EvGoSched, []frame{
   153  			{"runtime/trace_test.TestTraceSymbolize", 107},
   154  			{"testing.tRunner", 0},
   155  		}},
   156  		{trace.EvGoCreate, []frame{
   157  			{"runtime/trace_test.TestTraceSymbolize", 39},
   158  			{"testing.tRunner", 0},
   159  		}},
   160  		{trace.EvGoStop, []frame{
   161  			{"runtime.block", 0},
   162  			{"runtime/trace_test.TestTraceSymbolize.func1", 38},
   163  		}},
   164  		{trace.EvGoStop, []frame{
   165  			{"runtime.chansend1", 0},
   166  			{"runtime/trace_test.TestTraceSymbolize.func2", 42},
   167  		}},
   168  		{trace.EvGoStop, []frame{
   169  			{"runtime.chanrecv1", 0},
   170  			{"runtime/trace_test.TestTraceSymbolize.func3", 46},
   171  		}},
   172  		{trace.EvGoBlockRecv, []frame{
   173  			{"runtime.chanrecv1", 0},
   174  			{"runtime/trace_test.TestTraceSymbolize.func4", 50},
   175  		}},
   176  		{trace.EvGoUnblock, []frame{
   177  			{"runtime.chansend1", 0},
   178  			{"runtime/trace_test.TestTraceSymbolize", 109},
   179  			{"testing.tRunner", 0},
   180  		}},
   181  		{trace.EvGoBlockSend, []frame{
   182  			{"runtime.chansend1", 0},
   183  			{"runtime/trace_test.TestTraceSymbolize.func5", 54},
   184  		}},
   185  		{trace.EvGoUnblock, []frame{
   186  			{"runtime.chanrecv1", 0},
   187  			{"runtime/trace_test.TestTraceSymbolize", 110},
   188  			{"testing.tRunner", 0},
   189  		}},
   190  		{trace.EvGoBlockSelect, []frame{
   191  			{"runtime.selectgo", 0},
   192  			{"runtime/trace_test.TestTraceSymbolize.func6", 59},
   193  		}},
   194  		{trace.EvGoUnblock, []frame{
   195  			{"runtime.selectgo", 0},
   196  			{"runtime/trace_test.TestTraceSymbolize", 111},
   197  			{"testing.tRunner", 0},
   198  		}},
   199  		{trace.EvGoBlockSync, []frame{
   200  			{"sync.(*Mutex).Lock", 0},
   201  			{"runtime/trace_test.TestTraceSymbolize.func7", 67},
   202  		}},
   203  		{trace.EvGoUnblock, []frame{
   204  			{"sync.(*Mutex).Unlock", 0},
   205  			{"runtime/trace_test.TestTraceSymbolize", 115},
   206  			{"testing.tRunner", 0},
   207  		}},
   208  		{trace.EvGoBlockSync, []frame{
   209  			{"sync.(*WaitGroup).Wait", 0},
   210  			{"runtime/trace_test.TestTraceSymbolize.func8", 73},
   211  		}},
   212  		{trace.EvGoUnblock, []frame{
   213  			{"sync.(*WaitGroup).Add", 0},
   214  			{"sync.(*WaitGroup).Done", 0},
   215  			{"runtime/trace_test.TestTraceSymbolize", 116},
   216  			{"testing.tRunner", 0},
   217  		}},
   218  		{trace.EvGoBlockCond, []frame{
   219  			{"sync.(*Cond).Wait", 0},
   220  			{"runtime/trace_test.TestTraceSymbolize.func9", 78},
   221  		}},
   222  		{trace.EvGoUnblock, []frame{
   223  			{"sync.(*Cond).Signal", 0},
   224  			{"runtime/trace_test.TestTraceSymbolize", 117},
   225  			{"testing.tRunner", 0},
   226  		}},
   227  		{trace.EvGoSleep, []frame{
   228  			{"time.Sleep", 0},
   229  			{"runtime/trace_test.TestTraceSymbolize", 108},
   230  			{"testing.tRunner", 0},
   231  		}},
   232  	}
   233  	// Stacks for the following events are OS-dependent due to OS-specific code in net package.
   234  	if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
   235  		want = append(want, []eventDesc{
   236  			{trace.EvGoBlockNet, []frame{
   237  				{"net.(*netFD).accept", 0},
   238  				{"net.(*TCPListener).AcceptTCP", 0},
   239  				{"net.(*TCPListener).Accept", 0},
   240  				{"runtime/trace_test.TestTraceSymbolize.func10", 86},
   241  			}},
   242  			{trace.EvGoSysCall, []frame{
   243  				{"syscall.read", 0},
   244  				{"syscall.Read", 0},
   245  				{"os.(*File).read", 0},
   246  				{"os.(*File).Read", 0},
   247  				{"runtime/trace_test.TestTraceSymbolize.func11", 101},
   248  			}},
   249  		}...)
   250  	}
   251  	matched := make([]bool, len(want))
   252  	for _, ev := range events {
   253  	wantLoop:
   254  		for i, w := range want {
   255  			if matched[i] || w.Type != ev.Type || len(w.Stk) != len(ev.Stk) {
   256  				continue
   257  			}
   258  
   259  			for fi, f := range ev.Stk {
   260  				wf := w.Stk[fi]
   261  				if wf.Fn != f.Fn || wf.Line != 0 && wf.Line != f.Line {
   262  					continue wantLoop
   263  				}
   264  			}
   265  			matched[i] = true
   266  		}
   267  	}
   268  	for i, m := range matched {
   269  		if m {
   270  			continue
   271  		}
   272  		w := want[i]
   273  		t.Errorf("did not match event %v at %v:%v", trace.EventDescriptions[w.Type].Name, w.Stk[0].Fn, w.Stk[0].Line)
   274  		t.Errorf("seen the following events of this type:")
   275  		for _, ev := range events {
   276  			if ev.Type != w.Type {
   277  				continue
   278  			}
   279  			for _, f := range ev.Stk {
   280  				t.Logf("  %v:%v", f.Fn, f.Line)
   281  			}
   282  			t.Logf("---")
   283  		}
   284  	}
   285  }