让 gperftools 与 Rcpp 一起工作

Posted

技术标签:

【中文标题】让 gperftools 与 Rcpp 一起工作【英文标题】:Getting gperftools to work with Rcpp 【发布时间】:2016-10-18 20:31:36 【问题描述】:

我已阅读相关帖子 here 和 here,并查看了 Dirk Eddelbuettel 的演讲 here,但我什至无法从 gperftools 获取 .log 文件。这是我的R 文件,名为Rcpp_practice.R

library(Rcpp)

Sys.setenv("PKG_LIBS"="-lprofiler")
sourceCpp('eigen.cpp')

a <- matrix(rnorm(300^2), 300, 300)
getEigenValues(a)

这里是eigen.cpp的内容:

#include <RcppArmadillo.h>
#include <gperftools/profiler.h>
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::vec getEigenValues(arma::mat M) 
    return arma::eig_sym(M);

然后,在终端上(我使用的是 OSX):

CPUPROFILE="eigenprof.log" R -f "Rcpp_practice.R"

我希望看到eigenprof.log 出现在我的工作目录中,但我没有。另外,我没有收到我在 PROFILE: interrupts/evictions/bytes = 012/34/567891 形式的其他帖子中看到的消息

我确认我安装了最新版本的gperftools。 ($ brew upgrade google-perftools 给了Error: gperftools 2.5 already installed)。

我错过了什么?

更新

在我修改我的代码以匹配 @nrussell 后,我收到以下错误消息:

Error in dyn.load("/private/var/folders/6k/ffcchdq52kbb7d631b5vsqcw0000gn/T/RtmpCIdHkG/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7/sourcecpp_6c3253d60384/sourceCpp_2.so") : 
unable to load shared object '/private/var/folders/6k/ffcchdq52kbb7d631b5vsqcw0000gn/T/RtmpCIdHkG/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7/sourcecpp_6c3253d60384/sourceCpp_2.so':
dlopen(/private/var/folders/6k/ffcchdq52kbb7d631b5vsqcw0000gn/T/RtmpCIdHkG/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7/sourcecpp_6c3253d60384/sourceCpp_2.so, 6): Symbol not found: _ProfilerStart
Referenced from: /private/var/folders/6k/ffcchdq52kbb7d631b5vsqcw0000gn/T/RtmpCIdHkG/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7/sourcecpp_6c3253d60384/sourceCpp_2.so
Expected in: flat namespace
in /private/var/folders/6k/ffcchdq52kbb7d631b5vsqcw0000gn/T/RtmpCIdHkG/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7/sourcecpp_6c3253d60384/sourceCpp_2.so
Calls: sourceCpp -> source -> withVisible -> eval -> eval -> dyn.load
Execution halted

如果我以交互方式运行脚本,则会出现在 sourceCpp 的行中。

【问题讨论】:

您只显示部分命令。这肯定在很多个月前曾经有效,现在仍然应该有效。我要做的是从 c++ 文件中的最小 main() 回溯,确保我已整理好所有编译和链接标志和选项——然后将其带到基于 Rcpp 的构建中。 【参考方案1】:

我无法访问 OS X 机器,但以下在 Debian 8 上工作,我刚刚添加了对 C++ 代码的 ProfilerStart / ProfilerStop 调用(并且没有更改你的 R 代码完全¹):

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <gperftools/profiler.h>

// [[Rcpp::export]]
arma::vec getEigenValues(arma::mat M) 
    ProfilerStart("./eigen-prof.log");
    return arma::eig_sym(M);
    ProfilerStop();

¹请参阅下面的更新。


然后从终端,

R -f eigen-prof.R > /dev/null && google-pprof --text $(which R) eigen-prof.log 

# PROFILE: interrupts/evictions/bytes = 2/0/264
# Using local file /usr/local/bin/R.
# Using local file eigen-prof.log.
# /usr/bin/addr2line: /usr/local/bin/R: File format not recognized
# Total: 2 samples
#        1  50.0%  50.0%        1  50.0% dlamch_
#        1  50.0% 100.0%        1  50.0% dsymv_
#        0   0.0% 100.0%        1  50.0% 00000000004007ca
#        0   0.0% 100.0%        1  50.0% 00000000004007fa
#        0   0.0% 100.0%        1  50.0% 00007f84002bf0bd
#        0   0.0% 100.0%        1  50.0% 00007f84002bf2a8
#        0   0.0% 100.0%        1  50.0% 00007f84002c14c8
#        0   0.0% 100.0%        1  50.0% R_ReplConsole
#        0   0.0% 100.0%        1  50.0% Rf_ReplIteration
#        0   0.0% 100.0%        1  50.0% Rf_applyClosure
#        0   0.0% 100.0%        1  50.0% Rf_eval
#        0   0.0% 100.0%        1  50.0% __libc_start_main
#        0   0.0% 100.0%        1  50.0% dlatrd_
#        0   0.0% 100.0%        1  50.0% do_dotcall
#        0   0.0% 100.0%        1  50.0% dsyev_
#        0   0.0% 100.0%        1  50.0% dsytrd_
#        0   0.0% 100.0%        1  50.0% frame_dummy
#        0   0.0% 100.0%        1  50.0% run_Rmainloop 

