[Erlang_Question21]Erlang性能分析工具eprof fporf的应用

前段时间项目改代码突然cpu波动很大,排查了好久都没有找到原因,只能求助于性能测试工具

<<Erlang程序设计>>----Joe Armstorng[哈哈,登月第一人也叫Armstrong]

P416

cprof测试每个函数被调用了多少次,这个工具为轻量在运行系统上使用这个工具会给系统带来5%~10%的额外负载

fprof显示函数调用和被调用的埋单,并将结果输出到一个文件中,这个工具比较适合于在实验环境或模拟环境中对进行大规模的性能前一段,它会带来非常显著的系统负载.

eprof分分析一个Erlang程序中计算时间主要消耗在哪里,它实际是fprof的前任,不同在于:这适合规模小一些的性能前评估.

于是自己写了封装了一下,便于使用:

你可以使用seek_proc_info:help()查看到具体函数的作用:可以把这个当做cprof和fprof使用例子吧。

2> seek_proc_info:help().
Brief help:
seek_proc_info:queue(N) - show top N pids sorted by queue length
seek_proc_info:memory(N) - show top N pids sorted by memory usage
seek_proc_info:reds(N) - show top N pids sorted by reductions
Erlang shell with Ctrl+C
seek_proc_info:eprof_start() - start eprof on all available pids; DO NOT use on production system!
seek_proc_info:eprof_stop() - stop eprof and print result
seek_proc_info:fprof_start() - start fprof on all available pids; DO NOT use on production system!
seek_proc_info:fprof_stop() - stop eprof and print formatted result
seek_proc_info:fprof_start(N) - start and run fprof for N seconds; use seek_proc_info:fprof_analyze() to analyze collected statistics and print formatted result; use on production system with CARE
seek_proc_info:fprof_analyze() - analyze previously collected statistics using seek_proc_info:fprof_start(N) and print formatted result
seek_proc_info:help() - print this help
ok

只把你想监控的Application加到宏APPS里面,可以查看进程消息,内存,reduction情况。

源代码在下面,也可以自己改改看进程的其它信息哦。

%%%-------------------------------------------------------------------
%%% @author [email protected]
%%% @doc
%%%   A interface for eprof and fprof
%%%   call ?MODULE:help() to see
%%% @end
%%% Created : 03. Sep 2014 3:09 PM
%%%-------------------------------------------------------------------
-module(seek_proc_info).

%% API
-export([eprof_start/0, eprof_stop/0,
  fprof_start/0, fprof_start/1,
  fprof_stop/0, fprof_analyze/0,
  queue/1, memory/1,
  reds/1, help/0
]).

-define(APPS, [kernel,mnesia]).

%%====================================================================
%% API
%%====================================================================
help() ->
  io:format("Brief help:~n"
  "~p:queue(N) - show top N pids sorted by queue length~n"
  "~p:memory(N) - show top N pids sorted by memory usage~n"
  "~p:reds(N) - show top N pids sorted by reductions~n"
  "Erlang shell with Ctrl+C~n"
  "~p:eprof_start() - start eprof on all available pids; "
  "DO NOT use on production system!~n"
  "~p:eprof_stop() - stop eprof and print result~n"
  "~p:fprof_start() - start fprof on all available pids; "
  "DO NOT use on production system!~n"
  "~p:fprof_stop() - stop eprof and print formatted result~n"
  "~p:fprof_start(N) - start and run fprof for N seconds; "
  "use ~p:fprof_analyze() to analyze collected statistics and "
  "print formatted result; use on production system with CARE~n"
  "~p:fprof_analyze() - analyze previously collected statistics "
  "using ~p:fprof_start(N) and print formatted result~n"
  "~p:help() - print this help~n",
    lists:duplicate(12, ?MODULE)).

eprof_start() ->
  eprof:start(),
  case lists:keyfind(running, 1, application:info()) of
    {_, Apps} ->
      case get_procs(?APPS, Apps) of
        [] ->
          {error, no_procs_found};
        Procs ->
          eprof:start_profiling(Procs)
      end;
    _ ->
      {error, no_app_info}
  end.

fprof_start() ->
  fprof_start(0).

fprof_start(Duration) ->
  case lists:keyfind(running, 1, application:info()) of
    {_, Apps} ->
      case get_procs(?APPS, Apps) of
        [] ->
          {error, no_procs_found};
        Procs ->
          fprof:trace([start, {procs, Procs}]),
          io:format("Profiling started~n"),
          if Duration > 0 ->
            timer:sleep(Duration*1000),
            fprof:trace([stop]),
            fprof:stop();
            true->
              ok
          end
      end;
    _ ->
      {error, no_app_info}
  end.

fprof_stop() ->
  fprof:trace([stop]),
  fprof:profile(),
  fprof:analyse([totals, no_details, {sort, own},
    no_callers, {dest, "fprof.analysis"}]),
  fprof:stop(),
  format_fprof_analyze().

fprof_analyze() ->
  fprof_stop().

eprof_stop() ->
  eprof:stop_profiling(),
  eprof:analyze().

queue(N) ->
  dump(N, lists:reverse(lists:ukeysort(1, all_pids(queue)))).

memory(N) ->
  dump(N, lists:reverse(lists:ukeysort(3, all_pids(memory)))).

reds(N) ->
  dump(N, lists:reverse(lists:ukeysort(4, all_pids(reductions)))).

%%====================================================================
%% Internal functions
%%====================================================================
get_procs(Apps, AppList) ->
  io:format("Searching for processes to profile...~n", []),
  Procs = lists:foldl(
    fun({App, Leader},Acc) when is_pid(Leader) ->
      case lists:member(App, Apps) of
        true ->
          [get_procs2(Leader)|Acc];
        false ->
          Acc
      end;
      (_,Acc) ->
        Acc
    end,[], AppList),
  io:format("Found ~p processes~n", [length(Procs)]),
  Procs.

get_procs2(Leader) ->
  lists:filter(
    fun(Pid) ->
      case process_info(Pid, group_leader) of
        {_, Leader} ->
          true;
        _ ->
          false
      end
    end, processes()).

format_fprof_analyze() ->
  case file:consult("fprof.analysis") of
    {ok, [_, [{totals, _, _, TotalOWN}] | Rest]} ->
      OWNs =
        lists:flatmap(
        fun({MFA, _, _, OWN}) ->
          Percent = OWN*100/TotalOWN,
          case round(Percent) of
            0 -> [];
            _ -> [{mfa_to_list(MFA), Percent}]
          end
        end, Rest),
      ACCs = collect_accs(Rest),
      MaxACC = find_max(ACCs),
      MaxOWN = find_max(OWNs),
      io:format("=== Sorted by OWN:~n"),
      lists:foreach(
        fun({MFA, Per}) ->
          L = length(MFA),
          S = lists:duplicate(MaxOWN - L + 2, $ ),
          io:format("~s~s~.2f%~n", [MFA, S, Per])
        end, lists:reverse(lists:keysort(2, OWNs))),
      io:format("~n=== Sorted by ACC:~n"),
      lists:foreach(
        fun({MFA, Per}) ->
          L = length(MFA),
          S = lists:duplicate(MaxACC - L + 2, $ ),
          io:format("~s~s~.2f%~n", [MFA, S, Per])
        end, lists:reverse(lists:keysort(2, ACCs)));
    Err ->
      Err
  end.

mfa_to_list({M, F, A}) ->
  atom_to_list(M) ++ ":" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A);
mfa_to_list(F) when is_atom(F) ->
  atom_to_list(F).

find_max(List) ->
  find_max(List, 0).

find_max([{V, _}|Tail], Acc) ->
  find_max(Tail, lists:max([length(V), Acc]));
find_max([], Acc) ->
  Acc.

collect_accs(List) ->
  List1 = lists:filter(
    fun({{sys, _, _}, _, _, _}) ->
      false;
      ({suspend,_,_,_}) ->
        false;
      ({{gen_fsm, _, _},_,_,_}) ->
        false;
      ({{gen, _, _},_,_,_}) ->
        false;
      ({{gen_server, _, _},_,_,_}) ->
        false;
      ({{proc_lib, _, _},_,_,_}) ->
        false;
      (_) ->
        true
    end, List),
  calculate(List1).

calculate(List1) ->
  TotalACC = lists:sum([A || {_, _, A, _} <- List1]),
  List2 = lists:foldl(fun({MFA, _, ACC, _},NewList) ->
    Percent = ACC*100/TotalACC,
    case round(Percent) of
      0 -> NewList;
      _ -> [{mfa_to_list(MFA), Percent}|NewList]
     end
   end,[],List1),
  lists:reverse(List2).

all_pids(Type) ->
  lists:foldl(
    fun(P, Acc) when P == self() ->
      Acc;
      (P, Acc) ->
        case catch process_info(
          P,[message_queue_len, memory, reductions,
            dictionary, current_function, registered_name]) of
          [{_, Len}, {_, Memory}, {_, Reds},
            {_, Dict}, {_, CurFun}, {_, RegName}] ->
            IntQLen = get_internal_queue_len(Dict),
            if Type == queue andalso Len == 0 andalso IntQLen == 0 ->
              Acc;
              true ->
                [{lists:max([Len, IntQLen]),
                  Len,Memory, Reds, Dict, CurFun, P, RegName}|Acc]
            end;
          _ ->
            Acc
        end
    end, [], processes()).

get_internal_queue_len(Dict) ->
  case lists:keysearch(‘$internal_queue_len‘, 1, Dict) of
    {value, {_, N}} -> N;
    _ -> 0
  end.

dump(N, Rs) ->
  lists:foreach(
    fun({_, MsgQLen, Memory, Reds, Dict, CurFun, Pid, RegName}) ->
      io:format("** pid(~s)~n"
      "** registered name: ~p~n"
      "** memory: ~p~n"
      "** reductions: ~p~n"
      "** message queue len: ~p~n"
      "** current_function: ~p~n"
      "** dictionary: ~p~n~n",
        [pid_to_list(Pid), RegName, Memory, Reds, MsgQLen, CurFun, Dict])
    end, lists:sublist(Rs,N)).

洋葱、萝卜和西红柿,不相信世界上有南瓜这种东西。它们认为那是一种空想。南瓜不说话,只是默默地成长。——于尔克·舒比格《当世界年纪还小的时候》

时间: 2024-11-01 13:50:03

[Erlang_Question21]Erlang性能分析工具eprof fporf的应用的相关文章

erlang性能分析工具

Etop 类似top命令,查看erlang进程占用cpu.内存较高的进程 参数: node        atom       erlang node port        integer    The used port accumulate  boolean    If true execution time is accumulated lines       integer    Number of displayed processes interval    integer   

三种Linux性能分析工具的比较

无论是在CPU设计.服务器研发还是存储系统开发的过程中,性能总是一个绕不过去的硬指标.很多时候,我们发现系统功能完备,但就是性能不尽如意,这时候就需要找到性能瓶颈.进行优化.首先我们需要结合硬件特点.操作系统和应用程序的特点深入了解系统内部的运行机制.数据流图和关键路径,最好找出核心模块.建立起抽象模型:接着需要利用各种性能分析工具,探测相关模块的热点路径.耗时统计和占比.在这方面,Linux操作系统自带了多种灵活又具有专对性的工具,此外一些厂家也开源了不少优秀的性能分析工具.下面就结合笔者最近

Java 性能分析工具

如何利用 JConsole观察分析Java程序的运行,进行排错调优 http://jiajun.iteye.com/blog/810150 如何使用JVisualVM进行性能分析 http://jiajun.iteye.com/blog/1180230 全功能的Java剖析工具(profiler) http://www.blogjava.net/mrzhangshunli/archive/2007/08/27/140088.html http://www.cnblogs.com/jayzee/p

.NET 性能分析工具

Download .NET Profiler http://www.yourkit.com/dotnet/download/ dotTrace 5.5 Performance http://www.jetbrains.com/profiler/ .NET 性能分析工具,布布扣,bubuko.com

系统级性能分析工具perf的介绍与使用

测试环境:Ubuntu14.04  on VMWare Kernel:3.13.0-32 系统级性能优化通常包括两个阶段:性能剖析(performance profiling)和代码优化.性能剖析的目标是寻找性能瓶颈,查找引发性能问题的原因及热点代码.代码优化的目标是针对具体性能问题而优化代码或编译选项,以改善软件性能. 在性能剖析阶段,需要借助于现有的profiling工具,如perf等.在代码优化阶段往往需要借助开发者的经验,编写简洁高效的代码,甚至在汇编级别合理使用各种指令,合理安排各种指

linux下面的性能分析工具简介

iostat 命令详解 iostat用于输出cpu和磁盘I/O相关的统计信息.命令格式: Usage: iostat [ options ] [ <interval> [ <count> ] ] Options are: [ -c ] [ -d ] [ -N ] [ -n ] [ -h ] [ -k | -m ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ] [ -j { ID | LABEL | PATH | UUID | ... } [ <devi

性能分析工具-PerfView

Roslyn的PM(程序经理) Bill Chiles,Roslyn使用纯托管代码开发,但性能超过之前使用C++编写的原生实现,这有什么秘诀呢?他最近写了一篇文章叫做<Essential Performance Facts and .NET Framework Tips>里头推荐了一个性能分析工具<Improving Your App's Performance with PerfView>.PerfView能够收集Windows事件跟踪(ETW)数据来追踪程序的调用流向,这些程序

Java性能优化指南系列(二):Java 性能分析工具

进行JAVA程序性能分析的时候,我们一般都会使用各种不同的工具.它们大部分都是可视化的,使得我们可以直观地看到应用程序的内部和运行环境到底执行了什么操作,所以性能分析(性能调优)是依赖于工具的.在第2章,我强调了基于数据驱动的性能测试是非常重要的,我们必须测试应用的性能并理解每个指标的含义.性能分析和数据驱动非常类似,为了提升应用程序的性能,我们必须获取应用运行的相关数据.如何获取这些数据并理解它们是本章的主题.[本章重点介绍JDK中提供的性能分析工具] 操作系统工具及其分析 程序分析的起点并不

Oracle性能分析工具介绍及使用

oracle数据库级别优化分析工具介绍 当我们对数据库优化诊断时,需要收集相应的信息以供参考,从个人的使用经验来说,这种统计数据分为两大类 一类是数据库级别的统计信息二类是os级别的统计信息 下面就分别介绍在不同的级别下,常用什么工具来收集信息帮助优化诊断 首先是oracle数据库级别优化分析工具介绍 目录: 1.statspack2.ASH3.AWR4.ORACLE EXPLAIN PLAN的总结(查询sql的执行计划)   a.autotrace   b.explain的使用 1.stats