Как отлаживать программу MPI?

129

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

Есть ли подходы лучше? Как вы отлаживаете программы MPI?

Джей Конрод
источник

Ответы:

62

Как кто-то сказал, TotalView - это стандарт для этого. Но это будет стоить вам руки и ноги.

На сайте OpenMPI есть отличный FAQ по отладке MPI . Пункт № 6 в FAQ описывает, как присоединить GDB к процессам MPI. Прочтите все, есть несколько отличных советов.

Если вы обнаружите, что у вас слишком много процессов, которые нужно отслеживать, попробуйте Stack Trace Analysis Tool (STAT) . Мы используем это в Ливерморе для сбора трассировок стека потенциально сотен тысяч запущенных процессов и интеллектуального представления их пользователям. Это не полнофункциональный отладчик (полнофункциональный отладчик никогда не масштабируется до 208 тыс. Ядер), но он скажет вам, какие группы процессов делают то же самое. Затем вы можете пройти через представителя от каждой группы в стандартном отладчике.

Тодд Гэмблин
источник
14
По состоянию на 2010 год Allinea DDT представляет собой полнофункциональный отладчик, масштабируемый до более чем 208 тыс. Ядер
Марк
1
Так что я продолжу и проголосую за ответ @Mark здесь. ДДТ хорош. Попробуйте тоже. TotalView теперь также интегрируется со STAT, поэтому, если на вашем сайте есть установка TotalView, вы также можете попробовать это. LLNL поддерживает TotalView и DDT, и приятно, что у TotalView наконец-то появилась жесткая конкуренция.
Тодд Гэмблин
Хочу добавить ссылку на FAQ по отладке MPI ( open-mpi.org/faq/?category=debugging#serial-debuggers ). В частности, пункт 6 - хороший, быстрый и простой (достаточно даже для меня!) Способ хотя бы отладки отдельного процесса.
Джефф
Шаги в № 6 на странице часто задаваемых вопросов отлично сработали для меня и помогли разобраться в моей проблеме. Большое спасибо за это.
Джон Дитон,
86

Я нашел 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] [...]
messenjah
источник
Как я могу отправить один и тот же ввод для всех NP gdb xterms? Например, я хочу добавить по две точки останова к каждому процессу, а есть 16 процессов. Есть ли альтернатива xterm для этого? Можем ли мы объединить сеансы в один экземпляр screen, tmux или Terminator Криса Джонса?
osgx
@osgx Вы можете сделать это, сохранив команды («break xxx», «break yyy», «run») <file>и передав их -x <file>в gdb.
eush77
но я обнаружил ошибку, сообщение об ошибке: «Ошибка execvp в файле xterm (нет такого файла или каталога)»
hitwlh
когда я пробую это с jdb и OpenMPI, это не работает, т.е. каждый экземпляр jdb видит num_ranks из 1 вместо того, что задано аргументу -np. есть идеи почему?
Мишель Мюллер
26

Многие из публикаций здесь посвящены 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?
hitwlh
16

Как уже упоминалось, если вы работаете только с несколькими процессами MPI, вы можете попробовать использовать несколько сеансов gdb , грозный valgrind или создать собственное решение printf / logging.

Если вы используете больше процессов, чем это, вам действительно понадобится правильный отладчик. В разделе часто задаваемых вопросов OpenMPI рекомендуются как Allinea DDT, так и TotalView .

Я работаю на ДДТ Аллинея . Это полнофункциональный графический отладчик исходного кода, так что да, вы можете:

  • Отладка или присоединение к (более 200k) процессам MPI
  • Шагайте и приостанавливайте их группами или индивидуально
  • Добавить точки останова, часы и точки трассировки
  • Выявление ошибок и утечек памяти

...и так далее. Если вы использовали Eclipse или Visual Studio, вы будете как дома.

Мы добавили несколько интересных функций специально для отладки параллельного кода (будь то MPI, многопоточный или CUDA):

  • Скалярные переменные автоматически сравниваются во всех процессах: (источник: allinea.com )Спарклайны, показывающие значения по процессам

  • Вы также можете отслеживать и фильтровать значения переменных и выражений по процессам и времени: Значения журнала точек трассировки с течением времени

Он широко используется среди 500 лучших сайтов HPC, таких как ORNL , NCSA , LLNL , Jülich et. и др.

Интерфейс довольно шустрый; мы рассчитали пошаговое выполнение и объединение стеков и переменных 220 000 процессов за 0,1 с в рамках приемочного тестирования кластера Jaguar в Ок-Ридже.

@tgamblin упомянул превосходный STAT , который интегрируется с Allinea DDT , как и несколько других популярных проектов с открытым исходным кодом.

отметка
источник
7

Если вы tmuxпользователь, вам будет очень комфортно пользоваться скриптом Бенедикта Морбаха :tmpi

Первоисточник: https://github.com/moben/scripts/blob/master/tmpi

Форк: https://github.com/Azrael3000/tmpi

С его помощью у вас есть несколько панелей (количество процессов), все синхронизированные (каждая команда копируется на все панели или процессы одновременно, поэтому вы экономите много времени по сравнению с xterm -eподходом). Более того, вы можете знать значения переменных в процессе, который вы хотите, просто выполняя printбез перехода на другую панель, это будет печатать на каждой панели значения переменной для каждого процесса.

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

GG1991
источник
2
Поскольку tmpi действительно фантастический и именно то, что я искал, я раздвоил его на своей учетной записи github: github.com/Azrael3000/tmpi, так как первоначальный автор удалил его
Azrael3000
6

http://github.com/jimktrains/pgdb/tree/master - это утилита, которую я написал для этого. Есть несколько документов, и не стесняйтесь писать мне в личку, если у вас возникнут вопросы.

Вы в основном вызываете Perl-программу, которая обертывает GDB и направляет его ввод-вывод на центральный сервер. Это позволяет GDB работать на каждом хосте, а вам получать к нему доступ на каждом хосте с терминала.

Джим Кинер
источник
Спасибо! Я обязательно проверю это в следующий раз, когда буду работать в MPI.
Джей Конрод,
5

Использование 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 по аналогии с предыдущим разделом кода.

user3788566
источник
3

Также есть мой инструмент с открытым исходным кодом, padb, который помогает в параллельном программировании. Я называю это «Инструмент проверки работы», поскольку он работает не только как отладчик, но также может функционировать, например, как параллельная программа, подобная верхней. Запустите в режиме «Полный отчет», он покажет вам стек трассировки каждого процесса в вашем приложении вместе с локальными переменными для каждой функции по каждому рангу (при условии, что вы скомпилированы с -g). Он также покажет вам «очереди сообщений MPI», то есть список ожидающих отправки и получения для каждого ранга в задании.

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

PADB


источник
3

«Стандартный» способ отладки программ MPI - использование отладчика, который поддерживает эту модель выполнения.

Говорят, что в UNIX TotalView хорошо поддерживает MPI.

Сообщество
источник
2

Я использую этот небольшой доморощенный метод для присоединения отладчика к процессам 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 требовал большинства отладочных операторов, которые я когда-либо писал, даже для простого кода. (смеется) Это может быть очень полезно.
Troggy
3
Это решение аналогично пункту 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>.
Джефф
2

Команда для присоединения gdb к процессу mpi неполная, она должна быть

mpirun -np <NP> xterm -e gdb ./program 

Краткое обсуждение mpi и gdb можно найти здесь

akintayo
источник
2

Довольно простой способ отладки программы MPI.

В функции main () добавьте сон (some_seconds)

Запустите программу как обычно

$ mpirun -np <num_of_proc> <prog> <prog_args>

Программа запустится и перейдет в режим сна.

Таким образом, у вас будет несколько секунд, чтобы найти ваши процессы с помощью ps, запустить gdb и присоединиться к ним.

Если вы используете какой-либо редактор, например QtCreator, вы можете использовать

Отладка-> Начать отладку-> Присоединить к запущенному приложению

и найди там свои процессы.

незнакомец
источник
1

Я выполняю некоторую отладку, связанную с MPI, с трассировкой журнала, но вы также можете запустить gdb, если используете mpich2: MPICH2 и gdb . Этот метод является хорошей практикой, когда вы имеете дело с процессом, который сложно запустить из отладчика.

Джим Ханзикер
источник
Изменена на другую ссылку, которая не работает, добавлены комментарии.
Джим Ханзикер,
0

Другое решение - запустить ваш код в SMPI, смоделированном MPI. Это проект с открытым исходным кодом, в котором я участвую. Каждый ранг MPI будет преобразован в потоки одного и того же процесса UNIX. Затем вы можете легко использовать gdb для пошагового ранжирования MPI.

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

Для получения дополнительной информации см. Эту презентацию или соответствующий ответ .

Мартин Куинсон
источник