--module(beam_stats_state).
-
--include("include/beam_stats.hrl").
--include("include/beam_stats_process.hrl").
--include("include/beam_stats_processes.hrl").
-
--export_type(
- [ t/0
- ]).
-
--export(
- [ new/0
- , update/1
- , export/1
- ]).
-
--record(snapshots,
- { memory :: [{atom(), non_neg_integer()}]
- , processes :: beam_stats_processes:t()
- , run_queue :: non_neg_integer()
- , ets :: beam_stats_ets:t()
- }).
-
--type snapshots() ::
- #snapshots{}.
-
--record(deltas,
- { reductions :: non_neg_integer()
- }).
-
--type deltas() ::
- #deltas{}.
-
--record(totals,
- { io_bytes_in :: non_neg_integer()
- , io_bytes_out :: non_neg_integer()
- , context_switches :: non_neg_integer()
- }).
-
--type totals() ::
- #totals{}.
-
--record(?MODULE,
- { timestamp :: erlang:timestamp()
- , node_id :: atom()
- , snapshots :: snapshots() % Current state
- , deltas :: deltas() % Accumulated since last check
- , totals_previous :: totals() % Accumulated since VM start, as of last state
- , totals_current :: totals() % Accumulated since VM start, as of this state
- }).
-
--define(T, #?MODULE).
-
--opaque t() ::
- ?T{}.
-
--spec new() ->
- t().
-new() ->
- TotalsPrevious = totals_empty(),
- new(TotalsPrevious).
-
--spec new(TotalsPrevious :: totals()) ->
- t().
-new(#totals{}=TotalsPrevious) ->
- ?T
- { timestamp = beam_stats_source:os_timestamp()
- , node_id = beam_stats_source:erlang_node()
- , snapshots = snapshots_new()
- , deltas = deltas_new()
- , totals_previous = TotalsPrevious
- , totals_current = totals_new()
- }.
-
--spec update(t()) ->
- t().
-update(?T{totals_current=TotalsPrevious}) ->
- new(TotalsPrevious).
-
--spec export(t()) ->
- beam_stats:t().
-export(
- ?T
- { timestamp = Timestamp
- , node_id = NodeID
- , snapshots =
- #snapshots
- { memory = Memory
- , processes = Processes
- , run_queue = RunQueue
- , ets = ETS
- }
- , deltas =
- #deltas
- { reductions = Reductions
- }
- , totals_previous =
- #totals
- { io_bytes_in = PreviousIOBytesIn
- , io_bytes_out = PreviousIOBytesOut
- , context_switches = PreviousContextSwitches
- }
- , totals_current =
- #totals
- { io_bytes_in = CurrentIOBytesIn
- , io_bytes_out = CurrentIOBytesOut
- , context_switches = CurrentContextSwitches
- }
- }
-) ->
- #beam_stats
- { timestamp = Timestamp
- , node_id = NodeID
- , memory = Memory
- , io_bytes_in = CurrentIOBytesIn - PreviousIOBytesIn
- , io_bytes_out = CurrentIOBytesOut - PreviousIOBytesOut
- , context_switches = CurrentContextSwitches - PreviousContextSwitches
- , reductions = Reductions
- , run_queue = RunQueue
- , ets = ETS
- , processes = Processes
- }.
-
-snapshots_new() ->
- #snapshots
- { memory = beam_stats_source:erlang_memory()
- , processes = beam_stats_processes:collect()
- , run_queue = beam_stats_source:erlang_statistics(run_queue)
- , ets = beam_stats_ets:collect()
- }.
-
-deltas_new() ->
- {_ReductionsTotal, ReductionsDelta} = beam_stats_source:erlang_statistics(reductions),
- #deltas
- { reductions = ReductionsDelta
- }.
-
-totals_new() ->
- { {input , IOBytesIn}
- , {output , IOBytesOut}
- } = beam_stats_source:erlang_statistics(io),
- {ContextSwitches, 0} = beam_stats_source:erlang_statistics(context_switches),
- #totals
- { io_bytes_in = IOBytesIn
- , io_bytes_out = IOBytesOut
- , context_switches = ContextSwitches
- }.
-
-totals_empty() ->
- #totals
- { io_bytes_in = 0
- , io_bytes_out = 0
- , context_switches = 0
- }.