minor changes

This commit is contained in:
2024-05-06 21:42:13 +03:00
parent 15ec9d2208
commit ec20fbd897
18 changed files with 63 additions and 88 deletions

BIN
main.pdf

Binary file not shown.

View File

@@ -2,18 +2,14 @@
Рассмотрим подробнее устройство проходов, отвечающих за построение схемы распределения данных и распараллеливании (см. Рис. \ref{fig:distr-alg}).
Начнём с прохода LOOP\_ANALYZER\_DATA\_DIST\_S0. На вход он получает АСТ, заполненные структуры \texttt{FuncInfo} и \texttt{LoopGraph} для всей программы. Результатом данного прохода является заполненный граф измерений массивов.
В проходе происходит итерация по всем структурам \texttt{FuncInfo}, то есть по каждой функции. Для каждой функции выполняется следующее:
Начнём с прохода LOOP\_ANALYZER\_DATA\_DIST\_S0. На вход он получает АСД, заполненные структуры \texttt{FuncInfo} и \texttt{LoopGraph} для всей программы. Результатом данного прохода является заполненный граф измерений массивов. В проходе происходит итерация по всем структурам \texttt{FuncInfo}. Для каждой процедуры производятся следующие действия:
\begin{itemize}
\item выполняется проход по всем операторам функции;
\item выполняется проход по всем операторам процедуры;
\item если этот оператор содержит запись в элемент массива или чтение из массива и этот массив распределяемый, то есть он не является нигде приватным или редукционным, происходит отображение этой операции на содержащие её циклы;
\item отображение заключается в сохранении записей вида \textit{<цикл, массив, тип операции, номер измерения, A, B>} во временную структуру. Такая запись создаётся для каждого измерения, обращение по которому в текущей операции имеет вид \textit{A*i+B}, где \textit{A} и \textit{B} - целые числа, \textit{i} - счётчик цикла.
\item после похода по оператором, для каждого цикла проводится анализ зависимостей по данным. То есть проверка на то, что никакой виток цикла не использует данные, записываемые другими витками. Исключения составляют зависимости с фиксированным расстоянием между записывающим и читающим витками циклов. При наличии зависимостей в цикле, в структуру \texttt{LoopGraph} заносится соответствующая пометка.
\item отображение заключается в сохранении записей вида \textit{<цикл, массив, тип операции, номер измерения, A, B>} во временную структуру. Такая запись создаётся для каждого измерения, обращение по которому в текущей операции имеет вид \textit{A*i+B}, где \textit{A} и \textit{B} - целые числа, \textit{i} - счётчик цикла;
\item далее происходит добавление полученных записей об обращениях к массив в специальную структура данных -- граф измерений массивов. Эта структура используется для построения схемы распределения данных и представляет собой граф, вершинами которого являются измерения массивов, в дугами -- связи между измерениями массивов согласно их использованию в циклах программы (см. пример на Рис. \ref{fig:array_graph}). Подробно построение графа массивов описано в \cite{disser};
@@ -27,12 +23,12 @@
\label{fig:array_graph}
\end{figure}
Далее запускается проход LOOP\_ANALYZER\_DATA\_DIST\_S1. Входные данные у него такие же, как и у LOOP\_ANALYZER\_DATA\_DIST\_S0. Его цель -- собрать информацию о зависимостях по данным в циклах и обнавить соответствующие флаги в структурах \texttt{LoopGraph}.
Далее запускается проход LOOP\_ANALYZER\_DATA\_DIST\_S1. Входные данные у него такие же, как и у LOOP\_ANALYZER\_DATA\_DIST\_S0. Его цель -- собрать информацию о зависимостях по данным в циклах и записать её в поля структуры \texttt{LoopGraph}.
В этом проходе также идёт итерация по всем функциям программы и производятся следующие действия:
В этом проходе также происходит итерация по всем процедурам программы и производятся следующие действия:
\begin{itemize}
\item опять выполняется проход по всем операторам функции;
\item опять выполняется проход по всем операторам процедуры;
\item точно так же обрабатываются обращения к массивам с сохранением записей вида \textit{<цикл, массив, тип операции, номер измерения, A, B>};
@@ -45,43 +41,29 @@
\item после обработки всех функций проход завершает работу;
\end{itemize}
Проход LOOP\_ANALYZER\_DATA\_DIST\_S2 получает на вход граф измерений массивов. Результатом прохода является усечённый граф измерений массивов (такого графа измерений массивов, который не содержит циклов, порождающие конфликтные ситуации) для последующего создания распределения данных.
Он имеет следующий алгоритм:
\begin{itemize}
\item рассматривается граф измерений массивов;
\item происходит поиск циклов в графе;
\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>}. После заполнения этой информации, происходят следующие действия:
После этого запускается проход 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 по группе флагов структуры \texttt{LoopNode} определяется, есть ли факторы, препятствующие распараллеливанию цикла;
\item среди всех массивов, используемых в цикле, выбирается лучший для того, чтобы относительно него распределить витки циклы. Предпочтение отдаётся массивам, в которые происходит запись и имеют наибольшее количество измерений. Если таких нет, выбираются массивы, из которых происходит чтение.
\item если нет, среди всех массивов, используемых в цикле, выбирается лучший для того, чтобы относительно него распределить витки циклы. Предпочтение отдаётся массивам, в которые происходит запись и которые имеют наибольшее количество измерений. Если таких нет, выбираются массивы, из которых происходит чтение;
\item для каждого цикла без ограничений на распараллеливание создаётся структура типа \texttt{ParallelDirective}, в которую записывается выбранный массив и другая информация, такая как ACROSS-зависимости и др., извлекаемая в том числе из графа измерений массивов;
\item полученные структуры \texttt{ParallelDirective} сохраняются в соответствующих структурах \texttt{LoopNode}.
\item полученные структуры \texttt{ParallelDirective} сохраняются в соответствующих структурах \texttt{LoopNode};
\item после создание всех директив, для каждого тесновложенного гнезда параллельных циклов происходит объединение \texttt{ParallelDirective} для того, чтобы распараллеливался не только самый верхний цикл, а всё гнездо.
\item после создание всех директив, для каждого тесновложенного гнезда параллельных циклов происходит объединение \texttt{ParallelDirective} для того, чтобы распараллеливался не только самый верхний цикл, а всё гнездо;
\end{itemize}
Следом вызывается проход CREATE\_PARALLEL\_DIRS. На вход он получает построенные директивы распределения данных и директивы распараллеливания циклов в виде внутренних структур системы SAPFOR \texttt{DataDirective} и \texttt{ParallelDirective}.
Следом вызывается проход CREATE\_PARALLEL\_DIRS. На вход он получает построенные директивы распределения данных и директивы распараллеливания циклов в виде структур \texttt{DataDirective} и \texttt{ParallelDirective}.
Сначала рассматриваются директивы распределения данных. Для каждой директивы, по информации из структуры, строится её текстовое представление, в виде строк конструируются такие DVM-директивы как ALIGN и DISTRIBUTE.
Сначала рассматриваются директивы распределения данных. Для каждой директивы, по информации из структуры, строится её текстовое представление: в виде строк конструируются DVM-директивы \texttt{ALIGN} и \texttt{DISTRIBUTE}. Далее аналогичный процесс происходит с директивами распараллеливания: формируются директивы \texttt{PARALLEL ON} и все нужные клаузы, такие как \texttt{PRIVATE}, \texttt{REDUCTION}, \texttt{ACROSS}, \texttt{SHADOW\_RENEW}, \texttt{REMOTE\_ACCESS}. Текстовые директивы DVM-системы сохраняются в виде множества структур \texttt{CreatedDirective}, которые хранят текст директивы и строку, перед которой её необходимо будет вставить.
Далее аналогичный процесс происходит с директивами распараллеливания: формируются директивы PARALLEL ON и все нужные клаузы, такие как PRIVATE, REDUCTION, ACROSS, SHADOW\_RENEW, REMOTE\_ACCESS.
Текстовые директивы DVM-системы сохраняются в виде множества структур \texttt{CreatedDirective}, которые хранят текст директивы и строку, перед которой её необходимо будет вставить.
Наконец, проход INSERT\_PARALLEL\_DIRS, получающий множество созданных директив, производит их вставку в виде комментариев в АСТ обрабатываемой программы перед соответствующими операторами.
Наконец, проход INSERT\_PARALLEL\_DIRS, получающий множество созданных директив, производит их вставку в виде комментариев в АСД обрабатываемой программы перед соответствующими операторами.

View File

@@ -2,18 +2,18 @@
В предыдущей главе поверхностно описывались функции проходов, работающих при распараллеливании с распределением данных и их аналогов для случая общей памяти. В этой главе приводится подробное описание алгоритмов, с помощью которых реализованы эти проходы.
Весь исходный код системы SAPFOR написан на языке C++. Программа, поступающая на вход системе, переводится в абстрактное синтаксическое дерево операторов (АСТ). В качестве реализации абстрактного синтаксического дерева используется библиотека Sage++ \cite{sage}. Используя это представление, входную программу можно анализировать, модифицировать и переводить обратно в код на фортране.
Весь исходный код системы SAPFOR написан на языке C++. Программа, поступающая на вход системе, переводится в абстрактное синтаксическое дерево операторов (АСД). В качестве реализации абстрактного синтаксического дерева используется библиотека Sage++ \cite{sage}. С её помощью входную программу можно анализировать, модифицировать и переводить обратно в код на фортране.
Помимо библиотеки Sage++, в системе SAPFOR введён ряд типов данных, упрощающих разработку. Среди них можно выделить следующие наиболее используемые:
Помимо структур библиотеки Sage++, в системе SAPFOR введён ряд типов данных, упрощающих разработку. Среди них можно выделить следующие наиболее используемые:
\begin{itemize}
\item \texttt{Array} -- тип, отражающий массив, используемый во входной программе. Помимо прочего, содержит информацию о его имени, размерности, месте определения, местах использования;
\item \texttt{Array} -- тип, отражающий массив входной программы. Помимо прочего, содержит информацию о его имени, размерности, определении, местах использования;
\item \texttt{FuncInfo} -- отражает функцию входной программы. Содержит информацию о имени, месте определения, точках её вызова, подключенных common-блоков, именах её формальных аргументов, информацию о наличие побочных эффектов и т. д.;
\item \texttt{FuncInfo} -- отражает процедуру входной программы. Содержит информацию о названии, определении, точках её вызова, подключенных common-блоков, именах её формальных аргументов, информацию о наличие побочных эффектов и т. д.;
\item \texttt{LoopGraph} -- отражает цикл. Имеет информацию о месте расположения, вложенных циклах, вызовах функций внутри цикла, операциях над массивами внутри цикла. Если цикл находится в канонической форме, дополнительно содержит название итерационной переменной, границах и шаге итерирования, глубину гнезда тесновложенных циклов. Кроме этого структура содержит набор флагов, отмечающих интересующие с точки зрения распараллеливания свойства;
\item \texttt{ParallelDirective} -- структура, отражающая созданную директиву распараллеливания. Содержит информацию о размере распараллеливаемого гнезда, о клаузах типа SHADOW\_RENEW, ACROSS, REMOTE\_ACCESS, REDUCTION, PRIVATE и используемых в них массивах;
\item \texttt{ParallelDirective} -- структура, отражающая созданную директиву распараллеливания. Содержит информацию о размере распараллеливаемого гнезда, о клаузах \texttt{SHADOW\_RENEW}, \texttt{ACROSS}, \texttt{REMOTE\_ACCESS}, \texttt{REDUCTION}, \texttt{PRIVATE} и используемых в них массивах;
\end{itemize}
\input{src/sections/impl/distr}

View File

@@ -2,11 +2,11 @@
Как было описано ранее, проходы LOOP\_ANALYZER\_DATA\_DIST\_S* и CREATE\_TEMPLATE\_LINKS отвечают сугубо за распределение данных, поэтому работа по распараллеливанию на общую память начинается сразу с аналога прохода LOOP\_ANALYZER\_COMP\_DIST, который получил название LOOP\_ANALYZER\_NODIST.
На вход он также принимает АСТ программы, множество структур \texttt{LoopGraph} и \texttt{FuncInfo} (но без графа измерений массивов). Отличия в работе начинаются со способа построения кортежей \textit{<цикл, массив, тип операции, номер измерения, A, B>}: при распределении данных такие записи не сохранялись для массивов, которые являются приватными в каком либо цикле программы. При распараллеливании на общую память есть возможность снять это ограничение и отображать на цикл все его неприватные массивы, даже если для других циклов они являются приватными.
На вход он также принимает АСД программы, множество структур \texttt{LoopGraph} и \texttt{FuncInfo} (но без графа измерений массивов). Отличия в работе начинаются со способа построения кортежей \textit{<цикл, массив, тип операции, номер измерения, A, B>}: при распределении данных такие записи не сохранялись для массивов, которые являются приватными в каком либо цикле программы. При распараллеливании на общую память есть возможность снять это ограничение и отображать на цикл все его неприватные массивы, даже если для других циклов они являются приватными.
Далее, появилась возможность обойти отображение витков цикла на распределяемый массив. Преобразованный алгоритм не запускает поиск наилучшего распределённого массива для распределения вычислений и не заполняет соответствующее поле в структуре \texttt{ParallelDirective}, хотя заполнение других полей, таких как ACROSS-зависимости, остаёься актуальным.
На следующем этапе работает новый проход SELECT\_ARRAY\_DIM\_CONF решающий проблему распараллеливания циклов, использующих секции массивов. Подробно проблема описывалась в предыдущей главе. На вход алгоритм принимает множество структур \texttt{LoopNode} с заполенными полями параллельных директив \texttt{ParallelDirective}. Так же передаётся граф связей между массивами. Вершинами этого ориентированного графа являются структуры \texttt{Array}. Дуги строятся по следующему правилу: пусть массив \textit{B} является формальным аргументом процедуры \textit{F}. Тогда в графе существует дуга от массива \textit{A} к \textit{B} в том и только том случае, если есть вызов процедуры \textit{F} с предачей секции массива \textit{A} в качестве фактического аргумента для \textit{B}.
На следующем этапе работает новый проход SELECT\_ARRAY\_DIM\_CONF решающий проблему распараллеливания циклов, использующих секции массивов. Подробно проблема описывалась в предыдущей главе. На вход алгоритм принимает множество структур \texttt{LoopNode} с заполенными полями параллельных директив \texttt{ParallelDirective}. Так же передаётся \textit{граф связей между массивами}. Вершинами этого ориентированного графа являются структуры \texttt{Array}. Дуги строятся по следующему правилу: пусть массив \textit{B} является формальным аргументом процедуры \textit{F}. Тогда в графе существует дуга от массива \textit{A} к \textit{B} в том и только том случае, если есть вызов процедуры \textit{F} с предачей секции массива \textit{A} в качестве фактического аргумента для \textit{B}.
Перед тем как рассматривать работу алгоритма, введём два понятия. Будем называть масив \textit{главным}, если он не является формальным аргументом функции, в которой он определён. Заметим, что в графе связей между массивами главными будут те и только те, которые не имеют входящих дуг. Также назовём \textit{конфигурацией} n-мерного массива кортеж из n чисел $a_{i}$, в котором $a_{i}$ является длинной i-го измерения.
@@ -17,23 +17,23 @@
\item для каждого главного массива выбирается лучшая конфигурация -- такая, которая соовтветствует наибольшему суммарному количеству элементов (суммарное кол-во элементов вычисляется как произведение элементов кортежа);
\item рассматриваются все невыбранные конфигурации. Все циклы, которые используют хоть один массив, конфигурация которого не была выбрана на прошлом шаге, отстраняются от распараллеливания путём поднятия специального флага \texttt{hasAccessToSubArray} в структуре \texttt{LoopGraph} и удаляет в ней директиву распараллеливания, если она была;
\item рассматриваются все невыбранные конфигурации. Все циклы, которые используют хоть один массив, конфигурация которого не была выбрана на прошлом шаге, отстраняются от распараллеливания путём поднятия специального флага \texttt{hasAccessToSubArray} в структуре \texttt{LoopGraph} и удаления в ней директивы распараллеливания, если она была;
\end{itemize}
Таким образом, после данного прохода от распараллеливания будут отстранены циклы, которые могут спровоцировать ошибку выполнения системы DVM.
Далее в проходе INSERT\_PARALLEL\_DIRS\_NODIST запускается алгоритм получения текстового представления директив распараллеливания \texttt{ParallelDirective}, которое имет следующие отличия от случая распараллеливания с распределением:
Далее в проходе INSERT\_PARALLEL\_DIRS\_NODIST запускается алгоритм получения текстового представления директив распараллеливания \texttt{ParallelDirective}, который имет следующие отличия от случая распараллеливания с распределением:
\begin{itemize}
\item директивы распределения данных не используются проходом и не обрабатываются;
\item в параллельных директивах не происходит конструирование клаузы ON;
\item в параллельных директивах не происходит конструирование клаузы \texttt{ON};
\item не происходит конструирование клауз SHADOW\_RENEW и REMOTE\_ACCESS;
\item не происходит конструирование клауз \texttt{SHADOW\_RENEW} и \texttt{REMOTE\_ACCESS};
\item добавлено конструирование клауз TIE. Для заполнения списка отображаемых массивов используется сохранённая информация об обращениях к массивам с прохода LOOP\_ANALYZER\_NODIST.
\item добавлено конструирование клауз \texttt{TIE}. Для заполнения списка отображаемых массивов используется сохранённая информация об обращениях к массивам с прохода LOOP\_ANALYZER\_NODIST;
\end{itemize}
В результате получается множество созданных директив \textit{CreatedDirective}, содержащее только директивы распараллеливания на общую память.
В результате получается множество созданных директив \texttt{CreatedDirective}, содержащее только директивы распараллеливания на общую память.
Завершает распараллеливание на общую память вставка директив путём вызова кода прохода INSERT\_PARALLEL\_DIRS с передачей множества созданных директив \texttt{CreatedDirective}.

View File

@@ -1,6 +1,6 @@
\subsection{Общие сведения и термины из параллельного программирования}
Когда речь идёт о достаточно высокоуровневых технологиях распараллеливания (OpenMP, OpenACC, DVM), говорят о распараллеливании витков циклов. На это есть несколько причин:
Когда речь идёт о высокоуровневых технологиях распараллеливания (OpenMP, OpenACC, DVM), говорят о распараллеливании витков циклов. На это есть несколько причин:
\begin{itemize}
\item обычно, большая часть вычислительной работы в программах находится именно в циклах;

View File

@@ -9,7 +9,7 @@
Рассмотрим подробнее две из них, которые будут упомянаться далее в работе, более пристально. Это директивы приватизации и редукции. Директива приватизации, как и все директивы системе SAPFOR, представлена в виде комментария, начинающегося с префикса \texttt{\$SPF}. Далее идёт тело директивы, которое имеет вид \texttt{ANALYSIS (PRIVATE(...))}, где вместо троеточия должен быть указан список приватных переменных (скаляров или массивов) через запятую. Следующий пример демонстрирует использование директивы \texttt{PRIVATE} системы SAPFOR:
\begin{lstlisting}[style=FORT,caption={
пример задания приватного массива B для цикла на строке 3 с помощью директивы системе SAPFOR.
пример задания приватного массива \texttt{B} для цикла на строке 3 с помощью директивы системе SAPFOR.
}]
...
!$SPF ANALYSIS(PRIVATE(B))
@@ -25,9 +25,9 @@
Хотя скаляры и можно объявлять в директиве приватизации, на практике обычно это не используется, потому что в системе SAPFOR при распараллеливании автоматически производится анализ приватных скалярных переменных.
Аналогично устроена директива \texttt{!\$SPF ANALYSIS (REDUCTION(OP(...)))}, задающая редукцию по переменным из списка, стоящем вместо троеточия с бинарной редукционной операцией \texttt{OP}. Далее приведён приведён пример использования этой директивы:
Аналогично устроена директива \texttt{!\$SPF ANALYSIS (REDUCTION(OP(...)))}, задающая редукцию по переменным из списка, стоящем вместо троеточия. \texttt{OP} в директиве задаёт редукционную операцию. Далее приведён приведён пример использования этой директивы:
\begin{lstlisting}[style=FORT,caption={
пример задания редукции по переменной EPS с редукционной операцией взятия максимума.
пример задания редукции по переменной \texttt{EPS} с редукционной операцией взятия максимума.
}]
...
!$SPF ANALYSIS(REDUCTION (MAX(EPS)))

View File

@@ -1,16 +1,15 @@
\subsection{Второй этап -- реализация}
Таким образом, новый режим работы был оформлен как отдельных проход. По аналогии этот проход был назван INSERT\_PARALLEL\_DIRS\_NODIST, что подчёркивает отсутвие построения распределения данных. Поскольку INSERT\_PARALLEL\_DIRS осуществляет только вставку созданных заранее директив, его функционал менять не пришлось, поэтому внутри INSERT\_PARALLEL\_DIRS\_NODIST вызывается код прохода INSERT\_PARALLEL\_DIRS.
Новый режим работы распараллеливания на общую память был оформлен как отдельных проход. По аналогии этот проход был назван \\ 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\_PARALLEL\_DIRS, подверглось правкам. Оттуда полностью убран код, отвечающий за директивы распределения данных. Также изменён код для конструирования параллельных директив: убрано создание приставки ON в директиве и клауз удалённого доступа к данным, среди которых \texttt{SHADOW\_RENEW} и \texttt{REMOTE\_ACCESS}. Также был добавлен алгоритм заполнения клауз \texttt{TIE}. Оказалось, что новая версия CREATE\_PARALLEL\_DIRS стала намного компактнее и было решено не создавать для неё отдельный проход и сделать частью INSERT\_PARALLEL\_DIRS\_NODIST.
Также, новый проход не унаследовал зависимости от проходов \\ CREATE\_TEMPLATE\_LINKS и LOOP\_ANALYZER\_DATA\_DIST\_S*, посколько они отвечали только за распределение данных.
Ещё пришлось переработать проход LOOP\_ANALYZER\_COMP\_DIST. Он отвечал за анализ обращений к массивам внутри цикла и распараллеливание, на основе этой информации. Главное что пришлось изменить -- убрать часть с выбором массива, согласно которому распределяются витки цикла. Преобразованный проход получил название LOOP\_ANALYZER\_NODIST.
Проход LOOP\_ANALYZER\_COMP\_DIST пришлось переработать. Он отвечал за анализ обращений к массивам внутри цикла и распараллеливание на основе этой информации. Преобразованный проход получил название LOOP\_ANALYZER\_NODIST.
В результате схема зависимостей изменилась следующим образом:
\pagebreak
\begin{figure}[h]
\centering
\includegraphics[scale=0.5]{src/assets/pass_deps_nodist_0.png}

View File

@@ -18,7 +18,7 @@
Путём чтения исходного кода, документации и общения с авторами системы все эти вопросы были разрешены. Далее излагаются основные полученные сведения.
Как уже упомяналось ранее, структурно система SAPFOR состоит из множества алгоритмов, которые логически разделены на отдельные блоки -- проходы. Каждый проход выполняет свою функцию и может зависеть от других проходов. При запуске прохода перед ним запускаются все проходы, от которых он зависит непосредственно или транзитивно, при чём каждый проход запускается не больше одного раза. Таким образом в системе выстраивается дерево зависимостей проходов. На данный момент в системе их уже больше сотни.
Как уже упомяналось ранее, структурно система SAPFOR состоит из множества алгоритмов, которые логически разделены на отдельные блоки -- проходы. Каждый проход выполняет свою функцию и может зависеть от других проходов. При запуске прохода перед ним запускаются все проходы, от которых он зависит непосредственно или транзитивно, при чём каждый проход запускается не больше одного раза. Таким образом в системе выстраивается дерево зависимостей проходов.
Конечным проходом при распараллеливании с распределением данных явлется проход с названием INSERT\_PARALLEL\_DIRS, который производит вставку созданных директив в код. Главные его зависимости -- проход CREATE\_PARALLEL\_DIRS создания параллельных директив (без вставки) по полученной информации из анализа циклов. Анализ циклов производится следующей группой проходов:
@@ -32,7 +32,7 @@
\item LOOP\_ANALYZER\_DATA\_DIST\_S0;
\end{itemize}
Они заполняют структуры, описывающие циклы, анализируют обращения к массивам внутри циклов, отображают обращения к массивам на циклы. Вместе с этим происходит вызов прохода CREATE\_TEMPLATE\_LINKS, который создаёт структуру данных, позволяющую строить распределение данных. Эта структура данных называется \textit{графом измерений массивов}. Кроме этого в работе распараллеливания участвует ещё множество других проходов (всего порядка семидесяти), которые не относятся к распараллеливанию напрямую. Эти проходы не касаются распределения данных, поэтому они пристально не рассматривались. Часть дерева зависимостей прохода вставки параллельных директив изображена на Рис. \ref{fig:distr-alg}.
Они заполняют структуры, описывающие циклы, анализируют обращения к массивам внутри циклов, отображают обращения к массивам на циклы. Также они создают и заполняют структуру данных, позволяющую строить распределение данных -- \textit{граф измерений массивов}. Вместе с этим происходит вызов прохода CREATE\_TEMPLATE\_LINKS, который по построенному графу создаёт схему распределения данных. До них в работает ещё множество других проходов (всего порядка семидесяти), которые не относятся к распараллеливанию напрямую. Эти проходы не касаются распределения данных, поэтому они пристально не рассматривались. Часть дерева зависимостей прохода вставки параллельных директив изображена на Рис. \ref{fig:distr-alg}:
\pagebreak
@@ -43,4 +43,4 @@
\label{fig:distr-alg}
\end{figure}
Таким образом, было установлено, что для успешной реализации распараллеливания на общую память необходимо и достаточно внести изменения в эти семь проходов, а от прохода CREATE\_TEMPLATE\_LINKS стоит полностью отказаться в новом режиме.
Таким образом, было установлено, что для успешной реализации распараллеливания на общую память необходимо и достаточно внести изменения в эти семь проходов.

View File

@@ -6,6 +6,4 @@
\input{src/sections/solution/impl}
\input{src/sections/solution/testing}
% \input{src/sections/solution/issues}
\todo{Описание реализованных алгоритмов можно сюда добавить, прям по проходам}
% \input{src/sections/solution/issues}

View File

@@ -2,9 +2,9 @@
Поскольку работа ведётся с исходным кодом фортран-программ, множество возможных вариантов входных программ слишком велико, чтобы предусмотреть абсолютно все ситуации на этапе реализации. Из-за этого было необходимо произвести тщательное тестирование, чтобы выявить основные случаи некорректного поведения системы SAPFOR.
Было проведено тщательное тестирование добавленного функционала на предмет корректности. Оно проводилось как на небольших модельных примерах, так и на больших примерах практически используемых программ. Суммарно за всё тестирование было обнаружено порядка тридцати различных примеров некорректного поведения добавленного режима. Далее описаны наиболее содержательных из найденных ошибок и то, как они были исправлены.
Тестирование проводилось как на небольших модельных примерах, так и на больших примерах практически используемых программ. Суммарно за всё тестирование было обнаружено порядка тридцати различных примеров некорректного поведения добавленного режима. Далее описаны наиболее содержательные из найденных ошибок и то, как они были исправлены.
Первая из них касалась обработки приватных массивов. При распределении данных в DVM-системе запрещается распределять массивы, которые являются приватными хотябы для одного цикла. Поэтому в системе SAPFOR такие массивы не отображаются на циклы при построении схемы распределения данных. При распараллеливании на общую память DVM система допускает использование одного массива в качестве приватного и неприватного для разных циклов. Поэтому для режима распараллеливания на общую память было добавлено отображение на цикл всех неприватных для него массивов (в частности, это нужно для заполнения клаузы TIE). Из-за этого пришлось внести правки в проход LOOP\_ANALYZER\_NODIST.
Первая из них касалась обработки приватных массивов. При распределении данных в DVM-системе запрещается распределять массивы, которые являются приватными хотябы для одного цикла. Поэтому в системе SAPFOR такие массивы не отображаются на циклы при построении схемы распределения данных. При распараллеливании на общую память DVM система допускает использование одного массива в качестве приватного и неприватного для разных циклов. Поэтому для режима распараллеливания на общую память было добавлено отображение на цикл всех неприватных для него массивов (в частности, это нужно для заполнения клаузы \texttt{TIE}). Это привело к правкам в проходе LOOP\_ANALYZER\_NODIST.
Ещё одна проблема связана с обработкой передаваемых в процедуры секций массивов. Дело в том, что в DVM-системе запрещено использование в разных циклах пересекающихся по памяти различных секций массивов. Рассмотрим следующий пример:
@@ -36,7 +36,7 @@ end
В нём нём есть два параллельных цикла (строки 8 и 19). Один из них использует полный массив A (который объявлен на строке 3). Другой же использует секцию массива A, которая содержит его первые 50 элементов (объявление на строке 15). Запуск этого примера приводит к ошибке выполнения системы DVM. При этом если бы в подпрограмме \texttt{foo} было объявлено, что массив имеет размер 100 (то есть фактически передавался бы массив целиком), то ошибки бы не было.
В случае аналогичного распараллеливания с распределением, ошибок выполнения DVM не возникает. Из-за этого в цепь проходов распараллеливания на общую память был добавлен новый проход, который получил название SELECT\_ARRAY\_DIM\_CONF. Он запускается после анализа циклов и фильтрует параллельные циклы так, чтобы в них не было пересечений по памяти используемых массивов. При обнаружение конфликтной группы циклов, выбирается один из них, который будет распараллелен, а другие к распараллеливанию не допускаются.
В случае аналогичного распараллеливания с распределением, ошибок выполнения DVM не возникает. Из-за этого в цепь проходов распараллеливания на общую память был добавлен новый проход, который получил название SELECT\_ARRAY\_DIM\_CONF. Он запускается после анализа циклов и фильтрует параллельные циклы так, чтобы в них не было пересечений по памяти используемых массивов.
Таким образом схема проходов нового режима получила окончательный вид, представленный на Рис. \ref{fig:deps-final}:

View File

@@ -1,21 +1,21 @@
\subsection{Постановка задачи, определение целей работы}
Так возникает задача добавления в систему SAPFOR дополнительного сценария работы -- распараллеливания фортран-программ без построения схемы распределения данных и с использованием директив PARALLEL без клаузы ON.
Так возникает задача добавления в систему SAPFOR дополнительного сценария работы -- распараллеливания фортран-программ без построения схемы распределения данных и с использованием директив \texttt{PARALLEL} без клаузы \texttt{ON}.
Требуется, чтобы новый режим мог обходить ограничения, накладываемые распределением данных, тем самым расширяя класс распараллеливаемых программ на общую память по сравнению со стандартным распараллеливанием на кластер. В частности, вставляемые директивы должны корректно описывать все данные, используемые в цикле, их область хранения в памяти и зависимости типа ACROSS, если они есть.
Также от добавляемого функционала естественно потребовать его \textit{корректность}: при условии, если входная программа корректная, то система SAPFOR должна выдавать правильную параллельную программу, которая должен успешно компилироваться и выполняться.
Помимо этого, результирующее распараллеливание должно быть эффективным, то есть давать приемлемый прирост производительности за счёт многопоточного выполнения: не замедлять программу существенно в худших случаях и получать распараллеливание, конкурирующие с ручным в лучших случаях. В это требование дополнительно входит расстановка оптимизирующих клауз TIE в директивы PARALLEL везде, где это возможно.
Помимо этого, результирующее распараллеливание должно быть эффективным, то есть давать приемлемый прирост производительности за счёт многопоточного выполнения: не замедлять программу существенно в худших случаях и получать распараллеливание, конкурирующие с ручным в лучших случаях. В это требование дополнительно входит расстановка оптимизирующих клауз \texttt{TIE} в директивы \texttt{PARALLEL} везде, где это возможно.
Поскольку работа ведётся в рамках доработки системы SAPFOR, решение должно быть в неё интегрировано должным образом:
\begin{itemize}
\item в системе SAPFOR каждое преобразование оформляется в виде последовательности \textit{проходов} -- алгоритмов, которые логически разделены на блоки. Поэтому новый функционал должен быть реализован в виде нового прохода (или в виде последовательности новых проходов);
\item новый режим распараллеливания, должен учитывать и правильно обрабатывать директивы системы SAPFOR;
\item новый режим распараллеливания должен учитывать и правильно обрабатывать директивы системы SAPFOR;
\item должна быть добавлена возможность вызова это режима через диалоговую графическую оболочку;
\item должна быть добавлена возможность вызова этого режима через диалоговую графическую оболочку;
\item вместе с самим распараллеливанием должен быть добавлен функционал анализа входного кода, который выдавал бы информацию по распараллеливанию без фактической вставки директив. Аналогичный анализ в системе SAPFOR есть и для режима распараллеливания на кластер. Он служит для выявления проблем при автоматизированном распараллеливании;
\end{itemize}

View File

