Лекция №1 (Lec_1_paral)

advertisement
Замечание: 70% материала данной лекции соответствует различным разделам книги
1.
И. Одинцов Профессиональное программирование. Системный подход. – «БХВ-Петербург» - 2004.
– 610 с.
и выделено цветом!!!
Материал к лекции №1 (в том числе и дополнительный для самостоятельного
изучения). Лекция – 2 часа, самостоятельная работа – 2 часа, практикум – 2 часа, итого – 6
часов.
МЕТОДОЛОГИЯ
ИМПЕРАТИВНОГО ПАРАЛЛЕЛЬНОГО ПРОГРАММИРОВАНИЯ
1. Введение ....................................................................................................................................2
2. Методология императивного параллельного программирования: ..............................3
происхождение, теория и эволюция .........................................................................................3
2.1. Классификация по ядрам методологий ............................................................................3
2.2. Некоторые методологии, поддерживающие параллелелизм ........................................4
(реализационная специфика) ....................................................................................................4
2.3. Определение методологии императивного параллельного программирования ...........6
2.4. Простые примеры на основе OpenMP .............................................................................6
2.5. Происхождение, теория, эволюция ..................................................................................8
3. Методы и концепции. Синтаксис и семантика ...............................................................11
3.1. Методы и концепции ........................................................................................................11
3.2. Модель вычислений параллельного программирования в контексте модели
императивного программирования (самостоятельно) .......................................................11
3.3. Уровни параллелелизма ....................................................................................................12
3.4. Взаимодействие параллельных процессов (самостоятельно).....................................12
4. Языки параллельного программирования [1] ................................................................12
4.1. Программирование на параллельном языке программирования ..................................13
4.2. Программирование на широко распространенном языке программирования,
который расширен распараллеливающими конструкциями ...............................................13
4.3. Программирование с использованием дополнительных указаний компилятору .......13
4.4. Программирование на широко распространенном языке программирования с
использованием коммуникационных библиотек ...................................................................13
4.5. Средства автоматического распараллеливания последовательных программ
такими инструментами, как компиляторы ........................................................................14
5. Класс задач..............................................................................................................................14
6. Ускорение параллельной программы ...............................................................................14
1
7. Закон Амдала..........................................................................................................................14
Задание.........................................................................................................................................15
ЛИТЕРАТУРА ...........................................................................................................................16
1. Введение
Главными целями данного курса, во-первых, является формирование четкого
понимания того, что при выборе языка и инструмента среды программирования,
оптимальной архитектурной и операционной платформы определяющую роль играет
выбранная методология программирования (подобный взаимосвязанный подход к
программированию часто называют «системным»); второй, не менее важной целью,
является приобретение необходимых практических навыков.
Более подробно о системном подходе можно прочитать в
1.
2.
3.
И. Одинцов Профессиональное программирование. Системный подход. – «БХВ-Петербург» - 2004.
– 610 с.
Джин Бэкон, Тим Харрис Операционные системы. Параллельные и распределенные системы. – bhv
«Питер» - 2004 – 799 с.
http://www.it-education.ru/2006/reports/Kalinina.htm
Выбор конкретной методологии программирования, в свою очередь, определяется
классом решаемых задач.
Значительное число задач, имеющих большую вычислительную сложность и
возникающих при научных исследованиях, а также при моделировании различных
ситуаций в экономике, могут быть решены в рамках методологии императивного
параллельного программирования.
Поэтому в данном курсе в качестве изучаемой методологии была выбрана
методология императивного параллельного программирования, а в качестве
«дружественных» ей программных продуктов, архитектурной и операционной
платформы:
Архитектурная платформа: SMP – система (система с общей памятью)
Операционная платформа: Windows
Язык и инструменты среды программирования:
OpenMP (Intel C++), инструменты Intel (Thread Checker, Thread Profiler, VTune
Performance Analyzer).
Методология программирования – это совокупность методов, применяемых в
жизненном цикле программного обеспечения и объединенных общим философским
подходом.
2
Не исключено, что одна и та же задача может быть успешно решена в рамках
различных методологий. Очень часто вопрос о преимущественном выборе той или иной
методологии может решить только практический опыт. Тем не менее, вследствие того, что
выбор методологии требует выбора специфических средств для ее реализации,
необходимо выбрать конкретный вариант, иногда, возможно, и смешанную реализацию.
«Собрались однажды звери в лесу, чтобы строить мост через реку. Когда все
обсудили, медведь спрашивает: вопросы есть? Осел: «А как будем строить – вдоль или
поперек реки?»
(Анекдот о необходимости определяющих подходов [1])
Методологию можно также представлять как:
 Методология как концентрация практического опыта
 Алгоритмическое происхождение некоторых методологий
 Методологии как результат отображения структур (см. ниже)
