From 66a9271db995cd845e5cc8990b7b00b887276401 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Wed, 26 Feb 2020 14:12:08 +0200 Subject: [PATCH] Logs memory usage by specific parts of erlang VM at a time Log format: ``` 14:03:28.892 [info] EPP proxy memory usage total: 31.04 MB, processes: 8.60 MB, processes_used: 8.59 MB, system: 22.43 MB, atom: 492.61 KB, atom_used: 468.70 KB, binary: 893.20 KB, code: 8.16 MB, ets: 1.18 MB. ``` --- apps/epp_proxy/src/epp_proxy_sup.erl | 10 ++- apps/epp_proxy/src/memory_monitor.erl | 95 +++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 apps/epp_proxy/src/memory_monitor.erl diff --git a/apps/epp_proxy/src/epp_proxy_sup.erl b/apps/epp_proxy/src/epp_proxy_sup.erl index f10aa72..9814d67 100644 --- a/apps/epp_proxy/src/epp_proxy_sup.erl +++ b/apps/epp_proxy/src/epp_proxy_sup.erl @@ -57,10 +57,14 @@ init([]) -> PoolSupervisor = #{id => epp_pool_supervisor, type => supervisor, modules => [epp_pool_supervisor], start => {epp_pool_supervisor, start_link, []}}, + MemoryMonitor = #{id => memory_monitor, type => worker, + modules => [memory_monitor], + start => {memory_monitor, start_link, []}}, + SharedSpecs = [TLSAcceptor, PoolSupervisor, + MemoryMonitor], ChildrenSpec = case ?DevMode of - {ok, true} -> - [TCPAcceptor, TLSAcceptor, PoolSupervisor]; - _ -> [TLSAcceptor, PoolSupervisor] + {ok, true} -> [TCPAcceptor | SharedSpecs]; + _ -> SharedSpecs end, {ok, {SupFlags, ChildrenSpec}}. diff --git a/apps/epp_proxy/src/memory_monitor.erl b/apps/epp_proxy/src/memory_monitor.erl new file mode 100644 index 0000000..58b2c3b --- /dev/null +++ b/apps/epp_proxy/src/memory_monitor.erl @@ -0,0 +1,95 @@ +%%%------------------------------------------------------------------- +%%% @doc +%%% +%%% @end +%%% Created: 20 Feb 2020 +%%%------------------------------------------------------------------- +-module(memory_monitor). + +-behaviour(gen_server). + +-define(TEN_MINUTES_IN_MS, 10 * 30 * 1000). + +-define(THIRTY_MINUTES_IN_MS, 30 * 30 * 1000). + +-define(ONE_HOUR_IN_MS, 60 * 60 * 1000). + +-export([init/1, start_link/0]). + +-export([code_change/3, handle_call/3, handle_cast/2, + handle_info/2, terminate/2]). + +-export([log_memory/0]). + +-record(state, {timer_ref :: timer:tref()}). + +-type state() :: #state{}. + +-spec start_link() -> ignore | {error, _} | {ok, pid()}. + +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], + []). + +-spec init([]) -> {ok, state()}. + +init([]) -> + {ok, TimerReference} = + timer:send_interval(?THIRTY_MINUTES_IN_MS, log_usage), + erlang:send(self(), log_usage), + {ok, #state{timer_ref = TimerReference}}. + +%%%------------------------------------------------------------------- +%%% GenServer callbacks +%%%------------------------------------------------------------------- +-spec handle_call(_, _, State) -> {stop, + not_implemented, State}. + +handle_call(_M, _F, State) -> + {stop, not_implemented, State}. + +-spec handle_cast(_, State) -> {stop, not_implemented, + State}. + +handle_cast(_M, State) -> + {stop, not_implemented, State}. + +-spec handle_info(log_usage, _) -> {noreply, _}. + +handle_info(log_usage, State) -> + ok = log_memory(), {noreply, State}. + +-spec terminate(_, state()) -> ok. + +terminate(_Reason, State) -> + {ok, cancel} = timer:cancel(State#state.timer_ref), ok. + +-spec code_change(_, _, _) -> {ok, _}. + +code_change(_OldVersion, State, _Extra) -> {ok, State}. + +%%%------------------------------------------------------------------- +%%% Internal functions +%%%------------------------------------------------------------------- +log_memory() -> + Mem = erlang:memory(), + Values = lists:map(fun ({Name, Value}) -> + List = io_lib:format("~s: ~s", + [Name, + human_filesize(Value)]), + binary:list_to_bin(List) + end, + Mem), + Values, + lager:info("EPP proxy memory usage ~s.", + [lists:join(", ", Values)]). + +human_filesize(Size) -> + human_filesize(Size, + ["B", "KB", "MB", "GB", "TB", "PB"]). + +human_filesize(S, [_ | [_ | _] = L]) when S >= 1024 -> + human_filesize(S / 1024, L); +human_filesize(S, [M | _]) -> + List = io_lib:format("~.2f ~s", [float(S), M]), + binary:list_to_bin(List).