@@ -3,13 +3,13 @@
Как описывалось во введении, распараллеливание в модели DVM происходит при помощи специальных директив. При привычном распараллеливании с распределением данных, в основном, используются следующие директивы:
\begin{itemize}
\item DISTRIBUTE -- предназначена для распределения элементов массивов по узлам
\item \texttt{DISTRIBUTE} -- предназначена для распределения элементов массивов по узлам;
\item ALIGN -- отображает элементы нескольких массивов на заданный распределённый массив и распределяет их на соответствующие узлы
\item \texttt{ALIGN} -- отображает элементы нескольких массивов на заданный распределённый массив и распределяет их на соответствующие узлы;
\item REGION -- определяет область кода, которую следует выполнять параллельно
\item \texttt{REGION} -- определяет область кода, которую следует выполнять параллельно;
\item PARALLEL ... ON -- определяет цикл, витки которого следует выполнять параллельно, при этом задавая отображение пространства витков цикла на распределённый массив.
\item \texttt{PARALLEL ... ON} -- определяет цикл, витки которого следует выполнять параллельно, при этом задавая отображение пространства витков цикла на распределённый массив;
\end{itemize}
@@ -32,12 +32,12 @@
...
\end{lstlisting}
Чтобы дать пользователю возможность распараллеливать программы на общую память, в синтаксис языка DVM-системы была добавлена новая форма директивы PARALLEL для распараллеливания без распределения данных.
Чтобы дать пользователю возможность распараллеливать программы на общую память, в синтаксис языка DVM-системы была добавлена новая форма директивы \texttt{PARALLEL} для распараллеливания без распределения данных.
Новый вариант директивы PARALLEL отличается от исходного тем, что в ней отсутствует клауза ON. При использовании таких директив не надо указывать распределённые массивы. Сами директивы распределения данных также не нужны в таких программах. Более того, в таких директивах PARALLEL не должны присутствовать клаузы доступа к удалённым данных, такие как SHADOW\_RENEW, SHADOW\_COMPUTE и REMOTE\_ACCESS.
Новый вариант директивы \texttt{PARALLEL} отличается от исходного тем, что в ней отсутствует клауза \texttt{ON}. При использовании таких директив не надо указывать распределённые массивы. Сами директивы распределения данных также не нужны в таких программах. Более того, в таких директивах \texttt{PARALLEL} не должны присутствовать клаузы доступа к удалённым данных, такие как \texttt{SHADOW\_RENEW}, \texttt{SHADOW\_COMPUTE} и \texttt{REMOTE\_ACCESS}.
\begin{lstlisting}[style=FORT,caption={
пример распарараллеливания гнезда циклов на общую память. Здесь не должно быть ни директив распределения данных, ни клаузы ON отображения витков цикла на массив.
пример распарараллеливания гнезда циклов на общую память.
}]
...
!DVM$ REGION
@@ -52,4 +52,4 @@
...
\end{lstlisting}
Так же в таком варианте директивы PARALLEL может присутствовать клауза TIE, сопоставляющая итерации цикла с массивом, которая используется в DVM-системе для улучшения производительности выходного исполняемого кода.
Также в таком варианте директивы \texttt{PARALLEL} может присутствовать клауза \texttt{TIE}, сопоставляющая итерации цикла с массивом. Она используется в DVM-системе для улучшения производительности выходного исполняемого кода.

View File

@@ -2,4 +2,4 @@
Исследования по теме автоматизированного распараллеливания программ ведутся достаточно давно. На данный момент существует не так много широко используемых средств, позволяющих получать параллельный код. Среди средств, которые в той или иной степени помогают в процессе распараллеливания программ можно выделить следующие: Polaris, CAPO, WPP, SUIF, VAST/Parallel, OSCAR, ParallelWare, Intel Parallel Studio XE.
Однако, открытых реализаций алгоритмов распараллеливания почти нет, поэтому за основу решения был взят уже существующие в системе SAPFOR режим распараллеливания с распределением данных. Этот подход не только помог учесть спицифику языков фортран и DVM, но и позволил минимизировать объём внесённых в систему SAPFOR изменений.
Однако, открытых реализаций алгоритмов распараллеливания почти нет, поэтому за основу решения был взят уже существующий в системе SAPFOR режим распараллеливания с распределением данных. Этот подход не только помог учесть спицифику языков фортран и DVM, но и позволил минимизировать объём внесённых в систему SAPFOR изменений.

View File

@@ -1,7 +1,3 @@
\subsection{Мотивация поддержки режима распараллеливания на общую память в системе SAPFOR}
Поскольку система SAPFOR не способна проанализировать все тонкости логики работы программы, процесс построения оптимальной схемы распределения данных затрудняется. Поэтому аналогичная потребность в функционале распараллеливания на общую память возникает и в системе SAPFOR. Таким образом, реализация нового режима работы системы SAPFOR для распараллеливания на общую память стала для данной работы основной целью, которая детально описывается в последующих параграфах.
% Существующий режим распараллеливания основан на построении графа измерений массивов. Это граф, в котором вершинами являются измерения массивов, а дуги представляют собой информацию о совместном использовании элементов массива внутри отдельной итерации цикла. После этого по определённым правилам дуги взвешиваются и строится подграф, минимизирующий суммарный вес не вошедших в него дуг. По этому подграфу в результате строится распределение данных, и чем меньше суммарный вес не вошедших дуг, тем схема оптимальнее с точки зрения эффективности выполнения параллельной программы. Поэтому, в программах, где нет оптимального решения этой подзадачи, схема распределения строится плохо, возникает много обращений к данным с удалённых узлов и полученная программа получается неэффективной.
% Таким образом, возникает потребность в новом функционале системы SAPFOR, позволяющем распараллеливать программы на общую память. Разработка и реализация такого режима работы системы SAPFOR и стали главной целью данной работы.
Поскольку система SAPFOR не способна проанализировать все тонкости логики работы программы, процесс построения оптимальной схемы распределения данных затрудняется. Поэтому аналогичная потребность в функционале распараллеливания на общую память возникает и в системе SAPFOR. Таким образом, реализация нового режима работы системы SAPFOR для распараллеливания на общую память стала для данной работы основной целью, которая детально описывается в последующих параграфах.

View File

