diff options
Diffstat (limited to 'lib/tools/src')
-rw-r--r-- | lib/tools/src/eprof.erl | 30 | ||||
-rw-r--r-- | lib/tools/src/fprof.erl | 36 | ||||
-rw-r--r-- | lib/tools/src/lcnt.erl | 77 | ||||
-rw-r--r-- | lib/tools/src/tools.app.src | 2 | ||||
-rw-r--r-- | lib/tools/src/xref_base.erl | 22 | ||||
-rw-r--r-- | lib/tools/src/xref_parser.yrl | 6 | ||||
-rw-r--r-- | lib/tools/src/xref_utils.erl | 13 |
7 files changed, 118 insertions, 68 deletions
diff --git a/lib/tools/src/eprof.erl b/lib/tools/src/eprof.erl index 3ae899a078..535ddbcd04 100644 --- a/lib/tools/src/eprof.erl +++ b/lib/tools/src/eprof.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -246,7 +246,7 @@ handle_call(profile_stop, _From, #state{ profiling = true } = S) -> %% logfile handle_call({logfile, File}, _From, #state{ fd = OldFd } = S) -> - case file:open(File, [write]) of + case file:open(File, [write, {encoding, utf8}]) of {ok, Fd} -> case OldFd of undefined -> ok; @@ -478,11 +478,11 @@ string_bp_mfa([{Mfa, {Count, Time}}|Mfas], Tus, {MfaW, CountW, PercW, TimeW, TpC Stpc = s("~.2f", [divide(Time,Count)]), string_bp_mfa(Mfas, Tus, { - erlang:max(MfaW, length(Smfa)), - erlang:max(CountW,length(Scount)), - erlang:max(PercW, length(Sperc)), - erlang:max(TimeW, length(Stime)), - erlang:max(TpCW, length(Stpc)) + erlang:max(MfaW, string:length(Smfa)), + erlang:max(CountW,string:length(Scount)), + erlang:max(PercW, string:length(Sperc)), + erlang:max(TimeW, string:length(Stime)), + erlang:max(TpCW, string:length(Stpc)) }, [[Smfa, Scount, Sperc, Stime, Stpc] | Strings]). print_bp_mfa(Mfas, {Tn, Tus}, Fd, Opts) -> @@ -491,11 +491,11 @@ print_bp_mfa(Mfas, {Tn, Tus}, Fd, Opts) -> TnStr = s(Tn), TusStr = s(Tus), TuspcStr = s("~.2f", [divide(Tus,Tn)]), - Ws = {erlang:max(length("FUNCTION"), MfaW), - lists:max([length("CALLS"), CountW, length(TnStr)]), - erlang:max(length(" %"), PercW), - lists:max([length("TIME"), TimeW, length(TusStr)]), - lists:max([length("uS / CALLS"), TpCW, length(TuspcStr)])}, + Ws = {erlang:max(string:length("FUNCTION"), MfaW), + lists:max([string:length("CALLS"), CountW, string:length(TnStr)]), + erlang:max(string:length(" %"), PercW), + lists:max([string:length("TIME"), TimeW, string:length(TusStr)]), + lists:max([string:length("uS / CALLS"), TpCW, string:length(TuspcStr)])}, format(Fd, Ws, ["FUNCTION", "CALLS", " %", "TIME", "uS / CALLS"]), format(Fd, Ws, ["--------", "-----", "-------", "----", "----------"]), lists:foreach(fun (String) -> format(Fd, Ws, String) end, Strs), @@ -503,13 +503,13 @@ print_bp_mfa(Mfas, {Tn, Tus}, Fd, Opts) -> format(Fd, Ws, ["Total:", TnStr, "100.00%", TusStr, TuspcStr]), ok. -s({M,F,A}) -> s("~w:~w/~w",[M,F,A]); -s(Term) -> s("~p", [Term]). +s({M,F,A}) -> s("~w:~tw/~w",[M,F,A]); +s(Term) -> s("~tp", [Term]). s(Format, Terms) -> lists:flatten(io_lib:format(Format, Terms)). format(Fd, {MfaW, CountW, PercW, TimeW, TpCW}, Strings) -> - format(Fd, s("~~.~ps ~~~ps ~~~ps ~~~ps [~~~ps]~~n", [MfaW, CountW, PercW, TimeW, TpCW]), Strings); + format(Fd, s("~~.~wts ~~~ws ~~~ws ~~~ws [~~~ws]~~n", [MfaW, CountW, PercW, TimeW, TpCW]), Strings); format(undefined, Format, Strings) -> io:format(Format, Strings), ok; diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl index d1a4624419..2fe42beb03 100644 --- a/lib/tools/src/fprof.erl +++ b/lib/tools/src/fprof.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2016. All Rights Reserved. +%% Copyright Ericsson AB 2001-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1475,7 +1475,7 @@ info_suspect_call(GroupLeader, GroupLeader, _, _) -> ok; info_suspect_call(GroupLeader, _, Func, Pid) -> io:format(GroupLeader, - "~nWarning: ~p called in ~p - trace may become corrupt!~n", + "~nWarning: ~tp called in ~p - trace may become corrupt!~n", parsify([Func, Pid])). info(GroupLeader, GroupLeader, _, _) -> @@ -1498,13 +1498,13 @@ dump_stack(Dump, Stack, Term) -> {N, length(hd(Stack))} end end, - io:format(Dump, "~s~p.~n", [lists:duplicate(Depth, " "), parsify(Term)]), + io:format(Dump, "~s~tp.~n", [lists:duplicate(Depth, " "), parsify(Term)]), true. dump(undefined, _) -> false; dump(Dump, Term) -> - io:format(Dump, "~p.~n", [parsify(Term)]), + io:format(Dump, "~tp.~n", [parsify(Term)]), true. @@ -2603,17 +2603,17 @@ println({Io, [W1, W2, W3, W4]}, Head, println({Io, _}, Head, [], Tail, Comment) -> - io:format(Io, "~s~s~s~n", + io:format(Io, "~s~ts~ts~n", [pad(Head, $ , 3), Tail, Comment]); println({Io, _}, Head, {Tag, Term}, Tail, Comment) -> - io:format(Io, "~s~p, ~p~s~s~n", + io:format(Io, "~s~tp, ~tp~ts~ts~n", [pad(Head, $ , 3), parsify(Tag), parsify(Term), Tail, Comment]); println({Io, _}, Head, Term, Tail, Comment) -> - io:format(Io, "~s~p~s~s~n", + io:format(Io, "~s~tp~ts~ts~n", [pad(Head, $ , 3), parsify(Term), Tail, Comment]). @@ -2636,22 +2636,32 @@ funcstat_pd(Pid, Func1, Func0, Clocks) -> #funcstat{callers_sum = CallersSum, callers = Callers} = FuncstatCallers -> FuncstatCallers#funcstat{ - callers_sum = clocks_sum(CallersSum, Clocks, Func0), - callers = [Clocks#clocks{id = Func1} | Callers]} - end), + callers_sum = clocks_sum(CallersSum, Clocks, Func0), + callers = insert_call(Clocks, Func1, Callers)} + end), put({Pid, Func1}, case get({Pid, Func1}) of undefined -> - #funcstat{callers_sum = #clocks{id = Func1}, + #funcstat{callers_sum = #clocks{id = Func1}, called_sum = Clocks#clocks{id = Func1}, called = [Clocks#clocks{id = Func0}]}; #funcstat{called_sum = CalledSum, called = Called} = FuncstatCalled -> FuncstatCalled#funcstat{ called_sum = clocks_sum(CalledSum, Clocks, Func1), - called = [Clocks#clocks{id = Func0} | Called]} + called = insert_call(Clocks, Func0, Called)} end). +insert_call(Clocks, Func, ClocksList) -> + insert_call(Clocks, Func, ClocksList, []). + +insert_call(Clocks, Func, [#clocks{id = Func} = C | T], Acc) -> + [clocks_sum(C, Clocks, Func) | T ++ Acc]; +insert_call(Clocks, Func, [H | T], Acc) -> + insert_call(Clocks, Func, T, [H | Acc]); +insert_call(Clocks, Func, [], Acc) -> + [Clocks#clocks{id = Func} | Acc]. + %% Sort a list of funcstat records, @@ -2710,7 +2720,7 @@ postsort_r([[_|C] | L], R) -> flat_format(F, Trailer) when is_float(F) -> lists:flatten([io_lib:format("~.3f", [F]), Trailer]); flat_format(W, Trailer) -> - lists:flatten([io_lib:format("~p", [W]), Trailer]). + lists:flatten([io_lib:format("~tp", [W]), Trailer]). %% Format, flatten, and pad. flat_format(Term, Trailer, Width) -> diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl index d881fedbd5..139b3d8a4a 100644 --- a/lib/tools/src/lcnt.erl +++ b/lib/tools/src/lcnt.erl @@ -34,8 +34,11 @@ -export([start/0, stop/0]). -%% erts_debug:lock_counters api --export([rt_collect/0, +%% erts_debug:lcnt_xxx api +-export([rt_mask/0, + rt_mask/1, + rt_mask/2, + rt_collect/0, rt_collect/1, rt_clear/0, rt_clear/1, @@ -134,27 +137,61 @@ start_internal() -> %% -------------------------------------------------------------------- %% %% -%% API erts_debug:lock_counters +%% API erts_debug:lcnt_xxx %% %% -------------------------------------------------------------------- %% -rt_collect() -> - erts_debug:lock_counters(info). +rt_mask(Node, Categories) when is_atom(Node), is_list(Categories) -> + rpc:call(Node, lcnt, rt_mask, [Categories]). + +rt_mask(Node) when is_atom(Node) -> + rpc:call(Node, lcnt, rt_mask, []); + +rt_mask(Categories) when is_list(Categories) -> + case erts_debug:lcnt_control(copy_save) of + false -> + erts_debug:lcnt_control(mask, Categories); + true -> + {error, copy_save_enabled} + end. + +rt_mask() -> + erts_debug:lcnt_control(mask). rt_collect(Node) -> - rpc:call(Node, erts_debug, lock_counters, [info]). + rpc:call(Node, lcnt, rt_collect, []). +rt_collect() -> + erts_debug:lcnt_collect(). +rt_clear(Node) -> + rpc:call(Node, lcnt, rt_clear, []). rt_clear() -> - erts_debug:lock_counters(clear). + erts_debug:lcnt_clear(). -rt_clear(Node) -> - rpc:call(Node, erts_debug, lock_counters, [clear]). +rt_opt(Node, Arg) -> + rpc:call(Node, lcnt, rt_opt, [Arg]). -rt_opt({Type, Opt}) -> - erts_debug:lock_counters({Type, Opt}). +%% Compatibility shims for the "process/port_locks" options mentioned in the +%% manual. +rt_opt({process_locks, Enable}) -> + toggle_category(process, Enable); +rt_opt({port_locks, Enable}) -> + toggle_category(io, Enable); -rt_opt(Node, {Type, Opt}) -> - rpc:call(Node, erts_debug, lock_counters, [{Type, Opt}]). +rt_opt({Type, NewVal}) -> + PreviousVal = erts_debug:lcnt_control(Type), + erts_debug:lcnt_control(Type, NewVal), + PreviousVal. + +toggle_category(Category, true) -> + PreviousMask = erts_debug:lcnt_control(mask), + erts_debug:lcnt_control(mask, [Category | PreviousMask]), + lists:member(Category, PreviousMask); + +toggle_category(Category, false) -> + PreviousMask = erts_debug:lcnt_control(mask), + erts_debug:lcnt_control(mask, lists:delete(Category, PreviousMask)), + lists:member(Category, PreviousMask). %% -------------------------------------------------------------------- %% %% @@ -192,13 +229,9 @@ call(Msg) -> gen_server:call(?MODULE, Msg, infinity). %% -------------------------------------------------------------------- %% apply(M,F,As) when is_atom(M), is_atom(F), is_list(As) -> - ok = start_internal(), - Opt = lcnt:rt_opt({copy_save, true}), - lcnt:clear(), - Res = erlang:apply(M,F,As), - lcnt:collect(), - lcnt:rt_opt({copy_save, Opt}), - Res. + apply(fun() -> + erlang:apply(M,F,As) + end). apply(Fun) when is_function(Fun) -> lcnt:apply(Fun, []). @@ -209,7 +242,9 @@ apply(Fun, As) when is_function(Fun) -> lcnt:clear(), Res = erlang:apply(Fun, As), lcnt:collect(), - lcnt:rt_opt({copy_save, Opt}), + %% _ is bound to silence a dialyzer warning; it used to fail silently and + %% we don't want to change the error semantics. + _ = lcnt:rt_opt({copy_save, Opt}), Res. all_conflicts() -> all_conflicts(time). diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src index 12f0cfd2df..8beef49bf9 100644 --- a/lib/tools/src/tools.app.src +++ b/lib/tools/src/tools.app.src @@ -41,6 +41,6 @@ ] }, {runtime_dependencies, ["stdlib-3.1","runtime_tools-1.8.14", - "kernel-3.0","erts-7.0","compiler-5.0"]} + "kernel-5.4","erts-9.1","compiler-5.0"]} ] }. diff --git a/lib/tools/src/xref_base.erl b/lib/tools/src/xref_base.erl index 8d2cc07e40..3199b28acb 100644 --- a/lib/tools/src/xref_base.erl +++ b/lib/tools/src/xref_base.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2016. All Rights Reserved. +%% Copyright Ericsson AB 2000-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -405,21 +405,21 @@ analysis(exports_not_used, _) -> %% Local calls are not considered here. "X * UU" would do otherwise. "X - XU"; analysis({call, F}, functions) -> - make_query("range (E | ~w : Fun)", [F]); + make_query("range (E | ~tw : Fun)", [F]); analysis({use, F}, functions) -> - make_query("domain (E || ~w : Fun)", [F]); + make_query("domain (E || ~tw : Fun)", [F]); analysis({module_call, M}, _) -> - make_query("range (ME | ~w : Mod)", [M]); + make_query("range (ME | ~tw : Mod)", [M]); analysis({module_use, M}, _) -> - make_query("domain (ME || ~w : Mod)", [M]); + make_query("domain (ME || ~tw : Mod)", [M]); analysis({application_call, A}, _) -> - make_query("range (AE | ~w : App)", [A]); + make_query("range (AE | ~tw : App)", [A]); analysis({application_use, A}, _) -> - make_query("domain (AE || ~w : App)", [A]); + make_query("domain (AE || ~tw : App)", [A]); analysis({release_call, R}, _) -> - make_query("range (RE | ~w : Rel)", [R]); + make_query("range (RE | ~tw : Rel)", [R]); analysis({release_use, R}, _) -> - make_query("domain (RE || ~w : Rel)", [R]); + make_query("domain (RE || ~tw : Rel)", [R]); analysis(deprecated_function_calls, functions) -> "XC || DF"; analysis({deprecated_function_calls,Flag}, functions) -> @@ -1833,9 +1833,9 @@ message(true, What, Arg) -> unreadable -> io:format("Skipping ~ts (unreadable)~n", [Arg]); xref_attr -> - io:format("~ts: Skipping 'xref' attribute ~w~n", Arg); + io:format("~ts: Skipping 'xref' attribute ~tw~n", Arg); depr_attr -> - io:format("~ts: Skipping 'deprecated' attribute ~w~n", Arg); + io:format("~ts: Skipping 'deprecated' attribute ~tw~n", Arg); lib_search -> io:format("Scanning library path for BEAM files... ", []); lib_check -> diff --git a/lib/tools/src/xref_parser.yrl b/lib/tools/src/xref_parser.yrl index 0711da79e2..5ee6419ff5 100644 --- a/lib/tools/src/xref_parser.yrl +++ b/lib/tools/src/xref_parser.yrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2016. All Rights Reserved. +%% Copyright Ericsson AB 2000-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -170,7 +170,7 @@ is_prefix_op('#') -> numeric; is_prefix_op(_) -> false. check_regexp(String) -> - case re:compile(String) of + case re:compile(String, [unicode]) of {ok, _Expr} -> {regexpr, String}; {error, {ErrString, Position}} -> @@ -274,7 +274,7 @@ mfa2s({M,F,A}) -> [c2s(M),':',c2s(F),'/',A]. c2s(C) -> - [S] = io_lib:format("~p", [C]), + [S] = io_lib:format("~tp", [C]), list_to_atom(S). re(variable) -> ['_']; diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl index b0c168e018..02e207d40c 100644 --- a/lib/tools/src/xref_utils.erl +++ b/lib/tools/src/xref_utils.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2016. All Rights Reserved. +%% Copyright Ericsson AB 2000-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -638,14 +638,14 @@ neighbours([], G, Fun, VT, L, _V, Vs) -> neighbours(Vs, G, Fun, VT, L). match_list(L, RExpr) -> - {ok, Expr} = re:compile(RExpr), + {ok, Expr} = re:compile(RExpr, [unicode]), filter(fun(E) -> match(E, Expr) end, L). match_one(VarL, Con, Col) -> select_each(VarL, fun(E) -> Con =:= element(Col, E) end). match_many(VarL, RExpr, Col) -> - {ok, Expr} = re:compile(RExpr), + {ok, Expr} = re:compile(RExpr, [unicode]), select_each(VarL, fun(E) -> match(element(Col, E), Expr) end). match(I, Expr) when is_integer(I) -> @@ -653,7 +653,12 @@ match(I, Expr) when is_integer(I) -> {match, [{0,length(S)}]} =:= re:run(S, Expr, [{capture, first}]); match(A, Expr) when is_atom(A) -> S = atom_to_list(A), - {match, [{0,length(S)}]} =:= re:run(S, Expr, [{capture, first}]). + case re:run(S, Expr, [{capture, first}]) of + {match, [{0,Size}]} -> + Size =:= byte_size(unicode:characters_to_binary(S)); + _ -> + false + end. select_each([{Mod,Funs} | L], Pred) -> case filter(Pred, Funs) of |