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))
|
(setopt ielm-dynamic-return nil))
|
||||||
#+end_src
|
#+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]]
|
*** [[https://emacs.stackexchange.com/questions/2129/why-is-let-faster-with-lexical-scope][Disassemble dynamical and lexical scope]]
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: sec:disassemble-dynamical-lexical-scope
|
:CUSTOM_ID: sec:disassemble-dynamical-lexical-scope
|
||||||
|
Loading…
Reference in New Issue
Block a user