| // Copyright 2017 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package pprof | |
| import "unsafe" | |
| // A profMap is a map from (stack, tag) to mapEntry. | |
| // It grows without bound, but that's assumed to be OK. | |
| type profMap struct { | |
| hash map[uintptr]*profMapEntry | |
| all *profMapEntry | |
| last *profMapEntry | |
| free []profMapEntry | |
| freeStk []uintptr | |
| } | |
| // A profMapEntry is a single entry in the profMap. | |
| type profMapEntry struct { | |
| nextHash *profMapEntry // next in hash list | |
| nextAll *profMapEntry // next in list of all entries | |
| stk []uintptr | |
| tag unsafe.Pointer | |
| count int64 | |
| } | |
| func (m *profMap) lookup(stk []uint64, tag unsafe.Pointer) *profMapEntry { | |
| // Compute hash of (stk, tag). | |
| h := uintptr(0) | |
| for _, x := range stk { | |
| h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) | |
| h += uintptr(x) * 41 | |
| } | |
| h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) | |
| h += uintptr(tag) * 41 | |
| // Find entry if present. | |
| var last *profMapEntry | |
| Search: | |
| for e := m.hash[h]; e != nil; last, e = e, e.nextHash { | |
| if len(e.stk) != len(stk) || e.tag != tag { | |
| continue | |
| } | |
| for j := range stk { | |
| if e.stk[j] != uintptr(stk[j]) { | |
| continue Search | |
| } | |
| } | |
| // Move to front. | |
| if last != nil { | |
| last.nextHash = e.nextHash | |
| e.nextHash = m.hash[h] | |
| m.hash[h] = e | |
| } | |
| return e | |
| } | |
| // Add new entry. | |
| if len(m.free) < 1 { | |
| m.free = make([]profMapEntry, 128) | |
| } | |
| e := &m.free[0] | |
| m.free = m.free[1:] | |
| e.nextHash = m.hash[h] | |
| e.tag = tag | |
| if len(m.freeStk) < len(stk) { | |
| m.freeStk = make([]uintptr, 1024) | |
| } | |
| // Limit cap to prevent append from clobbering freeStk. | |
| e.stk = m.freeStk[:len(stk):len(stk)] | |
| m.freeStk = m.freeStk[len(stk):] | |
| for j := range stk { | |
| e.stk[j] = uintptr(stk[j]) | |
| } | |
| if m.hash == nil { | |
| m.hash = make(map[uintptr]*profMapEntry) | |
| } | |
| m.hash[h] = e | |
| if m.all == nil { | |
| m.all = e | |
| m.last = e | |
| } else { | |
| m.last.nextAll = e | |
| m.last = e | |
| } | |
| return e | |
| } | |