Optimización de Código

Optimización de Código
Información sobre la plantilla
Mejorar velocidad website.jpg
Concepto:Una mejora en la ejecución de programas

Optimización de código. Constituye un elemento importante en el desarrollo de una aplicación que aunque no asegure su éxito total, proporciona mejoras considerables que permiten un mayor acercamiento a este. Su objetivo principal radica en maximizar la eficiencia temporal y espacial de los programas permitiendo reorganizar el código de manera limpia, correcta y eficiente. Con el propósito de esclarecer aspectos como el momento, el lugar y la forma de realizar la optimización del código

Cada optimización está basada en una función de coste y en una transformación que preserve el significado del programa. Alega que con la primera se evalúa la mejora obtenida con la optimización, considerando como criterios más comunes 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. Mientras que las transformaciones se encargan del logro de dichas mejoras preservando el comportamiento del programa.

Estas transformaciones según el ámbito de la aplicación pueden clasificarse en optimizaciones locales y globales. Las primeras son aplicadas dentro de un bloque básico, es decir, una secuencia de sentencias en las cuales el flujo de control empieza al principio y acaba al final, sin posibilidad de parar o de tener saltos, lo cual puede entenderse como algoritmos, procedimientos o métodos específicos. Mientras que las optimizaciones globales son aplicadas a más de un bloque básico. Estas consideran el contenido y flujo de datos entre todos o parte de los bloques básicos.

Elementos a tener en cuenta al aplicar las técnicas de optimización

Factores a optimizar: (Ct/Ce)

  • Coste temporal (Ct): tiempo de ejecución.
  • Coste espacial (Ce): espacio de memoria utilizado.

Optimizar preferiblemente

En las rutinas que se ejecutan con mayor frecuencia, es decir, en las que obedecen la regla 90-10, lo cual significa que siempre hay un 10% del código que se ejecuta el 90% del tiempo. Para identificar estas rutinas se pueden utilizar las siguientes técnicas:

  • Sesiones de profiling: Procedimientos que se efectúan para de conocer cuanto tiempo demora la ejecución de un programa en cada instrucción.
  • Sentido común: Depende principalmente de los conocimientos y experiencia del programador.

¿Cómo optimizar?

Implementando rutinas o algoritmos de alta calidad.

El análisis de la complejidad asintótica es una alternativa viable para medir la eficiencia de un algoritmo con la cual es posible evaluar el ritmo de crecimiento de una función. Sin embargo no siempre es una métrica adecuada.

El empleo de trasformaciones que aseguren la reducción de Ct y Ce permite garantizar cierto grado de optimización en la generación de algoritmos y programas más eficientes, a continuación se mencionan alguna de estas técnicas de optimización sobre un bloque básico de instrucciones:

1. Optimizaciones que reducen la estructura:

  • Reutilización de expresiones comunes: regularmente tiende a favorecer el Ct.

Ejemplo básico:

a = b + c		a = b + c
d = a - d		d = a - d
e = (b + c)*d		e = a*d

*Precalcular expresiones constantes: tiende a favorecer el Ct.

Ejemplo básico:

i = 2 + 3 	 	i = 5
j = 4			j = 4
f = j + 2.5		f = 6.5
  • Reducir propagación de copias: tiende a favorecer el Ce. Ante instrucciones f = a, como se verá en el ejemplo básico, sustituir todos los usos de f por a.

Ejemplo básico:

a = 3 + i		a = 3 + i
f = a			b = a + c
b = f + c		d = a + m
d = a + m		m = a + d
m = f + d
  • Eliminar redundancias en acceso matrices: tiende a favorecer el Ct.

//Cod. fuente:

A: array [1...4, 1...6, 1...8] of integer
A[i,j,5] := A[i,j,6] + A[i,j,4]

//Sin optimización:

direc(A[i,j,5]) = direc(A[1,1,1]) + (i-1)*6*8 + (j-1)*8 + (5-1)
direc(A[i,j,6]) = direc(A[1,1,1]) + (i-1)*6*8 + (j-1)*8 + (6-1)

//Con optimización:

k := direc(A[1,1,1]) + (i-1)*6*8 + (j-1)*8
direc(A[i,j,5]) = k + 4
direc(A[i,j,6]) = k + 5 
  • Eliminar el código muerto: tiende a favorecer tanto el Ct y Ce.
  • Reducir declaración de variables innecesarias dentro de bucles: tiende a favorecer tanto el Ct y Ce.

2. Transformaciones algebraicas: Este grupo de transformaciones se utilizan para aplicar propiedades matemáticas que simplifiquen expresiones, reemplazando operaciones costosas de la máquina por otras menos costosas.

  • Reacondicionamiento de operadores: Cambiar orden de evaluación ampliando propiedades conmutativa, asociativa y distributiva.

Ejemplo básico: A = B*C*(D + E) ≡ A = (D + E)*B*C

3. Optimización de tipo Mirilla (peephole optimization): intenta mejorar el rendimiento del programa por medio de reemplazar esa breve secuencia de instrucciones por otra secuencia más corta y/o más rápida. Su salida es susceptible a ser optimizada de nuevo. Esta técnica se basa básicamente en:

a. Recorrer el código buscando combinaciones de instrucciones que puedan ser reemplazadas por otras equivalentes más eficientes. b. Utilizar una ventana de n instrucciones y un conjunto de patrones de transformación (patrón, secuencias de reemplazamiento). c. Si las instrucciones de la ventana encajan con algún patrón se reemplazan por la secuencia de reemplazamiento asociada. d. Las nuevas instrucciones son reconsideradas para las futuras optimizaciones. Por su parte las optimizaciones globales se basan en el análisis global de flujo de datos entre de los distintos bloques básicos que forman el código del programa. Entre las optimizaciones típicas se encuentran:

  • Optimización de bucles: Centra la optimización de bucles internos que responden a la regla 90-10.
  • Identificación de expresiones comunes entre bloques. Afecta a la asignación de registros entre los bloques básicos.
  • Optimización de llamadas a procedimientos: Las llamadas a procedimientos son realmente costosas debido fundamentalmente a:

a. cambios del ámbito de referencias. b. paso de parámetros + asignación de datos locales. c. gestión de Registros de Activación.

Para lo cual es aconsejable:

1. Optimizar manejo de Registro de Activación haciendo uso del almacenamiento estático si no hay llamadas recursivas y minimizando la copia de parámetros y número de registros a salvar.

2. Aplicar expansión en línea: lo cual consiste en eliminar llamadas a procedimientos, “copiando" el cuerpo del mismo en el lugar donde es llamado. Esta alternativa evita sobrecarga asociada con llamadas a procedimiento sin embargo pone en riesgo otras variables como el uso de memoria por consiguiente es factible aplicarla en procedimientos pequeños y llamados desde pocos lugares. Tampoco es aplicable en procedimientos recursivos. Una vez expuestos algunas consideraciones a tener presente al optimizar algoritmos y/o programas se mencionan algunas de las herramientas que pueden facilitar dicho proceso:

  • Compuware DevPartner Studio: es un conjunto de herramientas (suite) que permite a un desarrollador para analizar y evaluar el código bajo parámetros como: calidad, complejidad, memoria de detección de fugas, optimización de la memoria, análisis de rendimiento (tiempo), rendimiento experto (CPU, disco y el uso de recursos de red), código de análisis de cobertura, simulación de fallos (ambos. NET y ambiental) así como detección y seguimiento de interoperabilidad para C / C + + utilizando BoundsChecker tecnología. Se integra con Microsoft Visual Studio (2005 o superior).» [1]
  • Rational Purify: incluye posibilidades de depuración de memoria y detección de fugas de memoria. Es compatible con Windows, Linux, Solaris y AIX. » [2]
  • Intel VTune, suite de optimización con versiones Windows (Visual Studio .NET) y Linux. Permite realizar perfiles de desempeño para C, C++, C#, Fortran, Assembly and Java*.» [3]
  • Gcov, Gprof, Memprof : herramientas para realizar tests de cobertura, optimización y detección de errores de memoria, respectivamente. (Software libre) [4] [5] [6]
  • Electric Fence: herramienta pasiva que detecta errores relacionados con la memoria, como acceso fuera de rango a arrays, etc. (Software libre) [7]
  • Xdebug: herramienta para depurar el código contiene un generador de perfiles. (Software libre)

Las consideraciones anteriormente presentadas contribuyen a guiar el proceso de optimización de código a los programadores menos experimentados. Brindando un pequeño compendio de técnicas basadas fundamentalmente en la reducción tiempo de ejecución y espacio de memoria utilizado en la implementación de algoritmos y/o programas. Lo cual permitirá la generación de código fuente de manera intencionada, correcta y eficiente. Las herramientas citadas son una vía de realización del proceso de manera fácil y cómoda para el programador, extrayéndolo del tedioso proceso de optimización manual y particularizada.

El presente trabajo y, en consecuencia, la obtención de los resultados generados por el mismo, permitin arribar a las siguientes conclusiones:

1. El esclarecimiento de elementos cómo el momento, el lugar y la forma de realizar la optimización del código contribuye a responder preguntas cómo dónde, cuándo y cómo realizar la optimización del código implementado, las cuales frecuentemente inquietan a los programadores menos experimentados.

2. Las técnicas de optimización expuestas contribuyen a guiar el proceso de optimización de código enfocándose en la reducción del costo temporal y espacial, permitiendo la generación de algoritmos y programas implementados intencionalmente en pos de favorecer estos factores.

3. En favor de facilitar el proceso de optimización se citan algunas herramientas que extraen al programador del tedioso proceso de realizar transformaciones de manera manual y particularizada.

Referencias

  1. (Software comercial) Disponible en: [1]. Consultado el 15 de julio 2015
  2. (Software comercial) Disponible en: [2]. Consultado el 15 de julio 2015
  3. (Software comercial) Disponible en: [3]. Consultado el 15 de julio 2015
  4. GNU Cov: Disponible en: [4]. Consultado el 15 de julio 2015
  5. GNU Prof: Disponible en: [5]. Consultado el 15 de julio 2015
  6. Memprof: Disponible en: [6]. Consultado el 15 de julio 2015
  7. Disponible en: [7]. Consultado el 15 de julio 2015

Fuentes

  • Ariadna Rendón Artola. Autor para la correspondencia: arendon@.uci.cu.VIII Peña Tecnológica. Facultad 3, Universidad de las Ciencias Informáticas. Disponible en: Ptec.eventos.uci.cu .