2013-07-01 2 views
3

У меня есть реальная головоломка для вас.Случайные сбои с короткой программой c openmp на RHEL5

Ниже приведена небольшая автономная простая 40-строчная программа, которая вычисляет частичные суммы совокупности чисел и регулярно (но стохастически) сбрасывает узлы в кластере распределенной памяти, который я использую. Если я создаю 50 заданий PBS, которые запускают этот код, от 0 до 4 из них будут разбивать свои узлы. Это происходит при повторном повторении основного цикла каждый раз и на разных узлах каждый раз, нет различимого шаблона. Узлы просто «опускаются» на отчет о ганглиях, и я не могу их с ними («нет пути к хосту»). Если вместо отправки заданий я ssh на один из узлов и запускаю свою программу там, если мне не повезло, и он падает, я просто перестаю видеть текст, а затем вижу, что этот узел мертв на ганглиях.

Программа имеет резьбу с openmp, и аварии происходят только при возникновении большого количества потоков (например, 12).

Кластер это убийство является RHEL 5 кластера с узлами, которые имеют 2 6-ядерные X5650 процессоры:

[jamelang @ Гука ~] $ хвост/и т.д./RedHat-релиз
Red Hat Enterprise Linux Выпуск сервера 5.7 (Tikanga)

Я попытался включить дампы ядра ulimit -c unlimited, но файлы не отображаются. Это код, с комментариями:

#include <cstdlib> 
#include <cstdio> 

#include <omp.h> 

int main() { 

    const unsigned int numberOfThreads = 12; 
    const unsigned int numberOfPartialSums = 30000; 
    const unsigned int numbersPerPartialSum = 40; 

    // make some numbers 
    srand(0); // every instance of program should get same results 
    const unsigned int totalNumbersToSum = numbersPerPartialSum * numberOfPartialSums; 
    double * inputData = new double[totalNumbersToSum]; 
    for (unsigned int index = 0; index < totalNumbersToSum; ++index) { 
    inputData[index] = rand()/double(RAND_MAX); 
    } 

    omp_set_num_threads(numberOfThreads); 

    // prepare a place to dump output 
    double * partialSums = new double[numberOfPartialSums]; 

    // do the following algorithm many times to induce a problem 
    for (unsigned int repeatIndex = 0; repeatIndex < 100000; ++repeatIndex) { 
    if (repeatIndex % 1000 == 0) { 
     printf("Absurd testing is on repeat %06u\n", repeatIndex); 
    } 

#pragma omp parallel for 
    for (unsigned int partialSumIndex = 0; partialSumIndex < numberOfPartialSums; 
     ++partialSumIndex) { 
     // get this partial sum's limits 
     const unsigned int beginIndex = numbersPerPartialSum * partialSumIndex; 
     const unsigned int endIndex = numbersPerPartialSum * (partialSumIndex + 1); 
     // we just sum the 40 numbers, can't get much simpler 
     double sumOfNumbers = 0; 
     for (unsigned int index = beginIndex; index < endIndex; ++index) { 
     // only reading, thread-safe 
     sumOfNumbers += inputData[index]; 
     } 
     // writing to non-overlapping indices (guaranteed by omp), 
     // should be thread-safe. 
     // at worst we would have false sharing, but that would just affect 
     // performance, not throw sigabrts. 
     partialSums[partialSumIndex] = sumOfNumbers; 
    } 
    } 

    delete[] inputData; 
    delete[] partialSums; 
    return 0; 
} 

компилировать его следующим:

/home/jamelang/gcc-4.8.1/bin/g++ -O3 -Wall -fopenmp убийца. куб.см -o Убийца

Казалось бы, связь с правыми общими объектами в:

[[email protected] Killer]$ ldd Killer 
    linux-vdso.so.1 => (0x00007fffc0599000) 
    libstdc++.so.6 => /home/jamelang/gcc-4.8.1/lib64/libstdc++.so.6 (0x00002b155b636000) 
    libm.so.6 => /lib64/libm.so.6 (0x0000003293600000) 
    libgomp.so.1 => /home/jamelang/gcc-4.8.1/lib64/libgomp.so.1 (0x00002b155b983000) 
    libgcc_s.so.1 => /home/jamelang/gcc-4.8.1/lib64/libgcc_s.so.1 (0x00002b155bb92000) 
    libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003293a00000) 
    libc.so.6 => /lib64/libc.so.6 (0x0000003292e00000) 
    /lib64/ld-linux-x86-64.so.2 (0x0000003292a00000) 
    librt.so.1 => /lib64/librt.so.1 (0x0000003298600000) 

некоторых Примечания:
1. На osx lion с gcc 4.7 этот код выдает SIGABRT, похожий на этот вопрос: Why is this code giving SIGABRT with openMP?. Использование gcc 4.8, похоже, устраняет проблему на OSX. Однако использование gcc 4.8 на машине RHEL5 не исправляет. Машина RHEL5 имеет версию GLIBC версии 2.5, и кажется, что yum не предоставляет более позднюю версию, поэтому администраторы придерживаются 2.5.
2. Если я определяю обработчик сигнала SIGABRT, он не улавливает проблему на машине RHEL5, но он улавливает ее на OSX с помощью gcc47.
3. Я считаю, что никакие переменные не должны использоваться в предложении omp, поскольку все они могут иметь частные копии, но добавление их как общих не изменяет поведение.
4. Убийство узлов происходит независимо от используемого уровня оптимизации.
5. Убийство узлов происходит, даже если я запускаю программу изнутри gdb (например, поставьте «gdb -batch -x gdbCommands Killer» в файл pbs), где «gdbCommands» - это файл с одной строкой: «run»
6. Этот пример порождает потоки при каждом повторе. Одна из стратегий заключалась бы в том, чтобы создать параллельный блок, содержащий цикл повторов, чтобы предотвратить это. Однако это мне не помогает - этот пример является лишь представителем гораздо более крупного исследовательского кода, в котором я не могу использовать эту стратегию.

У меня все идеи, на моей последней соломе, на конце моего ума, готовые вытащить мои волосы и т. Д. С этим. У кого-нибудь есть предложения или идеи?

+0

GCC OpenMP runtime 'libgomp' реализует пул потоков, и поэтому новые последовательности не генерируются при последовательном входе в параллельную область. Но это может быть утечка памяти в 'libgomp'. То, что он также выходит из строя на OS X, означает, что проблема не связана с GLIBC. Всегда ли происходит авария вокруг одного и того же номера? –

+0

Сбой не происходит при одном и том же номере. Более 90% идентичных пробегов заканчиваются просто отлично, без проблем, а остальные падают в случайных местах, но почти всегда в небольшом количестве итераций. –

ответ

0

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

#pragma omp parallel for private(j) 
for (i = 0; i < height; i++) 
for (j = 0; j < width; j++) 
    c[i][j] = 2; 

В вашем случае, index и sumOfNumbers должны быть частными.

+0

С уважением, я не думаю, что это совершенно правильно. 'sumOfNumbers' и' index' объявляются в рамках блока 'omp parallel for', они автоматически закрыты. Кроме того, я не могу добавить 'private (sumOfNumbers)' в инструкцию pragma - он еще не был объявлен! Вы согласны? –

+0

Мой плохой, да, они по умолчанию закрыты. – shrm

+0

Без проблем! Я ценю готовность помочь. –

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