Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Speedup lsp-mode's JSONRPC processing (~2 times)
After this change, we are practically eliminating the cost of anything but the json parsing. I have performed the following optimization(Note that the parser function is called hundreds of times for bigger messages): 1. Replaced the calls to `store-substring` with collecting of the results and then concatenating them. Prior to this change, the json parsing was taking as much time as string concatenation. See benchmarks bellow. 2. Replaced `lsp--parser` structure in favor of keeping the state in closure vars/fields. See benchmarks bellow. 3. Replaced of the operations with faster equivalents(e. g. `if (string-empty-p foo)` with `if foo` 4. Removed redundant `substring` calls when the original string could have been reused 5. Removed redundant flags 6. Inlined function calls on the hot path Benchmarks: 1. Inserting: ``` elisp (defconst my/text "jdt://contents/java.xml/com.sun.org.apache.xerces.internal.jaxp/SAXParserImpl.class?=jdt.ls-java-project/%5C/usr%5C/lib%5C/jvm%5C/java-11-openjdk-amd64%5C/lib%5C/jrt-fs.jar%60java.xml=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/11%5C/docs%5C/api%5C/=/%3Ccom.sun.org.apache.xerces.internal.jaxp(SAXParserImpl.class") (benchmark-run 1000 (apply #'concat (-repeat 100 my/text))) ; => (0.039879415 0 0.0) (let* ((length (* 100 (length my/text)))) (benchmark-run 1000 (let ((ss (make-string length ?\s))) (--each (-repeat 100 my/text) (store-substring ss 0 it))))) ; => (1.8749312630000001 0 0.0) (with-temp-buffer (benchmark-run 1000 (--each (-repeat 100 my/text) (insert it)))) ; => (0.216264571 0 0.0) ``` 2. Accessing struct type fields vs accessing closure fields ``` elisp (cl-defstruct my/struct counter) (setq my/fn-closure (let ((content 0)) (lambda () (setf content (1+ content))))) (setq my/fn-using-struct (let ((content (make-my/struct :counter 0) )) (lambda () (setf (my/struct-counter content) (1+ (my/struct-counter content)))))) (benchmark-run 10000 (funcall my/fn-closure)) ; => (0.018466258 0 0.0) (benchmark-run 10000 (funcall my/fn-using-struct)) ; => (0.44053651899999996 0 0.0) ``` Note: it is ~2 times when using Emacs 27.x native json parsing
- Loading branch information
Showing
2 changed files
with
108 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
2fc61a9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎊
Congrats.
Just one thing: structs work much faster when byte-compiled. When it is, the difference in the related benchmark comes down to just 2-3x on my machine. This may or may not be important for your use.
2fc61a9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dgutov thank you, good to know.