github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/runtime/trace2string.go (about) 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 }