2015-10-01 2 views
1

Я хотел бы запрограммировать в поточном строительстве блоки с задачами. Но как сделать отладку на практике?Отладка в потоковом построении Блоки

В целом метод печати является надежной техникой для отладки программ. В моем опыте параллелизации MPI правильный способ ведения журнала - это то, что каждый поток печатает свою отладочную информацию в своем собственном файле (скажем, «debug_irank» с инерционным рангом в MPI_COMM_WORLD), чтобы можно было найти логические ошибки.

Как можно добиться чего-то подобного с помощью TBB? Неясно, как получить доступ к номеру потока в пуле потоков, поскольку это, очевидно, что-то внутреннее для tbb.

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

+1

Посмотрите на [этой статье] (http://goparallel.sourceforge.net/use-debugging-exception-features-tbb/). –

ответ

3

Прежде всего, запустите программу, используя 1 нить. Чтобы сделать это, построить task_scheduler_init как первое дело main, как это:

#include "tbb/tbb.h" 

int main() { 
    tbb::task_scheduler_init init(1); 
    ... 
} 

Обязательно компилировать с макро TBB_USE_DEBUG набором 1, так что проверка Т будет включена.

Если однопоточная версия работает, но в многопоточной версии нет, рассмотрите возможность использования Intel Inspector для определения условий гонки. Обязательно выполните компиляцию с TBB_USE_THREADING_TOOLS, чтобы инспектор получил достаточную информацию.

В противном случае я обычно начинаю с добавления утверждений, потому что машина может проверять утверждения намного быстрее, чем я могу читать сообщения журнала. Если я действительно озадачен тем, почему утверждение терпит неудачу, я использую printfs и идентификаторы задач (а не идентификаторы потоков). Самый простой способ создать идентификатор задачи - выделить его путем пошагового увеличения tbb::atomic<size_t> и сохранения результата в задаче.

Если у меня очень плохой день, а printfs меняют поведение программы, так что ошибка не появляется, я использую «delayed printfs». Настройте аргументы printf в круговом буфере и запустите printf в записях позже после обнаружения сбоя. Обычно для буфера я использую массив структур, содержащих строку формата и несколько значений размера слова, и делаю размер массива равным двум. Тогда для размещения слотов достаточно атомного приращения и маски. Например, примерно следующее:

const size_t bufSize = 1024; 

struct record { 
    const char* format; 
    void *arg0, *arg1; 
}; 

tbb::atomic<size_t> head; 

record buf[bufSize]; 

void recf(const char* fmt, void* a, void* b) { 
    record* r = &buf[head++ & bufSize-1]; 
    r->format = fmt; 
    r->arg0 = a; 
    r->arg1 = b; 
} 

void recf(const char* fmt, int a, int b) { 
    record* r = &buf[head++ & bufSize-1]; 
    r->format = fmt; 
    r->arg0 = (void*)a; 
    r->arg1 = (void*)b; 
} 

В двух подпрограммах recf записываются формат и значения. Кастинг несколько оскорбителен, но на большинстве архитектур вы можете правильно напечатать запись с printf(r->format, r->arg0, r->arg1), даже если вторая перегрузка recf создала запись.
~ ~

Смежные вопросы