Skip to content

Commit 102e4ca

Browse files
add disksnoop example
1 parent fed6af1 commit 102e4ca

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

BCC-Examples/disksnoop.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from vmlinux import struct_request, struct_pt_regs
2+
from pythonbpf import bpf, section, bpfglobal, compile_to_ir, compile, map
3+
from pythonbpf.helper import ktime
4+
from pythonbpf.maps import HashMap
5+
import logging
6+
from ctypes import c_int64, c_uint64, c_uint32, c_int32
7+
8+
# Constants
9+
REQ_WRITE = 1 # from include/linux/blk_types.h
10+
11+
@bpf
12+
@map
13+
def start() -> HashMap:
14+
return HashMap(key=c_uint64, value=c_uint64, max_entries=10240)
15+
16+
@bpf
17+
@section("kprobe/blk_mq_end_request")
18+
def trace_completion(ctx: struct_pt_regs) -> c_int64:
19+
# Get request pointer from first argument
20+
req_ptr = ctx.di
21+
req = struct_request(ctx.di)
22+
# Print: data_len, cmd_flags, latency_us
23+
data_len = req.__data_len
24+
cmd_flags = req.cmd_flags
25+
# Lookup start timestamp
26+
req_tsp = start.lookup(req_ptr)
27+
if req_tsp:
28+
# Calculate delta in nanoseconds
29+
delta = ktime() - req_tsp
30+
31+
# Convert to microseconds for printing
32+
delta_us = delta // 1000
33+
34+
print(f"{data_len} {cmd_flags:x} {delta_us}\n")
35+
36+
# Delete the entry
37+
start.delete(req_ptr)
38+
39+
return c_int64(0)
40+
41+
@bpf
42+
@section("kprobe/blk_mq_start_request")
43+
def trace_start(ctx1: struct_pt_regs) -> c_int32:
44+
req = ctx1.di
45+
ts = ktime()
46+
start.update(req, ts)
47+
return c_int32(0)
48+
49+
@bpf
50+
@bpfglobal
51+
def LICENSE() -> str:
52+
return "GPL"
53+
54+
55+
if __name__ == "__main__":
56+
compile_to_ir("disksnoop.py", "disksnoop.ll", loglevel=logging.INFO)
57+
compile()

tests/c-form/disksnoop.bpf.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// disksnoop.bpf.c
2+
// eBPF program (compile with: clang -O2 -g -target bpf -c disksnoop.bpf.c -o disksnoop.bpf.o)
3+
4+
#include "vmlinux.h"
5+
#include <bpf/bpf_helpers.h>
6+
#include <bpf/bpf_core_read.h>
7+
8+
char LICENSE[] SEC("license") = "GPL";
9+
10+
struct {
11+
__uint(type, BPF_MAP_TYPE_HASH);
12+
__type(key, __u64);
13+
__type(value, __u64);
14+
__uint(max_entries, 10240);
15+
} start_map SEC(".maps");
16+
17+
/* kprobe: record start timestamp keyed by request pointer */
18+
SEC("kprobe/blk_mq_start_request")
19+
int trace_start(struct pt_regs *ctx)
20+
{
21+
/* request * is first arg */
22+
__u64 reqp = (__u64)(ctx->di);
23+
__u64 ts = bpf_ktime_get_ns();
24+
25+
bpf_map_update_elem(&start_map, &reqp, &ts, BPF_ANY);
26+
27+
// /* optional debug:
28+
bpf_printk("start: req=%llu ts=%llu\n", reqp, ts);
29+
// */
30+
return 0;
31+
}
32+
33+
/* completion: compute latency and print data_len, cmd_flags, latency_us */
34+
SEC("kprobe/blk_mq_end_request")
35+
int trace_completion(struct pt_regs *ctx)
36+
{
37+
__u64 reqp = (__u64)(ctx->di);
38+
__u64 *tsp;
39+
__u64 now_ns;
40+
__u64 delta_ns;
41+
__u64 delta_us = 0;
42+
bpf_printk("%lld", reqp);
43+
tsp = bpf_map_lookup_elem(&start_map, &reqp);
44+
if (!tsp)
45+
return 0;
46+
47+
now_ns = bpf_ktime_get_ns();
48+
delta_ns = now_ns - *tsp;
49+
delta_us = delta_ns / 1000;
50+
51+
/* read request fields using CO-RE; needs vmlinux.h/BTF */
52+
__u32 data_len = 0;
53+
__u32 cmd_flags = 0;
54+
55+
/* __data_len is usually a 32/64-bit; use CORE read to be safe */
56+
data_len = ( __u32 ) BPF_CORE_READ((struct request *)reqp, __data_len);
57+
cmd_flags = ( __u32 ) BPF_CORE_READ((struct request *)reqp, cmd_flags);
58+
59+
/* print: "<bytes> <flags_hex> <latency_us>" */
60+
bpf_printk("%u %x %llu\n", data_len, cmd_flags, delta_us);
61+
62+
/* remove from map */
63+
bpf_map_delete_elem(&start_map, &reqp);
64+
65+
return 0;
66+
}

0 commit comments

Comments
 (0)