Next: Compatibility Tips, Previous: Style Tips, Up: Tips [Contents][Index]
Here are ways of improving the execution speed of Lisp programs.
Beside the static byte compilation yielding .elc files, you can
also use the byte-compile
function to create and use compiled
objects inline.
;; We create a byte compiled predicate and bind it to the variable ;;is-minus-one-p
. ;; Note that we do _NOT_ create a functionis-minus-one-p
. (setq is-minus-one-p (byte-compile #'(lambda (a) (zerop (1+ a))))) ⇒ #<compiled-function (a) "...(5)" [a zerop] 2>
;; We use the compiled function object of is-minus-one-p
.
(require 'cl)
(some is-minus-one-p '(1 2 3 4 -1))
⇒ t
byte-compile
property. If the property is non-nil
, then the function is
handled specially.
For example, the following input will show you that aref
is
compiled specially (see Array Functions) while assoc
is not
(see Sequence Functions):
(get 'aref 'byte-compile) ⇒ byte-compile-two-args
(get 'assoc 'byte-compile) ⇒ nil
function
(short form is #'
) instead of using an ordinary quote
(short '
). In byte compilation, the byte-compiler will look
for function quotes and compile them. Ordinarily quoted function
names will not be investigated nor byte compiled.
The same applies to anonymous function objects (lambda lists) in
non-obvious forms like backquoted macro bodies, or fset
constructions in macros of the form (list 'lambda argname
...)
.
On the other hand, if cheating the byte compiler is explicitly what
you want emacs lisp will also accept the normal quote
to refer
to the function cell in most cases.
defsubst
.
This eliminates the function call overhead. Since making a function
inline reduces the flexibility of changing the program, do not do it
unless it gives a noticeable speedup in something slow enough that
users care about the speed. See Inline Functions.
memq
, member
,
assq
, or assoc
is even faster than explicit iteration. It
may be worth rearranging a data structure so that one of these primitive
search functions can be used.
current-btime
function to obtain an absolute time stamp with a
microsecond resolution.
For example we measure the execution time of nreverse
for a
list of 1000 random numbers.
;; initialise the list
(setq lrn nil)
(dotimes (i 1000)
(setq lrn (cons (random) lrn)))
⇒ omitted
;; We use two time variables start and end.
(progn
(setq start (current-btime))
(setq lrn (nreverse lrn))
(setq end (current-btime)))
;; We investigate the time by simply subtracting start from end.
(- end start)
⇒ 190
;; This means nreverse
took about 190 microseconds.
;; The real value is highly likely a little less than this. ;; Let’s measure the overhead. (progn (setq start (current-btime)) (setq end (current-btime)) (- end start)) ⇒ 17
SXEmacs provides a multiplicity of types and containers to store your data. Which of them suits your purpose best depends on many things
Well, in this case you should definitely have a glance at the flavour you want to be compatible with. Also see Compatibility Tips.
If compatibility is not an issue, you can benefit in many cases from the large variety of dedicated data types in SXEmacs. See next item.
(Not yet prepared)
In some cases it is simply appropriate to use external tools. For example it does not make sense to re-implement the block zipping algorithm of bzip2 in elisp, instead create a process and call the bzip2 binary.
However, if external tools provide a shared object library the process approach will highly likely be a snail compared to an FFI implementation. The advantage is simply that FFI calls will not create that much overhead because the available data is simply reused and does not need further steps, e.g. preparing the input data for the external tool, or parsing the results and converting them to lisp data, again.
Again, think twice! An FFI implementation can waste a large amount of development time. Moreover, it requires a detailed knowledge of the internal concept of the external resource. It is very easy to crash your SXEmacs with FFI!
A safer way of using external libraries in the way FFI does is to
create an emodule. In very time critical scenarios, emodules may even
outperform FFI because large parts of a procedure can run at C level
without interacting with the lisp engine at all. You can even use all
the usual advantages of C, such as parallelism, multi-threading and
similar. Moreover, if desired you can wrap intermediate results to
special containers (using dynacat
s), and pass these to the lisp
level. Indeed, dynacat
s which escaped to the lisp level
are safe since there is no way to access or modify them. Of course,
you can envisage dedicated interface functions within your emodule
but even in that case the actual processing will always take place in
your emodule at C level.
Anyway, emodules suffer from a serious drawback: they have to be built first in order to use them. In contrast, both the process approach and the FFI implementation just work out of the box.
Next: Compatibility Tips, Previous: Style Tips, Up: Tips [Contents][Index]