Search code examples
performancecommon-lispsbcltypingclos

defclass type information for performance


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.


Solution

  • 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.