Tal vez las contribuciones más importantes de HPF sean las directivas de disposición de datos. Usándolas, el programador puede controlar cómo se acomodan los datos, basándose en su conocimiento acerca de las interacciones entre datos. Una directiva de ejemplo es la que sigue:
REAL*4 ROD(10)
!HPF$ DISTRIBUTE ROD(BLOCK)
El prefijo !HPF$ es visto como un comentario por cualquier compilador que no sea HPF, de forma que un compilador FORTRAN 90 común pueda ignorarla de forma segura. La directiva DISTRIBUTE indica que el arreglo ROD debe distribuirse entre múltiples procesadores. Si no se usase dicha directiva, el arreglo ROD se ubicaría en un procesador y se le comunicaría a los otros procesos conforme se necesitara. Existen varios esquemas de distribución que pueden hacerse en cada dimensión:
REAL*4 BOB(100,100,100),RICH(100,100,100)
!HPF$ DISTRIBUTE BOB(BLOCK,CYCLIC,*)
!HPF$ DISTRIBUTE RICH(CYCLIC(10))
Estas distribuciones operan como sigue:
BLOCK El arreglo se distribuye a lo largo de los procesadores usando bloques contiguos del valor del índice. Los bloques se hacen tan grandes como sea posible. CYCLIC El arreglo se distribuye a lo largo de los procesadores, mapeando cada elemento sucesivo al "siguiente" procesador, y cuando se llega al último procesador, la ubicación comienza nuevamente en el primero. CYCLIC(n) El arreglo se distribuye del mismo modo que en CYCLIC excepto que se colocan n elementos sucesivos en cada procesador antes de pasarse al siguiente.
Todos los elementos en esta dimensión se colocan en el mismo procesador. Esto es mayormente útil para arreglos multidimensionales.
La Figure 1 muestra cómo se mapean los elementos de un arreglo sencillo entre tres procesadores con diferentes directivas.
Deben ubicarse cuatro elementos en los Procesadores 1 y 2 porque no hay un Procesador 4 disponible para el elemento más a la izquierda si se ubican tres elementos en los Procesadores 1 y 2. En Figure 1, los elementos se ubican en procesadores sucesivos, regresando al Procesador 1 tras el último procesador. En Figure 1, usar un tamaño de bocado de CYCLIC es un compromiso entre BLOCK puro y CYCLIC puro.
Para explorar el uso de *, debemos observar un simple arreglo bidimensional mapeado entre cuatro procesadores. En Figure 2, mostramos la distribución del arreglo y cada celda indica cuál procesador almacenará el dato para dicha celda en un arreglo bidimensional. En Figure 2, la directiva lo descompone en ambas dimensiones simultáneamente. Este enfoque resulta en unos parches aproximadamente cuadrados en el arreglo. Sin embargo, puede que no sea el mejor enfoque. En el siguiente ejemplo, usamos el * para indicar que queremos que todos los elementos de una columna particular sean ubicados sobre le mismo procesador. Así, los valores de columna distribuyen equitativamente las columnas entre los procesadores. Entonces, todos los renglones en cada columna siguen donde ha sido colocada la columna. Ello permite un salto unitario para las porciones ubicadas adentro de los procesadores, y resulta benéfico en algunas aplicaciones. La sintaxis de * también se conoce como distribución sobre el procesador.
Cuando lidie con más de una estructura de datos para realizar un cálculo, puede bien sea distribuirlas separadamente , o bien usar la directiva ALIGN para asegurarse de que los elementos correspondientes de ambas estructuras estén alojados juntos. En el siguiente ejemplo, tenemos un arreglo de placa y un factor de escala que debemos aplicar a cada columna de la placa durante el cálculo:
DIMENSION PLATE(200,200),SCALE(200)
!HPF$ DISTRIBUTE PLATE(*,BLOCK)
!HPF$ ALIGN SCALE(I) WITH PLATE(J,I)
O bien:
DIMENSION PLATE(200,200),SCALE(200)
!HPF$ DISTRIBUTE PLATE(*,BLOCK)
!HPF$ ALIGN SCALE(:) WITH PLATE(*,:)
En ambos ejemplos, las variables PLATE y SCALE están ubicadas en los mismos procesadores que las columnas correspondientes de PLATE. La sintaxis * y : comunican la misma información. Cuando se usa *, esa dimensión se colapsa y no participa en la distribución. Cuando se usa :, significa que la esa dimensión sigue a la dimensión correspondiente en la variable que ya ha sido distribuida.
También puede usted especificar el acomodo de la variable SCALE y hacer que la variable PLATE "siga" la distribución de la variable SCALE:
DIMENSION PLATE(200,200),SCALE(200)
!HPF$ DISTRIBUTE SCALE(BLOCK)
!HPF$ ALIGN PLATE(J,I) WITH SCALE(I)
Puede agregar expresiones aritméticas simples en la directiva ALIGN, sujetas a ciertas limitaciones. Las otras directivas incluyen:
PROCESSORS Le permite crear una forma de configuración de los procesos que pueda usarse para alinear otras estructuras de datos. REDISTRIBUTE y REALIGN Le permite cambiar dinámicamente la forma de las estructuras de datos a tiempo de ejecución, conforme cambian los patrones de comunicación durante el curso de la misma. TEMPLATE Le permite crear un arreglo que no usa espacio. En vez de distribuir una estructura de datos y alinear todas las demás, algunos usuarios crearán y distribuirán una plantilla y luego alinearán todas las estructuras de datos reales de acuerdo a esa plantilla.
El uso de directivas puede fluctuar desde lo muy simple a lo muy complejo. En algunas situaciones, usted distribuirá la única estructura grande compartida, alineando unas pocas estructuras relacionadas y habrá terminado. En otras, los programadores intentan optimizar las comunicaciones basándose en la topología de la red de interconexión (hypercubo, red de interconexión multietapa, malla o toroide) usando directivas muy detalladas. También pueden redistribuir cuidadosamente los datos durante las varias fases del cómputo.
Con suerte, su aplicación logrará un buen rendimiento sin demasiado esfuerzo.