[英]Rcpp function [actually not] much slower inside of package than outside
I recently wrote a compute intense function in Rcpp.我最近在 Rcpp 中写了一个计算密集型 function。 Now, I would like to port this code to an R package. However, I notice that the code is much (~100x) slower when run inside an R package.
现在,我想将这段代码移植到 R package。但是,我注意到当在 R package 中运行时,代码要慢很多(~100 倍)。
I already read here , that this may have to do with how the function is called.我已经在这里读到,这可能与 function 的调用方式有关。 However, this is not a one-time cost.
但是,这不是一次性成本。 Instead, it scaled with the number of iterations in the Rcpp function (only a single call to Rcpp is made).
相反,它与 Rcpp function 中的迭代次数成比例(仅对 Rcpp 进行了一次调用)。
Please find a minimally complete verifiable example below.请在下面找到一个最低限度的完整可验证示例。 The function below doesn't do anything useful but shows the behavior I am worried about.
下面的 function 没有做任何有用的事情,但显示了我担心的行为。
How can I troubleshoot this issue?我该如何解决这个问题?
Steps to recreate package.重新创建 package 的步骤。
Use Rcpp.package.skeleton
to create a new package skeleton with Rcpp.使用
Rcpp.package.skeleton
用 Rcpp 创建一个新的 package 骨架。
Add the following example.cpp file to \src
.将以下example.cpp文件添加到
\src
。
example.cpp例子.cpp
#include <Rcpp.h> // [[Rcpp::export]] int example_cpp(Rcpp::IntegerMatrix mat, int iters) { for(int i = 0; i < iters; ++i) { std::vector<int> vec; std::iota(std::begin(vec), std::end(vec), 0); } return 0; }
Add the following example.R file to \R
.将以下example.R文件添加到
\R
。
example.R例子.R
# @export example <- function(mat, iters) { example_cpp(mat, iters) }
Test the Rcpp function inside/outside the package using the following script.使用以下脚本测试 package 内部/外部的 Rcpp function。
library(examplePackage) Rcpp::sourceCpp('src/example.cpp') exampleOutside <- function(mat, iters) { example_cpp(mat, iters) } set.seed(42) mat <- replicate(n=1000, sample(1:10)) for(iters in c(1e4, 1e5, 1e6)) { res <- microbenchmark::microbenchmark( example(mat, iters), exampleOutside(mat, iters), times=10 ) print(iters) print(res) }
Output. Output。
[1] 10000
Unit: microseconds
expr min lq mean median uq max neval
example(mat, iters) 629.550 630.977 696.1131 686.488 719.399 858.081 10
exampleOutside(mat, iters) 3.143 4.203 239.7205 5.021 6.981 2340.719 10
[1] 1e+05
Unit: microseconds
expr min lq mean median uq max neval
example(mat, iters) 6512.453 6625.420 6717.6595 6713.2375 6843.519 6921.158 10
exampleOutside(mat, iters) 2.637 3.226 7.6473 4.1205 12.647 16.489 10
[1] 1e+06
Unit: microseconds
expr min lq mean median uq max neval
example(mat, iters) 64091.144 66392.745 67491.8759 68001.405 68609.006 69028.736 10
exampleOutside(mat, iters) 2.885 3.574 10.6664 4.792 17.653 35.927 10
Edit: See below for the full discussion.编辑:完整讨论见下文。 You are measuring noise as the functions are empty returning immediately.
您正在测量噪声,因为函数为空并立即返回。 For a real problem I replace your function and it unused argument and data with a simple summation of the log of the loop value:
对于一个真正的问题,我将您的 function 及其未使用的参数和数据替换为循环值日志的简单总和:
#include <Rcpp.h>
// [[Rcpp::export]]
double nontrivial(int iters) {
double sum = 0;
for (int i = 0; i < iters; ++i) {
sum += log(i * 1.0);
}
return sum;
}
Running over 10 million elements the default one hundred takes just under five seconds, and post approaches are equally fast:运行超过 1000 万个元素,默认的 100 个元素只需要不到 5 秒,post 方法也同样快:
edd@rob:~/git/stackoverflow/74688018(master)$ Rscript nontrivial.R
test replications elapsed relative
1 inside 100 4.743 1.000
2 outside 100 4.920 1.037
edd@rob:~/git/stackoverflow/74688018(master)$
Updated files are in the repo linked below.更新的文件在下面链接的 repo 中。 The original reply from yesterday follows.
昨天的原始回复如下。
Thanks for making the problem smaller.感谢您使问题变小。 There are numerous problems here:
这里有很多问题:
replicate
doing therereplicate
在那里做什么Rcpp::sourceCpp("exampleOutside.cpp")
set.seed(42)
mat <- matrix(sample(1:10, 100, replace=TRUE), 10, 10)
rbenchmark::benchmark(examplePackage::example_cpp(mat, 10),
exampleOutside(mat, 10),
replications = 10)[,1:4]
> rbenchmark::benchmark(examplePackage::example_cpp(mat, 10),
+ exampleOutside(mat, 10), replications = 10)[,1:4]
test replications elapsed relative
2 exampleOutside(mat, 10) 10 0.001 NA
1 examplePackage::example_cpp(mat, 10) 10 0.000 NA
>
#include <Rcpp.h>
// [[Rcpp::export]]
int exampleOutside(Rcpp::IntegerMatrix mat, int iters) {
for(int i = 0; i < iters; ++i) {
std::vector<int> vec;
std::iota(std::begin(vec), std::end(vec), 0);
}
return 0;
}
Overall, this is a fairly good "teachable moment" about why minimal examples are recommended.总的来说,这是一个关于为什么建议使用最少示例的相当好的“教学时刻”。 You were chasing a mirage, and you didn't notice because you put up too many barriers for yourself to see that maybe your comparison setup was not quite right.
你在追逐海市蜃楼,但你没有注意到,因为你为自己设置了太多障碍,以至于你看不到你的比较设置可能不太正确。
In short, "when something cannot be true" (as in 'massive difference between same function compiled two different ways') it often is not.简而言之,“当某事不可能是真的时”(如“相同的 function 以两种不同方式编译的巨大差异”)通常不是。
(And for reproducibility all my files are in this directory on github .) (为了重现性,我的所有文件都在 github 的这个目录中。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.