gpt4 book ai didi

c++ - 带有 OpenMP 关键指令的 Rcpp 明显比编译的 C++ 代码慢

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:42:03 27 4
gpt4 key购买 nike

正如标题所说,与 R 包中使用的已编译和运行 C++ 代码相比,在 R 包中使用带有 Rcpp 的 #pragma omp critical 指令会显着降低执行速度,因为没有使用所有 CPU 能力。

考虑一个简单的 C++ 程序(使用 cmake):

test.h 为:

#ifndef RCPP_TEST_TEST_H
#define RCPP_TEST_TEST_H

#include <limits>
#include <cstdio>
#include <chrono>
#include <iostream>
#include <omp.h>

namespace rcpptest {
class Test {
public:
static unsigned int test();
};
}

#endif //RCPP_TEST_TEST_H

test.cpp中test.h的实现:

#include "test.h"

namespace rcpptest {
unsigned int Test::test() {
omp_set_num_threads(8);
unsigned int x = 0;

std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

#pragma omp parallel for
for (unsigned int i = 0; i < 100000000; ++i) {

#pragma omp critical
++x;
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "finished (ms): " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() <<std::endl;

return x;
}
}

主要是:

#include "src/test.h"

int main() {
unsigned int x = rcpptest::Test::test();
return 0;
}

如果我在 IDE (CLion) 中构建并运行该程序,一切正常。

然后我使用 Rcpp 创建了一个 R 包:

library(Rcpp)
Rcpp.package.skeleton('rcppTestLib')

并使用相同的 C++ 源代码为包 +“Rcpp”文件导出我的测试函数以从 R (rcppTestLib.cpp) 中使用:

#include <Rcpp.h>
#include "test.h"

// [[Rcpp::export]]
void rcppTest() {
rcpptest::Test::test();
}

如果我然后使用包从 R 运行测试

library(rcppTestLib)
rcppTest()

执行速度要慢得多。

我使用编译的 c++ 和 Rcpp 包进行了一些测试,结果是:

   program   | execution time
-----------------------------
compiled c++ | ~7 200ms
Rcpp package | ~551 000 ms

不同之处在于,使用 Rcpp 包会产生 8 个线程,但每个线程仅使用 ~1% 的 CPU,而使用编译的 C++ 时,8 个线程加起来使用了所有 CPU 能力。

我尝试将 #pragma omp critical 切换为 #pragma omp atomic,结果:

   program   | execution time
-----------------------------
compiled c++ | ~2 900ms
Rcpp package | ~3 300 ms

使用 #pragma omp atomic Rcpp 包产生 8 个线程并使用所有的 CPU 能力。然而,执行时间仍然存在差异,但并不那么显着。

所以我的问题是:为什么使用 #pragma omp critical R/Rcpp 包不使用所有的 CPU 能力,而使用 #pragma omp atomic 它甚至可以在 CLion 中构建和运行的相同代码在两种情况下都使用了所有 CPU 能力?

我在这里错过了什么?

最佳答案

这里有两个可能的选择:

  1. 在包形式中,OpenMP 标志选项尚未在 src/Makevars (unix) 或 src/Makevars.win 中设置(窗)
  2. 缺少 num_threads(x) 作为 critical 推出

对于一个,放置在 src/Makevarssrc/Makevars.win 文件中:

PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(SHLIB_OPENMP_CFLAGS)
PKG_CFLAGS = $(SHLIB_OPENMP_CFLAGS)
PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS)

详情请见:https://cran.r-project.org/doc/manuals/r-release/R-exts.html#OpenMP-support


关于缺少 num_threads(x)...我已经能够稍微加快这个问题...

改变:

#pragma omp parallel for

#pragma omp parallel for num_threads(4)

产量:

之前

finished (ms): 30822
[1] 1e+08

对比

之后

finished (ms): 17979
[1] 1e+08

或大约 1.7 的加速。我的想法是在 cmake 的某个地方设置了一个全局线程选项。

omp_set_num_threads(x)

set OMP_NUM_THREADS=x

https://gcc.gnu.org/onlinedocs/libgomp/omp_005fset_005fnum_005fthreads.html

https://software.intel.com/en-us/mkl-linux-developer-guide-setting-the-number-of-threads-using-an-openmp-environment-variable

关于c++ - 带有 OpenMP 关键指令的 Rcpp 明显比编译的 C++ 代码慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48949135/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com