Skip to content

Commit 089d363

Browse files
committed
runtime: fix tracing of syscall exit
Fix tracing of syscall exit after: https://go-review.googlesource.com/#/c/7504/ Change-Id: Idcde2aa826d2b9a05d0a90a80242b6bfa78846ab Reviewed-on: https://go-review.googlesource.com/8728 Reviewed-by: Rick Hudson <[email protected]> Run-TryBot: Dmitry Vyukov <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 53a8ee5 commit 089d363

File tree

3 files changed

+53
-16
lines changed

3 files changed

+53
-16
lines changed

src/internal/trace/parser.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,12 @@ func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
235235
EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet,
236236
EvGoSysBlock:
237237
lastG = 0
238+
case EvGoSysExit:
239+
if e.Args[1] != 0 {
240+
// EvGoSysExit emission is delayed until the thread has a P.
241+
// Give it the real timestamp.
242+
e.Ts = int64(e.Args[1])
243+
}
238244
}
239245
events = append(events, e)
240246
}
@@ -423,7 +429,12 @@ func postProcessTrace(events []*Event) error {
423429
g1.state = gWaiting
424430
gs[ev.Args[0]] = g1
425431
case EvGoInSyscall:
426-
// this case is intentionally left blank
432+
g1 := gs[ev.Args[0]]
433+
if g1.state != gRunnable {
434+
return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
435+
}
436+
g1.state = gWaiting
437+
gs[ev.Args[0]] = g1
427438
case EvGoCreate:
428439
if err := checkRunning(p, g, ev); err != nil {
429440
return err
@@ -498,17 +509,18 @@ func postProcessTrace(events []*Event) error {
498509
if err := checkRunning(p, g, ev); err != nil {
499510
return err
500511
}
501-
g.state = gRunnable
512+
g.state = gWaiting
502513
g.evStart.Link = ev
503514
g.evStart = nil
504515
p.g = 0
505516
case EvGoSysExit:
506-
if g.state != gRunnable {
507-
return fmt.Errorf("g %v is not runnable during syscall exit (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
517+
if g.state != gWaiting {
518+
return fmt.Errorf("g %v is not waiting during syscall exit (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
508519
}
509520
if g.ev != nil && g.ev.Type == EvGoSysCall {
510521
g.ev.Link = ev
511522
}
523+
g.state = gRunnable
512524
g.ev = ev
513525
case EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
514526
EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet:
@@ -638,6 +650,18 @@ func (l eventList) Swap(i, j int) {
638650
l[i], l[j] = l[j], l[i]
639651
}
640652

653+
// Print dumps events to stdout. For debugging.
654+
func Print(events []*Event) {
655+
for _, ev := range events {
656+
desc := EventDescriptions[ev.Type]
657+
fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off)
658+
for i, a := range desc.Args {
659+
fmt.Printf(" %v=%v", a, ev.Args[i])
660+
}
661+
fmt.Printf("\n")
662+
}
663+
}
664+
641665
// Event types in the trace.
642666
// Verbatim copy from src/runtime/trace.go.
643667
const (
@@ -670,7 +694,7 @@ const (
670694
EvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack]
671695
EvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack]
672696
EvGoSysCall = 28 // syscall enter [timestamp, stack]
673-
EvGoSysExit = 29 // syscall exit [timestamp, goroutine id]
697+
EvGoSysExit = 29 // syscall exit [timestamp, goroutine id, real timestamp]
674698
EvGoSysBlock = 30 // syscall blocks [timestamp]
675699
EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
676700
EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
@@ -715,7 +739,7 @@ var EventDescriptions = [EvCount]struct {
715739
EvGoBlockCond: {"GoBlockCond", true, []string{}},
716740
EvGoBlockNet: {"GoBlockNet", true, []string{}},
717741
EvGoSysCall: {"GoSysCall", true, []string{}},
718-
EvGoSysExit: {"GoSysExit", false, []string{"g"}},
742+
EvGoSysExit: {"GoSysExit", false, []string{"g", "ts"}},
719743
EvGoSysBlock: {"GoSysBlock", false, []string{}},
720744
EvGoWaiting: {"GoWaiting", false, []string{"g"}},
721745
EvGoInSyscall: {"GoInSyscall", false, []string{"g"}},

src/runtime/proc1.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,24 +1813,30 @@ func exitsyscall(dummy int32) {
18131813
return
18141814
}
18151815

1816+
var exitTicks int64
18161817
if trace.enabled {
18171818
// Wait till traceGoSysBlock event is emited.
18181819
// This ensures consistency of the trace (the goroutine is started after it is blocked).
18191820
for oldp != nil && oldp.syscalltick == _g_.m.syscalltick {
18201821
osyield()
18211822
}
1822-
// This can't be done since the GC may be running and this code
1823-
// will invoke write barriers.
1824-
// TODO: Figure out how to get traceGoSysExit into the trace log or
1825-
// it is likely not to work as expected.
1826-
// systemstack(traceGoSysExit)
1823+
// We can't trace syscall exit right now because we don't have a P.
1824+
// Tracing code can invoke write barriers that cannot run without a P.
1825+
// So instead we remember the syscall exit time and emit the event
1826+
// below when we have a P.
1827+
exitTicks = cputicks()
18271828
}
18281829

18291830
_g_.m.locks--
18301831

18311832
// Call the scheduler.
18321833
mcall(exitsyscall0)
18331834

1835+
// The goroutine must not be re-scheduled up to traceGoSysExit.
1836+
// Otherwise we can emit GoStart but not GoSysExit, that would lead
1837+
// no an inconsistent trace.
1838+
_g_.m.locks++
1839+
18341840
if _g_.m.mcache == nil {
18351841
throw("lost mcache")
18361842
}
@@ -1844,6 +1850,13 @@ func exitsyscall(dummy int32) {
18441850
_g_.syscallsp = 0
18451851
_g_.m.p.syscalltick++
18461852
_g_.throwsplit = false
1853+
1854+
if exitTicks != 0 {
1855+
systemstack(func() {
1856+
traceGoSysExit(exitTicks)
1857+
})
1858+
}
1859+
_g_.m.locks--
18471860
}
18481861

18491862
//go:nosplit
@@ -1871,7 +1884,7 @@ func exitsyscallfast() bool {
18711884
// Denote blocking of the new syscall.
18721885
traceGoSysBlock(_g_.m.p)
18731886
// Denote completion of the current syscall.
1874-
traceGoSysExit()
1887+
traceGoSysExit(0)
18751888
})
18761889
}
18771890
_g_.m.p.syscalltick++
@@ -1895,7 +1908,7 @@ func exitsyscallfast() bool {
18951908
osyield()
18961909
}
18971910
}
1898-
traceGoSysExit()
1911+
traceGoSysExit(0)
18991912
}
19001913
})
19011914
if ok {

src/runtime/trace.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const (
4545
traceEvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack]
4646
traceEvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack]
4747
traceEvGoSysCall = 28 // syscall enter [timestamp, stack]
48-
traceEvGoSysExit = 29 // syscall exit [timestamp, goroutine id]
48+
traceEvGoSysExit = 29 // syscall exit [timestamp, goroutine id, real timestamp]
4949
traceEvGoSysBlock = 30 // syscall blocks [timestamp]
5050
traceEvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
5151
traceEvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
@@ -797,8 +797,8 @@ func traceGoSysCall() {
797797
traceEvent(traceEvGoSysCall, 4)
798798
}
799799

800-
func traceGoSysExit() {
801-
traceEvent(traceEvGoSysExit, -1, uint64(getg().m.curg.goid))
800+
func traceGoSysExit(ts int64) {
801+
traceEvent(traceEvGoSysExit, -1, uint64(getg().m.curg.goid), uint64(ts)/traceTickDiv)
802802
}
803803

804804
func traceGoSysBlock(pp *p) {

0 commit comments

Comments
 (0)