CAD PANACEA HAS MOVED TO http://cadpanacea.com
14 December 2007
Command vs. entmake vs. vla-add          
If you program with autolisp, you have probably used the command function at some point, probably to construct drawing entities. There is certainly nothing wrong with that. However, if you are working on a large program that constructs a lot of drawing entities, you may have noticed that the command function runs pretty slow.


I put together some tests to compare the (command) function to two other methods of entity creation, (entmake) and (vla-add...). The test constructs 1,999 line entities using various methods.


I originally posted this on 13 DEC 2007, but after receiving a couple of good comments, I decided to edit this original post rather than make a separate entry. Thanks to the comments by Petri and Matt, I added a couple of new tests to the roundup.


Test1 - Uses the (command) function with CMDECHO set to 1

Test2 - Uses the (command) function with CMDECHO set to 0 and NOMUTT set to 1 (this basically turns the command line off...)

Test3 - Uses the (entmake) function.

Test4 - Uses the (vla-add...) function

Test5 - Uses the (vla-add...) function, but moves (vla-get-modelspace (vla-get-ActiveDocument (vlax-get-acad-object))) outside the timer, which make sense because the time to do this task should not be included. Surprisingly, it didn't make much differance at all.

The results are shown below. The times represent the average of 5 consecutive runs.


  • Test1 - 11.7 seconds
  • Test2 - 5.50 seconds
  • Test3 - 0.44 seconds
  • Test4 - 0.94 seconds
  • Test5 - 0.90 seconds

So (entmake) is still the fastest method, (vla-add...) takes about twice as long as entmake, and the most efficient (command) method about 12X longer on average. Removing the command line echoes from the (command) method speeds this up considerably.

In summary, if you are only drawing few entities, you won't notice any difference by modifying your code. On the other hand, if you code is drawing hundreds of entities, you might consider a change. Keep in mind that these numbers are relative and will vary depending on the system.

The lisp code used is shown below


(defun date2sec ()
(setq s (getvar "DATE"))
(setq seconds (* 86400.0 (- s (fix s))))
)

(defun C:test1 ( / i timer endtimer)
(setvar "cmdecho" 1)
(setq i 1 timer (date2sec))
(while (< i 2000)
(command "._line" (list i i 0.0) (list (+ 2 i)(+ 3 i) 0.0) "")
(setq i (1+ i))
)
(setq endtimer (date2sec))
(alert (rtos (- endtimer timer) 2 8))
)

(defun C:test2 ( / i timer endtimer)
(setvar "cmdecho" 0)
(setvar "nomutt" 1)
(setq i 1 timer (date2sec))
(while (< i 2000)
(command "._line" (list i i 0.0) (list (+ 2 i)(+ 3 i) 0.0) "")
(setq i (1+ i))
)
(setq endtimer (date2sec))
(alert (rtos (- endtimer timer) 2 8))
(setvar "cmdecho" 1)
(setvar "nomutt" 0)
)

(defun C:test3 ( / i timer endtimer)
(setq i 1 timer (date2sec))
(while (< i 2000)
(entmake (list
(cons 0 "LINE")
(cons 10 (list i i 0.0))
(cons 11 (list (+ 2 i)(+ 3 i) 0.0))
)
)
(setq i (1+ i))
)
(setq endtimer (date2sec))
(alert (rtos (- endtimer timer) 2 8))
)


(defun C:test4 ( / i timer endtimer)
(vl-load-com)
(setq i 1 timer (date2sec) ms
(vla-get-modelspace
(vla-get-ActiveDocument
(vlax-get-acad-object))))
(while (< i 2000)
(vla-addline ms
(vlax-3d-point (list i i 0.0))
(vlax-3d-point (list (+ 2 i)(+ 3 i) 0.0))
)
(setq i (1+ i))
)
(setq endtimer (date2sec))
(alert (rtos (- endtimer timer) 2 8))
)

(defun C:test5 ( / i timer endtimer)
(vl-load-com)
(setq ms (vla-get-modelspace
(vla-get-ActiveDocument
(vlax-get-acad-object)
)
)
)
(setq i 1 timer (date2sec))
(while (< i 2000)
(vla-addline ms
(vlax-3d-point (list i i 0.0))
(vlax-3d-point (list (+ 2 i)(+ 3 i) 0.0))
)
(setq i (1+ i))
)
(setq endtimer (date2sec))
(alert (rtos (- endtimer timer) 2 8))
)

Labels: , , ,


PermaLink       Posted 12/14/2007 07:10:00 AM     
6 COMMENTS!


Comment from: Blogger Matt Stachoni
Date: December 13, 2007 at 3:49:00 PM CST  

