让 gperftools 与 Rcpp 一起工作
Getting gperftools to work with Rcpp
我已阅读相关帖子 here and here, and looked at Dirk Eddelbuettel's talk 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
行上。
我无法访问 OS X 机器,但以下在 Debian 8 上运行,我刚刚在 ProfilerStart
/ ProfilerStop
调用中添加了您的 C++ 代码(根本没有更改您的 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 }')
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 等手动获取文件名。
在 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
暗示我们没有向编译器提供link Google perftools 库所需的信息。在 linker 调用中添加一个 -lprofiler
位足以解决此问题——最简单的方法是向 ~/.R/Makevars
添加一些内容,例如:
LDFLAGS = -L/usr/local/lib -lprofiler
假设您安装了 Google perftools + symlink以标准方式编辑到 /usr/local
。
更彻底的解决方案将涉及实现生成这些标志所需的 Rcpp 属性代码,以便添加 // [[Rcpp::plugin(gperftools)]]
足以确保 Rcpp 自动添加所需的标志。有关如何实现的一些信息,请参阅 ?Rcpp::Rcpp.plugin.maker
。
我已阅读相关帖子 here and here, and looked at Dirk Eddelbuettel's talk 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
行上。
我无法访问 OS X 机器,但以下在 Debian 8 上运行,我刚刚在 ProfilerStart
/ ProfilerStop
调用中添加了您的 C++ 代码(根本没有更改您的 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 }')
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 等手动获取文件名。
在 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
暗示我们没有向编译器提供link Google perftools 库所需的信息。在 linker 调用中添加一个 -lprofiler
位足以解决此问题——最简单的方法是向 ~/.R/Makevars
添加一些内容,例如:
LDFLAGS = -L/usr/local/lib -lprofiler
假设您安装了 Google perftools + symlink以标准方式编辑到 /usr/local
。
更彻底的解决方案将涉及实现生成这些标志所需的 Rcpp 属性代码,以便添加 // [[Rcpp::plugin(gperftools)]]
足以确保 Rcpp 自动添加所需的标志。有关如何实现的一些信息,请参阅 ?Rcpp::Rcpp.plugin.maker
。