Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Алгоритмы решения систем линейных уравнений с блочно-ленточными матрицами. Монография
.pdf
Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 4 81
Таблица 3. Результаты тестирования быстродействия алгоритма
Процессор Последовательное
в случае аффинной рекуррентной зависимости
выполнение (сек.)
Intel Xeon 0.16625 0.274417 6.0583
Выполнение 4-мя
потоками (сек.)
Ускорение
Объяснение причин ускорения
Наиболее долгими операциями считаем обращения к памяти (чтение и
запись).
В представленных примерах отображение из рекуррентно замкнутого
множества описывается несколькими числами; в частности, в распараллеливаемом цикле с аффинной рекуррентной зависимостью — двумя. Для
вычисления суперпозиции двух таких отображений необходимые данные,
аргументы операции «суперпозиция» и результат, помещаются в регистрах
общего назначения. Суперпозиция нескольких таких отображений вычисляется в цикле, и компилятор не сохраняет в памяти суперпозиции, которые
являются промежуточными данными, а временно хранит их в регистрах;
в оперативную память попадает только результирующая суперпозиция.
Чтения исходных отображений происходят из оперативной памяти и автоматически сохраняются в кэш-памяти. Впоследствии, при вычислении
всех результирующих данных, эти исходные отображения уже читаются из
кэш-памяти.
Таким образом, как при последовательном вычислении, так и в пред-
ставленном алгоритме исходные данные читаются по одному разу из оперативной памяти.
Запись в оперативную память при последовательном выполнении про-
исходит следующим образом. Перед записью в оперативную память в буферной памяти накапливается кэш-линейка результирующих значений,
после чего вся кэш-линейка сбрасывается в память. Далее шина, связывающая память и процессор, ждет формирования следующей кэш-линейки.
Запись в оперативную память при параллельном выполнении происхо-
дит следующим образом. Перед записью в оперативную память накапливаются кэш-линейки во всех вычислительных ядрах. Пока накапливается
кэш-линейка в одном процессорном ядре, в оперативную память сбрасывается кэш-линейка другого процессорного ядра.
Таким образом, при параллельном алгоритме процесс записи в память
происходит интенсивно, а при последовательном — с большими задержками в ожидании формирования кэш-линеек.

82 Б. Я. Штейнберг, О. Б. Штейнберг
4.6. Векторизация рекуррентных циклов
Рассмотрим цикл с операцией α:
for (i = 0; i < N; i++) {
X[i]=Y[i]αZ[i]; (13)
}
Операцию α будем называть векторной, если на вычислительном железе
имеется аналогичная операция над векторами (например, над векторными
регистрами [67]). Векторизацию можно воспринимать частным случаем
SIMD распараллеливания на архитектуре с общей памятью.
Рассмотрим следующий цикл, эквивалентный (13):
for (i = 0; i < N/4; i++) {
VX[i]=VY[i]αVZ[i];
}
Добавление префикса V к именам массивов показывает, что новые массивы рассматриваются как массивы векторов (в данном случае — длины 4).
При этом они располагаются в памяти по тем же адресам, что и исходные
массивы. Тогда, если операция в цикле (13) является векторной, а результат
векторного выполнения цикла эквивалентен результату выполнения последовательного, то будем называть его векторизуемым.
Определение векторизуемого цикла дано только для циклов, содержащих один оператор присваивания. В случае, когда тело цикла содержит
больше операторов (причем, не обязательно только операторов присваивания), его иногда можно заменить несколькими циклами, некоторые из которых окажутся векторизуемыми.
Лэмпорт показал в работе [68], что класс векторизуемых программ может быть расширен за счет применения вспомогательных преобразований.
Рекуррентные циклы обычно воспринимаются как циклы, не допускающие параллельного выполнения. Но это не совсем так.
Пример 36. Рассмотрим рекуррентный цикл:
for (i = 0; i < N; i++) {
X[i+P] = X[i]*Y;
}
Заметим, что ни SIMD, ни MIMD выполнение не даст результат,
эквивалентный последовательному выполнению данного цикла.

Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 4 83
С другой стороны, если вычисления ведутся на архитектуре, способной одновременно выполнять умножение не для всех значений
счетчика цикла (как SIMD), а для P, то результат будет эквивалентен
последовательному выполнению.
Этот цикл является векторизуемым на архитектуре, содержащей
операцию сложения векторов длины P. Чтобы подчеркнуть векторизуемость, запишем цикл следующим образом:
for (i = 0; i < N/P; i++) {
VX[i+P] = VX[i]+VVY;
}
В данном цикле префикс VV обозначает вектор, состоящий из элементов, указывающих на одну и ту же ячейку памяти.
Конец примера.
Рассмотрим рекуррентный цикл более сложного вида:
X[0] = h[0];
X[1] = h[1];
...
X[m-1] = h[m-1];
for (i = m; i < N + m; i++) {
X[i] = a
X[i-1]+a2X[i-2]+...+amX[i-m]+a0; (14)
1
}
где a
≠ 0. Не умаляя общности, будем считать, что число итераций цикла
m
кратно 4 (иначе можно отщепить несколько последних итераций, оставив в
основном цикле количество итераций, кратное 4).
Произведем «развертку цикла» кратности 4 [54, 59]:
X[0] = h[0];
X[1] = h[1];
...
X[m-1] = h[m-1];
for (i = m; i < N+m; i = i+4) {
X[i] = a
X[i-1]+a2X[i-2]+...+amX[i-m]+a0;
1
X[i+1] = a1X[i]+a2X[i-1]+...+amX[i-m+1]+a0;
X[i+2] = a1X[i+1]+a2X[i]+...+amX[i-m+2]+a0;
X[i+3] = a1X[i+2]+a2X[i+1]+...+amX[i-m+3]+a0;
}

84 Б. Я. Штейнберг, О. Б. Штейнберг
1 0 00
xi
∗=
[ 1]
[]
xi
−
[ 1]
[]
xi
−
∗∗
Рассмотрим операторы присваивания тела цикла как СЛАУ от неизвестных x[i], x[i + 1], x[i + 2], x[i + 3]. Перенесем их в получившихся равенствах
в левую часть и получим следующее матричное уравнение:
[]
1 00
a
−
1
aa
−−
21
aaa
−−−
321
10
[ 1]
xi
+
[ 2]
xi
+
1
[ 3]
xi
+
aa a a a a a
12 3 2 1 0
aa a a a a
23 2 1 0
= ∗
aa a a a
34 1 0
aa a a
45 0
...
m m mm
−−−
... 0
mm m
−−
... 0 0
mm
−
... 0 0 0
m
−
[ 2]
xi
...
−
xi m
1
.
Так как в левой части матрица имеет нижнетреугольную форму, то у нее
существует обратная. Умножим обе части получившегося равенства слева
на эту матрицу и получим:
1
[]
xi
[ 1]
xi
+
+
[ 2]
xi
[ 3]
xi
+
aa a a a a a
12 3 2 1 0
aa a a a a
23 2 1 0
aa a a a
34 1 0
aa a a
45 0
...
... 0
... 0 0
... 0 0 0
1 0 00
1 00
a
−
1
= ∗
−−
aa
21
aaa
−−−
321
m m mm
−−−
mm m
−−
mm
−
m
−
10
1
−
[ 2]
xi
...
−
xi m
1
.
Результат произведения двух матриц правой части равенства обозначим
через матрицу C.
X[0] = h[0];
X[1] = h[1];
...
X[m-1] = h[m-1];

Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 4 85
d
for (i = m; i < N + m; i = i + 4) {
X[i]=с
X[i+1]=с
X[i+2]=с
X[i+3]=с
X[i-1]+с
1,1
X[i-1]+с
2,1
X[i-1]+с
3,1
X[i-1]+с
4,1
X[i-2]+...+с
1,2
X[i-2]+...+с
2,2
X[i-2]+...+с
3,2
X[i-2]+...+с
4,2
X[i-m]+d1;
1,m
X[i-m]+d2;
2,m
X[i-m]+d3;
3,m
X[i-m]+d4;
4,m
}
где d
= a0, d2 = a0– a1, d3 = a0– a1– a2, d4 = a0– a1– a2– a3.
1
Теперь цикл можно векторизовать следующим образом:
X[0] = h[0];
X[1] = h[1];
...
X[m-1] = h[m-1];
for (i = m; i < N + m; i = i + 4) {
VX[i] = vc
VVX[i-1]+ vc
i,1
VVX[i-2]+...+ vc
i,2
VVX[i-m]+vd;
i,m
}
1
d
где
vd =
2
.
d
3
d
4
4.7. Совместное применение распараллеливания
и векторизации циклов с линейной
рекуррентной зависимостью
В данном разделе предложен алгоритм автоматического распараллеливания рекуррентных циклов с линейной рекуррентной зависимостью. Затем предлагается способ векторизации полученного кода. Кроме того, рассматриваемый метод может быть скомбинирован с методом, изложенным
в [69].
Далее будет рассматриваться задача распараллеливания цикла (14).
Распараллеливание выполняется на вычислительную модель, состоящую из 2k вычислительных устройств (k ∈ N). Описываемый алгоритм можно использовать в случае архитектуры с общей памятью, распределенной
памятью, а также и на специализированных параллельных вычислительных
системах. От типа памяти, как и от других элементов архитектуры, зависит
эффективность, но не зависит корректность и устойчивость алгоритма.

