github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/agent/ebpfspy/session_maps_linux.go (about) 1 //go:build ebpfspy 2 3 // Package ebpfspy provides integration with Linux eBPF. It is a rough copy of profile.py from BCC tools: 4 // 5 // https://github.com/iovisor/bcc/blob/master/tools/profile.py 6 package ebpfspy 7 8 import ( 9 "unsafe" 10 ) 11 12 //#cgo CFLAGS: -I./bpf/ 13 //#include <linux/types.h> 14 //#include "profile.bpf.h" 15 import "C" 16 17 func (s *Session) getCountsMapValues() (keys [][]byte, values [][]byte, batch bool, err error) { 18 // try lookup_and_delete_batch 19 var ( 20 mapSize = C.PROFILE_MAPS_SIZE 21 keySize = int(unsafe.Sizeof(C.struct_profile_key_t{})) 22 allKeys = make([]byte, mapSize*keySize) 23 pKeys = unsafe.Pointer(&allKeys[0]) 24 nextKey = C.struct_profile_key_t{} 25 ) 26 values, err = s.mapCounts.GetValueAndDeleteBatch(pKeys, nil, unsafe.Pointer(&nextKey), uint32(mapSize)) 27 if len(values) > 0 { 28 keys = collectBatchValues(allKeys, len(values), keySize) 29 return keys, values, true, nil 30 } 31 32 // batch failed or unsupported or just unlucky and got 0 stack-traces 33 // try iterating 34 it := s.mapCounts.Iterator() 35 for it.Next() { 36 key := it.Key() 37 v, err := s.mapCounts.GetValue(unsafe.Pointer(&key[0])) 38 if err != nil { 39 return nil, nil, false, err 40 } 41 keyCopy := make([]byte, len(key)) // The slice is valid only until the next call to Next. 42 copy(keyCopy, key) 43 keys = append(keys, keyCopy) 44 values = append(values, v) 45 } 46 return keys, values, false, nil 47 } 48 49 func (s *Session) clearCountsMap(keys [][]byte, batch bool) error { 50 if len(keys) == 0 { 51 return nil 52 } 53 if batch { 54 // do nothing, already deleted with GetValueAndDeleteBatch in getCountsMapValues 55 return nil 56 } 57 for _, key := range keys { 58 err := s.mapCounts.DeleteKey(unsafe.Pointer(&key[0])) 59 if err != nil { 60 return err 61 } 62 } 63 return nil 64 } 65 66 func (s *Session) clearStacksMap(knownKeys map[uint32]bool) error { 67 m := s.mapStacks 68 cnt := 0 69 errs := 0 70 if s.roundNumber%10 == 0 { 71 // do a full reset once in a while 72 it := m.Iterator() 73 var keys [][]byte 74 for it.Next() { 75 key := it.Key() 76 keyCopy := make([]byte, len(key)) // The slice is valid only until the next call to Next. 77 copy(keyCopy, key) 78 keys = append(keys, keyCopy) 79 } 80 for _, key := range keys { 81 if err := m.DeleteKey(unsafe.Pointer(&key[0])); err != nil { 82 errs += 1 83 } else { 84 cnt += 1 85 } 86 } 87 return nil 88 } 89 for stackId := range knownKeys { 90 k := stackId 91 if err := m.DeleteKey(unsafe.Pointer(&k)); err != nil { 92 errs += 1 93 } else { 94 cnt += 1 95 } 96 } 97 return nil 98 } 99 100 func collectBatchValues(values []byte, count int, valueSize int) [][]byte { 101 var value []byte 102 var collected [][]byte 103 for i := 0; i < count*valueSize; i += valueSize { 104 value = values[i : i+valueSize] 105 collected = append(collected, value) 106 } 107 return collected 108 }