log_utxocache_flush.py raw
1 #!/usr/bin/env python3
2 # Copyright (c) 2021-present The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 import sys
7 import ctypes
8 from bcc import BPF, USDT
9
10 """Example logging Bitcoin Core utxo set cache flushes utilizing
11 the utxocache:flush tracepoint."""
12
13 # USAGE: ./contrib/tracing/log_utxocache_flush.py <pid of bitcoind>
14
15 # BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into
16 # a sandboxed Linux kernel VM.
17 program = """
18 # include <uapi/linux/ptrace.h>
19
20 struct data_t
21 {
22 u64 duration;
23 u32 mode;
24 u64 coins_count;
25 u64 coins_mem_usage;
26 bool is_flush_for_prune;
27 };
28
29 // BPF perf buffer to push the data to user space.
30 BPF_PERF_OUTPUT(flush);
31
32 int trace_flush(struct pt_regs *ctx) {
33 struct data_t data = {};
34 bpf_usdt_readarg(1, ctx, &data.duration);
35 bpf_usdt_readarg(2, ctx, &data.mode);
36 bpf_usdt_readarg(3, ctx, &data.coins_count);
37 bpf_usdt_readarg(4, ctx, &data.coins_mem_usage);
38 bpf_usdt_readarg(5, ctx, &data.is_flush_for_prune);
39 flush.perf_submit(ctx, &data, sizeof(data));
40 return 0;
41 }
42 """
43
44 FLUSH_MODES = [
45 'NONE',
46 'IF_NEEDED',
47 'PERIODIC',
48 'FORCE_FLUSH',
49 'FORCE_SYNC',
50 ]
51
52
53 class Data(ctypes.Structure):
54 # define output data structure corresponding to struct data_t
55 _fields_ = [
56 ("duration", ctypes.c_uint64),
57 ("mode", ctypes.c_uint32),
58 ("coins_count", ctypes.c_uint64),
59 ("coins_mem_usage", ctypes.c_uint64),
60 ("is_flush_for_prune", ctypes.c_bool)
61 ]
62
63
64 def print_event(event):
65 print("%-15d %-12s %-15d %-15s %-8s" % (
66 event.duration,
67 FLUSH_MODES[event.mode],
68 event.coins_count,
69 "%.2f kB" % (event.coins_mem_usage/1000),
70 event.is_flush_for_prune
71 ))
72
73
74 def main(pid):
75 print(f"Hooking into bitcoind with pid {pid}")
76 bitcoind_with_usdts = USDT(pid=int(pid))
77
78 # attaching the trace functions defined in the BPF program
79 # to the tracepoints
80 bitcoind_with_usdts.enable_probe(
81 probe="flush", fn_name="trace_flush")
82 b = BPF(text=program, usdt_contexts=[bitcoind_with_usdts])
83
84 def handle_flush(_, data, size):
85 """ Coins Flush handler.
86 Called each time coin caches and indexes are flushed."""
87 event = ctypes.cast(data, ctypes.POINTER(Data)).contents
88 print_event(event)
89
90 b["flush"].open_perf_buffer(handle_flush)
91 print("Logging utxocache flushes. Ctrl-C to end...")
92 print("%-15s %-12s %-15s %-15s %-8s" % ("Duration (µs)", "Mode",
93 "Coins Count", "Memory Usage",
94 "Flush for Prune"))
95
96 while True:
97 try:
98 b.perf_buffer_poll()
99 except KeyboardInterrupt:
100 exit(0)
101
102
103 if __name__ == "__main__":
104 if len(sys.argv) != 2:
105 print("USAGE: ", sys.argv[0], "<pid of bitcoind>")
106 exit(1)
107
108 pid = sys.argv[1]
109 main(pid)
110