mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-04 02:36:16 +00:00
Since #28280, the cost of a non-wiping sync of the UTXO cache is only proportional to the number of dirty entries, rather than proportional to the size of the entire cache. Because of that, there is no reason to perform a wiping flush in case the contents of the cache is still useful. Split the FlushStateMode::ALWAYS mode into a FORCE_SYNC (non-wiping) and a FORCE_FLUSH (wiping), and then use the former in scantxoutset, gettxoutsetinfo, snapshot creation. Co-authored-by: l0rinc <pap.lorinc@gmail.com> Co-authored-by: cedwies <141683552+cedwies@users.noreply.github.com>
110 lines
2.9 KiB
Python
Executable File
110 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2021-present The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
import sys
|
|
import ctypes
|
|
from bcc import BPF, USDT
|
|
|
|
"""Example logging Bitcoin Core utxo set cache flushes utilizing
|
|
the utxocache:flush tracepoint."""
|
|
|
|
# USAGE: ./contrib/tracing/log_utxocache_flush.py <pid of bitcoind>
|
|
|
|
# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into
|
|
# a sandboxed Linux kernel VM.
|
|
program = """
|
|
# include <uapi/linux/ptrace.h>
|
|
|
|
struct data_t
|
|
{
|
|
u64 duration;
|
|
u32 mode;
|
|
u64 coins_count;
|
|
u64 coins_mem_usage;
|
|
bool is_flush_for_prune;
|
|
};
|
|
|
|
// BPF perf buffer to push the data to user space.
|
|
BPF_PERF_OUTPUT(flush);
|
|
|
|
int trace_flush(struct pt_regs *ctx) {
|
|
struct data_t data = {};
|
|
bpf_usdt_readarg(1, ctx, &data.duration);
|
|
bpf_usdt_readarg(2, ctx, &data.mode);
|
|
bpf_usdt_readarg(3, ctx, &data.coins_count);
|
|
bpf_usdt_readarg(4, ctx, &data.coins_mem_usage);
|
|
bpf_usdt_readarg(5, ctx, &data.is_flush_for_prune);
|
|
flush.perf_submit(ctx, &data, sizeof(data));
|
|
return 0;
|
|
}
|
|
"""
|
|
|
|
FLUSH_MODES = [
|
|
'NONE',
|
|
'IF_NEEDED',
|
|
'PERIODIC',
|
|
'FORCE_FLUSH',
|
|
'FORCE_SYNC',
|
|
]
|
|
|
|
|
|
class Data(ctypes.Structure):
|
|
# define output data structure corresponding to struct data_t
|
|
_fields_ = [
|
|
("duration", ctypes.c_uint64),
|
|
("mode", ctypes.c_uint32),
|
|
("coins_count", ctypes.c_uint64),
|
|
("coins_mem_usage", ctypes.c_uint64),
|
|
("is_flush_for_prune", ctypes.c_bool)
|
|
]
|
|
|
|
|
|
def print_event(event):
|
|
print("%-15d %-12s %-15d %-15s %-8s" % (
|
|
event.duration,
|
|
FLUSH_MODES[event.mode],
|
|
event.coins_count,
|
|
"%.2f kB" % (event.coins_mem_usage/1000),
|
|
event.is_flush_for_prune
|
|
))
|
|
|
|
|
|
def main(pid):
|
|
print(f"Hooking into bitcoind with pid {pid}")
|
|
bitcoind_with_usdts = USDT(pid=int(pid))
|
|
|
|
# attaching the trace functions defined in the BPF program
|
|
# to the tracepoints
|
|
bitcoind_with_usdts.enable_probe(
|
|
probe="flush", fn_name="trace_flush")
|
|
b = BPF(text=program, usdt_contexts=[bitcoind_with_usdts])
|
|
|
|
def handle_flush(_, data, size):
|
|
""" Coins Flush handler.
|
|
Called each time coin caches and indexes are flushed."""
|
|
event = ctypes.cast(data, ctypes.POINTER(Data)).contents
|
|
print_event(event)
|
|
|
|
b["flush"].open_perf_buffer(handle_flush)
|
|
print("Logging utxocache flushes. Ctrl-C to end...")
|
|
print("%-15s %-12s %-15s %-15s %-8s" % ("Duration (µs)", "Mode",
|
|
"Coins Count", "Memory Usage",
|
|
"Flush for Prune"))
|
|
|
|
while True:
|
|
try:
|
|
b.perf_buffer_poll()
|
|
except KeyboardInterrupt:
|
|
exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) != 2:
|
|
print("USAGE: ", sys.argv[0], "<pid of bitcoind>")
|
|
exit(1)
|
|
|
|
pid = sys.argv[1]
|
|
main(pid)
|