Source file src/runtime/tracetype.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Trace stack table and acquisition.
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/abi"
    11  	"internal/goarch"
    12  	"unsafe"
    13  )
    14  
    15  // traceTypeTable maps stack traces (arrays of PC's) to unique uint32 ids.
    16  // It is lock-free for reading.
    17  type traceTypeTable struct {
    18  	tab traceMap
    19  }
    20  
    21  // put returns a unique id for the type typ and caches it in the table,
    22  // if it's seeing it for the first time.
    23  //
    24  // N.B. typ must be kept alive forever for this to work correctly.
    25  func (t *traceTypeTable) put(typ *abi.Type) uint64 {
    26  	if typ == nil {
    27  		return 0
    28  	}
    29  	// Insert the pointer to the type itself.
    30  	id, _ := t.tab.put(noescape(unsafe.Pointer(&typ)), goarch.PtrSize)
    31  	return id
    32  }
    33  
    34  // dump writes all previously cached types to trace buffers and
    35  // releases all memory and resets state. It must only be called once the caller
    36  // can guarantee that there are no more writers to the table.
    37  func (t *traceTypeTable) dump(gen uintptr) {
    38  	w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree)
    39  	if root := (*traceMapNode)(t.tab.root.Load()); root != nil {
    40  		w = dumpTypesRec(root, w)
    41  	}
    42  	w.flush().end()
    43  	t.tab.reset()
    44  }
    45  
    46  func dumpTypesRec(node *traceMapNode, w traceExpWriter) traceExpWriter {
    47  	typ := (*abi.Type)(*(*unsafe.Pointer)(unsafe.Pointer(&node.data[0])))
    48  	typName := toRType(typ).string()
    49  
    50  	// The maximum number of bytes required to hold the encoded type.
    51  	maxBytes := 1 + 5*traceBytesPerNumber + len(typName)
    52  
    53  	// Estimate the size of this record. This
    54  	// bound is pretty loose, but avoids counting
    55  	// lots of varint sizes.
    56  	//
    57  	// Add 1 because we might also write a traceAllocFreeTypesBatch byte.
    58  	var flushed bool
    59  	w, flushed = w.ensure(1 + maxBytes)
    60  	if flushed {
    61  		// Annotate the batch as containing types.
    62  		w.byte(byte(traceAllocFreeTypesBatch))
    63  	}
    64  
    65  	// Emit type.
    66  	w.varint(uint64(node.id))
    67  	w.varint(uint64(uintptr(unsafe.Pointer(typ))))
    68  	w.varint(uint64(typ.Size()))
    69  	w.varint(uint64(typ.PtrBytes))
    70  	w.varint(uint64(len(typName)))
    71  	w.stringData(typName)
    72  
    73  	// Recursively walk all child nodes.
    74  	for i := range node.children {
    75  		child := node.children[i].Load()
    76  		if child == nil {
    77  			continue
    78  		}
    79  		w = dumpTypesRec((*traceMapNode)(child), w)
    80  	}
    81  	return w
    82  }
    83  

View as plain text