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

View as plain text