-
Notifications
You must be signed in to change notification settings - Fork 159
sassc is very slow to compile and install #189
Description
When doing a bundle install for a new Rails 6 app, I noticed most of the time is spent compiling sassc (libsass really).
This takes easily up to 2 minutes on Linux, which feels really slow for one gem.
A bit of a Nokogiri-like experience if you see what I mean.
Speaking of Nokogiri, they now have a prerelease gem installing in just 1 second, maybe we can use a similar approach?
$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
$ time gem install sassc
Building native extensions. This could take a while...
Successfully installed sassc-2.2.1
1 gem installed
89.75s user 5.43s system 99% cpu 1:36.12 total
I'm not sure what's the best way to address this but here are some ideas:
- Use the Makefile of libsass to build libsass as a shared library, and just link the C extension to it (as it used to be).
- Use make parallelism automatically, e.g., by setting MAKEFLAGS
- Distribute a binary gem on Linux and macOS. This requires having an easy workaround for non-glibc (e.g., alpine) to install from source, or not depending on on glibc (by linking the libc statically?).
- Changes in libsass so it compiles faster, such as Amalgamate sassc library #132.
- I thought the
-fltomight slow things down but actually it seems to speed up compilation withg++ 8.3.1!time gem install sassc -- --disable-ltotakes113.71s user 6.01s system 99% cpu 2:00.70 total.
Disabling all flags gives:time gem install sassc -- --disable-lto --disable-march-tune-native --disable-static-stdlib=>109.80s user 5.63s system 99% cpu 1:56.12 total.
Use the Makefile of libsass to build libsass as a shared library
That already builds quite a bit faster:
$ time BUILD=shared make
...
70.53s user 3.94s system 99% cpu 1:14.93 total
I would think the main gain there is that's compiled with -O2:
g++ -Wall -O2 -DLIBSASS_VERSION="3.6.1" -std=c++11 -I /home/eregon/code/libsass/include -fPIC -c -o src/remove_placeholders.o src/remove_placeholders.cpp
instead of (with gem install sassc):
g++ -I. -I/home/eregon/.rubies/ruby-2.6.5/include/ruby-2.6.0/x86_64-linux -I/home/eregon/.rubies/ruby-2.6.5/include/ruby-2.6.0/ruby/backward -I/home/eregon/.rubies/ruby-2.6.5/include/ruby-2.6.0 -I. -I./libsass/include -fPIC -O3 -ggdb3 -std=c++11 -march=native -mtune=native -flto -DLIBSASS_VERSION="3.6.1" -o remove_placeholders.o -c ./libsass/src/remove_placeholders.cpp
We can also parallelize it (I have 4 cores + 4 hyperthreads, i7-7700HQ CPU @ 2.80GHz):
$ time BUILD=shared MAKEFLAGS=-j4 make
81.15s user 4.51s system 387% cpu 22.132 total
That's a reasonable install time!
Using just the MAKEFLAGS approach with gem install is not quite enough:
time MAKEFLAGS=-j4 gem install sassc
Building native extensions. This could take a while...
Successfully installed sassc-2.2.1
1 gem installed
95.47s user 5.63s system 180% cpu 55.870 total
Relates to #132