]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make TestDebugLogInterleaving much more robust
authorAustin Clements <austin@google.com>
Wed, 24 Jul 2024 03:09:07 +0000 (23:09 -0400)
committerGopher Robot <gobot@golang.org>
Tue, 30 Jul 2024 17:16:52 +0000 (17:16 +0000)
The current test often doesn't actually generate enough interleaving
to result in multiple log shards. This CL rewrites this test to
forcibly create at least 10 log shards with interleaved log messages.
It also tests dlog's robustness to being held across M and P switches.

Change-Id: Ia913b17c0392384ff679832047f359945669bb15
Reviewed-on: https://go-review.googlesource.com/c/go/+/600699
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Austin Clements <austin@google.com>

src/runtime/debuglog_test.go
src/runtime/export_debuglog_test.go

index 0f91398cddcb94d20eaf8caade1f5a59d2b84c65..d958c037400ff3b958d22808b10171754c319381 100644 (file)
@@ -28,7 +28,6 @@ import (
        "runtime"
        "strings"
        "sync"
-       "sync/atomic"
        "testing"
 )
 
@@ -82,28 +81,63 @@ func TestDebugLogSym(t *testing.T) {
 func TestDebugLogInterleaving(t *testing.T) {
        skipDebugLog(t)
        runtime.ResetDebugLog()
+
+       n1 := runtime.CountDebugLog()
+       t.Logf("number of log shards at start: %d", n1)
+
+       const limit = 1000
+       const concurrency = 10
+
+       // Start several goroutines writing to the log simultaneously.
        var wg sync.WaitGroup
-       done := int32(0)
-       wg.Add(1)
-       go func() {
-               // Encourage main goroutine to move around to
-               // different Ms and Ps.
-               for atomic.LoadInt32(&done) == 0 {
-                       runtime.Gosched()
-               }
-               wg.Done()
-       }()
-       var want strings.Builder
-       for i := 0; i < 1000; i++ {
-               runtime.Dlog().I(i).End()
-               fmt.Fprintf(&want, "[] %d\n", i)
-               runtime.Gosched()
+       i := 0
+       chans := make([]chan bool, concurrency)
+       for gid := range concurrency {
+               chans[gid] = make(chan bool)
+               wg.Add(1)
+               go func() {
+                       defer wg.Done()
+                       var log *runtime.Dlogger
+                       for {
+                               <-chans[gid]
+                               if log != nil {
+                                       log.End()
+                               }
+                               next := chans[(gid+1)%len(chans)]
+                               if i >= limit {
+                                       close(next)
+                                       break
+                               }
+                               // Log an entry, but *don't* release the log shard until its our
+                               // turn again. This should result in at least n=concurrency log
+                               // shards.
+                               log = runtime.Dlog().I(i)
+                               i++
+                               // Wake up the next logger goroutine.
+                               next <- true
+                       }
+               }()
        }
-       atomic.StoreInt32(&done, 1)
-       wg.Wait()
+       // Start the chain reaction.
+       chans[0] <- true
 
+       // Wait for them to finish and get the log.
+       wg.Wait()
        gotFull := runtime.DumpDebugLog()
        got := dlogCanonicalize(gotFull)
+
+       n2 := runtime.CountDebugLog()
+       t.Logf("number of log shards at end: %d", n2)
+       if n2 < concurrency {
+               t.Errorf("created %d log shards, expected >= %d", n2, concurrency)
+       }
+
+       // Construct the desired output.
+       var want strings.Builder
+       for i := 0; i < limit; i++ {
+               fmt.Fprintf(&want, "[] %d\n", i)
+       }
+
        if got != want.String() {
                // Since the timestamps are useful in understand
                // failures of this test, we print the uncanonicalized
index fc55f73c1fb73c9054a21000a0387470c5fcae03..c370a7933611a5fc76c503cfdb2605f84834c39e 100644 (file)
@@ -48,3 +48,13 @@ func ResetDebugLog() {
        }
        startTheWorld(stw)
 }
+
+func CountDebugLog() int {
+       stw := stopTheWorld(stwForTestResetDebugLog)
+       i := 0
+       for l := allDloggers; l != nil; l = l.allLink {
+               i++
+       }
+       startTheWorld(stw)
+       return i
+}