diff options
author | Dmitry Vyukov <dvyukov@google.com> | 2016-04-07 15:48:15 +0200 |
---|---|---|
committer | Dmitry Vyukov <dvyukov@google.com> | 2016-04-24 09:11:37 +0000 |
commit | 75b844f0d228bda5dea2aabae096909f81355bac (patch) | |
tree | f3751910ecac44a0ff89309efc03a8c520ce269e /src/runtime/trace | |
parent | 687fe991e42f15fe1f491680c615ef96568f780a (diff) | |
download | go-75b844f0d228bda5dea2aabae096909f81355bac.tar.gz go-75b844f0d228bda5dea2aabae096909f81355bac.zip |
runtime/trace: test detection of broken timestamps
On some processors cputicks (used to generate trace timestamps)
produce non-monotonic timestamps. It is important that the parser
distinguishes logically inconsistent traces (e.g. missing, excessive
or misordered events) from broken timestamps. The former is a bug
in tracer, the latter is a machine issue.
Test that (1) parser does not return a logical error in case of
broken timestamps and (2) broken timestamps are eventually detected
and reported.
Change-Id: Ib4b1eb43ce128b268e754400ed8b5e8def04bd78
Reviewed-on: https://go-review.googlesource.com/21608
Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/trace')
-rw-r--r-- | src/runtime/trace/trace_stack_test.go | 5 | ||||
-rw-r--r-- | src/runtime/trace/trace_test.go | 48 |
2 files changed, 35 insertions, 18 deletions
diff --git a/src/runtime/trace/trace_stack_test.go b/src/runtime/trace/trace_stack_test.go index c3fb0f6fee..52a71bfb94 100644 --- a/src/runtime/trace/trace_stack_test.go +++ b/src/runtime/trace/trace_stack_test.go @@ -125,10 +125,7 @@ func TestTraceSymbolize(t *testing.T) { <-pipeReadDone Stop() - events, _, err := parseTrace(t, buf) - if err != nil { - t.Fatalf("failed to parse trace: %v", err) - } + events, _ := parseTrace(t, buf) // Now check that the stacks are correct. type frame struct { diff --git a/src/runtime/trace/trace_test.go b/src/runtime/trace/trace_test.go index d10e928a66..5fad3fb7f0 100644 --- a/src/runtime/trace/trace_test.go +++ b/src/runtime/trace/trace_test.go @@ -61,13 +61,13 @@ func TestTrace(t *testing.T) { } } -func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc, error) { +func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc) { events, err := trace.Parse(r, "") if err == trace.ErrTimeOrder { t.Skipf("skipping trace: %v", err) } if err != nil { - return nil, nil, err + t.Fatalf("failed to parse trace: %v", err) } gs := trace.GoroutineStats(events) for goid := range gs { @@ -75,7 +75,31 @@ func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GD // But still check that RelatedGoroutines does not crash, hang, etc. _ = trace.RelatedGoroutines(events, goid) } - return events, gs, nil + return events, gs +} + +func testBrokenTimestamps(t *testing.T, data []byte) { + // On some processors cputicks (used to generate trace timestamps) + // produce non-monotonic timestamps. It is important that the parser + // distinguishes logically inconsistent traces (e.g. missing, excessive + // or misordered events) from broken timestamps. The former is a bug + // in tracer, the latter is a machine issue. + // So now that we have a consistent trace, test that (1) parser does + // not return a logical error in case of broken timestamps + // and (2) broken timestamps are eventually detected and reported. + trace.BreakTimestampsForTesting = true + defer func() { + trace.BreakTimestampsForTesting = false + }() + for i := 0; i < 1e4; i++ { + _, err := trace.Parse(bytes.NewReader(data), "") + if err == trace.ErrTimeOrder { + return + } + if err != nil { + t.Fatalf("failed to parse trace: %v", err) + } + } } func TestTraceStress(t *testing.T) { @@ -209,10 +233,9 @@ func TestTraceStress(t *testing.T) { runtime.GOMAXPROCS(procs) Stop() - _, _, err = parseTrace(t, buf) - if err != nil { - t.Fatalf("failed to parse trace: %v", err) - } + trace := buf.Bytes() + parseTrace(t, buf) + testBrokenTimestamps(t, trace) } // Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine. @@ -353,9 +376,9 @@ func TestTraceStressStartStop(t *testing.T) { } time.Sleep(time.Millisecond) Stop() - if _, _, err := parseTrace(t, buf); err != nil { - t.Fatalf("failed to parse trace: %v", err) - } + trace := buf.Bytes() + parseTrace(t, buf) + testBrokenTimestamps(t, trace) } <-outerDone } @@ -413,10 +436,7 @@ func TestTraceFutileWakeup(t *testing.T) { done.Wait() Stop() - events, _, err := parseTrace(t, buf) - if err != nil { - t.Fatalf("failed to parse trace: %v", err) - } + events, _ := parseTrace(t, buf) // Check that (1) trace does not contain EvFutileWakeup events and // (2) there are no consecutive EvGoBlock/EvGCStart/EvGoBlock events // (we call runtime.Gosched between all operations, so these would be futile wakeups). |