Методика распараллеливания программ в модели DVM Институт прикладной математики им. М.В.Келдыша РАН http://www.keldysh.ru/pages/dvm Модель DVM Высокоуровневая модель параллелизма без явной ориентации на общую или распределенную память Ориентация на пользователей в области. вычислительной математики. Основные понятия: дискретные пространства в декартовых координатах, отображения и пересечения пространств. Язык распараллеливания в модели DVM - язык спецификаций масштабируемых параллельных программ. Средства программирования C-DVM = Язык Си + специальные макросы Fortran-DVM = Язык Фортран + специальные комментарии Специальные комментарии и макросы являются высокоуровневыми спецификациями параллелизма в терминах последовательной программы Отсутствуют низкоуровневые передачи данных и синхронизации Последовательный стиль программирования Спецификации параллелизма «невидимы» для стандартных компиляторов Существует только один экземпляр программы для последовательного и параллельного счета Состав DVM-системы Компилятор C-DVM Компилятор Fortran-DVM Система поддержки параллельного выполнения (Lib-DVM) DVM-отладчик Анализатор производительности DVM-программ Предсказатель производительности DVM-программ Правило собственных вычислений: OWN(A[i]) - процессор, на который распределен A[i] A[i] = expr Оператор всегда выполняется на процессоре OWN(A[i]) Локализация данных: Операнды expr распределены на процессор OWN(A[i]) Распараллеливание последовательной программы • Согласованное распределение массивов данных и параллельных циклов на массив виртуальных процессоров. Цель: максимум параллелизма и максимум локализации • Определение общих (не локальных данных) и их спецификация. Общие данные: данные, вычисляемые на одних процессорах и используемые на других процессорах. Выполнение программы Модель: одна программа - множество потоков данных На всех процессорах - одна и та же программа Проба: свой - “чужой” оператор по правилу собственных вычислений Абстрактная схема распределения данных и витков параллельных циклов Объекты: P - индексное пространство массива виртуальных процессоров, определяется пользователем и задается при запуске программы Ai - индексное пространство i-ого массива данных Lj - индексное пространство j-ого параллельного цикла Директивы распределения устанавливают соответствие между точками (элементами) индексных пространств: ALIGN: Ai1=>Ai2 Каждой точке (элементу) Ai2 ставится в соответствие подмножество точек (элементов) массива Ai1 PARALLEL: Lj=>Ai Каждой точке (элементу) Ai ставится в соответствие подмножество точек (витков цикла) Lj DISTRIBUTE: Ai=>P Каждой точке (виртуальному процессору) P ставится в соответствие подмножество точек (элементов) массива Ai Отображение последовательной программы Массивы ALIGN Массивы DISTRIBUTE PARALLEL Циклы PARALLEL DISTRIBUTE Массив виртуальных процессоров Физические процессоры Массив задач MAP Распределение данных DISTRIBUTE DVM( DISTRIBUTE f1…fk )<описание-массива-на-языке-Си> где fi = [ BLOCK ] - распределение равными блоками [] (распределенное измерение) - распределение целым измерением (локальное измерение) k - количество измерений массива P(m) - линейка виртуальных процессоров Распределение данных DISTRIBUTE Примеры: DVM( DISTRIBUTE [ BLOCK ] ) float A[N]; DVM( DISTRIBUTE [ ] ) float A[N]; DVM( DISTRIBUTE [ BLOCK ] [ ] ) float B[N][N]; DVM( DISTRIBUTE [ ] [ BLOCK ] ) float B[N][N]; P(m1,m2) - массив виртуальных процессоров Локализация данных ALIGN DVM( ALIGN a1…an WITH B b1…bm ) <описание-массива-A-на-языке-Си> где ai - параметр i-го измерения выравниваемого массива А bj - параметр j-го измерения базового массива B n - количество измерений массива А m - количество измерений массива В ai = a[Idi] [ ] bj=[c*Idj +d] [ ] Idi, Idj - идентификаторы c, d - целочисленные константы Локализация данных ALIGN Примеры: DVM( ALIGN [ i ] WITH B[ 2*i+1] ) float A[N]; DVM( ALIGN [ i ] [ j ] WITH C[ j ] [ i ] ) float D[N][N]; DVM( ALIGN [ i ] WITH C[ ] [ i ] ) float E[N]; DVM( ALIGN [ i ] [ ] WITH B[ i ] ) float C[N][N]; Распределение витков цикла PARALLEL Макросы заголовков циклов: # define DO ( v, f, u, s ) for(v=f; v<=u; v+=s) # define FOR ( v, h ) for(v=0; v<=h-1; v+=1) Параллельный цикл - массив витков цикла • тесно-гнездовой цикл • прямоугольное индексное пространство • виток цикла - неделимый объект (выполняется на одном процессоре) Распределение витков цикла PARALLEL DVM( PARALLEL [ I1 ]… [ In ] ON A e1… em ) где Ij n - индекс j-го заголовка параллельного цикла, - количество заголовков цикла, m - количество измерений массива, A - идентификатор распределенного массива, ei = [a*Ik+b], a, b - целочисленные переменные Распределение витков цикла PARALLEL Цикл не удовлетворяет требованиям массива витков цикла: Не тесно-гнездовой цикл FOR(i,N) { a=5.; FOR(j,N) { . . . } } Не прямоугольное индексное пространство FOR(i,N) DO(j,i,N,1) { . . . } Распределение витков цикла PARALLEL Цикл не удовлетворяет требованиям массива витков цикла: Виток цикла на разных процессорах FOR(i,N) FOR(i,N) { D[2*i] = ...; { D[2*i] = ...; } D[2*i+1]= …; } FOR(i,N) {D[2*i+1]= …; } DVM( DISTRIBUTE [ BLOCK ] [ BLOCK ] ) float A[N+1][N+1], B[N][N]; FOR(i,N) FOR(j,N) { A[i+1][j+1] = …; B[i][j] = …; } DVM( ALIGN [ i ] [ j ] WITH A[i+1] [j+1] ) float B[N][N]; Общие (удаленные) данные • Сравнение индексных выражений по • распределенным измерениям левой и правой части оператора присваивания Выражение условного оператора - правая часть A[i] = (C[i] > D[i]) ? B[i] : 0. Локализация данных DVM( DISTRIBUTE [ BLOCK ] ) float A[N]; DVM( ALIGN [ i ] WITH A[ i ] ) float B[N],C[N]; DVM( PARALLEL [ i ] ON A[ i ] ) FOR( i, N ) { A[i] = B[i] + C[i] ; } Локализация с помощью TEMPLATE DVM( DISTRIBUTE [ BLOCK ] ; TEMPLATE [N+d1+d2] ) void *TABC; DVM( ALIGN [ i ] WITH TABC[ i ] ) DVM( ALIGN [ i ] WITH TABC[ i +d1] ) DVM( ALIGN [ i ] WITH TABC[ i +d1+d2] ) DVM( PARALLEL [ i ] ON A[ i ] ) FOR( i, N ) { A[i] = B[i-d1] + C[i+d2] ; } float B[N]; float A[N]; float C[N]; Схема отображения ALIGN P1 TABC B d1 A d1+d2 C P2 P3 P4 Общие данные типа SHADOW DVM( DISTRIBUTE [ BLOCK ] ) float A[N]; DVM( ALIGN [ i ] WITH A[ i ]; SHADOW [d1:d2]) float B[N]; DVM( PARALLEL [ i ] ON A[ i ] ; SHADOW_RENEW B) DO( i,d1, N-d2-1,1 ) { A[i] = B[i-d1] + B[i+d2] ; } Общие данные типа ACROSS DVM( DISTRIBUTE [ BLOCK ]; SHADOW [d1:d2]) float A[N]; DVM( PARALLEL [ i ] ON A[ i ] ; ACROSS A[d1:d2]) DO( i,d1, N-d2-1,1 ) { A[i] = A[i-d1] + A[i+d2] ; } Общие данные типа REMOTE_ACCESS DVM( DISTRIBUTE [ BLOCK ] ) float A[N] , C[2*N]; DVM( PARALLEL [ i ] ON A[ i ] ; REMOTE_ACCESS C[5] C[i+N] ) FOR( i, N ) { A[i] = C[5] + C[i+N] ; } Общие данные типа REDUCTION DVM( DISTRIBUTE [ BLOCK ] ) float A[N]; DVM( PARALLEL [ i ] ON A[ i ] ; REDUCTION SUM (s) ) FOR( i, N ) { s = s + A[i] ; } DVM( DISTRIBUTE [ BLOCK ] ; TEMPLATE [N] ) void *TM; DVM( PARALLEL [ i ] ON TM[ i ] ; REDUCTION PRODUCT (sm) ) FOR( i, N ) { sm = sm * i ; } Параллельный цикл • Левая часть: распределенный массив, • редукционная переменная, приватная переменная. Распределенный цикл => распределенное измерение • Локальный цикл => локальное измерение Программа JACOBI на C-DVM #include <math.h> #include <stdlib.h> #include <stdio.h> #define Max(a,b) ((a)>(b)?(a):(b)) /* dummy macros for standard C compiler */ #define DVM(dvmdir) /* macros for DVM-loops */ #define DO(v,l,h,s) #define L 8 #define ITMAX 20 int i,j,it,k; double eps; double MAXEPS FILE *f; for(v=(l); v<=(h); v+=(s)) = 0.5; /* 2D arrays block distributed along 2 dimensions */ DVM(DISTRIBUTE [BLOCK][BLOCK]) double A[L][L]; DVM(ALIGN [i][j] WITH A[i][j]) double B[L][L]; int main(int an, char **as) { /* 2D loop with base array A */ DVM(PARALLEL [i][j] ON A[i][j]) DO(i,0,L-1,1) DO(j,0,L-1,1) {A[i][j]=0.; B[i][j]=1.+i+j;} Программа JACOBI на C-DVM /****** iteration loop *************************/ DO(it,1,ITMAX,1) { eps= 0.; /* Parallel loop with base array A /* calculating maximum in variable eps */ */ DVM(PARALLEL [i][j] ON A[i][j] ; REDUCTION MAX(eps) ) DO(i,1,L-2,1) DO(j,1,L-2,1) {eps = Max(fabs(B[i][j]-A[i][j]),eps); A[i][j] = B[i][j]; } /* Parallel loop with base array B and */ /* with prior updating shadow elements of array A */ DVM(PARALLEL [i][j] ON B[i][j]; SHADOW_RENEW A) DO(i,1,L-2,1) DO(j,1,L-2,1) B[i][j] = (A[i-1][j]+A[i+1][j]+ A[i][j-1]+A[i][j+1])/4.; printf( "it=%4i eps=%f\n", it,eps); if (eps < MAXEPS) break; }/*DO it*/ f=fopen("jacobi.dat","wb"); fwrite(B,sizeof(double),L*L,f); return 0; } Distribution of array A [8][8] processor arrangement 1 3*3 2 3 A11 A12 A13 A14 A13 A14 A15 A16 A17 A16 A 17 A18 A21 A22 A23 A24 A23 A24 A25 A26 A27 A26 A 27 A28 A31 A32 A33 A34 A33 A34 A35 A36 A37 A36 A 37 A38 A41 A42 A43 A44 A45 A46 A47 A48 A31 A32 A33 A34 A35 A36 A37 A38 A41 A42 A43 A44 A43 A44 A45 A46 A47 A46 A47 A48 A51 A52 A53 A54 A53 A54 A55 A56 A57 A56 A57 A58 A61 A62 A63 A64 A63 A64 A65 A66 A67 A66 A67 A68 A71 A72 A73 A74 A75 A76 A77 A78 A61 A62 A63 A64 A65 A66 A67 A68 A71 A72 A73 A74 A73 A74 A75 A76 A77 A76 A 77 A78 A81 A82 A83 A84 A83 A84 A85 A86 A87 A86 A 87 A88 1 2 3 shadow imported edges elements Программа SOR на C-DVM #include <stdlib.h> #include <stdio.h> #define DVM(dvmdir) #define DO(v,l,h,s) for(v=l; v<=h; v+=s) #define L 8 #define ITMAX 20 int i,j, it, k; FILE *f; DVM(DISTRIBUTE [BLOCK][BLOCK]) double A[L][L]; int main(int an, char **as) { DO(it,1,ITMAX,1) /****** iteration loop ******/ { eps= 0.; DVM(PARALLEL [i][j] ON A[i][j] ; ACROSS A[1:1][1:1]; REDUCTION MAX(eps) ) DO(i,1,L-2,1) DO(j,1,L-2,1) { double b; b=(A[i-1][j]+A[i+1][j]+A[i][j-1]+A[i][j+1])/4.; eps = Max(fabs(b-A[i][j]),eps); A[i][j] = b; } printf( "it=%4i eps=%3.3E\n", it,eps); if (eps < MAXEPS) break; }/*DO it*/ return 0; } Параллелизм по гиперплоскостям CDVM$ DISTRIBUTE A (BLOCK,BLOCK) j i t1 t2 t3 Конвейерный параллелизм CDVM$ DISTRIBUTE A (BLOCK,*) j i p0 t1 t2 t3 t4 t5 t6 t7 p1 t2 t3 t4 t5 t6 t7 t8 p2 t3 t4 t5 t6 t7 t8 t9 Оптимизация 1. Совмещение вычислений и доступа к общим данным 2. Избыточные вычисления вместо общих данных SHADOW 3. Асинхронное копирование вместо общих данных REMOTE Спецификация обновления значений общих данных • Перед циклом использования • Между циклом вычислений и циклом • • использования Матрица цикл-массив ({use,def}) Порядок выполнения циклов (граф управления) Совмещение вычислений и доступа к общим данным DVM(CREATE_SHADOW_GROUP grshad: A); . . . DVM(SHADOW_START grshad ); . . . DVM(PARALLEL [ i ] [ j ] ON A[ i ] [ j ]; SHADOW_WAIT grshad ) DO(i,1,L-2,1) DO(j,1,L-2,1) B[i][j] = (A[i-1][j]+A[i+1][j]+A[i][j-1]+A[i][j+1])/4; Избыточные вычисления DVM(PARALLEL [i] ON A[i]; SHADOW_COMPUTE) FOR(i,n) A[i] = i; DVM(PARALLEL [i] ON A[i] ) DO(i,1,n-2,1) C[i] = A[i-1] +A[i+1]; Асинхронное копирование секций массивов k = N/4 - 1; FOR (i, N-1) FOR (j, N-1) A[ i+k ] [ j+k ] = f( A[ 2*i ] [ 2*j ] ) ; 2N 2N N N DVM( DISTRIBUTE [ BLOCK ] [ BLOCK ] ) float A[2*N][2*N]; DVM( ALIGN [ i ] [ j ] WITH A[ i] [ j ] ) float B[2*N][2*N]; DVM( COPY_FLAG) void *flagS; k = N/4 - 1; DVM( PARALLEL [ i ] [ j ] ON B[2*i] [2*j] ) FOR (i, N-1) FOR (j, N-1) B[ 2*i ] [ 2*j ] = f( A[ 2*i ] [ 2*j ] ) ; DVM( COPY_START &flagS) FOR (i, N-1) FOR (j, N-1) A[ i+k ] [ j+k ] = B[ 2*i ] [ 2*j ] ; DVM( COPY_WAIT &flagS)