Current section
Files
Jump to
Current section
Files
src/load_ctl.erl
%%--------------------------------------------------------------------
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(load_ctl).
-include("lc.hrl").
-export([ is_overloaded/0
, is_high_mem/0
, maydelay/1
, accompany/2
, join/1
, leave/1
, whereis_runq_flagman/0
, whereis_mem_flagman/0
, stop_runq_flagman/0
, stop_runq_flagman/1
, stop_mem_flagman/0
, stop_mem_flagman/1
, restart_runq_flagman/0
, restart_mem_flagman/0
, put_config/1
, get_config/0
, get_memory_usage/0
, get_sys_memory/0
]).
%% overload check for realtime processing
-spec is_overloaded() -> boolean().
is_overloaded() ->
not (undefined =:= whereis(?RUNQ_MON_FLAG_NAME)).
%% overload check for realtime processing
-spec is_high_mem() -> boolean().
is_high_mem() ->
not (undefined =:= whereis(?MEM_MON_FLAG_NAME)).
-spec maydelay(erlang:timeout()) -> ok | timeout | false.
maydelay(Timeout) ->
case is_overloaded() andalso accompany(?RUNQ_MON_FLAG_NAME, Timeout) of
ok ->
ok;
{error, timeout} ->
timeout;
false ->
false
end.
%% process is put into a process priority group
%% process will be killed if system is overloaded when priority is under threshold
-spec join(non_neg_integer()) -> ok.
join(Priority) ->
ok = pg:join(?LC_SCOPE, {?LC_GROUP, Priority}, self()).
%% Leave process priority group, the number of leaves should match the number of join
-spec leave(non_neg_integer()) -> ok.
leave(Priority) ->
ok = pg:leave(?LC_SCOPE, {?LC_GROUP, Priority}, self()).
-spec put_config(map()) -> ok | {error, badarg}.
put_config(Config) when is_map(Config) ->
%% @TODO config validation.
persistent_term:put(?FLAG_MAN_CONFIGS_TERM, filter_config(Config));
put_config(_) ->
{error, badarg}.
-spec stop_runq_flagman() -> ok.
stop_runq_flagman() ->
lc_sup:stop_runq_flagman(infinity).
-spec stop_runq_flagman(erlang:timeout()) -> ok | {error, timeout}.
stop_runq_flagman(Timeout) ->
lc_sup:stop_runq_flagman(Timeout).
-spec stop_mem_flagman() -> ok.
stop_mem_flagman() ->
lc_sup:stop_mem_flagman(infinity).
-spec stop_mem_flagman(erlang:timeout()) -> ok | {error, timeout}.
stop_mem_flagman(Timeout) ->
lc_sup:stop_mem_flagman(Timeout).
-spec whereis_runq_flagman() -> pid() | undefined.
whereis_runq_flagman() ->
lc_sup:whereis_runq_flagman().
-spec whereis_mem_flagman() -> pid() | undefined.
whereis_mem_flagman() ->
lc_sup:whereis_mem_flagman().
-spec restart_runq_flagman() -> {ok, pid()} | {error, running | restarting | disabled}.
restart_runq_flagman() ->
case get_config() of
#{?RUNQ_MON_F0 := false} ->
{error, disabled};
_ ->
lc_sup:restart_runq_flagman()
end.
-spec restart_mem_flagman() -> {ok, pid()} | {error, running | restarting | disabled}.
restart_mem_flagman() ->
case get_config() of
#{?MEM_MON_F0 := false} ->
{error, disabled};
_ ->
lc_sup:restart_mem_flagman()
end.
-spec get_config() -> map().
get_config() ->
case persistent_term:get(?FLAG_MAN_CONFIGS_TERM, undefined) of
undefined ->
%% return defaults
#{ ?RUNQ_MON_F0 => ?RUNQ_MON_F0_DEFAULT
, ?RUNQ_MON_F1 => ?RUNQ_MON_F1_DEFAULT
, ?RUNQ_MON_F2 => ?RUNQ_MON_F2_DEFAULT
, ?RUNQ_MON_F3 => ?RUNQ_MON_F3_DEFAULT
, ?RUNQ_MON_F4 => ?RUNQ_MON_F4_DEFAULT
, ?RUNQ_MON_T1 => ?RUNQ_MON_T1_DEFAULT
, ?RUNQ_MON_T2 => ?RUNQ_MON_T2_DEFAULT
, ?RUNQ_MON_C1 => ?RUNQ_MON_C1_DEFAULT
, ?MEM_MON_F0 => ?MEM_MON_F0_DEFAULT
, ?MEM_MON_F1 => ?MEM_MON_F1_DEFAULT
, ?MEM_MON_T1 => ?MEM_MON_T1_DEFAULT
};
Other ->
Other
end.
filter_config(Config) ->
maps:with([ ?RUNQ_MON_F0
, ?RUNQ_MON_F1
, ?RUNQ_MON_F2
, ?RUNQ_MON_F3
, ?RUNQ_MON_F4
, ?RUNQ_MON_T1
, ?RUNQ_MON_T2
, ?RUNQ_MON_C1
, ?MEM_MON_F0
, ?MEM_MON_F1
, ?MEM_MON_T1
], Config).
-spec accompany(atom() | pid(), erlang:timeout()) -> ok | {error, timeout}.
accompany(Target, Timeout) ->
Mref = erlang:monitor(process, Target),
receive
{'DOWN', Mref, process, _Object, _Info} -> ok
after Timeout ->
erlang:demonitor(Mref, [flush]),
{error, timeout}
end.
%% @doc Return RAM usage ratio and total number of bytes.
%% `{0, 0}' indicates an error in collecting the stats.
-spec get_memory_usage() -> number().
get_memory_usage() ->
lc_lib:get_memory_usage().
%% @doc Return RAM usage ratio (from 0 to 1).
%% `0' probably indicates an error in collecting the stats.
-spec get_sys_memory() -> {number(), number()}.
get_sys_memory() ->
lc_lib:get_sys_memory().
%%%_* Emacs ====================================================================
%%% Local Variables:
%%% allout-layout: t
%%% erlang-indent-level: 2
%%% End: