\subsection{Алгоритмы распараллеливания с распределением данных}

Рассмотрим подробнее устройство реализованных в системе SAPFOR проходов, отвечающих за построение схемы распределения данных и распараллеливание (см. Рис. \ref{fig:distr-alg}).

Начнём с прохода LOOP\_ANALYZER\_DATA\_DIST\_S0. На вход он получает АСД, множества заполненных структур \texttt{FuncInfo} и \texttt{LoopGraph} для всей программы, отражающих все её процедуры и циклы. Результатом данного прохода является заполненный граф измерений массивов. В проходе происходит итерация по всем процедурам входной программы. Для каждой процедуры производятся следующие действия:

\begin{itemize}
    \item выполняется проход по всем операторам процедуры;

    \item если этот оператор содержит запись в элемент массива или чтение из массива и этот массив распределяемый, то есть он не является нигде приватным или редукционным, происходит отображение этой операции на содержащие её циклы;

    \item отображение заключается в сохранении записей вида \textit{<цикл, массив, тип операции, номер измерения, A, B>} во временную структуру. Такая запись создаётся для каждого измерения, обращение по которому в текущей операции имеет вид \textit{A*i+B}, где \textit{A} и \textit{B} - целые числа, \textit{i} - счётчик цикла;

    \item далее происходит добавление полученных записей об обращениях к массивам в специальную структуру данных -- граф измерений массивов. Эта структура используется для построения схемы распределения данных и представляет собой граф, вершинами которого являются измерения массивов, в дугами -- связи между измерениями массивов согласно их использованию в циклах программы. Подробно построение графа массивов описано в \cite{disser}; 

    \item после обработки всех процедур проход завершает работу.
\end{itemize}

Далее запускается проход LOOP\_ANALYZER\_DATA\_DIST\_S1. Входные данные у него такие же, как и у LOOP\_ANALYZER\_DATA\_DIST\_S0. Его цель -- собрать информацию о зависимостях по данным в циклах и записать её в поля структуры \texttt{LoopGraph}.

В этом проходе также происходит итерация по всем процедурам программы и производятся следующие действия:

\begin{itemize}
    \item выполняется проход по всем операторам процедуры;

    \item обрабатываются обращения к массивам с сохранением записей вида \textit{<цикл, массив, тип операции, номер измерения, A, B>};

    \item вместо добавления информации в граф измерений массивов выявляются зависимости по данным внутри циклов путём построения специального графа зависимостей;

    \item для каждого цикла, который имеет зависимости по данным, заносится пометка в структуру \texttt{LoopGraph} о том, что цикл имеет зависимость по данным и не может быть распараллелен;

    \item исключения составляют зависимости фиксированной длинны, то есть такие, что номера записывающих и читающих витков отличаются на фиксированную величину. Такие циклы могут быть распараллелены с помощью директивы ACROSS (см. пример на Рис. \ref{fig:hp} в главе \ref{sec:benchmark});

    \item после обработки всех процедур проход завершает работу.
\end{itemize}

Проход LOOP\_ANALYZER\_DATA\_DIST\_S2 получает на вход граф измерений массивов. Результатом прохода является усечённый граф измерений массивов (такой граф измерений массивов, который не содержит циклов, порождающих конфликтные ситуации) для последующего создания распределения данных. В основе лежат алгоритмы поиска простых циклов в графе и построения минимального остовного дерева.

Проход CRATE\_TEMPLATE\_LINKS получает на вход оптимизированный граф измерений массивов, в котором отсутствуют циклы. Поскольку в этом графе нет циклов, все его компоненты связности представляют собой деревья. В каждом таком дереве находится массив с наибольшей размерностью и по нему создаётся служебный массив-шаблон, на который выравниваются все массивы рассматриваемого дерева. Таким образом, на вход этот проход принимает граф измерений массивов, а на выходе получаются директивы распределения и выравнивания данных, представленные структурой \texttt{DataDirective}, хранящей всю необходимую информацию.

После этого запускается проход LOOP\_ANALYZER\_COMP\_DIST распределения вычислений согласно построенному распределению данных. На вход он получает АСД программы, множества структур \texttt{FuncInfo}, \texttt{LoopGraph}, граф измерений массивов и построенное распределение данных. Общая схема работы совпадает с LOOP\_ANALYZER\_DATA\_DIST\_S0 и LOOP\_ANALYZER\_DATA\_DIST\_S1: происходит итерация по всем процедурам и заполнение кортежей \textit{<цикл, массив, тип операции, номер измерения, A, B>}. После заполнения этой информации, происходят следующие действия:

\begin{itemize}
    \item по отдельности рассматривается каждый цикл;

    \item по группе флагов структуры \texttt{LoopNode} определяется, есть ли факторы, препятствующие распараллеливанию цикла;

    \item если нет, среди всех массивов, используемых в цикле, выбирается лучший для того, чтобы относительно него распределить витки цикла. Предпочтение отдаётся массивам, в которые происходит запись и которые имеют наибольшее количество измерений. Если таких нет, выбор происходит среди массивов, из которых происходит чтение;

    \item для каждого цикла без ограничений на распараллеливание создаётся структура типа \texttt{ParallelDirective}, в которую записывается выбранный массив и другая информация, такая как ACROSS-зависимости и др., извлекаемая в том числе из графа измерений массивов;

    \item полученные структуры \texttt{ParallelDirective} сохраняются в соответствующих структурах \texttt{LoopNode};

    \item после создание всех директив, для каждого тесновложенного гнезда параллельных циклов происходит объединение \texttt{ParallelDirective} для того, чтобы распараллеливался не только самый верхний цикл, а всё гнездо.
\end{itemize}

Затем вызывается проход CREATE\_PARALLEL\_DIRS. На вход он получает построенные директивы распределения данных и директивы распараллеливания циклов в виде структур \texttt{DataDirective} и \texttt{ParallelDirective}.

Сначала рассматриваются директивы распределения данных. Для каждой директивы, по информации из структуры, строится её текстовое представление: в виде строк конструируются DVM-директивы \texttt{ALIGN} и \texttt{DISTRIBUTE}. Далее аналогичный процесс происходит с директивами распараллеливания: формируются директивы \texttt{PARALLEL ON} и все нужные клаузы, такие как \texttt{PRIVATE}, \texttt{REDUCTION}, \texttt{ACROSS}, \texttt{SHADOW\_RENEW}, \texttt{REMOTE\_ACCESS}. Текстовые директивы DVM-системы сохраняются в виде множества структур \texttt{CreatedDirective}, которые хранят текст директивы и номер строки, перед которой её необходимо вставить.

Наконец, проход INSERT\_PARALLEL\_DIRS, получающий множество созданных директив, производит их вставку в виде комментариев в АСД обрабатываемой программы перед соответствующими операторами.

