// Copyright 2023 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.// This file contains data types that all implementations of the trace format// parser need to provide to the rest of the package.package traceimport ()// maxArgs is the maximum number of arguments for "plain" events,// i.e. anything that could reasonably be represented as a baseEvent.//// TODO(mknyszek): This is only 6 instead of 5 because GoStatusStack// has 5 arguments and needs to smuggle in a 6th. Figure out a way to// shrink this in the future.const maxArgs = 6// timedEventArgs is an array that is able to hold the arguments for any// timed event.type timedEventArgs [maxArgs - 1]uint64// baseEvent is the basic unprocessed event. This serves as a common// fundamental data structure across.type baseEvent struct { typ event.Type time Time args timedEventArgs}// extra returns a slice representing extra available space in args// that the parser can use to pass data up into Event.func ( *baseEvent) ( version.Version) []uint64 {switch {caseversion.Go122:return .args[len(go122.Specs()[.typ].Args)-1:] }panic(fmt.Sprintf("unsupported version: go 1.%d", ))}// evTable contains the per-generation data necessary to// interpret an individual event.type evTable struct { freq frequency strings dataTable[stringID, string] stacks dataTable[stackID, stack] pcs map[uint64]frame// extraStrings are strings that get generated during // parsing but haven't come directly from the trace, so // they don't appear in strings. extraStrings []string extraStringIDs map[string]extraStringID nextExtra extraStringID// expData contains extra unparsed data that is accessible // only to ExperimentEvent via an EventExperimental event. expData map[event.Experiment]*ExperimentalData}// addExtraString adds an extra string to the evTable and returns// a unique ID for the string in the table.func ( *evTable) ( string) extraStringID {if == "" {return0 }if .extraStringIDs == nil { .extraStringIDs = make(map[string]extraStringID) }if , := .extraStringIDs[]; {return } .nextExtra++ := .nextExtra .extraStrings = append(.extraStrings, ) .extraStringIDs[] = return}// getExtraString returns the extra string for the provided ID.// The ID must have been produced by addExtraString for this evTable.func ( *evTable) ( extraStringID) string {if == 0 {return"" }return .extraStrings[-1]}// dataTable is a mapping from EIs to Es.type dataTable[ ~uint64, any] struct { present []uint8 dense [] sparse map[]}// insert tries to add a mapping from id to s.//// Returns an error if a mapping for id already exists, regardless// of whether or not s is the same in content. This should be used// for validation during parsing.func ( *dataTable[, ]) ( , ) error {if .sparse == nil { .sparse = make(map[]) }if , := .get(); {returnfmt.Errorf("multiple %Ts with the same ID: id=%d, new=%v, existing=%v", , , , ) } .sparse[] = returnnil}// compactify attempts to compact sparse into dense.//// This is intended to be called only once after insertions are done.func ( *dataTable[, ]) () {if .sparse == nil || len(.dense) != 0 {// Already compactified.return }// Find the range of IDs. := (0) := ^(0)for := range .sparse {if > { = }if < { = } }if >= math.MaxInt {// We can't create a slice big enough to hold maxID elementsreturn }// We're willing to waste at most 2x memory.ifint(-) > max(len(.sparse), 2*len(.sparse)) {return }ifint() > len(.sparse) {return } := int() + 1 .present = make([]uint8, (+7)/8) .dense = make([], )for , := range .sparse { .dense[] = .present[/8] |= uint8(1) << ( % 8) } .sparse = nil}// get returns the E for id or false if it doesn't// exist. This should be used for validation during parsing.func ( *dataTable[, ]) ( ) (, bool) {if == 0 {return *new(), true }ifuint64() < uint64(len(.dense)) {if .present[/8]&(uint8(1)<<(%8)) != 0 {return .dense[], true } } elseif .sparse != nil {if , := .sparse[]; {return , true } }return *new(), false}// forEach iterates over all ID/value pairs in the data table.func ( *dataTable[, ]) ( func(, ) bool) bool {for , := range .dense {if .present[/8]&(uint8(1)<<(%8)) == 0 {continue }if !((), ) {returnfalse } }if .sparse == nil {returntrue }for , := range .sparse {if !(, ) {returnfalse } }returntrue}// mustGet returns the E for id or panics if it fails.//// This should only be used if id has already been validated.func ( *dataTable[, ]) ( ) { , := .get()if ! {panic(fmt.Sprintf("expected id %d in %T table", , )) }return}// frequency is nanoseconds per timestamp unit.type frequency float64// mul multiplies an unprocessed to produce a time in nanoseconds.func ( frequency) ( timestamp) Time {returnTime(float64() * float64())}// stringID is an index into the string table for a generation.type stringID uint64// extraStringID is an index into the extra string table for a generation.type extraStringID uint64// stackID is an index into the stack table for a generation.type stackID uint64// cpuSample represents a CPU profiling sample captured by the trace.type cpuSample struct {schedCtx time Time stack stackID}// asEvent produces a complete Event from a cpuSample. It needs// the evTable from the generation that created it.//// We don't just store it as an Event in generation to minimize// the amount of pointer data floating around.func ( cpuSample) ( *evTable) Event {// TODO(mknyszek): This is go122-specific, but shouldn't be. // Generalize this in the future. := Event{table: ,ctx: .schedCtx,base: baseEvent{typ: go122.EvCPUSample,time: .time, }, } .base.args[0] = uint64(.stack)return}// stack represents a goroutine stack sample.type stack struct { pcs []uint64}func ( stack) () string {varstrings.Builderfor , := range .pcs {fmt.Fprintf(&, "\t%#v\n", ) }return .String()}// frame represents a single stack frame.type frame struct { pc uint64 funcID stringID fileID stringID line uint64}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.