Еще одним фактором в пользу выбора методологии императивного параллельного
программирования является ее относительная простота, что позволяет в пределах данного
курса сконцентрировать внимание не только на ней, но и на других аспектах системного
подхода.
Более эффективным освоение «системного» подхода сделают практические
занятия с применением инструментов, которые будут диагностировать работу компьютера
на низшем уровне непосредственно при выполнении программы.
2. Методология императивного параллельного
программирования:
происхождение, теория и эволюция
2.1. Классификация по ядрам методологий
2.2. Некоторые
специфика)
методологии,
поддерживающие
параллелелизм
(реализационная
2.3. Определение методологии императивного параллельного программирования
2.4. Простые примеры
documents/spec25.pdf )
на
основе
OpenMP
(http://www.openmp.org/drupal/mp-
2.5. Происхождение, теория, эволюция
2.1. Классификация по ядрам методологий
3
Одной из очень удачных классификаций методологий представляется
классификация по ядрам, описанная в книге И.Одинцова [1]. Ниже приведен
оригинальный текст раздела 2.1.3.1. из [1]:
«Хотя все племена нтернети исповедуют, вобщем, единый культ, между ними идут
постоянные религиозные войны. Одна из самых затяжных непосредственно связана с тем,
какие палочки использовать для добывания дыма. Одно племя использует мсайе, палочки
из древесины кокосовой пальмы, а другое – нтскейпами, из древесины банановой пальмы.
Что интересно – те и другие одинаково кривые, но однако каждое племя замечает лишь
кривизну палочек противника.
(Юрий Нестеренко)
Наш подход к методологиям заключается в том, что существует некоторое ядро
методологии со своими методами, которое уточняется некоторыми дополнительными
особенностями. Этот подход напоминает принцип словообразования в русском языке –
есть корень, к которому добавляются приставки, суффиксы и окончания, уточняющие
смысл слова.
Ядра методологий определяются способом описания алгоритмов. Перечислим
основные ядра методологии...
 Методология императивного программирования
 Методология объектно-ориентированного программирования
 Методология функционального программирования
 Методология логического программирования
 Методология программирования в ограничениях
Каково взаимоотношение между этими методологиями? Начнем с того, что первичной
семантикой программирования является операционная семантика по очень простой
причине. Программа бессмысленна без наличия вычислителя (машины), способного ее
исполнить, причем исполнение протекает с достаточно мелкими шагами.
Все остальные семантики, в конечном счете, основаны на операционной. Точно также
все остальные разновидности программирования родились в недрах императивного, и в
большей или меньшей степени основаны на нем. И перечисленные методологии, кроме
императивной, представляют собой ее развитие, и, естественно, во многом обогащают.»
Таким образом, есть еще один аргумент для выбора методологии императивного
параллельного программирования в качестве первой для освоения – исторически она
возникла первой и, так или иначе, имеет связи со всеми остальными.
2.2. Некоторые методологии, поддерживающие параллелелизм
(реализационная специфика)
4
Реализационная специфика связана с наличием различной организации аппаратных
средств – в частности, централизованной и параллельной. В связи с этим можно выделить
следующие методологии:

Методология императивного параллельного программирования. Эту методологию
обычно называют кратко – методология параллельного программирования.

Методология логического параллельного программирования.

Методология функционального параллельного программирования
Необходимо заметить, что часто используется
функционального и логического программирования.
объединение
методологии
Ниже приводится текст разделов 2.1.3.1. и 2.1.3.4 из [1], содержащий аналогичную
информацию, а также справочные сведения по каждой из методологий (для
самостоятельного изучения):
«
Каждое из «корней» - ядер может получить «суффикс», определяющий некоторую
организацию аппаратной поддержки данной методологии. На данный момент наиболее
известными организациями являются две: централизованная и параллельная.
Ядра методологий изначально продумывались для централизованных архитектур.
Позже появились параллельные аппаратные реализации, к которым стали адаптироваться
уже существующие методологии. Приведем примеры параллельных методологий.

Методология императивного параллельного программирования. Эту методологию
обычно называют кратко – методология параллельного программирования.

Методология логического параллельного программирования.
....
Смешанные методологии включают объединение методов нескольких методологий.
Наиболее часто объединяются методологии функционального и логического
программирования.»
Для справки ( текст из различных разделов [1]):
«... сущность языка определяют три его составные части:



структура данных
структура управления
логика
Каждая из трех структур языка моделирования может быть отображена на одну из трех
структур языка программирования. В результате получается девять типов отображения.
При этом каждое из отображений определяет ибо методологию, либо достаточно
серьезный метод.
.....
5
2. Управление --> Управление. Отображение, связанное с понижением уровня
структуры управления языка моделирования, ведет к идее методологии структурного
программирования.
3. Логика --> Логика. Отображение лежит в основе методологии логического
программирования.
4. Данные -- > Управление. Отображение активизирует пассивные данные, преобразуя
их в активные процессы, и лежит в основе функционального программирования. В
значительной степени это отображение определяет методологию объектноориентированного программирования
....
Методология логического программирования – подход, согласно которому программа
содержит описание проблемы в терминах фактов и логических формул, а решение
проблемы система выполняет с помощью механизмов логического вывода.
.....
Методология функционального программирования – способ составления программ, в
которых единственным действием является вызов функции, единственным способом
расчленения программы на части – введение имени для функции и задание для этого
имени выражения, вычисляющего значение функции, а единственным правилом
композиции – оператор суперпозиции функций ....»
2.3. Определение методологии императивного параллельного
программирования
Методология императивного параллельного программирования – подход, в
котором предлагается использование явных конструкций для параллельного исполнения
выбранных фрагментов программ [1].
2.4. Простые примеры на основе OpenMP
(http://www.openmp.org/drupal/mp-documents/spec25.pdf )
Рассмотрим пример двух синтаксических конструкций явного распараллеливания
на основе технологии OpenMP (их работа будет исследоваться в рамках практического
занятия):
1. Конструкция «параллельные секции»: параллельно, одновременно выполняются
2 цикла.
#pragma omp parallel sections
{
#pragma omp section
for (i=0;i<N; i++ ) sum_a = sum_a + pow(sin(x),double(i));
#pragma omp section
6
for (j=0;j<N; j++ ) sum_b = sum_b + pow(cos(x),double(j));
}
Для двухъядерной или двухпроцессорной системы с общей памятью это можно
представить, как будто бы первый цикл (по i) выполняется на одном процессоре (ядре), а
второй цикл (по j) выполняется на другом процессоре (ядре). Это указывается явно.
2. Параллельно выполняется каждая половина итераций каждого цикла; в конце
каждого из них получается результирующее значение суммы (“reduction”), как сумма
результатов каждого из параллельных вычислений:
#pragma omp parallel for reduction(+:sum_a)
for (i=0;i<N; i++ ) sum_a = sum_a + pow(sin(x),double(i));
#pragma omp parallel for reduction(+:sum_b)
for (j=0;j<N; j++ ) sum_b = sum_b + pow(cos(x),double(j));
Здесь используется более сложная синтаксическая конструкция. В зависимости от
внутренних настроек компилятора, частью которого является OpenMP, в
двухпроцессорной (двухъядерной системе) итерации каждого из двух циклов могут быть
поделены между процессорами (ядрами) одним из двух способов:
При этом компилятору дается указание относительно использования общего
адресного
пространства.
Конструкция
reduction(+:sum_a)
(аналогично
reduction(+:sum_b) ) указывает, во-первых, что переменную sum_a (sum_b) следует
«размножить» по числу процессоров (ядер) или, другими словами, завести отдельную
копию этой переменной для вычислений на каждом процессоре (sum_a.копия1 и
7
sum_a.копия2). Благодаря этому вычисления на каждом процессоре будут практически
независимы.
Во-вторых, конструкция reduction указывает, что после окончания вычислений на
всех процессорах (ядрах) значения, полученные во всех копиях sum_a, следует сложить
(sum_a.копия1 + sum_a.копия2) и присвоить значению переменной sum_a (sum_a =
sum_a.копия1+ sum_a.копия2).
2.5. Происхождение, теория, эволюция
[1]:
«
Вычислительные задачи часто имеют огромные объемы. Анализ эффективности их
решений показал, что ситуацию можно значительно улучшить, если использовать для
вычислений не одно, а несколько вычислительных устройств одновременно. Создание
аппаратных многопроцессорных архитектур привело к широким исследовательским
работам в этой области. Еще одна причина возникновения данной методологии связана с
появлением достаточно сложных программ, требующих поддержки явного
параллелелизма (например, операционных систем).
Считается, что параллельное программирование возникло в 1962 году с
изобретением каналов – независимых аппаратных контроллеров, позволяющих
центральному процессору выполнить новую прикладную программу одновременно с
операциями ввода – вывода других программ. Первоначально с параллельным
программированием имели дело лишь разработчики операционных систем.»
Рассмотрим в общем и целом примеры параллельной организации систем с общей
памятью. Более подробно они будут рассмотрены позже.
Первоначально возникли многопроцессорные архитектуры с общей памятью.
Каждый процессор имел независимую кэш-память, в то время как соединение с
оперативной памятью осуществлялось, например, через общую шину. Пример одной из
первых подобных систем показан на рисунке ниже [2]:
8
На этом рисунке следует обратить внимание на наличие синхронизующего сигнала
между двумя процессорами. Это синхронизация кэш-памяти (2-ой кэш). Зачем она нужна?
Вернемся к рассмотренному примеру №2 на основе OpenMP из предыдущего
раздела. Ведь перед тем, как находить сумму
sum_a = sum_a.копия1+ sum_a.копия2
необходимо дождаться, когда каждый процессор вычислит свою sum_a.копия№i. Узнать
об этом можно с помощью синхронизирующих сигналов.
Гораздо позже возникли многоядерные архитектуры. Они имеют общую кэшпамять на уровне второго кэша. Пример двухъядерной архитектуры показан на рисунке
ниже (IIntel® Core™ Duo Processor[Intel]):
FP Unit
FP Unit
EXE Core
EXE Core
L1 Cache
L1 Cache
L2 Cache
System Bus
(667MHz, 5333MB/s)
Как уже отмечалось выше, одной из причин возникновения и развития
методологии императивного параллельного программирования является создание
современных операционных систем, которые являются по своей внутренней сути
параллельными программами.
Следует заметить, что параллелелизм на низшем уровне реализуется именно
операционной системой, а пользовательская параллельная программа «пользуется
предоставляемым сервисом параллелелизма» (непосредственно или через определенную
надстройку (технологию), например, OpenMP), например, с помощью интерфейса
системных вызовов ядра операционной системы, как показано на рисунке ниже [2]:
9
В современных Windows пользовательские потоки регистрируются как потоки
ядра, и самым непосредственным образом подчиняются всем «законам» операционной
системы, см. рисунок ниже [2]. Таким образом, способ организации параллелелизма
является еще одним подтверждением необходимости применения «системного» подхода.
10
Более подробно материал об операционных системах будет рассмотрен в
следующих лекциях.
3. Методы и концепции. Синтаксис и семантика
3.1. Методы и концепции
3.2. Модель вычислений параллельного программирования в контексте модели
императивного программирования (самостоятельно)
3.3. Уровни параллелелизма
3.4. Взаимодействие параллельных процессов (самостоятельно)
3.1. Методы и концепции
[1]
«Метод синхронизации исполняемого кода заключается в использовании специальных
атомических операций для осуществления взаимодействия между одновременно
исполняемыми фрагментами кода. Метод поддерживается концепцией примитивов
синхронизации.»
3.2. Модель вычислений параллельного программирования в
контексте модели императивного программирования
(самостоятельно)
[1]
«Модель вычислений параллельного программирования рассмотрим в контексте
модели императивного программирования.
Имеется несколько вычислителей, которые характеризуются наличием общих
элементов состояния.
Одно из возможных описаний вычислительной модели выглядит следующим образом.
Если на шаге вычислений с некоторым номером элемент состояния одного
вычислителя принимал данное значение, то для любого другого вычислителя на шаге
вычисления с тем же номером соответствующий элемент состояния также должен
принимать данное значение.
Прямым аналогом оператора в данной методологии является процесс. Основное
отличие этой методологии от императивной в том, что процессы могут выполняться
параллельно.
Паралллельная методология тесно привязана к платформе, на которой она реализуется.
Параллелизм может быть реализован как аппаратно на централизованной архитектуре, так
и на распределенной…»
11
3.3. Уровни параллелелизма
[1]
«В общем случае параллелелизм заключается в одновременной обработке
приложений, процессов, подпрограмм, циклов и операторов. В зависимости от уровня
дробления выделяют следующие уровни параллелелизма:

Параллелелизм на уровне микрокоманд

Параллелелизм на уровне операторов (кроме циклов)

Параллелелизм на уровне циклов и итераций

Параллелелизм на уровне подпрограмм, процедур и функций

Параллелелизм на уровне потоков управления

Параллелелизм на уровне процессов

Параллелелизм на уровне приложений»
3.4. Взаимодействие параллельных процессов (самостоятельно)
[1]
«Традиционно средство структурирования высокого уровня в данной методологии –
процесс. Процессы могут работать параллельно. Они осуществляют синхронизацию
между собой с помощью примитивов синхронизации – например, каналов связи…
Семантически взаимодействие параллельных процессов лучше всего представлять
как работу сети некоторых устройств, соединенных каналами, по которым текут данные.
Спроектировав в таких терминах, например, систему параллельных процессов для
быстрого суммирования большого количества чисел, можно легко описать эту систему в
приведенном синтаксисе.
Каждый вычислитель производит типичные для его вычислительной модели
операции (например, императивный вычислитель будет переходить из состояния в
состояние).
Когда процесс встречает инструкцию «принять значение из канала», он входит в
состояние ожидания, когда канал пуст. Как только в канале появляется значение, процесс
его считывает и продолжает работу…»
4. Языки параллельного программирования [1]
4.1. Программирование на параллельном языке программирования
12
4.2. Программирование на широко распространенном языке программирования, который
расширен распараллеливающими конструкциями
4.3. Программирование с использованием дополнительных указаний компилятору
4.4. Программирование на широко распространенном языке программирования с
использованием коммуникационных библиотек
4.5. Средства автоматического распараллеливания последовательных программ такими
инструментами, как компиляторы
Языки параллельного программирования используют явные конструкции для
параллельного исполнения выбранных фрагментов программ. Существует несколько
языковых подходов к программированию для параллельных вычислительных систем.
4.1. Программирование на параллельном языке
программирования
Программирование на параллельном языке программирования. Причем такие
языки могут быть:

Универсальными (например, Ada)

Для конкретных типов компьютера, позволяющем эффективно транслировать
программы на параллельном языке именно в эту архитектуру (напрмер, язык
Occam изначально разрабатывался для транспьютеров)
4.2. Программирование на широко распространенном языке
программирования, который расширен распараллеливающими
конструкциями
Наличие распараллеливающих конструкций на уровне языка:
 C
 C++
 Pascal.
4.3. Программирование с использованием дополнительных
указаний компилятору

на уровне языка прагм, например, по стандарту OpenMP.
4.4. Программирование на широко распространенном языке
программирования с использованием коммуникационных
библиотек
Программирование на широко распространенном языке программирования с
использованием коммуникационных библиотек и интерфейса для организации
межпроцессного взаимодействия. В этом случае конструкции параллелелизма вынесены с
языкового уровня на уровень операционной системы.
13
4.5. Средства автоматического распараллеливания
последовательных программ такими инструментами, как
компиляторы

Оптимизация с помощью Intel C++
Рассмотрим наиболее распространенные языки программирования, содержащие явные
конструкции параллельного исполнения [1].










1950
1960
Algol-68(1968)
1970 Concurrent Pascal(1972)
Modula-2(1978) GSP (1978)
1980 Edison (1980) Ada (1979, 1983)
Occam(1982)
Concurrent Prolog(1983)
Linda(1985)
Oblig(1993)
5. Класс задач
[1]
«Данная методология может очень эффективно применяться для обработки
больших однородных массивов данных. Такие массивы часто встречаются в реализации
вычислительных и статистических методов. Кроме того, методология параллельного
программирования успешно применяется при моделировании, в операционных системах и
системах реального времени.»
6. Ускорение параллельной программы
Ускорением параллельной программы называется отношение времени работы
последовательной, полностью оптимизированной программы, к времени работы
параллельной программы.
7. Закон Амдала
Закон Амдала представляет собой оценку ускорения параллельной программы на N
параллельно работающих аппаратных единицах (процессоров или ядер) при учете
временных долей последовательного (T(seq) ) и распараллеливаемого кода (T(for par)) от
общей доли первоначального, полностью последовательного кода (T(total)).
В данной оценке делается предположение, что время выполнения любого участка
кода не зависит от того, содержится ли в памяти данной аппаратной единицы только та
14
информация, которая относится к этому участку коду, или возможно, там находится еще и
дополнительная информация, связанная с работой остальной части программы.
Строго говоря, это предположение не всегда верно – ведь чем больше, например,
свободной кэш – памяти, тем быстрее работает программа (см. последующие лекции).
А при загрузке в память аппаратной единицы только части информации скорость
выполнения кода может существенно возрасти из-за отсутствия ранее выполняемых
операций подгрузки информации из других областей памяти (еще одно свидетельство в
пользу «системного» подхода!)
Поэтому закон Амдала в общем случае представляет собой только оценку
ускорения, но не непреодолимый закон. Реально за счет улучшения работы с памятью
(именно вследствие распараллеливания) ситуация в некоторых случаях может быть
намного лучше.
Логика вывода закона Амдала непосредственно видна из следующего рисунка:
За счет того, что время выполнения кода T(for par) уменьшается в N раз при
выполнении на N параллельно работающих аппаратных единицах, полное время работы
программы уменьшается и становится равным ( T(seq) + T(for par)/N).
Тогда ускорение параллельной программы:
A = T(total)/( T(seq) + T(for par)/N).
Задание
1. Определить ускорение параллельной программы для примеров со слайдов 12, 13,
открыв соответствующие проекты .
15
Генерацию параллельного кода можно включать – отключать с помощью вкладки
Properties/C/C++/Language/Directive OpenMP
2. Убедиться в правильной работе программы с помощью Tread Checker, для этого
установив число итераций циклов N = 30 (Tread Checker резко замедляет время работы
программы)
3. Убедиться в параллельной работе потоков с помощью Tread Profiler for OpenMP
ЛИТЕРАТУРА
1. И. Одинцов Профессиональное программирование. Системный подход. – «БХВПетербург» - 2004. – 610 с.
2. Джин Бэкон, Тим Харрис Операционные системы. Параллельные и распределенные
системы. – bhv «Питер» - 2004 – 799 с.
16
Download