Skip to content

Commit b3355cc

Browse files
committed
Split benchmarking code from test code
1 parent 0aa280d commit b3355cc

File tree

7 files changed

+243
-193
lines changed

7 files changed

+243
-193
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,5 @@ jobs:
8989
run: npm install -g tree-sitter-cli@0.19.3
9090
- run: bin/test
9191
if: ${{ !matrix.target }}
92+
- run: bin/test bench
93+
if: ${{ !matrix.target }}

.github/workflows/release.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ jobs:
7878
run: npm install -g tree-sitter-cli@0.19.3
7979
- run: bin/test
8080
if: ${{ !matrix.target }}
81+
- run: bin/test bench
82+
if: ${{ !matrix.target }}
8183

8284
- name: Rename cross-build's binary
8385
if: matrix.target

bin/test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ if [[ $* == "watch" ]]; then
1414
else
1515
if [[ $* == "integ" ]]; then
1616
test_mod="tsc-dyn-get-tests.el"
17+
elif [[ $* == "bench" ]]; then
18+
test_mod="tree-sitter-bench.el"
1719
else
1820
test_mod="tree-sitter-tests.el"
1921
fi

bin/test.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ if ($args[0] -eq "watch") {
1111
} else {
1212
if ($args[0] -eq "integ") {
1313
$test_mod = "tsc-dyn-get-tests.el"
14+
} elseif ($args[0] -eq "bench") {
15+
$test_mod = "tree-sitter-bench.el"
1416
} else {
1517
$test_mod = "tree-sitter-tests.el"
1618
}

tests/tree-sitter-bench.el

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
;;; tree-sitter-bench.el --- Benchmarks for tree-sitter.el -*- lexical-binding: t; coding: utf-8 -*-
2+
3+
;; Copyright (C) 2019-2022 Tuấn-Anh Nguyễn
4+
;;
5+
;; Author: Tuấn-Anh Nguyễn <ubolonton@gmail.com>
6+
;; SPDX-License-Identifier: MIT
7+
8+
;;; Commentary:
9+
10+
;; Benchmarks for `tree-sitter'.
11+
12+
;;; Code:
13+
14+
;; Local Variables:
15+
;; no-byte-compile: t
16+
;; End:
17+
18+
(require 'tree-sitter-tests-utils)
19+
20+
(ert-deftest parsing::bench ()
21+
(tsc-test-with c parser
22+
(tsc-test-with-file "data/types.rs"
23+
(let ((n 0))
24+
(while (<= n 4)
25+
(let ((tsc--buffer-input-chunk-size (* 1024 (expt 2 n))))
26+
(garbage-collect)
27+
(message "tsc-parse-chunks %6d %s" tsc--buffer-input-chunk-size
28+
(benchmark-run 10
29+
(tsc-parse-chunks parser #'tsc--buffer-input nil)))
30+
(cl-incf n)))))))
31+
32+
(ert-deftest cursor::bench ()
33+
(tsc-test-lang-with-file rust "data/types.rs"
34+
(require 'rust-mode)
35+
(rust-mode)
36+
(tree-sitter-mode)
37+
(let ((props [:named-p :type :start-byte :end-byte]))
38+
(dolist (n '(1 10 100))
39+
(message "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
40+
(garbage-collect)
41+
(message "%10s %3d %s" :mapc n
42+
(eval `(benchmark-run-compiled ,n
43+
(tsc-traverse-mapc
44+
tsc-test-no-op
45+
tree-sitter-tree
46+
,props))))
47+
(garbage-collect)
48+
(message "%10s %3d %s" :iter n
49+
(eval `(benchmark-run-compiled ,n
50+
(iter-do (_ (tsc-traverse-iter tree-sitter-tree ,props))
51+
(tsc-test-no-op)))))
52+
(garbage-collect)
53+
(message "%10s %3d %s" :do n
54+
(eval `(benchmark-run-compiled ,n
55+
(tsc-traverse-do ([named-p type start-byte end-byte] tree-sitter-tree)
56+
named-p type start-byte end-byte))))
57+
(garbage-collect)
58+
(message "%10s %3d %s" 'funcall n
59+
(eval `(benchmark-run-compiled ,(* 3429 n)
60+
(funcall tsc-test-no-op ,props 5))))))))
61+
62+
(ert-deftest hl::bench ()
63+
(tsc-test-lang-with-file rust "data/types.rs"
64+
(setq tree-sitter-hl-default-patterns (tree-sitter-langs--hl-default-patterns 'rust))
65+
(require 'rust-mode)
66+
(rust-mode)
67+
(font-lock-mode)
68+
(font-lock-set-defaults)
69+
(dolist (n '(1 10 100))
70+
(message "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
71+
(tree-sitter-hl-mode)
72+
(garbage-collect)
73+
(message "tree-sitter-hl %2d %s" n (eval `(benchmark-run-compiled ,n (font-lock-ensure))))
74+
(tree-sitter-hl-mode -1)
75+
(font-lock-ensure)
76+
(garbage-collect)
77+
(message " font-lock %2d %s" n (eval `(benchmark-run-compiled ,n (font-lock-ensure)))))))
78+
79+
(ert-deftest debug::bench ()
80+
(tsc-test-lang-with-file rust "data/types.rs"
81+
(setq tree-sitter-hl-default-patterns (tree-sitter-langs--hl-default-patterns 'rust))
82+
(require 'rust-mode)
83+
(rust-mode)
84+
(dolist (n '(1 10 100))
85+
(message "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
86+
(dolist (tree-sitter-debug-traversal-method '(:mapc :iter :do))
87+
(garbage-collect)
88+
(message "%10s %3d %s" tree-sitter-debug-traversal-method n
89+
(eval `(benchmark-run-compiled ,n
90+
(progn (tree-sitter-debug-mode -1)
91+
(tree-sitter-debug-mode)))))))))
92+
93+
(provide 'tree-sitter-bench)
94+
;;; tree-sitter-bench.el ends here

tests/tree-sitter-tests-utils.el

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
;;; tree-sitter-tests-utils.el --- Utils for tree-sitter-tests.el -*- lexical-binding: t; coding: utf-8 -*-
2+
3+
;; Copyright (C) 2019-2022 Tuấn-Anh Nguyễn
4+
;;
5+
;; Author: Tuấn-Anh Nguyễn <ubolonton@gmail.com>
6+
;; SPDX-License-Identifier: MIT
7+
8+
;;; Commentary:
9+
10+
;; Utils for `tree-sitter-tests'.
11+
12+
;;; Code:
13+
14+
(setq tsc-dyn-get-from nil)
15+
(require 'tree-sitter)
16+
(require 'tree-sitter-debug)
17+
18+
(defvar tree-sitter-langs--testing)
19+
;;; Disable grammar downloading.
20+
(let ((tree-sitter-langs--testing t))
21+
(require 'tree-sitter-langs))
22+
;;; Build the grammars, if necessary.
23+
(dolist (lang-symbol '(rust python javascript c))
24+
(tree-sitter-langs-ensure lang-symbol))
25+
26+
;; XXX: Bash grammar failed 'tree-sitter test' on Windows: 'Escaped newlines'.
27+
(with-demoted-errors "Failed to ensure bash grammar %s"
28+
(tree-sitter-langs-ensure 'bash))
29+
30+
(require 'ert)
31+
(require 'generator)
32+
33+
(eval-when-compile
34+
(require 'subr-x)
35+
(require 'cl-lib))
36+
37+
;;; ----------------------------------------------------------------------------
38+
;;; Helpers.
39+
40+
(defun tsc-test-make-parser (lang-symbol)
41+
"Return a new parser for LANG-SYMBOL."
42+
(let ((parser (tsc-make-parser))
43+
(language (tree-sitter-require lang-symbol)))
44+
(tsc-set-language parser language)
45+
parser))
46+
47+
(defun tsc-test-full-path (relative-path)
48+
"Return full path from project RELATIVE-PATH."
49+
(concat (file-name-directory (locate-library "tree-sitter-tests.el"))
50+
relative-path))
51+
52+
(defun tsc-test-tree-sexp (sexp &optional reset)
53+
"Check that the current syntax tree's sexp representation is SEXP.
54+
If RESET is non-nil, also do another full parse and check again."
55+
(should (equal (read (tsc-tree-to-sexp tree-sitter-tree)) sexp))
56+
(when reset
57+
(setq tree-sitter-tree nil)
58+
(tree-sitter--do-parse)
59+
(tsc-test-tree-sexp sexp)))
60+
61+
(defun tsc-test-use-lang (lang-symbol)
62+
"Turn on `tree-sitter-mode' in the current buffer, using language LANG-SYMBOL."
63+
(setq tree-sitter-language (tree-sitter-require lang-symbol))
64+
(ignore-errors
65+
(setq tree-sitter-hl-default-patterns
66+
(tree-sitter-langs--hl-default-patterns lang-symbol)))
67+
(add-hook 'tree-sitter-after-first-parse-hook
68+
(lambda () (should (not (null tree-sitter-tree)))))
69+
(tree-sitter-mode))
70+
71+
(defun tsc--listify (x)
72+
(if (listp x)
73+
x
74+
(list x)))
75+
76+
(defun tsc--hl-at (pos face)
77+
"Return t if text at POS is highlighted with FACE."
78+
(memq face (tsc--listify (get-text-property pos 'face))))
79+
80+
(defun tsc-test-no-op (&rest _args))
81+
82+
(defvar tsc-test-no-op
83+
(byte-compile #'tsc-test-no-op))
84+
85+
(defun tsc-test-render-node (type named-p start-byte end-byte field depth)
86+
(when named-p
87+
(message "%s%s%S (%s . %s)" (make-string (* 2 depth) ?\ )
88+
(if field
89+
(format "%s " field)
90+
"")
91+
type start-byte end-byte)))
92+
93+
(defmacro tsc-test-with (lang-symbol var &rest body)
94+
"Eval BODY with VAR bound to a new parser for LANG-SYMBOL."
95+
(declare (indent 2))
96+
`(let ((,var (tsc-test-make-parser ',lang-symbol)))
97+
,@body))
98+
99+
(defmacro tsc-test-with-file (relative-path &rest body)
100+
"Eval BODY in a temp buffer filled with content of the file at RELATIVE-PATH."
101+
(declare (indent 1))
102+
`(with-temp-buffer
103+
(let ((coding-system-for-read 'utf-8))
104+
(insert-file-contents (tsc-test-full-path ,relative-path)))
105+
,@body))
106+
107+
(defmacro tsc-test-lang-with-file (lang-symbol relative-path &rest body)
108+
"Eval BODY in a temp buffer filled with content of the file at RELATIVE-PATH.
109+
`tree-sitter-mode' is turned on, using the given language LANG-SYMBOL."
110+
(declare (indent 2))
111+
`(tsc-test-with-file ,relative-path
112+
(tsc-test-use-lang ',lang-symbol)
113+
,@body))
114+
115+
(defmacro tsc-test-with-advice (symbol where function &rest body)
116+
"Eval BODY while advising SYMBOL with FUNCTION at WHERE."
117+
(declare (indent 3))
118+
`(progn
119+
(advice-add ,symbol ,where ,function)
120+
(unwind-protect
121+
,@body
122+
(advice-remove ,symbol ,function))))
123+
124+
(defmacro tsc-test-capture-messages (&rest body)
125+
`(with-temp-buffer
126+
(let ((buf (current-buffer)))
127+
(tsc-test-with-advice 'message :override
128+
(lambda (fmt &rest args)
129+
(with-current-buffer buf
130+
(insert (apply #'format-message fmt args) "\n")))
131+
,@body)
132+
(with-current-buffer buf
133+
(buffer-string)))))
134+
135+
;; Local Variables:
136+
;; no-byte-compile: t
137+
;; End:
138+
139+
(provide 'tree-sitter-tests-utils)
140+
;;; tree-sitter-tests-utils.el ends here

0 commit comments

Comments
 (0)