github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/agent/ebpfspy/symbols_linux.go (about)

     1  //go:build ebpfspy
     2  // +build ebpfspy
     3  
     4  // Package ebpfspy provides integration with Linux eBPF. It is a rough copy of profile.py from BCC tools:
     5  //
     6  //	https://github.com/iovisor/bcc/blob/master/tools/profile.py
     7  package ebpfspy
     8  
     9  import "C"
    10  import (
    11  	"fmt"
    12  	"github.com/pyroscope-io/pyroscope/pkg/agent/ebpfspy/symtab"
    13  	"github.com/pyroscope-io/pyroscope/pkg/util/genericlru"
    14  	"sync"
    15  )
    16  
    17  type symbolCacheEntry struct {
    18  	symbolTable symtab.SymbolTable
    19  	roundNumber int
    20  }
    21  type pidKey uint32
    22  
    23  type symbolCache struct {
    24  	pid2Cache *genericlru.GenericLRU[pidKey, symbolCacheEntry]
    25  	mutex     sync.Mutex
    26  }
    27  
    28  func newSymbolCache(cacheSize int) (*symbolCache, error) {
    29  	pid2Cache, err := genericlru.NewGenericLRU[pidKey, symbolCacheEntry](cacheSize, func(pid pidKey, e *symbolCacheEntry) {
    30  		e.symbolTable.Close()
    31  	})
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	return &symbolCache{
    36  		pid2Cache: pid2Cache,
    37  	}, nil
    38  }
    39  
    40  func (sc *symbolCache) bccResolve(pid uint32, addr uint64, roundNumber int) symtab.Symbol {
    41  	e := sc.getOrCreateCacheEntry(pidKey(pid))
    42  	staleCheck := false
    43  	if roundNumber != e.roundNumber {
    44  		e.roundNumber = roundNumber
    45  		staleCheck = true
    46  	}
    47  	return e.symbolTable.Resolve(addr, staleCheck)
    48  }
    49  
    50  func (sc *symbolCache) getOrCreateCacheEntry(pid pidKey) *symbolCacheEntry {
    51  	sc.mutex.Lock()
    52  	defer sc.mutex.Unlock()
    53  	if cache, ok := sc.pid2Cache.Get(pid); ok {
    54  		return cache
    55  	}
    56  	var symbolTable symtab.SymbolTable
    57  	exe := fmt.Sprintf("/proc/%d/exe", pid)
    58  	bcc := func() symtab.SymbolTable {
    59  		return symtab.NewBCCSymbolTable(int(pid))
    60  	}
    61  	symbolTable, err := symtab.NewGoSymbolTable(exe, &bcc)
    62  	if err != nil || symbolTable == nil {
    63  		symbolTable = bcc()
    64  	}
    65  	e := &symbolCacheEntry{symbolTable: symbolTable}
    66  	sc.pid2Cache.Add(pid, e)
    67  	return e
    68  }
    69  
    70  func (sc *symbolCache) clear() {
    71  	sc.mutex.Lock()
    72  	defer sc.mutex.Unlock()
    73  	for _, pid := range sc.pid2Cache.Keys() {
    74  		sc.pid2Cache.Remove(pid)
    75  	}
    76  }