Merge #14519: tests: add utility to easily profile node performance with perf
13782b8ba8
docs: add perf section to developer docs (James O'Beirne)58180b5fd4
tests: add utility to easily profile node performance with perf (James O'Beirne) Pull request description: Adds a context manager to easily (and selectively) profile node performance during functional test execution using `perf`. While writing some tests, I encountered some odd bitcoind slowness. I wrote up a utility (`TestNode.profile_with_perf`) that generates performance diagnostics for a node by running `perf` during the execution of a particular region of test code. `perf` usage is detailed in the excellent (and sadly unmerged) https://github.com/bitcoin/bitcoin/pull/12649; all due props to @eklitzke. ### Example ```python with node.profile_with_perf("large-msgs"): for i in range(200): node.p2p.send_message(some_large_msg) node.p2p.sync_with_ping() ``` This generates a perf data file in the test node's datadir (`/tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data`). Running `perf report` generates nice output about where the node spent most of its time while running that part of the test: ```bash $ perf report -i /tmp/testtxmpod0y/node0/node-0-TestName-large-msgs.perf.data --stdio \ | c++filt \ | less # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 135 of event 'cycles:pp' # Event count (approx.): 1458205679493582 # # Children Self Command Shared Object Symbol # ........ ........ ............... ................... ........................................................................................................................................................................................................................................................................ # 70.14% 0.00% bitcoin-net bitcoind [.] CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) | ---CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) 70.14% 0.00% bitcoin-net bitcoind [.] CNetMessage::readData(char const*, unsigned int) | ---CNetMessage::readData(char const*, unsigned int) CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) 35.52% 0.00% bitcoin-net bitcoind [.] std::vector<char, zero_after_free_allocator<char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<char*, std::vector<char, zero_after_free_allocator<char> > >, unsigned long, char const&) | ---std::vector<char, zero_after_free_allocator<char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<char*, std::vector<char, zero_after_free_allocator<char> > >, unsigned long, char const&) CNetMessage::readData(char const*, unsigned int) CNode::ReceiveMsgBytes(char const*, unsigned int, bool&) ... ``` Tree-SHA512: 9ac4ceaa88818d5eca00994e8e3c8ad42ae019550d6583972a0a4f7b0c4f61032e3d0c476b4ae58756bc5eb8f8015a19a7fc26c095bd588f31d49a37ed0c6b3e
This commit is contained in:
commit
5029e94f85
6 changed files with 211 additions and 4 deletions
test/functional/test_framework
|
@ -128,6 +128,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||
help="Attach a python debugger if test fails")
|
||||
parser.add_argument("--usecli", dest="usecli", default=False, action="store_true",
|
||||
help="use bitcoin-cli instead of RPC for all commands")
|
||||
parser.add_argument("--perf", dest="perf", default=False, action="store_true",
|
||||
help="profile running nodes with perf for the duration of the test")
|
||||
self.add_options(parser)
|
||||
self.options = parser.parse_args()
|
||||
|
||||
|
@ -202,11 +204,20 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||
node.cleanup_on_exit = False
|
||||
self.log.info("Note: bitcoinds were not stopped and may still be running")
|
||||
|
||||
if not self.options.nocleanup and not self.options.noshutdown and success != TestStatus.FAILED:
|
||||
should_clean_up = (
|
||||
not self.options.nocleanup and
|
||||
not self.options.noshutdown and
|
||||
success != TestStatus.FAILED and
|
||||
not self.options.perf
|
||||
)
|
||||
if should_clean_up:
|
||||
self.log.info("Cleaning up {} on exit".format(self.options.tmpdir))
|
||||
cleanup_tree_on_exit = True
|
||||
elif self.options.perf:
|
||||
self.log.warning("Not cleaning up dir {} due to perf data".format(self.options.tmpdir))
|
||||
cleanup_tree_on_exit = False
|
||||
else:
|
||||
self.log.warning("Not cleaning up dir %s" % self.options.tmpdir)
|
||||
self.log.warning("Not cleaning up dir {}".format(self.options.tmpdir))
|
||||
cleanup_tree_on_exit = False
|
||||
|
||||
if success == TestStatus.PASSED:
|
||||
|
@ -310,6 +321,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||
extra_conf=extra_confs[i],
|
||||
extra_args=extra_args[i],
|
||||
use_cli=self.options.usecli,
|
||||
start_perf=self.options.perf,
|
||||
))
|
||||
|
||||
def start_node(self, i, *args, **kwargs):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue