You are on page 1of 12

1.

- INTRODUCCION

Idealmente, los compiladores deberían producir código objeto que fuera tan bueno como si
estuviera escrito directamente por un buen programador. La realidad es que esto es dificil de
conseguir y muy pocas veces se alcanza esa meta.

Sin embargo, el código generado por el compilador puede ser mejorado por medio de unas
transformaciones que se han denominado tradicionalmente optimizaciones, aunque el término
optimización es impropio ya que raramente se consigue que el código generado sea el mejor
posible.

El objetivo de las técnicas de optimización es mejorar el programa objeto para que nos dé un
rendimiento mayor. La mayoría de estas técnicas vienen a compensar ciertas ineficiencias que
aparecen en el lenguaje fuente, ineficiencias que son inherentes al concepto de lenguaje de alto
nivel, el cual suprime detalles de la máquina objeto para facilitar la tarea de implementar un
algoritmo. Las distintas técnicas de optimización se pueden clasificar o dividir de diversas formas.

Por una parte podemos hablar de aquellas técnicas que son dependientes de la máquina, y
aquellas que son independientes de la máquina (o sea, técnicas que sólo se pueden aplicar a una
determinada máquina objeto y técnicas que son aplicables a cualquier máquina objeto).

Por otra parte, las técnicas de optimización se dividen también en locales y globales. Las técnicas
de optimización locales analizarán sólo pequeñas porciones de código y en ellas realizarán
mejoras, mientras que para la aplicación de las técnicas globales será necesario el análisis de todo
el código.

Cada optimización está basada en una función de coste y en una transformación que preserve el
significado del programa. Mediante la función de coste queremos evaluar la mejora que hemos
obtenido con esa optimización y si compensa con el esfuerzo que el compilador realiza para poder
llevarla a cabo.

Los criterios más comunes que se suelen emplear son el ahorro en el tamaño del código, la
reducción del tiempo de ejecución y la mejora de las necesidades del espacio para los datos del
programa.

En cuanto a preservar el significado del programa, es lógico que no tendría sentido realizar
optimizaciones que modificaran el comportamiento del programa. Aunque parezca evidente,
puede haber complicadas optimizaciones que fallen en ese aspecto.

Por último, comentar que por muchas optimizaciones que se hayan realizado para mejorar el
rendimiento de un programa, siempre se obtendrá un mejor rendimiento si se utiliza un algoritmo
mejor.

Por todo ello, para obtener un buen programa lo primero es ver qué algoritmo utilizamos y si no es
posible desarrollar otro más eficiente. Una vez implementado el mejor algoritmo, ya se puede
entonces optimizar el código obtenido a partir de él para mejorar el rendimiento del programa.

Eliminación de código muerto. Las técnicas de optimización a través de varios procedimientos se reducen a aplicar las vistas aquí a cada uno de los procedimientos y después realizar un análisis interprocedural. Por programa sencillo entendemos aquel que se reduce a un sólo procedimiento o subrutina. Como el tiempo de optimización es gran consumidor de tiempo (dado que tiene que recorrer todo el árbol de posibles soluciones para el proceso de optimización) la optimización se deja hasta la fase de prueba final. Eliminación de sub-expresiones comunes. Son aquellas transformaciones que simplifican expresiones y/o reemplazan operaciones costosas de la máquina por otras menos costosas. o secuencia de sentencias en las cuales el flujo de control empieza al principio y acaba al final. 3. A partir de aquí dividimos el programa en bloques básicos [AHO86]. pues es una representación adecuada del programa sobre la que emplear las diversas técnicas de optimización. Además de este tipo de optimizaciones locales a un . Desafortunadamente no existen optimizadores que hagan un programa más rápido y que ocupe menor espacio. Renombrar variables temporales. La optimización es un proceso que tiene a minimizar o maximizar alguna variable de rendimiento. 4. La mayoría de los compiladores tienen una optimización baja. espacio. La optimización se realiza reestructurando el código de tal forma que el nuevo código generado tenga mayores beneficios. 2. obtenemos código intermedio de tres direcciones [AHO77]. se necesita de compiladores especiales para realmente optimizar el código. b) Transformaciones algebraicas. Intercambio de sentencias independientes adyacentes. Las optimizaciones se realizan en base al alcance ofrecido por el compilador. Algunos editores ofrecen una versión de depuración y otra de entrega o final. Partiendo de un programa sencillo. Estas optimizaciones se pueden dividir en: a) Optimizaciones que no modifican la estructura. es decir. Son: 1. Este último tipo de análisis no lo vamos a desarrollar en este artículo. entre más optimización mayor tiempo de compilación. procesador. etc. Las sentencias de un bloque básico constituyen una unidad sobre la cual se aplican las optimizaciones locales.1 TIPOS DE OPTIMIZACIÓN Existen diversas técnicas de optimización que se aplican al código generado para un programa sencillo. 3. sin posibilidad de parar o de tener saltos. generalmente tiempo.OPTIMIZACIÓN Las optimizaciones pueden realizarse de diferentes formas. La optimización va a depender del lenguaje de programación y es directamente proporcional al tiempo de compilación.

e intenta mejorar el rendimiento del programa por medio de reemplazar esa breve secuencia de instrucciones objeto por otra secuencia más corta y/o más rápida. generalmente tiempo. que lo veremos en el siguiente apartado. La mayoría de los compiladores tienen una optimización baja. Debido a la naturaleza de este tipo de optimización. procesador. hay dos tipos de optimizaciones importantes que se realizan: la localización y la asignación global de registros para las variables. con lo que serán necesarias varias pasadas para lograr la máxima optimización. Desafortunamente no existen optimizador que hagan un programa más rápido y que ocupe menor espacio. Las optimizaciones se realizan en base al alcance ofrecido por el compilador. 4. 2. y las optimizaciones que se realizan en los bucles. se necesita de compiladores especiales para realmente optimizar el código. espacio. donde se describen 123 combinaciones distintas de sentencias de código intermedio con sus correspondientes equivalencias Las técnicas de optimización global se basan todos ellos en el análisis global de flujo de datos. Eliminación de instrucciones redundantes. . su salida es susceptible de ser optimizada de nuevo.bloque básico. 3. a lo largo de los distintos bloques básicos que forman el código del programa. es decir. pues su ámbito se reduce a una breve secuencia de instrucciones. entre más optimización mayor tiempo de compilación Como el tiempo de optimización es gran consumidor de tiempo (dado que tiene que recorrer todo el árbol de posibles soluciones para el proceso de optimización) la optimización se deja hasta la fase de prueba final. Este análisis se realiza para el código de todo el programa. es decir. La optimización va a depender del lenguaje de programación y es directamente proporcional al tiempo de compilación. Simpificaciones algebraicas. La optimización es un proceso que tiene a minimizar o maximizar alguna variable de rendimiento. existe otro tipo de optimizaciones aún más locales. Optimizaciones en el flujo de control. Algunos editores ofrecen una versión de depuración y otra de entrega o final. siendo los más usuales los siguientes: 1. Suponiendo que tenemos la información que nos proporciona este análisis. Una aplicación de este tipo de optimización se puede encontrar en el kit ACK desarrollado por Tanembaum [Tane82]. etc. Uso de instrucciones máquina específicas. La optimización se realiza reestructurando el código de tal forma que el nuevo código generado tenga mayores beneficios.Las optimizaciones pueden realizarse de diferentes formas. A este tipo de optimización local se le llama optimización peephole. Hay varios tipos de optimización peephole.

. la concurrencia. • La idea del bloque básico es encontrar partes del programa cuyo análisis necesario para la optimización sea lo más simple posible. La optimización local sirve cuando un bloque de programa o sección es crítico por ejemplo: la E/S. En la mayoría de las ocasiones a través de funciones. etc. Implicaciones: – Si se ejecuta una instrucción del bloque se ejecutan todas en un orden conocido en tiempo de compilación. Como el espacio de soluciones es más pequeño la optimización local es más rápida Las características de las optimizaciones locales es que solo se ven reflejados en dichas secciones. la rapidez y confiabilidad de un conjunto de instrucciones. La optimización local sirve cuando un bloque de programa o sección es crítico por ejemplo: la E/S.3.1. la concurrencia. • Las optimizaciones locales se realizan sobre el bloque básico • Optimizaciones locales – Folding – Propagación de constantes – Reducción de potencia – Reducción de subexpresiones comunes Bloque Básico • Un bloque básico es un fragmento de código que tiene una única entrada y salida. métodos. La característica de las optimizaciones locales es que sólo se ven reflejados en dichas secciones. la rapidez y confiabilidad de un conjunto de instrucciones.1 LOCALES La optimización local se realiza sobre módulos del programa. y cuyas instrucciones se ejecutan secuencialmente. clases. procedimientos.

