aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/hodgesds/perf-utils/events.go
blob: 33d2492b15c5f46babf25f5839383669e8459146 (plain)
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
// +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{}
	// BUG(hodgesds): this should ideally check mounts for debugfs
	rawEvents, err := fileToStrings(TracingDir + "/available_events")
	// Events are colon delimited by type so parse the type and add sub
	// events appropriately.
	if err != nil {
		return events, err
	}
	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{}
	// BUG(hodgesds): this should ideally check mounts for debugfs
	rawEvents, err := fileToStrings(TracingDir + "/available_events")
	// Events are colon delimited by type so parse the type and add sub
	// events appropriately.
	if err != nil {
		return subsystems, err
	}
	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) {
	return fileToStrings(TracingDir + "/available_tracers")
}

// CurrentTracer returns the current tracer.
func CurrentTracer() (string, error) {
	res, err := fileToStrings(TracingDir + "/current_tracer")
	return res[0], err
}

// GetTracepointConfig is used to get the configuration for a trace event.
func GetTracepointConfig(subsystem, event string) (uint64, error) {
	res, err := fileToStrings(
		TracingDir + fmt.Sprintf("/events/%s/%s/id", subsystem, event))
	if err != nil {
		return 0, 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, 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
}