Skip to content

Commit a26e8ee

Browse files
committed
[tracing] tracepoint for utxocache flushes
Signed-off-by: Arnab Sen <[email protected]>
1 parent 4f8b1f8 commit a26e8ee

File tree

3 files changed

+129
-0
lines changed

3 files changed

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

doc/tracing.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,22 @@ Arguments passed:
108108
5. SigOps in the Block (excluding coinbase SigOps) `uint64`
109109
6. Time it took to connect the Block in microseconds (µs) as `uint64`
110110

111+
### Context `utxocache`
112+
113+
#### Tracepoint `utxocache:flush`
114+
115+
Is called *after* the caches and indexes are flushed depending on the mode
116+
`CChainState::FlushStateToDisk` is called with.
117+
118+
Arguments passed:
119+
1. Duration in microseconds as `int64`
120+
2. Flush state mode as `uint32`. It's an enumerator class with values `0`
121+
(`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`ALWAYS`)
122+
3. Number of coins flushed as `uint64`
123+
4. Memory usage in bytes as `uint64`
124+
5. If the flush was pruned as `bool`
125+
6. If it was full flush as `bool`
126+
111127
## Adding tracepoints to Bitcoin Core
112128

113129
To add a new tracepoint, `#include <util/trace.h>` in the compilation unit where

src/validation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,14 @@ bool CChainState::FlushStateToDisk(
21012101
nLastFlush = nNow;
21022102
full_flush_completed = true;
21032103
}
2104+
TRACE6(utxocache, flush,
2105+
(int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs)
2106+
(u_int32_t)mode,
2107+
(u_int64_t)coins_count,
2108+
(u_int64_t)coins_mem_usage,
2109+
(bool)fFlushForPrune,
2110+
(bool)fDoFullFlush
2111+
);
21042112
}
21052113
if (full_flush_completed) {
21062114
// Update best block in wallet (so we can detect restored wallets).

0 commit comments

Comments
 (0)