golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/trace/batchcursor.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 // Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT. 6 7 //go:build go1.21 8 9 package trace 10 11 import ( 12 "cmp" 13 "encoding/binary" 14 "fmt" 15 16 "golang.org/x/exp/trace/internal/event" 17 "golang.org/x/exp/trace/internal/event/go122" 18 ) 19 20 type batchCursor struct { 21 m ThreadID 22 lastTs Time 23 idx int // next index into []batch 24 dataOff int // next index into batch.data 25 ev baseEvent // last read event 26 } 27 28 func (b *batchCursor) nextEvent(batches []batch, freq frequency) (ok bool, err error) { 29 // Batches should generally always have at least one event, 30 // but let's be defensive about that and accept empty batches. 31 for b.idx < len(batches) && len(batches[b.idx].data) == b.dataOff { 32 b.idx++ 33 b.dataOff = 0 34 b.lastTs = 0 35 } 36 // Have we reached the end of the batches? 37 if b.idx == len(batches) { 38 return false, nil 39 } 40 // Initialize lastTs if it hasn't been yet. 41 if b.lastTs == 0 { 42 b.lastTs = freq.mul(batches[b.idx].time) 43 } 44 // Read an event out. 45 n, tsdiff, err := readTimedBaseEvent(batches[b.idx].data[b.dataOff:], &b.ev) 46 if err != nil { 47 return false, err 48 } 49 // Complete the timestamp from the cursor's last timestamp. 50 b.ev.time = freq.mul(tsdiff) + b.lastTs 51 52 // Move the cursor's timestamp forward. 53 b.lastTs = b.ev.time 54 55 // Move the cursor forward. 56 b.dataOff += n 57 return true, nil 58 } 59 60 func (b *batchCursor) compare(a *batchCursor) int { 61 return cmp.Compare(b.ev.time, a.ev.time) 62 } 63 64 // readTimedBaseEvent reads out the raw event data from b 65 // into e. It does not try to interpret the arguments 66 // but it does validate that the event is a regular 67 // event with a timestamp (vs. a structural event). 68 // 69 // It requires that the event its reading be timed, which must 70 // be the case for every event in a plain EventBatch. 71 func readTimedBaseEvent(b []byte, e *baseEvent) (int, timestamp, error) { 72 // Get the event type. 73 typ := event.Type(b[0]) 74 specs := go122.Specs() 75 if int(typ) >= len(specs) { 76 return 0, 0, fmt.Errorf("found invalid event type: %v", typ) 77 } 78 e.typ = typ 79 80 // Get spec. 81 spec := &specs[typ] 82 if len(spec.Args) == 0 || !spec.IsTimedEvent { 83 return 0, 0, fmt.Errorf("found event without a timestamp: type=%v", typ) 84 } 85 n := 1 86 87 // Read timestamp diff. 88 ts, nb := binary.Uvarint(b[n:]) 89 if nb <= 0 { 90 return 0, 0, fmt.Errorf("found invalid uvarint for timestamp") 91 } 92 n += nb 93 94 // Read the rest of the arguments. 95 for i := 0; i < len(spec.Args)-1; i++ { 96 arg, nb := binary.Uvarint(b[n:]) 97 if nb <= 0 { 98 return 0, 0, fmt.Errorf("found invalid uvarint") 99 } 100 e.args[i] = arg 101 n += nb 102 } 103 return n, timestamp(ts), nil 104 } 105 106 func heapInsert(heap []*batchCursor, bc *batchCursor) []*batchCursor { 107 // Add the cursor to the end of the heap. 108 heap = append(heap, bc) 109 110 // Sift the new entry up to the right place. 111 heapSiftUp(heap, len(heap)-1) 112 return heap 113 } 114 115 func heapUpdate(heap []*batchCursor, i int) { 116 // Try to sift up. 117 if heapSiftUp(heap, i) != i { 118 return 119 } 120 // Try to sift down, if sifting up failed. 121 heapSiftDown(heap, i) 122 } 123 124 func heapRemove(heap []*batchCursor, i int) []*batchCursor { 125 // Sift index i up to the root, ignoring actual values. 126 for i > 0 { 127 heap[(i-1)/2], heap[i] = heap[i], heap[(i-1)/2] 128 i = (i - 1) / 2 129 } 130 // Swap the root with the last element, then remove it. 131 heap[0], heap[len(heap)-1] = heap[len(heap)-1], heap[0] 132 heap = heap[:len(heap)-1] 133 // Sift the root down. 134 heapSiftDown(heap, 0) 135 return heap 136 } 137 138 func heapSiftUp(heap []*batchCursor, i int) int { 139 for i > 0 && heap[(i-1)/2].ev.time > heap[i].ev.time { 140 heap[(i-1)/2], heap[i] = heap[i], heap[(i-1)/2] 141 i = (i - 1) / 2 142 } 143 return i 144 } 145 146 func heapSiftDown(heap []*batchCursor, i int) int { 147 for { 148 m := min3(heap, i, 2*i+1, 2*i+2) 149 if m == i { 150 // Heap invariant already applies. 151 break 152 } 153 heap[i], heap[m] = heap[m], heap[i] 154 i = m 155 } 156 return i 157 } 158 159 func min3(b []*batchCursor, i0, i1, i2 int) int { 160 minIdx := i0 161 minT := maxTime 162 if i0 < len(b) { 163 minT = b[i0].ev.time 164 } 165 if i1 < len(b) { 166 if t := b[i1].ev.time; t < minT { 167 minT = t 168 minIdx = i1 169 } 170 } 171 if i2 < len(b) { 172 if t := b[i2].ev.time; t < minT { 173 minT = t 174 minIdx = i2 175 } 176 } 177 return minIdx 178 }