Автор работы: Пользователь скрыл имя, 26 Марта 2012 в 23:27, лекция
Технологии высокопроизводительных вычислений сегодня переживают весьма резкие качественные изменения. Круг вопросов, подлежащих обсуждению при систематическом изложении предмета, не устоялся и стремительно меняется. По этой причине мы разделим настоящий текст на две части.
В первой части, озаглавленной «Освоенные технологии», изложим предмет так, как его надо было рассказывать, скажем, 2 – 3 года назад, не забывая, конечно, о линейном, количественном развитии, имевшем место за эти 2 – 3 года в рамках традиционных подходов.
Введение.
Часть 1. Освоенные технологии.
1. Таксономия суперкомпьютеров и применяемых в связи с ними программистских технологий.
1.1. Архитектура фон Неймана.
1.2. Три этапа развития суперкомпьютерных технологий и две суперкомпьютерных революции.
1.3. Способы объединения многих процессоров в единую систему.
1.4. Альтернативные архитектуры.
1.5. Простейшая модельная программа.
1.5.1. Решение двумерной краевой задачи для уравнения теплопроводности методом Якоби.
1.5.2. Параллельная реализация «на бумаге».
1.5.3. Что потребуется для параллельной реализации на практике.
1.6. Общий состав программного обеспечения вычислительного кластера
1.7. Некоторые основные определения.
1.8. Технологии параллельной обработки данных без использования суперкомпьютеров.
2. Некоторые основные понятия архитектуры процессоров и ОС.
2.1. Некоторые основные определения.
2.2. Пример системы команд: обработка данных в памяти.
2.3. Чего нам не хватает.
2.3.1. Общее представление об управлении внешними устройствами.
2.3.2. Программа – диспетчер.
2.3.3. Прерывания.
2.3.4. Защита памяти и многорежимность процессора.
2.3.5. Виртуальная память.
2.4. Еще несколько определений.
3. Критерии эффективности коммуникационной сети.
4. Обзор процессорных и сетевых решений, применяемых в современных кластерах.
4.1. Выбор процессора.
4.2. Выбор коммуникационной сети.
5. Суперкомпьютер МВС-1000 и метакластер МВС-900.
5.1. Основные принципы организации МВС – 1000.
5.2. Как работает и зачем нужен метакластер МВС – 900.
6. Модели и технологии параллельного программирования.
6.1. Два способа параллельной обработки данных.
6.2. Два лица программистской модели.
6.3. Модель: явный двусторонний обмен сообщениями.
6.4. Модель: односторонний обмен сообщениями.
6.5. Модель: NUMA.
6.6. Модели, производные от явного двустороннего обмена сообщениями.
6.6.1. Модель библиотек коллективных операций над распределенными массивами.
6.6.2. Модель параллельных трансляторов в стиле HPF.
6.6.3. Модель непроцедурных языков.
6.7. Парадокс неприятия новых технологий.
6.8. Немного о технике реализации MPI.
Часть 2. Технологии, появляющиеся сегодня.
7. Почему «эпоха кластеров» заканчивается.
Литература.
Технологически организация HPF очень привлекательна (отсутствие необходимости сопровождать отдельно однопроцессорный и параллельный варианты текста, полная автоматизация файлового ввода – вывода для распределенных массивов).
Язык не имеет изобразительных средств для записи конвейерного параллелизма.
Следует отметить, что выбор в качестве базового языка именно Фортрана (а не C) не случаен. Наличие в C, в отличие от Фортрана, развитой адресной арифметики (полноценных указателей) сильно усложняет автоматический анализ текста программы.
Аналогичная российская разработка DVM [23], выполненная в ИПМ им. М. В. Келдыша РАН, включает в себя транслятор с языка, внешне очень похожего на HPF, но построенного на других принципах.
Серьезным недостатком HPF является то, что по тексту программы нельзя однозначно сказать, как именно транслятор ее «распараллелит». Пусть программист не указал для некоторого цикла CHPF$ INDEPENDENT. «Поймет» ли транслятор, что этот цикл – параллельный? Зависит это, вообще говоря, от конкретного транслятора и от того, правильно ли программист понимает его возможности. Если программист полагает, что транслятор его «поймет», но ошибается, получится крайне неэффективный параллельный код. Вместо желаемого ускорения программа замедлится, возможно, в тысячи раз. Зная об этой проблеме, и справедливо считая ее основной, разработчики DVM спроектировали такой набор директив, который однозначно определяет поведение транслятора. Транслятор DVM не ищет параллелизм в программе, он лишь выполняет то, что программист написал в форме директив. Если перед циклом не написано CDVM$ PARALLEL, транслятор не будет «догадываться», что этот цикл можно было бы исполнить параллельно.
В систему DVM входят трансляторы Фортран DVM, C DVM, небольшой транслятор HPF, средства отладки производительности и многое другое.
При разработке программ на C DVM настоятельно рекомендуется придерживаться «Фортрановского стиля программирования». Языки включают специальную форму параллельного цикла для организации конвейерного параллелизма. В настоящее время система интенсивно развивается в сторону гибридных моделей параллелизма, предназначенных для использования на установках с многопроцессорными узлами, в которых внутри узла общая память присутствует, а между узлами – нет.
6.6.3. Модель непроцедурных языков.
Ярким представителем технологии в рамках этой модели является язык Норма [24], также разработанный в ИПМ им. М. В. Келдыша РАН.
Эта программистская модель предполагает преодоление Основного постулата с неожиданной стороны. Если, как мы отмечали выше, при обсуждении Основного постулата, операторы традиционного алгоритмического языка высокого уровня слишком мелки, чтобы программа была обозримой для автоматического анализа, может быть, можно решить проблему, значительно увеличив «размер» оператора? Способ увеличения «размера» известен – надо от записи алгоритма (последовательности действий, которые надлежит выполнить при решении задачи) перейти к записи соотношений между входными данными и результатами, доверив транслятору построить алгоритм самостоятельно, причем сразу – параллельный. Поступая так, мы освобождаем транслятор от решения «обратной задачи» - восстановления смысла программы по ее однопроцессорному варианту. Смысл записан в виде соотношений, точнее, функций, преобразующих входные данные в результат. Поэтому Норму называют неалгоримическим, функциональным языком. Норма – несомненно, язык более высокого уровня, чем традиционные алгоритмические языки.
С точки зрения операторного программирования форма записи программ очень непривычная. Программа на Норме скорее напоминает текст из учебника по математическому анализу, чем текст программы. Например, присваивать значение данной переменной можно только один раз. Запись «a = b + 1» означает не «сделать a в данном месте программы равным текущему значению b + 1», а «принять к сведению, что a равно b + 1 (всегда)». Понятия «сейчас», «потом», «в данном месте программы» не существуют, как и понятие времени, в котором развертывается выполнение программы. Поэтому операторы присваивания можно писать в любом порядке. Словом, Норма – действительно язык записи соотношений, а не алгоритмов. Ниже приводится пример записи двух функций, вычисляющих, соответственно, сумму и произведение двух матриц.
PART Add.
a,b RESULT x
BEGIN
DOMAIN PARAMETERS n=4.
ijs: (is: (i=1..n); js: (j=1..n)).
VARIABLE a,b,x DEFINED ON ijs.
FOR ijs ASSUME x = a + b.
END PART.
PART Mult.
a,b RESULT x
BEGIN
DOMAIN PARAMETERS n=4.
ijks: (ijs: (is: (i=1..n); js: (j=1..n)); ks: (k=1..n)).
VARIABLE a,b,x DEFINED ON ijs.
VARIABLE t DEFINED ON ijks.
FOR ijks/k=1 ASSUME t = a[i,j=k] * b[i=k,j].
FOR ijks/k=2..n ASSUME t[i,j,k] = t[i,j,k-1] + a[i,j=k] * b[i=k,j].
FOR ijs ASSUME x = t[i,j,k=n].
END PART.
По такой функциональной, а не операторной, записи транслятор Норма успешно строит весьма эффективные параллельные программы.
6.7. Парадокс неприятия новых технологий.
Многолетний опыт развития технологий параллельного программирования, «надстроенных» над двусторонним рандеву (грубо говоря, над MPI) показывает, что технологии эти крайне неохотно и редко используются программистами на практике, причем тем реже, чем выше уровень технологии [1,12]. Из технологий, рассмотренных выше, в Разделе 6.6, более или менее широко распространены, пожалуй, лишь проблемно – ориентированные библиотеки коллективных операций. Почему же пользователи, часто и помногу жалуясь на трудности освоения параллельного программирования, упорно игнорируют попытки системных программистов помочь им, уменьшив эти трудности?
Гипотеза о том, что соответствующие программные системы просто плохо отлажены или порождают неэффективный код, не подтверждается. Все серьезные системы, такие, как DVM или Норма, проверялись обратным переносом больших комплексов реальных, производственных программ, написанных первоначально с использованием MPI. Документация этих систем также весьма качественная.
Действительный источник парадокса в том, что системы эти, в действительности, решают не ту задачу, автоматизируют не то, что в действительности трудно начинающим параллельным программистам.
Разработчики систем частичной автоматизации параллельного программирования – профессиональные системные программисты. Кроме того, им, как и всем людям, свойственно судить о других по себе. Они полагают, что прикладному программисту трудно, в процессе освоения параллельного программирования, то, что было трудно в аналогичной ситуации им самим, то есть кропотливо выписывать конкретные детали организации двусторонних обменов. Освоить же новую систему понятий, элегантную и остроумную, которая от этой кропотливой работы освобождает – гораздо легче.
В отношении очень многих прикладных программистов это верно. Очень многие прикладные программисты, к счастью, «видят» компьютер именно так, как «системщики», то есть постоянно, не стремясь к этому специально, держат в голове хорошо структурированную, формализованную модель вычислительной системы, программы и процесса ее построения, охотно и с интересом осваивают придуманные специально для них новые системы понятий. «Беда» лишь в том, что эта категория пользователей не нуждается в помощи систем автоматизации. Эти пользователи легко осваивают MPI, а затем столь же легко строят на его базе собственные «системы автоматизации» для конкретной задачи или класса задач. «Норму» или DVM они не осваивают не потому, что не могут, а потому, что для них это – лишняя работа.
На немыслимую трудность освоения параллельного программирования жалуются пользователи иного рода. Это – те программисты (зачастую, кстати сказать, весьма опытные), которые воспринимают вычислительную систему как досадную, но неизбежную помеху своей главной производственной деятельности (физике, химии, биологии). Примерно так, как «системщик» относится к «наворотам» новой версии Word или Excel, когда приходится оформлять документацию. Эти пользователи видят вычислительную систему нерасчлененно и целостно, на уровне привычки, совершенно справедливо полагая, что, раз уж без нее не обойтись, она должна просто считать побыстрее, и не засорять голову всякими программистскими моделями и прочей ерундой. Целостное, не вербализованное, во многом основанное на привычке представление об однопроцессорной машине у них есть, любое другое – крайне нежелательно, почти враждебно.
Как поступает такой пользователь, осваивая, например, DVM? Пролистав описание до первого примера программы, он вставляет в некоторые места своей программы некоторое количество директив распараллеливания, похожих на те, что были в примере. При этом, например, один и тот же массив может оказаться в вызывающей программе локальным, а в подпрограмме – распределенным по процессорам. Полученная программа запускается, в надежде, что если некоторое количество директив в нее вставлено, то некоторое ускорение, по сравнению с однопроцессорным вариантом, должно получиться. Получив вместо этого замедление в 10000 раз, пользователь бывает искренне возмущен. Замечание, что написанная лишь частично программа не способна частично ускориться, поскольку элементарно неправильна, отвергается как «демагогия» и «философствование». Указанная психологическая ловушка захлопывается тем скорее и надежнее, чем выше степень автоматизации, предлагаемая используемой технологией.
Для такого пользователя, в действительности, не важно, какой технологией пользоваться. При наличии достаточно сильной мотивации он может освоить любую, но двигаться будет строго индуктивно, отвергая всякую «простую и изящную», с точки зрения «системщика», общую логику, строя на конкретных примерах нерасчлененную и не вербализованную, на уровне привычки, модель новой для него сущности – параллельной вычислительной системы. Скорее всего, цель будет достигнута ручным применением технологии MPI, поскольку она элементарно проще сама по себе.
В значительной степени, именно для этой категории пользователей был придуман рассмотренный нами выше проект МВС – 900, с ее «портретным» сходством с настоящим кластером, с возможностью как угодно долго экспериментировать, не тратя на это дефицитные ресурсы.
6.8. Немного о технике реализации MPI.
В вычислительных кластерах используются как коммерческие, поставляемые с конкретным связным оборудованием, реализации MPI, так и свободно распространяемые в исходных текстах. И с теми, и с другими периодически возникают серьезные проблемы. Приведем два примера.
Первый пример. Большинство свободно распространяемых реализаций MPI по ряду причин плохо совмещают обмены, запущенные без ожидания конца, со счетом. Обычно это совмещение возможно лишь для сообщений сравнительно небольшой длины. Более длинные обмены, запущенные без ожидания конца, реализованы так, что начинают физически выполняться лишь при проверке их завершения. Такой технике реализации есть конкретное объяснение, связанное, в основном, с требованием переносимости свободно распространяемых реализаций на разные платформы. С точки зрения применения это – очень серьезный недостаток, препятствующий снижению накладных расходов на коммуникации путем их совмещения во времени со счетом.
Второй пример. Пусть возникла необходимость построить, основываясь на GRID – технологиях, единую MPI – систему из двух суперкомпьютеров, хотя бы один из которых оснащен коммерческой реализацией MPI (то есть такой, что исходные тексты отсутствуют). При этом имеющаяся коммерческая реализация – очень эффективная, и хотелось бы, чтобы «мета – MPI», распространенный на единое поле узлов из двух установок, в пределах «коммерческой» части работал так же эффективно, как и раньше. Сходная проблема возникает, в действительности, даже для свободно распространяемых реализаций, в случае, когда хотя бы одна из установок оснащена сетью, отличной от Ethernet. Как мы помним, реализации MPI для таких сетей обычно опираются на механизмы, отличные от tcp/ip, в то время как «связку» из двух установок, очевидно, придется делать на tcp/ip. «Связка» не создаст проблем, если на общем поле из двух установок будет работать единая реализация MPI на базе tcp/ip, но в этом случае мы потеряем эффективность работы внутри каждой из двух установок. Учитывая, что «связка» и сама по себе эффективности отнюдь не добавляет, хорошим такое решение не назовешь.
Оба приведенных примера сводятся, в конечном итоге, к единой инженерной задаче: как можно добавить недостающие свойства (подлинную асинхронность, «связку», шифрование, или, например, систему отладки и профилирования) к имеющейся реализации MPI, не перерабатывая ее, и даже не транслируя заново саму библиотеку?
Исторически эта проблема встала перед разработчиками MPI впервые в связи с необходимостью добавлять к имеющимся реализациям MPI средства профилирования и отладки. Хотелось бы иметь возможность создать «обертку» для каждой функции MPI, которая работает так:
- принимает все аргументы данной функции,
- делает нечто (например, засекает время),
- вызывает данную функцию,
- делает еще что – то, например, еще раз засекает время, вычисляет время работы функции и что – то с ним делает,
- возвращает все результаты, которых вызывающая программа ждет от данной функции.
Понятно, что в эту логику укладывается не только измерение времени, но и, например, построение «связки» из двух систем без нарушения целостности MPI в каждой из них, и корректное взаимодействие с системой дополнительного обеспечения асинхронности, если мы захотим ее построить.
Во всем этом не было бы ни малейшей проблемы, если бы не еще одно, совершенно естественное, требование: и «обертка», и исходная функция MPI должны называться одинаково! Ведь тексты не только самой библиотеки MPI, но и прикладной программы могут быть не доступны для повторной трансляции.
Решение этой проблемы основывается на так называемых «слабых символах (weak symbols)» - некогда дополнительной, а сегодня – практически обязательной возможности транслятора C и компоновщика (линкера).
От транслятора требуется наличие директивы #pragma weak, позволяющей снабдить имя функции синонимом, объявив его «слабым». Например, функция может иметь основное имя “abc” и слабый синоним “def”, обозначающие одну и ту же точку входа в функцию. Реализация такой возможности ничего не стоит разработчику транслятора, поскольку на уровне формата объектного модуля этот аппарат всегда был. Например, на ассемблере любая функция может иметь как угодно много равноправных названий. На Фортране запись синонимов, кстати, также допускается. Мы, впрочем, хотим, чтобы каждый из синонимов не просто обозначал одну и ту же функцию, но и имел дополнительный атрибут – признак «слабости».
Для вызывающей программы наличие синонима означает, что функцию можно с равным успехом вызвать и как “abc(…)”, и как “def(…)”, причем работать будет в обоих случаях один и тот же код.
От компоновщика – линкера – требуется лишь одна, тоже довольно простая, возможность. Если, в процессе связывания объектных модулей в загрузочный, компоновщик встречает повторное определение имени функции, то есть функцию, имя одного из синонимов которой уже встречалось, и вновь встреченный синоним – «слабый», то это – не ошибка. Слабый синоним можно молча игнорировать, а функцию – связывать обычным порядком, если она вызвана по другому имени.
Информация о работе Технологии высокопроизводительных вычислений