You are on page 1of 10

Velocidad de ejecucin para lenguajes de

personalizacin de AutoCAD
Actualmente AutoCAD permite su personalizacin mediante cuatro
lenguajes de programacin que pueden ser usados para realizar
desde tareas simples, repetitivas y con mucha frecuencia tediosas,
hasta complejas aplicaciones especializadas en cualquier campo del
diseo grfico asistido por computadora.
Estos cuatro lenguajes incluyen AutoLISP, Visual LISP, Visual Basic
(VBA) y C++ (ObjectARX/ObjectDBX). Visual Lisp es el hermano
mayor de AutoLisp y aunque podemos decir que engloba a AutoLISP
prefiero tratarlos como lenguajes separados y entender Visual LISP
como el lenguaje AutoLISP con extensiones ActiveX (u OLE, que es lo
mismo).
Ninguno de estos cuatro lenguajes es mejor ni peor que otro,
sencillamente son adecuados o no para la realizacin de una tarea
concreta. No obstante, personalmente la velocidad de ejecucin de
los algoritmos que implemento es una cuestin que me preocupa
mucho. Y aunque influye mucho ms sobre el rendimiento la forma
de implementar, el propio diseo del lenguaje tambin tiene un peso
especfico considerable.
Con el fin de comparar la velocidad de ejecucin de estos cuatro
lenguajes he preparado una sencilla prueba que permita realizar esta
comparacin. Aunque ya supongo cualitativamente los resultados de
la prueba, tengo curiosidad por cuantificarlos. Por ello he preparado la
siguiente prueba.
Ejecutar una rutina que dibuje un nmero determinado de crculos
concntricos y al finalizar muestre su tiempo de ejecucin. Este sera
ms o menos su pseudocdigo :
funcion DibujaCirculo(centro, radio)
{
AadeEntidadCirculoalModeloEspacio(centro, radio)
}
funcion concir()
{
solicitarepeticiones(n)
tomatiempoinicial()
repite n
{
DibujaCirculo(centro, radio)
radio = radio + 0.001

}
tomatiempofinal()
}

presentatiempoejecucion()

He intentado implementar las rutinas en los cuatro lenguajes en la


forma en que se parezcan lo mximo posible sin alterar la
metodologa de programacin inherente a cada uno de los lenguajes
de programacin bajo AutoCAD. Quizs se podran optimizar algunas
rutinas metiendo algunos parches para evitar ciertas llamadas, etc.
pero entonces creo que la prueba no tendra sentido. Por ello he
intentado respetar lo mximo posible las buenas formas de
programacin para todas las rutinas y sus respectivos lenguajes en
los que han sido implementadas.
La prueba consta de cinco programas que corresponden con lo
siguiente :

LSP : programa en AutoLISP. Comando : concirlsp

FAS : programa en AutoLISP compilado con Visual LISP.


Comando : concirfas

VLX : programa en AutoLISP con las extensiones ActiveX de


Visual LISP. Comando : concirvlx

VBA : programa en Visual Basic (VBA). Macro : concirVBA

ARX : programa en C++ (ObjectARX). Comando : concirarx

Los fuentes y los programas compilados se adjuntan en un archivo.


Aqu coloco las partes principales de cada uno de ellos :

AutoLISP (LSP) y Visual LISP (FAS)


