LINUX.ORG.RU

Поиск segfault-а на кластере под MPI

 , ,


1

3

Есть развесистый код, который запускается из под MPI на кластере где нить так на 1000 ядрах, работает часов 7, а потом падает с сегфолтом. Собирается интеловским компилятором. Суммарно корка весит более 3Тб, откладывать ее некуда, непосредственно войти на узлы где крутиться код нельзя. Как такое ловить?

Из советов старших товарищей и гугления родилась какая то такая такая фигня:

#include <stdio.h>
#include <execinfo.h>
#include <inttypes.h>
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/signal.h>

void my_sigsegv_handler(int signum, siginfo_t * info, void * f){
	printf("bad address %p\n", info->si_addr);
	void* buf[4096];
	int size = backtrace(buf, 4096);
	printf("backtrace(%d):\n", size);
	char ** strs = backtrace_symbols(buf, size);
	if(!strs) printf("error in bactrace_symbols()\n");
	else for (int i = 0; i<size; ++i) printf(" %s\n", strs[i]);
	free(strs);
	exit(1);
}

static struct sigaction sigsegv_act; 
void init_sigsegv_hook(){
	memset(&sigsegv_act, 0, sizeof(sigsegv_act)); 
	sigsegv_act.sa_sigaction = my_sigsegv_handler; 
	sigsegv_act.sa_flags = SA_SIGINFO; 
	sigaction(SIGSEGV, &sigsegv_act, NULL); 
}
Что еще можно сделать?

Хотелось бы (в идеале) получать читабельный backtrace с именами файлов исходников, именами функций и строчками кода. Еще хотелось бы как то смотреть значения некоторых (выбранных в коде) переменных, причем отладочная печать не очень подходит - логи будут здоровенные, да и тормозить будет. У нас есть технология вывода выбранных переменных поcле выкидывания (и ловли) исключения, беда в том что перехватчик сигнала если и выкидывает исключение то уже где то не там.

cast tailgunner

★★★★★

Последнее исправление: AntonI (всего исправлений: 2)

Хотелось бы (в идеале) получать читабельный backtrace с именами файлов исходников, именами функций и строчками кода.

https://github.com/ianlancetaylor/libbacktrace

Эта штука используется для бэктрейсов в GCC и выглядит это вот так https://gcc.gnu.org/bugzilla/attachment.cgi?id=38739

Еще хотелось бы как то смотреть значения некоторых (выбранных в коде) переменных

Если отладочная печать не подходит, и отладчик не подходит, то что вообще должно подходить?

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)

Хотелось бы (в идеале) получать читабельный backtrace с именами файлов исходников, именами функций и строчками кода.

1) компиль с -g3

2) у gdb есть приватная либа для работы с отладочной инфой. имена файлов и гулять по фреймам там вроде бы можно.

dzidzitop ★★
()
Ответ на: комментарий от SZT

За ссылку спасибо.

Насчет того что подходит - у нас есть вот такая самопальная утилитка WEXC:

   ...
   int a = ...;
   WEXC(a, 2*a, a+b);
   a = func(b);
   WEXC(a, 2*a, a+b);
   ...
которая создает на стеке объекты, содержащие сообщения с отладочной печатью (имя файла, функции, номер строки и дальше arg1=val1, arg=val2, и т.д.). Деструкторы этих объектов выводят содержимое в stderr если есть неперехваченное исключение. Это лучше чем отладочная печать, и даже в чем то лучше чем анализ корки (можно посмотреть на эволюцию значения) но есть две проблемы:

1) это сильно тормозит, потому что хотя печати и нет, но сообщение все равно формируется, это форматированный вывод в std::stringstream, и это долго.

2) Когда прилетает SEGFLT деструкторы уже не работают.

Первую проблему можно наверное решить если хранить не само сообщение, а копии аргументов WEXC в каком нить std::tuple. Правда для объектов не имеющих тривиальных конструкторов копирования таки придется формировать уже строку с содержимым, иначе полезут всякие сайд-эффекты.

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

AntonI ★★★★★
() автор топика

Так на заметку. Не знаю как у интеловского компилятора, но вот у gcc корки очень хорошо жмутся через bzip2. Не помню цифры, но уменьшение раз в 100 было, если не в 1000

