C++ rcpp功能中的长清理时间

C++ rcpp功能中的长清理时间,c++,r,rcpp,C++,R,Rcpp,观察到,在下面的rcpp函数中,当它以type==0运行时(使用std::unordered_map而不是std::map),运行时间会非线性增加 // [[Rcpp::export]] void cpp_test1(int a, int b, int type) { if (type==0) { std::unordered_map<int, std::unordered_map<int, NumericVector>> exposu

观察到,在下面的rcpp函数中,当它以type==0运行时(使用std::unordered_map而不是std::map),运行时间会非线性增加

// [[Rcpp::export]]
void cpp_test1(int a, int b, int type)
{     
  if (type==0)
  {     
    std::unordered_map<int, std::unordered_map<int, NumericVector>> exposure_by_date_name;
    for (int i=0; i < a; ++i)
    {
      for (int j=0; j < b; ++j)
      {
        exposure_by_date_name[i][j] = NumericVector(68);
      }
    }
    Rcpp::Rcout << "done work " << std::endl;
  } else {
    std::map<int, std::map<int, NumericVector>> exposure_by_date_name;
    for (int i=0; i < a; ++i)
    {
      for (int j=0; j < b; ++j)
      {
        exposure_by_date_name[i][j] = NumericVector(68);
      }
    }
    Rcpp::Rcout << "done work " << std::endl;
  }
  return;
}
我还注意到,这些时间似乎并没有花在填充地图结构上,“完成的工作”打印出来会很快打印出来,而且大部分时间都花在可能的某种清理上


有人了解到在使用无序地图的情况下,清理过程中等待的时间很长吗?

部分答案记录了我的发现:


  • 我可以在g++版本6.2和clang++版本3.8中重现这个问题,在这两种情况下都使用
    -O2
  • 它仅适用于
    std::unordered_map
    Rcpp::NumericVector
    Rcpp::IntegerVector
    的组合
  • 使用
    std::map
    boost::unordered_map
    而不是
    std::unordered_map
    可以消除该问题。使用
    std::vector
    而不是
    Rcpp::NumericVector
    也是如此
测试代码:

#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(BH)]]
#include <boost/unordered_map.hpp>

template<typename T, typename V>
void map_test(int a, int b) {
  T exposure_by_date_name;
  for (int i=0; i < a; ++i)
  {
    for (int j=0; j < b; ++j)
    {
      exposure_by_date_name[i][j] = V(68);
    }
  }
  Rcpp::Rcout << "done work" << std::endl;
}

// [[Rcpp::export]]
void cpp_test2(int a, int b, int type) {
  if (type == 0) {
    map_test<std::unordered_map<int, std::unordered_map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
  } else if (type == 1) {
    map_test<std::map<int, std::map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
  } else if (type == 2) {
    map_test<std::unordered_map<int, std::unordered_map<int, std::vector<double>>>, std::vector<double>>(a, b);
  } else if (type == 3) {
    map_test<boost::unordered_map<int, boost::unordered_map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
  } else if (type == 4) {
    map_test<std::unordered_map<int, std::unordered_map<int, Rcpp::IntegerVector>>, Rcpp::IntegerVector>(a, b);
  }
  Rcpp::Rcout << "function done" << std::endl;
}

/*** R
result = vector(mode = "list")
for (type in c(0, 1, 2, 3, 4))
{
  for (n in c(10, 50, 100, 200, 500))
  {
    this_result = system.time(cpp_test2(100, n, type))
    this_result$type = type
    this_result$n = n
    result = rbind(result, this_result)
    print(result)
  }
}
print(result)
*/

你在测试优化版还是未优化版?好问题。。。我对rcpp比较陌生,我甚至不知道如何控制它来构建优化或不优化的cpp代码。。。我如何判断/控制这一点以及默认值是什么?如果你在寻找性能,我想我在某个地方读到过,最好使用
boost::unordered\u map
而不是
std::unordered\u map
。您可以通过包{BH}获得boost头文件。我可以通过优化的构建(通过调用
Rcpp::sourceCpp
,使用选项
verbose=TRUE
)重现问题。如果我使用
std::vector
而不是
Rcpp::NumericVector
),它就会消失。疯狂。在您的系统上,什么是
sizeof(std::vector)
vs
sizeof(Rcpp::NumericVector)
?这会导致不同的分配/负载因子策略吗?@KonradRudolph,
sizeof(std::vector)
为24,
sizeof(Rcpp::NumericVector)
为16。
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(BH)]]
#include <boost/unordered_map.hpp>

template<typename T, typename V>
void map_test(int a, int b) {
  T exposure_by_date_name;
  for (int i=0; i < a; ++i)
  {
    for (int j=0; j < b; ++j)
    {
      exposure_by_date_name[i][j] = V(68);
    }
  }
  Rcpp::Rcout << "done work" << std::endl;
}

// [[Rcpp::export]]
void cpp_test2(int a, int b, int type) {
  if (type == 0) {
    map_test<std::unordered_map<int, std::unordered_map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
  } else if (type == 1) {
    map_test<std::map<int, std::map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
  } else if (type == 2) {
    map_test<std::unordered_map<int, std::unordered_map<int, std::vector<double>>>, std::vector<double>>(a, b);
  } else if (type == 3) {
    map_test<boost::unordered_map<int, boost::unordered_map<int, Rcpp::NumericVector>>, Rcpp::NumericVector>(a, b);
  } else if (type == 4) {
    map_test<std::unordered_map<int, std::unordered_map<int, Rcpp::IntegerVector>>, Rcpp::IntegerVector>(a, b);
  }
  Rcpp::Rcout << "function done" << std::endl;
}

/*** R
result = vector(mode = "list")
for (type in c(0, 1, 2, 3, 4))
{
  for (n in c(10, 50, 100, 200, 500))
  {
    this_result = system.time(cpp_test2(100, n, type))
    this_result$type = type
    this_result$n = n
    result = rbind(result, this_result)
    print(result)
  }
}
print(result)
*/
            user.self sys.self elapsed user.child sys.child type n  
this_result 0.004     0        0.003   0          0         0    10 
this_result 0.096     0        0.097   0          0         0    50 
this_result 0.444     0        0.443   0          0         0    100
this_result 1.572     0.004    1.574   0          0         0    200
this_result 18.9      0        18.899  0          0         0    500
this_result 0.004     0        0.002   0          0         1    10 
this_result 0.004     0        0.004   0          0         1    50 
this_result 0.004     0        0.006   0          0         1    100
this_result 0.008     0        0.009   0          0         1    200
this_result 0.028     0        0.026   0          0         1    500
this_result 0.004     0        0.001   0          0         2    10 
this_result 0.004     0        0.002   0          0         2    50 
this_result 0.004     0        0.004   0          0         2    100
this_result 0.008     0        0.007   0          0         2    200
this_result 0.02      0        0.018   0          0         2    500
this_result 0.004     0        0.001   0          0         3    10 
this_result 0         0        0.002   0          0         3    50 
this_result 0.004     0        0.004   0          0         3    100
this_result 0.008     0        0.008   0          0         3    200
this_result 0.02      0        0.022   0          0         3    500
this_result 0.004     0        0.003   0          0         4    10 
this_result 0.096     0        0.093   0          0         4    50 
this_result 0.376     0        0.376   0          0         4    100
this_result 1.508     0        1.508   0          0         4    200
this_result 18.896    0.024    18.916  0          0         4    500