У меня есть реальная головоломка для вас.Случайные сбои с короткой программой 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. Этот пример порождает потоки при каждом повторе. Одна из стратегий заключалась бы в том, чтобы создать параллельный блок, содержащий цикл повторов, чтобы предотвратить это. Однако это мне не помогает - этот пример является лишь представителем гораздо более крупного исследовательского кода, в котором я не могу использовать эту стратегию.
У меня все идеи, на моей последней соломе, на конце моего ума, готовые вытащить мои волосы и т. Д. С этим. У кого-нибудь есть предложения или идеи?
GCC OpenMP runtime 'libgomp' реализует пул потоков, и поэтому новые последовательности не генерируются при последовательном входе в параллельную область. Но это может быть утечка памяти в 'libgomp'. То, что он также выходит из строя на OS X, означает, что проблема не связана с GLIBC. Всегда ли происходит авария вокруг одного и того же номера? –
Сбой не происходит при одном и том же номере. Более 90% идентичных пробегов заканчиваются просто отлично, без проблем, а остальные падают в случайных местах, но почти всегда в небольшом количестве итераций. –