github.com/grafana/pyroscope-go/godeltaprof@v0.1.8-0.20240513050943-1b1f97373e2a/internal/pprof/map.go (about) 1 // Copyright 2017 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 package pprof 6 7 import "unsafe" 8 9 // A profMap is a map from (stack, tag) to mapEntry. 10 // It grows without bound, but that's assumed to be OK. 11 type profMap struct { 12 hash map[uintptr]*profMapEntry 13 all *profMapEntry 14 last *profMapEntry 15 free []profMapEntry 16 freeStk []uintptr 17 } 18 19 type count struct { 20 // alloc_objects, alloc_bytes for heap 21 // mutex_count, mutex_duration for mutex 22 v1, v2 int64 23 } 24 25 // A profMapEntry is a single entry in the profMap. 26 type profMapEntry struct { 27 nextHash *profMapEntry // next in hash list 28 nextAll *profMapEntry // next in list of all entries 29 stk []uintptr 30 tag uintptr 31 count count 32 } 33 34 func (m *profMap) Lookup(stk []uintptr, tag uintptr) *profMapEntry { 35 // Compute hash of (stk, tag). 36 h := uintptr(0) 37 for _, x := range stk { 38 h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) 39 h += uintptr(x) * 41 40 } 41 h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) 42 h += uintptr(tag) * 41 43 44 // Find entry if present. 45 var last *profMapEntry 46 Search: 47 for e := m.hash[h]; e != nil; last, e = e, e.nextHash { 48 if len(e.stk) != len(stk) || e.tag != tag { 49 continue 50 } 51 for j := range stk { 52 if e.stk[j] != uintptr(stk[j]) { 53 continue Search 54 } 55 } 56 // Move to front. 57 if last != nil { 58 last.nextHash = e.nextHash 59 e.nextHash = m.hash[h] 60 m.hash[h] = e 61 } 62 return e 63 } 64 65 // Add new entry. 66 if len(m.free) < 1 { 67 m.free = make([]profMapEntry, 128) 68 } 69 e := &m.free[0] 70 m.free = m.free[1:] 71 e.nextHash = m.hash[h] 72 e.tag = tag 73 74 if len(m.freeStk) < len(stk) { 75 m.freeStk = make([]uintptr, 1024) 76 } 77 // Limit cap to prevent append from clobbering freeStk. 78 e.stk = m.freeStk[:len(stk):len(stk)] 79 m.freeStk = m.freeStk[len(stk):] 80 81 for j := range stk { 82 e.stk[j] = uintptr(stk[j]) 83 } 84 if m.hash == nil { 85 m.hash = make(map[uintptr]*profMapEntry) 86 } 87 m.hash[h] = e 88 if m.all == nil { 89 m.all = e 90 m.last = e 91 } else { 92 m.last.nextAll = e 93 m.last = e 94 } 95 return e 96 }