ebpf_exporter

Форк
0
/
perf_event.go 
116 строк · 2.9 Кб
1
package exporter
2

3
/*
4
#include <stdlib.h>
5
#include <bpf/libbpf.h>
6

7
extern int attachPerfEventCallback(const struct bpf_program *prog,
8
                                   long cookie,
9
                                   struct bpf_link **link);
10
*/
11
import "C"
12

13
import (
14
	"fmt"
15
	"strconv"
16
	"strings"
17
	"syscall"
18
	"unsafe"
19

20
	"github.com/aquasecurity/libbpfgo"
21
	"github.com/elastic/go-perf"
22
	"github.com/iovisor/gobpf/pkg/cpuonline"
23
	"golang.org/x/sys/unix"
24
)
25

26
var libbpfPerfHandlers []int
27

28
func registerHandlers() error {
29
	if libbpfPerfHandlers != nil {
30
		return nil
31
	}
32

33
	name := C.CString("perf_event/")
34
	defer C.free(unsafe.Pointer(name))
35

36
	opts := C.struct_libbpf_prog_handler_opts{}
37
	opts.sz = C.sizeof_struct_libbpf_prog_handler_opts
38
	opts.prog_attach_fn = C.libbpf_prog_attach_fn_t(C.attachPerfEventCallback)
39

40
	handler := C.libbpf_register_prog_handler(name, uint32(libbpfgo.BPFProgTypePerfEvent), uint32(libbpfgo.BPFAttachTypePerfEvent), &opts)
41
	if handler < 0 {
42
		return fmt.Errorf("error registering prog handler: %s", unix.ErrnoName(syscall.Errno(handler)))
43
	}
44

45
	libbpfPerfHandlers = append(libbpfPerfHandlers, int(handler))
46

47
	return nil
48
}
49

50
func parseSectionConfig(section string) (*perf.Attr, []uint, error) {
51
	attr := &perf.Attr{}
52

53
	for _, item := range strings.Split(strings.TrimPrefix(section, "perf_event/"), ",") {
54
		kv := strings.SplitN(item, "=", 2)
55
		if len(kv) != 2 {
56
			return nil, nil, fmt.Errorf("invalid perf_event item: %q", item)
57
		}
58

59
		value, err := strconv.Atoi(kv[1])
60
		if err != nil {
61
			return nil, nil, fmt.Errorf("error parsing value of item %q as integer: %v", item, err)
62
		}
63

64
		switch kv[0] {
65
		case "type":
66
			attr.Type = perf.EventType(value)
67
		case "config":
68
			attr.Config = uint64(value)
69
		case "frequency":
70
			attr.SetSampleFreq(uint64(value))
71
		default:
72
			return nil, nil, fmt.Errorf("unknown perf_event item %q", item)
73
		}
74
	}
75

76
	cpus, err := cpuonline.Get()
77
	if err != nil {
78
		return nil, nil, fmt.Errorf("failed to determine online cpus: %v", err)
79
	}
80

81
	return attr, cpus, nil
82
}
83

84
func attachPerfEvent(prog *C.struct_bpf_program) ([]*C.struct_bpf_link, error) {
85
	section := C.GoString(C.bpf_program__section_name(prog))
86

87
	fa, cpus, err := parseSectionConfig(section)
88
	if err != nil {
89
		return nil, fmt.Errorf("failed to parse section %q: %v", section, err)
90
	}
91

92
	links := make([]*C.struct_bpf_link, len(cpus))
93

94
	name := C.GoString(C.bpf_program__name(prog))
95

96
	for i, cpu := range cpus {
97
		event, err := perf.Open(fa, perf.AllThreads, int(cpu), nil)
98
		if err != nil {
99
			return nil, fmt.Errorf("failed to open perf_event: %v", err)
100
		}
101

102
		fd, err := event.FD()
103
		if err != nil {
104
			return nil, fmt.Errorf("failed to get perf_event fd: %v", err)
105
		}
106

107
		link, err := C.bpf_program__attach_perf_event(prog, C.int(fd))
108
		if link == nil {
109
			return nil, fmt.Errorf("failed to attach perf event %d:%d to program %q on cpu %d: %v", fa.Type, fa.Config, name, cpu, err)
110
		}
111

112
		links[i] = link
113
	}
114

115
	return links, nil
116
}
117

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.