在RHEL5上使用短c openmp程序随机崩溃

时间:2013-07-01 00:40:49

标签: c++ multithreading crash parallel-processing openmp

我有一个真正的益智游戏给你们。

下面是一个小的,独立的,简单的40行程序,它计算了一堆数字的部分和,并且常规地(但随机地)崩溃我正在使用的分布式内存集群上的节点。如果我生成50个运行此代码的PBS作业,则0到4之间的任务将使其节点崩溃。它将在每次主循环的不同重复上发生,并且每次在不同的节点上发生,没有可辨别的模式。节点只是在神经节报告上“向下”,我不能ssh到他们(“没有路由到主机”)。如果我没有提交作业,而是将ssh移到其中一个节点上并在那里运行我的程序,如果我运气不好而崩溃那么我就停止看文本,然后看到那个节点在神经节上死了。

该程序使用openmp进行线程化,只有在生成大量线程(如12)时才会发生崩溃。

它要杀死的集群是一个RHEL 5集群,其节点有2个6核x5650处理器:

  

[jamelang @ hooke~] $ tail / etc / redhat-release
  红帽企业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 Killer.cc -o Killer

它似乎与正确的共享对象相关联:

    [jamelang@hooke 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.此示例在每次重复时生成线程。一种策略是制作包含重复循环的并行块以防止这种情况。然而,这对我没有帮助 - 这个例子只代表了一个更大的研究代码,我无法使用该策略。

我完全没有想法,在我的最后一根稻草上,在我的智慧结束时,准备好把头发拉出来等等。有没有人有任何建议或想法?

1 个答案:

答案 0 :(得分:0)

您正在尝试并行化嵌套for循环,在这种情况下,您需要将内部循环中的变量设为私有,以便每个线程都有自己的变量。可以使用private子句来完成,如下例所示。

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

在您的情况下,indexsumOfNumbers必须是私密的。