aboutsummaryrefslogtreecommitdiffstats
path: root/lib/tools/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tools/src')
-rw-r--r--lib/tools/src/lcnt.erl167
1 files changed, 114 insertions, 53 deletions
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
index c9a217c83a..e1772537d3 100644
--- a/lib/tools/src/lcnt.erl
+++ b/lib/tools/src/lcnt.erl
@@ -64,7 +64,11 @@
-export([
apply/3,
apply/2,
- help/0
+ apply/1,
+ all_conflicts/0,
+ all_conflicts/1,
+ pid/2, pid/3,
+ port/1, port/2
]).
-define(version, "1.0").
@@ -122,21 +126,23 @@ init([]) -> {ok, #state{ locks = [], duration = 0 } }.
clear() -> erts_debug:lock_counters(clear).
clear(Node) -> rpc:call(Node, erts_debug, lock_counters, [clear]).
-collect() -> gen_server:call(?MODULE, {collect, erts_debug:lock_counters(info)}).
-collect(Node) -> gen_server:call(?MODULE, {collect, rpc:call(Node, erts_debug, lock_counters, [info])}).
-locations() -> gen_server:call(?MODULE, {locations,[]}).
-locations(Opts) -> gen_server:call(?MODULE, {locations, Opts}).
-conflicts() -> gen_server:call(?MODULE, {conflicts, []}).
-conflicts(Opts) -> gen_server:call(?MODULE, {conflicts, Opts}).
-inspect(Lock) -> gen_server:call(?MODULE, {inspect, Lock, []}).
-inspect(Lock, Opts) -> gen_server:call(?MODULE, {inspect, Lock, Opts}).
-information() -> gen_server:call(?MODULE, information).
-swap_pid_keys() -> gen_server:call(?MODULE, swap_pid_keys).
-raw() -> gen_server:call(?MODULE, raw).
-set(Option, Value) -> gen_server:call(?MODULE, {set, Option, Value}).
-set({Option, Value}) -> gen_server:call(?MODULE, {set, Option, Value}).
-save(Filename) -> gen_server:call(?MODULE, {save, Filename}, infinity).
-load(Filename) -> start(), gen_server:call(?MODULE, {load, Filename}, infinity).
+collect() -> call({collect, erts_debug:lock_counters(info)}).
+collect(Node) -> call({collect, rpc:call(Node, erts_debug, lock_counters, [info])}).
+locations() -> call({locations,[]}).
+locations(Opts) -> call({locations, Opts}).
+conflicts() -> call({conflicts, []}).
+conflicts(Opts) -> call({conflicts, Opts}).
+inspect(Lock) -> call({inspect, Lock, []}).
+inspect(Lock, Opts) -> call({inspect, Lock, Opts}).
+information() -> call(information).
+swap_pid_keys() -> call(swap_pid_keys).
+raw() -> call(raw).
+set(Option, Value) -> call({set, Option, Value}).
+set({Option, Value}) -> call({set, Option, Value}).
+save(Filename) -> call({save, Filename}).
+load(Filename) -> start(), call({load, Filename}).
+
+call(Msg) -> gen_server:call(?MODULE, Msg, infinity).
%% -------------------------------------------------------------------- %%
%%
@@ -151,6 +157,9 @@ apply(M,F,As) when is_atom(M), is_atom(F), is_list(As) ->
lcnt:collect(),
Res.
+apply(Fun) when is_function(Fun) ->
+ lcnt:apply(Fun, []).
+
apply(Fun, As) when is_function(Fun) ->
lcnt:start(),
lcnt:clear(),
@@ -158,21 +167,23 @@ apply(Fun, As) when is_function(Fun) ->
lcnt:collect(),
Res.
-help() ->
- Help =
- "lcnt:conflicts() -> ok\n"
- "lcnt:conflicts(Opts) -> ok\n"
- " Returns a list of internal lock counters.\n"
- " Opts = [Opt]\n"
- " Opt = {sort, Sort} | {threshold, Threshold} | {print, PrintOpts} | {max_locks, MaxLocks} {combine, bool()}, {location, bool()}\n"
- " Sort = name | id | type | tries | colls | ratio | time | entry\n"
- " Threshold = {tries, integer()} | {colls, integer()} | {time, integer()}\n"
- " PrintOpts = [PrintOpt | {PrintOpt, Width}]\n"
- " PrintOpt = name | id | type | entry | tries | colls | ratio | time | duration\n"
- " Width = integer()\n"
- " MaxLocks = integer()\n",
- io:format("~s", [Help]),
- ok.
+all_conflicts() -> all_conflicts(time).
+all_conflicts(Sort) ->
+ conflicts([{max_locks, none}, {thresholds, []},{combine,false}, {sort, Sort}, {reverse, true}]).
+
+pid(Id, Serial) -> pid(node(), Id, Serial).
+pid(Node, Id, Serial) when is_atom(Node) ->
+ Header = <<131,103,100>>,
+ String = atom_to_list(Node),
+ L = length(String),
+ binary_to_term(list_to_binary([Header, bytes16(L), String, bytes32(Id), bytes32(Serial),0])).
+
+port(Id) -> port(node(), Id).
+port(Node, Id ) when is_atom(Node) ->
+ Header = <<131,102,100>>,
+ String = atom_to_list(Node),
+ L = length(String),
+ binary_to_term(list_to_binary([Header, bytes16(L), String, bytes32(Id), 0])).
%% -------------------------------------------------------------------- %%
%%
@@ -208,15 +219,15 @@ handle_call({locations, InOpts}, _From, #state{ locks = Locks } = State) when is
Default = [
{sort, time},
{reverse, false},
- {print, [name,id,tries,colls,ratio,time,duration]},
+ {print, [name,entry,tries,colls,ratio,time,duration]},
{max_locks, 20},
{combine, true},
{thresholds, [{tries, 0}, {colls, 0}, {time, 0}] },
- {locations, false}],
+ {locations, true}],
Opts = options(InOpts, Default),
Printables = filter_print([#print{
- name = term2string("~w", [Names]),
+ name = string_names(Names),
entry = term2string("~p:~p", [Stats#stats.file, Stats#stats.line]),
colls = Stats#stats.colls,
tries = Stats#stats.tries,
@@ -235,7 +246,7 @@ handle_call({inspect, Lockname, InOpts}, _From, #state{ duration = Duration, loc
{reverse, false},
{print, [name,id,tries,colls,ratio,time,duration]},
{max_locks, 20},
- {combine, false},
+ {combine, true},
{thresholds, [{tries, 0}, {colls, 0}, {time, 0}] },
{locations, false}],
@@ -249,21 +260,32 @@ handle_call({inspect, Lockname, InOpts}, _From, #state{ duration = Duration, loc
case proplists:get_value(locations, Opts) of
true ->
lists:foreach(fun
- (L) ->
- IdString = case proplists:get_value(full_id, Opts) of
- true -> term2string(proplists:get_value(L#lock.name, IDs, L#lock.id));
- _ -> term2string(L#lock.id)
- end,
- print("lock: " ++ term2string(L#lock.name)),
- print("id: " ++ IdString),
- print("type: " ++ term2string(L#lock.type)),
- Combined = [Stats || {Stats,_} <- combine_locations(L#lock.stats)],
- Ps = stats2print(Combined, Duration),
- Opts1 = options([{{print, [entry, name,id,tries,colls,ratio,time,duration]},
- print_lock_information(filter_print(Ps, Opts), proplists:get_value(print, Opts))
+ (#lock{ name = Name, id = Id, type = Type, stats = Stats }) ->
+ IdString = case proplists:get_value(full_id, Opts) of
+ true -> term2string(proplists:get_value(Name, IDs, Id));
+ _ -> term2string(Id)
+ end,
+ Combined = [CStats || {CStats,_} <- combine_locations(Stats)],
+ case Combined of
+ [] ->
+ ok;
+ _ ->
+ %io:format("Combined ~p~n", [Combined]),
+ print("lock: " ++ term2string(Name)),
+ print("id: " ++ IdString),
+ print("type: " ++ term2string(Type)),
+ Ps = stats2print(Combined, Duration),
+ Opts1 = options([{print, [entry, tries,colls,ratio,time,duration]},
+ {thresholds, [{tries, -1}, {colls, -1}, {time, -1}]}], Opts),
+ print_lock_information(filter_print(Ps, Opts1), proplists:get_value(print, Opts1))
+ end
+ % (#lock{ name = Name, id = Id}) ->
+ % io:format("Empty lock ~p ~p~n", [Name, Id])
end, Combos);
_ ->
- print_lock_information(locks2print(Combos, Duration), proplists:get_value(print, Opts))
+ Print1 = locks2print(Combos, Duration),
+ Print2 = filter_print(Print1, Opts),
+ print_lock_information(Print2, proplists:get_value(print, Opts))
end,
{reply, ok, State};
@@ -417,6 +439,13 @@ cut_locks(Locks, _) -> Locks.
reverse_locks(Locks, true) -> lists:reverse(Locks);
reverse_locks(Locks, _) -> Locks.
+
+%%
+string_names([]) -> "";
+string_names(Names) -> string_names(Names, []).
+string_names([Name], Strings) -> strings(lists:reverse([term2string(Name) | Strings]));
+string_names([Name|Names],Strings) -> string_names(Names, [term2string(Name) ++ ","|Strings]).
+
%% combine_locations
%% In:
%% Locations :: [#lock{}] | [#stats{}]
@@ -581,11 +610,43 @@ list2lock([F|Fs], List, Out) -> list2lock(Fs, List, [proplists:get_value(F, List
%% Out:
%% ok
+auto_print_width(Locks, Print) ->
+ % iterate all lock entries to save all max length values
+ % these are records, so we do a little tuple <-> list smashing
+ R = lists:foldl(fun
+ (L, Max) ->
+ list_to_tuple(lists:reverse(lists:foldl(fun
+ ({print,print}, Out) -> [print|Out];
+ ({Str, Len}, Out) -> [erlang:min(erlang:max(length(s(Str))+1,Len),80)|Out]
+ end, [], lists:zip(tuple_to_list(L), tuple_to_list(Max)))))
+ end, #print{ id = 3, type = 5, entry = 5, name = 5, tries = 7, colls = 13, cr = 16, time = 11, dtr = 14 },
+ Locks),
+ % Setup the offsets for later pruning
+ Offsets = [
+ {id, R#print.id},
+ {name, R#print.name},
+ {type, R#print.type},
+ {entry, R#print.entry},
+ {tries, R#print.tries},
+ {colls, R#print.colls},
+ {ratio, R#print.cr},
+ {time, R#print.time},
+ {duration, R#print.dtr}],
+ % Prune offsets to only allow specified print options
+ lists:foldr(fun
+ ({Type, W}, Out) -> [{Type, W}|Out];
+ (Type, Out) -> [proplists:lookup(Type, Offsets)|Out]
+ end, [], Print).
+
print_lock_information(Locks, Print) ->
- print_header(Print),
+ % remake Print to autosize entries
+ AutoPrint = auto_print_width(Locks, Print),
+
+ print_header(AutoPrint),
+
lists:foreach(fun
(L) ->
- print_lock(L, Print)
+ print_lock(L, AutoPrint)
end, Locks),
ok.
@@ -621,13 +682,13 @@ print_lock(L, Opts) -> print_lock(L, Opts, []).
print_lock(_, [], Formats) -> print(strings(lists:reverse(Formats)));
print_lock(L, [Opt|Opts], Formats) ->
case Opt of
- id -> print_lock(L, Opts, [{space, 18, s(L#print.id) } | Formats]);
+ id -> print_lock(L, Opts, [{space, 25, s(L#print.id) } | Formats]);
{id, W} -> print_lock(L, Opts, [{space, W, s(L#print.id) } | Formats]);
type -> print_lock(L, Opts, [{space, 18, s(L#print.type) } | Formats]);
{type, W} -> print_lock(L, Opts, [{space, W, s(L#print.type) } | Formats]);
entry -> print_lock(L, Opts, [{space, 30, s(L#print.entry)} | Formats]);
{entry, W} -> print_lock(L, Opts, [{space, W, s(L#print.entry)} | Formats]);
- name -> print_lock(L, Opts, [{space, 25, s(L#print.name) } | Formats]);
+ name -> print_lock(L, Opts, [{space, 22, s(L#print.name) } | Formats]);
{name, W} -> print_lock(L, Opts, [{space, W, s(L#print.name) } | Formats]);
tries -> print_lock(L, Opts, [{space, 12, s(L#print.tries)} | Formats]);
{tries, W} -> print_lock(L, Opts, [{space, W, s(L#print.tries)} | Formats]);
@@ -639,7 +700,7 @@ print_lock(L, [Opt|Opts], Formats) ->
{time, W} -> print_lock(L, Opts, [{space, W, s(L#print.time) } | Formats]);
duration -> print_lock(L, Opts, [{space, 20, s(L#print.dtr) } | Formats]);
{duration, W} -> print_lock(L, Opts, [{space, W, s(L#print.dtr) } | Formats]);
- _ -> print_lock(L, Opts, Formats)
+ _ -> print_lock(L, Opts, Formats)
end.
print_state_information(#state{ locks = Locks} = State) ->