tests: Improve runtime of some tests when --enable-debug #26656

pull achow101 wants to merge 6 commits into bitcoin:master from achow101:faster-test-runner-when-debug changing 7 files +110 −70
  1. achow101 commented at 1:38 am on December 8, 2022: member

    When configured with --enable-debug, many tests become dramatically slower. These slow downs are particularly noticed in tests that generate a lot of blocks in separate calls, make a lot of RPC calls, or send a lot of data from the test framework’s P2P connection. This PR aims to improve the runtime of some of the slower tests and improve the overall runtime of the test runner. This has improved the runtime of the test runner from ~400s to ~140s on my computer.

    The slowest test by far was wallet_import_rescan.py. This was taking ~320s. Most of that time was spent waiting for blocks to be mined and then synced to the other nodes. It was generating a new block for every new transaction it was creating in a setup loop. However it is not necessary to have one tx per block. By mining a block only every 10 txs, the runtime is improved to ~61s.

    The second slowest test was feature_fee_estimation.py. This test spends most of its time waiting for RPCs to respond. I was able to improve its runtime by batching RPC requests. This has improved the runtime from ~201s to ~140s.

    In feature_taproot.py, the test was constructing a Python CScript using a very large list of OP_CHECKSIGs. The constructor for the Python implementation of CScript was iterating this list in order to create a bytes from it even though a bytes could be created from it without iterating. By making the bytes before passing it into the constructor, we are able to improve this test’s runtime from ~131s to ~106s.

    Although interface_rpc.py was not typically a slow test, I found that it would occasionally have a super long runtime. It typically takes ~7s, but I have observed it taking >400s to run on occasion. This longer runtime occurs more often when --enable-debug. This long runtime was caused by the “exceeding work queue” test which is really just trying to trigger a race condition. In this test, it would create a few threads and try an RPC in a loop in the hopes that eventually one of the RPCs would be added to the work queue while another was processing. It used getrpcinfo for this, but this function is fairly fast. I believe what was happening was that with --enable-debug, all of the code for receiving the RPC would often take longer to run than the RPC itself, so the majority of the requests would succeed, until we got lucky after 10’s of thousands of requests. By changing this to use a slow RPC, the race condition can be triggered more reliably, and much sooner as well. I’ve used waitfornewblock with a 500ms timeout. This improves the runtime to ~3s consistently.

    The last test I’ve changed was rpc_packages.py. This test was one of the higher runtime variability tests. The main source of this variation appears to be waiting for the test node to relay a transaction to the test framework’s P2P connection. By whitelisting that peer, the variability is reduced to nearly 0.

    Lastly, I’ve reordered the tests in test_runner.py to account for the slower runtimes when configured with --enable-debug. Some of the slow tests I’ve looked at were listed as being fast which was causing overall test_runner.py runtime to be extended. This change makes the test runner’s runtime be bounded by the slowest test (currently feature_fee_estimation.py with my usual config (-j 60).

  2. DrahtBot commented at 1:38 am on December 8, 2022: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK willcl-ark
    Concept ACK fanquake

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #25634 (wallet, tests: Expand and test when the blank wallet flag should be un/set by achow101)
    • #25380 (Detect and ignore transactions that were CPFP’d in the fee estimator by darosior)
    • #24897 ([Draft / POC] Silent Payments by w0xlt)
    • #24748 (test/BIP324: functional tests for v2 P2P encryption by stratospher)
    • #24545 (BIP324: Enable v2 P2P encrypted transport by dhruv)
    • #21422 (Add feerate histogram to getmempoolinfo by kiminuo)
    • #20892 (tests: Run both descriptor and legacy tests within a single test invocation by achow101)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  3. DrahtBot added the label Tests on Dec 8, 2022
  4. achow101 force-pushed on Dec 8, 2022
  5. in test/functional/wallet_import_rescan.py:241 in 5dac98e823 outdated
    239+                conf_height = self.nodes[0].getblockcount() + 1
    240             variant.sent_amount = get_rand_amount()
    241             variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
    242-            self.generate(self.nodes[0], 1)  # Generate one block for each send
    243-            variant.confirmation_height = self.nodes[0].getblockcount()
    244+            variant.confirmation_height = conf_height;
    


    maflcko commented at 9:40 am on December 8, 2022:
    0test/functional/wallet_import_rescan.py:241:54: E703 statement ends with a semicolon
    

    achow101 commented at 5:01 pm on December 8, 2022:
    Fixed
  6. in test/functional/rpc_packages.py:32 in 5dac98e823 outdated
    28@@ -29,6 +29,7 @@ class RPCPackagesTest(BitcoinTestFramework):
    29     def set_test_params(self):
    30         self.num_nodes = 1
    31         self.setup_clean_chain = True
    32+        self.extra_args = [["-whitelist=127.0.0.1"]]
    


    maflcko commented at 9:40 am on December 8, 2022:
    nit: Could only add the needed permission flag? and add a comment?

    achow101 commented at 5:02 pm on December 8, 2022:
    Done
  7. maflcko approved
  8. maflcko commented at 9:42 am on December 8, 2022: member
    lgtm
  9. fanquake commented at 2:55 pm on December 8, 2022: member
    Concept ACK - seeing significant speedup when running the modified tests under --enable-debug. test/functional/test_runner.py wallet_import_rescan.py drops from 418s to 106s.
  10. achow101 force-pushed on Dec 8, 2022
  11. achow101 force-pushed on Dec 8, 2022
  12. DrahtBot added the label Needs rebase on Dec 9, 2022
  13. tests: reduce number of generated blocks for wallet_import_rescan
    Generating blocks is slow, especially when --enable-debug. There is no
    need to generate a new block for each transaction, so avoid doing that
    to improve this test's runtime.
    4ad7272f8b
  14. tests: Use batched RPC in feature_fee_estimation
    feature_fee_estimation has a lot of loops that hit the RPC many times in
    succession in order to setup scenarios. Using batched requests for these
    can reduce the test's runtime without effecting the test's behavior.
    544cbf776c
  15. tests: Initialize sigops draining script with bytes in feature_taproot
    The sigops draining script in feature_taproot's block_submit was
    initialized with a list that would end up always being iterated by
    CScript's constructor. Since this list is very large, a lot of time
    would be wasted. By creating and passing a bytes object initialized from
    that list, we can avoid this iteration and dramatically improve the
    runtime of feature_taproot.
    6c872d5e65
  16. tests: Use waitfornewblock for work queue test in interface_rpc
    The work queue exceeded test in interface_rpc.py would repeatedly call
    an RPC until the error was achieved. However hitting this error is
    dependent on the processing speed of the computer and the optimization
    level of the binary. Configurations that result in slower processing
    would result in the RPC used being processed before the error could be
    hit, resulting the test's runtime having a high variance.
    
    Switching the RPC to waitfornewblock allows it to run in a much more
    consistent time that is still fairly fast. waitfornewblock forces
    the RPC server to allocate a thread and wait, occupying a spot in the
    work queue. This is perfect for this test because the slower the RPC,
    the more likely we will achieve the race condition necessary to pass the
    test. Using a timeout of 500 ms appears to work reliably without causing
    the test to take too long.
    8c20796aac
  17. tests: Whitelist test p2p connection in rpc_packages
    test_submit_child_with_parents creates a p2p connection which waits for
    the node to announce transactions to it. By whitelisting this
    connection, we can reduce the amount of time spent waiting for this
    announcement which improves the test runtime and runtime variance.
    ff6c9fe027
  18. tests: Reorder longer running tests in test_runner
    The logest running tests should be at the front of the list in
    test_runner.py. Since compiling with --enable-debug can have a
    significant effect on test runtime, the order is based on the runtime
    with that option configured.
    1647a11f39
  19. achow101 force-pushed on Dec 9, 2022
  20. DrahtBot removed the label Needs rebase on Dec 9, 2022
  21. willcl-ark commented at 10:26 am on December 15, 2022: contributor

    Concept ACK!

    This is great to see and is something that has been bothering me for quite some time.

    Without this PR tests for me were taking 268 seconds to run, where:

    • wallet_import_rescan 227s,
    • feature_taproot 179s,
    • feature_fee_estimation 267s and
    • feature-block 167s.

    After this PR my total test time reduced to 171 seconds, where:

    • wallet_import_rescan 49s!,
    • feature_taproot 148s,
    • feature_fee_estimation 164s and
    • feature_block 170s.

    This leaves me with the following tests taking over 1 minute runtime:

     0 cat times | sort -k 3 -n -t "|" -r
     1feature_block.py                                       |  Passed  | 170 s
     2feature_fee_estimation.py                              |  Passed  | 164 s
     3feature_taproot.py                                     |  Passed  | 148 s
     4mempool_updatefromblock.py                             |  Passed  | 112 s
     5p2p_segwit.py                                          |  Passed  | 107 s
     6p2p_blockfilters.py                                    |  Passed  | 100 s
     7feature_assumevalid.py                                 |  Passed  | 99 s
     8wallet_taproot.py --descriptors                        |  Passed  | 92 s
     9p2p_headers_sync_with_minchainwork.py                  |  Passed  | 92 s
    10wallet_avoidreuse.py --legacy-wallet                   |  Passed  | 87 s
    11p2p_invalid_messages.py                                |  Passed  | 85 s
    12wallet_groups.py --descriptors                         |  Passed  | 76 s
    13wallet_avoidreuse.py --descriptors                     |  Passed  | 76 s
    14feature_maxuploadtarget.py                             |  Passed  | 71 s
    15mining_getblocktemplate_longpoll.py                    |  Passed  | 69 s
    16wallet_groups.py --legacy-wallet                       |  Passed  | 63 s
    17wallet_fundrawtransaction.py --descriptors             |  Passed  | 60 s
    
  22. willcl-ark approved
  23. willcl-ark commented at 8:16 pm on December 16, 2022: contributor

    ACK 1647a11

    The final tests to finish for me with --enable-debug and 50 jobs are generally:

     0245/255 - feature_coinstatsindex.py passed, Duration: 25 s
     1246/255 - p2p_headers_sync_with_minchainwork.py passed, Duration: 93 s
     2247/255 - wallet_taproot.py --descriptors passed, Duration: 94 s
     3248/255 - feature_config_args.py passed, Duration: 35 s
     4249/255 - p2p_blockfilters.py passed, Duration: 105 s
     5250/255 - feature_assumevalid.py passed, Duration: 105 s
     6251/255 - p2p_segwit.py passed, Duration: 107 s
     7252/255 - mempool_updatefromblock.py passed, Duration: 116 s
     8253/255 - feature_taproot.py passed, Duration: 155 s
     9254/255 - feature_block.py passed, Duration: 175 s
    10255/255 - feature_fee_estimation.py passed, Duration: 209 s
    

    So the new ordering of the list feels pretty good.

  24. maflcko merged this on Dec 19, 2022
  25. maflcko closed this on Dec 19, 2022

  26. sidhujag referenced this in commit b16daeb34e on Dec 19, 2022
  27. bitcoin locked this on Dec 19, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-03 13:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me