Está en la página 1de 9

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 supseudocdigo : 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-getAcad-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; } acutPrintf("\nRealizando la prueba para %d repeticiones ...", n); // 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 50 500 1000 2500 5000 10000 10 210 431 FAS 10 169 340 VLX VBA ARX 19 221 440 10 120 250 0 40 90 220

1061 871

1080 631

2113 1811 2172 1282 431 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. Cualquier duda u opinin puede hacrmela llegar a davidesqb@hotmail.com. Un saludo. David Esquinas.