|  | // 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 | 
|  | } |