Este documento discute varias técnicas de optimización que pueden ser aplicadas por un compilador para mejorar el rendimiento de un programa, como la eliminación de subexpresiones comunes y código muerto. También describe conceptos como diagramas de flujo de datos y bloques que representan el flujo de información en un sistema o proceso.
1. UNIVERSIDAD MARIANO GÁLVEZ DE GUATEMALA
Nombre del curso:
Compiladores
Integrantes del grupo:
Alexander Alberto López Medrano 1790-19-4721
Herberth Fernando Morales López 1790-19-21839
Jaime Aroldo Barillas Morales
2. Idealmente, los compiladores deberían producir código objeto. La
realidad es que esto es difícil 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
3. Optimización es un programa transformación técnica, que trata de mejorar el código por lo que
consumen menos recursos (es decir CPU, memoria) y ofrecer una alta velocidad.
En la optimización de alto nivel general de programación son sustituidos por construcciones muy eficiente
de bajo nivel los códigos de programación. Un código proceso en fase de optimización debe seguir las tres
normas que se explican a continuación:
• El código de salida no debe, de ninguna manera, cambiar el sentido del programa.
• Optimización debe aumentar la velocidad del programa y si es posible, el programa debe exigir
menos cantidad de recursos.
• Optimización debe ser rápido y no debe retrasar el proceso de compilación general.
Los esfuerzos para un código optimizado pueden ser utilizado en los distintos niveles de elaboración del
proceso.
• Al principio, los usuarios pueden cambiar o reorganizar el código o utilizar los mejores
algoritmos para escribir el código.
• Después de generar código intermedio, el compilador puede modificar el código intermedio por
dirección los cálculos y mejorar los lazos.
• Al tiempo que se produce la máquina de destino código, el compilador puede hacer uso de
jerarquía de memoria y registros de la CPU.
La optimización puede clasificarse en dos grandes categorías: independiente de la máquina y depende de
la máquina.
4. Las expresiones redundantes se calculan más de una vez en
ruta paralela, sin ningún cambio de operandos. Mientras que
parcial de las expresiones redundantes se calculan más de una
vez en el camino, sin ningún cambio de operandos.
Por ejemplo:
5. Loop-invariante código es parcialmente redundante y pueden
ser eliminados mediante un código de movimiento técnica.
Otro ejemplo de un código en donde podría ser redundante
seria:
If (condition)
{
a = y OP z;
}
else
{
...
}
c = y OP z;
6. En este caso podríamos vamos a asumir que los valores (y, z)
no cambian de asignación de variable a variable c. Aquí, si las
condiciones son verdaderas, y OP se calcula dos veces, si no,
una vez. Movimiento código se puede utilizar para eliminar
esta redundancia, como se muestra a continuación:
If (condition)
{ ...
tmp = y OP z;
a = tmp;
...
}
else
{
...
tmp = y OP z;
}
c = tmp;
En este caso, si la condición es verdadera o falsa; y OP z debe
calcularse sólo una vez.
7. El algoritmo QuickSort se basa en la técnica de "divide y vencerás" por la que, en
cada recursión, el problema se divide en subproblemas de menor tamaño y se
resuelven por separado (aplicando la misma técnica) para ser unidos de nuevo una
vez resueltos.Tiene como característica principal el ordenamiento más rápido
conocido, su tiempo de ejecución promedio es O(n log (n)), siendo en el peor de
los casos O(n2), caso altamente improbable.
Ejemplo:
1.- Se selecciona número “PIVOTE” con el cual se van a
compara cada uno de los elementos del arreglo.
Int pivote= vector [{vector [{primero + ultimo) / 2]
9. Hay varias formas en las que un compilador puede mejorar un programa, sin cambiar la
función que calcula. La eliminación de subexpresiones comunes, la propagación de copia, la
eliminación de código muerto y el cálculo previo de constantes son ejemplos comunes de
dichas transformaciones que preservan las funciones (o que preservan la semántica);
consideraremos cada uno de estos ejemplos, uno a la vez.
10. A una ocurrencia de una expresión E se le conoce como subexpresión común si E se calculó
previamente y los valores de las variables en E no han cambiado desde ese cálculo previo. Evitamos
volver a calcular E si podemos usar su valor calculado previamente; es decir, la variable x a la cual se
asignó el cálculo anterior de E no ha cambiado en ese lapso.
Ejemplo: En a figura se muestra el resultado de la eliminación de subexpresiones comunes tanto
globales como locales de los bloques B 5 y B 6 en el grafo de flujo de la figura 9.3. Primero hablaremos
sobre la transformación de B 5 y después mencionaremos algunas sutilezas relacionadas con los
arreglos. Después de eliminar las subexpresiones comunes locales, B 5 sigue evaluando 4 ∗ i y 4 ∗ j,
como se muestra la figura 9.4(b). Ambas son subexpresiones comunes; en especial, las tres
instrucciones.
11.
12. El bloque B 5 en la figura 9.5 puede mejorarse aún más mediante la eliminación de x,
mediante dos nuevas transformaciones. Una se relaciona con las asignaciones de la forma
u = v, conocidas como instrucciones de copia, o simplemente copias. Si hubiéramos
entrado en más detalles en el ejemplo 9.2, las copias hubieran surgido mucho antes,
debido a que el algoritmo normal para eliminar subexpresiones comunes las introduce, al
igual que varios otros algoritmos.
13. Eliminar código muerto tiene dos ventajas principales: reduce el
tamaño del programa, una consideración importante en algunos
contextos, y permite que el programa evite ejecutar operaciones
irrelevantes, reduciendo así el tiempo de ejecución.
Código muerto incluye código que nunca se ejecutará y código que
solo afecta a variables muertas, es decir, variables irrelevantes en la
salida del programa. Consideremos el siguiente ejemplo escrito en C.
Debido a la ejecución incondicional de la declaración return, la
asignación de iB nunca se logrará. Por lo tanto, puede eliminar ese
código.
14. El movimiento de software de código: es un
movimiento que apoya el uso de licencias de
código abierto para parte o todo el software,
una parte de la noción más amplia de
colaboración abierta. El movimiento de código
se inició para difundir el concepto/idea del
software de código. Los programadores que
apoyan la filosofía del movimiento de código
contribuyen a la comunidad de código abierto
escribiendo e intercambiando voluntariamente
código de programación para el desarrollo de
software .
15. Los Flujos de datos son las conexiones entre los distintos
elementos del sistema y los procesos; representan a la
información que los procesos exigen como entrada y/o las
informaciones que ellos generan como salida compuesta por un
solo.
El análisis del flujo de datos tienen por finalidad seguir la
trayectoria de los datos por todos los procesos de la empresa,
examinando el empleo de los datos para llevar a cabo procesos
específicos de la empresa. El análisis puede pensarse de tal
manera que se estudien actividades del sistema desde el punto
de vista de los datos; donde se originan, como se utilizan o
cambian, hacia donde van, incluyendo las paradas a lo largo del
camino que se siguen desde suorigen hasta su destino.
16. En los lenguajes de alto nivel el programador no conoce los detalles de
representación, en términos de bits, de las abstracciones elegidas.
Abstracción de datos= barrera entra la visión del programador sobre los
datos y la del ordenador.
Oculta datos irrelevantes para la resolución del problema: Principio de
ocultación de la información.
Los principios de abstracción de datos u ocultación de la información
son las bases de diseño descendente de estructuras de datos.
17. Un diagrama de flujo de datos (DFD) traza el flujo de la información para
cualquier proceso o sistema. Emplea símbolos definidos, como rectángulos,
círculos y flechas, además de etiquetas de texto breves, para mostrar las
entradas y salidas de datos, los puntos de almacenamiento y las rutas entre
cada destino.
Los diagramas de flujo de datos pueden variar desde simples panoramas de
procesos incluso trazados a mano, hasta DFD muy detallados y con
múltiples niveles que profundizan progresivamente en cómo se manejan los
datos. Se pueden usar para analizar un sistema existente o para modelar
uno nuevo
18.
19. Ees la representación del funcionamiento interno de un sistema, que se hace mediante
bloques y sus relaciones, y que, además, definen la organización de todo el proceso interno,
sus entradas y sus salidas.
Un diagrama de bloques de procesos de producción es utilizado para indicar la manera en la
que se elabora cierto producto, especificando la materia prima, la cantidad de procesos y la
forma en la que se presenta el producto terminado.
Un diagrama de bloques de modelo matemático es el utilizado para representar el control
de sistemas físicos (o reales) mediante un modelo matemático, en el cual, intervienen gran
cantidad de variables que se relacionan en todo el proceso de producción. El modelo
matemático que representa un sistema físico de alguna complejidad conlleva a la
abstracción entre la relación de cada una de sus partes, y que conducen a la pérdida del
concepto global. En ingeniería de control, se han desarrollado una representación gráfica
de las partes de un sistema y sus interacciones. Luego de la representación gráfica del
modelo matemático, se puede encontrar la relación entre la entrada y la salida del proceso
del sistema.
20.
21. Este análisis se puede llevar a cabo mediante el
análisis de variable viva, que es una forma de
análisis estático de software y análisis de flujo de
datos. Esta también es una diferencia con
respecto al código inalcanzable que se descubre
mediante un análisis de control del flujo.