\subsection{Процесс распараллеливания}

 Часто для того, чтобы получить эффективный параллельный вариант программы с помощью системы SAPFOR, требуется провести ряд преобразований исходного кода. При распараллеливании тестов NAS приходилось совершать много преобразований двух видов: подстановка процедур, указание приватных и редукционных массивов.

В некоторых местах распараллеливание циклов затруднено наличием в теле цикла вызовов процедур. Чтобы распараллелить такие циклы, можно попытаться подставить тело процедуры вместо её вызова. Так как в диалоговой оболочке есть проходы анализа кода и подстановки процедур, можно также без больших усилий найти циклы, которые не распараллеливаются из-за вызовов процедур и произвести подстановку в нужных местах.

Нередко в коде встречаются приватные и редукционные массивы. Так как система SAPFOR в данный момент не поддерживает автоматическое обнаружение таких массивов с помощью методов статического анализа, их приходится вручную указывать при помощи директив \texttt{!\$SPF ANALYSIS (PRIVATE)} и \texttt{!\$SPF ANALYSIS (REDUCTION)}.

Отдельного внимания потребовала программа LU. Основная вычислительная нагрузка программы приходится на алгоритм SSOR (метод симметричной последовательной верхней релаксации). Он представляет собой пару гнёзд циклов тесной вложенности два. Рассмотрим только первое из этих гнёзд, так как второе распараллеливается аналогично. Возможности параллельного выполнения витков этого цикла мешает только зависимость по данным массива \texttt{rsd}: каждая итерация с номером \textit{(i, j)} использует элементы, которые вычисляются витками \textit{(i - 1, j)}, \textit{(i, j - 1)}. В такой ситуации витки имеют частичный порядок и некоторые группы витков могут выполняться параллельно. В пакете есть три реализации такого распараллеливания:

\begin{itemize}
    \item версия с использованием так называемого \textit{конвейерного параллелизма}. В ней поддержание корректной последовательности витков цикла осуществляется за счёт использования служебного синхронизационного массива и примитивов синхронизации OpenMP \texttt{atomic read} и \texttt{atomic write};
    
    \item в другой версии, которая называется DO-ACROSS, используется похожая схема, только синхронизация реализована механизмом упорядоченного выполнения витков цикла. Для этого в OpenMP есть специальная директива \texttt{ORDERED};

    \item последняя версия использует \textit{параллелизм по гиперплоскостям}. При наличии такой зависимости, витки с номерами \textit{(i, j)}, у которых сумма \textit{i + j} совпадает, образуют гиперплоскости и могут выполняться параллельно (см. Рис. \ref{fig:hp}).
\end{itemize}

\begin{figure}[h]
\centering
\includegraphics[scale=1]{src/assets/hp.png}
\caption{Разделение итерационного пространства на гиперплоскости. Внутри одной гиперплоскости элементы могут считаться параллельно.}
\label{fig:hp}
\end{figure}

\pagebreak

В силу того, что SAPFOR не способен проанализировать логику синхронизаций и зависимости между разными гиперплоскостями, первый и третий варианты распараллелить не удалось. Однако, во втором варианте система SAPFOR успешно распознала зависимость по данным и распараллелила цикл с использованием клаузы \texttt{ACROSS}:

\pagebreak

\begin{lstlisting}[style=FORT,caption={
Пример вставленной клаузы ACROSS, задающую зависимость размера 1 по последним двум измерениям массива \texttt{rsd}. В теле цикла происходит чтение элементов массива \texttt{rsd(*,*,j-1,k)}, \texttt{rsd(*,*,j,k-1)} и запись в элементы массива \texttt{rsd(*,*,j,k)}. 
}]
!DVM$   REGION 
!DVM$   PARALLEL (k,j), PRIVATE (...), TIE(..., rsd(*,*,j,k)), ACROSS (rsd(0:0,0:0,1:0,1:0))
        do  k = 2,nz - 1
            do  j = jst,jend
                ...
            enddo  
        enddo  
!DVM$   END REGION
\end{lstlisting}

В результате автоматизированного распараллеливания с помощью системы SAPFOR были получены параллельные версии тестов BT, CG, EP, FT, SP, LU. Остальные тесты (то есть MG и UA) распараллелить не удалось даже при помощи преобразований. Причиной этому служит наличие в этих тестах нетривиальной логики, которая не позволяет системе SAPFOR производить распараллеливание.