我有一個真正的困惑你的人。在RHEL5上隨機崩潰,使用短c openmp程序
下面是一個小型的自包含的簡單的40行程序,用於計算我正在使用的分佈式內存羣集上的一些數字的部分和,並定期(但隨機)崩潰節點。如果我產生了50個運行此代碼的PBS作業,則其中的0到4個會使其節點崩潰。它會在每次主循環的不同重複時發生,並且每次都在不同的節點上發生,但沒有可辨別的模式。節點只是在神經節報告上「下」,我不能ssh給他們(「沒有路由到主機」)。如果不是提交作業,而是將作業提交到其中一個節點並在那裏運行我的程序,如果我運氣不好並且崩潰,那麼我會停止查看文本,然後看到該節點已死在神經節上。
該程序是用openmp進行線程化處理,並且只有當大量線程被產生時纔會發生崩潰(如12)。
它的殺羣集是RHEL 5簇與具有2 6核X5650處理器節點:
[jamelang @虎克〜] $尾的/ etc /紅帽釋放
紅帽企業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殺手。 CC -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.在使用gcc 4.7的osx lion上,此代碼將拋出一個SIGABRT,類似於此問題:Why is this code giving SIGABRT with openMP?。使用gcc 4.8似乎解決了OSX上的問題。但是,在RHEL5機器上使用gcc 4.8並不能解決問題。 RHEL5機器有GLIBC版本2.5,似乎yum沒有提供更高版本,所以管理員堅持2.5。
2.如果我定義了一個SIGABRT信號處理程序,它不會在RHEL5機器上發現問題,但它確實在OSX上用gcc47捕獲它。
3.我相信不需要在omp子句中共享變量,因爲它們都可以有私有副本,但將它們添加爲共享不會改變行爲。
4.無論使用哪種優化級別,都會發生節點查殺。
5.即使我在gdb中運行程序(即在pbs文件中放入「gdb -batch -x gdbCommands Killer」),也會發生節點死亡,其中「gdbCommands」是一行文件:「run」
6.這個例子在每次重複時產生線程。一種策略是製作一個包含重複循環的並行塊,以防止出現這種情況。然而,這並不能幫助我 - 這個例子只代表了一個更大的研究代碼,我不能使用這個策略。
我完全沒有想法,在我最後一根稻草,在我的機智的結尾,準備把我的頭髮拉出來,等等。有沒有人有任何建議或意見?
GCC的OpenMP運行時'libgomp'實現了一個線程池,因此在連續進入並行區域時不會產生新線程。但它可能是'libgomp'中的內存泄漏。它也在OS X上崩潰意味着問題不是GLIBC特定的。崩潰總是發生在相同的迭代數量附近嗎? –
在相同的迭代編號中不會發生崩潰。超過90%的相同運行完成沒問題,其他運行崩潰,隨機地點,但幾乎總是在少數迭代。 –