dave ★★★★★
()

А есть возможность запустить valgrind?? Вроде intel mpi можно было подсунуть valgrind для анализа каждого процесса приложения. Может valgrind выдаст что-то интересное??!

gvtlor
()
Ответ на: комментарий от XMs

Я надеюсь, тестами и статическим анализом код обложили?

:)

AlexVR ★★★★★
()
Ответ на: комментарий от AntonI

1) это сильно тормозит, потому что хотя печати и нет, но сообщение все равно формируется, это форматированный вывод в std::stringstream, и это долго.

оберни всю строчку кода в ещё один if или макрос напиши для этого.

dzidzitop ★★
()
Ответ на: комментарий от AntonI

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

А еще в обработчике сег-фолта можно повесится и подключится дебаггером к процессу ... или тупо снять копию рамы через /proc/$PID/mem, пожать и отправить через ssh на ноут или где там у вас есть три террабайта диска...

cvv ★★★★★
()
Ответ на: комментарий от cvv

я конечно очень..

Извиняюсь, я не по теме, но: может сменить версию компилятора и/или mpi? Авось повезет?

sshestov ★★
()

Stacktrace Антона Полухина попробуй. Она ещё не в бусте, но можешь найти её по boost stacktrace

zamazan4ik ★★
()
Ответ на: комментарий от dave

Это вряд ли, там в основном данные (чиселки, причем не нули), они жмутся не очень.

AntonI ★★★★★
() автор топика
Ответ на: комментарий от gvtlor

Гипотетически можно, но ждать тогда придется не 7 а 70 часов.

AntonI ★★★★★
() автор топика
Ответ на: комментарий от cvv

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

Нет, у нас WEXC в этом проекте не используется.

А еще в обработчике сег-фолта можно повесится и подключится дебаггером к процессу ... или тупо снять копию рамы через /proc/$PID/mem, пожать и отправить через ssh на ноут или где там у вас есть три террабайта диска...

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

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI

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

То есть, почему бы и вам не посмотреть корку через gdb прямо на удаленных серверах через ssh в терминале? Это очень просто и удобно

dave ★★★★★
()
Ответ на: комментарий от dave

Потому что на суперкомпьютере я не могу зайти по ssh на узел, на котором проводится мой расчет?

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI

Тогда могу посоветовать протестировать свой софт на локальном подконтрольном кластере, пусть не таком мощном, но, наверное, вы это уже сделали

dave ★★★★★
()
Ответ на: комментарий от dave

На достаточно подконтрольном кластере все работает.

AntonI ★★★★★
() автор топика
Ответ на: комментарий от AntonI

Кстати, иногда помогает туннелирование, когда можно зайти, пользуясь компьютером-посредником, если нет на прямую доступа, но, пожалуй, тоже знаете об этом)

dave ★★★★★
()

Хотелось бы (в идеале) получать читабельный backtrace с именами файлов исходников, именами функций и строчками кода

Можете немного доделать свой обработчик. Вызывать в нем addr2line, он умеет это показывать. Что-то типа такого:

void my_sigsegv_handler(int signum, siginfo_t *info, void *f)
{
    void* buf[4096];
    int size;
    char **strs;
 
    printf("bad address %p\n", info->si_addr);
 
    size = backtrace(buf, 4096);
    printf("backtrace(%d):\n", size);
 
    strs = backtrace_symbols(buf, size);
    if (strs) {
        int i;
        for (i = 0; i<size; ++i) {
            char cmd[PATH_MAX];
            FILE *p;
 
            sprintf(cmd, "addr2line -pif -e %s %p",
                program_invocation_name, buf[i]);
            p = popen(cmd, "r");
            if (p) {
                char res[PATH_MAX];
                fgets(res, sizeof(res), p);
                pclose(p);
                printf(" %s: %s", strs[i], res);
            } else {
                printf(" %s\n", strs[i]);
            }
        }
    } else {
        printf("error in bactrace_symbols()\n");
    }
    free(strs);
    exit(1);
}

Полностью рабочий пример здесь https://pastebin.com/LAeEi58P

Набросал по-быстрому, наверняка можно красивее и проще (addr2line умеет работать в batch-режиме, может этим можно как-то воспользоваться)

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.