* Benchmarks:
These benchmarks are after replacing parse-partial-sexp with syntax-ppss
and using defsubst in place of defun in a few more critical paths.
*** Ordinary section of code:
(benchmark-run 10 (rainbow-delimiters-propertize-region 16800 19000))
0.0403
0.0355
0.0315
0.0419
0.0319
0.0376
Before this round of optimizations (syntax-ppss+defsubst) this benchmark
took ~0.068 seconds. (Improvement: ~2x)
*** Segment where a bottleneck was hit earlier:
(benchmark-run 10 (rainbow-delimiters-propertize-region 23800 26000))
0.0842
0.0821
0.0905
0.0843
0.0784
0.0822
Before this round of optimizations (syntax-ppss+defsubst) this benchmark
took ~3.2 seconds. (Improvement: ~40x)
Replaced parse-partial-sexp with syntax-ppss, a cached version of the same fn.
Used in both rainbow-delimiters-depth and rainbow-delimiters-char-ineligible-p.
char-ineligible-p is run on every single delim as it gets highlighted.
depth is checked every time jit-lock fn gets called (once per pass).
The mode is 6-15x faster at highlighting delims now.
This first step is a naive improvement, just replacing the call
to parse-partial-sexp with syntax-ppss; there is more to gain.
Specifically we get a list of delim locations from syntax-ppss which
will allow us to avoid using re-search-forward+delim-type check;
instead we can just (goto-char) for each member of the list given to
us by syntax-ppss.
Benchmarks:
syntax-ppss benchmarks:: 2012-04-27
* rainbow-delimiters-char-ineligible-p:
*** rainbow-delimiters-char-ineligible-p-old::
***** uses (save-excursion (beginning-of-defun) (parse-partial-sexp (point) loc)))
Run on an ordinary small defun, meaning beg-of-defun+parse-partial-sexp have
lower overhead:
(benchmark-run 10000 (rainbow-delimiters-char-ineligible-p-old (point)))
0.382
0.322
0.3241
0.3244
0.5235 + gc
Run on a LARGE color-theme defun, which causes lag for beg-of-defun +
parse-partial-sexp. Speed degrades badly with large fn size.
(benchmark-run 10000 (rainbow-delimiters-char-ineligible-p-old (point)))
13.86086
14.709195 + gc
15.463448
Massive performance degradation - no wonder some people reported slowdown.
*** rainbow-delimiters-char-ineligible-p:
***** uses (syntax-ppss loc), the cached version of parse-partial-sexp
Run on an ordinary small defun:
(benchmark-run 10000 (rainbow-delimiters-char-ineligible-p (point)))
0.0287
0.1183
-0.708 + gc
0.1132
0.1172
0.1172
0.125999
0.12016
On a small defun, it's about .4s slower for 10,000 runs than the old version.
However, on large defuns...
Run on the same LARGE defun as the char-ineligible-p-old benchmark above:
(benchmark-run 10000 (rainbow-delimiters-char-ineligible-p (point)))
1.69163 + gc
0.94135
1.06332
0.93187
0.93072
On the order of a 13x speed improvement over -old fn on large defuns.
* Improvements to jit-lock fn speed from char-ineligible-p change:
*** rainbow-delimiters-propertize-region using OLD char-ineligible-p-old:
Run propertize-regions on the rainbow-delimiters.el file:
(benchmark-run 10 (rainbow-delimiters-propertize-region 16800 19000))
0.07045
0.06604
0.06445
0.06915
0.06829
Run propertize-region with old char-ineligible-p on a massive color-theme defun:
- from 23800, 26000 (same region size as 16800 to 19000)
(benchmark-run 10 (rainbow-delimiters-propertize-region 23800 26000))
3.4262
2.7935
4.0044
2.8100
3.3926
2.8331
3.6192
*** rainbow-delimiters-propertize-region using NEW char-ineligible-p:
Run propertize-region on the rainbow-delimiters.el file:
(benchmark-run 10 (rainbow-delimiters-propertize-region 16800 19000))
0.1075
0.1066
0.3578 + gc
0.1028
We see a slowdown from the new version in jit-lock. This is likely due to
the region from 16800-19000 only containing small fns not affected by the
lag introduced by larger fns.
Run propertize-region on a massive color-theme defun:
- from 23800, 26000 (same region size as 16800 to 19000)
(benchmark-run 10 (rainbow-delimiters-propertize-region 23800 26000))
0.1583
0.1527
0.1539
0.1544
0.1557
Huge improvement, down from about 3 seconds to 0.15s (20x improvement).
* rainbow-delimiters-depth speed increase:
*** Old rainbow-delimiters-depth:
***** Uses beg-of-defun+parse-partial-sexp, returns depth
Run on smaller defun:
(benchmark-run 10000 (rainbow-delimiters-depth-old (point)))
0.0608 + gc
0.31211
0.25139
0.50449 + gc
0.24204
0.25056
Run on a LARGE color-theme defun:
11.9003
12.5897
15.2455 + gc
14.8487
14.1190
*** New rainbow-delimiters-depth:
***** uses syntax-ppss instead of beg-of-defun+parse-partial-sexp, returns depth
(benchmark-run 10000 (rainbow-delimiters-depth (point)))
0.15836
0.17015
0.41939 + gc
0.16874
0.13655
0.13726
0.14030
0.62721 + gc
0.13498
0.23817
Doubled speed from old fn but slower gcs when they happen.
Run on a LARGE color-theme defun:
(benchmark-run 10000 (rainbow-delimiters-depth (point)))
0.8147
0.8021
0.8139
0.6038
Huge improvement, down from 12-15s to 0.8s (~17.5x improvement)
* Total speed improvement from depth+char-ineligible-p optimizations:
Run rainbow-delimiters-propertize-region on a relatively smaller defun:
(benchmark-run 10 (rainbow-delimiters-propertize-region 16800 19000))
0.10449
0.41737 + gc
0.10436
0.10183
0.11046
0.10177
0.10482
0.10229
Down from 0.65 seconds to 0.1 seconds (~6x improvement).
Run on a LARGE color-theme defun:
(benchmark-run 10 (rainbow-delimiters-propertize-region 23800 26000))
0.13815
0.20409
0.18792
0.19268
0.18909
0.18806
0.26894
0.18979
Down from ~3s to 0.2s. (15x improvement).
This corrects problems seen in various modes (perl, c++, lua) caused by basing the syntax table(s) used in rainbow-delimiters on emacs-lisp-mode-syntax-table. Delimiters should now colorize correctly taking into account the specifics of the syntax of whatever language or major-mode the buffer is in.