|
| 1 | +Example scripts for User-space, Statically Defined Tracing (USDT) |
| 2 | +================================================================= |
| 3 | + |
| 4 | +This directory contains scripts showcasing User-space, Statically Defined |
| 5 | +Tracing (USDT) support for Bitcoin Core on Linux using. For more information on |
| 6 | +USDT support in Bitcoin Core see the [USDT documentation]. |
| 7 | + |
| 8 | +[USDT documentation]: ../../doc/tracing.md |
| 9 | + |
| 10 | + |
| 11 | +Examples for the two main eBPF front-ends, [bpftrace] and |
| 12 | +[BPF Compiler Collection (BCC)], with support for USDT, are listed. BCC is used |
| 13 | +for complex tools and daemons and `bpftrace` is preferred for one-liners and |
| 14 | +shorter scripts. |
| 15 | + |
| 16 | +[bpftrace]: https://github.com/iovisor/bpftrace |
| 17 | +[BPF Compiler Collection (BCC)]: https://github.com/iovisor/bcc |
| 18 | + |
| 19 | + |
| 20 | +To develop and run bpftrace and BCC scripts you need to install the |
| 21 | +corresponding packages. See [installing bpftrace] and [installing BCC] for more |
| 22 | +information. For development there exist a [bpftrace Reference Guide], a |
| 23 | +[BCC Reference Guide], and a [bcc Python Developer Tutorial]. |
| 24 | + |
| 25 | +[installing bpftrace]: https://github.com/iovisor/bpftrace/blob/master/INSTALL.md |
| 26 | +[installing BCC]: https://github.com/iovisor/bcc/blob/master/INSTALL.md |
| 27 | +[bpftrace Reference Guide]: https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md |
| 28 | +[BCC Reference Guide]: https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md |
| 29 | +[bcc Python Developer Tutorial]: https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md |
| 30 | + |
| 31 | +## Examples |
| 32 | + |
| 33 | +The bpftrace examples contain a relative path to the `bitcoind` binary. By |
| 34 | +default, the scripts should be run from the repository-root and assume a |
| 35 | +self-compiled `bitcoind` binary. The paths in the examples can be changed, for |
| 36 | +example, to point to release builds if needed. See the |
| 37 | +[Bitcoin Core USDT documentation] on how to list available tracepoints in your |
| 38 | +`bitcoind` binary. |
| 39 | + |
| 40 | +[Bitcoin Core USDT documentation]: ../../doc/tracing.md#listing-available-tracepoints |
| 41 | + |
| 42 | +**WARNING: eBPF programs require root privileges to be loaded into a Linux |
| 43 | +kernel VM. This means the bpftrace and BCC examples must be executed with root |
| 44 | +privileges. Make sure to carefully review any scripts that you run with root |
| 45 | +privileges first!** |
| 46 | + |
| 47 | +### log_p2p_traffic.bt |
| 48 | + |
| 49 | +A bpftrace script logging information about inbound and outbound P2P network |
| 50 | +messages. Based on the `net:inbound_message` and `net:outbound_message` |
| 51 | +tracepoints. |
| 52 | + |
| 53 | +By default, `bpftrace` limits strings to 64 bytes due to the limited stack size |
| 54 | +in the eBPF VM. For example, Tor v3 addresses exceed the string size limit which |
| 55 | +results in the port being cut off during logging. The string size limit can be |
| 56 | +increased with the `BPFTRACE_STRLEN` environment variable (`BPFTRACE_STRLEN=70` |
| 57 | +works fine). |
| 58 | + |
| 59 | +``` |
| 60 | +$ bpftrace contrib/tracing/log_p2p_traffic.bt |
| 61 | +``` |
| 62 | + |
| 63 | +Output |
| 64 | +``` |
| 65 | +outbound 'ping' msg to peer 11 (outbound-full-relay, [2a02:b10c:f747:1:ef:fake:ipv6:addr]:8333) with 8 bytes |
| 66 | +inbound 'pong' msg from peer 11 (outbound-full-relay, [2a02:b10c:f747:1:ef:fake:ipv6:addr]:8333) with 8 bytes |
| 67 | +inbound 'inv' msg from peer 16 (outbound-full-relay, XX.XX.XXX.121:8333) with 37 bytes |
| 68 | +outbound 'getdata' msg to peer 16 (outbound-full-relay, XX.XX.XXX.121:8333) with 37 bytes |
| 69 | +inbound 'tx' msg from peer 16 (outbound-full-relay, XX.XX.XXX.121:8333) with 222 bytes |
| 70 | +outbound 'inv' msg to peer 9 (outbound-full-relay, faketorv3addressa2ufa6odvoi3s77j4uegey0xb10csyfyve2t33curbyd.onion:8333) with 37 bytes |
| 71 | +outbound 'inv' msg to peer 7 (outbound-full-relay, XX.XX.XXX.242:8333) with 37 bytes |
| 72 | +… |
| 73 | +``` |
| 74 | + |
| 75 | +### p2p_monitor.py |
| 76 | + |
| 77 | +A BCC Python script using curses for an interactive P2P message monitor. Based |
| 78 | +on the `net:inbound_message` and `net:outbound_message` tracepoints. |
| 79 | + |
| 80 | +Inbound and outbound traffic is listed for each peer together with information |
| 81 | +about the connection. Peers can be selected individually to view recent P2P |
| 82 | +messages. |
| 83 | + |
| 84 | +``` |
| 85 | +$ python3 contrib/tracing/p2p_monitor.py ./src/bitcoind |
| 86 | +``` |
| 87 | + |
| 88 | +Lists selectable peers and traffic and connection information. |
| 89 | +``` |
| 90 | + P2P Message Monitor |
| 91 | + Navigate with UP/DOWN or J/K and select a peer with ENTER or SPACE to see individual P2P messages |
| 92 | +
|
| 93 | + PEER OUTBOUND INBOUND TYPE ADDR |
| 94 | + 0 46 398 byte 61 1407590 byte block-relay-only XX.XX.XXX.196:8333 |
| 95 | + 11 1156 253570 byte 3431 2394924 byte outbound-full-relay XXX.X.XX.179:8333 |
| 96 | + 13 3425 1809620 byte 1236 305458 byte inbound XXX.X.X.X:60380 |
| 97 | + 16 1046 241633 byte 1589 1199220 byte outbound-full-relay 4faketorv2pbfu7x.onion:8333 |
| 98 | + 19 577 181679 byte 390 148951 byte outbound-full-relay kfake4vctorjv2o2.onion:8333 |
| 99 | + 20 11 1248 byte 13 1283 byte block-relay-only [2600:fake:64d9:b10c:4436:aaaa:fe:bb]:8333 |
| 100 | + 21 11 1248 byte 13 1299 byte block-relay-only XX.XXX.X.155:8333 |
| 101 | + 22 5 103 byte 1 102 byte feeler XX.XX.XXX.173:8333 |
| 102 | + 23 11 1248 byte 12 1255 byte block-relay-only XX.XXX.XXX.220:8333 |
| 103 | + 24 3 103 byte 1 102 byte feeler XXX.XXX.XXX.64:8333 |
| 104 | +… |
| 105 | +``` |
| 106 | + |
| 107 | +Showing recent P2P messages between our node and a selected peer. |
| 108 | + |
| 109 | +``` |
| 110 | + ---------------------------------------------------------------------- |
| 111 | + | PEER 16 (4faketorv2pbfu7x.onion:8333) | |
| 112 | + | OUR NODE outbound-full-relay PEER | |
| 113 | + | <--- sendcmpct (9 bytes) | |
| 114 | + | inv (37 byte) ---> | |
| 115 | + | <--- ping (8 bytes) | |
| 116 | + | pong (8 byte) ---> | |
| 117 | + | inv (37 byte) ---> | |
| 118 | + | <--- addr (31 bytes) | |
| 119 | + | inv (37 byte) ---> | |
| 120 | + | <--- getheaders (1029 bytes) | |
| 121 | + | headers (1 byte) ---> | |
| 122 | + | <--- feefilter (8 bytes) | |
| 123 | + | <--- pong (8 bytes) | |
| 124 | + | <--- headers (82 bytes) | |
| 125 | + | <--- addr (30003 bytes) | |
| 126 | + | inv (1261 byte) ---> | |
| 127 | + | … | |
| 128 | +
|
| 129 | +``` |
| 130 | + |
| 131 | +### log_raw_p2p_msgs.py |
| 132 | + |
| 133 | +A BCC Python script showcasing eBPF and USDT limitations when passing data |
| 134 | +larger than about 32kb. Based on the `net:inbound_message` and |
| 135 | +`net:outbound_message` tracepoints. |
| 136 | + |
| 137 | +Bitcoin P2P messages can be larger than 32kb (e.g. `tx`, `block`, ...). The |
| 138 | +eBPF VM's stack is limited to 512 bytes, and we can't allocate more than about |
| 139 | +32kb for a P2P message in the eBPF VM. The **message data is cut off** when the |
| 140 | +message is larger than MAX_MSG_DATA_LENGTH (see script). This can be detected |
| 141 | +in user-space by comparing the data length to the message length variable. The |
| 142 | +message is cut off when the data length is smaller than the message length. |
| 143 | +A warning is included with the printed message data. |
| 144 | + |
| 145 | +Data is submitted to user-space (i.e. to this script) via a ring buffer. The |
| 146 | +throughput of the ring buffer is limited. Each p2p_message is about 32kb in |
| 147 | +size. In- or outbound messages submitted to the ring buffer in rapid |
| 148 | +succession fill the ring buffer faster than it can be read. Some messages are |
| 149 | +lost. BCC prints: `Possibly lost 2 samples` on lost messages. |
| 150 | + |
| 151 | + |
| 152 | +``` |
| 153 | +$ python3 contrib/tracing/log_raw_p2p_msgs.py ./src/bitcoind |
| 154 | +``` |
| 155 | + |
| 156 | +``` |
| 157 | +Logging raw P2P messages. |
| 158 | +Messages larger that about 32kb will be cut off! |
| 159 | +Some messages might be lost! |
| 160 | + outbound msg 'inv' from peer 4 (outbound-full-relay, XX.XXX.XX.4:8333) with 253 bytes: 0705000000be2245c8f844c9f763748e1a7… |
| 161 | +… |
| 162 | +Warning: incomplete message (only 32568 out of 53552 bytes)! inbound msg 'tx' from peer 32 (outbound-full-relay, XX.XXX.XXX.43:8333) with 53552 bytes: 020000000001fd3c01939c85ad6756ed9fc… |
| 163 | +… |
| 164 | +Possibly lost 2 samples |
| 165 | +``` |
| 166 | + |
| 167 | +### connectblock_benchmark.bt |
| 168 | + |
| 169 | +A `bpftrace` script to benchmark the `ConnectBlock()` function during, for |
| 170 | +example, a blockchain re-index. Based on the `validation:block_connected` USDT |
| 171 | +tracepoint. |
| 172 | + |
| 173 | +The script takes three positional arguments. The first two arguments, the start, |
| 174 | +and end height indicate between which blocks the benchmark should be run. The |
| 175 | +third acts as a duration threshold in milliseconds. When the `ConnectBlock()` |
| 176 | +function takes longer than the threshold, information about the block, is |
| 177 | +printed. For more details, see the header comment in the script. |
| 178 | + |
| 179 | +By default, `bpftrace` limits strings to 64 bytes due to the limited stack size |
| 180 | +in the kernel VM. Block hashes as zero-terminated hex strings are 65 bytes which |
| 181 | +exceed the string limit. The string size limit can be set to 65 bytes with the |
| 182 | +environment variable `BPFTRACE_STRLEN`. |
| 183 | + |
| 184 | +The following command can be used to benchmark, for example, `ConnectBlock()` |
| 185 | +between height 20000 and 38000 on SigNet while logging all blocks that take |
| 186 | +longer than 25ms to connect. |
| 187 | + |
| 188 | +``` |
| 189 | +$ BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt 20000 38000 25 |
| 190 | +``` |
| 191 | + |
| 192 | +In a different terminal, starting Bitcoin Core in SigNet mode and with |
| 193 | +re-indexing enabled. |
| 194 | + |
| 195 | +``` |
| 196 | +$ ./src/bitcoind -signet -reindex |
| 197 | +``` |
| 198 | + |
| 199 | +This produces the following output. |
| 200 | +``` |
| 201 | +Attaching 5 probes... |
| 202 | +ConnectBlock Benchmark between height 20000 and 38000 inclusive |
| 203 | +Logging blocks taking longer than 25 ms to connect. |
| 204 | +Starting Connect Block Benchmark between height 20000 and 38000. |
| 205 | +BENCH 39 blk/s 59 tx/s 59 inputs/s 20 sigops/s (height 20038) |
| 206 | +Block 20492 (000000f555653bb05e2f3c6e79925e01a20dd57033f4dc7c354b46e34735d32b) 20 tx 2319 ins 2318 sigops took 38 ms |
| 207 | +BENCH 1840 blk/s 2117 tx/s 4478 inputs/s 2471 sigops/s (height 21879) |
| 208 | +BENCH 1816 blk/s 4972 tx/s 4982 inputs/s 125 sigops/s (height 23695) |
| 209 | +BENCH 2095 blk/s 2890 tx/s 2910 inputs/s 152 sigops/s (height 25790) |
| 210 | +BENCH 1684 blk/s 3979 tx/s 4053 inputs/s 288 sigops/s (height 27474) |
| 211 | +BENCH 1155 blk/s 3216 tx/s 3252 inputs/s 115 sigops/s (height 28629) |
| 212 | +BENCH 1797 blk/s 2488 tx/s 2503 inputs/s 111 sigops/s (height 30426) |
| 213 | +BENCH 1849 blk/s 6318 tx/s 6569 inputs/s 12189 sigops/s (height 32275) |
| 214 | +BENCH 946 blk/s 20209 tx/s 20775 inputs/s 83809 sigops/s (height 33221) |
| 215 | +Block 33406 (0000002adfe4a15cfcd53bd890a89bbae836e5bb7f38bac566f61ad4548c87f6) 25 tx 2045 ins 2090 sigops took 29 ms |
| 216 | +Block 33687 (00000073231307a9828e5607ceb8156b402efe56747271a4442e75eb5b77cd36) 52 tx 1797 ins 1826 sigops took 26 ms |
| 217 | +BENCH 582 blk/s 21581 tx/s 27673 inputs/s 60345 sigops/s (height 33803) |
| 218 | +BENCH 1035 blk/s 19735 tx/s 19776 inputs/s 51355 sigops/s (height 34838) |
| 219 | +Block 35625 (0000006b00b347390c4768ea9df2655e9ff4b120f29d78594a2a702f8a02c997) 20 tx 3374 ins 3371 sigops took 49 ms |
| 220 | +BENCH 887 blk/s 17857 tx/s 22191 inputs/s 24404 sigops/s (height 35725) |
| 221 | +Block 35937 (000000d816d13d6e39b471cd4368db60463a764ba1f29168606b04a22b81ea57) 75 tx 3943 ins 3940 sigops took 61 ms |
| 222 | +BENCH 823 blk/s 16298 tx/s 21031 inputs/s 18440 sigops/s (height 36548) |
| 223 | +Block 36583 (000000c3e260556dbf42968aae3f904dba8b8c1ff96a6f6e3aa5365d2e3ad317) 24 tx 2198 ins 2194 sigops took 34 ms |
| 224 | +Block 36700 (000000b3b173de9e65a3cfa738d976af6347aaf83fa17ab3f2a4d2ede3ddfac4) 73 tx 1615 ins 1611 sigops took 31 ms |
| 225 | +Block 36832 (0000007859578c02c1ac37dabd1b9ec19b98f350b56935f5dd3a41e9f79f836e) 34 tx 1440 ins 1436 sigops took 26 ms |
| 226 | +BENCH 613 blk/s 16718 tx/s 25074 inputs/s 23022 sigops/s (height 37161) |
| 227 | +Block 37870 (000000f5c1086291ba2d943fb0c3bc82e71c5ee341ee117681d1456fbf6c6c38) 25 tx 1517 ins 1514 sigops took 29 ms |
| 228 | +BENCH 811 blk/s 16031 tx/s 20921 inputs/s 18696 sigops/s (height 37972) |
| 229 | +
|
| 230 | +Took 14055 ms to connect the blocks between height 20000 and 38000. |
| 231 | +
|
| 232 | +Histogram of block connection times in milliseconds (ms). |
| 233 | +@durations: |
| 234 | +[0] 16838 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| |
| 235 | +[1] 882 |@@ | |
| 236 | +[2, 4) 236 | | |
| 237 | +[4, 8) 23 | | |
| 238 | +[8, 16) 9 | | |
| 239 | +[16, 32) 9 | | |
| 240 | +[32, 64) 4 | | |
| 241 | +``` |
0 commit comments