From 9f0e2acbdc7105f02a8cac2aa11cf9259dca34ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?=
Date: Thu, 18 May 2017 23:05:02 +0200
Subject: Make lock counter info independent of the locks being counted
This allows us to enable/disable lock counting at will, and greatly improves
the performance of erts_debug:lock_counters/1 since we no longer have to
worry about the lock counters "dying" while we're enumerating them.
OTP-14412
---
lib/tools/doc/src/lcnt.xml | 8 --------
1 file changed, 8 deletions(-)
(limited to 'lib')
diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml
index 6e66a957ab..590049e681 100644
--- a/lib/tools/doc/src/lcnt.xml
+++ b/lib/tools/doc/src/lcnt.xml
@@ -109,14 +109,6 @@
statistics. If the server held any lock statistics data before the collect then
that data is lost.
-
-
- When collection occurs the runtime system transitions to a single thread,
- blocking all other threads. No other tasks will be scheduled during this
- operation. Depending on the size of the data this might take a long time
- (several seconds) and cause timeouts in the system.
-
-
--
cgit v1.2.3
From 392341efcebca6c41d4f88eb3f5731fe46473af7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?=
Date: Tue, 23 May 2017 18:01:43 +0200
Subject: Enable lcnt smoke test on all builds that have lcnt enabled
---
lib/tools/test/lcnt_SUITE.erl | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/tools/test/lcnt_SUITE.erl b/lib/tools/test/lcnt_SUITE.erl
index 2e48b11740..a7da4b1844 100644
--- a/lib/tools/test/lcnt_SUITE.erl
+++ b/lib/tools/test/lcnt_SUITE.erl
@@ -151,10 +151,9 @@ t_swap_keys_file([File|Files]) ->
%% Simple smoke test of actual lock-counting, if running on
%% a run-time with lock-counting enabled.
-
smoke_lcnt(Config) ->
- case erlang:system_info(build_type) of
- lcnt ->
+ case catch erlang:system_info(lock_counting) of
+ true ->
do_smoke_lcnt(Config);
_ ->
{skip,"Lock counting is not enabled"}
--
cgit v1.2.3
From 33a1962290ba6a6116cefe9fabb2e6cef823b33b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?=
Date: Fri, 23 Jun 2017 13:15:22 +0200
Subject: Break erts_debug:lock_counters/1 into separate BIFs
---
lib/kernel/src/erts_debug.erl | 35 +++++++++++++++-----
lib/kernel/src/kernel.app.src | 2 +-
lib/tools/src/lcnt.erl | 77 +++++++++++++++++++++++++++++++------------
lib/tools/src/tools.app.src | 2 +-
4 files changed, 85 insertions(+), 31 deletions(-)
(limited to 'lib')
diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl
index ad92aafc2f..480db6814e 100644
--- a/lib/kernel/src/erts_debug.erl
+++ b/lib/kernel/src/erts_debug.erl
@@ -33,10 +33,10 @@
-export([breakpoint/2, disassemble/1, display/1, dist_ext_to_term/2,
dump_monitors/1, dump_links/1, flat_size/1,
- get_internal_state/1, instructions/0, lock_counters/1,
+ get_internal_state/1, instructions/0,
map_info/1, same/2, set_internal_state/2,
- size_shared/1, copy_shared/1, dirty_cpu/2, dirty_io/2,
- dirty/3]).
+ size_shared/1, copy_shared/1, dirty_cpu/2, dirty_io/2, dirty/3,
+ lcnt_control/1, lcnt_control/2, lcnt_collect/0, lcnt_clear/0]).
-spec breakpoint(MFA, Flag) -> non_neg_integer() when
MFA :: {Module :: module(),
@@ -142,12 +142,31 @@ ic(F) when is_function(F) ->
io:format("Total: ~w~n",[lists:sum([C||{_I,C}<-Is])]),
R.
--spec lock_counters(info) -> term();
- (clear) -> ok;
- ({copy_save, boolean()}) -> boolean();
- ({process_locks, boolean()}) -> boolean().
+-spec lcnt_control
+ (copy_save, boolean()) -> ok;
+ (mask, list(atom())) -> ok.
-lock_counters(_) ->
+lcnt_control(_Option, _Value) ->
+ erlang:nif_error(undef).
+
+-spec lcnt_control
+ (copy_save) -> boolean();
+ (mask) -> list(atom()).
+
+lcnt_control(_Option) ->
+ erlang:nif_error(undef).
+
+-type lcnt_lock_info() :: {atom(), term(), atom(), term()}.
+
+-spec lcnt_collect() ->
+ list({duration, {non_neg_integer(), non_neg_integer()}} |
+ {locks, list(lcnt_lock_info())}).
+
+lcnt_collect() ->
+ erlang:nif_error(undef).
+
+-spec lcnt_clear() -> ok.
+lcnt_clear() ->
erlang:nif_error(undef).
-spec same(Term1, Term2) -> boolean() when
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 1128ee3ec5..7aefbbd9b6 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -120,6 +120,6 @@
{applications, []},
{env, [{error_logger, tty}]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-9.0", "stdlib-3.0", "sasl-3.0"]}
+ {runtime_dependencies, ["erts-9.1", "stdlib-3.0", "sasl-3.0"]}
]
}.
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"]}
]
}.
--
cgit v1.2.3
From 876ecc058d0d7dd48f8c5f7ddaf189d278e69925 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?=
Date: Thu, 29 Jun 2017 19:32:41 +0200
Subject: Document rt_mask and add warnings about copy_save
---
lib/tools/doc/src/lcnt.xml | 98 +++++++++++++++++++++++++++++++++-----
lib/tools/doc/src/lcnt_chapter.xml | 11 +++--
2 files changed, 94 insertions(+), 15 deletions(-)
(limited to 'lib')
diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml
index 590049e681..922c2ac0f4 100644
--- a/lib/tools/doc/src/lcnt.xml
+++ b/lib/tools/doc/src/lcnt.xml
@@ -5,7 +5,7 @@
2009
- 2016
+ 2017
Ericsson AB, All Rights Reserved
@@ -314,24 +314,22 @@
apply(Fun) -> term()
Same as apply(Fun, []).
+
+ Fun = fun()
+
Same as apply(Fun, []).
apply(Fun, Args) -> term()
- Clears counters, applies function and collects the profiling results.
+ Same as apply(Module, Function, Args).
Fun = fun()
Args = [term()]
- Clears the lock counters and then setups the instrumentation to save all destroyed locks.
- After setup the fun is called, passing the elements in Args as arguments.
- When the fun returns the statistics are immediately collected to the server. After the
- collection the instrumentation is returned to its previous behavior.
- The result of the applied fun is returned.
-
+ Same as apply(Module, Function, Args).
@@ -349,6 +347,13 @@
collection the instrumentation is returned to its previous behavior.
The result of the applied function is returned.
+
+
+ This function should only be used for micro-benchmarks; it sets copy_save
+ to true for the duration of the call, which can quickly lead to running
+ out of memory.
+
+
@@ -421,6 +426,68 @@
Clear the internal counters. Same as lcnt:clear(Node).
+
+ rt_mask() -> [category_atom()]
+ Same as rt_mask(node()).
+ Same as rt_mask(node()).
+
+
+
+ rt_mask(Node) -> [category_atom()]
+ Returns the current lock category mask.
+
+ Node = node()
+
+
+
+ Refer to rt_mask/2 for a list of valid categories. All
+ categories are enabled by default.
+
+
+
+
+
+ rt_mask(Categories) -> ok | {error, copy_save_enabled}
+ Same as rt_mask(node(), Categories).
+
+ Categories = [atom()]
+
+ Same as rt_mask(node(), Categories).
+
+
+
+ rt_mask(Node, Categories) -> ok | {error, copy_save_enabled}
+ Changes the lock category mask.
+
+ Node = node()
+ Categories = [atom()]
+
+
+
+ Sets the lock category mask to the given categories.
+
+
+ This will fail if the copy_save option is enabled; see
+ lcnt:rt_opt/2.
+
+ Valid categories are:
+
+ - allocator
+ - db (ETS tables)
+ - debug
+ - distribution
+ - generic
+ - io
+ - process
+ - scheduler
+
+
+ This list is subject to change at any time, as is the category any given lock
+ may belong to.
+
+
+
+
rt_opt({Type, bool()}) -> bool()
Same as rt_opt(node(), {Type, Opt}).
@@ -434,16 +501,25 @@
Type = copy_save | process_locks
- Changes the lock counter behavior and returns the previous behaviour.
Option description:
{copy_save, bool()}
- - Enable statistics saving from destroyed locks by copying. This might consume a lot of memory.
+
- Retains the statistics of destroyed locks.
Default: false
+
+
+ This option will use a lot of memory when enabled, which must be
+ reclaimed with lcnt:rt_clear. Note that it makes no distinction
+ between locks that were destroyed and locks for which counting was
+ disabled, so enabling this option will disable changes to the lock
+ category mask.
+
+
{process_locks, bool()}
- - Profile process locks.
+
- Profile process locks, equal to adding process to the lock category mask;
+ see lcnt:rt_mask/2
Default: true
diff --git a/lib/tools/doc/src/lcnt_chapter.xml b/lib/tools/doc/src/lcnt_chapter.xml
index 1981d66117..24b58136aa 100644
--- a/lib/tools/doc/src/lcnt_chapter.xml
+++ b/lib/tools/doc/src/lcnt_chapter.xml
@@ -4,7 +4,7 @@
- 20092016
+ 20092017
Ericsson AB. All Rights Reserved.
@@ -29,7 +29,7 @@
nobody
no
2009-11-26
- PA1
+ PA2
lcnt_chapter.xml
@@ -97,8 +97,11 @@ ok
ok
- Another way to to profile a specific function is to use lcnt:apply/3 or lcnt:apply/1 which does lcnt:clear/0 before the function and lcnt:collect/0 after its invocation.
- It also sets copy_save to true for the duration of the function call
+ Another way to to profile a specific function is to use lcnt:apply/3 or lcnt:apply/1
+ which does lcnt:clear/0 before the function and lcnt:collect/0 after its invocation.
+ This method should only be used in micro-benchmarks since it sets copy_save to true
+ for the duration of the function call, which may cause the emulator to run out of memory if
+ attempted under load.
Erlang R13B03 (erts-5.7.4) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe]
--
cgit v1.2.3