This commit is contained in:
2024-05-06 19:59:07 +03:00
commit 15ec9d2208
40 changed files with 3135 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
\subsection{Второй этап -- реализация}
Таким образом, новый режим работы был оформлен как отдельных проход. По аналогии этот проход был назван INSERT\_PARALLEL\_DIRS\_NODIST, что подчёркивает отсутвие построения распределения данных. Поскольку INSERT\_PARALLEL\_DIRS осуществляет только вставку созданных заранее директив, его функционал менять не пришлось, поэтому внутри INSERT\_PARALLEL\_DIRS\_NODIST вызывается код прохода INSERT\_PARALLEL\_DIRS.
Само создание текста параллельных директив, которое происходило в проходе CREATE\_PARALLEL\_DIRS, подверглось правкам. Оттуда полностью убран код, отвечающий за директивы распределения данных. Также изменён код для конструирования параллельных директив: убрано создание приставки ON в директиве и клауз удалённого доступа к данным, среди которых SHADOW\_RENEW и REMOTE\_ACCESS. Также был переработан алгоитм заполнения клауз TIE (который был реализован для старого режима распараллеливания на общую память). В нём использовались массивы, согласно которым распределялись витки цикла, а в новом режиме отображения витков циклов на массивы нет. Новый алгоритм напрямую использует обращения к массивам, происходящие внутри цикла. Оказалось, что новая версия CREATE\_PARALLEL\_DIRS стала намного компактнее и было решено не создавать для неё отдельный проход и сделать частью INSERT\_PARALLEL\_DIRS\_NODIST.
Также, новый проход не унаследовал зависимости от проходов \\ CREATE\_TEMPLATE\_LINKS и LOOP\_ANALYZER\_DATA\_DIST\_S*, посколько они отвечали только за распределение данных.
Ещё пришлось переработать проход LOOP\_ANALYZER\_COMP\_DIST. Он отвечал за анализ обращений к массивам внутри цикла и распараллеливание, на основе этой информации. Главное что пришлось изменить -- убрать часть с выбором массива, согласно которому распределяются витки цикла. Преобразованный проход получил название LOOP\_ANALYZER\_NODIST.
В результате схема зависимостей изменилась следующим образом:
\pagebreak
\begin{figure}[h]
\centering
\includegraphics[scale=0.5]{src/assets/pass_deps_nodist_0.png}
\caption{сравнение схемы работы проходов режима распараллеливания с распределением данных (слева) с новым режимом распараллеливания на общую память (справа).}
\end{figure}
Далее, следует сказать о ещё одной немаловажной части работы -- интеграции с инструментом для визуализации (диалоговой оболочкой) системы SAPFOR. Здесь требовалось реализовать два основных сценария работы. Первый основной сценарий -- запуск распараллеливания на общую память. Требовалось предоставить интерфейс для вызова прохода визуализатором. С этим не возникло сложностей, так как для этого потребовалось написать простую функцию \texttt{SPF\_SharedMemoryParallelization}, которую вызывает диалоговая оболочка и которая в свою очередь запускает проход INSERT\_PARALLEL\_DIRS\_NODIST. Второй сценарий работы предполагал запуск анализа распараллеливания без фактической вставки директив. Аналгично запуску распараллеливания, была добавлена возможность вызывать из визуализатора проход LOOP\_ANALYZER\_NODIST.

View File

@@ -0,0 +1,15 @@
\subsection{Дополнительные проблемы}
Так же в процессе тестирования были обнаружены некоторые другие проблемы, которые не относятся напрямую с распараллеливанием на общую память. Среди них есть как недочёты системы SAPFOR, так и DVM:
\begin{itemize}
\item неправильная обработка OpenMP директив (SAPFOR)
\item распараллеливание циклов, содержащих оператор return (SAPFOR)
\item неправильная обработка встроенных функций Фортрана (функция int() обрабатывалась как обычная переменная) (DVM)
\item ошибки при создании кода для CUDA-устройств связанные со встроенными битовыми операциями (DVM)
\item ошибки при создании кода для CUDA-устройств связанные с использованием в фортране ключевых слов языка Си (DVM)
\end{itemize}

View File

