Skip to content
Permalink
Browse files
Merge pull request #66 from ferd/otp-21-support
OTP-21 support
  • Loading branch information
ferd committed Jun 29, 2018
2 parents 5838f71 + e60f8c5 commit d19f241c414ef1681a27ac9ed019a984acbe6863
Showing 7 changed files with 85 additions and 27 deletions.
@@ -1,20 +1,14 @@
sudo: false
language: erlang
otp_release:
- 21.0
- 20.0
- 19.3
- 18.3
- 17.3
- 17.1
- 17.0
- R16B03-1
- R16B03
- R16B02
- R16B01
- R16B
- R15B03
- R15B02
script: "rm -rf deps ebin test/*.beam logs && ./rebar get-deps compile && ./rebar ct"
script: "wget https://s3.amazonaws.com/rebar3/rebar3 && escript rebar3 do edoc, eunit, ct"
branches:
only:
- master
@@ -16,7 +16,7 @@ Current Status

[![Build Status](https://travis-ci.org/ferd/recon.png)](https://travis-ci.org/ferd/recon)

Versions supported: R15B02 and up
Versions supported: OTP-17 and up. Support of R16B03-1 down to R15B02 is best effort.

Changelog
---------
@@ -27,6 +27,11 @@ all stable changes of the first version of Recon.

*2.x*

- 2.3.6
- Adapting for OTP-21. Includes the 'deprecation' of `recon:files/0`
since OTP-21 no longer supports listing all file descriptors, and
removing `error_logger_queue_len` from node stats since a new
logging mechanism was introduced in-process instead.
- 2.3.5
- fixing timefold's first iteration to prevent errors at call-site
by sleeping before sampling
@@ -1,6 +1,6 @@
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp disable
%%!
%% This script takes the EDoc output page, and tries to bring them to
%% a more modern format suitable for a recon site.
%% Run with `escript docsite.erl' or as `./docsite.erl'. The script
@@ -0,0 +1,5 @@
{profiles, [
{test, [
{erl_opts, [nowarn_export_all]}
]}
]}.
@@ -1,6 +1,6 @@
{application, recon,
[{description, "Diagnostic tools for production use"},
{vsn, "2.3.5"},
{vsn, "2.3.6"},
{modules, [recon, recon_alloc, recon_lib, recon_trace]},
{registered, []},
{applications, [kernel, stdlib]},
@@ -376,7 +376,8 @@ node_stats_list(N, Interval) ->
%%
%% Absolutes are values that keep changing with time, and are useful to know
%% about as a datapoint: process count, size of the run queue, error_logger
%% queue length, and the memory of the node (total, processes, atoms, binaries,
%% queue length in versions before OTP-21 or those thar run it explicitely,
%% and the memory of the node (total, processes, atoms, binaries,
%% and ets tables).
%%
%% Increments are values that are mostly useful when compared to a previous
@@ -392,14 +393,25 @@ node_stats_list(N, Interval) ->
Stats :: {[Absolutes::{atom(),term()}],
[Increments::{atom(),term()}]}.
node_stats(N, Interval, FoldFun, Init) ->
Logger = case whereis(error_logger) of
undefined -> logger;
_ -> error_logger
end,
%% Turn on scheduler wall time if it wasn't there already
FormerFlag = erlang:system_flag(scheduler_wall_time, true),
%% Stats is an ugly fun, but it does its thing.
Stats = fun({{OldIn,OldOut},{OldGCs,OldWords,_}, SchedWall}) ->
%% Absolutes
ProcC = erlang:system_info(process_count),
RunQ = erlang:statistics(run_queue),
{_,LogQ} = process_info(whereis(error_logger), message_queue_len),
LogQ = case Logger of
error_logger ->
{_,LogQLen} = process_info(whereis(error_logger),
message_queue_len),
LogQLen;
_ ->
undefined
end,
%% Mem (Absolutes)
Mem = erlang:memory(),
Tot = proplists:get_value(total, Mem),
@@ -418,8 +430,9 @@ node_stats(N, Interval, FoldFun, Init) ->
SchedWallNew = erlang:statistics(scheduler_wall_time),
SchedUsage = recon_lib:scheduler_usage_diff(SchedWall, SchedWallNew),
%% Stats Results
{{[{process_count,ProcC}, {run_queue,RunQ},
{error_logger_queue_len,LogQ}, {memory_total,Tot},
{{[{process_count,ProcC}, {run_queue,RunQ}] ++
[{error_logger_queue_len,LogQ} || LogQ =/= undefined] ++
[{memory_total,Tot},
{memory_procs,ProcM}, {memory_atoms,Atom},
{memory_bin,Bin}, {memory_ets,Ets}],
[{bytes_in,BytesIn}, {bytes_out,BytesOut},
@@ -511,6 +524,9 @@ udp() -> recon_lib:port_list(name, "udp_inet").
sctp() -> recon_lib:port_list(name, "sctp_inet").

%% @doc returns a list of all file handles open on the node.
%% @deprecated Starting with OTP-21, files are implemented as NIFs
%% and can no longer be listed. This function returns an empty list
%% in such a case.
-spec files() -> [port()].
files() -> recon_lib:port_list(name, "efile").

@@ -7,6 +7,16 @@
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).

-ifdef(OTP_RELEASE).
-define(FILES_IMPL, nif).
-define(ERROR_LOGGER_MATCH(_), ).
-define(REDUCTIONS_MATCH(X), X).
-else.
-define(FILES_IMPL, port).
-define(ERROR_LOGGER_MATCH(X), X,).
-define(REDUCTIONS_MATCH(_), []).
-endif.

all() -> [{group,info}, proc_count, proc_window, bin_leak,
node_stats_list, get_state, source, tcp, udp, files, port_types,
inet_count, inet_window, binary_memory, scheduler_usage].
@@ -29,22 +39,36 @@ init_per_group(info, Config) ->
end_per_group(info, Config) ->
exit(?config(pid, Config), kill).

init_per_testcase(files, Config) ->
case ?FILES_IMPL of
nif -> {skip, "files can no longer be listed in OTP-21 and above"};
port -> Config
end;
init_per_testcase(_, Config) ->
Config.

end_per_testcase(_, Config) ->
Config.

%%%%%%%%%%%%%
%%% TESTS %%%
%%%%%%%%%%%%%

info3(Config) ->
Pid = ?config(pid, Config),
{A,B,C} = pid_to_triple(Pid),
Info = recon:info(Pid),
Info = recon:info(A,B,C).

Info1 = recon:info(Pid),
Info2 = recon:info(A,B,C),
%% Reduction count is unreliable
?assertMatch(?REDUCTIONS_MATCH(
[{work, [{reductions,_}]}, {work, [{reductions,_}]}]
), (Info1 -- Info2) ++ (Info2 -- Info1)).

info4(Config) ->
Pid = ?config(pid, Config),
Keys = [meta, signals, location, memory_used, work,
links, monitors, reductions, messages,
[links, monitors, reductions, messages]],
links, monitors, messages,
[links, monitors, messages]],
{A,B,C} = pid_to_triple(Pid),
lists:map(fun(Key) ->
Info = recon:info(Pid, Key),
@@ -67,11 +91,25 @@ info1(Config) ->
undefined == proplists:get_value(K, proplists:get_value(Cat,Info))
]),
register(info1, Pid),
Res = recon:info(info1),
Res = recon:info(whereis(info1)),
Res = recon:info(pid_to_triple(whereis(info1))),
Res = recon:info(lists:flatten(io_lib:format("~p",[Pid]))),
unregister(info1).
Res1 = recon:info(info1),
Res2 = recon:info(whereis(info1)),
Res3 = recon:info(pid_to_triple(whereis(info1))),
Res4 = recon:info(lists:flatten(io_lib:format("~p",[Pid]))),
unregister(info1),
L = lists:usort(Res1 ++ Res2 ++ Res3 ++ Res4),
?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
{work,[{reductions,_}]},
{work,[{reductions,_}]}]), L -- Res1),
?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
{work,[{reductions,_}]},
{work,[{reductions,_}]}]), L -- Res2),
?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
{work,[{reductions,_}]},
{work,[{reductions,_}]}]), L -- Res3),
?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
{work,[{reductions,_}]},
{work,[{reductions,_}]}]), L -- Res4),
ok.

info2(Config) ->
Pid = ?config(pid, Config),
@@ -82,7 +120,7 @@ info2(Config) ->
total_heap_size, garbage_collection]},
{work, [reductions]}],
%% registered_name is special -- only returns
%% [] when passed through by info/2. Because we pass terms through
%% [] when passed through by info/2. Because we pass terms through
%% according to the docs, we have to respect that
[] = recon:info(Pid, registered_name),
%% Register to get the expected tuple
@@ -138,7 +176,7 @@ node_stats_list(_Config) ->
Res = recon:node_stats_list(2,100),
2 = length([1 || {[{process_count,_},
{run_queue,_},
{error_logger_queue_len,_},
?ERROR_LOGGER_MATCH({error_logger_queue_len,_})
{memory_total,_},
{memory_procs,_},
{memory_atoms,_},

0 comments on commit d19f241

Please sign in to comment.