defclass type information for performance
Asked Answered
P

2

5

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.

Podium answered 14/4, 2014 at 13:3 Comment(0)
H
5

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.

Hoodmanblind answered 14/4, 2014 at 13:52 Comment(2)
Using a reader was a good idea, but it didn't work for me directly. What worked, however, is a reader plus the following, using your class and function names: (declaim (ftype (function ((c)) (simple-array bit)) c-arr)). With this in place, even the :type can be omitted, as well as (declare (type class-1 inst)).Podium
It probably should be (declaim (ftype (function (c) (simple-array bit)) c-arr)). Both appear to work, I am not sure why. Haven't used that form before.Podium
G
4

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:

  • no information: generic operations, reasonably fast
  • type declaration available: added operations to check for this specific type during runtime -> slower
  • type declarations available, high optimization and low safety: NO added operations to type check at runtime, specialized code generated for this type -> POSSIBLY FASTER

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.

Gapin answered 14/4, 2014 at 14:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.