aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/trace
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-04-07 15:48:15 +0200
committerDmitry Vyukov <dvyukov@google.com>2016-04-24 09:11:37 +0000
commit75b844f0d228bda5dea2aabae096909f81355bac (patch)
treef3751910ecac44a0ff89309efc03a8c520ce269e /src/runtime/trace
parent687fe991e42f15fe1f491680c615ef96568f780a (diff)
downloadgo-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.go5
-rw-r--r--src/runtime/trace/trace_test.go48
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).