Opened 12 years ago

Closed 10 years ago

#220 closed enhancement (fixed)

Adding a type specifier to one slot makes instantiation over 3x slower

Reported by: alms Owned by: gb
Priority: major Milestone:
Component: Performance Version:
Keywords: Cc:

Description

Running on a 2.16 GHz Core 2 Duo MacBook? Pro with 2 GB RAM:

Welcome to Clozure Common Lisp Version 1.1-r7809 (DarwinX8664)!
? (defclass class-with-typed-slot ()
  ((attribute-one :initarg :attribute-one
                  :type string)))

(defclass class-with-untyped-slot ()
  ((attribute-one :initarg :attribute-one)))

(defun instantiate-class-with-typed-slot (times)
  (dotimes (i times)
    (make-instance 'class-with-typed-slot :attribute-one "one")))

(defun instantiate-class-with-untyped-slot (times)
  (dotimes (i times)
    (make-instance 'class-with-untyped-slot :attribute-one "one")))

? ? ? INSTANTIATE-CLASS-WITH-UNTYPED-SLOT
? (time (instantiate-class-with-typed-slot 50000))
(INSTANTIATE-CLASS-WITH-TYPED-SLOT 50000) took 336 milliseconds (0.336 seconds) to run 
                    with 2 available CPU cores.
During that period, 307 milliseconds (0.307 seconds) were spent in user mode
                    6 milliseconds (0.006 seconds) were spent in system mode
4 milliseconds (0.004 seconds) was spent in GC.
 6,400,624 bytes of memory allocated.
NIL
? (time (instantiate-class-with-untyped-slot 50000))
(INSTANTIATE-CLASS-WITH-UNTYPED-SLOT 50000) took 97 milliseconds (0.097 seconds) to run 
                    with 2 available CPU cores.
During that period, 93 milliseconds (0.093 seconds) were spent in user mode
                    4 milliseconds (0.004 seconds) were spent in system mode
3 milliseconds (0.003 seconds) was spent in GC.
 4,800,624 bytes of memory allocated.
NIL
? 

Change History (3)

comment:1 Changed 12 years ago by gb

  • Priority changed from minor to major
  • Status changed from new to assigned

It is generally going to be more expensive to do something than it is not to do it. A lot of the particular expense in your example has to do with the (sometimes poor) way that slot type specifiers get canonicalized and decanonicalized; what we'd like is for STRINGP to be called on every attempt to initialize the slot, but STRING gets canonicalized as (VECTOR CHARACTER), and we fail to recognize that as being entirely equivalent to STRING.

(let* ((pred (let* ((ctype (ccl::specifier-type 'string)))
               #'(lambda (x) (ccl::ctypep x ctype)))))
  (time (dotimes (i 1000000) (funcall pred "a"))))
(DOTIMES (I 1000000) (FUNCALL PRED "a")) took 1,747 milliseconds (1.747 seconds) to run 
                    with 4 available CPU cores.
During that period, 1,743 milliseconds (1.743 seconds) were spent in user mode
                    3 milliseconds (0.003 seconds) were spent in system mode
9 milliseconds (0.009 seconds) was spent in GC.
 16,000,000 bytes of memory allocated.
 65 minor page faults, 0 major page faults, 0 swaps.

instead of:

(let* ((pred 'stringp))
  (time (dotimes (i 1000000) (funcall pred "a"))))
(DOTIMES (I 1000000) (FUNCALL PRED "a")) took 16 milliseconds (0.016 seconds) to run 
                    with 4 available CPU cores.
During that period, 16 milliseconds (0.016 seconds) were spent in user mode
                    0 milliseconds (0.000 seconds) were spent in system mode
NIL

which is a little more like it.

So, we shouldn't see this kind of overhead for types like STRING and SIMPLE-STRING; in some other cases, we should expect significant work to be involved in type checking.

comment:2 Changed 12 years ago by alms

By the way, I discovered this by way of the CLOS/SIMPLE-INSTANTIATE benchmark. Removing the slot type from that benchmark cuts our execution time by about 65%.

comment:3 Changed 10 years ago by gb

  • Resolution set to fixed
  • Status changed from assigned to closed

In this case, instantiation of a class with a slot of type STRING is currently marginally slower (a few %) than instantiation of a similar class with an untyped slot.

Note: See TracTickets for help on using tickets.