Source file src/runtime/trace2string.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  //go:build goexperiment.exectracer2
     6  
     7  // Trace string management.
     8  
     9  package runtime
    10  
    11  // Trace strings.
    12  
    13  const maxTraceStringLen = 1024
    14  
    15  // traceStringTable is map of string -> unique ID that also manages
    16  // writing strings out into the trace.
    17  type traceStringTable struct {
    18  	// lock protects buf.
    19  	lock mutex
    20  	buf  *traceBuf // string batches to write out to the trace.
    21  
    22  	// tab is a mapping of string -> unique ID.
    23  	tab traceMap
    24  }
    25  
    26  // put adds a string to the table, emits it, and returns a unique ID for it.
    27  func (t *traceStringTable) put(gen uintptr, s string) uint64 {
    28  	// Put the string in the table.
    29  	ss := stringStructOf(&s)
    30  	id, added := t.tab.put(ss.str, uintptr(ss.len))
    31  	if added {
    32  		// Write the string to the buffer.
    33  		systemstack(func() {
    34  			t.writeString(gen, id, s)
    35  		})
    36  	}
    37  	return id
    38  }
    39  
    40  // emit emits a string and creates an ID for it, but doesn't add it to the table. Returns the ID.
    41  func (t *traceStringTable) emit(gen uintptr, s string) uint64 {
    42  	// Grab an ID and write the string to the buffer.
    43  	id := t.tab.stealID()
    44  	systemstack(func() {
    45  		t.writeString(gen, id, s)
    46  	})
    47  	return id
    48  }
    49  
    50  // writeString writes the string to t.buf.
    51  //
    52  // Must run on the systemstack because it may flush buffers and thus could acquire trace.lock.
    53  //
    54  //go:systemstack
    55  func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) {
    56  	// Truncate the string if necessary.
    57  	if len(s) > maxTraceStringLen {
    58  		s = s[:maxTraceStringLen]
    59  	}
    60  
    61  	lock(&t.lock)
    62  	w := unsafeTraceWriter(gen, t.buf)
    63  
    64  	// Ensure we have a place to write to.
    65  	var flushed bool
    66  	w, flushed = w.ensure(2 + 2*traceBytesPerNumber + len(s) /* traceEvStrings + traceEvString + ID + len + string data */)
    67  	if flushed {
    68  		// Annotate the batch as containing strings.
    69  		w.byte(byte(traceEvStrings))
    70  	}
    71  
    72  	// Write out the string.
    73  	w.byte(byte(traceEvString))
    74  	w.varint(id)
    75  	w.varint(uint64(len(s)))
    76  	w.stringData(s)
    77  
    78  	// Store back buf if it was updated during ensure.
    79  	t.buf = w.traceBuf
    80  	unlock(&t.lock)
    81  }
    82  
    83  // reset clears the string table and flushes any buffers it has.
    84  //
    85  // Must be called only once the caller is certain nothing else will be
    86  // added to this table.
    87  //
    88  // Because it flushes buffers, this may acquire trace.lock and thus
    89  // must run on the systemstack.
    90  //
    91  //go:systemstack
    92  func (t *traceStringTable) reset(gen uintptr) {
    93  	if t.buf != nil {
    94  		lock(&trace.lock)
    95  		traceBufFlush(t.buf, gen)
    96  		unlock(&trace.lock)
    97  		t.buf = nil
    98  	}
    99  
   100  	// Reset the table.
   101  	lock(&t.tab.lock)
   102  	t.tab.reset()
   103  	unlock(&t.tab.lock)
   104  }
   105  

View as plain text