-
Notifications
You must be signed in to change notification settings - Fork 10
/
events.go
156 lines (144 loc) · 4.21 KB
/
events.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//go:build linux
// +build linux
package perf
import (
"fmt"
"strconv"
"strings"
"unsafe"
"golang.org/x/sys/unix"
)
const (
// PERF_TYPE_TRACEPOINT is a kernel tracepoint.
PERF_TYPE_TRACEPOINT = 2
)
// AvailableEvents returns a mapping of available subsystems and their
// corresponding list of available events.
func AvailableEvents() (map[string][]string, error) {
events := map[string][]string{}
tracefsMount, err := TraceFSMount()
if err != nil {
return events, err
}
rawEvents, err := fileToStrings(tracefsMount + "/available_events")
if err != nil {
return events, err
}
// Events are colon delimited by type so parse the type and add sub
// events appropriately.
for _, rawEvent := range rawEvents {
splits := strings.Split(rawEvent, ":")
if len(splits) <= 1 {
continue
}
eventTypeEvents, found := events[splits[0]]
if found {
events[splits[0]] = append(eventTypeEvents, splits[1])
continue
}
events[splits[0]] = []string{splits[1]}
}
return events, err
}
// AvailableSubsystems returns a slice of available subsystems.
func AvailableSubsystems() ([]string, error) {
subsystems := []string{}
tracefsMount, err := TraceFSMount()
if err != nil {
return subsystems, err
}
rawEvents, err := fileToStrings(tracefsMount + "/available_events")
if err != nil {
return subsystems, err
}
// Events are colon delimited by type so parse the type and add sub
// events appropriately.
for _, rawEvent := range rawEvents {
splits := strings.Split(rawEvent, ":")
if len(splits) <= 1 {
continue
}
subsystems = append(subsystems, splits[0])
}
return subsystems, nil
}
// AvailableTracers returns the list of available tracers.
func AvailableTracers() ([]string, error) {
tracefsMount, err := TraceFSMount()
if err != nil {
return []string{}, err
}
return fileToStrings(tracefsMount + "/available_tracers")
}
// CurrentTracer returns the current tracer.
func CurrentTracer() (string, error) {
tracefsMount, err := TraceFSMount()
if err != nil {
return "", err
}
res, err := fileToStrings(tracefsMount + "/current_tracer")
return res[0], err
}
// GetTracepointConfig is used to get the configuration for a trace event.
func GetTracepointConfig(subsystem, event string) (uint64, error) {
tracefsMount, err := TraceFSMount()
if err != nil {
return 0, err
}
res, err := fileToStrings(
tracefsMount + fmt.Sprintf("/events/%s/%s/id", subsystem, event))
if err != nil {
return 0, fmt.Errorf("Failed to get tracepoint config for %s:%s: %q", subsystem, event, err)
}
return strconv.ParseUint(res[0], 10, 64)
}
// ProfileTracepoint is used to profile a kernel tracepoint event for a
// specific PID. Events can be listed with `perf list` for Tracepoint Events or
// in the /sys/kernel/debug/tracing/events directory with the kind being the
// directory and the event being the subdirectory.
func ProfileTracepoint(subsystem, event string, pid, cpu int, opts ...int) (BPFProfiler, error) {
config, err := GetTracepointConfig(subsystem, event)
if err != nil {
return nil, err
}
eventAttr := &unix.PerfEventAttr{
Type: PERF_TYPE_TRACEPOINT,
Config: config,
Size: uint32(unsafe.Sizeof(unix.PerfEventAttr{})),
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
Sample_type: PERF_SAMPLE_IDENTIFIER,
}
var eventOps int
if len(opts) > 0 {
eventOps = opts[0]
}
fd, err := unix.PerfEventOpen(
eventAttr,
pid,
cpu,
-1,
eventOps,
)
if err != nil {
return nil, fmt.Errorf("Failed to open perf event for PerfEventAttr %+v: %q", eventAttr, err)
}
return &profiler{
fd: fd,
}, nil
}
// TracepointEventAttr is used to return an PerfEventAttr for a trace event.
func TracepointEventAttr(subsystem, event string) (*unix.PerfEventAttr, error) {
config, err := GetTracepointConfig(subsystem, event)
if err != nil {
return nil, err
}
return &unix.PerfEventAttr{
Type: PERF_TYPE_TRACEPOINT,
Config: config,
Size: uint32(unsafe.Sizeof(unix.PerfEventAttr{})),
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
Sample_type: PERF_SAMPLE_IDENTIFIER,
}, nil
}