Россия, г. Саранск |
Отладка параллельных MPI программ в среде Microsoft Visual Studio 2005
8.4.2. Задание 2 - Использование точек остановки
Мы уже использовали точки остановки в предыдущих пунктах. В данном задании мы рассмотрим вопросы использования условных точек остановки, то есть точек остановки, позволяющих указать условия, которые должны выполняться для приостановки работы программы. Использование точек остановки с условиями в некоторых случаях существенно более эффективно, так как позволяет программисту более точно указать необходимые моменты остановки процесса выполнения параллельной программы.
- Откройте проект параллельного вычисления числа Пи ( parallelpi ) и выполните настройки, необходимые для проведения отладки MPI программ (если это еще не было сделано), указав число запускаемых процессов равное 2. Откройте файл " parallelpi.cpp " (дважды щелкните на файле в окне " Solution Explorer ").
- Поставьте точку остановки на любой строке текста программы (например, на строке с " MPI_Init ") и запустите отладку. По достижении точки остановки выполнение процессов приостановится.
- Вы можете устанавливать точки остановки, которые будут приостанавливать работу только тех процессов (или потоков), которые Вам нужны. Для этого поставьте другую точку остановки ниже по тексту программы, щелкните по красному значку новой точки остановки правой кнопкой мыши и выберите в открывшемся меню пункт " Filter ".
- В открывшемся окне можно указать те процессы и потоки, выполнение которых должно быть прервано по достижении указанной точки остановки. Кроме того, можно указать имя вычислительного узла, на котором точка остановки будет приостанавливать процессы (параметр используется в случае, если часть процессов отлаживаемой задачи запущена на удаленных узлах). Список названий параметров указан в подсказке на окне. При написании логических выражений можно использовать логические функции " и " (" AND ", " & ") , " или " (" OR ", " || "), " не " (" NOT ", " !"). Например, для указания того, что приостановить работу должен только один процесс, используется выражение " ProcessId = <идентификатор процесса> ", где идентификатор процесса можно узнать в окне " Processes ". Нажмите " OK " для сохранения условия.
- Кроме того, Вы можете указать условия на значения переменных, которые должны выполняться для приостановки работы программы. Щелкните правой кнопкой мыши на точке остановки и выберите пункт " Conditions ".
- В открывшемся окне Вы можете указать условия 2 типов:
- Условие первого типа - приостановить работу программы, если выполнены условия. Для использования этого типа условий установите флаг " Is true " и введите условное выражение в поле " Conditions ". При вводе выражения используется синтаксис, принятый в C++. Так, для остановки только процесса с индексом 0 следует ввести условие " MyID == 0 ".
- Условие второго типа - приостановить работу программы, если значение введенного выражения (необязательно логического) изменилось с момента предыдущего выполнения строки, на которой находится точка остановки. Для использования этого типа условий установите флаг " Has changed ".
- Поставьте флаг " Is true ; и введите условие остановки " MyID == 0 ". Нажмите " OK " для сохранения введенного условия.
8.4.3. Задание 3 - Особенности отладки параллельных MPI программ
Отладчик параллельных MPI программ в Microsoft Visual Studio появился впервые в версии Visual Studio 2005. Однако компиляцию и отладку MPI программ можно производить и в более ранних версиях среды разработки. Обычными приемами в случае отсутствия истинной поддержки MPI со стороны отладчика являются следующие:
- Использование текстовых сообщений, выводимых в файл или на экран, со значениями интересуемых переменных и/или информацией о том, какой именно участок программы выполняется. Такой подход часто называют " printf отладкой " (" printf debugging "), так как чаще всего для вывода сообщений на консольный экран используется функция " printf ". Данный подход хорош тем, что он не требует от программиста специальных навыков работы с каким-либо отладчиком, и при последовательном применении позволяет найти ошибку. Однако для того, чтобы получить значение очередной переменной, приходится каждый раз писать новый код для вывода сообщений, перекомпилировать программу и производить новый запуск. Это занимает много времени. Кроме того, добавление в текст программы нового кода может приводить к временному исчезновению проявлений некоторых ошибок.
- Использование последовательного отладчика. Так как MPI задача состоит из нескольких взаимодействующих процессов, то для отладки можно запустить несколько копий последовательного отладчика, присоединив каждую из них к определенному процессу MPI задания. Данный подход позволяет в некоторых случаях более эффективно производить отладку, чем при использовании текстовых сообщений. Главным недостатком подхода является необходимость ручного выполнения многих однотипных действий. Представьте, например, необходимость приостановки 32 процессов MPI задания: в случае использования последовательного отладчика придется переключиться между 32 процессами отладчика и вручную дать команду приостановки.
Параллельный отладчик Microsoft Visual Studio 2005 лишен указанных недостатков и позволяет существенно экономить время на отладку. Это достигается за счет того, что среда рассматривает все процессы одной MPI задачи как единую параллельно выполняемую программу, максимально приближая отладку к отладке последовательных программ. К числу особенностей параллельной отладки относятся уже рассмотренное окно " Processes ", позволяющего переключаться между параллельными процессами, а также дополнительные настройки среды (см. задание 2 упражнения 1).
8.4.4. Задание 4 - Обзор типичных ошибок при написании параллельных MPI программ
Все ошибки, которые встречаются при последовательном программировании, характерны также и для параллельного программирования. Однако кроме них есть ряд специфических типов ошибок, обусловленных наличием в MPI задаче нескольких взаимодействующих процессов. Дополнительные сложности в разработке параллельных программ обуславливают повышенные требования к квалификации программистов, реализующих параллельные версии алгоритмов. И хотя перечислить все типы ошибок, которые могут возникнуть при программировании с использованием технологии MPI, крайне затруднительно, дадим краткую характеристику ряду наиболее характерных ошибок, преследующих начинающих разработчиков. К числу наиболее типичных ошибок при параллельном программировании с использованием технологии MPI следует отнести:
- Взаимная блокировка при пересылке сообщений. Предположим, что n процессов передают информацию друг другу по цепочке так, что процесс с индексом i передает информацию процессу с индексом i+1 (для индексов i=0,…,n-2 ), а процесс с индексом n-1 передает информацию процессу с индексом 0. Передача осуществляется с использованием функции отправки сообщений MPI_Send и функции приема сообщений MPI_Recv, при этом каждый процесс сначала вызывает MPI_Send, а затем MPI_Recv. Функции являются блокирующими, то есть MPI_Send возвратит управление только тогда, когда передача будет завершена, или когда сообщение будет скопировано во внутренний буфер. Таким образом, стандарт допускает возможность, что функции отправки сообщения вернут управление только после того, как передача будет завершена. Но передача не может завершиться, пока принимающий процесс не вызовет функцию MPI_Recv. А функция MPI_Recv будет вызвана, в свою очередь, только после того, как процесс завершит отправку своего сообщения. Так как цепочка передачи сообщений замкнута, отправка сообщений может не завершиться никогда, потому что каждый процесс будет ожидать завершения отправки своего сообщения, и никто не вызовет функцию приема сообщения. Избежать подобной блокировки можно, например, вызывая на процессах с четными индексами сначала MPI_Send, а затем MPI_Recv, а на процессах с нечетными индексами - в обратной порядке. Несмотря на очевидность ошибки, ее часто допускают, так как при небольших сообщениях высока вероятность, что сообщения уберутся во внутренние структуры библиотеки, функция отправки сообщения вернет управление, и ошибка не даст о себе знать.
- Освобождение или изменение буферов, используемых при неблокирующей пересылке. При вызове неблокирующих функций возврат из них происходит немедленно, а адреса массивов с сообщениями запоминаются во внутренних структурах библиотеки MPI. При непосредственной передаче сообщений по сети, которая будет выполнена в отдельном потоке, происходит обращение к исходному массиву с сообщением, поэтому важно, чтобы этот участок памяти не был удален или изменен до окончания передачи (установить, что передача завершена можно вызовом специальных функций). Однако часто об этом правиле забывают, что приводит к непредсказуемому поведению программы. Такого рода ошибки являются одними из самых сложных для отладки,
- Несоответствие вызовов функций передачи и приема сообщений. Важно следить, чтобы каждому вызову функции отправки сообщения соответствовал вызов функции приема и наоборот. Однако в том случае, когда число передач заранее не известно, а определяется в ходе вычислений, бывает легко ошибиться и не обеспечить нужных гарантий выполнения данного условия. К этому же типу ошибок можно отнести вызов функций передачи и приема сообщений с несоответствующими тэгами идентификации сообщений.
8.5. Контрольные вопросы
- Как локально протестировать работоспособность параллельной программы, разработанной для использования с библиотекой MS MPI до запуска ее на кластере? Какое программное обеспечение должно быть установлено для этого на Вашей рабочей станции?
- Перечислите и дайте краткое описание основным окнам среды Microsoft Visual Studio 2005, используемым при отладке?
- Что такое и для чего используются точки остановки? Что такое условные точки остановки?
- В чем принципиальная особенность отладки параллельных MPI программ в среде Microsoft Visual Studio 2005?
- Какие типичные ошибки при программировании с использованием технологии MPI Вы знаете?