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 7package runtime 8 9// Trace strings. 10 11const maxTraceStringLen = 1024 12 13// traceStringTable is map of string -> unique ID that also manages 14// writing strings out into the trace. 15type 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. 25func (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. 39func (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 53func (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. 85func (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