Производительность вычислительного кластера определяется двумя факторами: количеством вычислительных узлов и производительностью каждого вычислительного узла. Идея увеличения производительности кластера за счет наращивания производительности вычислительных узлов выглядит весьма привлекательной и используется уже давно. В самом деле, использование двухпроцессорных узлов вместо однопроцессорных позволяет вдвое увеличить общую производительность вычислительной системы без какого-либо существенного усложнения технических решений. Особенно массовый характер этот подход принял после появления многоядерных процессоров. На сегодняшний день стандартной является конфигурация вычислительного узла с двумя 4-х ядерными процессорами. А появились процессоры и с 6-ю и с 10-ю ядрами. Без сомнения, они найдут широкое применение при создании вычислительных кластеров. В связи с этим остро возник вопрос - как наиболее эффективно использовать такие вычислительные системы? Достаточно очевидно, что если на узле 8 ядер, то вряд ли целесообразно запускать на нем 8 независимых процессов. Во-первых, резко возрастет число конфликтов по шине памяти. А во-вторых, велик риск, что операционная система уйдет в <свопинг>, если памяти на узле не хватит для постоянного размещения в ней наиболее активно используемых страниц всех процессов. Наиболее разумным решением представляется запуск на каждом узле одного многонитевого процесса, который бы смог задействовать всю вычислительную мощь узла. Такая схема предполагает совместное использование двух технологий для распараллеливания программы: MPI - для распараллеливания между узлами, и OpenMP - для распараллеливания внутри узлов.
В нашем случае, ввиду простоты программы, эта идея реализуется достаточно легко. Приведем текст соответствующей программы.
program pi_mpi include 'mpif.h' integer n, i double precision d, s, x, pi, temp integer myid, numprocs, ierr, status(3) integer sumtag, sizetag call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr) call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr) sizetag = 10 sumtag = 17 if (myid .eq. 0) then write(*,*) 'n?' read(*,*) n endif call MPI_BCAST(n,1,MPI_INTEGER,0, $ MPI_COMM_WORLD,ierr) d = 1.0/n s = 0.0 !$OMP PARALLEL PRIVATE(x), SHARED(d) !$OMP& REDUCTION(+: s) !$OMP DO do i = myid+1, n, numprocs x = (i-0.5)*d s = s+4.0/(1.0+x*x) enddo !$OMP END DO !$OMP END PARALLEL pi = d*s call MPI_REDUCE(pi,temp,1,MPI_DOUBLE_PRECISION, $ MPI_SUM,master,MPI_COMM_WORLD,ierr) pi = temp if (myid .eq. 0) then write(*, 100) pi 100 format(' pi = ', f20.15) endif call MPI_FINALIZE(ierr) end
В этой MPI-программе с помощью OpenMP распараллелено вычисление частичных сумм на каждом многоядерном узле. Читателю предлагается в качестве упражнения написать такую программу на языке Си.
Интересно отметить, что при тестировании производительности вычислительного узла, содержащего два 4-х ядерных процессора, с помощью теста HPL [17] оказалось, что максимальная производительность достигается тогда, когда на узле запускается два 4-х нитевых процесса, т.е. когда структура программы наилучшим образом соответствует архитектуре узла. Результаты тестирования для различных сочетаний числа процессов и числа нитей в каждом процессе представлены в Таблице 1.1
Размерность решаемой системы уравнений N = 40000
proc х threads | 1 x 1 | 1 x 8 | 2 x 4 | 4 x 2 | 8 x 1 | 8 x 1* |
время решения(cek.) | 5173 | 751 | 729 | 751 | 747 | 689 |
производительность(Gflops) | 8.25 | 56.80 | 58.50 | 56.79 | 57.11 | 61.87 |
* В расчете использовано 8 узлов, по одному процессу на узле.
Здесь в первом столбце представлена производительность одного процессорного ядра. В столбцах 2 - 5 производительность узла в целом, при различных сочетаниях количества процессов и нитей в вычислительном узле. Последний столбец иллюстрирует масштабируемость программы по узлам кластера. Из таблицы видно, что полная производительность вычислительного узла на программе HPL примерно в 7 раз выше, чем производительность одного ядра, и она слабо зависит от сочетания числа процессов и нитей в узле. К сожалению, на реальных программах, обрабатывающих большие массивы данных, масштабируемость внутри узла оказывается значительно хуже, и кроме того, она практически всегда хуже, чем масштабируемость по вычислительным узлам, при условии, что используется скоростная коммуникационная сеть Infiniband.