【问题标题】:Paralellized execution in nested for using Cilk使用 Cilk 嵌套并行执行
【发布时间】:2016-03-19 02:03:50
【问题描述】:

我正在尝试实现一个操纵矩阵的二维模板算法。对于矩阵中的每个字段,将其上、下、左、右的字段相加并除以 4 以计算新值。对于给定的矩阵,此过程可能会重复多次。

该程序是用 C 语言编写的,并使用 cilkplus gcc 二进制文件进行编译。

**编辑:我想你可能对编译器标志感兴趣:

~/cilkplus/bin/gcc -fcilkplus -lcilkrts -pedantic-errors -g -Wall -std=gnu11 -O3  `pkg-config --cflags glib-2.0 gsl`   -c -o sal_cilk_tst.o sal_cilk_tst.c

请注意,真正的代码涉及一些指针算法以保持一切一致。顺序实现有效。我在这里省略了这些步骤以增强可理解性。

伪代码看起来像这样(没有边缘情况处理):

for(int i = 0; i < iterations; i++){
   for(int j = 0; j < matrix.width; j++){
      for(int k = 0; k < matrix.height; k++){
         result_ matrix[j][k] = (matrix[j-1][k] + 
                                 matrix[j+1][k] +
                                 matrix[j]  [k+1] +
                                 matrix[j]  [k-1]) / 4;
      }
   }
   matrix = result_matrix;
}

然后将模板计算本身移动到函数apply_stencil(...)

for(int i = 0; i < iterations; i++){
   for(int j = 0; j < matrix.width; j++){
      for(int k = 0; k < matrix.height; k++){
         apply_stencil(matrix, result_matrix, j, k);
      }
   }
   matrix = result_matrix;
}

并尝试并行化:

for(int i = 0; i < iterations; i++){
   for(int j = 0; j < matrix.width; j++){
      cilk_for(int k = 0; k < matrix.height; k++){ /* <--- */
         apply_stencil(matrix, result_matrix, j, k);
      }
   }
   matrix = result_matrix;
}

此版本编译时没有错误/警告,但在执行时会直接生成Floating point exception。如果您想知道:将哪个 for 循环制成 cilk_for 循环并不重要。所有配置(除了没有 cilk_for)都会产生相同的错误。

可能的其他方法:

for(int i = 0; i < iterations; i++){
   for(int j = 0; j < matrix.width; j++){
      for(int k = 0; k < matrix.height; k++){
         cilk_spawn apply_stencil(matrix, result_matrix, j, k); /* <--- */
      }
   }
   cilk_sync; /* <--- */
   matrix = result_matrix;
}

编译时会产生 3 个警告:i, jk 似乎未初始化。 尝试执行时,执行matrix = result_matrix; 步骤的函数似乎未定义。

现在是实际问题:Cilk 为什么以及如何破坏我的顺序代码;或者更确切地说,我怎样才能阻止它这样做?

如果您有兴趣,当然也可以获得实际代码。然而,这个项目是针对大学课程的,因此会受到其他学生的抄袭,这些学生发现了这个线程,这就是为什么我不想公开分享它。

**更新:

按照建议,我尝试仅使用 1 个工作线程运行算法,从而有效地使 cilk 实现顺序化。这确实,令人惊讶的是,工作得很好。但是,一旦我将工人的数量更改为两个,熟悉的错误就会返回。

我不认为这种行为是由竞争条件引起的。由于工作矩阵在每次迭代后都会更改并调用cilk_sync,因此实际上没有临界区。所有线程不依赖于其他人在同一迭代中写入的数据。

接下来我将尝试尝试其他版本的 cilkplus 编译器,看看它是否可能是他们这边的错误。

【问题讨论】:

    标签: c cilk cilk-plus


    【解决方案1】:

    关于 cilk_for 中的浮点异常,在 Cilk Plus 运行时的某些版本中已经修复了一些问题。是否有可能您使用的是过时的版本?

    https://software.intel.com/en-us/forums/intel-cilk-plus/topic/558825

    另外,产生的具体警告信息是什么?旧版本的 Cilk Plus GCC 会出现一些“未初始化变量”警告,我认为这是虚假警告。

    【讨论】:

      【解决方案2】:

      Cilk 运行时使用递归分治算法来并行化您的循环。本质上,它将范围分成两半,并递归调用自身两次,生成一半并调用一半。

      作为初始化的一部分,它会计算一个“粒度”,即它将您的范围划分为的最小尺寸的大小。默认情况下,即 loopRange/8P,其中 P 是核心数。

      一个有趣的实验是将 Cilk 工人的数量设置为 1。当你这样做时,所有的 cilk_for 机制都被扩大了,但因为只有 1 个工人,所以什么都不会被盗。

      另一种可能性是尝试在 Cilkscreen(Cilk 种族检测器)下运行您的代码。不幸的是,只有 GCC 的 cilkplus 分支会生成 Cilkscreen 需要的注释。您的选择是使用 Intel 编译器,或者尝试使用 GCC 4.9 的 cilkplus 分支。关于如何拉下代码并构建它的说明位于cilkplus.org website

      【讨论】:

        猜你喜欢
        • 2020-11-05
        • 2018-06-22
        • 1970-01-01
        • 1970-01-01
        • 2012-01-03
        • 2018-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多