利用Google Perftools和kcachegrind深入分解R措施机能瓶颈
1 分解与Profiling
这里的”分解”对应的单词是”profiling”, 中文好像没有词语能精准地表达出原词的内在, 与”shell”的环境有点雷同, 所以就不去决心翻译了. 由于没有学过软件工程, 不惜先贴一段wiki上profiling的界说[1]:
In software engineering, program profiling, software profiling or simply profiling, a form of dynamic program analysis (as opposed to static code analysis), is the investigation of a program’s behavior using information gathered as the program executes. The usual purpose of this analysis is to determine which sections of a program to optimize – to increase its overall speed, decrease its memory requirement or sometimes both.
要提高R措施的运行速度, 不只仅需要剽悍的呆板(单核高频, 多核并行, GPU)和高效的代码(向量化, 殽杂编程), 寻找措施中的机能瓶颈并举办有针对的优化也是很重要的, “找到北这个偏向”, 就是profiling的意义地址.
R中其实自带了几个最简朴的profiling东西, 我们或多或少都打仗过:
base::system.time()
—— 简略的计时秒表utils::Rprof()
—— 对CPU的浅易profile东西utils::Rprofmem()
—— 对内存的浅易profile东西关于这些函数的利用, 可以参看Ross Ihaka的说明[2]. 与此同时, CRAN上profr(Hadley Wickham)和proftools(Luke Tierney)两个微型包均提供了可视化Rprof()
函数输出功效的本领. 可是, 这类简朴的profiling只将措施拆解了到了单个R运算的条理, 没有提供更深一层, 即profiling compiled code的成果. R原生支持这个特性, 但需要在编译时对默认选项举办简朴的修改[4].
2 安装Google Perftools
翻看Dirk Eddelbuettel牛在useR2010上的RhpcTutorial[3], 个中提到了Google员工开拓的Google Perftools可以profiling compiled code. 试了一下, 感受是个不错的东西, 共同kcachegrind, 还可以将功效可视化.
测试情况: Arch Linux x86_64
AUR上已有一位大人在维护google-perftools(源代码安装):
sudo yaourt -S google-perftools
Fedora:
sudo yum install google-perftools
Ubuntu:
sudo apt-get install google-perftools
不外Ubuntu/Fedora客栈中的二进制包大概较量陈旧了, 无妨直接自行编译版本:
svn checkout http://google-perftools.googlecode.com/svn/trunk/
在Arch x86_64下, google-perftools的默认安装路径为
/usr/bin
库文件libprofiler.so位于
/usr/lib
Google Perftools东西会合除了名为pprof的CPU profiler以外, 还提供了堆内存泄漏检测/利用环境统计等东西. 这里我们只存眷pprof就可以了: 它通过CPU间断采样的方法统计每个函数被采样的次数, 占总采样次数的百分比, 挪用的子函数的被采样次数等等(可以说”分解”在此处照旧较量得当的). 最后通过这些信息寻找措施的(CPU)机能瓶颈.
3 利用Google Perftools
要和R一起利用, pprof有两种可行的运行方法, 第一种较量硬朗: 在编译选项中直接插手对libprofiler.so的引用, R在运行时就会自动加载libprofiler库:
wget http://cran.r-project.org/src/base/R-2/R-2.13.1.tar.gz
tar -xf R-2.13.1.tar.gz
cd R-2.13.1export MAIN_CFLAGS=”-pg”
export MAIN_FFLAGS=”-pg”
export MAIN_LDFLAGS=”-pg”
export LDFLAGS=”-lprofiler”
# 也可显式指定路径:
# export LDFLAGS=”-L/usr/lib -lprofiler”
./configure –enable-R-shlib
参数 -pg 打开R的profiling支持, 设定LDFLAGS用以毗连libprofiler库.
configure完成:
R is now configured for x86_64-unknown-linux-gnuSource directory: .
Installation directory: /usr/localC compiler: gcc -std=gnu99 -g -O2
Fortran 77 compiler: gfortran -g -O2C++ compiler: g++ -g -O2
Fortran 90/95 compiler: gfortran -g -O2
Obj-C compiler:Interfaces supported: X11
External libraries: readline, ICU, lzma
Additional capabilities: PNG, JPEG, TIFF, NLS, cairo
Options enabled: shared R library, shared BLAS, R profiling, JavaRecommended packages: yes
功效无误, 开始编译安装:make && sudo make install这样, 毗连了libprofiler.so的R编译乐成.
第二种利用pprof的方法则相对委婉: 利用时动态预加载库文件就可以了, Dirk大人的RhpcTutorial中已经给出说明, 此略.
选取《Wringting R Extension》 3.2节中给出的一个例子举办测试:
#!/usr/local/lib64/R/bin/Rscript |
将profiling功效记录到文件:
chmod 755 profiling.R |
这里在写R文件时用了一点点能力, 使得它可以或许支持类Unix系统的Shebang特性而直接执行, 参考[7], [8].
执行完毕后, 我们即可利用pprof来阐明输出的功效文件(一个二进制文件!)了. pprof可以将此文件理会成你想要的各类可读的形式. 其参数如下:
pprof –option [ –focus=< regexp > ] [ –ignore=< regexp > ]
[–line or addresses or functions] 可执行文件路径 功效文件路径
方括号为可选项目, < regexp >
为正则表达式.
详细的选项分为几组. 个中输格外式的根基可选项为:
text, callgrind, gv, evince, web, symbols, dot, ps, pdf, svg, gif, raw, list=< regexp >, disasm
text
暗示字符统计输出形式, 其它均对应各自的图形名目;list=< regexp >
暗示输出匹配正则表达式的函数的源代码;diasm=< regexp >
暗示输出匹配正则表达式的函数的反汇编代码.其他较量重要的参数:
–focus=< regexp >
暗示只统计函数名匹配正则表达式的函数的采样;–ignore=< regexp >
暗示不统计函数名匹配正则表达式的函数的采样;[–line or addresses or functions]
暗示生成的统计是基于代码行, 指令地点照旧函数的, 默认是函数.这里仅输出文字型功效:
pprof –cum –text /usr/local/lib64/R/bin/Rscript rprof.out | less |
功效中的前15位:
Total: 254 samples
2 0.8% 0.8% 213 83.9% Rf_applyClosure
24 9.4% 10.2% 213 83.9% Rf_eval
0 0.0% 10.2% 213 83.9% do_begin
0 0.0% 10.2% 212 83.5% do_set
0 0.0% 10.2% 206 81.1% do_internal
0 0.0% 10.2% 148 58.3% do_lapply
7 2.8% 13.0% 123 48.4% Rf_evalList
0 0.0% 13.0% 107 42.1% Rf_ReplIteration
0 0.0% 13.0% 104 40.9% R_ReplConsole
0 0.0% 13.0% 102 40.2% Rf_usemethod
0 0.0% 13.0% 100 39.4% run_Rmainloop
0 0.0% 13.0% 96 37.8% main
0 0.0% 13.0% 92 36.2% __libc_start_main
0 0.0% 13.0% 85 33.5% do_usemethod
1 0.4% 13.4% 85 33.5% forcePromise
输出功效中, 每行对应着一个函数的统计:
假如你的系统中安装了gnu-gv或evince, 即可直接立刻显示一幅无码清晰大图(ps/pdf):
pprof –gv /usr/local/lib64/R/bin/Rscript rprof.out |
其他几个较量常用的选项大概是
生成PDF:
pprof –pdf /usr/local/lib64/R/bin/Rscript rprof.out > rprof.pdf |
生成SVG:
pprof –svg /usr/local/lib64/R/bin/Rscript rprof.out > rprof.svg |
生成GraphViz所支持的dot名目:
pprof –dot /usr/local/lib64/R/bin/Rscript rprof.out > rprof.dot |
虽然, 要想读懂图中的内容, 从而针对某些部门举办优化, 还需要对R的底层较量熟悉才行: 最起码要相识涉及到的C函数的详细成果.
4 共同kcachegrind可视化profile功效
pprof可将输出转化为强大的Valgrind东西会合的组件Callgrind可回收的名目, 共同KCachegrind这个图形前端, 即可对功效举办简朴的可视化, 可以或许交互哦亲:
# For Arch Linux |
其实看上去KCachegrid就是做了一个最普通的树可视化, 所以理论上我们其实可以用角度各异的无数种手段展示profiling功效: 就是画一棵树嘛. 不外KCachegrind中可以与图形交互, 进一步的阐明很利便, 各人可以本身进一步体验.
5 其他东西(sprof和oprofile)
Writing R Extensions[6]提到别的两个可供Linuxer选择的东西: sprof和oprofile, 我没有尝试, 感乐趣的同学不妨实践一下.