ebpf_exporter

Форк
0
/
softirq-latency-net-rx.bpf.c 
166 строк · 4.5 Кб
1
#include <vmlinux.h>
2
#include <bpf/bpf_tracing.h>
3
#include "maps.bpf.h"
4

5
// Loosely based on https://github.com/xdp-project/xdp-project/blob/master/areas/latency/softirq_net_latency.bt
6

7
// 30 buckets for latency, max range is 0.5s .. 1.0s
8
#define MAX_LATENCY_SLOT 31
9

10
#define check_net_rx(vec_nr)                                                                                           \
11
    if (vec_nr != NET_RX_SOFTIRQ) {                                                                                    \
12
        return 0;                                                                                                      \
13
    }
14

15
/* This provide easy way to disable measuring 'runtime'.
16
 * This avoids hooking 'softirq_exit' as it can be expensive and for NET_RX
17
 * this isn't the right hook as runtime is affected by NAPI packet bulking.
18
 */
19
#define CONFIG_MEASURE_RUNTIME 1
20

21
// We only use one index in the array for this
22
u32 net_rx_idx = 0;
23

24
struct softirq_latency_key_t {
25
    u32 bucket;
26
};
27

28
struct {
29
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
30
    __uint(max_entries, 1);
31
    __type(key, u32);
32
    __type(value, u64);
33
} softirq_raised_total SEC(".maps");
34

35
struct {
36
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
37
    __uint(max_entries, 1);
38
    __type(key, u32);
39
    __type(value, u64);
40
} softirq_serviced_total SEC(".maps");
41

42
struct {
43
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
44
    __uint(max_entries, 1);
45
    __type(key, u32);
46
    __type(value, u64);
47
} softirq_raise_timestamp SEC(".maps");
48

49
struct {
50
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
51
    __uint(max_entries, MAX_LATENCY_SLOT + 2);
52
    __type(key, u32);
53
    __type(value, u64);
54
} softirq_wait_seconds SEC(".maps");
55

56
#ifdef CONFIG_MEASURE_RUNTIME
57
struct {
58
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
59
    __uint(max_entries, 1);
60
    __type(key, u32);
61
    __type(value, u64);
62
} softirq_entry_timestamp SEC(".maps");
63

64
struct {
65
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
66
    __uint(max_entries, MAX_LATENCY_SLOT + 2);
67
    __type(key, u32);
68
    __type(value, u64);
69
} softirq_runtime_seconds SEC(".maps");
70
#endif
71

72
SEC("tp_btf/softirq_raise")
73
int BPF_PROG(softirq_raise, unsigned int vec_nr)
74
{
75
    u64 *existing_ts_ptr, *raised_total_ptr, ts;
76

77
    check_net_rx(vec_nr);
78

79
    ts = bpf_ktime_get_ns();
80

81
    read_array_ptr(&softirq_raised_total, &net_rx_idx, raised_total_ptr);
82
    *raised_total_ptr += 1;
83

84
    read_array_ptr(&softirq_raise_timestamp, &net_rx_idx, existing_ts_ptr);
85

86
    // Set the timestamp only if it is not set, so that we always measure the oldest non-entered raise
87
    if (!*existing_ts_ptr) {
88
        *existing_ts_ptr = ts;
89
    }
90

91
    return 0;
92
}
93

94
SEC("tp_btf/softirq_entry")
95
int BPF_PROG(softirq_entry, unsigned int vec_nr)
96
{
97
    u64 delta_ns, *raise_ts_ptr, *serviced_total_ptr, ts;
98
    struct softirq_latency_key_t key = {};
99

100
    check_net_rx(vec_nr);
101

102
    ts = bpf_ktime_get_ns();
103

104
    read_array_ptr(&softirq_serviced_total, &net_rx_idx, serviced_total_ptr);
105
    *serviced_total_ptr += 1;
106

107
    read_array_ptr(&softirq_raise_timestamp, &net_rx_idx, raise_ts_ptr);
108

109
    // Interrupt was re-rased after ts was obtained, resulting in negative duration
110
    if (*raise_ts_ptr > ts) {
111
        return 0;
112
    }
113

114
    // Interrupt entry started with no corresponding raise, resulting in large duration
115
    if (!*raise_ts_ptr) {
116
        return 0;
117
    }
118

119
    delta_ns = ts - *raise_ts_ptr;
120

121
    increment_exp2_histogram_nosync(&softirq_wait_seconds, key, delta_ns, MAX_LATENCY_SLOT);
122

123
    // Allow raise timestamp to be set again
124
    *raise_ts_ptr = 0;
125

126
#ifdef CONFIG_MEASURE_RUNTIME
127
    u64 *existing_entry_ts_ptr;
128

129
    read_array_ptr(&softirq_entry_timestamp, &net_rx_idx, existing_entry_ts_ptr);
130

131
    // There is some time from function start to here, so overall service time includes it
132
    *existing_entry_ts_ptr = ts;
133
#endif
134
    return 0;
135
}
136

137
#ifdef CONFIG_MEASURE_RUNTIME
138
SEC("tp_btf/softirq_exit")
139
int BPF_PROG(softirq_exit, unsigned int vec_nr)
140
{
141
    u64 delta_ns, *entry_ts_ptr, ts;
142
    struct softirq_latency_key_t key = {};
143

144
    check_net_rx(vec_nr);
145

146
    ts = bpf_ktime_get_ns();
147

148
    read_array_ptr(&softirq_entry_timestamp, &net_rx_idx, entry_ts_ptr);
149

150
    // Interrupt exited with no corresponding entry, resulting in large duration
151
    if (!*entry_ts_ptr) {
152
        return 0;
153
    }
154

155
    delta_ns = ts - *entry_ts_ptr;
156

157
    increment_exp2_histogram_nosync(&softirq_runtime_seconds, key, delta_ns, MAX_LATENCY_SLOT);
158

159
    // Reset entry ts to prevent skipped entries to be counted at exit
160
    *entry_ts_ptr = 0;
161

162
    return 0;
163
}
164
#endif
165

166
char LICENSE[] SEC("license") = "GPL";
167

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

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

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

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