(defun DibujaCirculo (centro radio)
;crear la nueva entidad circle
(entmake (list '(0 . "CIRCLE") (cons 10 centro) (cons 40
radio)))
)
(defun c:concirlsp ( / centro radio n t0 tf tiempo)
;mensaje de consola
(princ "\nPrueba de velocidad [LSP].\n")
;inicializar las variables
(setq centro (list 0 0 0))

(setq radio 1.000)


;solicitar el nmero de repeticiones
(setq n (getint "\nNmero de repeticiones : "))
(if (or (= n nil) (<= n 0)) (setq n 1000))
(princ "\nRealizando la prueba para ")
(princ n)
(princ " repeticiones ...\n")
;tomar el tiempo inicial
(setq t0 (getvar "DATE"))
;repetir n veces ...
(repeat n
(DibujaCirculo centro radio)
(setq radio (+ radio 0.001))

;tomar el tiempo final


(setq tf (getvar "DATE"))
;mostrar los milisegundos
(setq tiempo (* (- tf t0) 86400000))
(princ
(princ
(princ
(princ
(princ

"\nTiempo de ejecucin de la prueba = ")


(fix tiempo))
" ms, con ")
n)
" repeticiones.")

(princ)
)

Visual LISP (VLX)


(defun DibujaCirculoVLX (centro radio)

;aadir la nueva entidad circle a la base de datos de AutoCAD


(vla-addCircle *MODELSPACE* (vlax-3D-point centro) radio)

(defun c:concirvlx ( / centro radio n t0 tf tiempo)


;capturar los errores
(defun *error* (msg)
(setq *error* nil)
;liberar
(setq *MODELSPACE* nil)
(princ msg)
)
;mensaje de consola
(princ "\nPrueba de velocidad [VLX].\n")

;cargar las funciones extendidas de AutoLISP


(vl-load-com)
;obtener un puntero al modelo espacio del documento activo
(setq *MODELSPACE* (vla-get-ModelSpace (vla-get-ActiveDocument
(vlax-get-Acad-Object))))
;inicializar las variables
(setq centro (list 0 0 0))
(setq radio 1.000)
;tomar el nmero de repeticiones
(setq n (getint "\nNmero de repeticiones : "))
(if (or (= n nil) (<= n 0)) (setq n 1000))
(princ "\nRealizando la prueba para ")
(princ n)
(princ " repeticiones ...\n")
;tomar el tiempo inicial
(setq t0 (getvar "DATE"))
;repetir n veces ...
(repeat n
(DibujaCirculoVLX centro radio)
(setq radio (+ radio 0.001))
)
;tomar el tiempo final
(setq tf (getvar "DATE"))
;mostrar los milisegundos
(setq tiempo (* (- tf t0) 86400000))
(princ
(princ
(princ
(princ
(princ

"\nTiempo de ejecucin de la prueba = ")


(fix tiempo))
" ms, con ")
n)
" repeticiones.")

;liberar
(setq *MODELSPACE* nil)
(princ)
)

Visual Basic (VBA)


Option Explicit
'
Public Sub DibujaCirculo(ByRef centro As AcPoint, _
ByRef radio As Double)
'
On Error Resume Next
'
Dim centerPoint(0 To 2) As Double
'
'/* preparar la matriz */

With centro
'
centerPoint(0) = .X
centerPoint(1) = .Y
centerPoint(2) = .Z
'
End With
'
'/* usaremos vinculacin temprana para optimizar
'
la velocidad de ejecucin */
Dim objCircle As AcadCircle
'
Set objCircle = ThisDrawing.ModelSpace.AddCircle(centerPoint,
radio)
'
End Sub
'
Public Sub concirVBA()
'
On Error Resume Next
'
Dim centro
As New AcPoint
Dim radio
As Double
Dim n
As Integer
Dim t0
As Double
Dim tf
As Double
Dim i
As Integer
Dim tiempo
As Double
Dim promptStr
As String
'
'/* mensaje de consola */
ActiveDocument.Utility.Prompt (vbCrLf & "Prueba de velocidad
[VBA].")
'
'/* inicializar las variables */
'
With centro
'
.X = 0#
.Y = 0#
.Z = 0#
'
End With
'
radio = 1#
'
'/* solicitar el nmero de repeticiones */
'
Err.Clear
'
n = ActiveDocument.Utility.GetInteger(vbCrLf & "Nmero de
repeticiones : ")
'
'/* chequear si se cancel */
If (Err.Number = -2147352567) Then
'
ActiveDocument.Utility.Prompt ("*Cancel*" & vbCrLf)
'
Exit Sub
'
End If

'
If (n <= 0) Then
'
n = 1000
'
End If
'
ActiveDocument.Utility.Prompt (vbCrLf & "Realizando la prueba para
" & _
n & " repeticiones ..." & vbCrLf)
'
'/* tomar el tiempo inicial */
t0 = ActiveDocument.GetVariable("DATE")
'
'/* repetir n veces ... */
For i = 1 To n
'
Call DibujaCirculo(centro, radio)
'
radio = radio + 0.001
'
Next i
'
'/* tomar el tiempo final */
tf = ActiveDocument.GetVariable("DATE")
'
'/* calcular los milisegundos */
tiempo = (tf - t0) * 86400000#
'
promptStr = vbCrLf & "Tiempo de ejecucin de la prueba = " & _
CLng(tiempo) & " ms, con " & n & " repeticiones." &
vbCrLf
'
ActiveDocument.Utility.Prompt promptStr
'
'/* liberar */
'
Set centro = Nothing
'
End Sub

C++ (ObjectARX)
Acad::ErrorStatus appendEntityToModelSpaceBlockTableRecord(AcDbEntity
*pEntity, AcDbObjectId& ID)
{
Acad::ErrorStatus
es;
AcDbBlockTable *pBlockTable;
// obtener un puntero a la BlockTableRecord Modelo Espacio
es = acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pBlockTable, AcDb::kForRead);
if (es != Acad::eOk)
return es;
AcDbBlockTableRecord *pBlockTableRecord;
es = pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,
AcDb::kForWrite);

pBlockTable->close();
if (es != Acad::eOk)
return es;
// aadir la entidad a la BlockTableRecord
es = pBlockTableRecord->appendAcDbEntity(ID, pEntity);
// se cierra la entidad
pEntity->close();
pBlockTableRecord->close();
}

return es;

void DibujaCirculo(AcGePoint3d &centro, double &radio)


{
AcDbCircle
*pCircle;
AcGeVector3d
normal(0.0, 0.0, 1.0);
// crear la nueva entidad circle ...
try
{
}

pCircle = new AcDbCircle(centro, normal, radio);

catch(const std::bad_alloc&)
{
acdbFail("\nError de asignacin de memoria
[DibujaCirculo].");
return;
}
AcDbObjectId ID;
// ... y aadirla a la base de datos de AutoCAD
if
(appendEntityToModelSpaceBlockTableRecord((AcDbEntity*)pCircle, ID) !=
Acad::eOk)
{
if (pCircle)
{
delete pCircle;
}
acdbFail("\nError al aadir la entidad a la Base de
Datos [DibujaCirculo].");
}

return;

return;
}
// This is command 'CONCIRARX'
void TPLDPruebasconcirarx()
{
// mensaje de consola

acutPrintf("\nPrueba de velocidad [ARX].\n");


// inicializar las variables
AcGePoint3d
centro(0, 0, 0);
double
radio = 1.000;
// solicitar el nmero de repeticiones
int n;
if (acedGetInt("\nNmero de repeticiones : ", &n) == RTCAN)
{
acutPrintf("*Cancel*\n");
return;
}
if (n <= 0)
{
n = 1000;
}
n);

acutPrintf("\nRealizando la prueba para %d repeticiones ...",


// tomar el tiempo inicial
struct resbuf rb;

if (acedGetVar("DATE", &rb) != RTNORM)


{
acdbFail("\nError al tomar la variable de Sistema
DATE.");
}
double t0 = static_cast<double>(rb.resval.rreal);
// repetir n veces ...
for (int i = 0; i < n; i++)
{
DibujaCirculo(centro, radio);
}

radio += 0.001;

// tomar el tiempo final


if (acedGetVar("DATE", &rb) != RTNORM)
{
acdbFail("\nError al tomar la variable de Sistema
DATE.");
}
double tf = static_cast<double>(rb.resval.rreal);
// mostrar los milisegundos
double tiempo = (tf - t0) * 86400000;
acutPrintf("\nTiempo de ejecucin de la prueba = %.0f ms, con
%d repeticiones.", tiempo, n);

return;
}

Tabla de resultados
Pues aqu est el resultado de la prueba hecho con un P4 a 1.7GHz
con 256MB de RAM y bajo AutoCAD 2000. Antes de presentar la tabla
he de decir que personalmente me esperaba lo siguiente.
AutoLISP sera es ms lento de todos, seguido muy de cerca por el
formato FAS. Posteriormente crea que el formato VLX ira muy a la
par con VBA y no hubiera sabido decidirme entre uno y otro para la
tercera posicin. Y por ltimo me esperaba una victoria aplastante de
ObjectARX. Pero hay sorpresas :
REPETICIONES

Tiempo en milisegundos
LSP

FAS

VLX

VBA

ARX

50

10

10

19

10

500

210

169

221

120

40

1000

431

340

440

250

90

2500

1061

871

1080

631

220

5000

2113

1811

2172

1282

431

10000

4126

3925

4336

2564

871

Qu ha ocurrido con VLX?. Bien, pues buscando un poco por la red


encontr esto:
Will My Program Run Faster?
There are two sides to the time savings issue in relationship to a
programming tool such as Visual LISP.
A topic of interest to many programmers is speed of execution, or more
succinctly, "Will my program run
faster?" The answer is basically an affirmative-with some caveats.
There are subtle differences in the
way the individual interpreters evaluate program code, and, as a
consequence of the way they are built,
programs will run at different speeds. The style of the programming
will influence the speed more than
anything else. For example, when I tested the speed of Visual LISP
versus AutoLISP, I found a case where
AutoLISP was faster. AutoLISP handled a recursion problem faster than
Visual LISP. The example used was
the common factorial computation function. Even after the Visual LISP
program was compiled into an ARX
module, AutoLISP was slightly faster at solving the problem. However,
in the other tests using more
common iteration structures and involving floating point arithmetic,
the Visual LISP program was two

to three times faster on a regular basis. You can expect AutoLISP


applications that involve numerical
work to run faster in the Visual LISP environment (once properly
prepared).
Fuente:
Bill Kramer
http://cadence.advanstar.com/1998/0898/focus0898.html

Tengan cuidado con este tipo de cosas ya que a veces creemos


cosas errneamente que nos pueden llevar a realizar malos diseos y
no entender el porqu de ello. As que cuando la velocidad de
ejecucin sea un item a tener en cuenta ojo con las funciones que
empleemos, parece ser que no por ser una funcin ms moderna est
ms optimizada o tenga que ser ms rpida, aunque la mayora
estaremos de acuerdo en que debera serlo.

You might also like