最近 eBPF 轮子造的多了后,发现需要用 histogram 的时候,要写的代码就一个模板,如下。
以下内容以 syscalldist 为例。
用于 histogram 的 C 代码
参考(抄袭) libbpf-tools 里 histogram 的实现,用于 histogram 的 C 代码如下:
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
|
#define MAX_SLOTS 36
struct hist {
__u64 slots[MAX_SLOTS];
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, struct hist);
__uint(max_entries, 1); // 按需变更最大数量
} hists SEC(".maps");
SEC("raw_tracepoint/sys_exit")
int sys_exit(struct bpf_raw_tracepoint_args *ctx)
{
// ...
struct hist initial_hist = {};
__u32 index = 0;
struct hist *hp = bpf_map_lookup_or_try_init(&hists, &index, &initial_hist);
if (!hp)
return 0;
// 计算 delta
__u64 delta = bpf_ktime_get_ns() - *tsp;
delta /= 1000; // micro-second
// 使用 log2 计算数组索引
__u64 slot = log2l(delta);
if (slot >= MAX_SLOTS)
slot = MAX_SLOTS - 1;
// 使用原子操作进行计数递增
__sync_fetch_and_add(&hp->slots[slot], 1);
return 0;
}
|
如上代码片段便是用于 histogram 的 C 代码模板。
用于 histogram 的 Go 代码
对应于 histogram 的 C 代码,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
|
const (
maxSlots = 36
)
type slot struct {
Slots [maxSlots]uint64
}
func printHist(m *ebpf.Map, syscallID uint32) {
// 从 hists bpf map 中获取 histogram 数据
slotNumber := 1
slots := make([]slot, slotNumber)
for key := uint32(0); key < uint32(slotNumber); key++ {
err := m.Lookup(key, &slots[key])
if err != nil {
log.Printf("Failed to lookup key(%d): %v", key, err)
return
}
}
for _, s := range slots[:] {
sum := lodash.Sum(s.Slots[:])
fmt.Println()
fmt.Printf("Histogram for syscall(%d) (sum %d):\n", syscallID, sum)
PrintLog2Hist(s.Slots[:], "usecs") // 打印出 histogram 数据
}
}
func PrintLog2Hist[T constraints.Integer](vals []T, valType string) {
// 代码较长,请参考 https://github.com/Asphaltt/syscalldist/blob/main/pkg/histogram/histogram.go#L34
}
|
histogram 数据示例
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
|
# ./syscalldist --pid 2153676 --syscall 7
2022/09/14 15:03:59 Attached raw_tracepoint(sys_enter)
2022/09/14 15:03:59 Attached raw_tracepoint(sys_exit)
2022/09/14 15:03:59 Hit Ctrl-C to end.
^C
Histogram for syscall(7) (sum 15):
usecs : count distribution
0 -> 1 : 0 | |
2 -> 3 : 0 | |
4 -> 7 : 0 | |
8 -> 15 : 0 | |
16 -> 31 : 0 | |
32 -> 63 : 0 | |
64 -> 127 : 0 | |
128 -> 255 : 0 | |
256 -> 511 : 0 | |
512 -> 1023 : 0 | |
1024 -> 2047 : 0 | |
2048 -> 4095 : 0 | |
4096 -> 8191 : 0 | |
8192 -> 16383 : 0 | |
16384 -> 32767 : 0 | |
32768 -> 65535 : 0 | |
65536 -> 131071 : 0 | |
131072 -> 262143 : 0 | |
262144 -> 524287 : 15 |****************************************|
|
小结
常用的代码模板,还是 Ctrl+C&Ctrl+V 来的快。