`
一个程序猿
  • 浏览: 3366 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

erlang进程性能分析方法

阅读更多
有时erlang进程cpu异常高,可以通过下面的工具函数(fprof)来分析一下各函数占用cpu时间的情况
Now = fun() ->
    {A, B, _} = erlang:now(),
    A * 1000000 + B
end.

Fprof_start = fun(Procs) ->
    fprof:trace([start, {file, "/tmp/fprof.trace"}, {procs, Procs}])
end.

Fprof_stop = fun() ->
    ok = fprof:trace(stop),
    ok = fprof:profile({file, "/tmp/fprof.trace"}),
    Analyse = lists:concat(["/tmp/fprof-", Now(), ".analysis"]),
    % {sort, own}
    ok = fprof:analyse([{dest, Analyse}, {details, true}, {totals, true}, {sort, own}]),
    io:format(("fprof result:~s\n"), [Analyse]),
    ok
end.

%% Fprof_start  Fprof_stop 是用来开启和关闭对erlang系统的监控,并生成分板结果文件/tmp/fprof-xxxx.analysis

调用方式:
PID = pid(x,x,x). %% 需要监控的erlang进程号,可以通过etop来查出哪个进程cpu异常高,使用方法常见注1
Fprof_start(PID).
%% 停一段时间,具体看情况,可能是20秒吧
Fprof_stop().
%% 然后就可以看分析结果文件了,如何分析见注2

如果不需要分析得这么细可以用 eprof
eprof:start().
eprof:profile([pid(x,x,x)]).
eprof:stop_profiling().
eprof:analyze().
%% 停一小段时间
eprof:stop().


另外推荐一本erlang之父写的经典名书《Erlang程序设计》,前阵子看到淘宝上有卖,还送erlang资料,随手买了一本收藏:
http://item.taobao.com/item.htm?id=26286504297
注1:
spawn(fun() -> etop:start([{output, text}, {interval, 5}, {lines, 20}, {sort, memory}]) end).


sortIdentifies what information to sort by.
Value: runtime | reductions | memory | msg_q
Default: runtime (reductions if tracing=off)

注2:转自涛老大的博客http://erlangdisplay.iteye.com/blog/318975
Erlang tools lib中包含三个用于性能分析的工具:cprof,eporf和fprof。
cprof 提供函数调用计数,其对系统的性能影响最小
eprof 提供函数运行时间的百分比
fprof 通过将trace存储到文件,提供函数调用计数及运行时间统计信息

这里我们主要介绍fprof,首先其提供的信息最为详细,其次因为将trace存储到文件中,我们可以进行较长运行时间的性能分析

fprof使用

1,fprof:start().
2,
Erlang代码  
1. fprof:apply 
2. fprof:profile 
3. fprof:analyse 
     
OR  
Erlang代码  
1. fprof:trace(start) 
2. fprof:trace(stop) 
3. fprof:profile 
4. fprof:analyse 

apply在函数开始的时候进行fprof:trace(start, ..),在函数结束的时候执行fprof:trace(stop).上面三个函数都有很多可选参数,默认情况下,使用下面文件保存各阶段信息:fprof.trace, fprof.profile,fprof.analysis
  
fprof Analysis format
产生了分析报告,最重要的就是如何阅读了。

让我们写一个简单的例子:
Erlang代码  
1. -module(bar). 
2. -export([test/1]). 
3.  
4. test(N) when is_integer(N) ->     
5.     L = lists:seq(1, N), 
6.     L2 = lists:map(fun(E) -> E * 2 end, L), 
7.     _L3 = lists:splitwith(fun(E) -> E rem 2 =:= 0 end, L2), 
8.     ok. 


进行profiling

Erlang代码  
1. > c(bar). 
2. > fprof:apply(bar, test, [1000]). 
3. > fprof:profile(). 
4. > fprof:analyse({dest, "bar.analysis"}). 
5. Processing data... 
6. Creating output... 
7. Done! 
8. ok 


analysis结果已经保存到bar.analysis中,此文件可以通过erl_scan and erl_parse, file:consult/1 or io:read/2进行读取分析。

下面我们看看analysis内容:
引用

%% Analysis results:
{  analysis_options,
[{callers, true},
  {sort, acc},
  {totals, false},
  {details, true}]}.

%                                               CNT       ACC       OWN       
[{ totals,                                     5019,   18.886,   18.884}].  %%%


CNT表示总的函数调用次数,ACC表示Trace起始经历的时间,OWN是Trace中所有函数执行的时间和(不包含调用函数的执行时间),我们这个例子中OWN和ACC比较接近,因为我们这里在启动trace后就立即开始了函数调用,没有进行其他特殊的工作。这里时间的单位为ms。

引用

%                                               CNT       ACC       OWN       
[{ "<0.82.0>",                                 5019,undefined,   18.884}].   %%

这里表示一个process的开始,在我们这个例子中我们调用fprof:apply/3开始进行trace,因此这个Pid其实就是我们调用apply所在的Process,我们没有Spawn新的Process,所以这里的CNT,OWN和totals相同。ACC的值为undefined,这是因为这个数值对于我们没有什么意义,我们可以通过totals计算出这个数值。
请注意此行结尾处的 “%%”表明一个process的开始

引用

{[{undefined,                                     0,   18.886,    0.002}],    
{ {fprof,apply_start_stop,4},                    0,   18.886,    0.002},     %
[{{bar,test,1},                                  1,   18.884,    0.004},     
  {suspend,                                       1,    0.000,    0.000}]}.   

{[{{fprof,apply_start_stop,4},                    1,   18.884,    0.004}],    
{ {bar,test,1},                                  1,   18.884,    0.004},     %
[{{lists,map,2},                                 1,   14.859,   12.352},     
  {{lists,splitwith,2},                           1,    3.012,    0.001},     
  {{lists,seq,2},                                 1,    1.009,    0.001}]}.   

analysis内容通过空行,间隔成不同的段落。

每个段落中尾部以"%"标记的行为这个段落的标记行。比如上面的内容中{bar,test,1}所在行为一个关键行,此行上面的List为所有调用bar:test/1的函数列表(called list),此行下面的List为bar:test/1调用的函数列表(calling list)。

所有的段落按照ACC递减的顺序排列,同时段落内部的called list和calling list也是按照这个规则排列。

CNT为对应函数累计调用次数,ACC为此函数消耗时间包含其调用的函数,OWN为此函数自身消耗时间不包含called函数。即:
ACC(marked) = OWN(marked) + ACC(calling fun 1) + ACC(calling fun 2) ... ACC(calling fun N)
让我们看看上面的内容中,{bar,test,1}其ACC为:
18.884 = 0.004 + 14.859 + 3.012 + 1.009
同时{bar,test,1}作为我们module的入口其ACC为18.884等于所在process对应的OWN时间。

其实看到这里,我们已经明白,我们这个module中{lists,map,2}最耗时,其占用79% (14.859/18.880)时间,{lists,splitwith,2}占用16% (3.012/18.880) 的时间,而{lists,seq,2} (1.009%18.880) 只占用5%左右。

引用

{[{{bar,test,1},                                  1,   14.859,   12.352},     
  {{lists,map,2},                              1000,    0.000,    1.502}],    
{ {lists,map,2},                              1001,   14.859,   13.854},     %
[{{bar,'-test/1-fun-0-',1},                   1000,    1.002,    1.001},     
  {garbage_collect,                               2,    0.002,    0.002},     
  {suspend,                                       1,    0.001,    0.000},     
  {{lists,map,2},                              1000,    0.000,    1.502}]}.  

接下来就是依次分析所有的被调用函数,这里说明{lists,map,2}被两个函数调用:
{bar,test,1}和{lists,map,2},也许你有疑问了,在bar:test/1中的确调用了lists:map/2依次,可是我的代码中没有用lists:map/2调用lists:map/2啊,看看stdlib/src/lists.erl代码,你就会明白,lists:map/2是递归方式调用,所以bar module中调用了1次,而我们的List长度是1000,所以lists:map/2函数就被调用了 1 + 1000 = 1001次哦。然后marked行下面就是lists:map/2调用的函数列表。

bar.analysis接下的部分,是对每个函数的分析,如果某个函数为BIF,没有调用任何其他函数,那么其对应的输出内容为:
引用

{[{{lists,reverse,1},                             1,    0.001,    0.001}],    
{ {lists,reverse,2},                             1,    0.001,    0.001},     %
[ ]}.

恩,我们lists:reverse/2是BIF,毫无疑问。

在结果中出现了suspend,这是一个pseudo函数,用来说明我们的process此刻处于中止状态,为什么会处于中止状态?我们没有调用erlang:yield/0,也没有调用receive相关的函数,怎么中止了呢?这里是Erlang虚拟机调度的结果,suspend函数对应的ACC时间总是为0,要不要把真正的suspend时间显示出来,这是一个值得争论的问题。
同样的还有garbage_collect函数,其OWN和ACC相同,这里我们把garbage_collect计入了运行时间。


分享到:
评论

相关推荐

    Erlang--性能分析工具之eprof

    **Erlang——性能分析工具之eprof** 在Erlang编程中,优化代码性能是提高系统效率的关键环节。Erlang的eprof工具就是为此目的设计的,它是一个强大的性能分析器,帮助开发者识别和定位程序中的瓶颈。通过深入理解...

    erlang 深度分析

    - `perf`: 专门用于性能分析的工具。 #### 5. Erlang分布协议(Erlang Distributed Protocol) - **概念**: Erlang节点之间通信的协议,支持跨节点的进程间通信。 - **格式**: 包含节点标识、消息类型等字段,保证了...

    erlang整理的一些心得和lunix查看cpu和内存信息的方法

    6. **sar**:系统活动报告工具,可以从日志文件中分析历史性能数据,适用于长期监控。 7. **/proc 文件系统**:Linux 提供了一个虚拟文件系统 `/proc`,其中包含关于系统和进程的实时信息。例如,`/proc/cpuinfo` ...

    Erlang项目内存泄漏分析方法

    1. 确认内存泄漏:使用像top这样的系统监控工具,观察Erlang进程的内存占用情况。如果内存消耗持续升高,那么很可能存在内存泄漏。 2. 进入线上系统:使用Rebar工具,可以方便地管理Erlang项目。通过远程shell命令...

    基于ErlangC函数的Oracle性能预测和分析.pdf

    总之,本文通过结合Erlang C函数和实际操作系统的监控工具,为Oracle数据库性能预测提供了一种科学的分析方法。这种方法可以帮助管理员更好地理解系统的性能瓶颈,预测未来可能的问题,并采取相应措施优化系统,从而...

    图书:Erlang和OTP实战

    4. 并发编程:探讨Erlang进程间的同步和异步通信,以及避免竞态条件和死锁的方法。 5. 容错与恢复:了解Erlang的故障检测和恢复机制,以及如何利用OTP库来实现系统的高可用性。 6. 热代码升级:学习如何在不中断服务...

    erl_nif 扩展erlang的另外一种方法

    4. **错误处理和崩溃恢复**:讲解在NIF中如何正确处理错误,避免Erlang进程因C代码异常而崩溃,并讨论Erlang的错误处理模型如何适应NIF。 5. **并发与线程安全**:由于Erlang是并发编程的语言,NIF必须考虑并发执行...

    erlang服务器集合

    通过分析这些服务器代码,我们可以学习如何利用Erlang的特性来优化性能,如合理使用进程、避免全局状态、减少同步开销等。 总之,这个Erlang服务器集合为学习和研究Erlang在分布式系统、游戏服务器开发中的应用提供...

    erlang lib of iconv

    总之,Erlang Lib of Iconv是一个为Erlang提供字符编码转换功能的库,它的源码和使用方法对于需要处理多种编码格式的Erlang开发者来说是非常有价值的资源。通过深入研究源码和实践应用,开发者可以更好地理解和利用...

    Erlang学习资料

    #### 三、Erlang多核编程实践案例分析 - **工业实例**:Erlang已经在多个行业中得到了广泛应用,特别是在电信领域。例如,Ericsson公司就大量使用Erlang来构建其核心产品和服务。 - **编程示例**:通过具体的编程...

    erlang高级原理和应用PPT

    1. **并发编程**:Erlang的轻量级进程模型,消息传递机制,以及如何通过进程间的通信实现并发和分布式系统的构建。 2. **分布式特性**:Erlang的分布式节点通信,分布式数据管理,以及如何在多台机器上部署和运行...

    Erlang and OTP实战

    这些工具可能包括性能分析、资源监控、进程状态检查等,它们对于维护和优化运行中的系统至关重要。 6. **实现缓存系统**:缓存系统在提高数据密集型应用程序性能方面扮演着重要的角色。在Erlang中实现缓存系统可能...

    erlbench:Erlang性能测量

    **erlbench:Erlang性能测量** Erlang是一种函数式编程语言,以其在并发处理和容错性方面的出色表现而闻名。...掌握`erlbench` 的使用和结果分析,对于提升Erlang应用程序的性能和稳定性具有重要意义。

    Go/Python/Erlang编程语言对比分析及示例代码

    Erlang的并发模型基于actor模型,每个actor都是独立的轻量级进程,通过消息传递进行交互,这种设计天然支持分布式计算。 Python的并发处理相对较弱,虽然有threading和asyncio等模块提供并发支持,但受到GIL(全局...

    getting_started_erlang-5.4.pdf

    - **单向链接(monitor)**:Erlang 进程间通信的一种机制,用于监视其他进程的状态。 - **二进制数据处理(binaries/bitsyntax)**:Erlang 处理二进制数据的特殊语法。 - **列表推导(List Comprehensions)**:一...

    Manning.Erlang.and.OTP.in.Action.May.2010.MEAP

    - **性能测试**:介绍了如何使用各种工具和技术来进行性能测试和分析。 #### 七、安装与配置 - **安装Erlang**:附录A提供了详细的指导,帮助读者顺利安装Erlang环境。 - **列表与引用透明性**:附录B深入探讨了...

    RabbitMQ进程结构分析与性能调优

    【RabbitMQ进程结构分析】 RabbitMQ是一个基于Erlang构建的开源消息队列系统,它遵循AMQP(高级消息...通过对RabbitMQ的进程结构分析和性能调优,可以更好地利用其特性,解决实际工作中的挑战,提高系统的整体效率。

Global site tag (gtag.js) - Google Analytics