【问题标题】:Profiling Rcpp code on OS X在 OS X 上分析 Rcpp 代码
【发布时间】:2012-10-24 19:54:10
【问题描述】:

我有兴趣在 OS X(Mountain Lion 10.8.2)下分析一些 Rcpp 代码,但分析器在运行时崩溃。

使用inline 的玩具示例,只是为了花足够的时间让分析器注意到。

library(Rcpp)
library(inline)

src.cpp <- "
  RNGScope scope;
  int n = as<int>(n_);
  double x = 0.0;
  for ( int i = 0; i < n; i++ )
    x += (unif_rand()-.5);
  return wrap(x);"

src.c <- "
  int i, n = INTEGER(n_)[0];
  double x = 0.0;
  GetRNGstate();
  for ( i = 0; i < n; i++ )
    x += (unif_rand()-.5);
  PutRNGstate();
  return ScalarReal(x);"

f.cpp <- cxxfunction(signature(n_="integer"), src.cpp, plugin="Rcpp")
f.c <- cfunction(signature(n_="integer"), src.c)

如果我使用 GUI Instruments(在 Xcode 中,版本 4.5 (4523))或命令行 sample,两者都会崩溃:Instruments 立即崩溃,而 sample 在崩溃前完成处理样本:

# (in R)
set.seed(1)
f.cpp(200000000L)

# (in a separate terminal window)
~ » sample R  # this invokes the profiler
Sampling process 81337 for 10 seconds with 1 millisecond of run time between samples
Sampling completed, processing symbols...
[1]    81654 segmentation fault  sample 81337

如果我使用 C 版本(即f.c(200000000L))执行相同的过程,则 Instruments 和 sample 都可以正常工作,并产生类似的输出

Call graph:
1832 Thread_6890779   DispatchQueue_1: com.apple.main-thread  (serial)
  1832 start  (in R) + 52  [0x100000e74]
    1832 main  (in R) + 27  [0x100000eeb]
      1832 run_Rmainloop  (in libR.dylib) + 80  [0x1000e4020]
        1832 R_ReplConsole  (in libR.dylib) + 161  [0x1000e3b11]
          1832 Rf_ReplIteration  (in libR.dylib) + 514  [0x1000e3822]
            1832 Rf_eval  (in libR.dylib) + 1010  [0x1000aa402]
              1832 Rf_applyClosure  (in libR.dylib) + 849  [0x1000af5d1]
                1832 Rf_eval  (in libR.dylib) + 1672  [0x1000aa698]
                  1832 do_dotcall  (in libR.dylib) + 16315  [0x10007af3b]
                    1382 file1412f6e212474  (in file1412f6e212474.so) + 53  [0x1007fded5]  file1412f6e212474.cpp:16
                    + 862 unif_rand  (in libR.dylib) + 1127,1099,...  [0x10000b057,0x10000b03b,...]
                    + 520 fixup  (in libR.dylib) + 39,67,...  [0x10000aab7,0x10000aad3,...]
                    356 file1412f6e212474  (in file1412f6e212474.so) + 70,61,...  [0x1007fdee6,0x1007fdedd,...]  file1412f6e212474.cpp:16
                    56 unif_rand  (in libR.dylib) + 1133  [0x10000b05d]
                    38 DYLD-STUB$$unif_rand  (in file1412f6e212474.so) + 0  [0x1007fdf1c]

如果我做错了什么,是否有其他首选方式,或者这是不可能的,我真的很感激一些建议。鉴于 Rcpp 的主要用途之一似乎是加速 R 代码,我很惊讶没有找到更多关于此的信息,但也许我找错地方了。

这是在带有 R 2.15.1 (x86_64-apple-darwin9.8.0)、Rcpp 0.9.15 和 g++ 的 OS X 10.8.2 上 --version 报告“i686-apple-darwin11-llvm-g++-4.2 ( GCC)4.2.1(基于 Apple Inc. build 5658)(LLVM build 2336.11.00)”。

解决方案

感谢 Dirk 在下面的回答,以及他在这里的谈话 http://dirk.eddelbuettel.com/papers/ismNov2009introHPCwithR.pdf,我至少有一个使用 Google perftools 的部分解决方案。首先,从这里安装http://code.google.com/p/gperftools/,并在编译 C++ 代码时将 -lprofiler 添加到 PKG_LIBS。然后要么

(a) 以CPUPROFILE=samples.log R 运行 R,运行所有代码并退出(或使用 Rscript)

(b) 使用两个小实用函数来打开/关闭分析:

