]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: write out a batch with alignment info for traceallocfree
authorMichael Anthony Knyszek <mknyszek@google.com>
Mon, 20 May 2024 20:31:36 +0000 (20:31 +0000)
committerGopher Robot <gobot@golang.org>
Wed, 22 May 2024 20:31:27 +0000 (20:31 +0000)
Currently the traceallocfree experiment is missing info in the trace for
interpeting the produced events. Most notably, the base heap address is
missing. While not technically necessary, it is useful for getting an
accurate picture of the program's memory layout, and will be useful for
future trace experiments. Since we want to emit a batch for this, we
should also emit a batch for all the alignment info that's used to
compress the addresses (IDs) produced for the alloc/free events.

This CL distinguishes the different formats of the experimental batches
(note that there's already batches containing type information in this
experiment) by putting a byte at the beginning of each experimental
batch indicating its format.

Change-Id: Ifc4e77a23458713b7d95e0dfa056a29e1629ccd7
Reviewed-on: https://go-review.googlesource.com/c/go/+/586997
Auto-Submit: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/runtime/mksizeclasses.go
src/runtime/sizeclasses.go
src/runtime/trace.go
src/runtime/traceallocfree.go
src/runtime/tracetype.go

index 26ca49e6eb13d6985722e05344003227e99bffd0..bb06ba1eddc32caa9c6f77343c2ce9f07a03e542 100644 (file)
@@ -75,6 +75,7 @@ func main() {
 
 const (
        // Constants that we use and will transfer to the runtime.
+       minHeapAlign = 8
        maxSmallSize = 32 << 10
        smallSizeDiv = 8
        smallSizeMax = 1024
@@ -99,7 +100,7 @@ func makeClasses() []class {
 
        classes = append(classes, class{}) // class #0 is a dummy entry
 
-       align := 8
+       align := minHeapAlign
        for size := align; size <= maxSmallSize; size += align {
                if powerOfTwo(size) { // bump alignment once in a while
                        if size >= 2048 {
@@ -288,6 +289,7 @@ func maxObjsPerSpan(classes []class) int {
 
 func printClasses(w io.Writer, classes []class) {
        fmt.Fprintln(w, "const (")
+       fmt.Fprintf(w, "minHeapAlign = %d\n", minHeapAlign)
        fmt.Fprintf(w, "_MaxSmallSize = %d\n", maxSmallSize)
        fmt.Fprintf(w, "smallSizeDiv = %d\n", smallSizeDiv)
        fmt.Fprintf(w, "smallSizeMax = %d\n", smallSizeMax)
index 9314623453116a4115a1965a1637a8e2966cc0bf..bbcaa9e983fd042daafdb97d2a139fc8afe06e9b 100644 (file)
@@ -82,6 +82,7 @@ package runtime
 //      8192    13         32768
 
 const (
+       minHeapAlign    = 8
        _MaxSmallSize   = 32768
        smallSizeDiv    = 8
        smallSizeMax    = 1024
index 49ac3e2d45d2a8e8cae311eee068a5f0b0d44720..e893525bd08fff6aab23e6f880a6ac2f8e5f6d59 100644 (file)
@@ -290,7 +290,7 @@ func StartTrace() error {
 
        // Dump a snapshot of memory, if enabled.
        if trace.enabledWithAllocFree {
-               traceSnapshotMemory()
+               traceSnapshotMemory(firstGen)
        }
 
        // Record the heap goal so we have it at the very beginning of the trace.
index 3067e1667025b96f85edf7b3cec67a010d3f8d76..67c6f40926ff1ee6a12a6b28f1ef8882f91bec06 100644 (file)
@@ -11,13 +11,38 @@ import (
        "runtime/internal/sys"
 )
 
+// Batch type values for the alloc/free experiment.
+const (
+       traceAllocFreeTypesBatch = iota // Contains types. [{id, address, size, ptrspan, name length, name string} ...]
+       traceAllocFreeInfoBatch         // Contains info for interpreting events. [min heap addr, page size, min heap align, min stack align]
+)
+
 // traceSnapshotMemory takes a snapshot of all runtime memory that there are events for
 // (heap spans, heap objects, goroutine stacks, etc.) and writes out events for them.
 //
 // The world must be stopped and tracing must be enabled when this function is called.
-func traceSnapshotMemory() {
+func traceSnapshotMemory(gen uintptr) {
        assertWorldStopped()
 
+       // Write a batch containing information that'll be necessary to
+       // interpret the events.
+       var flushed bool
+       w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree)
+       w, flushed = w.ensure(1 + 4*traceBytesPerNumber)
+       if flushed {
+               // Annotate the batch as containing additional info.
+               w.byte(byte(traceAllocFreeInfoBatch))
+       }
+
+       // Emit info.
+       w.varint(uint64(trace.minPageHeapAddr))
+       w.varint(uint64(pageSize))
+       w.varint(uint64(minHeapAlign))
+       w.varint(uint64(fixedStack))
+
+       // Finish writing the batch.
+       w.flush().end()
+
        // Start tracing.
        trace := traceAcquire()
        if !trace.ok() {
@@ -103,7 +128,7 @@ func (tl traceLocker) HeapObjectFree(addr uintptr) {
 
 // traceHeapObjectID creates a trace ID for a heap object at address addr.
 func traceHeapObjectID(addr uintptr) traceArg {
-       return traceArg(uint64(addr)-trace.minPageHeapAddr) / 8
+       return traceArg(uint64(addr)-trace.minPageHeapAddr) / minHeapAlign
 }
 
 // GoroutineStackExists records that a goroutine stack already exists at address base with the provided size.
index 41dce9c9f2400d5ff4807315ade1d14f733fd9fa..b27a6909168b65056ad2749824d2f35c9f275857 100644 (file)
@@ -54,8 +54,13 @@ func dumpTypesRec(node *traceMapNode, w traceExpWriter) traceExpWriter {
        // bound is pretty loose, but avoids counting
        // lots of varint sizes.
        //
-       // Add 1 because we might also write traceEvTypes.
-       w, _ = w.ensure(1 + maxBytes)
+       // Add 1 because we might also write a traceAllocFreeTypesBatch byte.
+       var flushed bool
+       w, flushed = w.ensure(1 + maxBytes)
+       if flushed {
+               // Annotate the batch as containing types.
+               w.byte(byte(traceAllocFreeTypesBatch))
+       }
 
        // Emit type.
        w.varint(uint64(node.id))