Skip to content

Commit 847f157

Browse files
felixgegopherbot
authored andcommitted
internal/trace: add a validator test for the new clock snapshots
Check that the clock snapshots, when expected to be present, are non-zero and monotonically increasing. This required some refactoring to make the validator aware of the version of the trace it is validating. Change-Id: I04c4dd10fe6975cbac12bb0ddaebcec3a5284e7b Reviewed-on: https://go-review.googlesource.com/c/go/+/669715 Auto-Submit: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: David Chase <drchase@google.com>
1 parent 2d21614 commit 847f157

File tree

7 files changed

+72
-38
lines changed

7 files changed

+72
-38
lines changed

src/internal/trace/gc_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ func TestMMUTrace(t *testing.T) {
118118
}
119119
t.Run("V2", func(t *testing.T) {
120120
testPath := "testdata/tests/go122-gc-stress.test"
121-
r, _, err := testtrace.ParseFile(testPath)
121+
r, _, _, err := testtrace.ParseFile(testPath)
122122
if err != nil {
123123
t.Fatalf("malformed test %s: bad trace file: %v", testPath, err)
124124
}

src/internal/trace/reader_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ func TestReaderGolden(t *testing.T) {
3737
t.Fatalf("failed to relativize testdata path: %v", err)
3838
}
3939
t.Run(testName, func(t *testing.T) {
40-
tr, exp, err := testtrace.ParseFile(testPath)
40+
tr, ver, exp, err := testtrace.ParseFile(testPath)
4141
if err != nil {
4242
t.Fatalf("failed to parse test file at %s: %v", testPath, err)
4343
}
44-
testReader(t, tr, exp)
44+
testReader(t, tr, ver, exp)
4545
})
4646
}
4747
}
@@ -93,7 +93,7 @@ func FuzzReader(f *testing.F) {
9393
})
9494
}
9595

