diff options
| author | Austin Clements <austin@google.com> | 2016-11-04 11:13:27 -0400 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2016-11-18 17:49:18 +0000 |
| commit | d0b3c169acda68040d051c27627c08da4e3377bd (patch) | |
| tree | 18eab35bf96cd57f38279bfdc90174abdf36d1ba /src/cmd/trace/trace_test.go | |
| parent | 0eb26fa8ba531b21d183fd3a4d3fb8abf57db7aa (diff) | |
| download | go-d0b3c169acda68040d051c27627c08da4e3377bd.tar.xz | |
cmd/trace: fix goroutine view
Currently, trace processing interleaves state/statistics updates and
emitting trace viewer objects. As a result, if events are being
filtered, either by time or by goroutines, we'll miss those
state/statistics updates. At best, this leads to bad statistics;
however, since we're now strictly checking G state transitions, it
usually leads to a failure to process the trace if there is any
filtering.
Fix this by separating state updates from emitting trace object. State
updates are done before filtering, so we always have correct state
information and statistics. Trace objects are only emitted if we pass
the filter. To determine when we need to emit trace counters, rather
than duplicating the knowledge of which events might modify
statistics, we keep track of the previously emitted counters and emit
a trace counter object whenever these have changed.
Fixes #17719.
Change-Id: Ic66e3ddaef60d1acaaf2ff4c62baa5352799cf99
Reviewed-on: https://go-review.googlesource.com/32810
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Diffstat (limited to 'src/cmd/trace/trace_test.go')
| -rw-r--r-- | src/cmd/trace/trace_test.go | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go index 73a2883f1e..d14239cfe1 100644 --- a/src/cmd/trace/trace_test.go +++ b/src/cmd/trace/trace_test.go @@ -60,3 +60,42 @@ func TestGoroutineCount(t *testing.T) { } } } + +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) + } +} |