86 Б. Я. Штейнберг, О. Б. Штейнберг
Не умаляя общности, будем считать, что N кратно m. Если это не так, то
применим преобразование «расщепление цикла», заменяя фрагмент программы (14) следующим фрагментом:
X[0] = h[0];
X[1] = h[1];
...
X[m-1] = h[m-1];
for (i = m; i < N+m — (N % m); i++) {
X[i] = a
X[i-1]+a2X[i-2]+...+amX[i-m]+a0;
1
}
for (i = N+m — (N % m); i < N+m; i++) {
X[i] = a1X[i-1]+a2X[i-2]+...+amX[i-m]+a0;
}
Количество итераций в первом цикле равно N – (N % m), а во втором,
соответственно, N % m. После этого к первому циклу можно применить
рассматриваемый алгоритм. Второй цикл можно не распараллеливать, поскольку он содержит мало итераций.
Алгоритм параллельного вычисления цикла с линейной
рекуррентной зависимостью
Применяя к циклу (14) преобразование «раскрутка цикла», получим:
X[0] = h[1];
X[1] = h[2];
...
X[m-1] = h[m-1];
X[m] = a
X[m+1] = amX[1]+a
...
X[i+N-1] = amX[N-1]+a
В результате получим код, вычисление которого равносильно решению
системы линейных алгебраических уравнений (СЛАУ). Данной СЛАУ соответствует следующая расширенная матрица:
X[0]+a
m
X[1]+...+a1X[m-1]+a0;
m-1
X[2]+...+a1X[m]+a0;
m-1
X[N]+...+a1X[N+m-2]+a0;
m-1

Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 4 87
a
1 21
32
...
, .
aa a a
a aa
AB
1 0 ... 0 0 0 ... 0 0 0
0 1 ... 0 0 0 ... 0 0 0
... ... ... ... ... ... ... ... ... ...
0 0 ... 1 0 0 ... 0 0 0
aa a
−− −
mm
0 ... 1 ... 0 0 0
− −−
... 1 0 ... 0 0 0
11
−
a aa
m
21
... ... ... ... ... ... ... ... ... ...
0 0 ... ... 1 0 0
0 0 ... 0 ... 1 0
0 0 ... 0 0
aa a
−− −
mm m
−−
12
aa a
−− −
mm
−
11
a
−
m
... 1
aa
−−
21
[0]
h
[1]
h
...
[ 1]
hm
a
0
a
0
...
a
0
a
0
a
0
−
Эту матрицу в свою очередь можно представить в виде блочной [70]
двухдиагональной матрицы:
h
0 0 0 ... 0 0 0
I
BA
−
0 0 ... 0 0 0
0 0 ... 0 0 0
0 0 ... 0 0 0
BA
−
BA
−
... ... ... ... ... ... ... ...
0 0 0 0 ... 0 0
0 0 0 0 ... 0
0 0 0 0 ... 0
1 0 ... 0 0 [0]
0 1 ... 0 0 [1]
I h= a =
=
где
... ... ... ... ... ... ...
0 0 ... 1 0 [ 2]
0 0 ... 0 1 [ 1
A
BA
−
−
, , ,
(0)
a
(0)
a
(0)
,
a
...
(0)
a
(0)
a
BA
(0)
a
h
h
hm a
hm
(0)
−
−
0
a
0
0
a
0
.
1 0 ... 0 0
−
... ... ... ... ...
= =
aa
−−
aa a
−− −
1 ... 0 0
a
1
23
mm
−−
12 1
mm
−−
... 1 0
... 1
mm
−
0 ...
m
... ... ... ... ...
0 0 ...
0 0 ... 0
aa
mm
1
−
a
m
Матрица A является нижнетреугольной с главной диагональю, состоя-
щей из единиц, а значит — обратимой. В блочной матрице умножим слева
все строки, кроме первой, на A–1. Получим:

88 Б. Я. Штейнберг, О. Б. Штейнберг
−−
1,1 1,2 1, 1
1 1 1 (1)
m,1 m,2 m,
1 1 ... 1+− − + − + + − +
() () ()
mm
x[i m ]= b x[i m] b x[i m + ] b x[i ] a ;
BI
( )
2
− =+=+
h
(1)
a
(1)
a
(1)
a
,
...
(1)
a
(1)
a
(1)
(1)
a
−
(1) 1 (1) 1 (0)
где
=
, .B A B a =A a
I
0 0 0 ... 0 0 0
(1)
BI
0 0 ... 0 0 0
−
0 0 ... 0 0 0
0 0 ... 0 0 0
(1)
BI
(1)
BI
−
... ... ... ... ... ... ... ...
0 0 0 0 ... 0 0
0 0 0 0 ... 0
0 0 0 0 ... 0
I
(1)
BI
−
BI
−
Таким образом, задача решения полученной СЛАУ эквивалентна задаче
вычисления цикла (14). Кроме того, эта СЛАУ может быть решена следующим фрагментом кода:
X[0] = h[0];
X[1] = h[1];
...
X[m-1] = h[m-1];
for (i = m; i < N + m; i = i + 4) {
1 1 1 (1)
x[i]= b x[i m] b x[i m + ] b x[i ] a ;
() () ()
1 ... 1− + − ++ −+
m
...
}
Теперь прибавим ко всем строкам, кроме первой, предыдущую строку,
умноженную слева на B
(1)
. Получим:
I
0 0 0 ... 0 0 0
BI
−
0 0 ... 0 0 0
0 0 0 ... 0 0 0
I
(2)
0 0 ... 0 0 0
(2)
BI
−
... ... .. ... ... ... ... ...
0 0 0 0 ... 0 0
0 0 0 0 ... 0 0
0 0 0 0 ... 0
2 1 (1) (1) (2 ) (1) (1) (1)
( ) ()
где
B = B h a Bha a Ba
, , .
2
I
(2)
−
h
h
2
(2)
a
(2)
a
,
...
(2)
a
I
(2)
a
(2)
a

Алгоритмы решения СЛАУ с блочно-ленточными матрицами. Глава 4 89
22 22
1,1 1,2 1,m 1
2 * 2* 1 ... 1− + − + + −− +
() () () ()
x[i]= b x[i m] b x[i m + ] b x[i m ] a ;
22
22 22
1,1 1,2 1,m 1
2 * 2* 1 ... 1− + − + + −− +
() () () ()
x[i]= b x[i m] b x[i m + ] b x[i m ] a ;
22
22
Решение полученной СЛАУ равносильно вычислению цикла (14). Кро-
ме того, эта СЛАУ может быть решена следующим фрагментом кода:
X[0] = h[0];
...
X[m – 1] = h[m – 1];
X[m] = h
[0];
2
...
X[2*m – 1] = h2[m – 1];
for (i = 2*m; i < N+2*m; i = i+2*m) {
...
22
() ()
x[i m ]= b x[i m] b x[i m + ]
b x[i m ] a ;
1 2 * 2* 1 ...+− − + − +
() ()
m,m m
m,1 m,2
1+ −− +
}
for (i = 2*m + m; i < N+2*m; i = i+2*m) {
...
() ()
x[i m ]= b x[i m] b x[i m + ]
b x[i m ] a ;
1 2 * 2* 1 ...+− − + − +
() ()
m,m m
m,1 m,2
1+ −− +
}
Первый цикл этой программы работает с нечетными строчками блочной
матрицы, а второй — с четными. Эта программа может быть параллельно
выполнена на двух ВУ (каждое ВУ вычисляет по одному циклу).
Таким же образом есть возможность получить фрагмент кода, эквива-
лентный фрагменту (14), который может быть распараллелен на P = 2
K
ВУ:
X[0] = h[0];
...
X[m – 1] = h[m – 1];
X[m] = h
[0];
2
...
X[2*m – 1] = h2[m – 1];
...
X[(P – 1)*m] = hP[0];
...
X[P*m – 1] = hP[m – 1];

90 Б. Я. Штейнберг, О. Б. Штейнберг
P
* * 1 ...−+ − +
( 1) * 1+ −− −+
P
P
( 1) * 1+ −− −+
1,1 1,2
−+ − +
1,m 1
P
1 * * 1 ...+− − + − +
m,m m
P
−+ − +
for (i = P*m; i < N+P*m; i = i+P*m) {
x[i]= b x[i P m] b x[i P m + ]
(P) ( )
1,1 1,2
(P) (P)
b x[i P m ] a ;
1,m 1
...
( ) (P)
x[i m ]= b x[i P m] b x[i P m + ]
b x[i P m ] a ;
1 * * 1 ...+− − + − +
( ) (P)
m,m m
m,1 m,2
}
for (i = P*m + m; i < N+P*m; i = i+P*m) {
x[i]= b x[i P m] b x[i P m + ]
(P) ( )
(P) (P)
b x[i P m ] a ;
* * 1 ...
( 1) * 1+ −− −+
P
...
x[i m ]= b x[i P m] b x[i P m + ]
P
( ) (P)
b x[i P m ] a ;
( ) (P)
m,1 m,2
( 1) * 1+ −− −+
}
Итак, получен алгоритм, состоящий в замене фрагмента программы (14)
фрагментом программы, циклы которого могут вычисляться параллельно.
При этом если коэффициенты a
, a1, …, am не зависят от счетчика цикла,
0
то преобразование является устойчивым, что показано в работе [30]. Под
устойчивостью понимается следующее: если значения элементов a0, a1, …,
am изменить на малую величину, то значения элементов вычисляемого массива X[m], X [m + 1], …, X[N + m – 1] тоже изменятся на малую величину.
Добавление векторизации циклов
к рассмотренному алгоритму
Выше показано, как можно распараллелить цикл (14) на P вычислительных устройств. Но каждое из этих устройств может быть способно выполнять векторные операции. В этом случае полученный параллельный код
можно векторизовать следующим образом. Векторизовать можно каждый
цикл по отдельности, а значит, алгоритм позволяет проводить векторизацию, использующую векторы разной длины для каждого вычислительного
устройства. Рассмотрим, как это сделать, на примере первого цикла, полученного в результате применения алгоритма.
for (i = P*m; i < N+P*m; i = i+P*m) {
x[i]= b x[i P m] b x[i P m + ]
(P) ( )
1,1 1,2
(P) (P)
b x[i P m ] a ;
1,m 1
* * 1 ...
( 1) * 1+ −− −+
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
