SArgs []string // event-type-specific string args
// linked event (can be nil), depends on event type:
// for GCStart: the GCStop
- // for GCScanStart: the GCScanDone
+ // for GCSTWStart: the GCSTWDone
// for GCSweepStart: the GCSweepDone
// for GoCreate: first GoStart of the created goroutine
// for GoStart/GoStartLabel: the associated GoEnd, GoBlock or other blocking event
return
}
switch ver {
- case 1005, 1007, 1008, 1009:
+ case 1005, 1007, 1008, 1009, 1010:
// Note: When adding a new version, add canned traces
// from the old version to the test suite using mkcanned.bash.
break
if raw.typ == EvGoStartLabel {
e.SArgs = []string{strings[e.Args[2]]}
}
- case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone:
+ case EvGCSTWStart:
+ e.G = 0
+ switch e.Args[0] {
+ case 0:
+ e.SArgs = []string{"mark termination"}
+ case 1:
+ e.SArgs = []string{"sweep termination"}
+ default:
+ err = fmt.Errorf("unknown STW kind %d", e.Args[0])
+ return
+ }
+ case EvGCStart, EvGCDone, EvGCSTWDone:
e.G = 0
case EvGoEnd, EvGoStop, EvGoSched, EvGoPreempt,
EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
type pdesc struct {
running bool
g uint64
- evScan *Event
+ evSTW *Event
evSweep *Event
}
gs := make(map[uint64]gdesc)
ps := make(map[int]pdesc)
gs[0] = gdesc{state: gRunning}
- var evGC *Event
+ var evGC, evSTW *Event
checkRunning := func(p pdesc, g gdesc, ev *Event, allowG0 bool) error {
name := EventDescriptions[ev.Type].Name
}
evGC.Link = ev
evGC = nil
- case EvGCScanStart:
- if p.evScan != nil {
- return fmt.Errorf("previous scanning is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
- }
- p.evScan = ev
- case EvGCScanDone:
- if p.evScan == nil {
- return fmt.Errorf("bogus scanning end (offset %v, time %v)", ev.Off, ev.Ts)
- }
- p.evScan.Link = ev
- p.evScan = nil
+ case EvGCSTWStart:
+ evp := &evSTW
+ if ver < 1010 {
+ // Before 1.10, EvGCSTWStart was per-P.
+ evp = &p.evSTW
+ }
+ if *evp != nil {
+ return fmt.Errorf("previous STW is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
+ }
+ *evp = ev
+ case EvGCSTWDone:
+ evp := &evSTW
+ if ver < 1010 {
+ // Before 1.10, EvGCSTWDone was per-P.
+ evp = &p.evSTW
+ }
+ if *evp == nil {
+ return fmt.Errorf("bogus STW end (offset %v, time %v)", ev.Off, ev.Ts)
+ }
+ (*evp).Link = ev
+ *evp = nil
case EvGCSweepStart:
if p.evSweep != nil {
return fmt.Errorf("previous sweeping is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
if ver < 1007 {
narg-- // 1.7 added an additional seq arg
}
+ case EvGCSTWStart:
+ if ver < 1010 {
+ narg-- // 1.10 added an argument
+ }
}
return narg
}
EvProcStop = 6 // stop of P [timestamp]
EvGCStart = 7 // GC start [timestamp, seq, stack id]
EvGCDone = 8 // GC done [timestamp]
- EvGCScanStart = 9 // GC mark termination start [timestamp]
- EvGCScanDone = 10 // GC mark termination done [timestamp]
+ EvGCSTWStart = 9 // GC mark termination start [timestamp, kind]
+ EvGCSTWDone = 10 // GC mark termination done [timestamp]
EvGCSweepStart = 11 // GC sweep start [timestamp, stack id]
EvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed]
EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
EvProcStop: {"ProcStop", 1005, false, []string{}},
EvGCStart: {"GCStart", 1005, true, []string{"seq"}}, // in 1.5 format it was {}
EvGCDone: {"GCDone", 1005, false, []string{}},
- EvGCScanStart: {"GCScanStart", 1005, false, []string{}},
- EvGCScanDone: {"GCScanDone", 1005, false, []string{}},
+ EvGCSTWStart: {"GCSTWStart", 1005, false, []string{"kind"}}, // <= 1.9, args was {} (implicitly {0})
+ EvGCSTWDone: {"GCSTWDone", 1005, false, []string{}},
EvGCSweepStart: {"GCSweepStart", 1005, true, []string{}},
EvGCSweepDone: {"GCSweepDone", 1005, false, []string{"swept", "reclaimed"}}, // before 1.9, format was {}
EvGoCreate: {"GoCreate", 1005, true, []string{"g", "stack"}},
now := nanotime()
work.tSweepTerm = now
work.pauseStart = now
+ if trace.enabled {
+ traceGCSTWStart(1)
+ }
systemstack(stopTheWorldWithSema)
// Finish sweep before we start concurrent scan.
systemstack(func() {
// Concurrent mark.
systemstack(func() {
- now = startTheWorldWithSema()
+ now = startTheWorldWithSema(trace.enabled)
})
work.pauseNS += now - work.pauseStart
work.tMark = now
} else {
+ if trace.enabled {
+ // Switch to mark termination STW.
+ traceGCSTWDone()
+ traceGCSTWStart(0)
+ }
t := nanotime()
work.tMark, work.tMarkTerm = t, t
work.heapGoal = work.heap0
work.tMarkTerm = now
work.pauseStart = now
getg().m.preemptoff = "gcing"
+ if trace.enabled {
+ traceGCSTWStart(0)
+ }
systemstack(stopTheWorldWithSema)
// The gcphase is _GCmark, it will transition to _GCmarktermination
// below. The important thing is that the wb remains active until
// so events don't leak into the wrong cycle.
mProf_NextCycle()
- systemstack(func() { startTheWorldWithSema() })
+ systemstack(func() { startTheWorldWithSema(true) })
// Flush the heap profile so we can start a new cycle next GC.
// This is relatively expensive, so we don't do it with the
work.helperDrainBlock = true
}
- if trace.enabled {
- traceGCScanStart()
- }
-
if work.nproc > 1 {
noteclear(&work.alldone)
helpgc(int32(work.nproc))
}
}
- if trace.enabled {
- traceGCScanDone()
- }
-
cachestats()
// Update the marked heap stat.
_g_.m.traceback = 2
gchelperstart()
- if trace.enabled {
- traceGCScanStart()
- }
-
// Parallel mark over GC roots and heap
if gcphase == _GCmarktermination {
gcw := &_g_.m.p.ptr().gcw
gcw.dispose()
}
- if trace.enabled {
- traceGCScanDone()
- }
-
nproc := atomic.Load(&work.nproc) // work.nproc can change right after we increment work.ndone
if atomic.Xadd(&work.ndone, +1) == nproc-1 {
notewakeup(&work.alldone)
traceEvProcStop = 6 // stop of P [timestamp]
traceEvGCStart = 7 // GC start [timestamp, seq, stack id]
traceEvGCDone = 8 // GC done [timestamp]
- traceEvGCScanStart = 9 // GC mark termination start [timestamp]
- traceEvGCScanDone = 10 // GC mark termination done [timestamp]
+ traceEvGCSTWStart = 9 // GC STW start [timestamp, kind]
+ traceEvGCSTWDone = 10 // GC STW done [timestamp]
traceEvGCSweepStart = 11 // GC sweep start [timestamp, stack id]
traceEvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed]
traceEvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
trace.headerWritten = true
trace.lockOwner = nil
unlock(&trace.lock)
- return []byte("go 1.9 trace\x00\x00\x00\x00")
+ return []byte("go 1.10 trace\x00\x00\x00")
}
// Wait for new data.
if trace.fullHead == 0 && !trace.shutdown {
traceEvent(traceEvGCDone, -1)
}
-func traceGCScanStart() {
- traceEvent(traceEvGCScanStart, -1)
+func traceGCSTWStart(kind int) {
+ traceEvent(traceEvGCSTWStart, -1, uint64(kind))
}
-func traceGCScanDone() {
- traceEvent(traceEvGCScanDone, -1)
+func traceGCSTWDone() {
+ traceEvent(traceEvGCSTWDone, -1)
}
// traceGCSweepStart prepares to trace a sweep loop. This does not