96-
func testReader(t *testing.T, tr io.Reader, exp *testtrace.Expectation) {
96+
func testReader(t *testing.T, tr io.Reader, ver version.Version, exp *testtrace.Expectation) {
9797
r, err := trace.NewReader(tr)
9898
if err != nil {
9999
if err := exp.Check(err); err != nil {
@@ -102,6 +102,7 @@ func testReader(t *testing.T, tr io.Reader, exp *testtrace.Expectation) {
102102
return
103103
}
104104
v := testtrace.NewValidator()
105+
v.GoVersion = ver
105106
for {
106107
ev, err := r.ReadEvent()
107108
if err == io.EOF {

src/internal/trace/summary_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ func basicGoroutineSummaryChecks(t *testing.T, summary *trace.GoroutineSummary)
264264
}
265265

266266
func summarizeTraceTest(t *testing.T, testPath string) *trace.Summary {
267-
trc, _, err := testtrace.ParseFile(testPath)
267+
trc, _, _, err := testtrace.ParseFile(testPath)
268268
if err != nil {
269269
t.Fatalf("malformed test %s: bad trace file: %v", testPath, err)
270270
}
@@ -388,7 +388,7 @@ func basicGoroutineExecStatsChecks(t *testing.T, stats *trace.GoroutineExecStats
388388

389389
func TestRelatedGoroutinesV2Trace(t *testing.T) {
390390
testPath := "testdata/tests/go122-gc-stress.test"
391-
trc, _, err := testtrace.ParseFile(testPath)
391+
trc, _, _, err := testtrace.ParseFile(testPath)
392392
if err != nil {
393393
t.Fatalf("malformed test %s: bad trace file: %v", testPath, err)
394394
}

src/internal/trace/testtrace/format.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,50 @@ import (
88
"bytes"
99
"fmt"
1010
"internal/trace/raw"
11+
"internal/trace/version"
1112
"internal/txtar"
1213
"io"
1314
)
1415

1516
// ParseFile parses a test file generated by the testgen package.
16-
func ParseFile(testPath string) (io.Reader, *Expectation, error) {
17+
func ParseFile(testPath string) (io.Reader, version.Version, *Expectation, error) {
1718
ar, err := txtar.ParseFile(testPath)
1819
if err != nil {
19-
return nil, nil, fmt.Errorf("failed to read test file for %s: %v", testPath, err)
20+
return nil, 0, nil, fmt.Errorf("failed to read test file for %s: %v", testPath, err)
2021
}
2122
if len(ar.Files) != 2 {
22-
return nil, nil, fmt.Errorf("malformed test %s: wrong number of files", testPath)
23+
return nil, 0, nil, fmt.Errorf("malformed test %s: wrong number of files", testPath)
2324
}
2425
if ar.Files[0].Name != "expect" {
25-
return nil, nil, fmt.Errorf("malformed test %s: bad filename %s", testPath, ar.Files[0].Name)
26+
return nil, 0, nil, fmt.Errorf("malformed test %s: bad filename %s", testPath, ar.Files[0].Name)
2627
}
2728
if ar.Files[1].Name != "trace" {
28-
return nil, nil, fmt.Errorf("malformed test %s: bad filename %s", testPath, ar.Files[1].Name)
29+
return nil, 0, nil, fmt.Errorf("malformed test %s: bad filename %s", testPath, ar.Files[1].Name)
2930
}
3031
tr, err := raw.NewTextReader(bytes.NewReader(ar.Files[1].Data))
3132
if err != nil {
32-
return nil, nil, fmt.Errorf("malformed test %s: bad trace file: %v", testPath, err)
33+
return nil, 0, nil, fmt.Errorf("malformed test %s: bad trace file: %v", testPath, err)
3334
}
3435
var buf bytes.Buffer
3536
tw, err := raw.NewWriter(&buf, tr.Version())
3637
if err != nil {
37-
return nil, nil, fmt.Errorf("failed to create trace byte writer: %v", err)
38+
return nil, 0, nil, fmt.Errorf("failed to create trace byte writer: %v", err)
3839
}
3940
for {
4041
ev, err := tr.ReadEvent()
4142
if err == io.EOF {
4243
break
4344
}
4445
if err != nil {
45-
return nil, nil, fmt.Errorf("malformed test %s: bad trace file: %v", testPath, err)
46+
return nil, 0, nil, fmt.Errorf("malformed test %s: bad trace file: %v", testPath, err)
4647
}
4748
if err := tw.WriteEvent(ev); err != nil {
48-
return nil, nil, fmt.Errorf("internal error during %s: failed to write trace bytes: %v", testPath, err)
49+
return nil, 0, nil, fmt.Errorf("internal error during %s: failed to write trace bytes: %v", testPath, err)
4950
}
5051
}
5152
exp, err := ParseExpectation(ar.Files[0].Data)
5253
if err != nil {
53-
return nil, nil, fmt.Errorf("internal error during %s: failed to parse expectation %q: %v", testPath, string(ar.Files[0].Data), err)
54+
return nil, 0, nil, fmt.Errorf("internal error during %s: failed to parse expectation %q: %v", testPath, string(ar.Files[0].Data), err)
5455
}
55-
return &buf, exp, nil
56+
return &buf, tr.Version(), exp, nil
5657
}

src/internal/trace/testtrace/validation.go

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,21 @@ import (
88
"errors"
99
"fmt"
1010
"internal/trace"
11+
"internal/trace/version"
1112
"slices"
1213
"strings"
1314
)
1415

1516
// Validator is a type used for validating a stream of trace.Events.
1617
type Validator struct {
17-
lastTs trace.Time
18-
gs map[trace.GoID]*goState
19-
ps map[trace.ProcID]*procState
20-
ms map[trace.ThreadID]*schedContext
21-
ranges map[trace.ResourceID][]string
22-
tasks map[trace.TaskID]string
23-
nSync int
24-
Go121 bool
18+
lastTs trace.Time
19+
gs map[trace.GoID]*goState
20+
ps map[trace.ProcID]*procState
21+
ms map[trace.ThreadID]*schedContext
22+
ranges map[trace.ResourceID][]string
23+
tasks map[trace.TaskID]string
24+
lastSync trace.Sync
25+
GoVersion version.Version
2526
}
2627

2728
type schedContext struct {
@@ -43,11 +44,12 @@ type procState struct {
4344
// NewValidator creates a new Validator.
4445
func NewValidator() *Validator {
4546
return &Validator{
46-
gs: make(map[trace.GoID]*goState),
47-
ps: make(map[trace.ProcID]*procState),
48-
ms: make(map[trace.ThreadID]*schedContext),
49-
ranges: make(map[trace.ResourceID][]string),
50-
tasks: make(map[trace.TaskID]string),
47+
gs: make(map[trace.GoID]*goState),
48+
ps: make(map[trace.ProcID]*procState),
49+
ms: make(map[trace.ThreadID]*schedContext),
50+
ranges: make(map[trace.ResourceID][]string),
51+
tasks: make(map[trace.TaskID]string),
52+
GoVersion: version.Current,
5153
}
5254
}
5355

@@ -74,10 +76,38 @@ func (v *Validator) Event(ev trace.Event) error {
7476
switch ev.Kind() {
7577
case trace.EventSync:
7678
s := ev.Sync()
77-
if s.N != v.nSync+1 {
78-
e.Errorf("sync count is not sequential: expected %d, got %d", v.nSync+1, s.N)
79+
if s.N != v.lastSync.N+1 {
80+
e.Errorf("sync count is not sequential: expected %d, got %d", v.lastSync.N+1, s.N)
7981
}
80-
v.nSync = s.N
82+
// The trace reader currently emits synthetic sync events at the end of
83+
// a trace. Those don't contain clock snapshots data, so we don't try
84+
// to validate them.
85+
//
86+
// TODO(felixge): Drop the synthetic syncs as discussed in CL 653576.
87+
if v.GoVersion >= version.Go125 && !(s.N > 1 && s.ClockSnapshot == nil) {
88+
if s.ClockSnapshot == nil {
89+
e.Errorf("sync %d has no clock snapshot", s.N)
90+
}
91+
if s.ClockSnapshot.Wall.IsZero() {
92+
e.Errorf("sync %d has zero wall time", s.N)
93+
}
94+
if s.ClockSnapshot.Mono == 0 {
95+
e.Errorf("sync %d has zero mono time", s.N)
96+
}
97+
if s.ClockSnapshot.Trace == 0 {
98+
e.Errorf("sync %d has zero trace time", s.N)
99+
}
100+
if s.N >= 2 && !s.ClockSnapshot.Wall.After(v.lastSync.ClockSnapshot.Wall) {
101+
e.Errorf("sync %d has non-increasing wall time: %v vs %v", s.N, s.ClockSnapshot.Wall, v.lastSync.ClockSnapshot.Wall)
102+
}
103+
if s.N >= 2 && !(s.ClockSnapshot.Mono > v.lastSync.ClockSnapshot.Mono) {
104+
e.Errorf("sync %d has non-increasing mono time: %v vs %v", s.N, s.ClockSnapshot.Mono, v.lastSync.ClockSnapshot.Mono)
105+
}
106+
if s.N >= 2 && !(s.ClockSnapshot.Trace > v.lastSync.ClockSnapshot.Trace) {
107+
e.Errorf("sync %d has non-increasing trace time: %v vs %v", s.N, s.ClockSnapshot.Trace, v.lastSync.ClockSnapshot.Trace)
108+
}
109+
}
110+
v.lastSync = s
81111
case trace.EventMetric:
82112
m := ev.Metric()
83113
if !strings.Contains(m.Name, ":") {
@@ -143,7 +173,7 @@ func (v *Validator) Event(ev trace.Event) error {
143173
if new == trace.GoUndetermined {
144174
e.Errorf("transition to undetermined state for goroutine %d", id)
145175
}
146-
if v.nSync > 1 && old == trace.GoUndetermined {
176+
if v.lastSync.N > 1 && old == trace.GoUndetermined {
147177
e.Errorf("undetermined goroutine %d after first global sync", id)
148178
}
149179
if new == trace.GoNotExist && v.hasAnyRange(trace.MakeResourceID(id)) {
@@ -196,7 +226,7 @@ func (v *Validator) Event(ev trace.Event) error {
196226
if new == trace.ProcUndetermined {
197227
e.Errorf("transition to undetermined state for proc %d", id)
198228
}
199-
if v.nSync > 1 && old == trace.ProcUndetermined {
229+
if v.lastSync.N > 1 && old == trace.ProcUndetermined {
200230
e.Errorf("undetermined proc %d after first global sync", id)
201231
}
202232
if new == trace.ProcNotExist && v.hasAnyRange(trace.MakeResourceID(id)) {
@@ -325,7 +355,7 @@ func (v *Validator) getOrCreateThread(e *errAccumulator, ev trace.Event, m trace
325355
// Be lenient about GoUndetermined -> GoSyscall transitions if they
326356
// originate from an old trace. These transitions lack thread
327357
// information in trace formats older than 1.22.
328-
if !v.Go121 {
358+
if v.GoVersion >= version.Go122 {
329359
return false
330360
}
331361
if ev.Kind() != trace.EventStateTransition {

src/internal/trace/trace_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"internal/testenv"
1313
"internal/trace"
1414
"internal/trace/testtrace"
15+
"internal/trace/version"
1516
"io"
1617
"os"
1718
"path/filepath"
@@ -617,7 +618,7 @@ func testTraceProg(t *testing.T, progName string, extra func(t *testing.T, trace
617618
tb := traceBuf.Bytes()
618619

619620
// Test the trace and the parser.
620-
testReader(t, bytes.NewReader(tb), testtrace.ExpectSuccess())
621+
testReader(t, bytes.NewReader(tb), version.Current, testtrace.ExpectSuccess())
621622

622623
// Run some extra validation.
623624
if !t.Failed() && extra != nil {

src/internal/trace/tracev1_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package trace_test
77
import (
88
"internal/trace"
99
"internal/trace/testtrace"
10+
"internal/trace/version"
1011
"io"
1112
"os"
1213
"path/filepath"
@@ -38,7 +39,7 @@ func TestTraceV1(t *testing.T) {
3839
}
3940

4041
v := testtrace.NewValidator()
41-
v.Go121 = true
42+
v.GoVersion = version.Go121
4243
for {
4344
ev, err := tr.ReadEvent()
4445
if err != nil {

0 commit comments

Comments
 (0)