У меня есть программа MPI, которая компилируется и запускается, но я хотел бы пройти через нее, чтобы убедиться, что ничего необычного не происходит. В идеале мне нужен простой способ присоединить GDB к какому-либо конкретному процессу, но я не совсем уверен, возможно ли это и как это сделать. Альтернативой может быть запись отладочного вывода каждого процесса в отдельный файл журнала, но на самом деле это не дает такой же свободы, как отладчик.
Есть ли подходы лучше? Как вы отлаживаете программы MPI?

«Стандартный» способ отладки программ MPI - использование отладчика, который поддерживает эту модель выполнения.
В UNIX говорят, что TotalView хорошо поддерживает MPI.
Как кто-то еще сказал, TotalView является стандартом для этого. Но это будет стоить вам руки и ноги.
На сайте OpenMPI есть отличный FAQ по отладке MPI. Пункт № 6 в FAQ описывает, как присоединить GDB к процессам MPI. Прочтите все, есть несколько отличных советов.
Если вы обнаружите, что у вас слишком много процессов, которые нужно отслеживать, проверьте Инструмент анализа трассировки стека (STAT). Мы используем это в Ливерморе для сбора трассировок стека потенциально сотен тысяч запущенных процессов и интеллектуального представления их пользователям. Это не полнофункциональный отладчик (полнофункциональный отладчик никогда не масштабируется до 208 тыс. Ядер), но он скажет вам, какие группы процессов делают то же самое. Затем вы можете пройти через представителя каждой группы в стандартном отладчике.
Так что я продолжу и проголосую за ответ @Mark здесь. ДДТ - это хорошо. Попробуйте тоже. TotalView теперь также интегрируется со STAT, поэтому, если на вашем сайте есть установка TotalView, вы также можете попробовать это. LLNL поддерживает TotalView и DDT, и приятно, что у TotalView наконец-то появилась жесткая конкуренция.
Хочу добавить ссылку на FAQ по отладке MPI (open-mpi.org/faq/?category=debugging#serial-debuggers). В частности, пункт 6 - хороший, быстрый и простой (достаточно даже для меня!) Способ хотя бы отладки отдельного процесса.
Шаги в №6 на странице часто задаваемых вопросов отлично сработали для меня и помогли разобраться в моей проблеме. Большое спасибо за это.
http://github.com/jimktrains/pgdb/tree/master - это утилита, которую я написал для этого. Есть несколько документов, и не стесняйтесь писать мне в личку, если у вас возникнут вопросы.
Вы в основном вызываете Perl-программу, которая обертывает GDB и направляет его ввод-вывод на центральный сервер. Это позволяет GDB работать на каждом хосте, а вы можете получить к нему доступ на каждом хосте с терминала.
Спасибо! Я обязательно проверю это в следующий раз, когда буду работать в MPI.
Я использую этот небольшой доморощенный метод для присоединения отладчика к процессам MPI - вызовите следующую функцию DebugWait () сразу после MPI_Init () в вашем коде. Теперь, когда процессы ждут ввода с клавиатуры, у вас есть время подключить к ним отладчик и добавить точки останова. Когда вы закончите, введите один символ, и вы готовы к работе.
static void DebugWait(int rank) {
char a;
if (rank == 0) {
scanf("%c", &a);
printf("%d: Starting now\n", rank);
}
MPI_Bcast(&a, 1, MPI_BYTE, 0, MPI_COMM_WORLD);
printf("%d: Starting now\n", rank);
}
Конечно, вы можете скомпилировать эту функцию только для отладочных сборок.
MPI требовало большинства отладочных операторов, которые я когда-либо писал, даже для простого кода. (смеется) Это может быть очень полезно.
Это решение аналогично пункту 6 здесь (open-mpi.org/faq/?category=debugging#serial-debuggers). Вы можете немного улучшить свой код, добавив gethostname(hostname, sizeof(hostname)); printf("PID %d on host %s ready for attach\n", getpid(), hostname);. Затем вы подключаетесь к процессу, набрав rsh <hostname_from_print_statement> и, наконец, gdb --pid=<PID_from_print_statement>.
Я провожу отладку, связанную с MPI, с трассировкой журнала, но вы также можете запустить gdb, если используете mpich2: MPICH2 и gdb. Этот метод является хорошей практикой, когда вы имеете дело с процессом, который сложно запустить из отладчика.
Изменена на другую ссылку, которая не работает, добавлены комментарии.
Также есть мой инструмент с открытым исходным кодом, padb, который помогает в параллельном программировании. Я называю его «Инструмент проверки работы», поскольку он функционирует не только как отладчик, но также может функционировать, например, как параллельная программа, подобная верхней. Запустите в режиме «Полный отчет», он покажет вам стек трассировки каждого процесса в вашем приложении вместе с локальными переменными для каждой функции по каждому рангу (при условии, что вы скомпилированы с -g). Он также покажет вам «очереди сообщений MPI», то есть список ожидающих отправки и получения для каждого ранга в задании.
Помимо отображения полного отчета, также можно указать padb увеличивать отдельные фрагменты информации в задании. Существует множество опций и элементов конфигурации для управления отображаемой информацией. Более подробную информацию см. На веб-странице.
Я нашел gdb весьма полезным. Я использую это как
mpirun -np <NP> xterm -e gdb ./program
Это запускает окна xterm, в которых я могу делать
run <arg1> <arg2> ... <argN>
обычно работает нормально
Вы также можете упаковать эти команды вместе, используя:
mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...]
Как я могу отправить один и тот же ввод на все NP gdb xterms? Например, я хочу добавить по две точки останова к каждому процессу, а есть 16 процессов. Есть ли альтернатива xterm для этого? Можем ли мы объединить сеансы в один экземпляр screen, tmux или Terminator Криса Джонса?
@osgx Вы можете сделать это, сохранив команды («break xxx», «break yyy», «run») в <file> и передав -x <file> в gdb.
но я обнаружил ошибку, сообщение об ошибке: «Ошибка execvp в файле xterm (нет такого файла или каталога)»
когда я пробую это с помощью jdb и OpenMPI, это не работает, т.е. каждый экземпляр jdb видит num_ranks из 1 вместо того, что задано аргументу -np. есть идеи почему?
http://valgrind.org/ nuf сказал
Более конкретная ссылка: Отладка параллельных программ MPI с помощью Valgrind
Valgrind - это не то же самое, что интерактивный отладчик, но приятно знать, что он работает с MPI.
Команда для присоединения gdb к процессу mpi неполная, она должна быть
mpirun -np <NP> xterm -e gdb ./program
Краткое обсуждение mpi и gdb можно найти здесь
Как уже упоминалось, если вы работаете только с горстка процессов MPI, вы можете попробовать использовать несколько сеансов gdb, грозный Valgrind или развернуть собственное решение printf / logging.
Если вы используете больше процессов, чем это, вам действительно нужен правильный отладчик. OpenMPI FAQ рекомендует как Аллинея ДДТ, так и TotalView.
Работаю на Аллинея ДДТ. Это полнофункциональный графический отладчик исходного кода, поэтому вы можете:
...и так далее. Если вы использовали Eclipse или Visual Studio, вы будете как дома.
Мы добавили несколько интересных функций специально для отладки кода параллельный (будь то MPI, многопоточный или CUDA):
Скалярные переменные автоматически сравниваются во всех процессах:

(source: allinea.com)
Вы также можете отслеживать и фильтровать значения переменных и выражений по процессам и времени:

Он широко используется на сайтах топ500 HPC, таких как ORNL, NCSA, LLNL, Юлих et. al.
Интерфейс довольно шустрый; мы рассчитали пошаговое выполнение и объединение стеков и переменных 220 000 процессов за 0,1 с в рамках приемочного тестирования кластера Jaguar в Ок-Ридже.
@tgamblin упомянул отличный СТАТИСТИКА, который интегрируется с Аллинея ДДТ, как и несколько других популярных проектов с открытым исходным кодом.
Многие из публикаций здесь посвящены GDB, но не упоминают, как подключиться к процессу из запуска. Очевидно, ко всем процессам можно прикрепить:
mpiexec -n X gdb ./a.out
Но это крайне неэффективно, так как вам придется подскакивать, чтобы запустить все ваши процессы. Если вы просто хотите отладить один (или небольшое количество) процессов MPI, вы можете добавить его как отдельный исполняемый файл в командной строке с помощью оператора ::
mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out
Теперь только один из ваших процессов получит GDB.
Я могу использовать "mpiexec -n X gdb ./a.out", но есть ли способ использовать режим gdb -tui?
Использование screen вместе с gdb для отладки приложений MPI отлично работает, особенно если xterm недоступен или вы имеете дело с несколькими процессорами. На пути к сопутствующему поиску stackoverflow было много подводных камней, поэтому я воспроизведу свое решение полностью.
Во-первых, добавьте код после MPI_Init, чтобы распечатать PID и остановить программу, чтобы ждать, пока вы присоединитесь. Стандартное решение кажется бесконечным циклом; В конце концов я остановился на raise(SIGSTOP);, который требует дополнительного вызова continue для выхода в gdb.
}
int i, id, nid;
MPI_Comm_rank(MPI_COMM_WORLD,&id);
MPI_Comm_size(MPI_COMM_WORLD,&nid);
for (i=0; i<nid; i++) {
MPI_Barrier(MPI_COMM_WORLD);
if (i==id) {
fprintf(stderr,"PID %d rank %d\n",getpid(),id);
}
MPI_Barrier(MPI_COMM_WORLD);
}
raise(SIGSTOP);
}
После компиляции запустите исполняемый файл в фоновом режиме и перехватите stderr. Затем вы можете grep файл stderr для некоторого ключевого слова (здесь буквальный PID), чтобы получить PID и рейтинг каждого процесса.
MDRUN_EXE=../../Your/Path/To/bin/executable
MDRUN_ARG = "-a arg1 -f file1 -e etc"
mpiexec -n 1 $MDRUN_EXE $MDRUN_ARG >> output 2>> error &
sleep 2
PIDFILE=pid.dat
grep PID error > $PIDFILE
PIDs=(`awk '{print $2}' $PIDFILE`)
RANKs=(`awk '{print $4}' $PIDFILE`)
Сессия gdb может быть присоединена к каждому процессу с помощью gdb $MDRUN_EXE $PID. Выполнение этого в рамках сеанса экрана обеспечивает легкий доступ к любому сеансу gdb. -d -m запускает экран в отсоединенном режиме, -S "P$RANK" позволяет вам присвоить имя экрану для облегчения доступа в дальнейшем, а опция -l для bash запускает его в интерактивном режиме и предотвращает немедленный выход из gdb.
for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
PID=${PIDs[$i]}
RANK=${RANKs[$i]}
screen -d -m -S "P$RANK" bash -l -c "gdb $MDRUN_EXE $PID"
done
После того, как gdb запустился на экранах, вы можете ввести сценарий ввода на экраны (чтобы вам не приходилось вводить каждый экран и вводить одно и то же) с помощью команды screen -X stuff. В конце команды требуется перевод строки. Здесь -S "P$i" получает доступ к экранам с использованием ранее данных имен. Параметр -p 0 имеет решающее значение, в противном случае команда периодически завершается ошибкой (в зависимости от того, подключены ли вы ранее к экрану).
for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
screen -S "P$i" -p 0 -X stuff "set logging file debug.$i.log
"
screen -S "P$i" -p 0 -X stuff "set logging overwrite on
"
screen -S "P$i" -p 0 -X stuff "set logging on
"
screen -S "P$i" -p 0 -X stuff "source debug.init
"
done
На этом этапе вы можете подключиться к любому экрану с помощью screen -rS "P$i" и отсоединить с помощью Ctrl+A+D. Команды могут быть отправлены во все сеансы gdb по аналогии с предыдущим разделом кода.
Другое решение - запустить ваш код в SMPI, смоделированном MPI. Это проект с открытым исходным кодом, в котором я участвую. Каждый ранг MPI будет преобразован в потоки одного и того же процесса UNIX. Затем вы можете легко использовать gdb для пошагового ранжирования MPI.
SMPI предлагает другие преимущества для изучения приложений MPI: ясность (вы можете наблюдать за всеми частями системы), воспроизводимость (несколько прогонов приводят к одному и тому же поведению, если вы не укажете это), отсутствие ошибок (поскольку моделируемая платформа остается разной). от хоста) и т. д.
Для получения дополнительной информации см. эта презентация или тот связанный ответ.
Если вы пользователь tmux, вам будет очень комфортно использовать скрипт Бенедикт Морбах: tmpi.
Первоисточник: https://github.com/moben/scripts/blob/master/tmpi
Вилка: https://github.com/Azrael3000/tmpi
С его помощью у вас есть несколько панелей (количество процессов), все синхронизированные (каждая команда копируется на все панели или процессы одновременно, поэтому вы экономите много времени по сравнению с подходом xterm -e). Более того, вы можете знать значения переменных в нужном вам процессе, просто выполняя print, без необходимости переходить на другую панель, это будет печатать на каждой панели значения переменной для каждого процесса.
Если вы не являетесь пользователем tmux, я настоятельно рекомендую попробовать и посмотреть.
Поскольку tmpi действительно фантастический и именно то, что я искал, я форкнул его в своей учетной записи github: github.com/Azrael3000/tmpi, так как оригинальный автор удалил его
Довольно простой способ отладки программы MPI.
В функции main () добавьте сон (some_seconds)
Запустите программу как обычно
$ mpirun -np <num_of_proc> <prog> <prog_args>
Программа запустится и перейдет в режим сна.
Таким образом, у вас будет несколько секунд, чтобы найти свои процессы с помощью ps, запустить gdb и присоединиться к ним.
Если вы используете какой-либо редактор, например QtCreator, вы можете использовать
Отладка-> Начать отладку-> Присоединиться к запущенному приложению
и найди там свои процессы.
Вы можете использовать код Visual Studio, который бесплатен и с ним намного проще работать, чем с xterm. Вы дублируете окно VS Code и вручную присоединяете отладчик к каждому процессу. Смотрите инструкцию в видео ниже:
По состоянию на 2010 год Аллинея ДДТ - это полнофункциональный отладчик, масштабируемый до более чем 208 тыс. Ядер.