为什么我的C++实现比 R 源慢?
Why is my C++ implementation slower than the R source?
我试图用Rcpp实现charToRaw
函数。 下面的C_charToRaw
是从 R 源复制的。
C++代码:
#include <Rcpp.h>
#include <Rinternals.h>
// [[Rcpp::export]]
Rcpp::RawVector Cpp_charToRaw(const std::string& s) {
Rcpp::RawVector res(s.begin(), s.end());
return res;
}
// [[Rcpp::export]]
SEXP C_charToRaw(SEXP x) {
if (!Rf_isString(x) || LENGTH(x) == 0) {
Rf_error("argument must be a character vector of length 1");
}
if (LENGTH(x) > 1) {
Rf_warning("argument should be a character vector of length 1nall but the first element will be ignored");
}
int nc = LENGTH(STRING_ELT(x, 0));
SEXP ans = Rf_allocVector(RAWSXP, nc);
if (nc) {
memcpy(RAW(ans), CHAR(STRING_ELT(x, 0)), nc);
}
return ans;
}
基准代码:
x = "Test string. Test string"
bench::mark(
Cpp_charToRaw(x),
C_charToRaw(x),
charToRaw(x),
iterations = 100000
)
基准测试结果:
# A tibble: 3 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm> <list> <list>
1 Cpp_charToRaw(x) 1.44µs 1.58µs 611480. 0B 30.6 99995 5 163.5ms < [24… <df[,…
2 C_charToRaw(x) 1.38µs 1.49µs 648339. 0B 38.9 99994 6 154.2ms < [24… <df[,…
3 charToRaw(x) 277.88ns 329.81ns 2747742. 0B 27.5 99999 1 36.4ms < [24… <df[,…
# … with 2 more variables: time <list>, gc <list>
问题:为什么内置charToRaw
这么快?
构建日志:
Generated extern "C" functions
--------------------------------------------------------
#include <Rcpp.h>
// Cpp_charToRaw
Rcpp::RawVector Cpp_charToRaw(const std::string& s);
RcppExport SEXP sourceCpp_1_Cpp_charToRaw(SEXP sSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< const std::string& >::type s(sSEXP);
rcpp_result_gen = Rcpp::wrap(Cpp_charToRaw(s));
return rcpp_result_gen;
END_RCPP
}
// C_charToRaw
SEXP C_charToRaw(SEXP x);
RcppExport SEXP sourceCpp_1_C_charToRaw(SEXP xSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< SEXP >::type x(xSEXP);
rcpp_result_gen = Rcpp::wrap(C_charToRaw(x));
return rcpp_result_gen;
END_RCPP
}
Generated R functions
-------------------------------------------------------
`.sourceCpp_1_DLLInfo` <- dyn.load('/tmp/RtmpIEEIRN/sourceCpp-x86_64-pc-linux-gnu-1.0.2/sourcecpp_11646c07fffb/sourceCpp_5.so')
Cpp_charToRaw <- Rcpp:::sourceCppFunction(function(s) {}, FALSE, `.sourceCpp_1_DLLInfo`, 'sourceCpp_1_Cpp_charToRaw')
C_charToRaw <- Rcpp:::sourceCppFunction(function(x) {}, FALSE, `.sourceCpp_1_DLLInfo`, 'sourceCpp_1_C_charToRaw')
rm(`.sourceCpp_1_DLLInfo`)
Building shared library
--------------------------------------------------------
DIR: /tmp/RtmpIEEIRN/sourceCpp-x86_64-pc-linux-gnu-1.0.2/sourcecpp_11646c07fffb
/usr/lib64/R/bin/R CMD SHLIB -o 'sourceCpp_5.so' --preclean 'test.cpp'
g++ -I"/usr/include/R/" -DNDEBUG -I"/home/xxx/R/x86_64-pc-linux-gnu-library/3.6/Rcpp/include" -I"/home/xxx/projects/R/packages/RestRserve/tmp" -I"/home/xxx/projects/R/packages/RestRserve/tmp/../inst/include" -D_FORTIFY_SOURCE=2 -fpic -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -c test.cpp -o test.o
g++ -shared -L/usr/lib64/R/lib -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -o sourceCpp_5.so test.o -L/usr/lib64/R/lib -lR
更新
根据答案和评论Rcpp::RNGScope
禁用了[[Rcpp::export(rng = false)]]
.
Cpp_rawToChar
功能也几乎没有改进:
// [[Rcpp::export(rng = false)]]
Rcpp::RawVector Cpp_charToRaw2(const char* s) {
Rcpp::RawVector res(s, s + std::strlen(s));
return res;
}
更新的基准:
# A tibble: 4 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory
<bch:expr> <bch> <bch:> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm> <list> <list>
1 Cpp_charToRaw(x) 448ns 506ns 1789684. 0B 35.8 99998 2 55.9ms < [24… <df[,…
2 Cpp_charToRaw2(x) 361ns 412ns 2180744. 0B 43.6 99998 2 45.9ms < [24… <df[,…
3 C_charToRaw(x) 331ns 369ns 2428416. 0B 24.3 99999 1 41.2ms < [24… <df[,…
4 charToRaw(x) 274ns 311ns 2930855. 0B 58.6 99998 2 34.1ms < [24… <df[,…
# … with 2 more variables: time <list>, gc <list>
开销几乎可以肯定来自函数周围的 Rcpp 包装器。从生成的代码中可以看出,此包装器设置了一个 RNG 范围,它涉及复制一个大的数字向量(在您的情况下,这实际上是不必要的;使用[[Rcpp::export(rng = false)]]
禁用它)。在Cpp_charToRaw
的情况下,包装器还需要将R向量复制到std::string
中,因为这种转换不能就地发生(它可以与std::string_view
一起发生)。
您可以通过对空 Rcpp 函数进行基准测试来测试此 Rcpp 开销:
// [[Rcpp::export]]
SEXP do_nothing(SEXP x) {
return x;
}
相关文章:
- 为什么在此排序算法实现中,向量明显比数组慢?
- C# HashSet VS C++ std::unordered_set 使用自定义类键。C++慢...不可能。如何实现 C# 的速度?
- C++openssl SHA256运行速度比JDK SHA256实现慢
- 当给出预先排序的输入时,为什么我的快速排序实现很慢
- 为什么我的 Rcpp 实现查找唯一项的数量比基本 R 慢?
- 为什么我的C++实现比 R 源慢?
- 为什么此范围为Vectors求和的实现速度较慢
- 为什么 std::inner_product 比朴素的实现慢
- 随着线程数量的增加,OpenMP的实现速度越来越慢
- 为什么我的方法的JNI实现比纯Java慢
- 为什么这个普通的数组实现比STD ::向量实现性能慢
- 实现近乎实时的CPU功能,如glAlphaFunc(GL_GREATER),具有RGB源和RGBA覆盖
- 多个源中的模板实现
- C++ 模板复杂图像读取类执行时间慢,声明和实现分离
- 为什么 std::vector 这么快(或者我的实现太慢了)
- 为什么大小..(T)这么慢?在没有大小的情况下实现C++14 make_index_sequence.(T)
- 推力::max_element 比较慢 cublasIsamax - 更有效的实现
- C++ openmp 比串行实现慢得多
- 与Yeppp一起表演!比本机实现慢
- OpenCL实现的算法比正常循环慢