Opened 14 years ago
Closed 14 years ago
#1043 closed defect (fixed)
Using the command Eval in NameBlocks
Reported by: | Pedro Gea | Owned by: | Víctor de Buen Remiro |
---|---|---|---|
Priority: | normal | Milestone: | |
Component: | Kernel | Version: | |
Severity: | critical | Keywords: | |
Cc: |
Description
Se encuentra un comportamiento inesperado al utilizar el comando Eval
dentro del método de un nameblock.
El objetivo de este tique es manifestar este problema e intentar entender qué está ocurriendo.
A continuación se indica un ejemplo en el que se reproduce un error similar al encontrado en un proyecto y en el que se encuentran las consecuencias más catastróficas:
Text expression = TxtListItem(For(1, 200, Text (Real i) { "Serie ExtendSerie( SubSer(Pulse(Succ(y2001,C,"<<i<<"),C),y2000, y2005), y1999, y2006)" }), "+"); NameBlock space = [[ Anything Evalua(Text e) { Eval(e) } ]]; Serie space::Evalua(expression);
La ejecuación de este código emplea algo más de 2 minutos y medio en acabar con toda la RAM libre y comenzar a enviar errores como:
ERROR: [14978] FATAL: No se pudo alojar un arreglo de 2558 items x 8 bytes
sin poder detenerse de ninguna forma más que matando el proceso asociado a TOLBase.
El mismo ejemplo utilizando simplemente Serie Eval(expression);
llega al resultado adecuado en algo más de 2 segundos y sin problema alguno.
¿Qué está ocurriendo?
En un ejemplo menos catástrófico se observa que el tiempo para evaluar la misma expresión es bastante distinto (sin llegar a dar errores) al usar Eval
o space::Evalua
.
Change History (2)
comment:1 Changed 14 years ago by
Status: | new → accepted |
---|
comment:2 Changed 14 years ago by
Resolution: | → fixed |
---|---|
Status: | accepted → closed |
He estado haciendo pruebas con un ciclo de 50 en lugar de 200 para que no se caiga, y por lo que veo no tiene nada que ver con que sea un método de un NameBlock, pues si se define una función normal pasa exactamente lo mismo
Por algún motivo tarda mucho más en evaluar y consume más memoria, aunque, si no se cae por el camino, cuando se descompila se recupera por completo esa memoria.
En cambio, si definimos una función con tipo de retorno conocido, tanto fuera como dentro de un NameBlock, todo funciona correctamente, ni se consume memoria ni tarda de más apenas:
Por último, si no usamos ninguna función pero no le especificamos al Eval el tipo devuelto, es decir si escribimos
entonces pasa algo intermedio, no se gasta memoria pero tarda casi tanto como en el caso de usar una función sin tipo de retorno especificado.
Evaluar con la gramática Anything es siempre más costoso pues tiene que buscar en todas las gramáticas tanto los operadores como los operandos, pero no pensaba yo que pudiera ser tanto. Lo que no tengo ni idea de dónde viene es el consumo de memoria.
Interviniendo el código C++ de la función especial Eval para que compruebe si la palabra inicial de la expresión es un nombre de tipo válido con el cual evaluar la expresión desaparece el problema aunque sigo sin saber porqué se consume tanta RAM.
En general la norma debe ser que siempre que se conozca el tipo que devuelve una expresión se debe especificar el mismo.