Программирование для многопроцессорных систем в стандарте MPI - Шпаковский Г.И., Серикова Н.В.. Программирование для многопроцессорных систем в стандарте MPI -. Организация вычислений в многопроцессорных системах
Скачать 1.61 Mb.
|
Пример 4. Решение системы линейных уравнений Следующий пример иллюстрирует параллельное решение систе- мы линейных уравнений с помощью SLES. Пользовательский интер- фейс для инициации программы, создания векторов и матриц и реше- ния линейной системы является тем же для однопроцессорного и мно- гопроцессорного примеров. Главное различие состоит в том, что каж- дый процесс формирует локальную часть матрицы и вектора в па- раллельном случае. static char help[] = "Solves a linear system in parallel with SLES.\n\ Input parameters include:\n\ -random_exact_sol : use a random exact solution vector\n\ -view_exact_sol : write exact solution vector to stdout\n\ -m -n #include "petscsles.h" int main(int argc,char **args) { Vec x,b,u; /* приближенное решение, RHS, точное решение */ Mat A; /* матрица линейной системы */ SLES sles; /* метод решения линейной системы */ PetscRandom rctx; /* генератор случайных чисел */ double norm; /* норма ошибки решения */ int i,j,I,J,Istart,Iend,ierr,m = 8,n = 7,its; PetscTruth flg; Scalar v,one = 1.0,neg_one = -1.0; KSP ksp; PetscInitialize(&argc,&args,(char *)0,help); ierr = PetscOptionsGetInt(PETSC_NULL,"-",&m,PETSC_NULL);CHKERRQ(ierr); ierr = PetscOptionsGetInt(PETSC_NULL,"-",&n,PETSC_NULL);CHKERRQ(ierr); /* Организуем матрицу и правосторонний вектор, который определяет линейную систему, Ax = b. Создаем параллельную матрицу, описывая только ее глобальные размеры. Когда используется MatCreate(), формат матрицы может быть описан на этапе исполнения. */ ierr=MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE, m*n,m*n,&A); CHKERRQ(ierr); ierr = MatSetFromOptions(A);CHKERRQ(ierr); /* Матрица разделена крупными кусками строк по процессам. Определяем, какие строки матрицы размещены локально.*/ ierr = MatGetOwnershipRange(A,&Istart,&Iend);CHKERRQ(ierr); 266 /* Размещаем матричные элементы. Каждому процессу нужно разместить только те элементы, которые принадлежат ему локально (все нелокальные элементы бу- дут посланы в соответствующий процессор во время сборки матрицы). */ for (I=Istart; I { J = I – n; ierr = MatSetValues(A,1,&I,1,&J,&v,INSERT_VALUES); CHKERRQ(ierr); } if (i CHKERRQ(ierr); } if (j>0) { J = I – 1; ierr = MatSetValues(A,1,&I,1,&J,&v,INSERT_VALUES); CHKERRQ(ierr); } if (j CHKERRQ(ierr); } v = 4.0; ierr = MatSetValues(A,1,&I,1,&I,&v,INSERT_VALUES); CHKERRQ(ierr); } ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); /* Создаем параллельные векторы. Формируем вектор и затем дублируем, если необходимо. Когда в этом примере используется VecCreate() и VecSetFromOptions(), указывается только глобальный размер вектора; парал- лельное разбиение определяется на этапе исполнения. Когда решается линейная система, векторы и матрицы обязаны быть разбиты соответственно. PETSc авто- матически генерирует соответствующее разбиение матриц и векторов, когда MatCreate() и VecCreate() используются с тем же самым коммуникатором. Поль- зователь может альтернативно описать размеры локальных векторов и матриц, когда необходимо более сложное разбиение (путем замещения аргумента PETSC_DECIDE в VecCreate()). */ ierr = VecCreate(PETSC_COMM_WORLD,PETSC_DECIDE,m*n,&u); CHKERRQ(ierr); 267 ierr = VecSetFromOptions(u);CHKERRQ(ierr); ierr = VecDuplicate(u,&b);CHKERRQ(ierr); ierr = VecDuplicate(b,&x);CHKERRQ(ierr); /* Установим точное решение, затем вычислим правосторонний вектор. По умол- чанию используем точное решение вектора для случая, когда все элементы вектора равны единице. Альтернативно, используя опцию – random_sol, фор- мируем решение вектора со случайными компонентами. */ ierr = PetscOptionsHasName(PETSC_NULL,"-random_exact_sol",&flg); CHKERRQ(ierr); if (flg) { ierr = PetscRandomCreate(PETSC_COMM_WORLD,RANDOM_DEFAULT,&rctx); CHKERRQ(ierr); ierr = VecSetRandom(rctx,u);CHKERRQ(ierr); ierr = PetscRandomDestroy(rctx);CHKERRQ(ierr); } else ierr = VecSet(&one,u);CHKERRQ(ierr); ierr = MatMult(A,u,b);CHKERRQ(ierr); /* Выводим точное решение вектора, если необходимо */ ierr = PetscOptionsHasName(PETSC_NULL,"-view_exact_sol",&flg); CHKERRQ(ierr); if (flg) { ierr = VecView(u,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr); } /* Создаем метод решения системы линейных уравнений */ ierr = SLESCreate(PETSC_COMM_WORLD,&sles);CHKERRQ(ierr); /* Устанавливаем операторы. Здесь матрица, которая определяет линейную систему, служит как preconditioning матрица. */ ierr = SLESSetOperators(sles,A,A,DIFFERENT_NONZERO_PATTERN); CHKERRQ(ierr); /* Устанавливается метод решения */ ierr = SLESGetKSP(sles,&ksp);CHKERRQ(ierr); ierr = KSPSetTolerances(ksp,1.e-2/((m+1)*(n+1)),1.e-50, PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); ierr = SLESSetFromOptions(sles);CHKERRQ(ierr); /* Решается линейная система */ ierr = SLESSolve(sles,b,x,&its);CHKERRQ(ierr); /* Проверяется решение norm *= sqrt(1.0/((m+1)*(n+1))); */ ierr = VecAXPY(&neg_one,u,x);CHKERRQ(ierr); ierr = VecNorm(x,NORM_2,&norm);CHKERRQ(ierr); /* Печатается информация о сходимости. PetscPrintf() создает одно предложение печати из всех процессов, которые разделяют коммуникатор. Альтернативой яв- ляется PetscFPrintf(), которая печатает в файл. */ 268 ierr = PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A iterations d\n", norm,its); CHKERRQ(ierr); /* Освобождается рабочее пространство. Все PETSc объекты должны быть разру- шены, когда они больше не нужны. */ ierr = SLESDestroy(sles);CHKERRQ(ierr);ierr = VecDestroy(u);CHKERRQ(ierr); ierr = VecDestroy(x);CHKERRQ(ierr);ierr = VecDestroy(b);CHKERRQ(ierr); ierr = MatDestroy(A);CHKERRQ(ierr); ierr = PetscFinalize();CHKERRQ(ierr); return 0; } КОНТРОЛЬНЫЕ ВОПРОСЫ К ГЛАВЕ 13 Контрольные вопросы к 13.1 1. Для чего предназначена библиотека ScaLAPACK? 2. Для чего предназначена библиотека PETSc? 3. Опишите уровень операций в библиотеки BLAS? 4. Для чего предназначена библиотека BLAS? 5. Для чего предназначена библиотека LAPACK? 6. Каково назначение библиотеки BLAСS? 7. Объясните назначение параметров функции vTRSD2D. 8. Какие четыре шага надо сделать, чтобы выполнить программу ScaLAPACK? 9. Опишите каждый из этих четырех шагов. 10. Объясните на примере программы умножения матриц особенности работы библиотеки ScaLAPACK. Контрольные вопросы к 13.2 1. Какие задачи позволяет решать библиотека PETSc? 2. Нужно ли вызывать MPI_Init при написании PETSc программы? 3. В каком случае необходимо создание коммуникатора и как это сделать? 4. Какие типы векторов существуют в библиотеке? Как создать вектор того или иного типа? 5. В каком случае нужно создавать параллельные векторы? 6. Можно ли распределить компоненты параллельного вектора по процессам не равными частями? 7. Как определить номера строк в локальном процессе при создании параллель- ной матрицы? 8. Какие матричные операции библиотеки можно использовать для параллель- ного решения задачи умножения матрицы на матрицу? 9. Необходим ли MPICH для инсталляции PETSc? 10. Как выполнить PETSc-программу на 4 процессах, задавая различные размер- ности задачи? 269 ПРИЛОЖЕНИЯ Приложение 1. КОНСТАНТЫ ДЛЯ ЯЗЫКОВ С И FORTRAN Здесь приведены константы, определенные в файлах mpi.h (для C) и mpif.h (для языка Fortran). /* возвращаемые коды (как для C, так и для Fortran) */ MPI_SUCCESS MPI_ERR_BUFFER MPI_ERR_COUNT MPI_ERR_TYPE MPI_ERR_TAG MPI_ERR_COMM MPI_ERR_RANK MPI_ERR_REQUEST MPI_ERR_ROOT MPI_ERR_GROUP MPI_ERR_OP MPI_ERR_TOPOLOGY MPI_ERR_DIMS MPI_ERR_ARG MPI_ERR_UNKNOWN MPI_ERR_TRUNCATE MPI_ERR_OTHER MPI_ERR_INTERN MPI_ERR _ PENDING MPI_ERR_IN_STATUS MPI_ERR_LASTCODE /* константы (как для C, так и для Fortran) */ MPI_BOTTOM MPI_PROC_NULL MPI_ANY_SOURCE MPI_ANY_TAG MPI_UNDEFINED MPI_BSEND_OVERHEAD MPI_KEYVAL_INVALID /* размер статуса и резервируемые индексные значения (Fortran) */ MPI_STATUS_SIZE MPI_SOURCE MPI_TAG MPI_ERROR /* описатели обработчика ошибок (C и Fortran) */ MPI_ERRORS_ARE_FATAL MPI_ERRORS_RETURN 270 /* максимальные размеры строк */ MPI_MAX_PROCESSOR_NAME MPI_MAX_ERROR_STRING /* элементарные типы данных (C) */ MPI_CHAR MPI_SHORT MPI_INT MPI_LONG MPI_UNSIGNED_CHAR MPI_UNSIGNED_SHORT MPI_UNSIGNED MPI_UNSIGNED_LONG MPI_FLOAT MPI_DOUBLE MPI_LONG_DOUBLE MPI_BYTE MPI_PACKED /* элементарные типы данных(Fortran) */ MPI_INTEGER MPI_REAL MPI_DOUBLE_PRECISION MPI_COMPLEX MPI_LOGICAL MPI_CHARACTER MPI_BYTE MPI_PACKED /* типы данных для функций редукции (C) */ MPI_FLOAT_INT MPI_DOUBLE_INT MPI_LONG_INT MPI_2INT MPI_SHORT_INT MPI_LONG_DOUBLE_INT /* типы данных для функций редукции (Fortran) */ MPI_2REAL MPI_2DOUBLE_PRECISION MPI_2INTEGER /* дополнительные типы данных (Fortran) */ MPI_INTEGER1 MPI_INTEGER2 MPI_INTEGER4 MPI_REAL2 MPI_REAL4 MPI_REAL8 etc. 271 /* дополнительные типы данных (C) */ MPI_LONG_LONG_INT etc. /*специальные типы данных для создания производных типов данных */ MPI_UB MPI_LB /* зарезервированные коммуникаторы (C и Fortran) */ MPI_COMM_WORLD MPI_COMM_SELF /* результаты сравнения коммуникаторов и групп */ MPI_IDENT MPI_CONGRUENT MPI_SIMILAR MPI_UNEQUAL /* ключи запроса среды (C и Fortran) */ MPI_TAG_UB MPI_IO MPI_HOST MPI_WTIME_IS_GLOBAL /* коллективные операции (C и Fortran) */ MPI_MAX MPI_MIN MPI_SUM MPI_PROD MPI_MAXLOC MPI_MINLOC MPI_BAND MPI_BOR MPI_BXOR MPI_LAND MPI_LOR MPI_LXOR /* нулевые дескрипторы */ MPI_GROUP_NULL MPI_COMM_NULL MPI_DATATYPE_NULL MPI_REQUEST_NULL MPI_OP_NULL MPI_ERRHANDLER_NULL /* пустая группа */ MPI_GROUP_EMPTY /* топологии (C и Fortran) */ MPI_GRAPH MPI_CART /* предопределенные функции в C и Fortrun*/ MPI_NULL_COPY_FN 272 MPI_NULL_DELETE_FN MPI_DUP_FN Следующее есть типы С, также включенные в файл mpi.h. /* скрытые типы */ MPI_Aint MPI_Status /* дескрипторы различных структур */ MPI_Group MPI_Comm MPI_Datatype MPI_Request MPI_Op MPI_Errhandler Приложение 2. ПЕРЕЧЕНЬ ФУНКЦИЙ MPI-1.1 1. MPI_ABORT ( comm, errorcode ) Прекращает выполнение операций 2. MPI_ADDRESS (location, address) Получает адрес в ячейке памяти 3. MPI_ALLGATHER ( sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm) Собирает данные от всех процессов и распределяет их всем процессам 4. MPI_ALLGATHERV ( sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm) Собирает данные от всех процессов и поставляет их всем процессам 5. MPI_ALLREDUCE ( sendbuf, recvbuf, count, datatype, op, comm) Выполняет глобальную операцию над данными от всех процессов и результат посылает обратно всем процессам 6. MPI_ALLTOALL (sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm) Посылает данные от всех процессов всем процессам 7. MPI_ALLTOALLV (sendbuf, sendcounts, sdispls, sendtype, recvbuf, recvcounts, rdispls, recvtype, comm) Посылает данные от всех процессов всем процессам со смещением 8. MPI_BARRIER ( comm ) Блокирует дальнейшее исполнение, пока все процессы не достигнут этой функции 9. MPI_BCAST( buffer, count, datatype, root, comm ) Широковещательная рассылка сообщения от одного процесса всем 10. MPI_BSEND (buf, count, datatype, dest, tag, comm) Операция посылки сообщения с определенным пользователем буфером 11. MPI_BSEND_INIT (buf, count, datatype, dest, tag, comm, request) Создает дескриптор для буферизованной посылки 273 12. MPI_BUFFER_ATTACH ( buffer, size) Создает определяемый пользователем буфер для посылки 13. MPI_BUFFER_DETACH ( buffer_addr, size) Удаляет существующий буфер 14. MPI_CANCEL (request) Отменяет коммуникационный запрос 15. MPI_CART_COORDS (comm, rank, maxdims, coords) Определяет координаты процесса в картезианской топологии в соответст- вии с его номером 16. MPI_CART_CREATE (comm_old, ndims, dims, periods, reorder, comm_cart) Создает новый коммуникатор по заданной топологической информации 17. MPI_CART_GET (comm, maxdims, dims, periods, coords) Получает связанную с коммуникатором информацию о картезианской топо- логии 18. MPI_CART_MAP (comm, ndims, dims, periods, newrank) Отображает процесс в соответствии с топологической информацией 19. MPI_CART_RANK (comm, coords, rank) Определяет номер процесса в коммуникаторе с картезианской топологией 20. MPI_CART_SHIFT (comm, direction, disp, rank_source, rank_dest) Возвращает новые номера процессов отправителя и получателя после сдвига в заданном направлении 21. MPI_CART_SUB (comm, remain_dims, newcomm) Разделяет коммуникатор на подгруппы, которые формируют картезианские решетки меньшей размерности 22. MPI_CARTDIM_GET (comm, ndims) Получает информацию о связанной с коммуникатором картезианской топо- логии 23. MPI_COMM_COMPARE (comm1, comm2, result) Сравнивает два коммуникатора 24. MPI_COMM_CREATE (comm, group, newcomm) Создает новый коммуникатор 25. MPI_COMM_DUP (comm, newcomm) Создает новый коммуникатор путем дублирования существующего со всеми его параметрами 26. MPI_COMM_FREE (comm) Маркирует коммуникатор для удаления 27. MPI_COMM_GROUP (comm, group) Осуществляет доступ к группе, связанной с данным коммуникатором 28. MPI_COMM_RANK (comm, rank) Определяет номер процесса в коммуникаторе 29. MPI_COMM_SIZE (comm, size) Определяет размер связанной с коммуникатором группы 30. MPI_COMM_SPLIT (comm, color, key, newcomm) Создает новый коммуникатор на основе признаков и ключей 31. MPI_DIMS_CREATE (nnodes, ndims, dims) Распределяет процессы по размерностям 274 32. MPI_FINALIZE ( ) Завершает выполнение программы MPI 33. MPI_ GATHER ( sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm) Собирает в один процесс данные от группы процессов 34. MPI_GATHERV ( sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm) Векторный вариант функции GATHER 35. MPI_GET_COUNT (status, datatype, count) Получает номер старших элементов 36. MPI_GET_ELEMENTS ( status, datatype, count) Возвращает номер базового элемента в типе данных 37. MPI_GET_PROCESSOR_NAME ( name, resultlen ) Получает номер процессора 38. MPI_GET_VERSION (version, subversion) Возвращает версию MPI 39. MPI_GRAPH_CREATE (comm_old, nnodes, index, edges, reorder, comm_graph) Создает новый коммуникатор согласно топологической информации 40. MPI_GRAPH_GET(comm, maxindex, maxedges, index, edges) Получает информацию о связанной с коммуникатором графовой топологии. 41. MPI_GRAPH_MAP (comm, nnodes, index, edges, newrank) Размещает процесс согласно информации о топологии графа 42. MPI_GRAPH_NEIGHBORS_COUNT(comm, rank, nneighbors) Возвращает число соседей узла в графовой топологии 43. MPI_GRAPH_NEIGHBORS (comm, rank, maxneighbors, neighbors) Возвращает соседей узла в графовой топологии 44. MPI_GRAPHDIMS_GET (comm, nnodes, nedges) Получает информацию о связанной с коммуникатором топологии 45. MPI_GROUP_COMPARE (group1, group2, result) Сравнивает две группы 46. MPI_GROUP_DIFFERENCE (group1, group2, newgroup) Создает группу по разности двух групп 47. MPI_GROUP_EXCL (group, n, ranks, newgroup) Создает группу путем переупорядочивания существующей группы и отбора только тех элементов, которые не указаны в списке 48. MPI_GROUP_FREE (group) Освобождает группу 49. MPI_GROUP_INCL (group, n, ranks, newgroup) Создает группу путем переупорядочивания существующей группы и отбора только тех элементов, которые указаны в списке 50. MPI_GROUP_INTERSECTION (group1, group2, newgroup) Создает группу на основе пересечения двух групп 51. MPI_GROUP_RANGE_EXCL (group, n, ranges, newgroup) Создает группу путем исключения ряда процессов из существующей группы 52. MPI_GROUP_RANGE_INCL (group, n, ranges, newgroup) Создает новую группу из ряда номеров существующей группы 275 53. MPI_GROUP_RANK (group, rank) Возвращает номер процесса в данной группе 54. MPI_GROUP_SIZE (group, size) Возвращает размер группы 55. MPI_GROUP_TRANSLATE_RANKS (group1, n, ranks1, group2, ranks2) Переводит номер процесса в одной группе в номер в другой группе 56. MPI_GROUP_UNION(group1, group2, newgroup) Создает новую группу путем объединения двух групп 57. |