Skip to content
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

Merged
merged 4 commits into from Apr 10, 2018
Merged

Run unit tests in parallel #12926

merged 4 commits into from Apr 10, 2018

Conversation

sipa
Copy link
Member

@sipa sipa commented Apr 9, 2018

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.

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" "{}/*"
Copy link
Contributor

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

Copy link
Member Author

@sipa sipa Apr 9, 2018

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).

@@ -0,0 +1,6 @@
#!/bin/bash

PROCESSES=4
Copy link
Member

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?

Copy link
Member Author

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.

@@ -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..."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/.py/.sh/ :-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

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" "{}/*"
Copy link
Contributor

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@practicalswift
Copy link
Contributor

Strong concept ACK.

I like the straightforwardness and compactness of this solution vs. the previous attempt at parallelism.

Do you have any speedup measurements?

@@ -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..."
Copy link
Contributor

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are unrelated tests.

Copy link
Contributor

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 :-)

@sipa
Copy link
Member Author

sipa commented Apr 9, 2018

@practicalswift 48 minutes (when lucky) to 23 minutes for the win32 test in Travis.

@maflcko
Copy link
Member

maflcko commented Apr 9, 2018

48 minutes (when lucky) to 23 minutes for the win32 test in Travis.

🎉

@maflcko
Copy link
Member

maflcko commented Apr 9, 2018

utACK e764ddcab74755274856cf217cdeb83e2d5d9bc0

@practicalswift
Copy link
Contributor

practicalswift commented Apr 9, 2018

@sipa Wow! That will help us get rid of those nasty win32 Travis timeouts! :-)

@practicalswift
Copy link
Contributor

practicalswift commented Apr 9, 2018

utACK e764ddcab74755274856cf217cdeb83e2d5d9bc0

My shell nits on this PR would have been communicated automatically (and hopefully fixed pre human review) if shellcheck linting was enabled in Travis. Please help review #12871 if you find shellcheck valuable :-)

@theuni
Copy link
Member

theuni commented Apr 9, 2018

48 minutes (when lucky) to 23 minutes for the win32 test in Travis.

Nice! Reviewing.

@theuni
Copy link
Member

theuni commented Apr 9, 2018

cory@Macbook:~/dev/bitcoin/src$ sort -R
sort: invalid option -- R

:(

@practicalswift
Copy link
Contributor

practicalswift commented Apr 9, 2018

@theuni Oh, that's bad! What version of sort are you using?

FWIW:

$ sort --version
2.3-Apple (99)
$ (echo A; echo B) | sort -R
B
A
$ (echo A; echo B) | sort -R
A
B

@sipa
Copy link
Member Author

sipa commented Apr 9, 2018

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.

@theuni
Copy link
Member

theuni commented Apr 9, 2018

@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.

@practicalswift
Copy link
Contributor

practicalswift commented Apr 9, 2018

@sipa What about using awk?

$ (echo A; echo B) | awk 'BEGIN { srand(); } { printf("%.10f %s\n", rand(), $0); }' | \
      sort | cut -f2- -d' '
A
B
$ (echo A; echo B) | awk 'BEGIN { srand(); } { printf("%.10f %s\n", rand(), $0); }' | \
      sort | cut -f2- -d' '
B
A

@sipa
Copy link
Member Author

sipa commented Apr 9, 2018

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.

@fanquake fanquake added the Tests label Apr 9, 2018
@practicalswift
Copy link
Contributor

utACK aa9be23327db7a12760f250e7261b5f6be6f9de0

@sipa
Copy link
Member Author

sipa commented Apr 9, 2018

Why the reordering of Travis builds? I'm not opposing it – just curious :-)

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.

@theuni
Copy link
Member

theuni commented Apr 10, 2018

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 :)

@sipa
Copy link
Member Author

sipa commented Apr 10, 2018

Totally changed the approach, integrating everything into makefiles rather than creating external runner scripts (thanks @theuni). See updated PR description.

@jamesob
Copy link
Member

jamesob commented Apr 10, 2018

Tested ACK 7ef9cd8

Seeing a mild improvement locally 🎉

201804_parunit

make -j 4 check 282.46s user 14.91s system 252% cpu 1:57.88 total

master

make -j 4 check 193.71s user 10.10s system 129% cpu 2:37.31 total

@laanwj
Copy link
Member

laanwj commented Apr 10, 2018

Totally changed the approach, integrating everything into makefiles rather than creating external runner scripts (thanks @theuni). See updated PR description.

Heh you implemented my IRC joke. I'm surprised that this works out to an elegant approach.
But it's really neat - will test.

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!

@practicalswift
Copy link
Contributor

The new version is even better!

Nice to avoid having two settings for concurrency (make -j and shell script variable).

@kallewoof
Copy link
Member

kallewoof commented Apr 10, 2018

Seeing about 2x improvement. Tested ACK

master:         make -j10 check   97.74s user 52.14s system 138% cpu 1:48.19  total
201804_parunit: make -j10 check  109.30s user 16.73s system 219% cpu   57.482 total

@jonasschnelli
Copy link
Contributor

Tested ACK 7ef9cd8

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

@laanwj laanwj merged commit 7ef9cd8 into bitcoin:master Apr 10, 2018
laanwj added a commit that referenced this pull request Apr 10, 2018
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
scravy added a commit to dtr-org/unit-e that referenced this pull request Apr 1, 2019
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>
scravy added a commit to dtr-org/unit-e that referenced this pull request Apr 1, 2019
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>
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Apr 13, 2021
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
xdustinface added a commit to xdustinface/dash that referenced this pull request Apr 14, 2021
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Apr 14, 2021
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Apr 15, 2021
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Apr 17, 2021
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
kwvg pushed a commit to kwvg/dash that referenced this pull request Apr 23, 2021
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
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants