.
Начертательная геометрия Геометрическое черчение Инженерная графика Интегралы Математический анализ Матрицы Производные Векторная алгебра

 

6.3. Преобразование последовательных программ
в последовательно-параллельные

Задача распараллеливания. В любом полном рассмотрении вопросов параллельного программирования должны быть представлены способы получения параллельной программы из обычной алгоритмической записи, которая несет в себе след чисто последовательной логики рассуждений, так как любые вычисления, проводимые вручную и автоматически, выполнялись последовательно. Однако оказывается, что любой реальный процесс при детальном его рассмотрении выполняется параллельно. И чем внимательнее и детальнее мы постараемся его описать, тем больше это описание будет приближаться к параллельной форме. Следовательно, задача состоит в том, чтобы с помощью каких-то понятий научиться достаточно просто и полно описывать естественные параллельные процессы.

Сложность задачи распараллеливания во многом определяется языком, на котором записан исходный алгоритм. Наиболее просто это делать, если язык не содержит циклических структур. Примером таких языков можно назвать языки "геометрического описания деталей со сложной объемной конфигурацией". Это язык, в котором предложение – последовательность директив.

Как правило, основное время выполнения программ на обычных языках связано с реализацией циклов. Поэтому важной задачей является распараллеливание циклов.

Как указывалось выше, некоторые языки программирования имеют средства для описания параллелизма. Однако все параллельные фрагменты программы должны быть указаны явным образом. Более того, должна быть указана последовательность их выполнения, организована передача необходимых управлений и т. д. [an error occurred while processing this directive]

При использовании языка PL/1, например, программист должен:

·  выделить и пометить независимые фрагменты программы (с помощью операторов CALL и TASK, например);

·  обеспечить синхронизацию при выполнении фрагментов (используя, скажем, оператор DELAY);

·  осуществить взаимное управление фрагментами (операторы COMPLETE, WAIT, RETURN).

Следовательно, все трудности по организации параллельной обработки ложатся на программиста, так как он, по-существу, должен предварительно написать весь "сценарий" прохождения задачи через компьютер в параллельном режиме.

На разработку математического и программного обеспечения, согласно различным литературным источникам, тратится от 70 до 90 % всех затрат на создание ВС. Это одна из основных причин, почему необходимо эффективно использовать накопившееся обеспечение для однопроцессорных ЭВМ при переходе к МВС. Математическое и программное обеспечение следует адаптировать для новых ВС. Таким образом, рождается актуальная проблема – преобразование последовательных программ в последовательно-парал-лельные. Но так как эта работа необычайно трудоемка, ее следует автоматизировать. Решение указанной проблемы позволяет, во-первых, высвободить большие трудовые ресурсы, во-вторых, использовать накопленный за долгие годы развития ЭВМ информационно-программный багаж без ручного перепрограммирования и, в-третьих, осуществить переход на многопроцессорные системы с меньшими затратами труда и времени.

Распараллеливание программ можно осуществлять как на уровне отдельных задач, так и на уровне отдельных процедур, операторов, операций и микроопераций. Целесообразность преобразования на указанных уровнях должна решаться в каждом отдельном случае в зависимости от структуры ВС, типа программы и цели, которая ставится при ее решении.

Рассмотрим общую схему преобразования последовательных программ в последовательно-параллельные. Организовать параллельные вычисления можно с помощью некоторой формальной процедуры, выполняемой автоматически над каждой программой, состоящей из последовательности операторов обычного ЯП. Эта процедура позволяет избавить программиста от анализа собственной программы и помогает выявить ее внутренний параллелизм. Выявление параллелизма заключается в разбиении всех операторов программ на два класса: тех, которые могут выполняться параллельно, и тех, которые должны быть завершены прежде, чем следующие последовательности операторов начнут выполняться.

Такой подход к распараллеливанию основывается на представлении программы в виде ориентированного графа G, множество вершин которого V = {v1, v2, ..., vn} соответствует либо отдельным операторам программы, либо совокупности этих операторов (типа подпрограмм в языке ФОРТРАН либо процедур в языке АЛГОЛ или ПАСКАЛЬ). Множество направленных дуг U = {u1, u2, ..., um} соответствует возможным переходам между операторами программы.

Из теории графов известно, что ориентированный граф полностью описывается соответствующей матрицей смежности такой, что ее элемент

 

 

ì 1, если существует дуга (ui,uj);

Сij =

í

 

î 0, если такой дуги нет.


Пусть рассматриваемый граф G является произвольным циклическим графом с одной входной и одной выходной вершинами. Следуя определению сильносвязного подграфа, будем идентифицировать его с таким фрагментом в программе, из любого оператора которого существует переход в любой другой оператор, принадлежащий этому же фрагменту. Например, сильносвязным подграфом будут фрагменты 2, 3, 4 (рис. 6.3).

 

 

 

