Skip to content

Commit 913b714

Browse files
committed
Merge bitcoin/bitcoin#22902: tracing: utxocache tracepoints
2bc51c5 [tracing] tracepoints to utxocache add, spent and uncache (Arnab Sen) a26e8ee [tracing] tracepoint for utxocache flushes (Arnab Sen) Pull request description: This PR adds some of the UTXO set cache tracepoints proposed in bitcoin/bitcoin#20981 (comment). The first tracepoints were added in bitcoin#22006. tracepoint | description -- | -- `utxocache:flush` | Is called after the caches and indexes are flushed `utxocache:add` | when a new coin is added to the UTXO cache `utxocache:spent` | when a coin is spent `utxocache:uncache` | when coin is removed from the UTXO cache The tracepoints are further documented in `docs/tracing.md` and the usage is shown via the two newly added example scripts in `contrib/tracing/`. ACKs for top commit: laanwj: Code and documentation review ACK 2bc51c5 Tree-SHA512: d6b4f435d3260de4c48b36956f9311f65ab3b52cd03b1e0a4ba9cf47a774d8c4b31878e222b11e0ba5d233a68f7567f8a367b12a6392f688c10c11529341e837
2 parents a574f4a + 2bc51c5 commit 913b714

File tree

6 files changed

+327
-0
lines changed

6 files changed

+327
-0
lines changed