In (C:LINE 3), take out the

(vla-get-modelspace
(vla-get-ActiveDocument
(vlax-get-acad-object)
)
)

statement from the timer and see if times improve.

As I understand it, getting the initial AcadObject / ActiveDocument / ModelSpace objects injects overhead that is not pertinent to the comparison between (entmake) and (vla-add-...).

I would also suggest you compare (entmod) to the equivalent (vla-put...) methods: you should see VLA operations to be orders of magnitude faster than old-school DXF operations.


Comment from: Blogger Unknown
Date: December 13, 2007 at 5:03:00 PM CST  

Hi,

in C:Line1 set cmdecho to 0 and nomutt to 1 and my time dropped from 24s to 9s. A lot of the time was spent on refreshing the commandline!

/Petri


Comment from: Blogger R.K. McSwain
Date: December 14, 2007 at 9:05:00 AM CST  

I updated/rewrote this post to accommodate you guys' comments.

Thanks!


Comment from: Anonymous Anonymous
Date: December 17, 2007 at 1:42:00 PM CST  

It's not actually all that surprising that (entmake) performs comparably to (or even better than) COM for entity creation: you need to pass an association list with all the data that's needed by the entity creation process.

What's also important to measure is the time it takes to update just one or two properties (such as the layer or color) of a large number of entities. In this particulatr scenarios COM should outperform (entmod), as (entmod) is dealing with much more data than the specific "delta" in entity properties.

Kean


Comment from: Anonymous Anonymous
Date: December 21, 2007 at 2:40:00 AM CST  

You should also make sure that OSNAP is off in the COMMAND-Functions. Have you made your tests with OSNAP on or off?

Cheers, Marco


Comment from: Blogger Unknown
Date: March 28, 2008 at 9:25:00 AM CDT  

I've modified the code to Test3 & Test5 to include the suggested modify test:

(defun C:test3 (/ i timer endtimer lst ed)
(setq i 1
timer (date2sec)
lst nil
) ;_ end of setq
(while (< i 2000)
(entmake (list
(cons 0 "LINE")
(cons 10 (list i i 0.0))
(cons 11 (list (+ 2 i) (+ 3 i) 0.0))
) ;_ end of list
) ;_ end of entmake
(setq lst (cons (entlast) lst))
(setq i (1+ i))
) ;_ end of while
(setq endtimer (date2sec))
(alert (strcat "2000 entities created in "
(rtos (- endtimer timer) 2 8)
" seconds"
) ;_ end of strcat
) ;_ end of alert

;; Added modify (change color to red
(setq i 0
timer (date2sec)
) ;_ end of setq
(while (< i (length lst))
(setq ed (entget (nth i lst)))
(setq ed (subst '(62 . 1) (assoc 62 ed) ed))
(entmod ed)
(setq i (1+ i))
) ;_ end of while
(setq endtimer (date2sec))
(alert (strcat "2000 entities modified in "
(rtos (- endtimer timer) 2 8)
" seconds"
) ;_ end of strcat
) ;_ end of alert
) ;_ end of defun

(defun C:test5 (/ i timer endtimer lst eo)
(vl-load-com)
(setq ms (vla-get-modelspace
(vla-get-ActiveDocument
(vlax-get-acad-object)
) ;_ end of vla-get-ActiveDocument
) ;_ end of vla-get-modelspace
) ;_ end of setq
(setq i 1
timer (date2sec)
) ;_ end of setq
(while (< i 2000)
(vla-addline
ms
(vlax-3d-point (list i i 0.0))
(vlax-3d-point (list (+ 2 i) (+ 3 i) 0.0))
) ;_ end of vla-addline
(setq lst (cons (entlast) lst))
(setq i (1+ i))
) ;_ end of while
(setq endtimer (date2sec))
(alert (strcat "2000 entities created in "
(rtos (- endtimer timer) 2 8)
" seconds"
) ;_ end of strcat
) ;_ end of alert

;; Added modify (change color to red
(setq i 0
timer (date2sec)
) ;_ end of setq
(while (< i (length lst))
(setq eo (vlax-ename->vla-object (nth i lst)))
(vla-put-color eo 1)
(setq i (1+ i))
) ;_ end of while
(setq endtimer (date2sec))
(alert (strcat "2000 entities modified in "
(rtos (- endtimer timer) 2 8)
" seconds"
) ;_ end of strcat
) ;_ end of alert
) ;_ end of defun

When I run this I get:
Test3 (0.17s make) (0.28s mod)
Test5 (0.41s make) (0.30s mod)

The slight discrepancy with mod may be because the need to obtain a vla-object from the ename.

Post a comment