blob: d14239cfe16be560ad108e33256ba963334544b5 [file] [log] [blame]
package main
import (
"internal/trace"
"testing"
)
// TestGoroutineCount tests runnable/running goroutine counts computed by generateTrace
// remain in the valid range.
// - the counts must not be negative. generateTrace will return an error.
// - the counts must not include goroutines blocked waiting on channels or in syscall.
func TestGoroutineCount(t *testing.T) {
w := trace.NewWriter()
w.Emit(trace.EvBatch, 0, 0) // start of per-P batch event [pid, timestamp]
w.Emit(trace.EvFrequency, 1) // [ticks per second]
// In this test, we assume a valid trace contains EvGoWaiting or EvGoInSyscall
// event for every blocked goroutine.
// goroutine 10: blocked
w.Emit(trace.EvGoCreate, 1, 10, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
w.Emit(trace.EvGoWaiting, 1, 10) // [timestamp, goroutine id]
// goroutine 20: in syscall
w.Emit(trace.EvGoCreate, 1, 20, 2, 1)
w.Emit(trace.EvGoInSyscall, 1, 20) // [timestamp, goroutine id]
// goroutine 30: runnable
w.Emit(trace.EvGoCreate, 1, 30, 5, 1)
w.Emit(trace.EvProcStart, 2, 0) // [timestamp, thread id]
// goroutine 40: runnable->running->runnable
w.Emit(trace.EvGoCreate, 1, 40, 7, 1)
w.Emit(trace.EvGoStartLocal, 1, 40) // [timestamp, goroutine id]
w.Emit(trace.EvGoSched, 1, 8) // [timestamp, stack]
events, err := trace.Parse(w, "")
if err != nil {
t.Fatalf("failed to parse test trace: %v", err)
}
params := &traceParams{
events: events,
endTime: int64(1<<63 - 1),
}
// If the counts drop below 0, generateTrace will return an error.
viewerData, err := generateTrace(params)
if err != nil {
t.Fatalf("generateTrace failed: %v", err)
}
for _, ev := range viewerData.Events {
if ev.Name == "Goroutines" {
cnt := ev.Arg.(*goroutineCountersArg)
if cnt.Runnable+cnt.Running > 2 {
t.Errorf("goroutine count=%+v; want no more than 2 goroutines in runnable/running state", cnt)
}
t.Logf("read %+v %+v", ev, cnt)
}
}
}
func TestGoroutineFilter(t *testing.T) {
// Test that we handle state changes to selected goroutines
// caused by events on goroutines that are not selected.
w := trace.NewWriter()
w.Emit(trace.EvBatch, 0, 0) // start of per-P batch event [pid, timestamp]
w.Emit(trace.EvFrequency, 1) // [ticks per second]
// goroutine 10: blocked
w.Emit(trace.EvGoCreate, 1, 10, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
w.Emit(trace.EvGoWaiting, 1, 10) // [timestamp, goroutine id]
// goroutine 20: runnable->running->unblock 10
w.Emit(trace.EvGoCreate, 1, 20, 7, 1)
w.Emit(trace.EvGoStartLocal, 1, 20) // [timestamp, goroutine id]
w.Emit(trace.EvGoUnblockLocal, 1, 10, 8) // [timestamp, goroutine id, stack]
w.Emit(trace.EvGoEnd, 1) // [timestamp]
// goroutine 10: runnable->running->block
w.Emit(trace.EvGoStartLocal, 1, 10) // [timestamp, goroutine id]
w.Emit(trace.EvGoBlock, 1, 9) // [timestamp, stack]
events, err := trace.Parse(w, "")
if err != nil {
t.Fatalf("failed to parse test trace: %v", err)
}
params := &traceParams{
events: events,
endTime: int64(1<<63 - 1),
gs: map[uint64]bool{10: true},
}
_, err = generateTrace(params)
if err != nil {
t.Fatalf("generateTrace failed: %v", err)
}
}