github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/agent/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  // A profMapEntry is a single entry in the profMap.
    20  type profMapEntry struct {
    21  	nextHash *profMapEntry // next in hash list
    22  	nextAll  *profMapEntry // next in list of all entries
    23  	stk      []uintptr
    24  	tag      unsafe.Pointer
    25  	count    int64
    26  }
    27  
    28  func (m *profMap) lookup(stk []uint64, tag unsafe.Pointer) *profMapEntry {
    29  	// Compute hash of (stk, tag).
    30  	h := uintptr(0)
    31  	for _, x := range stk {
    32  		h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
    33  		h += uintptr(x) * 41
    34  	}
    35  	h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
    36  	h += uintptr(tag) * 41
    37  
    38  	// Find entry if present.
    39  	var last *profMapEntry
    40  Search:
    41  	for e := m.hash[h]; e != nil; last, e = e, e.nextHash {
    42  		if len(e.stk) != len(stk) || e.tag != tag {
    43  			continue
    44  		}
    45  		for j := range stk {
    46  			if e.stk[j] != uintptr(stk[j]) {
    47  				continue Search
    48  			}
    49  		}
    50  		// Move to front.
    51  		if last != nil {
    52  			last.nextHash = e.nextHash
    53  			e.nextHash = m.hash[h]
    54  			m.hash[h] = e
    55  		}
    56  		return e
    57  	}
    58  
    59  	// Add new entry.
    60  	if len(m.free) < 1 {
    61  		m.free = make([]profMapEntry, 128)
    62  	}
    63  	e := &m.free[0]
    64  	m.free = m.free[1:]
    65  	e.nextHash = m.hash[h]
    66  	e.tag = tag
    67  
    68  	if len(m.freeStk) < len(stk) {
    69  		m.freeStk = make([]uintptr, 1024)
    70  	}
    71  	e.stk = m.freeStk[:len(stk)]
    72  	m.freeStk = m.freeStk[len(stk):]
    73  
    74  	for j := range stk {
    75  		e.stk[j] = uintptr(stk[j])
    76  	}
    77  	if m.hash == nil {
    78  		m.hash = make(map[uintptr]*profMapEntry)
    79  	}
    80  	m.hash[h] = e
    81  	if m.all == nil {
    82  		m.all = e
    83  		m.last = e
    84  	} else {
    85  		m.last.nextAll = e
    86  		m.last = e
    87  	}
    88  	return e
    89  }