Reputation: 59333
I just recently figured out that my Minitest test cases can run in parallel. All I had to do was
require "minitest/hell"
and so I did. Unfortunately, my tests run exactly like before. Everything passes and it takes exactly as much time as it usually does. I checked htop
while running my test suite, and only one core is utilized.
I set a breakpoint in a random test to check if the tests were actually set to run in parallel:
(byebug) Minitest::Test.test_order :parallel
So what's going on?
My first assumption was that Minitest counts the amount of CPU cores when deciding how many processes to spawn. I had multiple physical processors (in a virtual machine) but just 1 core per processor. I have changed my VPS to having two physical processors, each with 4 cores, and my tests still aren't being run in parallel.
$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 Thread(s) per core: 1 Core(s) per socket: 4 Socket(s): 2 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 62 Stepping: 4 CPU MHz: 2600.000 BogoMIPS: 5200.00 Hypervisor vendor: VMware Virtualization type: full L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 20480K NUMA node0 CPU(s): 0-7
Upvotes: 4
Views: 3698
Reputation: 1289
severin's answer about MRI not being able to execute in parallel because of the GIL is correct. (Disclaimer: I wrote the article he links to.) The language gets a little fuzzy in many writeups, but you can read this article for a very straightforward description.
If you're still interested in running tests in parallel and can't change Ruby interpreters, take a look at the parallel_tests gem as an alternative for doing that, albeit with some limitations.
Upvotes: 3
Reputation: 35453
To run tests in parallel, you either need a Ruby version that enables parallel execution (e.g. JRuby), or you can use simple shell commands to launch multiple minitest runs.
For example, use gnu parallel:
find test -type f | parallel --dry-run bundle exec rake test TEST={}
(The dry-run
flag is so you can see what's happening before you run it; omit the dry-run
flag when you're satisfied the commands will do what you want.)
The overhead of bundle exec and rake are very high. The core advantage of the parallel execution is to ensure your tests behave correctly -- i.e. the core advantage is not speed. If you use parallel, you will likely want to try spork
which keeps a pre-warmed app ready.
Upvotes: 2
Reputation: 10268
Minitest uses threads and not processes for parallel test execution.
Since MRI (the standard Ruby interpreter) has a Global Interpreter Lock only one thread can be executed at a time. Therefore your tests do not run in parallel when using MRI.
You can get you tests to run in parallel by using a Ruby interpreter that supports concurrent threads like JRuby or Rubinius.
Read this article for more details.
Upvotes: 6