RcppExport SEXP start_profiler(SEXP str) {
  ProfilerStart(as<const char*>(str));
  return R_NilValue;
}

RcppExport SEXP stop_profiler() {
  ProfilerStop();
  return R_NilValue;
}

然后,你可以在 R 中做

.Call("start_profiler", "samples.log")
# code that calls C++ code to be profiled
.Call("stop_profiler")

无论哪种方式,文件samples.log 都将包含分析信息。这可以用

查看
pprof --text /Library/Frameworks/R.framework/Resources/bin/exec/x86_64/R samples.log

产生类似的输出

Using local file /Library/Frameworks/R.framework/Resources/bin/exec/x86_64/R.
Using local file samples.log.
Removing __sigtramp from all stack traces.
Total: 112 samples
  64  57.1%  57.1%       64  57.1% _unif_rand
  30  26.8%  83.9%       30  26.8% _process_system_Renviron
  14  12.5%  96.4%      101  90.2% _for_profile
   3   2.7%  99.1%        3   2.7% Rcpp::internal::expr_eval_methods
   1   0.9% 100.0%        1   0.9% _Rf_PrintValueRec
   0   0.0% 100.0%        1   0.9% 0x0000000102bbc1ff
   0   0.0% 100.0%       15  13.4% 0x00007fff5fbfe06f
   0   0.0% 100.0%        1   0.9% _Rf_InitFunctionHashing
   0   0.0% 100.0%        1   0.9% _Rf_PrintValueEnv
   0   0.0% 100.0%      112 100.0% _Rf_ReplIteration

这可能会在一个真实的例子中提供更多信息。

【问题讨论】:

  • +1 -- perftools、gcc profiler 或 valgrind 都可以提供帮助。 R 是交互式的这一事实确实会在此处添加一个扳手,因为它会添加更多代码层。
  • 我在升级 XCode 时自己遇到了这个问题,但我认为可能只是我自己。问题是 Shark 以前可以完美地分析 Rcpp,但现在它已经不存在了。我想我们可以称之为 Apple 错误。

标签: r profiling rcpp


【解决方案1】:

我很困惑,你的例子不完整:

  • 您没有显示cfunction()cxxfunction() 的(微不足道的)调用

  • 你没有展示你是如何调用分析器的

  • 您没有分析 C 或 C++ 代码 (!!)

您能否编辑问题并使其更清楚?

另外,当我运行它时,这两个示例确实给出了相同的速度结果,因为它们本质上是相同的。 [ Rcpp 可以让你在调用中使用糖随机数函数来执行此操作。 ]

R> library(Rcpp)
R> library(inline)
R> 
R> src.cpp <- "
+   RNGScope scope;
+   int n = as<int>(n_);
+   double x = 0.0;
+   for ( int i = 0; i < n; i++ )
+     x += (unif_rand()-.5);
+   return wrap(x);"
R> 
R> src.c <- "
+   int i, n = INTEGER(n_)[0];
+   double x = 0.0;
+   GetRNGstate();
+   for ( i = 0; i < n; i++ )
+     x += (unif_rand()-.5);
+   PutRNGstate();
+   return Rf_ScalarReal(x);"
R> 
R> fc   <- cfunction(signature(n_="int"), body=src.c)
R> fcpp <- cxxfunction(signature(n_="int"), body=src.c, plugin="Rcpp")
R> 
R> library(rbenchmark)
R> 
R> print(benchmark(fc(10000L), fcpp(10000L)))
         test replications elapsed relative user.self sys.self user.child sys.child
1   fc(10000)          100   0.013        1     0.012        0          0         0
2 fcpp(10000)          100   0.013        1     0.012        0          0         0
R> 

【讨论】:

  • 嗨,Dirk,感谢您的帮助!为了清楚起见,我已经编辑了上面的示例,我希望。使用“sample”命令调用分析器,我已经包含了 C 版本的输出,以表明正在分析的是 C。我之前已经成功地将这种通用方法用于 R+C 代码,但没有用于 C++。这些示例应该给出相同的结果,并且不能代表我实际尝试分析的问题。再次感谢,里奇
  • 我现在明白了——我对这方面的 OS X 方面一无所知。对于gcc 等人,我在我的网站/以前的谈话中在“使用 R 的 HPC 简介”幻灯片中添加了一些关于概要分析的注释。您需要使用 r-sig-mac 查看 sample 是否适用于 R 工具链。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-21
  • 2014-02-09
相关资源
最近更新 更多