Steal João Távora's benchmarking code
This commit is contained in:
parent
67b4b360c6
commit
d588ea7849
172
README.org
172
README.org
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user