Steal João Távora's benchmarking code

This commit is contained in:
Gerard Vermeulen 2023-11-22 13:15:20 +01:00
parent 67b4b360c6
commit d588ea7849

View File

@ -5058,6 +5058,178 @@ src_emacs-lisp{(describe-function 'inferior-emacs-lisp-mode)}.
(setopt ielm-dynamic-return nil))
#+end_src
*** [[https://lists.gnu.org/archive/html/emacs-devel/2023-11/msg00764.html][Benchmarking Emacs Lisp]]
:PROPERTIES:
:CUSTOM_ID: sec:benchmarking
:header-args:emacs-lisp: :exports code :tangle no
:END:
The following snippets present and use a [[https://lists.gnu.org/archive/html/emacs-devel/2023-11/msg00764.html][copy]] of João Távora's code to benchmark
Emacs Lisp forms.
#+caption[Define macro to benchmark groups of forms]:
#+caption: Define macro to benchmark groups of forms.
#+name: lst:benchmark-group
#+begin_src emacs-lisp -n :results silent
(defvar joaot/bench-group-name nil)
(defvar joaot/setup-form nil)
(defvar joaot/timings-alist nil)
(defvar joaot/repetitions nil)
(defmacro joaot/with-benchmark-group (bench-name
setup-form
repetitions
&rest body)
(declare (indent 1))
(let ((f `(alist-get ,bench-name joaot/timings-alist nil nil #'equal)))
`(let ((joaot/bench-group-name ,bench-name)
(joaot/setup-form ',setup-form)
(joaot/repetitions ,repetitions))
(setf ,f (list))
,@body
(cl-loop with sorted = (setf ,f (cl-sort ,f #'< :key #'cadr))
with fastest = (cadr (car sorted))
for i from 0
for res in sorted
for prev-time = time
for (_n time . more) = res
do (setcdr res
(cl-list* (if (eq time fastest) "FASTEST"
(format "%2.1fx %sSLOWER"
(/ time fastest)
(if (= i 1) ""
(format "(rel %2.1fx) "
(/ time prev-time)))))
time
more)))
joaot/timings-alist)))
#+end_src
#+caption[Define macro to benchmark forms]:
#+caption: Define macro to benchmark forms.
#+name: lst:benchmark-form
#+begin_src emacs-lisp -n :results silent
(defmacro joaot/bench (form)
`(cl-progv
(mapcar #'car joaot/setup-form)
(mapcar #'eval (mapcar #'cdr joaot/setup-form))
(let ((res
(benchmark-call (prog1
(,(if (native-comp-available-p)
'native-compile
'byte-compile)
'(lambda () ,form))
(garbage-collect))
joaot/repetitions))
(group-name joaot/bench-group-name)
(bench-name ',(car form)))
(push (cons bench-name res)
(alist-get group-name joaot/timings-alist nil nil #'equal)))))
#+end_src
#+caption[Define benchmark helper functions]:
#+caption: Define benchmark helper functions.
#+name: lst:benchmark-helpers
#+begin_src emacs-lisp -n :results silent
(defun bench-cl-loop-list (l)
(cl-loop for e in l thereis (identity e)))
(defun bench-cl-loop-vec (v)
(cl-loop for e across v thereis (identity e)))
(defun bench-cl-some (seq)
(cl-some #'identity seq))
(defun bench-seq-some (seq)
(seq-some #'identity seq))
#+end_src
#+caption[Benchmark =some= operations on big lists]:
#+caption: Benchmark =some= operations on big lists.
#+name: lst:benchmark-some-big-lists
#+begin_src emacs-lisp -n :results pp silent
(joaot/with-benchmark-group "\"some\" operation, big lists"
((list1 . (make-list 100000 nil)))
100
(joaot/bench (bench-cl-loop-list list1))
(joaot/bench (cl-some #'identity list1))
(joaot/bench (seq-some #'identity list1)))
#+end_src
#+caption[Benchmark =some= operations on small lists]:
#+caption: Benchmark =some= operations on small lists.
#+name: lst:benchmark-some-small-lists
#+begin_src emacs-lisp -n :results pp silent
(joaot/with-benchmark-group "\"some\" operation, small lists"
((list1 . (make-list 10 nil)))
100000
(joaot/bench (bench-cl-loop-list list1))
(joaot/bench (cl-some #'identity list1))
(joaot/bench (seq-some #'identity list1)))
#+end_src
#+caption[Accumulated results of benchmark examples]:
#+caption: Accumulated results of benchmark examples.
#+name: lst:benchmark-example
#+header: :wrap "src emacs-lisp -n"
#+begin_src emacs-lisp -n :exports both :results pp
(joaot/with-benchmark-group "destructuring"
((list1 . (make-list 3 0)))
100000
(joaot/bench (pcase-let ((`(,a ,b ,c) list1)) (+ a b c)))
(joaot/bench (cl-destructuring-bind (a b c) list1 (+ a b c)))
(joaot/bench (seq-let (a b c) list1 (+ a b c))))
#+end_src
#+caption[Accumulated results of benchmark examples]:
#+caption: Accumulated results of benchmark examples.
#+name: lst:benchmark-example-results
#+RESULTS: lst:benchmark-example
#+begin_src emacs-lisp -n
(("\"some\" operation, small lists" (cl-some "FASTEST" 0.027944 0 0.0)
(seq-some "2.6x SLOWER" 0.073602 0 0.0)
(bench-cl-loop-list "134.4x (rel 51.0x) SLOWER" 3.7544939999999998
12 2.701254000000006))
("\"some\" operation, big lists" (cl-some "FASTEST" 0.242062 0 0.0)
(seq-some "2.5x SLOWER" 0.614304 0 0.0)
(bench-cl-loop-list "14.5x (rel 5.7x) SLOWER" 3.505071 0 0.0))
("destructuring"
(cl-destructuring-bind "FASTEST" 0.013874999999999998 0 0.0)
(pcase-let "1.2x SLOWER" 0.016648 0 0.0)
(seq-let "2.8x (rel 2.4x) SLOWER" 0.039485 0 0.0)))
#+end_src
*** [[info:elisp#Debugging][Debugging Emacs Lisp (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:debugging
:header-args:emacs-lisp: :exports code :tangle no
:END:
Listing [[lst:example-edebug][edebug example]] from the [[https://www.emacswiki.org/emacs/SourceLevelDebugger][source level debugger (edebug)]] wiki entry is a
minimal example of how to use =edebug=:
1. Type {{{kbd(C-c ')}}} to open its =org-src-mode= buffer.
2. Type {{{kbd(C-M-x)}}} with point in =foo=.
3. Type {{{kbd(C-M-x)}}} with point in =bar=.
4. Evaluate =(foo)=.
5. Type {{{kbd(C-u C-M-x)}}} with point in =bar=.
6. Evalute =(foo)=.
7. Type the space bar to step through =bar=.
Note: I fail to instrument functions as in [[info:elisp#Edebug][Edebug (info)]].
#+caption[Example for =edebug=]:
#+caption: Example for =edebug=.
#+name: lst:example-edebug
#+begin_src emacs-lisp -n :exports code :results silent
(defun foo ()
(interactive)
(bar))
(defun bar ()
(let ((a 5)
(b 7))
(message "%d" (+ a b))))
#+end_src
*** [[https://emacs.stackexchange.com/questions/2129/why-is-let-faster-with-lexical-scope][Disassemble dynamical and lexical scope]]
:PROPERTIES:
:CUSTOM_ID: sec:disassemble-dynamical-lexical-scope