Рис. 6.3. Сильносвязный подграф

 

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

Итак, ставится задача – преобразовать алгоритм решения задачи, заданный последовательной программой, для параллельной его реализации на многопроцессорной вычислительной системе.

Для преобразования программы из одной (последовательной) формы в другую (последовательно-параллельную) мы используем ее интерпретацию в виде орграфа. Вообще говоря, идея использовать некоторый "формализм" в качестве посредника для преобразования программ встречалась и раньше в связи с другими задачами. Так, в трансляторе системы АЛЬФА был введен дополнительный проход, во время которого по исходной программе строилась ее модель в виде схемы Лаврова, что позволило обнаруживать и анализировать информационные связи в целях глобальной экономии памяти.

Построим схему алгоритма распараллеливания программ, используя некоторые сведения из теории графов.

 

Схема алгоритма

 

1. Представление исходной программы в виде графа. Этот процесс достаточно подробно изложен выше.

2. Сведение циклического графа к ациклическому. Большое количество вершин графа G приводит к большому порядку матрицы смежности C. Для уменьшения порядка матрицы произведем сжатие линейных участков программы в отдельные обобщенные операторы, т. е. выделим в исходном графе G линейные подграфы и поставим им в соответствие одну обобщенную вершину графа, не нарушая при этом ни одного из существующих ориентированных циклов. Таким образом, из исходного графа G мы получаем граф G¢. Затем в графе G¢ выделим множество сильносвязных подграфов. Каждый сильносвязный подграф заменим отдельной вершиной. После выполнения указанных действий в общем случае циклический граф G превращается в сжатый ациклический граф G¢¢, представляющий собой модель исходной программы. Вершинами графа G¢¢ будут фрагменты исходной программы в виде линейных участков и сильносвязных областей.

3. Наложение информационных связей, заданных между операторами программы, на связи возможных переходов. До этого момента информационно-логические связи, заданные между операторами программы, не претерпевали существенных изменений. Преобразуем их, учитывая взаимосвязи укрупненных вершин графа G¢¢.

Если в графе G¢¢ существует переход от вершины vi к вершине vj, то это совсем не означает, что начало выполнения оператора, соответствующего вершине vj, должно тут же следовать за окончанием оператора, соответствующего вершине vi. Однако, если результат оператора vi является аргументом оператора vj, то в данном случае выполнение оператора vj не может начаться раньше, чем окончится выполнение оператора vi.

После анализа входов и выходов для всех компонент приведенного графа G¢¢ производится наложение информационных связей на связи возможных переходов, т. е. на связи, представленные в матрице смежности графа G¢¢. Для анализа входов и выходов всех компонент графа G¢¢ необходимо составить матрицу H информационной зависимости, элементы которой hij принимают соответственно значения 0 или 1. При этом

 

ì 1, если j-й оператор зависит от значений переменных,

hij =

í  полученных в i-м операторе;

 

î 0, в противном случае.

Чтобы практически построить матрицу H, для каждого оператора программы определяем множество изменяемых и множество упоминаемых переменных. Затем берем первую изменяемую переменную из первого оператора программы и просматриваем все остальные операторы программы на предмет присутствия этой переменной в упоминаемых множествах этих операторов до тех пор, пока исследуемая переменная не встретится в изменяемом множестве одного из операторов. Если эта переменная присутствует в упоминаемом множестве одного из операторов, то в матрицу информационной зависимости на место пересечения строки с номером, равным номеру оператора с проверяемой переменной, и столбца с номером, равным номеру оператора, в упоминаемом множестве которого присутствует проверяемая переменная, заносим единицу.

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

В результате выполнения этого этапа граф G¢¢ преобразуется в граф , в матрице смежности   которого учтены как информационные связи между операторами, так и связи возможных переходов.

4. Распределение вершин графа по уравнениям готовности. На данном этапе исходя из графа   и матрицы   строится так называемое Е-разделение, т. е. выделяются классы E1, E2, E3, ... , En операторов и устанавливается между ними отношение предшествования. Е-разделение определяет класс операторов, параллельное выполнение которых должно быть завершено прежде, чем начнут выполняться операторы следующего класса. По выполнению этого этапа все операторы (вершины графа ) будут распределены по уровням готовности.

5. Формирование ветвей решения. На пятом этапе анализируются компоненты каждого уровня. Если анализируемая вершина уровня представляет собой сильносвязный подграф, то в нем выделяются элементарные циклы, компонентами которых являются отдельные линейные фрагменты. Если же исследуемая вершина отображает сжатый линейный участок программы, то анализируются информационные связи внутри этого линейного участка.

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

 

На главную