从R调用的带有openmp的C代码给出的结果不一致

时间:2019-02-13 17:21:50

标签: r openmp

下面是一段从R运行的C代码,用于将矩阵的每一行与矢量进行比较。相同值的数量存储在两列矩阵的第一列中。
我知道可以很容易地在R中完成它(就像检查结果一样),但这是更复杂用例的第一步。
当不使用openmp时,它可以正常工作。当使用openmp时,它会给出相关(0.99)但结果不一致。
问题1:我在做什么错了?
Question2:我使用double for循环用零填充输出矩阵(ret)。有什么更好的解决方案?

此外,在包装中使用代码时,也观察到不一致之处。我试图使用inline使代码可重现,但是它无法识别openmp语句(我试图在cfunction的参数中包括'omp.h',...)。
问题3:我们如何使此代码与inline一起使用?

在这个话题上,我(太过远了)。


library(inline)

compare <- cfunction(c(x = "integer", vec = "integer"), "
  const int I = nrows(x), J = ncols(x);
  SEXP ret;
  PROTECT(ret = allocMatrix(INTSXP, I, 2));
  int *ptx = INTEGER(x), *ptvec = INTEGER(vec), *ptret = INTEGER(ret);

  for (int i=0; i<I; i++)
      for (int j=0; j<2; j++)
          ptret[j * I + i] = 0;

  int i, j;

  #pragma omp parallel for default(none) shared(ptx, ptvec, ptret) private(i,j)

  for (j=0; j<J; j++)
   for (i=0; i<I; i++)
      if (ptx[i + I * j] == ptvec[j]) {++ptret[i];}

  UNPROTECT(1);
  return ret;
")


N = 3e3
M = 1e4
m = matrix(sample(c(-1:1), N*M, replace = TRUE), nc = M)
v = sample(-1:1, M, replace = TRUE)

cc = compare(m, v)
cr = rowSums(t(t(m) == v))
all.equal(cc[,1], cr)

1 个答案:

答案 0 :(得分:0)

由于上面的评论,我重新考虑了数据竞赛问题。
IIUC,我的循环在j(各列)上并行化。然后,每个线程都有自己的i值(行),但是各个线程可能具有相同的值,然后试图同时增加ptret[i]。 为了避免这种情况,我现在首先在i上循环,以便只有一个线程将增加每一行。
然后,我意识到我可以在第一个循环内移动ptret的零初始化。
它似乎有效。我得到了相同的结果,增加了CPU使用率,并在笔记本电脑上加快了3-4倍的速度。
我想这可以解决问题1和2。我将仔细研究inline / openmp问题。
下面的代码,一遍。

#include <omp.h>
#include <R.h>
#include <Rinternals.h>
#include <stdio.h>

SEXP c_compare(SEXP x, SEXP vec)
{
  const int I = nrows(x), J = ncols(x);
  SEXP ret;
  PROTECT(ret = allocMatrix(INTSXP, I, 2));
  int *ptx = INTEGER(x), *ptvec = INTEGER(vec), *ptret = INTEGER(ret);

  int i, j;
#pragma omp parallel for default(none) shared(ptx, ptvec, ptret) private(i, j)
  for (i = 0; i < I; i++) {
    // init ptret to zero
    ptret[i] = 0;
    ptret[I + i] = 0;

    for (j = 0; j < J; j++)
      if (ptx[i + I * j] == ptvec[j]) {
        ++ptret[i];
      }
    }

  UNPROTECT(1);
  return ret;
}