@@ -0,0 +1,46 @@
\subsection{Первый этап -- подготовка}
Основной целью данного этапа стал анализ внутреннего устройства системы SAPFOR, так как было принято решение реализовывать распараллеливание как часть её функционала. На данном этапе было проведено исследование исходного кода системы, которое дало ответы на следующие вопросы:
\begin{itemize}
\item как происходит запуск распараллеливания с распределением данных;
\item какой код и в какой последовательни работает при распараллеливании с распределением данных;
\item какие органичивающие проверки планируется убрать в проходе распараллеливания на общую память;
\item какие структуры данных используются;
\item использование каких структур данных нужно избежать;
\item какие существующие алгоритмы (с можификациями или без) можно (и нужно) переиспользовать в добавляемом режиме;
\end{itemize}
Путём чтения исходного кода, документации и общения с авторами системы все эти вопросы были разрешены. Далее излагаются основные полученные сведения.
Как уже упомяналось ранее, структурно система SAPFOR состоит из множества алгоритмов, которые логически разделены на отдельные блоки -- проходы. Каждый проход выполняет свою функцию и может зависеть от других проходов. При запуске прохода перед ним запускаются все проходы, от которых он зависит непосредственно или транзитивно, при чём каждый проход запускается не больше одного раза. Таким образом в системе выстраивается дерево зависимостей проходов. На данный момент в системе их уже больше сотни.
Конечным проходом при распараллеливании с распределением данных явлется проход с названием INSERT\_PARALLEL\_DIRS, который производит вставку созданных директив в код. Главные его зависимости -- проход CREATE\_PARALLEL\_DIRS создания параллельных директив (без вставки) по полученной информации из анализа циклов. Анализ циклов производится следующей группой проходов:
\begin{itemize}
\item LOOP\_ANALYZER\_COMP\_DIST;
\item LOOP\_ANALYZER\_DATA\_DIST\_S2;
\item LOOP\_ANALYZER\_DATA\_DIST\_S1;
\item LOOP\_ANALYZER\_DATA\_DIST\_S0;
\end{itemize}
Они заполняют структуры, описывающие циклы, анализируют обращения к массивам внутри циклов, отображают обращения к массивам на циклы. Вместе с этим происходит вызов прохода CREATE\_TEMPLATE\_LINKS, который создаёт структуру данных, позволяющую строить распределение данных. Эта структура данных называется \textit{графом измерений массивов}. Кроме этого в работе распараллеливания участвует ещё множество других проходов (всего порядка семидесяти), которые не относятся к распараллеливанию напрямую. Эти проходы не касаются распределения данных, поэтому они пристально не рассматривались. Часть дерева зависимостей прохода вставки параллельных директив изображена на Рис. \ref{fig:distr-alg}.
\pagebreak
\begin{figure}[h]
\centering
\includegraphics[scale=0.5]{src/assets/pass_deps_dist.png}
\caption{упрощённая схема работы проходов при распараллеливании с распределением данных.}
\label{fig:distr-alg}
\end{figure}
Таким образом, было установлено, что для успешной реализации распараллеливания на общую память необходимо и достаточно внести изменения в эти семь проходов, а от прохода CREATE\_TEMPLATE\_LINKS стоит полностью отказаться в новом режиме.

View File

@@ -0,0 +1,11 @@
\section{Построение решения}
Весь процесс построения решения можно разделить на три основных этапа -- исследование кодовой базы системы SAPFOR, внесение необходимых правок и тестирование реализованного функционала.
\input{src/sections/solution/prep}
\input{src/sections/solution/impl}
\input{src/sections/solution/testing}
% \input{src/sections/solution/issues}
\todo{Описание реализованных алгоритмов можно сюда добавить, прям по проходам}

View File

@@ -0,0 +1,50 @@
\subsection{Третий этап -- тестирование и решение возникших проблем}
Поскольку работа ведётся с исходным кодом фортран-программ, множество возможных вариантов входных программ слишком велико, чтобы предусмотреть абсолютно все ситуации на этапе реализации. Из-за этого было необходимо произвести тщательное тестирование, чтобы выявить основные случаи некорректного поведения системы SAPFOR.
Было проведено тщательное тестирование добавленного функционала на предмет корректности. Оно проводилось как на небольших модельных примерах, так и на больших примерах практически используемых программ. Суммарно за всё тестирование было обнаружено порядка тридцати различных примеров некорректного поведения добавленного режима. Далее описаны наиболее содержательных из найденных ошибок и то, как они были исправлены.
Первая из них касалась обработки приватных массивов. При распределении данных в DVM-системе запрещается распределять массивы, которые являются приватными хотябы для одного цикла. Поэтому в системе SAPFOR такие массивы не отображаются на циклы при построении схемы распределения данных. При распараллеливании на общую память DVM система допускает использование одного массива в качестве приватного и неприватного для разных циклов. Поэтому для режима распараллеливания на общую память было добавлено отображение на цикл всех неприватных для него массивов (в частности, это нужно для заполнения клаузы TIE). Из-за этого пришлось внести правки в проход LOOP\_ANALYZER\_NODIST.
Ещё одна проблема связана с обработкой передаваемых в процедуры секций массивов. Дело в том, что в DVM-системе запрещено использование в разных циклах пересекающихся по памяти различных секций массивов. Рассмотрим следующий пример:
\begin{lstlisting}[style=FORT,caption={пример, вызывающий ошибку выполнения.}]
program p
...
integer:: A(100)
call foo(A)
!DVM$ REGION
!DVM$ PARALLEL (i), TIE(A(i))
do i = 1, 100
A(i) = ...
endo
!DVM$ END REGION
end
subroutine foo(A)
integer:: A(50)
!DVM$ REGION
!DVM$ PARALLEL (i), TIE(A(i))
do i = 1, 50
A(i) = ...
endo
!DVM$ END REGION
end
\end{lstlisting}
В нём нём есть два параллельных цикла (строки 8 и 19). Один из них использует полный массив A (который объявлен на строке 3). Другой же использует секцию массива A, которая содержит его первые 50 элементов (объявление на строке 15). Запуск этого примера приводит к ошибке выполнения системы DVM. При этом если бы в подпрограмме \texttt{foo} было объявлено, что массив имеет размер 100 (то есть фактически передавался бы массив целиком), то ошибки бы не было.
В случае аналогичного распараллеливания с распределением, ошибок выполнения DVM не возникает. Из-за этого в цепь проходов распараллеливания на общую память был добавлен новый проход, который получил название SELECT\_ARRAY\_DIM\_CONF. Он запускается после анализа циклов и фильтрует параллельные циклы так, чтобы в них не было пересечений по памяти используемых массивов. При обнаружение конфликтной группы циклов, выбирается один из них, который будет распараллелен, а другие к распараллеливанию не допускаются.
Таким образом схема проходов нового режима получила окончательный вид, представленный на Рис. \ref{fig:deps-final}:
% \pagebreak
\begin{figure}[h]
\centering
\includegraphics[scale=0.5]{src/assets/pass_deps_nodist_1.png}
\caption{итоговая схема работы проходов при распределении на общую память.}
\label{fig:deps-final}
\end{figure}