github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/cmd/trace/trace_test.go (about)

     1  package main
     2  
     3  import (
     4  	"internal/trace"
     5  	"strings"
     6  	"testing"
     7  )
     8  
     9  // TestGoroutineCount tests runnable/running goroutine counts computed by generateTrace
    10  // remain in the valid range.
    11  //   - the counts must not be negative. generateTrace will return an error.
    12  //   - the counts must not include goroutines blocked waiting on channels or in syscall.
    13  func TestGoroutineCount(t *testing.T) {
    14  	w := trace.NewWriter()
    15  	w.Emit(trace.EvBatch, 0, 0)  // start of per-P batch event [pid, timestamp]
    16  	w.Emit(trace.EvFrequency, 1) // [ticks per second]
    17  
    18  	// In this test, we assume a valid trace contains EvGoWaiting or EvGoInSyscall
    19  	// event for every blocked goroutine.
    20  
    21  	// goroutine 10: blocked
    22  	w.Emit(trace.EvGoCreate, 1, 10, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
    23  	w.Emit(trace.EvGoWaiting, 1, 10)      // [timestamp, goroutine id]
    24  
    25  	// goroutine 20: in syscall
    26  	w.Emit(trace.EvGoCreate, 1, 20, 2, 1)
    27  	w.Emit(trace.EvGoInSyscall, 1, 20) // [timestamp, goroutine id]
    28  
    29  	// goroutine 30: runnable
    30  	w.Emit(trace.EvGoCreate, 1, 30, 5, 1)
    31  
    32  	w.Emit(trace.EvProcStart, 2, 0) // [timestamp, thread id]
    33  
    34  	// goroutine 40: runnable->running->runnable
    35  	w.Emit(trace.EvGoCreate, 1, 40, 7, 1)
    36  	w.Emit(trace.EvGoStartLocal, 1, 40) // [timestamp, goroutine id]
    37  	w.Emit(trace.EvGoSched, 1, 8)       // [timestamp, stack]
    38  
    39  	events, err := trace.Parse(w, "")
    40  	if err != nil {
    41  		t.Fatalf("failed to parse test trace: %v", err)
    42  	}
    43  
    44  	params := &traceParams{
    45  		events:  events,
    46  		endTime: int64(1<<63 - 1),
    47  	}
    48  
    49  	// If the counts drop below 0, generateTrace will return an error.
    50  	viewerData, err := generateTrace(params)
    51  	if err != nil {
    52  		t.Fatalf("generateTrace failed: %v", err)
    53  	}
    54  	for _, ev := range viewerData.Events {
    55  		if ev.Name == "Goroutines" {
    56  			cnt := ev.Arg.(*goroutineCountersArg)
    57  			if cnt.Runnable+cnt.Running > 2 {
    58  				t.Errorf("goroutine count=%+v; want no more than 2 goroutines in runnable/running state", cnt)
    59  			}
    60  			t.Logf("read %+v %+v", ev, cnt)
    61  		}
    62  	}
    63  }
    64  
    65  func TestGoroutineFilter(t *testing.T) {
    66  	// Test that we handle state changes to selected goroutines
    67  	// caused by events on goroutines that are not selected.
    68  
    69  	w := trace.NewWriter()
    70  	w.Emit(trace.EvBatch, 0, 0)  // start of per-P batch event [pid, timestamp]
    71  	w.Emit(trace.EvFrequency, 1) // [ticks per second]
    72  
    73  	// goroutine 10: blocked
    74  	w.Emit(trace.EvGoCreate, 1, 10, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
    75  	w.Emit(trace.EvGoWaiting, 1, 10)      // [timestamp, goroutine id]
    76  
    77  	// goroutine 20: runnable->running->unblock 10
    78  	w.Emit(trace.EvGoCreate, 1, 20, 7, 1)
    79  	w.Emit(trace.EvGoStartLocal, 1, 20)      // [timestamp, goroutine id]
    80  	w.Emit(trace.EvGoUnblockLocal, 1, 10, 8) // [timestamp, goroutine id, stack]
    81  	w.Emit(trace.EvGoEnd, 1)                 // [timestamp]
    82  
    83  	// goroutine 10: runnable->running->block
    84  	w.Emit(trace.EvGoStartLocal, 1, 10) // [timestamp, goroutine id]
    85  	w.Emit(trace.EvGoBlock, 1, 9)       // [timestamp, stack]
    86  
    87  	events, err := trace.Parse(w, "")
    88  	if err != nil {
    89  		t.Fatalf("failed to parse test trace: %v", err)
    90  	}
    91  
    92  	params := &traceParams{
    93  		events:  events,
    94  		endTime: int64(1<<63 - 1),
    95  		gs:      map[uint64]bool{10: true},
    96  	}
    97  
    98  	_, err = generateTrace(params)
    99  	if err != nil {
   100  		t.Fatalf("generateTrace failed: %v", err)
   101  	}
   102  }
   103  
   104  func TestPreemptedMarkAssist(t *testing.T) {
   105  	w := trace.NewWriter()
   106  	w.Emit(trace.EvBatch, 0, 0)  // start of per-P batch event [pid, timestamp]
   107  	w.Emit(trace.EvFrequency, 1) // [ticks per second]
   108  
   109  	// goroutine 9999: running -> mark assisting -> preempted -> assisting -> running -> block
   110  	w.Emit(trace.EvGoCreate, 1, 9999, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
   111  	w.Emit(trace.EvGoStartLocal, 1, 9999)   // [timestamp, goroutine id]
   112  	w.Emit(trace.EvGCMarkAssistStart, 1, 2) // [timestamp, stack]
   113  	w.Emit(trace.EvGoPreempt, 1, 3)         // [timestamp, stack]
   114  	w.Emit(trace.EvGoStartLocal, 1, 9999)   // [timestamp, goroutine id]
   115  	w.Emit(trace.EvGCMarkAssistDone, 1)     // [timestamp]
   116  	w.Emit(trace.EvGoBlock, 1, 4)           // [timestamp, stack]
   117  
   118  	events, err := trace.Parse(w, "")
   119  	if err != nil {
   120  		t.Fatalf("failed to parse test trace: %v", err)
   121  	}
   122  
   123  	params := &traceParams{
   124  		events:  events,
   125  		endTime: int64(1<<63 - 1),
   126  	}
   127  
   128  	viewerData, err := generateTrace(params)
   129  	if err != nil {
   130  		t.Fatalf("generateTrace failed: %v", err)
   131  	}
   132  
   133  	marks := 0
   134  	for _, ev := range viewerData.Events {
   135  		if strings.Contains(ev.Name, "MARK ASSIST") {
   136  			marks++
   137  		}
   138  	}
   139  	if marks != 2 {
   140  		t.Errorf("Got %v MARK ASSIST events, want %v", marks, 2)
   141  	}
   142  }