Научная статья на тему 'Алгоритмы конструирования асинхронных программ заданной степени непроцедурности методом группировки'

Алгоритмы конструирования асинхронных программ заданной степени непроцедурности методом группировки Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
226
41
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
СБОРОЧНАЯ ТЕХНОЛОГИЯ ПРОГРАММИРОВАНИЯ / АСИНХРОННЫЕ ЯЗЫКИ И СИСТЕМЫ ПРОГРАММИРОВАНИЯ / ДИНАМИЧЕСКИЕ СВОЙСТВА ПРОГРАММ / АВТОМАТИЗАЦИЯ ПАРАЛЛЕЛЬНОЙ РЕАЛИЗАЦИИ ЧИСЛЕННЫХ МОДЕЛЕЙ / DYNAMIC PROGRAM'S PROPERTIES / ASSEMBLY TECHNOLOGY OF PROGRAMMING / ASYNCHRONOUS LANGUAGES AND PROGRAMMING SYSTEMS / AUTOMATION OF THE PARALLEL REALIZATION OF THE NUMERIC MODELS

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Арыков Сергей Борисович, Малышкин Виктор Эммануилович

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

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

ALGORITHMS OF ASYNCHRONOUS PROGRAMS CONSTRUCTION WITH PREDEFINED LEVEL OF NON-PROCEDURALITY BASED ON GROUPING METHOD

Problems of asynchronous programs development for parallel implementation of the large scale numerical models are considered. Assembly technology is proposed to be used in order to support program assembling in the asynchronous programming system. This provides automatic implementation of dynamic properties (setting up on the available resources, dynamic load balancing, dynamic resource distribution, etc.) of application program. Special version of asynchronous model of computation is proposed which allows in the wide range to vary the overheads of the program execution with the help of computation fragments grouping. Asynchronous parallel programming system Aspect is considered which implements some principles of the assembly technology on the symmetric multiprocessor or multicores computers.

Текст научной работы на тему «Алгоритмы конструирования асинхронных программ заданной степени непроцедурности методом группировки»

УДК 519.685.1

С. Б. Арыков, В. Э. Малышкин

Институт вычислительной математики и математической геофизики СО РАН пр. Акад. Лаврентьева, 6, Новосибирск, 630090, Россия E-mail: [email protected]; [email protected]

АЛГОРИТМЫ КОНСТРУИРОВАНИЯ АСИНХРОННЫХ ПРОГРАММ ЗАДАННОЙ СТЕПЕНИ НЕПРОЦЕДУРНОСТИ МЕТОДОМ ГРУППИРОВКИ

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

Ключевые слова: сборочная технология программирования, асинхронные языки и системы программирования, динамические свойства программ, автоматизация параллельной реализации численных моделей.

Введение

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

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

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

Особенности решения численных задач методом «частицы-в-ячейках»

Рассмотрим особенности параллельной реализации алгоритмов решения больших численных задач на примере использования метода «частицы-в-ячейках» (Particle-In-Cell, далее PIC) в задачах динамики бесстолкновительной плазмы. Обсуждается не PIC, а особенности вычислительной схемы реализации PIC, почему и в описании PIC опущены многие существенные детали метода, которые несущественны для его реализации.

Особенности метода «частицы-в-ячейках». Бесстолкновительная, полностью ионизированная плазма описывается кинетическими уравнениями Власова для функций распределения частиц разных сортов с самосогласованными электромагнитными полями [Григорьев и др., 2004], а также системой уравнений Максвелла для электромагнитных полей. Плотность тока и плотность пространственного заряда определяются как интегралы функций распределения частиц по скоростному пространству.

ISSN 1818-7900. Вестник НГУ. Серия: Информационные технологии. 2009. Том 7, выпуск 1 © С. Б. Арыков, В. Э. Малышкин, 2009

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

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

Процесс моделирования состоит из серии шагов по времени. На каждом шаге:

1) на основе значений электромагнитных полей вычисляется сила, действующая на каждую частицу;

2) вычисляются новые скорости и координаты частиц;

3) на основе новых координат и скоростей частиц вычисляются значения средней плотности тока и заряда в узлах сетки;

4) из полученных значений средней плотности тока и заряда пересчитываются значения электромагнитных полей.

Выделим основные особенности, существенные с точки зрения параллельной реализации PIC-метода:

1) очень большой объем данных и вычислений. Для решения реальных задач с необходимой точностью требуются большие трехмерные сетки (например, 1024 х 1024 х 1024) и миллиарды частиц;

2) вычисления производятся на сетке (или нескольких сетках, сдвинутых относительно друг друга), имеющей регулярную структуру;

3) вычисления локальны. Для вычисления значений электрического и магнитного полей в текущей ячейке необходима информация только из соседних ячеек. Для обработки частиц необходима информация о полях только текущей ячейки.

Проблемы параллельной реализации метода «частицы-в-ячейках». Детальное изложение проблем параллельной реализации PIC-метода можно найти в [Вшивков и др., 1997; Kraeva, Malyshkin, 2001], отметим здесь лишь главный момент.

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

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

1) позволяла настраиваться на доступные ресурсы (количество узлов в мультикомпьюте-ре, количество процессоров / ядер на каждом узле, объем оперативной памяти);

2) умела осуществлять динамическую балансировку загрузки;

3) поддерживала возможность дублирования одного слоя сетки на нескольких узлах для выравнивания нагрузки в случае, если все частицы соберутся в одном или нескольких слоях (о технологии виртуальных слоев см.: [Краева, Малышкин, 1999; Kraeva, Malyshkin, 2001]).

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

Сборочная технология программирования. Одним из подходов, позволяющих переложить задачу обеспечения динамических свойств на систему программирования, является сборочная технология [Kraeva, Malyshkin, 2001].

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

Для метода «частицы-в-ячейках» естественным атомарным фрагментом является ячейка пространства моделирования. Данными здесь являются значения электромагнитных полей в узлах и частицы внутри ячейки, а вычисления определяются алгоритмом моделирования. Из ячеек конструируются минимальные фрагменты (например, строка, столбец или слой), из которых собирается все пространство моделирования.

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

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

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

В качестве модели вычислений для фрагментированных программ наиболее подходящей является асинхронная модель [Котов, Нариньяни, 1966; Котов, 1972; Котов, 1980], поскольку она:

1) представляет программу в виде множества Л-блоков, что близко к представлению в виде множества фрагментов;

2) позволяет исполнять Л-блок сразу после того, как готовы его входные данные, т. е. поддерживает очередь готовых фрагментов заполненной;

3) при добавлении новых ограничений в Л-программы (явных или неявных) наблюдается полезная «монотонность» в уменьшении недетерминизма исполнения, что согласуется с укрупнением размеров фрагментов в сборочной технологии.

Асинхронная модель вычислений

Базовая асинхронная модель. Асинхронная модель вычислений впервые была предложена достаточно давно - в середине 60-х гг. В наиболее общем виде ее можно описать следующим образом.

Лсинхронная программа (или Л-программа) - это конечное множество Л-блоков, определенных над информационной IM и управляющей CM памятями. Память состоит из переменных с неразрушающим чтением и записью, стирающей предыдущее содержимое переменной. Информационная память используется для хранения данных решаемой задачи, а управляющая - для организации управления в программе. Каждый Л-блок Л представляется тройкой (T, O, C), где T - спусковая функция (или триггер-функция), представляющая собой некоторый предикат над CM; O - операция над IM, вычисляющая по входным параметрам in(4) значения выходных параметров out(A); C - управляющий оператор, изменяющий значение управляющей памяти и организующий управление в программе.

Вычисления по асинхронной программе организуются следующим образом.

1. Для всех Л-блоков вычисляются их триггер-функции. Л-блок с истинным значением триггер-функции объявляется готовым к исполнению. Формируется множество готовых к исполнению Л-блоков.

2. Выполняется некоторое подмножество готовых к исполнению Л-блоков. Выполнение Л-блока состоит в вычислении его операции и управляющего оператора. После завершения выполнения Л-блоков переходим на шаг 1.

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

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

1. Позволяет сохранять весь присущий задаче естественный параллелизм (представлять программу в максимально непроцедурной форме).

2. Благодаря механизму спусковых функций, который лишь разрешает, а не предписывает исполнение Л-блоков, предоставляет возможность организации гибкого взаимодействия между параллельной программой и вычислительной системой.

3. Полностью отделяет вычисления от управления.

4. Достаточно легко моделирует другие модели вычислений.

5. Для нее разработаны формальные алгоритмы синтеза параллельных программ на основы вычислительных моделей.

Лсинхронная модель с массовыми Л-блоками. В работе [Вальковский, Малышкин, 1988] асинхронная модель получила дальнейшее развитие. Для представления массовых вычислений в нее было введено понятие массового Л-блока. Не вдаваясь в детали, новое определение Л-блока можно сформулировать следующим образом.

Пусть Е = {А1, А2,..., Ат} - конечное множество Л-блоков; N - множество натуральных чисел, О с Е х N. Элемент (А, 7) е О называется 7-м экземпляром А, А е Е (каждый элемент множества Е может иметь несколько экземпляров; количество экземпляров у разных элементов может отличаться). Л-блок А называется простым, если NA = {к |(А, к) е О} - одноэлементное множество, и массовым, если NА содержит более одного элемента. Множество NА называется областью применимости Л-блока Л. Каждому экземпляру Л-блока А в зависимости от номера 7 ставится в соответствие единственное конечное множество входных т(А(7)) и единственное конечное множество выходных ои1(А(7)) переменных.

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

При таком определении Л-блока появляется возможность применять Л-блоки с массивами.

Проблемы организации управления в асинхронной модели вычислений. Рассмотрим проблемы асинхронной модели вычислений с точки зрения ее реализации на мультипроцессоре или многоядерном процессоре. Такой подход представляется оправданным, поскольку большинство современных распределенных вычислительных систем в качестве узла имеют машину с 8МР-архитектурой, а учитывая направления развития микропроцессоров (увеличение количества ядер), эта тенденция будет только возрастать.

Пусть необходимо умножить матрицу А на матрицу В, а результат поместить в матрицу В. Формально решение задачи можно записать в виде следующих формул:

Пример матриц для 7 = 1 ... 4, ] = 1 ... 4, к = 1 ... 4 приведен на рис. 1. Для удобства матрица С показана в разрезе по измерению 7.

Алгоритм умножения матриц допускает очень высокую степень асинхронности исполнения: каждое умножение элемента матрицы А на элемент матрицы В может быть выполнено

с(7,], к) = а(7, к) * Ь(к, j), ^7,]) = с(7, j, 1) + с(7, j, 2) + ... + с(7, j, и).

(1) (2)

независимо. Сложения результатов умножения каждой строки на каждый столбец также могут быть выполнены независимо.

Рис. 1. Результат работы программы умножения матриц по формулам (1) и (2)

С целью сохранения естественного параллелизма алгоритма в асинхронной модели представим его в виде двух массовых Л-блоков: А1 вычисляет матрицу С (каждый экземпляр А1 вычисляет один элемент матрицы С по формуле (1)), а А2 - матрицу В (каждый экземпляр А2 вычисляет один элемент матрицы В по формуле (2)), причем каждый из экземпляров второго Л-блока может быть выполнен только после соответствующих экземпляров (вычисляющих строку матрицы С) первого Л-блока. Из-за высокой степени асинхронности исполнение данной программы потребует больших накладных расходов на организацию управления. Рассмотрим их более внимательно.

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

Расходы на управляющую память. Если каждый управляющий оператор использует хотя бы по одной переменной (например, для управления разрешением запуска Л-блока), то объем памяти, затрачиваемой на организацию вычислений будет сопоставим с объемом памяти, необходимым для хранения данных. В частности, в приведенном примере для выделения по одной переменной для управления каждым Л-блоком необходимо 80 переменных (64 операции умножения плюс 16 редукционных операций суммирования), в то время как под все данные (включая промежуточные матрицы) необходимо 112 переменных, т. е. расходы на управляющую память составляют 71 % от полезного объема данных.

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

Один из подходов к решению данной проблемы заключается в разработке вычислителей, поддерживающих асинхронную модель на аппаратном уровне (например, такая попытка была предпринята в проекте МАРС [Котов, Марчук, 1983]), однако они не получили распространения. Другой подход состоит в том, чтобы подобрать размер (или «вычислительный вес») фрагмента вычислений (гранулы параллелизма) таким образом, чтобы сделать накладные расходы в процентном отношении приемлемыми. В частности, такой подход применяет-

ся в Т-системе [Moskovsky, Roganov, Abramov, 2007]. В простейшем случае (шаблон типа «Map») Т-система умеет агрегировать несколько операций в одну, в остальном же задача подбора оптимального размера фрагмента вычислений (Т-функции в терминах Т-системы) возложена на программиста.

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

Асинхронная модель с группировкой вычислений

Общий подход к организации группировки. Пусть задана некоторая Л-программа. Идея автоматизированного подбора оптимального размера фрагмента вычислений заимствована из сборочной технологии. Исходные экземпляры Л-блоков будем считать атомарными фрагментами вычислений (по аналогии с атомарными фрагментами в сборочной технологии), из которых с помощью объединения нескольких экземпляров в один, более крупный, будем конструировать группы (минимальные фрагменты вычислений). Экземпляры, включенные в одну группу, будем называть элементами этой группы.

Оставляя пока в стороне вопросы объединения в группу триггер-функций экземпляров и операций экземпляров (поскольку они представляют собой «полезные» вычисления и сэкономить на них невозможно), отметим, что механическое объединение управляющих операторов экземпляров в управляющий оператор группы (когда управляющий оператор группы представляет собой последовательность управляющих операторов экземпляров), очевидно, не даст существенного эффекта, так как объем «управляющих» вычислений не сократится.

Чтобы при объединении экземпляров иметь возможность сокращать «управляющие» вычисления, необходимо точно знать, какие вычисления производятся в управляющих операторах. Ни базовая, ни асинхронная модель с массовыми Л-блоками не делают никаких предположений относительно этих вычислений, поэтому для эффективной реализации группировки необходима конкретизация асинхронной модели.

Конкретизация асинхронной модели. Прежде всего, необходимо выбрать способ управления в программе. Наиболее очевидным является подход, при котором каждой входной переменной каждого Л-блока сопоставляется признак готовности этой переменной (например, он используется в [Вальковский, Малышкин, 1988; Лельчук, 1984]). Если признаки готовности всех входных переменных Л-блока истинны, значит, он готов к исполнению. Однако такой подход имеет существенные недостатки. Во-первых, для хранения признаков готовности необходимо дополнительно выделять большой объем памяти, что является неприемлемым для крупных вычислительных задач. Во-вторых, при записи значения в переменную необходимо изменять соответствующим образом и признак готовности переменной, т. е. вместо одной записи в память получается две. В-третьих, для проверки условия готовности требуется много времени, если на вход Л-блока поступает большой объем данных.

Альтернативный вариант заключается в том, что признак готовности вводится не для каждой входной переменной Л-блока, а для всего Л-блока в целом. Аналогичный подход используется при аппаратной реализации некоторых вычислителей с управлением потоком данных, однако там его реализация (с программной точки зрения) тривиальна, поскольку отсутствуют структурные переменные (например, массивы), массовые операции и группировка операций (о группировке см. в следующем разделе). Этот подход выбран в качестве базового в данной работе.

Вначале конкретизируем управление для базовой асинхронной модели. Каждому Л-блоку Л поставим в соответствие некоторое число N(A), равное количеству входных переменных Л-блока Л. Это число будем называть числом зависимостей Л-блока Л. В управляющей памяти для каждого Л-блока Л выделим по одной переменной, которую будем называть счетчиком зависимостей Л и обозначать dep^). Будем считать, что в начальном состоянии памяти аер(Л) = Щ(Л).

Исполнение Л-программы уточняется следующим образом.

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

2. Управляющий оператор Л-блока осуществляет уменьшение счетчиков зависимости у всех Л-блоков, входные переменные которых вычислены операцией Л-блока.

Заметим, что у Л-блока могут быть входные переменные, которые не вычисляются другими Л-блоками (начальные данные). Такие переменные не учитываются при вычислении числа зависимостей Л-блока (в противном случае его исполнение никогда не начнется).

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

Распространим теперь введенные определения на асинхронную модель с массовыми Л-блоками. Каждому 7-му экземпляру Л-блока Л (7) поставим в соответствие некоторое число ЩА(г')), которое будем называть числом зависимостей экземпляра. В управляющей памяти для каждого экземпляра Л-блока Л выделим по одной переменной, которую будем называть счетчиком зависимостей 7-го экземпляра Л-блока Л и обозначать dep(Л(7')).

Поскольку в модели с массовыми Л-блоками имеются структурные переменные (например, записи или массивы), вычисление N^(7)) имеет ряд особенностей. Структурные переменные могут поступать на вход Л-блока как целиком (например, весь массив), так и по частям (некоторые поля записи). Если структурная переменная целиком будет вносить в значение N^(7)) единицу (как в случае базовой асинхронной модели), тогда возникнет проблема с тем, сколько будет вносить часть (один или несколько компонентов) структурной переменной.

Для ее решения введем вспомогательное определение. Каждой переменной х поставим в соответствие некоторое число М(х), равное единице, если х - простая переменная, либо сумме М(х(7)), если х - структурная переменная (здесь х(7) - компоненты х). Это число будем называть числом компонентов переменной. Например, если переменная х есть массив из 10 записей, каждая из которых содержит по 2 целых числа, то число компонентов х равно 20.

Число зависимости М(А(7)) 7-го экземпляра Л-блока Л по определению положим равным сумме чисел компонентов всех входных переменных экземпляра Л-блока Л (N(А(7) = ^М(х), где х е (А(7)). Будем считать, что в начальном состоянии памяти

dep(A(7)) = N^(7)). Исполнение Л-программы уточняется аналогично базовой асинхронной модели.

В качестве примера рассмотрим Л-программу умножения матриц, состоящую из двух массовых Л-блоков: Л1 (выполняет операции умножения) и А2 (выполняет операции сложения). Так как элементы матрицы являются числами (простые переменные), то счетчик зависимости каждого экземпляра Л-блока А2 перед началом исполнения программы будет равен четырем (ЩА2(7)) = 1 + 1 + 1 + 1).

Конструирование управляющего оператора. Для автоматического конструирования управляющего оператора необходимы исходные данные. Оставляя за рамками статьи причины выбора таких данных и способы их описания, далее будем считать, что программистом задано множество Л-блоков Е = {А1, А2,..., Ап} с пустым управляющим оператором и предикат Рг еу (А1, А^), принимающий значение ИСТИНА, если Л-блок А1 должен выполниться раньше Л-блока А^ (т. е. между ними существует информационная зависимость).

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

Конструирование управляющего оператора для базовой асинхронной модели достаточно очевидно и может быть выполнено по следующему алгоритму (для Л-блока Л).

1. Формируем множество М всех В1 е Е , таких, что пересечение оШ;(А) п т(В7) не пусто и Рг еу (А, В7) принимает значение ИСТИНА.

2. Для каждого В7 из М включаем в управляющий оператор Л-блока Л команду уменьшения dep( В7) на величину |ои1;( А) п т( В7)|.

Для асинхронной модели с массовыми вычислениями, как и в случае с определением числа зависимостей экземпляра, из-за наличия структурных переменных возникает ряд сложностей. Дополнительные трудности создает также то, что простые Л-блоки могут вычислять переменные для массовых Л-блоков, и наоборот.

Вначале рассмотрим конструирование управляющего оператора для простого Л-блока Л, вычисляющего одну переменную х для простого Л-блока В (зависимость «Простой Л-блок -Простой Л-блок»). Поскольку х может быть как простой так и структурной переменной, возможно несколько вариантов: Л-блок Л вычисляет х целиком либо только некоторый компонент х; А-блок В на входе имеет либо х целиком, либо некоторый компонент х. Поэтому в управляющий оператор Л-блока Л необходимо включить одну команду, уменьшающую значение dep(B) на величину У, которая рассчитывается по следующим правилам:

• если выходная переменная вычисляется целиком, входная переменная потребляется целиком, то У = М(х);

• если выходная переменная вычисляется целиком, входная переменная потребляется частично, то У = М(х(7)), где х(7) - потребляемый компонент переменной х;

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

• если выходная переменная вычисляется частично, входная переменная потребляется целиком, то У = М(х(7)), где х(7) - вычисленный компонент переменной х;

• если выходная переменная вычисляется частично, входная переменная вычисляется частично, то необходимо проверить, совпадает ли вычисленный компонент х(7) с потребляемым компонентом х(/). Если совпадение обнаружено, У = М(х(7)) = М(х(/)). В противном случае У = 0.

При конструировании управляющего оператора для простого Л-блока Л, вычисляющего одну переменную х для экземпляров массового Л-блока В (зависимость «Простой Л-блок -Массовый Л-блок») необходимо рассмотреть два варианта.

1. Входная переменная х Л-блока В не является массовой (т. е. одна и та же для всех экземпляров В). В этом случае в управляющий оператор Л-блока Л необходимо включить 7 команд, каждая из которых уменьшает соответствующий dep(B(7)) на величину У, рассчитываемую аналогично случаю «Простой Л-блок - Простой Л-блок».

2. Входная переменная х Л-блока В является массовой (т. е. каждый экземпляр Л-блока В получает на вход свой собственный компонент переменной). В этом случае в управляющий оператор Л-блока Л необходимо включить одну команду, уменьшающую значение dep(B(7)) на величину У, которая рассчитывается по следующим правилам:

• если выходная переменная вычисляется целиком, то в управляющий оператор Л-блока Л необходимо включить 7 команд, каждая из которых уменьшает соответствующий dep(B(7)) на величину М(х(7));

• если выходная переменная вычисляется частично, то необходимо проверить, попадает ли вычисленный компонент х(/) в область применимости Л-блока Л. Если попадает, то в управляющий оператор Л-блока Л необходимо включить одну команду, уменьшающую число зависимости экземпляра, потребляющего вычисленное значение на М(х(/)).

Аналогичным образом рассматриваются зависимости «Массовый Л-блок - Простой Л-блок» и «Массовый Л-блок - Массовый Л-блок».

Для Л-программы имеет место зависимость «Массовый Л-блок - Массовый Л-блок». Входная переменная х Л-блока Л2 является массовой, поэтому в управляющий оператор каждого экземпляра А 1, который вычисляет переменные, потребляемые экземплярами Л2, будет добавлено по одной команде, уменьшающей значение счетчика соответствующего экземпляра Л2 на единицу.

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

во проверок условия готовности каждого Л-блока не превосходит количества его переменных, причем оно может быть даже меньше, чем число входных переменных Л-блока в случае, когда один Л-блок вычисляет для другого Л-блока сразу несколько входных переменных. Тогда проверка условия готовности будет выполнена один раз - после завершения обновления dep(A) зависимого Л-блока А.

Группировка вычислений. Как было отмечено, общий подход к группировке заключается в объединении нескольких экземпляров Л-блока в более крупный блок, называемый группой. Если Л-блок простой (состоит из одного экземпляра), то он является группой по определению (остается без изменений). Далее рассматриваются только массовые Л-блоки.

С учетом введенных уточнений группировку экземпляров массового Л-блока можно определить следующим образом. Пусть задан Л-блок Л, определяющий экземпляры А1, А2,..., Ап. Разделим экземпляры Л-блока Л на группы по к элементов в каждой. Входные переменные группы есть объединение входных переменных элементов, выходные переменные группы есть объединение выходных переменных элементов. Вместо к счетчиков зависимостей (для каждого элемента) выделяется один счетчик зависимостей на всю группу целиком. Таким образом, группа может быть исполнена, только если все ее входные переменные вычислены.

Объединение триггер-функций. Если исходный Л-блок имел пустую триггер-функцию, то новый Л-блок также будет иметь пустую триггер-функцию. Триггер-функции, не влияющие на количество вычисляемых экземпляров (область применимости массового Л-блока известна до начала вычислений), должны удовлетворять дополнительному ограничению: для массовых Л-блоков триггер-функция не может зависеть от массовых переменных. Это позволяет исключить ситуации, когда из-за ложности триггер-функции одного экземпляра отменяется выполнение всей группы целиком 1.

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

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

Л-блока имела вид NA = {71/' = к ± Ь, к = п...т л п, т, Ь е N} (это условие является ключевым

для данной работы). Тогда экземпляры Л-блока можно объединять в группы в порядке возрастания номера экземпляра. Порядок вычисления операций экземпляров внутри группы задается пользователем.

Конструирование управляющего оператора. Поскольку область применимости имеет вид 7 = к ± Ь, то и компоненты массовых выходных переменных будут вычисляться последовательно. Поэтому при конструировании управляющего оператора группы (в соответствии с алгоритмом, приведенным ранее) в тех местах, где необходимо проверять, попадает ли вычисленная переменная в область применимости зависимого блока, можно сразу искать пересечение диапазонов и уменьшать значение счетчика зависимого экземпляра на число компонентов в пересечении. Другими словами, за счет линейности области применимости Л-блока Л проверку всего диапазона удается заменить проверкой на границах.

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

