Skip to content

Commit c7227bc

Browse files
aclementsgopherbot
authored andcommitted
runtime: make TestDebugLogInterleaving much more robust
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 <[email protected]> Reviewed-by: Carlos Amedee <[email protected]> Auto-Submit: Austin Clements <[email protected]>
1 parent cc258e6 commit c7227bc

File tree

2 files changed

+62
-18
lines changed

2 files changed

+62
-18
lines changed

src/runtime/debuglog_test.go

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
"runtime"
2929
"strings"
3030
"sync"
31-
"sync/atomic"
3231
"testing"
3332
)
3433

@@ -82,28 +81,63 @@ func TestDebugLogSym(t *testing.T) {
8281
func TestDebugLogInterleaving(t *testing.T) {
8382
skipDebugLog(t)
8483
runtime.ResetDebugLog()
84+
85+
n1 := runtime.CountDebugLog()
86+
t.Logf("number of log shards at start: %d", n1)
87+
88+
const limit = 1000
89+
const concurrency = 10
90+
91+
// Start several goroutines writing to the log simultaneously.
8592
var wg sync.WaitGroup
86-
done := int32(0)
87-
wg.Add(1)
88-
go func() {
89-
// Encourage main goroutine to move around to
90-
// different Ms and Ps.
91-
for atomic.LoadInt32(&done) == 0 {
92-
runtime.Gosched()
93-
}
94-
wg.Done()
95-
}()
96-
var want strings.Builder
97-
for i := 0; i < 1000; i++ {
98-
runtime.Dlog().I(i).End()
99-
fmt.Fprintf(&want, "[] %d\n", i)
100-
runtime.Gosched()
93+
i := 0
94+
chans := make([]chan bool, concurrency)
95+
for gid := range concurrency {
96+
chans[gid] = make(chan bool)
97+
wg.Add(1)
98+
go func() {
99+
defer wg.Done()
100+
var log *runtime.Dlogger
101+
for {
102+
<-chans[gid]
103+
if log != nil {
104+
log.End()
105+
}
106+
next := chans[(gid+1)%len(chans)]
107+
if i >= limit {
108+
close(next)
109+
break
110+
}
111+
// Log an entry, but *don't* release the log shard until its our
112+
// turn again. This should result in at least n=concurrency log
113+
// shards.
114+
log = runtime.Dlog().I(i)
115+
i++
116+
// Wake up the next logger goroutine.
117+
next <- true
118+
}
119+
}()
101120
}
102-
atomic.StoreInt32(&done, 1)
103-
wg.Wait()
121+
// Start the chain reaction.
122+
chans[0] <- true
104123

124+
// Wait for them to finish and get the log.
125+
wg.Wait()
105126
gotFull := runtime.DumpDebugLog()
106127
got := dlogCanonicalize(gotFull)
128+
129+
n2 := runtime.CountDebugLog()
130+
t.Logf("number of log shards at end: %d", n2)
131+
if n2 < concurrency {
132+
t.Errorf("created %d log shards, expected >= %d", n2, concurrency)
133+
}
134+
135+
// Construct the desired output.
136+
var want strings.Builder
137+
for i := 0; i < limit; i++ {
138+
fmt.Fprintf(&want, "[] %d\n", i)
139+
}
140+
107141
if got != want.String() {
108142
// Since the timestamps are useful in understand
109143
// failures of this test, we print the uncanonicalized

src/runtime/export_debuglog_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,13 @@ func ResetDebugLog() {
4848
}
4949
startTheWorld(stw)
5050
}
51+
52+
func CountDebugLog() int {
53+
stw := stopTheWorld(stwForTestResetDebugLog)
54+
i := 0
55+
for l := allDloggers; l != nil; l = l.allLink {
56+
i++
57+
}
58+
startTheWorld(stw)
59+
return i
60+
}

0 commit comments

Comments
 (0)