erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 line
5.6 KiB

4 年之前
  1. -module(utVMInfo).
  2. -compile([export_all, nowarn_export_all]).
  3. %% 打印并排序各个表的缓存消耗
  4. show_cache() ->
  5. io:format("table name | memory | size~n", []),
  6. lists:reverse(lists:keysort(2, [{T, ets:info(T, memory), ets:info(T, size)} || T <- ets:all()])).
  7. %% 打印进程消耗内存的信息
  8. show_process() ->
  9. lists:reverse(lists:keysort(2, [{erlang:process_info(P, registered_name), erlang:process_info(P, heap_size)} || P <- erlang:processes()])).
  10. %% 打印当前进程数量
  11. show_process_count() ->
  12. length(erlang:processes()).
  13. %% 反编译
  14. %% 确认线上运行代码是否正确,reltools没掌握好,升级偶尔出现问题
  15. decompile(Mod) ->
  16. {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(code:which(Mod), [abstract_code]),
  17. io:format("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
  18. %% 进程栈
  19. %% 类似于jstack,发现大量进程挂起,进程数过高,运行慢,hang住等问题用到
  20. pstack(Reg) when is_atom(Reg) ->
  21. case whereis(Reg) of
  22. undefined -> undefined;
  23. Pid -> pstack(Pid)
  24. end;
  25. pstack(Pid) ->
  26. io:format("~s~n", [element(2, process_info(Pid, backtrace))]).
  27. %% ====================================================================
  28. %% etop
  29. %% 分析内存、cpu占用进程,即使数十w进程node 也能正常使用
  30. %% 进程CPU占用排名
  31. %% --------------------------------------------------------------------
  32. etop() ->
  33. spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, reductions}]) end).
  34. %% 进程Mem占用排名
  35. etop_mem() ->
  36. spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, memory}]) end).
  37. %% 停止etop
  38. etop_stop() ->
  39. etop:stop().
  40. %% ====================================================================
  41. %% 对所有process做gc
  42. %% 进程内存过高时,来一发,看看是内存泄露还是gc不过来
  43. gc_all() ->
  44. [erlang:garbage_collect(Pid) || Pid <- processes()].
  45. %% 对MFA 执行分析,会严重减缓运行,建议只对小量业务执行
  46. %% 结果:
  47. %% fprof 结果比较详细,能够输出热点调用路径
  48. fprof(M, F, A) ->
  49. fprof:start(),
  50. fprof:apply(M, F, A),
  51. fprof:profile(),
  52. fprof:analyse(),
  53. fprof:stop().
  54. %% 对整个节点内所有进程执行eprof, eprof 对线上业务有一定影响,慎用!
  55. %% 建议TimeoutSec<10s,且进程数< 1000,否则可能导致节点crash
  56. %% 结果:
  57. %% 输出每个方法实际执行时间(不会累计方法内其他mod调用执行时间)
  58. %% 只能得到mod - Fun 执行次数 执行耗时
  59. eprof_all(TimeoutSec) ->
  60. eprof(processes() -- [whereis(eprof)], TimeoutSec).
  61. eprof(Pids, TimeoutSec) ->
  62. eprof:start(),
  63. eprof:start_profiling(Pids),
  64. timer:sleep(TimeoutSec),
  65. eprof:stop_profiling(),
  66. eprof:analyze(total),
  67. eprof:stop().
  68. %% scheduler usage
  69. %% 统计下1s每个调度器CPU的实际利用率(因为有spin wait、调度工作, 可能usage 比top显示低很多)
  70. scheduler_usage() ->
  71. scheduler_usage(1000).
  72. scheduler_usage(RunMs) ->
  73. erlang:system_flag(scheduler_wall_time, true),
  74. Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)),
  75. timer:sleep(RunMs),
  76. Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)),
  77. erlang:system_flag(scheduler_wall_time, false),
  78. Cores = lists:map(fun({{_I, A0, T0}, {I, A1, T1}}) ->
  79. {I, (A1 - A0) / (T1 - T0)} end, lists:zip(Ts0, Ts1)),
  80. {A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai,Ti}) ->
  81. {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0, Ts1)),
  82. Total = A/T,
  83. io:format("~p~n", [[{total, Total} | Cores]]).
  84. %% 进程调度
  85. %% 统计下1s内调度进程数量(含义:第一个数字执行进程数量,第二个数字迁移进程数量)
  86. scheduler_stat() ->
  87. scheduler_stat(1000).
  88. scheduler_stat(RunMs) ->
  89. erlang:system_flag(scheduling_statistics, enable),
  90. Ts0 = erlang:system_info(total_scheduling_statistics),
  91. timer:sleep(RunMs),
  92. Ts1 = erlang:system_info(total_scheduling_statistics),
  93. erlang:system_flag(scheduling_statistics, disable),
  94. lists:map(fun({{_Key, In0, Out0}, {Key, In1, Out1}}) ->
  95. {Key, In1 - In0, Out1 - Out0} end, lists:zip(Ts0, Ts1)).
  96. %% ====================================================================
  97. %% trace 日志
  98. %% 会把mod 每次调用详细MFA log 下来,args 太大就不好看了
  99. %% trace Mod 所有方法的调用
  100. %% --------------------------------------------------------------------
  101. trace(Mod) ->
  102. dbg:tracer(),
  103. dbg:tpl(Mod, '_', []),
  104. dbg:p(all, c).
  105. %% trace Node上指定 Mod 所有方法的调用, 结果将输出到本地shell
  106. trace(Node, Mod) ->
  107. dbg:tracer(),
  108. dbg:n(Node),
  109. dbg:tpl(Mod, '_', []),
  110. dbg:p(all, c).
  111. %% 停止trace
  112. trace_stop() ->
  113. dbg:stop_clear().
  114. %% ====================================================================
  115. %% 内存高OOM 排查工具
  116. %% etop 无法应对10w+ 进程节点, 下面代码就没问题了;找到可疑proc后通过pstack、message_queu_len 排查原因
  117. proc_mem_all(SizeLimitKb) ->
  118. Procs = [{undefined, Pid} || Pid<- erlang:processes()],
  119. proc_mem(Procs, SizeLimitKb).
  120. proc_mem(SizeLimitKb) ->
  121. Procs = [{Name, Pid} || {_, Name, Pid, _} <- release_handler_1:get_supervised_procs(),
  122. is_process_alive(Pid)],
  123. proc_mem(Procs, SizeLimitKb).
  124. proc_mem(Procs, SizeLimitKb) ->
  125. SizeLimit = SizeLimitKb * 1024,
  126. {R, Total} = lists:foldl(fun({Name, Pid}, {Acc, TotalSize}) ->
  127. case erlang:process_info(Pid, total_heap_size) of
  128. {_, Size0} ->
  129. Size = Size0*8,
  130. case Size > SizeLimit of
  131. true -> {[{Name, Pid, Size} | Acc], TotalSize+Size};
  132. false -> {Acc, TotalSize}
  133. end;
  134. _ -> {Acc, TotalSize}
  135. end
  136. end, {[], 0}, Procs),
  137. R1 = lists:keysort(3, R),
  138. {Total, lists:reverse(R1)}.
  139. %% ====================================================================
  140. %% Internal functions
  141. %% ====================================================================