@@ -1,6 +1,6 @@
\section{Распараллеливание на общую память}
При написании параллельных DVMH-программ пользователь решает две задачи: он должен найти оптимальный способ распределения данных и обозначить циклы, которые могут выполняться параллельно. На практике нередко возникают ситуации, когда для рассматриваемой программы решить первую из этих задачу слишком сложно или невозможно, но вторая задача решается успешно, то есть программа обладает хорошим потенциалом для распараллеливания.
При написании параллельных DVMH-программ пользователь решает две задачи: он должен найти оптимальный способ распределения данных и обозначить циклы, которые могут выполняться параллельно. На практике нередко возникают ситуации, когда для рассматриваемой программы решить первую задачу трудно или невозможно, но вторая задача решается успешно, то есть программа обладает хорошим потенциалом для распараллеливания.
Основной проблемой, возникающей при попытке построить схему распределения данных, является то, что разные циклы для их распараллеливания могут требовать разных, конфликтующих, схем распределения данных. При распараллеливании практически значимых программ, в силу их объёмности, такие конфликты возникают повсеместно. Эта проблема подробно рассматривается в \cite{par-reg}.

View File

@@ -6,9 +6,9 @@
В некоторых местах распараллеливание циклов осложнено наличием в теле цикла вызовов процедур. Чтобы распараллелить такие циклы, можно попытаться подставить тело процедуры вместо её вызова. Так как в диалоговой оболочке есть проходы анализа кода и подстановки процедур, можно также без больших усилий найти циклы, которые не распараллеливаются из-за вызовов процедур и произвести подстановку в нужных местах.
Нередко в коде встречаются приватные и редукционные массивы. Так как система SAPFOR в данный момент не поддерживает автоматическое обнаружение таких массивов, их приходится вручную указывать при помощи директив SPF ANALYSIS (PRIVATE) и SPF ANALYSIS (REDUCTION).
Нередко в коде встречаются приватные и редукционные массивы. Так как система SAPFOR в данный момент не поддерживает автоматическое обнаружение таких массивов, их приходится вручную указывать при помощи директив \texttt{!\$SPF ANALYSIS (PRIVATE)} и \texttt{!\$SPF ANALYSIS (REDUCTION)}.
Отдельного внимания потребовала программа LU. Основная вычислительная нагрузка программы приходится на алгоритм SSOR (метод симмтричной последовательной верхней релаксации). Он представляет собой пару гнёзд циклов глубины два. Рассмотрим первое из этих гнёзд, так как второе распараллеливается полностью аналогично. Возможности параллельного выполнения витков этого цикла мешает только зависимость по данным массива \texttt{rsd}: каждая итерация с номером \textit{(i, j)} использует элементы, которые вычисляются витками \textit{(i - 1, j)}, \textit{(i, j - 1)}. В такой ситуации витки имеют частичный порядок и некоторые группы витков могут выполняться параллельно. В пакете есть три реализации такого распараллеливания:
Отдельного внимания потребовала программа 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};
@@ -25,7 +25,7 @@
\label{fig:hp}
\end{figure}
В силу того, что SAPFOR не способен проанализировать логику синхронизаций и зависимости между разными гиперплоскостями, первый и третий варинты распараллелить не удалось. Однако во втором варианте система SAPFOR успешно распознала зависимость по данным и распараллелила цикл с использованием клаузы ACROSS:
В силу того, что SAPFOR не способен проанализировать логику синхронизаций и зависимости между разными гиперплоскостями, первый и третий варинты распараллелить не удалось. Однако во втором варианте система SAPFOR успешно распознала зависимость по данным и распараллелила цикл с использованием клаузы \texttt{ACROSS}:
\begin{lstlisting}[style=FORT,caption={
пример вставленной клаузы ACROSS, задающую зависимость размера 1 по последним двум измерениям массива \texttt{rsd}. В теле цикла происходит чтение элементов массива \texttt{rsd(*,*,j-1,k)}, \texttt{rsd(*,*,j,k-1)}, \texttt{rsd(*,*,j-1,k-1)} и запись в элементы массива \texttt{rsd(*,*,j,k)}.

View File

@@ -32,7 +32,7 @@
\item время работы DVM-версий и OpenMP-версий на различном количестве используемых потоков также отличается несущественно, с ростом количества потоков это различие уменьшается;
\item в целом, есть примеры, на которых DVM-версии быстрее, чем версии на OpenMP и наоборот;
\item есть примеры, на которых DVM-версии быстрее, чем версии на OpenMP и наоборот;
\end{itemize}
@@ -40,7 +40,7 @@
В процессе запусков возникли проблемы с тестом FT. Параллельная версия этого теста содержит приватные массивы больших размеров, что приводило к переполнению памяти видеокарты. Поэтому было принято решение отказаться от запуска программы FT на ускорителях.
Результаты представлены на Рис. \ref{fig:gpu}:
Результаты остальных запусков представлены на Рис. \ref{fig:gpu}:
\pagebreak
\begin{figure}[hbt!]
\centering

View File

@@ -1,7 +1,7 @@
\section{Исследование эффективности}
\label{sec:benchmark}
Немаловажную роль в оценке качества выполненной работы играет тестирование на предмет эффективности получаемого распараллеливания. Для этих целей был выбран специальный пакет программ, который широко используется в сфере исследования эффективности распараллеливания -- пакет \textit{NAS Parallel Benchmarks} \cite{npb}, который далее будет детально рассмотрен.
Немаловажную роль в оценке качества выполненной работы играет тестирование на предмет эффективности получаемого распараллеливания. Для этих целей был выбран специальный пакет программ, который широко используется в сфере исследования эффективности распараллеливания -- пакет \textit{NAS Parallel Benchmarks} \cite{npb}.
\input{src/sections/tests/npb}
\input{src/sections/tests/parallelizing}