Awesome
Benchmarking different Sass implementations
Methodology can be found in install.sh
, bench.sh
, and generate.py
. The test cases are largely adapted from dart-sass's own benchmark suite. This suite of benchmarks adds a few additional test cases, namely bulma and more benchmarks against bootstrap.
In general, grass
appears to be ~2x faster on all benchmarks. Full results can be found in results
. Below are the summaries from all runs:
Summary
'grass bootstrap/scss/bootstrap.scss ' ran
2.12 ± 0.06 times faster than './sassc/bin/sassc bootstrap/scss/bootstrap.scss '
4.22 ± 5.67 times faster than './dart-sass/sass bootstrap/scss/bootstrap.scss '
Summary
'grass bulma/bulma.sass ' ran
1.77 ± 0.08 times faster than './sassc/bin/sassc bulma/bulma.sass '
2.85 ± 3.03 times faster than './dart-sass/sass bulma/bulma.sass '
Summary
'grass small-plain.scss ' ran
1.89 ± 0.24 times faster than './sassc/bin/sassc small-plain.scss '
17.56 ± 91.83 times faster than './dart-sass/sass small-plain.scss '
Summary
'grass large-plain.scss ' ran
2.19 ± 0.02 times faster than './sassc/bin/sassc large-plain.scss '
2.95 ± 0.75 times faster than './dart-sass/sass large-plain.scss '
Summary
'grass preceding-sparse-extend.scss ' ran
2.19 ± 0.02 times faster than './sassc/bin/sassc preceding-sparse-extend.scss '
2.95 ± 0.72 times faster than './dart-sass/sass preceding-sparse-extend.scss '
Summary
'grass following-sparse-extend.scss ' ran
2.29 ± 0.02 times faster than './sassc/bin/sassc following-sparse-extend.scss '
2.82 ± 0.70 times faster than './dart-sass/sass following-sparse-extend.scss '
Summary
'grass preceding-dense-extend.scss ' ran
1.97 ± 0.03 times faster than './dart-sass/sass preceding-dense-extend.scss '
2.02 ± 0.02 times faster than './sassc/bin/sassc preceding-dense-extend.scss '
Summary
'grass following-dense-extend.scss ' ran
1.53 ± 0.21 times faster than './dart-sass/sass following-dense-extend.scss '
1.55 ± 0.01 times faster than './sassc/bin/sassc following-dense-extend.scss '
Summary
'grass single-bootstrap.scss ' ran
2.13 ± 0.03 times faster than './sassc/bin/sassc single-bootstrap.scss '
3.16 ± 0.04 times faster than './dart-sass/sass single-bootstrap.scss '
Summary
'grass large-bootstrap.scss ' ran
1.79 ± 0.02 times faster than './dart-sass/sass large-bootstrap.scss '
2.01 ± 0.02 times faster than './sassc/bin/sassc large-bootstrap.scss '
Summary
'grass a11ycolor.scss ' ran
1.64 ± 0.03 times faster than './sassc/bin/sassc a11ycolor.scss '
1.82 ± 0.02 times faster than './dart-sass/sass a11ycolor.scss '
# `sassc` (`libsass`) is excluded from this run as it does not support the module
# system
Summary
'./dart-sass/sass duomo.scss ' ran
3.79 ± 0.03 times faster than 'grass duomo.scss '
There isn't one specific optimization that makes grass
so much faster than other existing implementations. grass
has a heavily optimized @extend
implementation that likely plays a large role, and it uses string interning wherever possible, including units.
grass
does perform much slower than dart-sass
on the duomo
benchmark. duomo
appears to exercise three pathological cases -- it has a massive number of imports of the same file, it makes heavy use of the module system, and it has a huge number of map operations.
grass
's import caching is much less robust than dart-sass
's, so it spends more time doing redundant work.
The module system in grass
is still relatively nascent, especially performance-wise. It has not received any profiling or optimization and it relies on structures of deeply nested Arc<RefCell<Vec<_>>>
. This makes for a lot of slowness around importing of many modules.
Map insertion and lookup are O(n)
in grass
, and map construction is O(n^2)
. This is because, in grass
, maps are represented as an array of tuples, while in dart-sass
maps are represented by proper hash maps. In general this is not enough to be noticeable on performance profiles, but this library manages to come up with a case in which enough maps are used that this matters.