Поясним сказанное на примере. Пусть экземпляры А-блока A(i) вычисляют массив целых чисел x(i), а экземпляры А-блока B(i) потребляют значения массива x(i). Пусть экземпляры А-блока B сгруппированы в группы по 5 и нам нужно сгруппировать экземпляры А-блока А в группы по 3. Рассмотрим управляющий оператор группы А(1) (в эту группу входят 1, 2 и 3-й экземпляры исходного А-блока). Вместо того, чтобы проверять, что каждый x(1), x(2), x(3) попадают в область применимости B(1), ищется пересечение диапазона переменных, вычисляемых группой А(1) (этот диапазон x[1...3]) с областью переменных, потребляемых блоком B(1) (этот диапазон x[1...5]), после чего счетчик зависимостей B(1) уменьшается на 3 одной командой. Если бы экземпляры B были сгруппированы в группы по 2, то потребляемый B(1) диапазон был бы другим (x[1...2]) и управляющий оператор А(1) уменьшал бы его счетчик зависимостей только на 2 (так как мощность пересечения x[1...3] с x[1...2] равна 2).

После объединения экземпляров А-блока А в группы управляющие операторы всех А-блоков, которые вычисляют переменные для А-блока А, также необходимо сконструировать заново (теоретически, этого можно и не делать, однако в этом случае накладные расходы на управление запуском групп А-блока А не уменьшаться).

Заметим, что термин «группа» введен только для удобства, чтобы отличать сконструированные экземпляры от исходных. С точки зрения модели вычислений, вместо исходного массового А-блока А с n экземплярами мы имеем новый массовый А-блок Л' с m экземплярами.

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

Рис. 2. Умножение матриц с группировкой вычислений

В качестве примера рассмотрим группировку А-блока А1 программы умножения матриц. Сгруппируем экземпляры А-блока А1 в группы по два по каждой координате. Тогда вместо 64 экземпляров А-блока А1 получим 8 групп А-блока А1', каждая из которых вычисляет параллелепипед размером 2 х 2 х 2. На рис. 2 квадратами выделены данные, которые потребляет / вычисляет первая группы А-блока А1'.

Используя приведенные ранее алгоритмы, можно автоматически перестроить управление таким образом, что А-блок А2 будет запускаться только после вычисления соответствующей пары групп А -блока А1'.

Выигрыш от группировки очевиден. Во-первых, сократилось количество объектов, которыми необходимо управлять во время исполнения программы: вместо 64 экземпляров осталось 8 групп. Во-вторых, сокращение количества управляющих операторов не привело к

увеличению вычислительной сложности оставшихся: если в Л-программе для запуска одного экземпляра Л2 необходимо было выполнить 4 операции уменьшения его счетчика зависимостей, то теперь это количество сократилось до 2 операций.

Система программирования Аспект

Система асинхронного параллельного программирования Аспект [Арыков, Малышкин, 2008] разрабатывается в Институте вычислительной математики и математической геофизики СО РАН и является одной из реализаций идей сборочной технологии программирования. Она предназначена для решения задач численного моделирования и состоит из двух основных компонентов: транслятора и исполнительной подсистемы (рис. 3).

Рис. 3. Компоненты системы Аспект и их взаимодействие

На вход транслятора поступает программа на языке Аспект. Этот язык позволяет представлять алгоритм в виде множества операций и задавать связи между ними. Средствами языка для каждой операции описываются только входные и выходные переменные, а способ вычисления выходных переменных из входных («тело» операции) может быть задан на любом существующем языке (в текущей реализации используется С++). Поэтому Аспект не является языком программирования в обычном смысле, его основная функция - описание способа применения операций к данным, а также задание управления (как потокового, так и прямого). Транслятор осуществляет генерацию асинхронной программы в сгруппированной форме по описанным в разделе 4 алгоритмам.

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

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

Рис. 4. Процесс получения исполняемого файла в системе Аспект

Рассмотрим результаты тестирования системы Аспект на примере модельной задачи умножения матриц. Для тестирования использовалась следующая конфигурация: Athlon 64 X2 3600+ (2*256 L2), 1024 DDR2 RAM, Windows Vista Ultimate. Результаты тестирования для матриц размером 400 на 400 элементов приведены на рис. 5 (отметка Б/А показывает скорость аналогичной программы, разработанной вручную).

0,5 0,25

Б № 400 200 100 50 25

Размер группы

Рис. 5. Результаты умножения матриц с различными размерами групп

