§17. Отладка и профилирование параллельных приложений

Другим важным этапом в технологическом цикле разработки параллельных программ является трассировка и профилирование. В процессе компиляции трассировку можно задать посредством опций: -mpitrace. При запуске параллельного приложения на стандартное устройство вывода поступает текстовая информация о последовательности вызовов MPI-функции в формате:

[номер процесса] старт функции…

[номер процесса] завершение функции…

Для более детального разбора полученной информации удобнее перенаправить вывод в файл, например trace.log(пример файла приведен на рис. 8).

Зачастую простой разбор этого файла помогает обнаружить ошибки в параллельных программах. Во-первых, каждая функция в случае успешного выполнения порождает пару записей в файле: “старт” и ”завершение” функции, в случае неуспешного выполнения выведется информация лишь о старте этой функции. Во-вторых, некоторые функции (например,MPI_Send,MPI_Recv) выводят параметры их запуска (например, count – количество отправляемых или получаемых элементов, dest – адрес получателя, source – адрес отправителя, tag– идентификатор сообщения и т.д.), которые могут помочь разобраться в правильности использования функций для посылки и приема сообщений.

Опция –mpitraceпомогает отследить ошибки, появляющиеся при неправильном использовании функций.

Производительность MPI-приложений можно оценить путем анализа файла *.clog, порождаемого, если на этапе компиляции будет задана опция –mpilog.

В результате выполнения параллельного приложения создается файл (например,example.clog), который необходимо сконвертировать в файл example.slog утилитой MPI clog2slog. Получившийся в результате файл пригоден для визуального просмотра с помощью утилиты logviewer.

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

 

Starting MPI_Init...

Starting MPI_Init...

Starting MPI_Init...

Starting MPI_Init...

[0] Ending MPI_Init

[0] Starting MPI_Comm_size...

[0] Ending MPI_Comm_size

[0] Starting MPI_Comm_rank...

[0] Ending MPI_Comm_rank

 Hello,  0 processor of  4...work

[0] Starting MPI_Send with count=4, dest=1, tag=1...

[1] Ending MPI_Init

[2] Ending MPI_Init

[3] Ending MPI_Init

[0] Ending MPI_Send

[0] Starting MPI_Recv with count=4, source=3, tag=1...

[1] Starting MPI_Comm_size...

[1] Ending MPI_Comm_size

[1] Starting MPI_Comm_rank...

[1] Ending MPI_Comm_rank

 Hello,  1 processor of  4...work

[1] Starting MPI_Recv with count=4, source=0, tag=1...

[1] Ending MPI_Recv from 0 with tag 1

[1] Starting MPI_Send with count=0, dest=2, tag=1...

[1] Ending MPI_Send

[1] Starting MPI_Finalize...

[2] Starting MPI_Comm_size...

[2] Ending MPI_Comm_size

[2] Starting MPI_Comm_rank...

[2] Ending MPI_Comm_rank

 Hello,  2 processor of  4...work

[2] Starting MPI_Recv with count=4, source=1, tag=1...

[3] Starting MPI_Comm_size...

[3] Ending MPI_Comm_size

[3] Starting MPI_Comm_rank...

[3] Ending MPI_Comm_rank

 Hello,  3 processor of  4...work

[3] Starting MPI_Recv with count=4, source=2, tag=1...

Рис. 8. Пример трассировки параллельной программы