– Se añade el atributo de constante temporal a los símbolos no terminales y a las variables de la tabla de símbolos. – Se añade el procesamiento de las constantes a las reglas de análisis de expresiones. – Ejemplo: A=2+3+A+C -> A=5+A+C • Estas optimizaciones permiten que el programador utilice cálculos entre constantes representados explícitamente sin introducir ineficiencias.Ensamblamiento (Folding) • El ensamblamiento es remplazar las expresiones por su resultado cuando se pueden evaluar en tiempo de compilación (resultado constante). Implementación del Folding • Implementación del floding durante la generación de código realizada conjuntamente con el análisis sintáctico. – Optimiza: 2+3+b -> 5+b • Hay una suma de constantes (2+3)+b – No optimiza: 2+b+3 -> 2+b+3 • No hay una suma de constantes (2+b)+3 Implementación del Folding .

14 G2R=PI/180 -> G2R=3.14 -> PI=3. Propagación de constantes • Desde que se asigna a una variable un valor constante hasta la siguiente asignación. . • Ejemplo: Propagación Ensamblamiento PI=3. – #define a 10 Con la ventaja que la variable puede ser local.14 -> PI=3.• Implementación posterior a la generación de código – Buscar partes del árbol donde se puede aplicar la propiedad conmutativa: • Sumas/restas: como la resta no es conmutativa se transforma en sumas: a+b-c+d -> a+b+(-c)+d • Productos/divisiones: como la división no es conmutativa se transforma en productos: a*b/c*e - > a*b*(1/c)*e – Buscar las constantes y operarlas – Reconstruir el árbol.017 PI y G2R se consideran constantes hasta la próxima asignación. se considera a la variable equivalente a la constante. • Estas optimizaciones permiten que el programador utilice variables como constantes sin introducir ineficiencias. Por ejemplo en C no hay constantes y será lo mismo utilizar – Int a=10.14/180 -> G2R=0.

