]> Cypherpunks repositories - gostls13.git/commitdiff
internal/trace: make Reader output deterministic
authorRhys Hiltner <rhys.hiltner@gmail.com>
Tue, 2 Jul 2024 22:26:32 +0000 (15:26 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 22 Jul 2024 21:23:42 +0000 (21:23 +0000)
Multiple Ms can offer Events with identical timestamps. The Reader
edits those so the timestamps are strictly increasing, but it needs a
way to break the tie. Use something deterministic (such as the order of
the batches), rather than map iteration order.

Updates #68277

Change-Id: I4a1f70c1669ce1c9b52d09e2bc99acbc831ef9a4
Reviewed-on: https://go-review.googlesource.com/c/go/+/596355
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Rhys Hiltner <rhys.hiltner@gmail.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
src/internal/trace/generation.go
src/internal/trace/reader.go
src/internal/trace/trace_test.go

index 098d1d4f23949d603878d5e6e808e235f63b2fbf..98bbf4398569f9a1dc580293db8810f20481c4c9 100644 (file)
@@ -25,6 +25,7 @@ import (
 type generation struct {
        gen        uint64
        batches    map[ThreadID][]batch
+       batchMs    []ThreadID
        cpuSamples []cpuSample
        *evTable
 }
@@ -169,6 +170,9 @@ func processBatch(g *generation, b batch) error {
                        return err
                }
        default:
+               if _, ok := g.batches[b.m]; !ok {
+                       g.batchMs = append(g.batchMs, b.m)
+               }
                g.batches[b.m] = append(g.batches[b.m], b)
        }
        return nil
index c05d5b58b38d7c93a4603aa7b9c760cc709b222e..81157292fb3f089955dbc6863e78c42ff208048b 100644 (file)
@@ -142,7 +142,8 @@ func (r *Reader) ReadEvent() (e Event, err error) {
                r.cpuSamples = r.gen.cpuSamples
 
                // Reset frontier.
-               for m, batches := range r.gen.batches {
+               for _, m := range r.gen.batchMs {
+                       batches := r.gen.batches[m]
                        bc := &batchCursor{m: m}
                        ok, err := bc.nextEvent(batches, r.gen.freq)
                        if err != nil {
index 7dc5cbb89d739929130296f4876f6a8bdc131875..1929069cc5da97edbaeb69c8ba60a085b9c44974 100644 (file)
@@ -507,7 +507,7 @@ func TestTraceStress(t *testing.T) {
        case "js", "wasip1":
                t.Skip("no os.Pipe on " + runtime.GOOS)
        }
-       testTraceProg(t, "stress.go", nil)
+       testTraceProg(t, "stress.go", checkReaderDeterminism)
 }
 
 func TestTraceStressStartStop(t *testing.T) {
@@ -535,6 +535,43 @@ func TestTraceIterPull(t *testing.T) {
        testTraceProg(t, "iter-pull.go", nil)
 }
 
+func checkReaderDeterminism(t *testing.T, tb, _ []byte, _ bool) {
+       events := func() []trace.Event {
+               var evs []trace.Event
+
+               r, err := trace.NewReader(bytes.NewReader(tb))
+               if err != nil {
+                       t.Error(err)
+               }
+               for {
+                       ev, err := r.ReadEvent()
+                       if err == io.EOF {
+                               break
+                       }
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       evs = append(evs, ev)
+               }
+
+               return evs
+       }
+
+       evs1 := events()
+       evs2 := events()
+
+       if l1, l2 := len(evs1), len(evs2); l1 != l2 {
+               t.Fatalf("re-reading trace gives different event count (%d != %d)", l1, l2)
+       }
+       for i, ev1 := range evs1 {
+               ev2 := evs2[i]
+               if s1, s2 := ev1.String(), ev2.String(); s1 != s2 {
+                       t.Errorf("re-reading trace gives different event %d:\n%s\n%s\n", i, s1, s2)
+                       break
+               }
+       }
+}
+
 func testTraceProg(t *testing.T, progName string, extra func(t *testing.T, trace, stderr []byte, stress bool)) {
        testenv.MustHaveGoRun(t)