Don’t set print-escape-newlines in the minibuffer
[emacs.git] / lisp / emacs-lisp / benchmark.el
blobe062a1867a8835fd225ea1081d6015cebfbc06af
1 ;;; benchmark.el --- support for benchmarking code -*- lexical-binding: t -*-
3 ;; Copyright (C) 2003-2018 Free Software Foundation, Inc.
5 ;; Author: Dave Love <fx@gnu.org>
6 ;; Keywords: lisp, extensions
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
23 ;;; Commentary:
25 ;; Utilities for timing the execution of forms, including the time
26 ;; taken for GC. Note that prior to timing code you may want to
27 ;; ensure things like: there has just been a GC, the relevant code is
28 ;; already loaded (so that there's no overhead from autoloading etc.),
29 ;; and the code is compiled if appropriate (but see
30 ;; `benchmark-run-compiled').
32 ;;; Code:
34 (defmacro benchmark-elapse (&rest forms)
35 "Return the time in seconds elapsed for execution of FORMS."
36 (declare (indent 0) (debug t))
37 (let ((t1 (make-symbol "t1")))
38 `(let (,t1)
39 (setq ,t1 (current-time))
40 ,@forms
41 (float-time (time-subtract nil ,t1)))))
43 ;;;###autoload
44 (defmacro benchmark-run (&optional repetitions &rest forms)
45 "Time execution of FORMS.
46 If REPETITIONS is supplied as a number, run forms that many times,
47 accounting for the overhead of the resulting loop. Otherwise run
48 FORMS once.
49 Return a list of the total elapsed time for execution, the number of
50 garbage collections that ran, and the time taken by garbage collection.
51 See also `benchmark-run-compiled'."
52 (declare (indent 1) (debug t))
53 (unless (or (natnump repetitions) (and repetitions (symbolp repetitions)))
54 (setq forms (cons repetitions forms)
55 repetitions 1))
56 (let ((i (make-symbol "i"))
57 (gcs (make-symbol "gcs"))
58 (gc (make-symbol "gc")))
59 `(let ((,gc gc-elapsed)
60 (,gcs gcs-done))
61 (list ,(if (or (symbolp repetitions) (> repetitions 1))
62 ;; Take account of the loop overhead.
63 `(- (benchmark-elapse (dotimes (,i ,repetitions)
64 ,@forms))
65 (benchmark-elapse (dotimes (,i ,repetitions))))
66 `(benchmark-elapse ,@forms))
67 (- gcs-done ,gcs)
68 (- gc-elapsed ,gc)))))
70 ;;;###autoload
71 (defmacro benchmark-run-compiled (&optional repetitions &rest forms)
72 "Time execution of compiled version of FORMS.
73 This is like `benchmark-run', but what is timed is a funcall of the
74 byte code obtained by wrapping FORMS in a `lambda' and compiling the
75 result. The overhead of the `lambda's is accounted for."
76 (declare (indent 1) (debug t))
77 (unless (or (natnump repetitions) (and repetitions (symbolp repetitions)))
78 (setq forms (cons repetitions forms)
79 repetitions 1))
80 (let ((i (make-symbol "i"))
81 (gcs (make-symbol "gcs"))
82 (gc (make-symbol "gc"))
83 (code (byte-compile `(lambda () ,@forms)))
84 (lambda-code (byte-compile `(lambda ()))))
85 `(let ((,gc gc-elapsed)
86 (,gcs gcs-done))
87 (list ,(if (or (symbolp repetitions) (> repetitions 1))
88 ;; Take account of the loop overhead.
89 `(- (benchmark-elapse (dotimes (,i ,repetitions)
90 (funcall ,code)))
91 (benchmark-elapse (dotimes (,i ,repetitions)
92 (funcall ,lambda-code))))
93 `(benchmark-elapse (funcall ,code)))
94 (- gcs-done ,gcs) (- gc-elapsed ,gc)))))
96 ;;;###autoload
97 (defun benchmark (repetitions form)
98 "Print the time taken for REPETITIONS executions of FORM.
99 Interactively, REPETITIONS is taken from the prefix arg, and
100 the command prompts for the form to benchmark.
101 For non-interactive use see also `benchmark-run' and
102 `benchmark-run-compiled'."
103 (interactive "p\nxForm: ")
104 (let ((result (eval `(benchmark-run ,repetitions ,form) t)))
105 (if (zerop (nth 1 result))
106 (message "Elapsed time: %fs" (car result))
107 (message "Elapsed time: %fs (%fs in %d GCs)" (car result)
108 (nth 2 result) (nth 1 result)))))
110 (provide 'benchmark)
112 ;;; benchmark.el ends here