From: Carlos Amedee Date: Tue, 7 May 2024 19:37:10 +0000 (-0400) Subject: internal/trace: remove remnanats of v1 tracer X-Git-Tag: go1.23rc1~290 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=664088b898330a2c73121c5a6f2d4dbec5b180d7;p=gostls13.git internal/trace: remove remnanats of v1 tracer This change removes unused parts of the v1 tracer in preperation of the move of the v2 tracer into the trace package. Updates #67367 Change-Id: I3e53a8afdef72dc90c2d5b514380d1077d284bc7 Reviewed-on: https://go-review.googlesource.com/c/go/+/584537 Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- diff --git a/src/internal/trace/gc.go b/src/internal/trace/gc.go index ca91969cfb..60c45f46aa 100644 --- a/src/internal/trace/gc.go +++ b/src/internal/trace/gc.go @@ -45,164 +45,6 @@ const ( UtilPerProc ) -// MutatorUtilization returns a set of mutator utilization functions -// for the given trace. Each function will always end with 0 -// utilization. The bounds of each function are implicit in the first -// and last event; outside of these bounds each function is undefined. -// -// If the UtilPerProc flag is not given, this always returns a single -// utilization function. Otherwise, it returns one function per P. -func MutatorUtilization(events []*Event, flags UtilFlags) [][]MutatorUtil { - if len(events) == 0 { - return nil - } - - type perP struct { - // gc > 0 indicates that GC is active on this P. - gc int - // series the logical series number for this P. This - // is necessary because Ps may be removed and then - // re-added, and then the new P needs a new series. - series int - } - ps := []perP{} - stw := 0 - - out := [][]MutatorUtil{} - assists := map[uint64]bool{} - block := map[uint64]*Event{} - bgMark := map[uint64]bool{} - - for _, ev := range events { - switch ev.Type { - case EvGomaxprocs: - gomaxprocs := int(ev.Args[0]) - if len(ps) > gomaxprocs { - if flags&UtilPerProc != 0 { - // End each P's series. - for _, p := range ps[gomaxprocs:] { - out[p.series] = addUtil(out[p.series], MutatorUtil{ev.Ts, 0}) - } - } - ps = ps[:gomaxprocs] - } - for len(ps) < gomaxprocs { - // Start new P's series. - series := 0 - if flags&UtilPerProc != 0 || len(out) == 0 { - series = len(out) - out = append(out, []MutatorUtil{{ev.Ts, 1}}) - } - ps = append(ps, perP{series: series}) - } - case EvSTWStart: - if flags&UtilSTW != 0 { - stw++ - } - case EvSTWDone: - if flags&UtilSTW != 0 { - stw-- - } - case EvGCMarkAssistStart: - if flags&UtilAssist != 0 { - ps[ev.P].gc++ - assists[ev.G] = true - } - case EvGCMarkAssistDone: - if flags&UtilAssist != 0 { - ps[ev.P].gc-- - delete(assists, ev.G) - } - case EvGCSweepStart: - if flags&UtilSweep != 0 { - ps[ev.P].gc++ - } - case EvGCSweepDone: - if flags&UtilSweep != 0 { - ps[ev.P].gc-- - } - case EvGoStartLabel: - if flags&UtilBackground != 0 && strings.HasPrefix(ev.SArgs[0], "GC ") && ev.SArgs[0] != "GC (idle)" { - // Background mark worker. - // - // If we're in per-proc mode, we don't - // count dedicated workers because - // they kick all of the goroutines off - // that P, so don't directly - // contribute to goroutine latency. - if !(flags&UtilPerProc != 0 && ev.SArgs[0] == "GC (dedicated)") { - bgMark[ev.G] = true - ps[ev.P].gc++ - } - } - fallthrough - case EvGoStart: - if assists[ev.G] { - // Unblocked during assist. - ps[ev.P].gc++ - } - block[ev.G] = ev.Link - default: - if ev != block[ev.G] { - continue - } - - if assists[ev.G] { - // Blocked during assist. - ps[ev.P].gc-- - } - if bgMark[ev.G] { - // Background mark worker done. - ps[ev.P].gc-- - delete(bgMark, ev.G) - } - delete(block, ev.G) - } - - if flags&UtilPerProc == 0 { - // Compute the current average utilization. - if len(ps) == 0 { - continue - } - gcPs := 0 - if stw > 0 { - gcPs = len(ps) - } else { - for i := range ps { - if ps[i].gc > 0 { - gcPs++ - } - } - } - mu := MutatorUtil{ev.Ts, 1 - float64(gcPs)/float64(len(ps))} - - // Record the utilization change. (Since - // len(ps) == len(out), we know len(out) > 0.) - out[0] = addUtil(out[0], mu) - } else { - // Check for per-P utilization changes. - for i := range ps { - p := &ps[i] - util := 1.0 - if stw > 0 || p.gc > 0 { - util = 0.0 - } - out[p.series] = addUtil(out[p.series], MutatorUtil{ev.Ts, util}) - } - } - } - - // Add final 0 utilization event to any remaining series. This - // is important to mark the end of the trace. The exact value - // shouldn't matter since no window should extend beyond this, - // but using 0 is symmetric with the start of the trace. - mu := MutatorUtil{events[len(events)-1].Ts, 0} - for i := range ps { - out[ps[i].series] = addUtil(out[ps[i].series], mu) - } - return out -} - // MutatorUtilizationV2 returns a set of mutator utilization functions // for the given v2 trace, passed as an io.Reader. Each function will // always end with 0 utilization. The bounds of each function are implicit diff --git a/src/internal/trace/gc_test.go b/src/internal/trace/gc_test.go index 8c9f77f57a..a74d59d8b7 100644 --- a/src/internal/trace/gc_test.go +++ b/src/internal/trace/gc_test.go @@ -5,12 +5,10 @@ package trace import ( - "bytes" tracev2 "internal/trace/v2" "internal/trace/v2/testtrace" "io" "math" - "os" "testing" "time" ) @@ -118,17 +116,6 @@ func TestMMUTrace(t *testing.T) { } } } - t.Run("V1", func(t *testing.T) { - data, err := os.ReadFile("testdata/stress_1_10_good") - if err != nil { - t.Fatalf("failed to read input file: %v", err) - } - events, err := Parse(bytes.NewReader(data), "") - if err != nil { - t.Fatalf("failed to parse trace: %s", err) - } - check(t, MutatorUtilization(events.Events, UtilSTW|UtilBackground|UtilAssist)) - }) t.Run("V2", func(t *testing.T) { testPath := "v2/testdata/tests/go122-gc-stress.test" r, _, err := testtrace.ParseFile(testPath) @@ -155,30 +142,6 @@ func TestMMUTrace(t *testing.T) { }) } -func BenchmarkMMU(b *testing.B) { - data, err := os.ReadFile("testdata/stress_1_10_good") - if err != nil { - b.Fatalf("failed to read input file: %v", err) - } - events, err := Parse(bytes.NewReader(data), "") - if err != nil { - b.Fatalf("failed to parse trace: %s", err) - } - mu := MutatorUtilization(events.Events, UtilSTW|UtilBackground|UtilAssist|UtilSweep) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - mmuCurve := NewMMUCurve(mu) - xMin, xMax := time.Microsecond, time.Second - logMin, logMax := math.Log(float64(xMin)), math.Log(float64(xMax)) - const samples = 100 - for i := 0; i < samples; i++ { - window := time.Duration(math.Exp(float64(i)/(samples-1)*(logMax-logMin) + logMin)) - mmuCurve.MMU(window) - } - } -} - func mmuSlow(util []MutatorUtil, window time.Duration) (mmu float64) { if max := time.Duration(util[len(util)-1].Time - util[0].Time); window > max { window = max diff --git a/src/internal/trace/goroutines.go b/src/internal/trace/goroutines.go deleted file mode 100644 index 4b4f13d2ae..0000000000 --- a/src/internal/trace/goroutines.go +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package trace - -import ( - "sort" - "strings" -) - -// GDesc contains statistics and execution details of a single goroutine. -type GDesc struct { - ID uint64 - Name string - PC uint64 - CreationTime int64 - StartTime int64 - EndTime int64 - - // List of regions in the goroutine, sorted based on the start time. - Regions []*UserRegionDesc - - // Statistics of execution time during the goroutine execution. - GExecutionStat - - *gdesc // private part. -} - -// UserRegionDesc represents a region and goroutine execution stats -// while the region was active. -type UserRegionDesc struct { - TaskID uint64 - Name string - - // Region start event. Normally EvUserRegion start event or nil, - // but can be EvGoCreate event if the region is a synthetic - // region representing task inheritance from the parent goroutine. - Start *Event - - // Region end event. Normally EvUserRegion end event or nil, - // but can be EvGoStop or EvGoEnd event if the goroutine - // terminated without explicitly ending the region. - End *Event - - GExecutionStat -} - -// GExecutionStat contains statistics about a goroutine's execution -// during a period of time. -type GExecutionStat struct { - ExecTime int64 - SchedWaitTime int64 - IOTime int64 - BlockTime int64 - SyscallTime int64 - GCTime int64 - SweepTime int64 - TotalTime int64 -} - -// sub returns the stats v-s. -func (s GExecutionStat) sub(v GExecutionStat) (r GExecutionStat) { - r = s - r.ExecTime -= v.ExecTime - r.SchedWaitTime -= v.SchedWaitTime - r.IOTime -= v.IOTime - r.BlockTime -= v.BlockTime - r.SyscallTime -= v.SyscallTime - r.GCTime -= v.GCTime - r.SweepTime -= v.SweepTime - r.TotalTime -= v.TotalTime - return r -} - -// snapshotStat returns the snapshot of the goroutine execution statistics. -// This is called as we process the ordered trace event stream. lastTs and -// activeGCStartTime are used to process pending statistics if this is called -// before any goroutine end event. -func (g *GDesc) snapshotStat(lastTs, activeGCStartTime int64) (ret GExecutionStat) { - ret = g.GExecutionStat - - if g.gdesc == nil { - return ret // finalized GDesc. No pending state. - } - - if activeGCStartTime != 0 { // terminating while GC is active - if g.CreationTime < activeGCStartTime { - ret.GCTime += lastTs - activeGCStartTime - } else { - // The goroutine's lifetime completely overlaps - // with a GC. - ret.GCTime += lastTs - g.CreationTime - } - } - - if g.TotalTime == 0 { - ret.TotalTime = lastTs - g.CreationTime - } - - if g.lastStartTime != 0 { - ret.ExecTime += lastTs - g.lastStartTime - } - if g.blockNetTime != 0 { - ret.IOTime += lastTs - g.blockNetTime - } - if g.blockSyncTime != 0 { - ret.BlockTime += lastTs - g.blockSyncTime - } - if g.blockSyscallTime != 0 { - ret.SyscallTime += lastTs - g.blockSyscallTime - } - if g.blockSchedTime != 0 { - ret.SchedWaitTime += lastTs - g.blockSchedTime - } - if g.blockSweepTime != 0 { - ret.SweepTime += lastTs - g.blockSweepTime - } - return ret -} - -// finalize is called when processing a goroutine end event or at -// the end of trace processing. This finalizes the execution stat -// and any active regions in the goroutine, in which case trigger is nil. -func (g *GDesc) finalize(lastTs, activeGCStartTime int64, trigger *Event) { - if trigger != nil { - g.EndTime = trigger.Ts - } - finalStat := g.snapshotStat(lastTs, activeGCStartTime) - - g.GExecutionStat = finalStat - - // System goroutines are never part of regions, even though they - // "inherit" a task due to creation (EvGoCreate) from within a region. - // This may happen e.g. if the first GC is triggered within a region, - // starting the GC worker goroutines. - if !IsSystemGoroutine(g.Name) { - for _, s := range g.activeRegions { - s.End = trigger - s.GExecutionStat = finalStat.sub(s.GExecutionStat) - g.Regions = append(g.Regions, s) - } - } - *(g.gdesc) = gdesc{} -} - -// gdesc is a private part of GDesc that is required only during analysis. -type gdesc struct { - lastStartTime int64 - blockNetTime int64 - blockSyncTime int64 - blockSyscallTime int64 - blockSweepTime int64 - blockGCTime int64 - blockSchedTime int64 - - activeRegions []*UserRegionDesc // stack of active regions -} - -// GoroutineStats generates statistics for all goroutines in the trace. -func GoroutineStats(events []*Event) map[uint64]*GDesc { - gs := make(map[uint64]*GDesc) - var lastTs int64 - var gcStartTime int64 // gcStartTime == 0 indicates gc is inactive. - for _, ev := range events { - lastTs = ev.Ts - switch ev.Type { - case EvGoCreate: - g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)} - g.blockSchedTime = ev.Ts - // When a goroutine is newly created, inherit the task - // of the active region. For ease handling of this - // case, we create a fake region description with the - // task id. This isn't strictly necessary as this - // goroutine may not be associated with the task, but - // it can be convenient to see all children created - // during a region. - if creatorG := gs[ev.G]; creatorG != nil && len(creatorG.gdesc.activeRegions) > 0 { - regions := creatorG.gdesc.activeRegions - s := regions[len(regions)-1] - if s.TaskID != 0 { - g.gdesc.activeRegions = []*UserRegionDesc{ - {TaskID: s.TaskID, Start: ev}, - } - } - } - gs[g.ID] = g - case EvGoStart, EvGoStartLabel: - g := gs[ev.G] - if g.PC == 0 && len(ev.Stk) > 0 { - g.PC = ev.Stk[0].PC - g.Name = ev.Stk[0].Fn - } - g.lastStartTime = ev.Ts - if g.StartTime == 0 { - g.StartTime = ev.Ts - } - if g.blockSchedTime != 0 { - g.SchedWaitTime += ev.Ts - g.blockSchedTime - g.blockSchedTime = 0 - } - case EvGoEnd, EvGoStop: - g := gs[ev.G] - g.finalize(ev.Ts, gcStartTime, ev) - case EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect, - EvGoBlockSync, EvGoBlockCond: - g := gs[ev.G] - g.ExecTime += ev.Ts - g.lastStartTime - g.lastStartTime = 0 - g.blockSyncTime = ev.Ts - case EvGoSched, EvGoPreempt: - g := gs[ev.G] - g.ExecTime += ev.Ts - g.lastStartTime - g.lastStartTime = 0 - g.blockSchedTime = ev.Ts - case EvGoSleep, EvGoBlock: - g := gs[ev.G] - g.ExecTime += ev.Ts - g.lastStartTime - g.lastStartTime = 0 - case EvGoBlockNet: - g := gs[ev.G] - g.ExecTime += ev.Ts - g.lastStartTime - g.lastStartTime = 0 - g.blockNetTime = ev.Ts - case EvGoBlockGC: - g := gs[ev.G] - g.ExecTime += ev.Ts - g.lastStartTime - g.lastStartTime = 0 - g.blockGCTime = ev.Ts - case EvGoUnblock: - g := gs[ev.Args[0]] - if g.blockNetTime != 0 { - g.IOTime += ev.Ts - g.blockNetTime - g.blockNetTime = 0 - } - if g.blockSyncTime != 0 { - g.BlockTime += ev.Ts - g.blockSyncTime - g.blockSyncTime = 0 - } - g.blockSchedTime = ev.Ts - case EvGoSysBlock: - g := gs[ev.G] - g.ExecTime += ev.Ts - g.lastStartTime - g.lastStartTime = 0 - g.blockSyscallTime = ev.Ts - case EvGoSysExit: - g := gs[ev.G] - if g.blockSyscallTime != 0 { - g.SyscallTime += ev.Ts - g.blockSyscallTime - g.blockSyscallTime = 0 - } - g.blockSchedTime = ev.Ts - case EvGCSweepStart: - g := gs[ev.G] - if g != nil { - // Sweep can happen during GC on system goroutine. - g.blockSweepTime = ev.Ts - } - case EvGCSweepDone: - g := gs[ev.G] - if g != nil && g.blockSweepTime != 0 { - g.SweepTime += ev.Ts - g.blockSweepTime - g.blockSweepTime = 0 - } - case EvGCStart: - gcStartTime = ev.Ts - case EvGCDone: - for _, g := range gs { - if g.EndTime != 0 { - continue - } - if gcStartTime < g.CreationTime { - g.GCTime += ev.Ts - g.CreationTime - } else { - g.GCTime += ev.Ts - gcStartTime - } - } - gcStartTime = 0 // indicates gc is inactive. - case EvUserRegion: - g := gs[ev.G] - switch mode := ev.Args[1]; mode { - case 0: // region start - g.activeRegions = append(g.activeRegions, &UserRegionDesc{ - Name: ev.SArgs[0], - TaskID: ev.Args[0], - Start: ev, - GExecutionStat: g.snapshotStat(lastTs, gcStartTime), - }) - case 1: // region end - var sd *UserRegionDesc - if regionStk := g.activeRegions; len(regionStk) > 0 { - n := len(regionStk) - sd = regionStk[n-1] - regionStk = regionStk[:n-1] // pop - g.activeRegions = regionStk - } else { - sd = &UserRegionDesc{ - Name: ev.SArgs[0], - TaskID: ev.Args[0], - } - } - sd.GExecutionStat = g.snapshotStat(lastTs, gcStartTime).sub(sd.GExecutionStat) - sd.End = ev - g.Regions = append(g.Regions, sd) - } - } - } - - for _, g := range gs { - g.finalize(lastTs, gcStartTime, nil) - - // sort based on region start time - sort.Slice(g.Regions, func(i, j int) bool { - x := g.Regions[i].Start - y := g.Regions[j].Start - if x == nil { - return true - } - if y == nil { - return false - } - return x.Ts < y.Ts - }) - - g.gdesc = nil - } - - return gs -} - -// RelatedGoroutines finds a set of goroutines related to goroutine goid. -func RelatedGoroutines(events []*Event, goid uint64) map[uint64]bool { - // BFS of depth 2 over "unblock" edges - // (what goroutines unblock goroutine goid?). - gmap := make(map[uint64]bool) - gmap[goid] = true - for i := 0; i < 2; i++ { - gmap1 := make(map[uint64]bool) - for g := range gmap { - gmap1[g] = true - } - for _, ev := range events { - if ev.Type == EvGoUnblock && gmap[ev.Args[0]] { - gmap1[ev.G] = true - } - } - gmap = gmap1 - } - gmap[0] = true // for GC events - return gmap -} - -func IsSystemGoroutine(entryFn string) bool { - // This mimics runtime.isSystemGoroutine as closely as - // possible. - // Also, locked g in extra M (with empty entryFn) is system goroutine. - return entryFn == "" || entryFn != "runtime.main" && strings.HasPrefix(entryFn, "runtime.") -} diff --git a/src/internal/trace/mkcanned.bash b/src/internal/trace/mkcanned.bash deleted file mode 100755 index 879cf1c500..0000000000 --- a/src/internal/trace/mkcanned.bash +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2016 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# mkcanned.bash creates canned traces for the trace test suite using -# the current Go version. - -set -e - -if [ $# != 1 ]; then - echo "usage: $0