最近 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 来的快。