Browse Source

ft: 部分优化调整

master
SisMaker 3 years ago
parent
commit
1f535f6941
13 changed files with 121 additions and 95 deletions
  1. +27
    -8
      README.md
  2. +2
    -2
      src/callgrind/tpCallGrind.erl
  3. +9
    -0
      src/eTpf.erl
  4. +0
    -1
      src/eTpf_app.erl
  5. +2
    -2
      src/flame/tpFlame.erl
  6. +2
    -2
      src/gcColl/tpGcColl.erl
  7. +2
    -2
      src/messages/tpMsgRS.erl
  8. +2
    -2
      src/messages/tpMsgSD.erl
  9. +2
    -2
      src/tracer/tpTracerFile.erl
  10. +1
    -0
      src/tracer/tpTracerShell.erl
  11. +3
    -3
      src/tracer/tpTracerSocket.erl
  12. +5
    -5
      src/utils/tpSocketCli.erl
  13. +64
    -66
      src/utils/tpTermCut.erl

+ 27
- 8
README.md View File

@ -13,6 +13,14 @@ Useage
oooo
相关软件
-----
[qcachegrind](http://47.108.26.175:53000/SisMaker/eTpfSoftware)
[graphviz](http://47.108.26.175:53000/SisMaker/eTpfSoftware)
[FlameGraph](https://github.com/brendangregg/FlameGraph)
[seqdiag](http://blockdiag.com/en/seqdiag/)
## 介绍
eTpf是Erlang/OTP的跟踪器和分析器。 旨在提供一种非常有效的工具, 可在开发和生产环境中使用, 并且即使在繁忙的系统上也能够长时间运行 需要使用cachegrind工具从中读取输出lg_callgrind。
@ -255,7 +263,7 @@ eTpf的主要目的是对Erlang应用程序进行性能分析。这是通过首
快速开始 假设您使用概要文件模式和运行标志生成了跟踪文件(如Tracer一章中所述),则可以使用以下命令生成callgrind.out文件:
```
1> tpCallgrind:profile_many("traces.lz4.*", "callgrind.out", #{running => true}).
1> tpCallgrind:pfm("traces.lz4.*", "callgrind.out", #{running => true}).
```
这将为您生成的所有跟踪文件创建一个callgrind.out文件。例如,如果您具有“ traces.lz4.1”和“ traces.lz4.2”,则现在还应该具有“ callgrind.out.1”和“ callgrind.out.2”。
@ -267,22 +275,22 @@ $ qcachegrind callgrind.out
它将自动检测并打开所有与该callgrind.out.*模式匹配的文件。
Profiling one file 您可以通过调用函数来分析一个文件 `tpCallgrind:utils/2,3`。它包含跟踪文件名,输出文件名和一个可选的选项映射:
Profiling one file 您可以通过调用函数来分析一个文件 `tpCallgrind:pfs/2,3`。它包含跟踪文件名,输出文件名和一个可选的选项映射:
```
1> tpCallgrind:utils("traces.lz4.1", "callgrind.out.1").
1> tpCallgrind:pfs("traces.lz4.1", "callgrind.out.1").
```
它还接受以下选项:
```
1> tpCallgrind:utils("traces.lz4.1", "callgrind.out.1", #{running => true}).
1> tpCallgrind:pfs("traces.lz4.1", "callgrind.out.1", #{running => true}).
```
Profiling many files 便利功能可用于一次分析许多文件:`tpCallgrind:profile_many/2,3`, 它以通配符模式作为第一个参数,并以文件名前缀作为第二个参数:
```
1> tpCallgrind:profile_many("traces.lz4.*", "callgrind.out").
1> tpCallgrind:pfm("traces.lz4.*", "callgrind.out").
```
如果有两个跟踪文件,这将导致两个'callgrind.out'文件:'callgrind.out.1'和'callgrind.out.2'。
@ -290,13 +298,13 @@ Profiling many files 便利功能可用于一次分析许多文件:`tpCallgrin
它还接受以下选项:
```
1> tpCallgrind:profile_many("traces.lz4.*", "callgrind.out", #{running => true}).
1> tpCallgrind:pfm("traces.lz4.*", "callgrind.out", #{running => true}).
```
Running information 当跟踪文件包含运行信息时,这意味着它们是在running启用了标记的情况下创建的,您还需要将running标记传递给事件探查器,以使该信息在'callgrind.out'文件中可用:
```
1> tpCallgrind:profile_many("traces.lz4.*", "callgrind.out", #{running => true}).
1> tpCallgrind:pfm("traces.lz4.*", "callgrind.out", #{running => true}).
```
Scope 默认情况下,跟踪事件的范围是全局的。这意味着cachegrind工具会将所有事件组合在一起,无论它们发生在何处。这对于查看哪些功能总体上占用最多资源很有用。
@ -304,7 +312,7 @@ Scope 默认情况下,跟踪事件的范围是全局的。这意味着cachegri
其他时间,您可能想查看哪些进程占用最多的资源。为此,您需要指示eTpf在生成“ callgrind.out”文件时保留过程信息。使用以下scope选项完成此操作:
```
1> lg_callgrind:profile_many("traces.lz4.*", "callgrind.out", #{scope => per_process}).
1> lg_callgrind:pfm("traces.lz4.*", "callgrind.out", #{scope => per_process}).
```
使用cachegrind工具 当将cachegrind工具与Looking Glass生成的输出一起使用时,需要注意一些陷阱。
@ -502,6 +510,17 @@ activation = none;
序列 图1.示例输出
执行 seqdiag 命令
$ seqdiag simple.diag
$ ls simple.png
simple.png
如果您想要 SVG 图像,请使用 -T 选项
$ seqdiag -Tsvg simple.diag
$ ls simple.svg
simple.svg
识别过程 Looking Glass将显示每个过程的pid和一个示例消息,但识别哪个过程并不总是理想的。
为了解决这个问题,Looking Glass提供了一个简单的解决方案:lg在运行跟踪程序时将消息发送到指定的进程。 Looking

+ 2
- 2
src/callgrind/tpCallGrind.erl View File

@ -7,8 +7,8 @@
-export([pfm/4]).
-type opts() :: #{
scope => global | per_process, %% Whether we filter the output per process.
running => boolean() %% Whether we compute and save wait times.
scope => global | per_process, %% Whether we filter the output per process.
running => boolean() %% Whether we compute and save wait times.
}.
-record(call, {

+ 9
- 0
src/eTpf.erl View File

@ -29,6 +29,9 @@
, cgPfm/3
, cgPfm/4
, gcPfs/1
, gcPfm/2
%% trace函数
, trace/1
, trace/2
@ -87,6 +90,12 @@ cgPfm(Wildcard, Cwd, Prefix) ->
cgPfm(Wildcard, Cwd, Prefix, Opts) ->
tpCallGrind:pfm(Wildcard, Cwd, Prefix, Opts).
gcPfs(InputFile) ->
tpGcColl:pfs(InputFile).
gcPfm(InputFiles, Cwd) ->
tpGcColl:pfm(InputFiles, Cwd).
-spec trace(userInput()) -> ok.
trace(Input) ->
trace(Input, tpTracerShell).

+ 0
- 1
src/eTpf_app.erl View File

@ -1,5 +1,4 @@
-module(eTpf_app).
-behaviour(application).
-export([start/2, stop/1]).

+ 2
- 2
src/flame/tpFlame.erl View File

@ -1,8 +1,8 @@
-module(tpFlame). %%
-export([
pfs/2 %%
, pfm/3 %%
pfs/2
, pfm/3
]).
-record(state, {

+ 2
- 2
src/gcColl/tpGcColl.erl View File

@ -3,8 +3,8 @@
-include("eTpf.hrl").
-export([
pfs/1 %%
, pfm/2 %%
pfs/1
, pfm/2
]).
-record(state, {

+ 2
- 2
src/messages/tpMsgRS.erl View File

@ -3,8 +3,8 @@
-include("eTpf.hrl").
-export([
pfs/1 %%
, pfm/2 %%
pfs/1
, pfm/2
]).
-record(state, {

+ 2
- 2
src/messages/tpMsgSD.erl View File

@ -3,8 +3,8 @@
-include("eTpf.hrl").
-export([
pfs/2 %%
, pfm/3 %%
pfs/2
, pfm/3
]).
-record(state, {

+ 2
- 2
src/tracer/tpTracerFile.erl View File

@ -16,8 +16,8 @@
-record(state, {
parent :: pid()
, fDir :: file:filename_all() %% file base name
, fBaseName :: file:filename_all() %% file base name
, fDir :: file:filename_all()
, fBaseName :: file:filename_all()
, size = 0 :: non_neg_integer()
, fMaxSize :: infinity | non_neg_integer()
, ioDevice :: file:io_device()

+ 1
- 0
src/tracer/tpTracerShell.erl View File

@ -18,6 +18,7 @@ start_link(_TracerOpts) ->
init(Parent) ->
process_flag(message_queue_data, off_heap),
process_flag(trap_exit, true),
?MODULE:loop(Parent).
loop(Parent) ->

+ 3
- 3
src/tracer/tpTracerSocket.erl View File

@ -84,12 +84,12 @@ trace_loop(State = #state{parent = Parent, timerRef = TRef}, CSocket) ->
?MODULE:trace_loop(State, CSocket);
Msg ->
Bin = term_to_binary(Msg),
_ = byte_size(Bin),
%% _ = byte_size(Bin),
case erlang:port_command(CSocket, <<Bin/binary>>, [nosuspend]) of
true ->
?MODULE:trace_loop(State, CSocket);
%% The send buffer is full.
false ->
_ ->
close(State, CSocket)
end
end.
@ -98,7 +98,7 @@ close(State, CSocket) ->
_ = gen_tcp:close(CSocket),
accept(cancel_timeout(State)).
system_continue(_, _, {LoopTag = accept_loop, State, LoopArgs}) ->
system_continue(_, _, {LoopTag, State, LoopArgs}) ->
case LoopTag of
accept_loop ->
?MODULE:accept_loop(State, LoopArgs);

+ 5
- 5
src/utils/tpSocketCli.erl View File

@ -15,7 +15,7 @@
-record(state, {
port :: inet:port_number(),
baseFileName :: file:filename_all(),
fBaseName :: file:filename_all(),
nth = 0 :: non_neg_integer(),
socket :: inet:socket() | undefined,
ioDevice :: file:io_device() | undefined,
@ -30,10 +30,10 @@ start_link(Port, BaseFilename) ->
stop(Pid) ->
gen_srv:stop(Pid).
init([Port, BaseFilename]) ->
init([Port, FBaseName]) ->
process_flag(message_queue_data, off_heap),
process_flag(trap_exit, true),
{ok, #state{port = Port, baseFileName = BaseFilename}, {nTimeout, connect, 0, doConnect}}.
{ok, #state{port = Port, fBaseName = FBaseName}, {nTimeout, connect, 0, doConnect}}.
handleCall(_Msg, _State, _FROM) ->
{reply, ignored}.
@ -56,10 +56,10 @@ handleInfo({tcp_closed, _Socket}, State) ->
{noreply, clearSet(State), {nTimeout, connect, 0, doConnect}};
handleInfo({tcp_error, _Socket, _}, State) ->
{noreply, clearSet(State), {nTimeout, connect, 0, doConnect}};
handleInfo(doConnect, #state{port = Port, baseFileName = Filename0, nth = Nth} = State) ->
handleInfo(doConnect, #state{port = Port, fBaseName = FBaseName, nth = Nth} = State) ->
case gen_tcp:connect("localhost", Port, [binary, {packet, 2}, {active, true}]) of
{ok, Socket} ->
Filename = filename:flatten([Filename0, ".", integer_to_list(Nth)]),
Filename = filename:flatten([FBaseName, ".", integer_to_list(Nth)]),
{ok, IoDevice} = file:open(Filename, [write, raw]),
{noreply, State#state{socket = Socket, nth = Nth + 1, ioDevice = IoDevice}};
{error, _} ->

+ 64
- 66
src/utils/tpTermCut.erl View File

@ -1,92 +1,90 @@
-module(tpTermCut).
-include("eTpf.hrl").
%% 使
-export([cut/1]).
-export([cut/2]).
getTcmValue(Key) ->
case get(Key) of
undefined ->
maps:get(Key, ?defTcmMap);
Value ->
Value
end.
case get(Key) of
undefined ->
maps:get(Key, ?defTcmMap);
Value ->
Value
end.
cut(Term) ->
cut(Term, 1).
cut(Term, 1).
cut(Term, Depth) ->
TcmDepth = getTcmValue(tcmDepth),
case Depth > TcmDepth of
true ->
'$truncated';
_ ->
if
is_bitstring(Term) ->
case bit_size(Term) > getTcmValue(tcmBitSize) of
true ->
TcmBinSize = getTcmValue(tcmBinSize),
<<CutBin:TcmBinSize/binary, _/bits>> = Term,
<<CutBin/binary, "$truncated">>;
_ ->
Term
end;
is_list(Term) ->
cutList(Term, Depth, 0, getTcmValue(tcmListSize), getTcmValue(tcmNestStruct), 0, []);
is_map(Term), Depth =:= TcmDepth ->
#{'$truncated' => '$truncated'};
is_map(Term) ->
maps:from_list(cutMap(maps_to_list(Term, getTcmValue(tcmMapSize)), Depth, getTcmValue(tcmNestStruct), 0));
is_tuple(Term), Depth =:= TcmDepth ->
{'$truncated'};
is_tuple(Term) ->
list_to_tuple(cutList(tuple_to_list(Term), Depth, 0, getTcmValue(tcmTupleSize), getTcmValue(tcmNestStruct), 0, []));
true ->
Term
end
end.
TcmDepth = getTcmValue(tcmDepth),
case Depth > TcmDepth of
true ->
'$truncated';
_ ->
if
is_bitstring(Term) ->
case bit_size(Term) > getTcmValue(tcmBitSize) of
true ->
TcmBinSize = getTcmValue(tcmBinSize),
<<CutBin:TcmBinSize/binary, _/bits>> = Term,
<<CutBin/binary, "$truncated">>;
_ ->
Term
end;
is_list(Term) ->
cutList(Term, Depth, 0, getTcmValue(tcmListSize), getTcmValue(tcmNestStruct), 0, []);
is_map(Term), Depth =:= TcmDepth ->
#{'$truncated' => '$truncated'};
is_map(Term) ->
maps:from_list(cutMap(mapsToList(Term, getTcmValue(tcmMapSize)), Depth, getTcmValue(tcmNestStruct), 0));
is_tuple(Term), Depth =:= TcmDepth ->
{'$truncated'};
is_tuple(Term) ->
list_to_tuple(cutList(tuple_to_list(Term), Depth, 0, getTcmValue(tcmTupleSize), getTcmValue(tcmNestStruct), 0, []));
true ->
Term
end
end.
cutList([], _, _, _, _, _, Acc) ->
lists:reverse(Acc);
lists:reverse(Acc);
cutList([Term | Tail], Depth, Len, TcmTupleSize, TcmNestStruct, NumStructs, Acc) ->
case Len >= TcmTupleSize orelse NumStructs >= TcmNestStruct of
true ->
lists:reverse(['$truncated' | Acc]);
_ ->
%% if List was a cons, Tail can be anything
cutList(Tail, Depth, Len + 1, TcmTupleSize, TcmNestStruct, NumStructs + isStruct(Term), [cut(Term, Depth + 1) | Acc])
end;
case Len >= TcmTupleSize orelse NumStructs >= TcmNestStruct of
true ->
lists:reverse(['$truncated' | Acc]);
_ ->
%% if List was a cons, Tail can be anything
cutList(Tail, Depth, Len + 1, TcmTupleSize, TcmNestStruct, NumStructs + isStruct(Term), [cut(Term, Depth + 1) | Acc])
end;
cutList(Term, Depth, _, _, _, _, Acc) -> %% if List was a cons [[[a,a,a|b],1,2,3]|bbbb]
lists:reverse(Acc) ++ cut(Term, Depth + 1).
lists:reverse(Acc) ++ cut(Term, Depth + 1).
cutMap([], _, _, _) ->
[];
[];
cutMap(_, _, TcmNestStruct, NumStructs) when NumStructs > TcmNestStruct ->
[{'$truncated', '$truncated'}];
[{'$truncated', '$truncated'}];
cutMap([{Key, Value} | Tail], Depth, TcmNestStruct, NumStructs) ->
AddStruct = isStruct(Key) + isStruct(Value),
[{cut(Key, Depth + 1), cut(Value, Depth + 1)} | cutMap(Tail, Depth, TcmNestStruct, NumStructs + AddStruct)].
AddStruct = isStruct(Key) + isStruct(Value),
[{cut(Key, Depth + 1), cut(Value, Depth + 1)} | cutMap(Tail, Depth, TcmNestStruct, NumStructs + AddStruct)].
isStruct(Term) ->
case is_list(Term) orelse is_map(Term) orelse is_tuple(Term) of
true ->
1;
_ ->
0
end.
case is_list(Term) orelse is_map(Term) orelse is_tuple(Term) of
true ->
1;
_ ->
0
end.
maps_to_list(Map, MaxSize) ->
I = maps:iterator(Map),
maps_to_list(maps:next(I), MaxSize, []).
mapsToList(Map, MaxSize) ->
I = maps:iterator(Map),
mapsToList(maps:next(I), MaxSize, []).
%% Returns elements in arbitrary order. We reverse when we truncate
%% so that the truncated elements come at the end to avoid having
%% two truncated elements in the final output.
maps_to_list(none, _, Acc) ->
Acc;
maps_to_list(_, 0, Acc) ->
lists:reverse([{'$truncated', '$truncated'} | Acc]);
maps_to_list({K, V, I}, N, Acc) ->
maps_to_list(maps:next(I), N - 1, [{K, V} | Acc]).
mapsToList(none, _, Acc) ->
Acc;
mapsToList(_, 0, Acc) ->
lists:reverse([{'$truncated', '$truncated'} | Acc]);
mapsToList({K, V, I}, N, Acc) ->
mapsToList(maps:next(I), N - 1, [{K, V} | Acc]).

Loading…
Cancel
Save