Índice 1. 2. 3. 4. 5 5. 6. 7. 8. 9. Arquitectura y Computación de Alto Rendimiento Vectorización Introducción Compilación Bucles vectorizables y dificultades Mensajes del Compilador P di consejo Pedir j all compilador il d Directivas OpenMP Directivas Intel Intrinsics y clases de C++. Prefetch Ejemplo 2 Introducción Introducción Los procesadores tienen unidades vectoriales que se usan con instrucciones SIMD Hereda la idea de antiguos superordenadores (Cray) e Intel lleva tiempo con ello: MMX (Matrix (M t i Math M th Extensions): E t i ) 64 bits bit SSE 1-5 (Streaming SIMD Extensions): 128 bits ● AVX 1-2 (Advanced Vector Extensions): 256 bits ● IMCI (Initial Many Core Instructions): 512 bits ● ● Bucle escalar for (i=0; i<n ; i++) C[i] = A[i] + B[i]; Intel Xeon Phi ejecuta 16 instrucciones SP o 8 de DP por ciclo (Con FMA 32 SP o 16 DP) 3 Introducción 4 Esquema general Bucle SIMD o vectorizado (pseudo código) for ( i=0; i<n ; i+=4 ) C[i:(i+4)] = A[i:(i+4)]+B[i:(i+4)]; 5 AC : MP: Introd. a OpenMP 6 1 Introducción Varias opciones Múltiples operandos posibles 7 AC : MP: Introd. a OpenMP Compilación Bucles vectorizables icc -O3 vectoriza ● -no-vec: No vectoriza (tb –no-simd ) ● -vec-report=n: Informa de la vectorización (0..7) ● -xhost xhost o -mhost: mhost: indica la arquitectura ● gcc -O3 vectoriza -ftree-vectorize: vectoriza ● -ftree-vectorizer-verbose=n: Informa de la vectorización (0..9) ● -mhost: indica la arquitectura ● ● Contables, a la entrada debe saberse el número de iteraciones, que no puede cambiar Bucles sencillos, con una entrada y salida Evitar saltos (if, goto, switch), el comportamiento de todas las iteraciones es el mismo mismo, aunque if sencillos se permiten. (usar peeling) Bucle más interno (hay collapse, interchange,..) Sin llamadas a funciones, a menos que tengan versión vectorial (sin,cos,log,sqrt,max,pow,exp…) Podemos hacerla con las funciones elementales O hacerla inline ● ● 9 10 Dificultades en la vectorización Datos no contiguos, es vectorizable pero lento: ● ● ● Ejemplos de mensajes del compilador icc Low trip count Not Inner Loop ● Existence of vector dependence (aliasing) ● ● • No suele ser vectorizable menos tipo reduction • Ambigüedades en el uso de punteros ● Contador incrementa de N en N, Uso de indirecciones Vector de estructuras (mejor estructura de vect) Dependencias entre iteraciones ● 8 Mejor notación vectorial que punteros Datos no alineados o condiciones frontera (provoca peeling). Uso del long double (usar menor tamaño posible) 11 Uso de random o modulo usar #pragma ivdep (Intel) O usar restrict (std=c99): void copy(char * restrict a, char * restrict b, int n) Vectorization possible but seems inefficient Condition may protect exception (ivdep) ● data type unsupported on given target architecture ● ● 12 2 Ejemplos de mensajes del compilador Obteniendo información icc ● ● ● ● ● Statement cannot be vectorized (switch, loop) Subscript too complex Unsupported Loop Structure Top test could not be found Operator unsuited for vectorization Al compilar con opción -vec-report2 informa de la vectorización de bucles en Host y MIC icc -vec-report2 -openmp offload.c offload.c(57): (col. 2) remark: *MIC* LOOP WAS VECTORIZED. offload c(54): (col offload.c(54): (col. 7) remark: *MIC* loop was not vectorized: not inner loop. offload.c(53): (col. 5) remark: *MIC* loop was not vectorized: not inner loop. Opciones de 0 a 6, también 7 pero la salida es para herramientas (Script Python VecAnalysis) 13 ACAR: Introd. al Intel Xeon Phi Obteniendo información Pedir consejo al compilador Al compilar con -vec-report nos informa de: -guide: Genera un informe más detallado que los logs, dando consejos y chequeos a seguir lucas.c(372): remark #30513: (VECT) Insert a "#pragma ivdep" statement right before the loop at line 372 to vectorize the loop. [VERIFY] Make sure that these arrays in the loop do not have unsafe cross-iteration dependencies: It, Ix, Iy. A cross-iteration dependency exists if a memory location is modified in an iteration of the loop and accessed (by a read or a write) in another iteration of the loop. Make sure that there are no such dependencies, or that any cross-iteration dependencies can be safely ignored. Number of advice-messages emitted for this compilation session: 1. ● n=0: Nada de información ● n=1: (por defecto) Bucles vectorizados ● n=2: tb bucles no vectorizados y por qué ● n=3: Añade información de dependencias ● n=4: Informa sólo de bucles no vectorizados ● n=5: Como el n=4 pero añade dependencias ● n=6: Información muy detallada ● n=7: Como el 6 pero para herramientas (VecAnalysis) ACAR: Introd. al Intel Xeon Phi 15 16 Directiva OpenMP para vectorizar 14 Directiva para funciones vectoriales #pragma omp simd: Que vectorice si puede Admite clausulas: reduction, collapse,private,… Admite bucles “externos” Se le puede añadir safelen(n) indicando número iteraciones seguras, sin dependencias También linear(list[:step]) que indica variables que se incrementan con “step” a cada iteración aligned(list[:alignment]) 17 #pragma omp declare simd: Que genere versión escalar y vectorial de la función Admite clausulas: reduction, linear, aligned,… simdlen(n) longitud del vector que debe soportar la l ffunción ió vectorial i l uniform(list) indica variables constantes Inbranch: siempre se llama desde un if Notinbranch: nunca se llama desde un if 18 3 Vectorización con OpenMP Directivas Intel para ayudar al compilador La directiva simd se puede combinar con for (reparte iteraciones vectorizadas entre hilos) También con parallel y for icc ● #pragma ivdep: Que ignore las dependencias • ● ● ● ● ● Se le asegura que no las hay (punteros) #pragma loop count (n): Nº iteraciones típico #pragma vector always: Que vectorice si puede #pragma vector aligned: Asegura datos alineados #pragma novector: Que no vectorice #pragma vector nontemporal: Todos los datos serán sobreescritos, no hace falta leerlos 20 Directivas intel para ayudar al compilador Funciones vectoriales o elementales (Intel) #pragma simd: Que vectorice si puede Es “similar” al OpenMP, admite clausulas adicionales (reduction, private,…) Admite bucles “externos” Se le puede añadir vectorlength(n) indicando tamaño del vector que es seguro, sin dependencias También “linear(…)” que indica variables que se pueden deducir del índice del bucle Se pueden generar versiones vectoriales de ciertas funciones Facilita la vectorización de bucles que las usen No aplicable si es inline También se genera la versión escalar __declspec(vector) o __attribute__((vector)) 21 22 Compiler Intrinsics Versiones de intrinsics con mask // IMCI Intrisics // SSE2 Intrinsics for (int i=0; i<n; i+=16) { for (int i=0; i<n; i+=4) { __m512 Avec=_mm512_load_ps(A+i); __m128 Avec=_mm_load_ps(A+i); __m512 Bvec=_mm512_load_ps(B+i); __m128 Bvec=_mm_load_ps(B+i); Avec=_mm512_add_ps(Avec, Bvec); Avec=_mm_add_ps(Avec, Bvec); _mm512_store_ps(A+i, Avec); _mm_store_ps(A+i, Avec); } } P Pseudo-ensamblador: d bl d V Vectorizar t i a mano. Vectores alineados: float A[n] y B[n] a 16 bytes (SSE2) o a 64 bytes (IMCI) (#include <immintrin.h>) “n” múltiplo de 4 (SSE) o de 16 (IMCI) Carga en registros vectoriales, suma y guarda // Versión escalar for (int i=0; i<n; i+=1) A[i] = A[i] + C[i]; AC : MP: Introd. a OpenMP 23 Hay una máscara para determinar sobre que elemento se hace o no la operación vectorial // Version escalar for i = 1 to 16 if a[i] < b[i] z[i] = x[i] * y[i]; // Version intrinsics #include <immintrin.h> __m512i z, x, y; __mmask k = _mm512_cmplt_ps(a, b); // Asigna z o x*y según k z = _mm512_mask_mul_ps(z, k, x, y); AC : MP: Introd. a OpenMP 24 4 Clases de C++ Interfaz de intrinsics. Más legible Se protege con #ifdef __MIC__ Varias clases: F32vec16, F64vec8, I32vec16, Is32vec16, Y SSE (F32vec4, F64vec2) o AVX(F32vec8, F64vec4) Se puede combinar con genéricos: Ejemplo: Intrinsics vs clases // Version Escalar float a[16], r[16]; for i = 0 to 15 r[i] = exp(a[i]) // Intrinsics #include <immintrin.h> __m512 vr, va = &a[0]; vr = __mm512_exp_ps(va); *(__mm512 *)&(r[0]) = vr; // Vector Classes #include <micvec.h> F32vec16 vr, va = &a[0]; vr = exp(va); // Bastante más legible *(F32vec16 *)&(r[0]) = vr; Iu32vec16, I64vec8 SIMDType foo<SIMDType, BasicType>(SIMDType a) F32vec8 res = foo<F32vec8, float>(a) AC : MP: Introd. a OpenMP 25 AC : MP: Introd. a OpenMP Prefetch Para reducir fallos de cache Manualmente con intrisics: O con pragma (tb noprefetch) Ejemplo Calcular el potencial eléctrico en varios puntos del espacio cuando hay m cargas, cada una con carga electrica qi en la posición indicada por el vector ri Para punto, situado donde indica el vector cada punto R, el potencial eléctrico viene dado por: con: _mm_prefetch((char *) &a[i], hint); #pragma prefetch a [:hint[:distance]] 26 Distance en número iteraciones en avance Hint distintos modos (L1-L2, exclusivo, temporal) El Hw hace prefetching, el compilador también, puede interferir. Desactivarlos para más control AC : MP: Introd. a OpenMP 27 28 29 class Charge f { // Inefficient public: float x,y,z,q; // Coord. & charge charge(); ~charge(); }; void calculate_electric_potential( const int m, // N. of charges const int n, // N. of points in each dim. const Charge* chg, // Array of Charges float* const phi, // Out: elec. Potential const float ds // Spatial grid spacing ) 30 Ejemplo Ejemplo AC : MP: Introd. a OpenMP 5 Ejemplo Ejemplo: Mejoras // Carga desde n*n puntos u “observadores” for (int c=0; c<n*n ; c++) { const float Rx=ds*(float)(c/n);//X-coord const float Ry=ds*(float)(c%n);//Y-coord const float Rz=ds*(float)(0);//Z-coord (0) f for (i (int t i=0; i 0 i< i<m; i++){// autovectorized t t i d Tres cambios: ● AoS to SoA: Accesos contiguos • ● // Non-unit stride: (&chg[i+1].x - &chg[i].x) != sizeof(float) const float dx=chg[i].x - Rx; const float dy=chg[i].y - Ry; const float dz=chg[i].z - Rz; phi[c] -=chg[i].q/sqrtf(dx*dx+dy*dy+dz*dz); ● Evitar dependencias (restrict o pragma ivdep) Datos alineados a 32 bytes: • • • ● • } 31 class Charge f { Ejemplo public: const int m; float *x,*y,*z,*q; // Coord. & charge charge(const int M): m(M) { x=(float*)_mm_malloc(m*sizeof(float),32); y=(float*)_mm_malloc(m*sizeof(float),32); (fl t*) ll ( * i f(fl t) 32) z=(float*)_mm_malloc(m*sizeof(float),32); q=(float*)_mm_malloc(m*sizeof(float),32); } ~charge() { _mm_free(x); _mm_free(y); _mm_free(z); _mm_free(q); } 33 }; Ejemplo __declspec(align(32)) float A[n]; X=(float*)_mm_malloc(size, 32); __atribute__ ((aligned (base,offset))) float A[n]; Y avisar al compilador • } En vez de un vector de estructuras, una estructura de vectores. #pragma vector aligned __assume_aligned(array, n) 32 Ejemplo void calculate_electric_potential( const int m, // N. of charges const int n, // N. of points in each dim. const Charge &chg, // Charges float* restrict const phi, // Potential const float ds // Spatial grid spacing ) 34 Ejemplo: Rendimiento for (int c=0; c<n*n ; c++) { const float Rx=ds*(float)(c/n);//X-coord const float Ry=ds*(float)(c%n);//Y-coord const float Rz=ds*(float)(0);//Z-coord #pragma vector aligned f for (i (int t i i=0; 0 i< i<m; i++){// autovectorized t t i d const float dx=chg.x[i] - Rx; const float dy=chg.y[i] - Ry; const float dz=chg.y[i] - Rz; phi[c] -=chg.q[i]/sqrtf(dx*dx+dy*dy+dz*dz); } } 35 36 6
© Copyright 2024