Why are my Minitest tests running in parallel?
I recently realized that my Minitest tests can run in parallel. All I had to do was
require "minitest/hell"
and so I did. Unfortunately, my tests run exactly the same as before. Everything passes, and it takes just as long as usual. I checked htop
while running my test suite and only one core is used.
I set a breakpoint in a random test to check if the tests were actually running in parallel:
(byebug) Minitest :: Test.test_order : parallel
So what's going on?
My first guess was that Minitest counts the number of processor cores when choosing the number of processes to spawn. I had multiple physical processors (in a virtual machine) but only 1 core per processor. I changed my VPS to have two physical processors, each with 4 cores, and my tests are still not running 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
source to share
Minitest uses threads, not processes, to run the test in parallel.
Since the MRI (Standard Ruby Interpreter) has a global interpreter lock, only one thread can execute at a time. Therefore your tests do not run in parallel when using an MRI.
You can run tests in parallel using a Ruby interpreter that supports parallel threads like JRuby or Rubinius.
source to share
severin's answer that MRI cannot be performed in parallel due to GIL. (Disclaimer: I wrote the article he links to.) The language is a little vague in many emails, but you can read this article for a very simple description.
If you're still interested in running tests in parallel and can't change Ruby interpreters, look at the parallel_tests gem for an alternative, albeit with some limitations.
source to share
For tests to run in parallel, you need a Ruby version that allows parallel execution (like JRuby), or you can use simple shell commands to run a few minimal runs.
For example, use gnu parallel:
find test -type f | parallel --dry-run bundle exec rake test TEST={}
(The flag dry-run
so you can see what happens before it runs, omit the flag dry-run
, when you're satisfied, the commands will do what you want.)
The exec and rake overhead is very high. The main benefit of parallel execution is to make sure your tests run correctly - that is, the main benefit is not speed. If you are using parallel, you probably want to try spork
which one the finished application supports.
source to share