关于您的更新,请尝试将 sourceCpp 调用更改为

sourceCpp(
    'eigen-prof.cpp',
    verbose = TRUE,
    rebuild = TRUE,
    cacheDir = "/tmp/profdir"
)

我使用cacheDir = "/tmp/profdir" 覆盖sourceCpp 用于构建共享库的默认随机目录(tempdir());和rebuild = TRUE 以确保每次运行都会生成一个新的.so

回到您的 shell,运行这些命令,根据需要替换适当的文件和目录名称:

R -f eigen-prof.R so_file=$(find /tmp/profdir/ -iname '*.so' -printf "%T+\t%p\n" | sort -r | head -n1 | awk 'print $2') google-pprof --text $so_file eigen-prof.log

这给了我

# Using local file /tmp/profdir/sourceCpp-x86_64-pc-linux-gnu-0.12.7/sourcecpp_5dc5531d6f20/sourceCpp_4.so.
# Using local file eigen-prof.log.
# Total: 2 samples
#        1  50.0%  50.0%        1  50.0% dsterf_
#        1  50.0% 100.0%        1  50.0% dsymv_
#        0   0.0% 100.0%        2 100.0% 0x00000000004007ca
#        0   0.0% 100.0%        2 100.0% 0x00000000004007fa
#        0   0.0% 100.0%        2 100.0% R_ReplConsole
#        0   0.0% 100.0%        2 100.0% Rf_ReplIteration
#        0   0.0% 100.0%        2 100.0% Rf_applyClosure
#        0   0.0% 100.0%        2 100.0% Rf_eval
#        0   0.0% 100.0%        2 100.0% __libc_start_main
#        0   0.0% 100.0%        2 100.0% arma::auxlib::eig_sym
#        0   0.0% 100.0%        1  50.0% dlatrd_
#        0   0.0% 100.0%        2 100.0% do_dotcall
#        0   0.0% 100.0%        2 100.0% dsyev_
#        0   0.0% 100.0%        1  50.0% dsytrd_
#        0   0.0% 100.0%        2 100.0% eig_sym (inline)
#        0   0.0% 100.0%        2 100.0% getEigenValues
#        0   0.0% 100.0%        2 100.0% run_Rmainloop
#        0   0.0% 100.0%        2 100.0% sourceCpp_1_getEigenValues
#        0   0.0% 100.0%        2 100.0% syev (inline)

我把第二步放在一起,所以不要以此来评判我;但它只是在您传递给cacheDir(在我的情况下为/tmp/profdir)的目录中搜索最近创建(修改)的.so 文件。如果您的机器缺少任何这些程序,您也可以使用 Finder 等手动获取文件名。

【讨论】:

“这个东西插上了吗?” Get the machine that goes 'Biiing' 这至少让我遇到了一个新错误。它很大,但以Error in dyn.load 开头,包括unable to load shared object '/a/long/path/sourceCpp_2.soExpected in: flat namespace【参考方案2】:

在 OS X 上,当我天真地尝试编译代码时,我看到了同样的错误:

> Rcpp::sourceCpp('scratch/prof.cpp')
Error in dyn.load("/private/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T/RtmpgOwFk7/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7.1/sourcecpp_9f424793a11/sourceCpp_2.so") : 
  unable to load shared object '/private/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T/RtmpgOwFk7/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7.1/sourcecpp_9f424793a11/sourceCpp_2.so':
  dlopen(/private/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T/RtmpgOwFk7/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7.1/sourcecpp_9f424793a11/sourceCpp_2.so, 6): Symbol not found: _ProfilerStart
  Referenced from: /private/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T/RtmpgOwFk7/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7.1/sourcecpp_9f424793a11/sourceCpp_2.so
  Expected in: flat namespace
 in /private/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T/RtmpgOwFk7/sourceCpp-x86_64-apple-darwin13.4.0-0.12.7.1/sourcecpp_9f424793a11/sourceCpp_2.so

相关位 Symbol not found: _ProfilerStart 暗示我们没有向编译器提供链接到 Google perftools 库所需的信息。在链接器调用中添加-lprofiler 位就足以解决此问题——最简单的方法是在您的~/.R/Makevars 中添加一些内容,例如:

LDFLAGS = -L/usr/local/lib -lprofiler

假设您已安装 Google perftools + 以标准方式符号链接到 /usr/local

更彻底的解决方案将涉及实现生成这些标志所需的 Rcpp 属性代码,以便添加 // [[Rcpp::plugin(gperftools)]] 足以确保 Rcpp 自动添加所需的标志。请参阅?Rcpp::Rcpp.plugin.maker 了解有关如何实现的一些信息。

【讨论】:

以上是关于让 gperftools 与 Rcpp 一起工作的主要内容,如果未能解决你的问题,请参考以下文章

(Rcpp)armadillos abs() 函数在 std::abs 工作时与 c++ double 一起使用时输出错误值

将 3rd 方头文件与 Rcpp 一起使用

已安装Rcpp Rtools但未找到错误消息g ++

使用带有排序的 gperftools 时分析计时器已过期

使用 Rcpp 中包含的标准

解释 gperftools 在多线程工作负载上的结果