;;; -*- 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:
