log_utxocache_flush.py
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)