contrib/tracing/README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,62 @@ Histogram of block connection times in milliseconds (ms).
234234
[16, 32) 9 | |
235235
[32, 64) 4 | |
236236
```
237+
238+
### log_utxocache_flush.py
239+
240+
A BCC Python script to log the cache and index flushes. Based on the
241+
`utxocache:flush` tracepoint.
242+
243+
```bash
244+
$ python3 contrib/tracing/log_utxocache_flush.py ./src/bitcoind
245+
```
246+
247+
```
248+
Logging utxocache flushes. Ctrl-C to end...
249+
Duration (µs) Mode Coins Count Memory Usage Prune Full Flush
250+
0 PERIODIC 28484 3929.87 kB False False
251+
1 PERIODIC 28485 3930.00 kB False False
252+
0 PERIODIC 28489 3930.51 kB False False
253+
1 PERIODIC 28490 3930.64 kB False False
254+
0 PERIODIC 28491 3930.77 kB False False
255+
0 PERIODIC 28491 3930.77 kB False False
256+
0 PERIODIC 28496 3931.41 kB False False
257+
1 PERIODIC 28496 3931.41 kB False False
258+
0 PERIODIC 28497 3931.54 kB False False
259+
1 PERIODIC 28497 3931.54 kB False False
260+
1 PERIODIC 28499 3931.79 kB False False
261+
.
262+
.
263+
.
264+
53788 ALWAYS 30076 4136.27 kB False False
265+
7463 ALWAYS 0 245.84 kB False False
266+
```
267+
268+
### log_utxos.bt
269+
270+
A `bpftrace` script to log information about the coins that are added, spent, or
271+
uncached from the UTXO set. Based on the `utxocache:add`, `utxocache:spend` and
272+
`utxocache:uncache` tracepoints.
273+
274+
```bash
275+
$ bpftrace contrib/tracing/log_utxos.bt
276+
```
277+
278+
It should produce an output similar to the following.
279+
280+
```bash
281+
Attaching 4 probes...
282+
OP Outpoint Value Height Coinbase
283+
Added 6ba9ad857e1ef2eb2a2c94f06813c414c7ab273e3d6bd7ad64e000315a887e7c:1 10000 2094512 No
284+
Spent fa7dc4db56637a151f6649d8f26732956d1c5424c82aae400a83d02b2cc2c87b:0 182264897 2094512 No
285+
Added eeb2f099b1af6a2a12e6ddd2eeb16fc5968582241d7f08ba202d28b60ac264c7:0 10000 2094512 No
286+
Added eeb2f099b1af6a2a12e6ddd2eeb16fc5968582241d7f08ba202d28b60ac264c7:1 182254756 2094512 No
287+
Added a0c7f4ec9cccef2d89672a624a4e6c8237a17572efdd4679eea9e9ee70d2db04:0 10072679 2094513 Yes
288+
Spent 25e0df5cc1aeb1b78e6056bf403e5e8b7e41f138060ca0a50a50134df0549a5e:2 540 2094508 No
289+
Spent 42f383c04e09c26a2378272ec33aa0c1bf4883ca5ab739e8b7e06be5a5787d61:1 3848399 2007724 No
290+
Added f85e3b4b89270863a389395cc9a4123e417ab19384cef96533c6649abd6b0561:0 3788399 2094513 No
291+
Added f85e3b4b89270863a389395cc9a4123e417ab19384cef96533c6649abd6b0561:2 540 2094513 No
292+
Spent a05880b8c77971ed0b9f73062c7c4cdb0ff3856ab14cbf8bc481ed571cd34b83:1 5591281046 2094511 No
293+
Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:0 5589696005 2094513 No
294+
Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:1 1565556 2094513 No
295+
```
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env python3
2+
3+
import sys
4+
import ctypes
5+
from bcc import BPF, USDT
6+
7+
"""Example logging Bitcoin Core utxo set cache flushes utilizing
8+
the utxocache: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+
26+
// BPF perf buffer to push the data to user space.
27+
BPF_PERF_OUTPUT(flush);
28+
29+
int trace_flush(struct pt_regs *ctx) {
30+
struct data_t data = {};
31+
bpf_usdt_readarg(1, ctx, &data.duration);
32+
bpf_usdt_readarg(2, ctx, &data.mode);
33+
bpf_usdt_readarg(3, ctx, &data.coins_count);
34+
bpf_usdt_readarg(4, ctx, &data.coins_mem_usage);
35+
bpf_usdt_readarg(5, ctx, &data.is_flush_prune);
36+
bpf_usdt_readarg(5, ctx, &data.is_full_flush);
37+
flush.perf_submit(ctx, &data, sizeof(data));
38+
return 0;
39+
}
40+
"""
41+
42+
FLUSH_MODES = [
43+
'NONE',
44+
'IF_NEEDED',
45+
'PERIODIC',
46+
'ALWAYS'
47+
]
48+
49+
50+
class Data(ctypes.Structure):
51+
# define output data structure corresponding to struct data_t
52+
_fields_ = [
53+
("duration", ctypes.c_uint64),
54+
("mode", ctypes.c_uint32),
55+
("coins_count", ctypes.c_uint64),
56+
("coins_mem_usage", ctypes.c_uint64),
57+
("is_flush_prune", ctypes.c_bool),
58+
("is_full_flush", ctypes.c_bool)
59+
]
60+
61+
62+
def print_event(event):
63+
print("%-15d %-10s %-15d %-15s %-8s %-8s" % (
64+
event.duration,
65+
FLUSH_MODES[event.mode],
66+
event.coins_count,
67+
"%.2f kB" % (event.coins_mem_usage/1000),
68+
event.is_flush_prune,
69+
event.is_full_flush
70+
))
71+
72+
73+
def main(bitcoind_path):
74+
bitcoind_with_usdts = USDT(path=str(bitcoind_path))
75+
76+
# attaching the trace functions defined in the BPF program
77+
# to the tracepoints
78+
bitcoind_with_usdts.enable_probe(
79+
probe="flush", fn_name="trace_flush")
80+
b = BPF(text=program, usdt_contexts=[bitcoind_with_usdts])
81+
82+
def handle_flush(_, data, size):
83+
""" Coins Flush handler.
84+
Called each time coin caches and indexes are flushed."""
85+
event = ctypes.cast(data, ctypes.POINTER(Data)).contents
86+
print_event(event)
87+
88+
b["flush"].open_perf_buffer(handle_flush)
89+
print("Logging utxocache flushes. Ctrl-C to end...")
90+
print("%-15s %-10s %-15s %-15s %-8s %-8s" % ("Duration (µs)", "Mode",
91+
"Coins Count", "Memory Usage",
92+
"Prune", "Full Flush"))
93+
94+
while True:
95+
try:
96+
b.perf_buffer_poll()
97+
except KeyboardInterrupt:
98+
exit(0)
99+
100+
101+
if __name__ == "__main__":
102+
if len(sys.argv) < 2:
103+
print("USAGE: ", sys.argv[0], "path/to/bitcoind")
104+
exit(1)
105+
106+
path = sys.argv[1]
107+
main(path)

contrib/tracing/log_utxos.bt

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env bpftrace
2+
3+
/*
4+
5+
USAGE:
6+
7+
bpftrace contrib/tracing/log_utxos.bt
8+
9+
This script requires a 'bitcoind' binary compiled with eBPF support and the
10+
'utxochache' tracepoints. By default, it's assumed that 'bitcoind' is
11+
located in './src/bitcoind'. This can be modified in the script below.
12+
13+
NOTE: requires bpftrace v0.12.0 or above.
14+
*/
15+
16+
BEGIN
17+
{
18+
printf("%-7s %-71s %16s %7s %8s\n",
19+
"OP", "Outpoint", "Value", "Height", "Coinbase");
20+
}
21+
22+
/*
23+
Attaches to the 'utxocache:add' tracepoint and prints additions to the UTXO set cache.
24+
*/
25+
usdt:./src/bitcoind:utxocache:add
26+
{
27+
$txid = arg0;
28+
$index = (uint32)arg1;
29+
$height = (uint32)arg2;
30+
$value = (int64)arg3;
31+
$isCoinbase = arg4;
32+
33+
printf("Added ");
34+
$p = $txid + 31;
35+
unroll(32) {
36+
$b = *(uint8*)$p;
37+
printf("%02x", $b);
38+
$p-=1;
39+
}
40+
41+
printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" ));
42+
}
43+
44+
/*
45+
Attaches to the 'utxocache:spent' tracepoint and prints spents from the UTXO set cache.
46+
*/
47+
usdt:./src/bitcoind:utxocache:spent
48+
{
49+
$txid = arg0;
50+
$index = (uint32)arg1;
51+
$height = (uint32)arg2;
52+
$value = (int64)arg3;
53+
$isCoinbase = arg4;
54+
55+
printf("Spent ");
56+
$p = $txid + 31;
57+
unroll(32) {
58+
$b = *(uint8*)$p;
59+
printf("%02x", $b);
60+
$p-=1;
61+
}
62+
63+
printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" ));
64+
}
65+
66+
/*
67+
Attaches to the 'utxocache:uncache' tracepoint and uncache UTXOs from the UTXO set cache.
68+
*/
69+
usdt:./src/bitcoind:utxocache:uncache
70+
{
71+
$txid = arg0;
72+
$index = (uint32)arg1;
73+
$height = (uint32)arg2;
74+
$value = (int64)arg3;
75+
$isCoinbase = arg4;
76+
77+
printf("Uncache ");
78+
$p = $txid + 31;
79+
unroll(32) {
80+
$b = *(uint8*)$p;
81+
printf("%02x", $b);
82+
$p-=1;
83+
}
84+
85+
printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" ));
86+
}

doc/tracing.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,55 @@ 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+
127+
#### Tracepoint `utxocache:add`
128+
129+
It is called when a new coin is added to the UTXO cache.
130+
131+
Arguments passed:
132+
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
133+
2. Output index as `uint32`
134+
3. Block height the coin was added to the UTXO-set as `uint32`
135+
4. Value of the coin as `int64`
136+
5. If the coin is a coinbase as `bool`
137+
138+
#### Tracepoint `utxocache:spent`
139+
140+
It is called when a coin is spent from the UTXO cache.
141+
142+
Arguments passed:
143+
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
144+
2. Output index as `uint32`
145+
3. Block height the coin was spent, as `uint32`
146+
4. Value of the coin as `int64`
147+
5. If the coin is a coinbase as `bool`
148+
149+
#### Tracepoint `utxocache:uncache`
150+
151+
It is called when the UTXO with the given outpoint is removed from the cache.
152+
153+
Arguments passed:
154+
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
155+
2. Output index as `uint32`
156+
3. Block height the coin was uncached, as `uint32`
157+
4. Value of the coin as `int64`
158+
. If the coin is a coinbase as `bool`
159+
111160
## Adding tracepoints to Bitcoin Core
112161

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

src/coins.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <consensus/consensus.h>
88
#include <logging.h>
99
#include <random.h>
10+
#include <util/trace.h>
1011
#include <version.h>
1112

1213
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
@@ -95,6 +96,12 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
9596
it->second.coin = std::move(coin);
9697
it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
9798
cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
99+
TRACE5(utxocache, add,
100+
outpoint.hash.data(),
101+
(uint32_t)outpoint.n,
102+
(uint32_t)coin.nHeight,
103+
(int64_t)coin.out.nValue,
104+
(bool)coin.IsCoinBase());
98105
}
99106

100107
void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) {
@@ -120,6 +127,12 @@ bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
120127
CCoinsMap::iterator it = FetchCoin(outpoint);
121128
if (it == cacheCoins.end()) return false;
122129
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
130+
TRACE5(utxocache, spent,
131+
outpoint.hash.data(),
132+
(uint32_t)outpoint.n,
133+
(uint32_t)it->second.coin.nHeight,
134+
(int64_t)it->second.coin.out.nValue,
135+
(bool)it->second.coin.IsCoinBase());
123136
if (moveout) {
124137
*moveout = std::move(it->second.coin);
125138
}
@@ -231,6 +244,12 @@ void CCoinsViewCache::Uncache(const COutPoint& hash)
231244
CCoinsMap::iterator it = cacheCoins.find(hash);
232245
if (it != cacheCoins.end() && it->second.flags == 0) {
233246
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
247+
TRACE5(utxocache, uncache,
248+
hash.hash.data(),
249+
(uint32_t)hash.n,
250+
(uint32_t)it->second.coin.nHeight,
251+
(int64_t)it->second.coin.out.nValue,
252+
(bool)it->second.coin.IsCoinBase());
234253
cacheCoins.erase(it);
235254
}
236255
}

src/validation.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,13 @@ 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);
21042111
}
21052112
if (full_flush_completed) {
21062113
// Update best block in wallet (so we can detect restored wallets).

0 commit comments

Comments
 (0)