New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Run unit tests in parallel #12926
Run unit tests in parallel #12926
Conversation
test/util/bitcoin-unit-tests.sh
Outdated
PROCESSES=4 | ||
DIR="$(dirname "$0")" | ||
|
||
cat $DIR/../../src/{,wallet/,qt/}test/*.cpp | fgrep BOOST_FIXTURE_TEST_SUITE | cut -d '(' -f 2 | cut -d ',' -f 1 | shuf | xargs -n 1 -P $PROCESSES -I "{}" -- bash "$DIR/bitcoin-unit-test.sh" "{}/*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Double quote to prevent globbing and word splitting :-)
cat "$DIR"/../../src/{,wallet/,qt/}test/*.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed (the files are now passed in from Makefile, as suggested by Cory).
test/util/bitcoin-unit-tests.sh
Outdated
@@ -0,0 +1,6 @@ | |||
#!/bin/bash | |||
|
|||
PROCESSES=4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense just to do xargs ... -P 0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like hardcoding the parallellism here, but with -P 0
my system will run all tests simultaneously - that's a bit scary w.r.t. resource usage.
src/Makefile.test.include
Outdated
@@ -151,6 +150,8 @@ bitcoin_test_clean : FORCE | |||
rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) | |||
|
|||
check-local: | |||
@echo "Running test/util/bitcoin-unit-tests.py..." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/.py/.sh/
:-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
test/util/bitcoin-unit-tests.sh
Outdated
PROCESSES=4 | ||
DIR="$(dirname "$0")" | ||
|
||
cat $DIR/../../src/{,wallet/,qt/}test/*.cpp | fgrep BOOST_FIXTURE_TEST_SUITE | cut -d '(' -f 2 | cut -d ',' -f 1 | shuf | xargs -n 1 -P $PROCESSES -I "{}" -- bash "$DIR/bitcoin-unit-test.sh" "{}/*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shuf
is not available under OS X by default. Is sort -R
sufficiently portable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Strong concept ACK. I like the straightforwardness and compactness of this solution vs. the previous attempt at parallelism. Do you have any speedup measurements? |
src/Makefile.test.include
Outdated
@@ -151,6 +150,8 @@ bitcoin_test_clean : FORCE | |||
rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) | |||
|
|||
check-local: | |||
@echo "Running unit tests..." | |||
@$(top_builddir)/test/util/bitcoin-unit-tests.sh $(BITCOIN_TESTS) | |||
@echo "Running test/util/bitcoin-util-test.py..." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentionally keeping bitcoin-util-test.py
in there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are unrelated tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, ofc – my bad. Sorry :-)
@practicalswift 48 minutes (when lucky) to 23 minutes for the win32 test in Travis. |
🎉 |
utACK e764ddcab74755274856cf217cdeb83e2d5d9bc0 |
@sipa Wow! That will help us get rid of those nasty win32 Travis timeouts! :-) |
utACK e764ddcab74755274856cf217cdeb83e2d5d9bc0 My shell nits on this PR would have been communicated automatically (and hopefully fixed pre human review) if |
Nice! Reviewing. |
cory@Macbook:~/dev/bitcoin/src$ sort -R
sort: invalid option -- R :( |
@theuni Oh, that's bad! What version of FWIW:
|
If the random sorting is an issue we can just sort alphabetically. This would also let us do things like indicate which tests are big in their name for example, to put them earlier in the list. |
@sipa The profile dir for tests is defined as: pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000))); As GetTime() has only second-level resolution, we may want to bump up the rand range a bit. |
@sipa What about using
|
Removed random sorting (made it alphabetical), reordered the Travis tests from slow to fast (except the doc test which goes still first for fast-fail), and increased the test temp directory entropy. |
utACK aa9be23327db7a12760f250e7261b5f6be6f9de0 |
In order to maximally exploit parallelism (of Travis jobs) you generally want to start the longest-running ones to start first. Sometimes not all jobs are started simultaneously (based on other load), in which case this matters in reducing the overall wall clock time spent between pushing and getting a final Travis result. |
Reviewers: Sorry for the interruption, see the new approach here. I was discussing this earlier with @sipa and wanted to see if we could get this to work while preserving the make jobs. It turned out to be substantially simpler than what was in the PR already, and I guess @sipa doesn't hate it too much :) |
Totally changed the approach, integrating everything into makefiles rather than creating external runner scripts (thanks @theuni). See updated PR description. |
Tested ACK 7ef9cd8 Seeing a mild improvement locally 🎉 201804_parunit
master
|
Heh you implemented my IRC joke. I'm surprised that this works out to an elegant approach. After already having built all, including the test executables, and commenting out secp256k1 and univalue tests (which take up significant time and aren't relevant here): user@ishtar:~/src/bitcoin/build$ time make -j10 check
real 1m6.551s
user 1m8.388s
sys 0m2.392s
(12926)user@ishtar:~/src/bitcoin/build$ time make -j10 check
real 0m23.140s
user 1m4.544s
sys 0m8.616s Almost three times speed-up (on an 8-core machine). Nice! |
The new version is even better! Nice to avoid having two settings for concurrency ( |
Seeing about 2x improvement. Tested ACK
|
Tested ACK 7ef9cd8 OSX 10.13.4 (2.9 GHz Intel Core i7): This PR:
versus master:
|
7ef9cd8 Increase entropy in test temp directory name (Pieter Wuille) f6dfb0f Reorder travis builds (Pieter Wuille) 156db42 tests: run tests in parallel (Cory Fields) 66f3255 tests: split up actual tests and helper files (Cory Fields) Pull request description: This runs the unit tests (`src/test/test_bitcoin`) in 4 separate simultaneous processes, significantly speeding up some Travis runs (over 2x for win32). This uses an approach by @theuni that relies on `make` as the mechanism for distributing tests over processes (through `-j`). For every test .cpp file, we search for `BOOST_FIXTURE_TEST_SUITE` or `BOOST_AUTO_TEST_SUITE`, and then invoke the test binary for just that suite (using `-t`). The (verbose) output is stored in a temporary file, and only shown in the case of failure. Some makefile reshuffling is necessary to avoid trying to run tests from `src/test/test_bitcoin.cpp` for example, which contains framework/utility code but no real tests. Finally, order the Travis jobs from slow to fast (apart from the arm/doc job which goes first, for fast failure). This should help reducing the total wall clock time before opening a PR and finishing Travis, in case where not all jobs are started simultaneously. This is an alternative to #12831. Tree-SHA512: 9f82eb4ade14ac859618da533c7d9df2aa9f5592a076dcc4939beeffd109eda33f7d5480d8f50c0d8b23bf3099759e9f3a2d4c78efb5b66b04569b39b354c185
Currently unit tests can not be run in parallel. This prevents us from speeding up ci builds (see bitcoin/bitcoin#12926, #865) and won't work with the updated build definitions from bitcoin 0.17 (#860). This is a regression which was introduced in #793. This pull request fixes #861. The problem is that the `StateDB` component does something actively when being initialized (not something a component should do), which is to access disk and so on, which can fail. Since there is a `UnitEInjector` for every `BasicTestingSetup` running the unit tests in parallel creates a database _in the same directory_ per unit tests suite which clashes and breaks and throws and aborts and dies. This can be prevented by using an in-memory database, but the problem shifts: How to get that configuration in? I did not want to expose this as a user-definable setting and also not as a chain parameter, so these two configuration options are not available. Which is why I created `UnitEInjectorConfiguration`. This is something which should not be necessary as usually you would not expose the same module as in production in unit tests but use a subset or just the mocked version, but since the rest of bitcoin is not in well-defined components and accesses them using `GetComponent` a global injector has to be available in some tests. The change ultimately does not affect the prod version of things, but the tests, which inject a different `UnitEInjectorConfiguration`. I made this a `struct` rather then just a flag `unit_tests` such that it is extensible in case we have other cases like this. In order to make the injector be able to access fields from it's own instance in the definition of a component I altered the definition of `UNMANAGED_COMPONENT` a bit. I would like to point out that these initialization issues would also have happened with an Application class (#723), as that is exactly what `UnitEInjector` is, just you would inject things manually. Signed-off-by: Julian Fleischer <julian@thirdhash.com>
This is a backport of bitcoin/bitcoin#12926, which unveils how master is currently broken as reported in #861 Here is the original description: > This runs the unit tests (`src/test/test_bitcoin`) in 4 separate simultaneous processes, significantly speeding up some Travis runs (over 2x for win32). > > This uses an approach by @theuni that relies on `make` as the mechanism for distributing tests over processes (through `-j`). For every test .cpp file, we search for `BOOST_FIXTURE_TEST_SUITE` or `BOOST_AUTO_TEST_SUITE`, and then invoke the test binary for just that suite (using `-t`). The (verbose) output is stored in a temporary file, and only shown in the case of failure. > > Some makefile reshuffling is necessary to avoid trying to run tests from `src/test/test_bitcoin.cpp` for example, which contains framework/utility code but no real tests. For bitcoin this improved in quite a nice speedup for builds (especially the Win32 unit test only one): > OSX 10.13.4 (2.9 GHz Intel Core i7): `time make -j5 V=1 check` > > This PR: > > ``` > real 1m28.438s > user 3m42.053s > sys 0m45.473s > ``` > > versus master: > > ``` > real 3m5.687s > user 2m57.911s > sys 0m46.390s > ``` Signed-off-by: Julian Fleischer <julian@thirdhash.com>
7ef9cd8 Increase entropy in test temp directory name (Pieter Wuille) f6dfb0f Reorder travis builds (Pieter Wuille) 156db42 tests: run tests in parallel (Cory Fields) 66f3255 tests: split up actual tests and helper files (Cory Fields) Pull request description: This runs the unit tests (`src/test/test_bitcoin`) in 4 separate simultaneous processes, significantly speeding up some Travis runs (over 2x for win32). This uses an approach by @theuni that relies on `make` as the mechanism for distributing tests over processes (through `-j`). For every test .cpp file, we search for `BOOST_FIXTURE_TEST_SUITE` or `BOOST_AUTO_TEST_SUITE`, and then invoke the test binary for just that suite (using `-t`). The (verbose) output is stored in a temporary file, and only shown in the case of failure. Some makefile reshuffling is necessary to avoid trying to run tests from `src/test/test_bitcoin.cpp` for example, which contains framework/utility code but no real tests. Finally, order the Travis jobs from slow to fast (apart from the arm/doc job which goes first, for fast failure). This should help reducing the total wall clock time before opening a PR and finishing Travis, in case where not all jobs are started simultaneously. This is an alternative to bitcoin#12831. Tree-SHA512: 9f82eb4ade14ac859618da533c7d9df2aa9f5592a076dcc4939beeffd109eda33f7d5480d8f50c0d8b23bf3099759e9f3a2d4c78efb5b66b04569b39b354c185
7ef9cd8 Increase entropy in test temp directory name (Pieter Wuille) f6dfb0f Reorder travis builds (Pieter Wuille) 156db42 tests: run tests in parallel (Cory Fields) 66f3255 tests: split up actual tests and helper files (Cory Fields) Pull request description: This runs the unit tests (`src/test/test_bitcoin`) in 4 separate simultaneous processes, significantly speeding up some Travis runs (over 2x for win32). This uses an approach by @theuni that relies on `make` as the mechanism for distributing tests over processes (through `-j`). For every test .cpp file, we search for `BOOST_FIXTURE_TEST_SUITE` or `BOOST_AUTO_TEST_SUITE`, and then invoke the test binary for just that suite (using `-t`). The (verbose) output is stored in a temporary file, and only shown in the case of failure. Some makefile reshuffling is necessary to avoid trying to run tests from `src/test/test_bitcoin.cpp` for example, which contains framework/utility code but no real tests. Finally, order the Travis jobs from slow to fast (apart from the arm/doc job which goes first, for fast failure). This should help reducing the total wall clock time before opening a PR and finishing Travis, in case where not all jobs are started simultaneously. This is an alternative to bitcoin#12831. Tree-SHA512: 9f82eb4ade14ac859618da533c7d9df2aa9f5592a076dcc4939beeffd109eda33f7d5480d8f50c0d8b23bf3099759e9f3a2d4c78efb5b66b04569b39b354c185
7ef9cd8 Increase entropy in test temp directory name (Pieter Wuille) f6dfb0f Reorder travis builds (Pieter Wuille) 156db42 tests: run tests in parallel (Cory Fields) 66f3255 tests: split up actual tests and helper files (Cory Fields) Pull request description: This runs the unit tests (`src/test/test_bitcoin`) in 4 separate simultaneous processes, significantly speeding up some Travis runs (over 2x for win32). This uses an approach by @theuni that relies on `make` as the mechanism for distributing tests over processes (through `-j`). For every test .cpp file, we search for `BOOST_FIXTURE_TEST_SUITE` or `BOOST_AUTO_TEST_SUITE`, and then invoke the test binary for just that suite (using `-t`). The (verbose) output is stored in a temporary file, and only shown in the case of failure. Some makefile reshuffling is necessary to avoid trying to run tests from `src/test/test_bitcoin.cpp` for example, which contains framework/utility code but no real tests. Finally, order the Travis jobs from slow to fast (apart from the arm/doc job which goes first, for fast failure). This should help reducing the total wall clock time before opening a PR and finishing Travis, in case where not all jobs are started simultaneously. This is an alternative to bitcoin#12831. Tree-SHA512: 9f82eb4ade14ac859618da533c7d9df2aa9f5592a076dcc4939beeffd109eda33f7d5480d8f50c0d8b23bf3099759e9f3a2d4c78efb5b66b04569b39b354c185
This runs the unit tests (
src/test/test_bitcoin
) in 4 separate simultaneous processes, significantly speeding up some Travis runs (over 2x for win32).This uses an approach by @theuni that relies on
make
as the mechanism for distributing tests over processes (through-j
). For every test .cpp file, we search forBOOST_FIXTURE_TEST_SUITE
orBOOST_AUTO_TEST_SUITE
, and then invoke the test binary for just that suite (using-t
). The (verbose) output is stored in a temporary file, and only shown in the case of failure.Some makefile reshuffling is necessary to avoid trying to run tests from
src/test/test_bitcoin.cpp
for example, which contains framework/utility code but no real tests.Finally, order the Travis jobs from slow to fast (apart from the arm/doc job which goes first, for fast failure). This should help reducing the total wall clock time before opening a PR and finishing Travis, in case where not all jobs are started simultaneously.
This is an alternative to #12831.