.constante) – Procesar secuencialmente la lista de expresiones y asignaciones – Para expresión y asignación • Sustituir las apariciones de las variables que se encuentran en el conjunto de definiciones por sus constantes asociadas. – Para asignaciones • Eliminar del conjunto de definiciones la definición de la variable asignada • Añadir la definición de la variable asignada si se le asigna una constante. implementación de la Propagación de Constantes • Separar el árbol en bloques básicos – Cada bloque básico será una lista de expresiones y asignaciones • Para cada bloque básico – Inicializar el conjunto de definiciones a conjunto vacío. • Definición: (variable.• Actualmente en C se puede definir const int a=10.

5 2. Reutilizaci on de expresiones comunes a=b+c d=a-d e=b+c f=a-d ! a=b+c d=a-d e=a f=a-d 3. sustituir todos los usos de f por a a=3+i f=a b=f+c d=a+m m=f+d ! a=3+i b=a+c d=a+m m=a+d .Ejecuci on en tiempo de compilaci on Precalcular expresiones constantes (con constantes o variables cuyo valor no cambia) i=2+3!i=5 j=4 f = j + 2. Propagaci on de copias Ante instrucciones f = a.5 ! j=4 f = 6.

izq. 8*x. x<<1 (despl. x<<3...) 4*x. Ejecución en tiempo de compilación Precalcular expresiones constantes (con constantes o variables cuyo valor no cambia). x / 2 ! x>>2 EJEMPLOS: 1... 3!i=5 j=4 f = j + 2. ! x<<2.5 ! j=4 f = 6.. Reutilización de expresiones comunes a=b+c d=a-d e=b+c f=a-d ! a=b+c d=a-d e=a f=a–d .5 2..Reducci on de potencia Reemplazar una operaci on por otra equivalente menos costosa x2 ! x * x 2*x ! x + x (suma).

Propagación de copias Ante instrucciones f=a. sustituir todos los usos de f por a. Transformaciones algebraicas: Aplicar propiedades matemáticas para simplificar expresiones o Eliminación secuencias nulas o Reducción de potencia o Reacondicionamiento de operandos 3. a=3+i f=a b=f+c d=a+m m=f+d ! a=3+i b=a+c d=a+m m=a+d 4. Eliminación redundancias en acceso matrices Localizar expresiones comunes en cálculo direcciones de matrices. y si dichas acciones están mal realizadas.3.2 Bucles • Los ciclos son una de las partes más esenciales en el rendimiento de un programa dado que realizan acciones repetitivas.1. el problema se hace N veces más grandes. • La mayoría de las optimizaciones sobre ciclos tratan de encontrar elementos que no deben repetirse en un ciclo. Ciclos . 5.

• Algunas optimizaciones incluyen utilizar como variables registros del CPU. • c = 5.3 Globales • La optimización global se da con respecto a todo el código. Ciclos • El problema de la optimización en ciclos y en general radica es que muy difícil saber el uso exacto de algunas instrucciones.1. • Las optimizaciones globales pueden depender de la arquitectura de la máquina.2 Costos • Los costos son el factor más importante a tomar en cuenta a la hora de optimizar ya que en ocasiones la mejora obtenida puede verse no reflejada en el programa final pero si ser perjudicial para el equipo de desarrollo. • Otros uso de la optimización pueden ser el mejoramiento de consultas en SQL o en aplicaciones remotas (sockets. sobre todo en instrucciones de bifurcación como son las decisiones. …. siendo el salto lo más pequeño posible 3. utilizar instrucciones en ensamblador. etc. • La idea es tener los saltos lo más cerca de las llamadas.• while(a == b) •{ • int c = a. • Por ejemplo: for(int i=0.4 De mirilla • La optimización de mirilla trata de estructurar de manera eficiente el flujo del programa. Costos • Pero en cambio si esa optimización se hace por ejemplo en un ciclo. Optimización global • En algunos casos es mejor mantener variables globales para agilizar los procesos (el proceso de declarar variables y eliminarlas toma su tiempo) pero consume más memoria. • Este tipo de optimización es más lenta pero mejora el desempeño general de todo programa. si la ganancia es de 30 ms 300s .1. la mejora obtenida puede ser N veces mayor por lo cual el costo se minimiza y es benéfico la mejora.) 3. ciclos y saltos de rutinas. 3. • La optimización de una pequeña mejora tal vez tenga una pequeña ganancia en tiempo o en espacio pero sale muy costosa en tiempo en generarla. •} • En este caso es mejor pasar el int c =a. E/S. fuera del ciclo de ser posible. i++). i < 10000. Así que no todo código de proceso puede ser optimizado.

2.2. tarjetas de video) o de mucha memoria. 3. • En algunos casos es preferible tener la lógica del negocio más fuerte en otros dispositivos y hacer uso de arquitecturas descentralizadas como cliente/servidor o P2P.2 Criterios para mejorar el código • La mejor manera de optimizar el código es hacer ver a los programadores que optimicen su código desde el inicio. • Los costos de ejecución son aquellos que vienen implícitos al ejecutar el programa. . por lo que el espacio y la velocidad del microprocesadores son elementos que se deben optimizar para tener un mercado potencial más amplio. • Otro tipo de aplicaciones que deben optimizarse son las aplicacione spara dispositivos móviles. entre ellas tenemos los depuradores y desambladores •La optimización al igual que la programación es un arte y no se ha podido sistematizar del todo.1 Costo de ejecución.3 Herramientas para el análisis del flujo de datos • Existen algunas herramientas que permiten el análisis de los flujos de datos. 3. • Los criterios de optimización siempre están definidos por el compilador Criterios de optimización • Muchos de estos criterios pueden modificarse con directivas del compilador desde el código o de manera externa.2. • Este proceso lo realizan algunas herramientas del sistema como los ofuscadores para código móvil y código para dispositivos móviles.3. Costos de ejecución • Los dispositivos móviles tiene recursos más limitados que un dispositivo de cómputo convencional razón por la cual. • En algunos programas se tiene un mínimo para ejecutar el programa. Costos de ejecución • Las aplicaciones multimedias como los videojuegos tienen un costo de ejecución alto por lo cual la optimización de su desempeño es crítico.g. el problema radica en que el costo podría ser muy grande ya que tendría que codificar más y/o hacer su código mas legible. el mejor uso de memoria y otros recursos de hardware tiene mayor rendimiento. la gran mayoría de las veces requieren de procesadores rápidos (e.