Из диаграммы видно, что ускорение достигает значения 1,93 (при размере группы в 50 экземпляров). Это объясняется тем, что, хотя каждое ядро имеет отдельный кэш второго уровня, доступ к оперативной памяти производится через общий контроллер. Таким образом, понятно, что эффективное использование кэш-памяти для многоядерных процессоров имеет первостепенное значение.

Скачок при размере группы в 400 экземпляров происходит потому, что ее размер совпадает с исходным размером матриц, т. е. вся матрица представляет собой одну группу. В этой ситуации для 2-го ядра просто нет работы.

Следует обратить внимание на то, что ось групп не линейна. Например, при размере группы в 100 экземпляров всего получается 80 групп (4*4*4 + 4*4), а при размере в 50 экземпляров - уже 576 групп. Таким образом, при существенном увеличении числа групп скорость счета не возрастает (она даже несколько снижается под влиянием кэш-памяти), что свидетельствует об эффективности работы ядра системы.

Заключение

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

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

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

Список литературы

Григорьев Ю. Н., Вшивков В. А., Федорук М. П. Численное моделирование методами час-тиц-в-ячейках. Новосибирск: Изд-во СО РАН, 2004. 360 с.

Вшивков В. А., Краева М. А., Малышкин В. Э. Параллельная реализация метода частиц // Программирование. 1997. № 2. С. 39-51.

Краева М. А., Малышкин В. Э. Алгоритмы динамической балансировки загрузки при реализации метода частиц в ячейках на МИМД-мультикомпьютерах // Программирование. 1999. № 1. С. 47-53.

KraevaM. A., Malyshkin V. E. Assembly technology for parallel realization of numerical models on MIMD-multicomputers // Future Generation Computer Systems. 2001. Vol. 17. P. 755-765.

Котов В. Е., Нариньяни А. С. Асинхронные вычислительные процессы над памятью // Кибернетика. 1966. № 3. С. 64-71.

Котов В. Е. О практической реализации асинхронных параллельных вычислений // Системное и теоретическое программирование. Новосибирск: ВЦ СО АН СССР, 1972. С.110-125.

Котов В. Е. О параллельных языках. II // Кибернетика. 1980. № 3. С. 1-10.

Котов В. Е., Марчук А. Г. Некоторые итоги и перспективы развития проекта МАРС // Актуальные проблемы развития архитектуры и программного обеспечения ЭВМ и вычислительных систем. Новосибирск: ВЦ СО АН СССР, 1983. С. 13-23.

Moskovsky A., Roganov V., Abramov S. Parallelism granules aggregation with the T-system // Poc. of the 9th Int. Conf. on Parallel Computing Technologies (PaCT-2007). Lecture Notes in Computer Science. Berlin: Springer, 2007. Vol. 4671. P. 293-302.

Вальковский В. А., Малышкин В. Э. Синтез параллельных программ и систем на вычислительных моделях. Новосибирск: Наука, 1988. 129 с.

Лельчук Т. И. Языковая реализация параллельной асинхронной модели вычислений // Кибернетика. 1984. № 5. С. 32-37.

Арыков С. Б., Малышкин В. Э. Система асинхронного параллельного программирования «Аспект» // Вычислительные методы и программирование. 2008. Т. 9. № 1. С. 205-209.

Материал поступил в редколлегию 16.07.2008

S. B. Arykov, V. E. Malyskin

ALGORITHMS OF ASYNCHRONOUS PROGRAMS CONSTRUCTION WITH PREDEFINED LEVEL OF NON-PROCEDURALITY BASED ON GROUPING METHOD

Problems of asynchronous programs development for parallel implementation of the large scale numerical models are considered. Assembly technology is proposed to be used in order to support program assembling in the asynchronous programming system. This provides automatic implementation of dynamic properties (setting up on the available resources, dynamic load balancing, dynamic resource distribution, etc.) of application program. Special version of asynchronous model of computation is proposed which allows in the wide range to vary the overheads of the program execution with the help of computation fragments grouping. Asynchronous parallel programming system Aspect is considered which implements some principles of the assembly technology on the symmetric multiprocessor or multicores computers.

Keywords: assembly technology of programming, asynchronous languages and programming systems, dynamic program's properties, automation of the parallel realization of the numeric models.

i Надоели баннеры? Вы всегда можете отключить рекламу.