DVM отладчик
Предварительный дизайн
* Октябрь, 1999 *

- дата последнего обновления 02.10.00 -


Оглавление

1 Функции DVM отладчика

1.1 Метод динамического контроля DVM-указаний
1.2 Типы выявляемых ошибок
1.3 Метод сравнения результатов выполнения

2 Состав DVM отладчика
3 Подход и принципы реализации DVM-отладчика

3.1 Метод контроля DVM-указаний

3.1.1 Контроль инициализации переменных и элементов массивов
3.1.2 Контроль доступа к элементам распределенного массива
3.1.3 Контроль приватных и неизменяемых переменных
3.1.4 Контроль редукционных переменных
3.1.5 Контроль использования буфера удаленных элементов

3.2 Метод сравнения результатов выполнения

3.2.1 Накопление трассировки
3.2.2 Сравнение результатов
3.2.3 Контроль редукционных операций


1 Функции DVM отладчика

DVM отладчик предназначен для отладки DVM-программ (написанных на языках Fortran-DVM и C-DVM). Для отладки DVM-программ используется следующий подход. Сначала программа отлаживается на рабочей станции как последовательная программа с использованием обычных средств отладки. Затем программа выполняется на той же рабочей станции в специальном режиме проверки DVM-директив. На третьем этапе программа выполняется на параллельном компьютере в специальном режиме сравнения промежуточных результатов выполнения с эталонными результатами (например, с результатами последовательного выполнения).

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

В общем случае можно выделить следующие четыре класса ошибок:

Ошибки первого класса выявляются при компиляции.

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

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

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

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

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

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

1.1 Метод динамического контроля DVM-указаний

Динамический контроль основан на моделировании параллельного выполнения DVM-программы на одном процессоре. Использование данного метода может существенно замедлить выполнение программы и требует больших объемов дополнительной памяти. Поэтому, он может применяться только для программы со специально подобранными тестовыми данными ограниченного объема.

1.2 Типы выявляемых ошибок

Средства динамического контроля позволяют выявлять следующие типы ошибок:

  1. Необъявленная зависимость по данным в параллельном цикле или между параллельными задачами.
  2. Чтение неинициализированных переменных.
  3. Модификация в параллельной конструкции нераспределенных переменных, которые не являются редукционными или приватными.
  4. Использование редукционных переменных после запуска асинхронной редукции, но до ее завершения.
  5. Выход за пределы распределенного массива.
  6. Необъявленный доступ к нелокальным элементам распределенного массива.
  7. Запись в теневые грани распределенного массива.
  8. Чтение теневых элементов массива до завершения операции их обновления.

1.3 Метод сравнения результатов выполнения

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

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

2 Состав DVM отладчика

Отладчик можно разбить на две, четко выраженные, системы: динамический контроль и сравнение результатов выполнения.

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

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

Динамический контроль включает в себя следующие компоненты:

Система сравнения результатов вычислений включает в себя следующие компоненты:

3 Подход и принципы реализации DVM-отладчика

3.1 Метод контроля DVM-указаний

Все данные, которые могут использоваться в DVM-программе, разделяются на следующие классы:

Исходя из этих классов данных, строятся алгоритмы проверки.

3.1.1 Контроль инициализации переменных и элементов массивов

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

3.1.2 Контроль доступа к элементам распределенного массива

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

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

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

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

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

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

Состояние “обновление не выполнялось” устанавливается при модификации любого экспортируемого элемента распределенного массива. Это обеспечивает контроль некорректного доступа к теневым элементам до начала выполнения следующей операции обновления теневых граней.

3.1.3 Контроль приватных и неизменяемых переменных

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

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

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

3.1.4 Контроль редукционных переменных

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

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

Замечание. Неверная спецификация редукционной операции (например, задание MIN вместо MAX) не обнаруживается при данном методе, но будет обнаружена при использовании метода сравнения результатов выполнения.

3.1.5 Контроль использования буфера удаленных элементов

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

3.2 Метод сравнения результатов выполнения

3.2.1 Накопление трассировки

При накоплении результатов вычислений в файл записывается следующая информация:

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

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

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

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

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

3.2.2 Сравнение результатов

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

При последующем выполнении программы, трассируемые события сравниваются с эталонными.

При этом, учитываются следующие особенности выполнения программы в параллельном режиме:

3.2.3 Контроль редукционных операций

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

Для контроля правильности спецификации редукционной операции, вычисление редукционной операции производится двумя различными способами. Первый способ – это стандартный метод вычисления редукции. Сначала на каждом процессоре выполняются отображенные на него витки параллельного цикла или параллельные задачи, в которых в соответствии с заданным программистом алгоритмом будет вычислен частичный результат редукции. Конечный результат редукционной операции вычисляется библиотекой Lib-DVM путем объединения всех частичных результатов в соответствии с описанной программистом редукционной операцией. Если программа выполняется последовательно (или параллельно, но на одном процессоре), то редукционная операция целиком будет вычислена в соответствии с заданным программистом алгоритмом.

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

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