In the following program, removing the line
(declare (type (simple-array bit) arr))
makes running time increase by more than a factor of 3, using SBCL. The type information given in the defclass
macro via :type
on the other hand appears to have no impact on performance.
(defclass class-1 () ((arr :type (simple-array bit))))
(defun sample (inst)
(declare (type class-1 inst))
(let ((arr (slot-value inst 'arr)))
(declare (type (simple-array bit) arr)) ;; 3x running time without
(map-into arr #'(lambda (dummy) (if (< (random 1.0) 0.5) 0 1)) arr)))
(let ((inst (make-instance 'class-1)))
(setf (slot-value inst 'arr) (make-array 10000 :element-type 'bit))
(loop for i from 1 to 10000 do (sample inst)))
How can I have the same performance benefit without having to declare the arr
slot a simple-array bit
each time I use it? The latter is particularly annoying since (as far as I have found out) is requires to introduce a binding via let
or similar each time; I cannot just write (slot-value inst 'arr)
in the place where I need it.
First of all, this is an SBCL-specific question, you might get a better answer on the SBCL user list. Different compilers do different optimizations, and most ignore at least some declarations.
Second, you should let-bind arr
because you are using it twice.
Third, you can use the
if you want to avoid let-bind:
(the (simple-array bit) (slot-value inst 'arr))
Fourth, if you want the compiler to infer the type, use a specific reader instead of slot-value
:
(defclass c () ((arr :type (simple-array bit) :reader c-arr)))
(defun sample (inst)
(declare (type class-1 inst))
(let ((arr (c-arr inst)))
(map-into arr #'(lambda (dummy) (random 2)) arr)))
c-arr
should allow the compiler to infer the value type easier, but (as you have discovered yourself!) you might need to declare its return type:
(declaim (ftype (function (c) (simple-array bit)) c-arr))
The reason is, apparently, that SBCL ignores slot type declarations.
Adding type information has different effects depending which compiler you use and which optimization levels are in effect.
For an optimizing compiler it might look like this:
Some compilers also ignore type declarations for CLOS slots. If they don't, there are again two variants: 1) safety means runtime checks added and 2) low safety and high speed means specialized instructions generated
Summary: type declarations may add runtime overhead with high safety due to added type checks. Specialized data types not necessarily faster with low safety and high optimization.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With