log_utxocache_flush.py raw
1 #!/usr/bin/env python3
2 # Copyright (c) 2021-2022 The Limenka 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 Limenka utxo set cache flushes utilizing
11 the utxocache:flush tracepoint."""
12
13 # USAGE: ./contrib/tracing/log_utxocache_flush.py path/to/limenkad
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 'ALWAYS'
49 ]
50
51
52 class Data(ctypes.Structure):
53 # define output data structure corresponding to struct data_t
54 _fields_ = [
55 ("duration", ctypes.c_uint64),
56 ("mode", ctypes.c_uint32),
57 ("coins_count", ctypes.c_uint64),
58 ("coins_mem_usage", ctypes.c_uint64),
59 ("is_flush_for_prune", ctypes.c_bool)
60 ]
61
62
63 def print_event(event):
64 print("%-15d %-10s %-15d %-15s %-8s" % (
65 event.duration,
66 FLUSH_MODES[event.mode],
67 event.coins_count,
68 "%.2f kB" % (event.coins_mem_usage/1000),
69 event.is_flush_for_prune
70 ))
71
72
73 def main(pid):
74 print(f"Hooking into limenkad with pid {pid}")
75 limenkad_with_usdts = USDT(pid=int(pid))
76
77 # attaching the trace functions defined in the BPF program
78 # to the tracepoints
79 limenkad_with_usdts.enable_probe(
80 probe="flush", fn_name="trace_flush")
81 b = BPF(text=program, usdt_contexts=[limenkad_with_usdts])
82
83 def handle_flush(_, data, size):
84 """ Coins Flush handler.
85 Called each time coin caches and indexes are flushed."""
86 event = ctypes.cast(data, ctypes.POINTER(Data)).contents
87 print_event(event)
88
89 b["flush"].open_perf_buffer(handle_flush)
90 print("Logging utxocache flushes. Ctrl-C to end...")
91 print("%-15s %-10s %-15s %-15s %-8s" % ("Duration (µs)", "Mode",
92 "Coins Count", "Memory Usage",
93 "Flush for Prune"))
94
95 while True:
96 try:
97 b.perf_buffer_poll()
98 except KeyboardInterrupt:
99 exit(0)
100
101
102 if __name__ == "__main__":
103 if len(sys.argv) != 2:
104 print("USAGE: ", sys.argv[0], "<pid of limenkad>")
105 exit(1)
106
107 pid = sys.argv[1]
108 main(pid)
109