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

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

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

Ответ 1

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

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

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

Ответ 2

Я нашел 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] [...]

Ответ 3

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

mpiexec -n X gdb ./a.out

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

mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out

Теперь только один из ваших процессов получит GDB.

Ответ 4

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

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

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

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

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

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

  • Скалярные переменные автоматически сравниваются по всем процессам: Sparklines showing values across processes
    (источник: allinea.com)

  • Вы также можете отслеживать и фильтровать значения переменных и выражений по процессам и времени: Tracepoints log values over time

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

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

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

Ответ 6

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

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

Ответ 7

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

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

Вилка: https://github.com/Azrael3000/tmpi

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

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

Ответ 8

Использование 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 запустится на экраны, вы можете script ввести на экраны (чтобы вам не приходилось вводить каждый экран и вводить одно и то же) с помощью экрана -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 по аналогии с предыдущим разделом кода.

Ответ 9

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

В UNIX TotalView, как утверждается, имеет хороший suppoort для MPI.

Ответ 10

Я использую этот маленький метод homebrewn для присоединения отладчика к процессам 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);
}

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

Ответ 11

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

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

Padb

Ответ 12

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

Ответ 13

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

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

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

Ответ 15

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

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

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

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

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

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

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

Debug-> Запустить debugging-> Присоединить к запущенному приложению

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

Ответ 16

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

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

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