# # -*- mode: emacs-lisp; lexical-binding:t -*-

;;

* Benchmarking

This file is not meant a emacs package, but for benchmarking m-buffer.
To hide Emacs' there are lots of places where m-buffer saves, changes and then
restores this global state. One obvious question is what impact does this have
on performance. We check this here.

** Evaluation

   The results of running these forms are "pre-evaluated", because this file
   forms part of the lentic documentation for m-buffer. We could evaluate
   these at export time but, by default, this form of evaluation is blocked.
   Moreover, it can be quite slow which would be less than ideal with
   lentic-server.

   To evaluate on the local machine use `org-babel-execute-buffer', probably
   after setting `org-confirm-babel-evaluate' to nil.

** Support

   Build a nice simple bench macro.

#+begin_src emacs-lisp
(defmacro bench
    (&rest body)
  `(format "%e"
           (car
            (benchmark-run-compiled
             1000000
             (progn
               ,@body)))))
#+end_src

#+RESULTS:
: bench

** How Long does it take to change current-buffer

*** Entering and Restoring

    There are lots of places where we set the current buffer, do something, then
    get the result again, so understanding how long this takes is important.
    So, how long does it take to set and restore the current buffer.

    It's quite a bit slower -- about an order of magnitude.

**** Implementation

    We get the `current-buffer' and `point'. In the first case, we also do
    this inside a `with-current-buffer'.

#+begin_src emacs-lisp
(bench
 (with-current-buffer
     (current-buffer)
   (point)))
#+end_src

#+RESULTS:
: 3.371566e-02


#+begin_src emacs-lisp
(bench
 (current-buffer)
 (point))
#+end_src

#+RESULTS:
: 2.120534e-03


*** Does buffer context help

   Is `with-current-buffer' quicker if we are already in the current-buffer?
   This is interesting to know because if it is, grouping several commands
   that operate on a single would run much faster.

   We test this by entering having two `with-current-buffer' calls which do
   nothing, one nested and one not. Our conclusion is, no, it makes not
   difference, so there is little pointing in putting a grouping construct in,
   unless we do something intelligent.
   

#+BEGIN_SRC emacs-lisp
(bench
 (with-current-buffer
     (current-buffer)
   (with-current-buffer
       (current-buffer))))
#+END_SRC

#+RESULTS:
: 1.001554e-01


#+BEGIN_SRC emacs-lisp
(bench
 (with-current-buffer
     (current-buffer))
 (with-current-buffer
     (current-buffer)))
#+END_SRC

#+RESULTS:
: 1.205835e-01

*** How fast is point

   m-buffer-at provides stateless functions, but how much overhead does this
   introduce. We try this with the simplest function I can think of, which is
   point. The various forms look different here -- because we have a
   `current-buffer' call in, but not with `point'. But then, effectively,
   `point' must call `current-buffer' somewhere as part of its implementation,
   so this difference is fair.

   We conclude that m-buffer is about 100x slower for calling `point', even
   when the buffer does not actually need to be changed. So, a lot slower.

#+BEGIN_SRC emacs-lisp
(bench
 (point))
#+END_SRC

#+RESULTS:
: -1.722546e-03

#+BEGIN_SRC emacs-lisp
(bench
 (with-current-buffer
     (current-buffer)
   (point)))
#+END_SRC

#+RESULTS:
: 3.669245e-02

#+BEGIN_SRC emacs-lisp
(bench
 (m-buffer-at-point
  (current-buffer)))
#+END_SRC

#+RESULTS:
: 1.011448e-01


# Local Variables:
# lentic-init: lentic-el-org-init
# End:
