<< Chapter < Page Chapter >> Page >

DO I=1,N A(I) = A(I) / SQRT(X*X + Y*Y)ENDDO

que se convierte en:


TEMP = 1 / SQRT(X*X + Y*Y) DO I=1,NA(I) = A(I) * TEMP ENDDO

Hicimos emerger una operación cara e invariante hacia afuera del ciclo, y asignamos el resultado a una variable temporal. Observe también que hicimos una simplificación algebraica cuando intercambiamos una división por la multiplicación por un inverso. La multiplicación se ejecutará mucho más rápido. Puede ser que su compilador sea lo suficientemente listo para hacer tales transformaciones por sí mismo, asumiendo que usted le haya instruido de que son transformaciones legales; pero sin rastrear el código ensamblador generado, no puede usted estar seguro. Por supuesto, si usted reacomoda el código a mano y el tiempo de ejecución del ciclo súbitamente disminuye, sabrá que el compilador ha sido un lastre hasta entonces.

En ocasiones querrá usted sumergir una operación tras el ciclo. Usualmente, se trata de algún cálculo realizado cada iteración, pero cuyo resultado sólo se requiere al final. Para ilustrarlo, he aquí una clase de ciclo distinto de los que hemos visto hasta ahora, uno que busca el caracter final en una cadena:


while (*p != ’ ’) c = *p++;

se convierte en:


while (*p++ != ’ ’); c = *(p-1);

La nueva versión del ciclo mueve la asignación de c más allá de la última iteración. Debemos admitir que esta transformación puede ser un logro para un compilador y que el ahorro no sea muy grande. Pero ilustra la idea de sumergir una operación muy bien.

Nuevamente, emerger y sumergir instrucciones para colocarlas afuera de ciclos es algo que su compilador puede que sea capaz de hacer. Pero a menudo usted puede reestructurar ligeramente los cálculos por sí mismo sólo con moverlos, y obtener un beneficio todavía mayor.

Manipulando los elementos de un arreglo en bucles

Hay otra área donde debe usted confiar en que el compilador hará lo correcto. Cuando emplee repetidamente un elemento de un arreglo adentro de un bucle, querrá que se cargue una sola vez de la memoria. Tome el siguiente bucle como un ejemplo. Reutiliza X(I) dos veces:


DO I=1,N XOLD(I) = X(I)X(I)= X(I) + XINC(I) ENDDO

En realidad, los pasos encargados de recuperar X(I) sólo son subexpresiones comunes adicionales: un cálculo de direcciones (posiblemente) y una operación de carga de memoria. Puede usted ver que la operación se repite al reescribir el ciclo ligeramente:


DO I=1,N TEMP= X(I)XOLD(I) = TEMP X(I)= TEMP + XINC(I)ENDDO

Los compiladores de FORTRAN deben reconocer que se está usando dos veces el mismo elemento X(I) y que por tanto sólo se requiere cargarlo una vez, pero no siempre un compilador es tan inteligente. A veces tiene usted que crear una variable escalar temporal para almacenar el valor de un elemento del arreglo en el cuerpo de un bucle. Esto es particularmente cierto cuando hay llamados a subrutinas o funciones en el ciclo, o cuando alguna de las variables está declarada como external o COMMON . Asegúrese de emparejar los tipos entre las variables temporales y las otras variables, pues no quiere incurrir la sobrecarga derivada de la conversión de tipos sólo por estar "ayudando" al compilador. En el caso de los compiladores de C, el mismo tipo de expresiones indexadas son un reto incluso mayor. Considere este código:


doinc(int xold[],int x[],int xinc[],int n){ for (i=0; i<n; i++) { xold[i]= x[i];x[i]= x[i]+ xinc[i];} }

A menos que el compilador pueda ver las definiciones de x , xinc y xold , debe asumir que son apuntadores señalando a la misma celda de almacenamiento, y repetir las operaciones de carga y almacenamiento. En este caso, introducir variables temporales para almacenar los valores de x , xinc , y xold es una optimización que el compilador no es libre de hacer.

Es interesante señalar que si bien usar variables escalares temporales en el ciclo es útil para las máquinas RISC y superescalares, no ayuda al código que se ejecuta sobre hardware paralelo. Un compilador paralelo busca oportunidades de eliminar los escalares o, cuando menos, de reemplazarlos con vectores temporales. Si ejecuta su código sobre una máquina paralela de vez en cuando, debe ser cuidadoso antes de introducir variables escalares temporales en un ciclo. Una dudosa ganancia de rendimiento en una instancia puede convertirse en una pérdida de rendimiento real en otra.

Get Jobilize Job Search Mobile App in your pocket Now!

Get it on Google Play Download on the App Store Now




Source:  OpenStax, Cómputo de alto rendimiento. OpenStax CNX. Sep 02, 2011 Download for free at http://cnx.org/content/col11356/1.2
Google Play and the Google Play logo are trademarks of Google Inc.

Notification Switch

Would you like to follow the 'Cómputo de alto rendimiento' conversation and receive update notifications?

Ask