RubyMine high CPU, no background tasks

RubyMine, being an IDE and not light editor, is expected to hog some CPU. But after each RSpec run, the CPU usage jumps to 300 % for several minutes. If I do fast iteration on specs, then this high CPU usage is constant and heats up my Mac, causing fan noise and of course drains battery.

Screen Shot 2017-08-23 at 17.13.19.png

Googling around for solution did not find anything, especially as there are not background processes running. I even tried profiling the app to see if it gives any  ideas (hint: it did not).

One support ticket for WebStorm though tipped me off and turned out that the culprit are Inspections – those little yellow or red markers around right gutter that tell you when your code smells or is outright broken.


Handpick the Inspections

Screen Shot 2017-08-23 at 17.11.58.png

Navigate to Preferences > Editor > Inspections and go through the long list. Unfortunately RubyMine does not tell you which Inspection it currently runs, so it is trial and error to find out what causes the slowness.

In my case there were a lot of “Double quotes” as well as whitespace whitespace warnings, but growing tired of not finding any low hanging fruits, I decided to just disable almost all warnings and left only error-level Inspections.

Now, after running specs, RubyMine CPU usage jumps to around 100 % for only a little while and then returns to normal.


A note on tabs

RubyMine has default setting of allowing only a handful of tabs open at the same time. Increasing this limit affects, among other things, the Inspections performance too as these are run for all tabs after every spec run. (Don’t ask me why JetBrains thinks this is necessary.)

Faster RubyMine RSpec with Vagrant

I use RubyMine and Vagrant for my Rails development and run RSpec specs from RubyMine for convenience. The problem is that every time I start rspec, it takes a few seconds to connect to the box, before actually doing anything. This is especially annoying when running single spec which should be fast.

vagrant ssh is slow to connect

% time vagrant ssh -c whoami
Connection to closed.
2,57s user 0,73s system 82% cpu 3,984 total

That’s probably because vagrant ssh-config takes most of that time to sort things out:

% time vagrant ssh-config > /dev/null
2,53s user 0,79s system 77% cpu 4,269 total

When researching this issue, some people mention DNS or other Vagrant provider specific issues, but they complain of an order of magnitude slower (30-40 sec) connection. Might just be that I have everything set up correctly and it just takes that much time to get the configuration.

But what this means is that if you run RSpecs from RubyMine, they are slow to start, because RubyMine executes vagrant ssh-config every time (RUBY-16186).

Direct SSH to the rescue

Fortunately, direct SSH with keypair authentication is blazing fast:

time ssh vagrant@ -i ~/.ssh/parallels_key whoami
0,01s user 0,01s system 21% cpu 0,114 total

So, to take advantage of that you need to:

  1. set up SSH configuration
  2. configure RubyMine remote ruby over SSH, not Vagrant
  3. Add RubyMine helpers to RUBYLIB to be able to start persistent spring instance.

Set up SSH configuration

Vagrant might be using their vagrant_insecure_private_key for the SSH or, in my case, Parallels custom keypair, as I don’t use VirtualBox. So run this command to find out which key is in use:

% vagrant ssh-config
Host default
  User vagrant
  Port 22
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/laas/project/.vagrant/machines/default/parallels/private_key
  IdentitiesOnly yes
  LogLevel FATAL

Now we know the IP address of the box and what keyfile is used. For easier access, I symlinked the key file to my .ssh folder:

ln -s IdentityFile /Users/laas/project/.vagrant/machines/default/parallels/private_key ~/.ssh/parallels_key

You can try out SSH connection:

ssh vagrant@ -i ~/.ssh/parallels_key whoami

Configure RubyMine to use remote ruby over SSH

Next step is to configure new Ruby SDK for the project. Open Preferences and navigate Language & Frameworks > Ruby SDK and Gems, click + button and pick New remote…. Then fill in the data as shown in the screenshot and when closing dialog, ensure that the newly added ruby is selected as active.

Configure Remote Ruby Interpreter

Now specs should still run (but take several seconds every time to boot up Rails, because spring is shut down after every connection).

Note: I actually use landrush to manage development boxes names and so I can configure remote ruby with a domain name and not worry about IP address changes when recreating the devbox.

Add RubyMine helpers to RUBYLIB

The problem above is that spring closes itself down every time SSH connection is closed. One could start a long-running spring from terminal SSH, but that would result in RubyMine complaining that it can not load teamcity formatter:

cannot load such file -- teamcity/spec/runner/formatter/teamcity/formatter (LoadError)

This is because RubyMine injects a special formatter into rspec so that it can parse the output better. Thanks to Oleg at Jetbrains (RUBY-16324) I discovered that the required formatters are present in the vagrant box and all I need is to add them to ruby load path, before starting spring.

So, I added following lines to my /home/vagrant/.bashrc:

# RubyMine-RUBYLIB
if [[ -d "$HOME/.rubymine_helpers" ]]
  export RUBYLIB=$HOME/.rubymine_helpers/rb/testing/patch/common/:$HOME/.rubymine_helpers/rb/testing/patch/bdd/:$RUBYLIB

This sets up RUBYLIB variable with RubyMine helpers. I skipped over testunit folder, as I do not use that, but feel free to add that also if you need it.

Let the specs fly

Now, just SSH into your Vagrant box, start Spring, e.g. by running:

bin/rspec --help

And then RubyMine can re-use the already running Spring server to speed itself up.