1 Star 0 Fork 2.9K

Runner365/dgiot

forked from dgiot开源社区/dgiot 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
emqx_vm.erl 13.02 KB
一键复制 编辑 原始数据 按行查看 历史
jhonliu 提交于 2022-12-29 18:13 . feat: v4.4.11
%%--------------------------------------------------------------------
%% Copyright (c) 2017-2022 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(emqx_vm).
-export([ schedulers/0
, scheduler_usage/1
, system_info_keys/0
, get_system_info/0
, get_system_info/1
, get_memory/0
, get_memory/2
, mem_info/0
, loads/0
]).
-export([ process_info_keys/0
, get_process_info/0
, get_process_info/1
, process_gc_info_keys/0
, get_process_gc_info/0
, get_process_gc_info/1
, get_process_group_leader_info/1
, get_process_limit/0
]).
-export([ get_ets_list/0
, get_ets_info/0
, get_ets_info/1
, get_otp_version/0
]).
-export([cpu_util/0]).
-ifdef(TEST).
-compile(export_all).
-compile(nowarn_export_all).
-endif.
-define(UTIL_ALLOCATORS, [temp_alloc,
eheap_alloc,
binary_alloc,
ets_alloc,
driver_alloc,
sl_alloc,
ll_alloc,
fix_alloc,
literal_alloc,
std_alloc
]).
-define(PROCESS_INFO_KEYS, [initial_call,
current_stacktrace,
registered_name,
status,
message_queue_len,
group_leader,
priority,
trap_exit,
reductions,
%%binary,
last_calls,
catchlevel,
trace,
suspending,
sequential_trace_token,
error_handler
]).
-define(PROCESS_GC_KEYS, [memory,
total_heap_size,
heap_size,
stack_size,
min_heap_size
]).
-define(SYSTEM_INFO_KEYS, [allocated_areas,
allocator,
alloc_util_allocators,
build_type,
check_io,
compat_rel,
creation,
debug_compiled,
dist,
dist_ctrl,
driver_version,
elib_malloc,
dist_buf_busy_limit,
%fullsweep_after, % included in garbage_collection
garbage_collection,
%global_heaps_size, % deprecated
heap_sizes,
heap_type,
info,
kernel_poll,
loaded,
logical_processors,
logical_processors_available,
logical_processors_online,
machine,
%min_heap_size, % included in garbage_collection
%min_bin_vheap_size, % included in garbage_collection
modified_timing_level,
multi_scheduling,
multi_scheduling_blockers,
otp_release,
port_count,
process_count,
process_limit,
scheduler_bind_type,
scheduler_bindings,
scheduler_id,
schedulers,
schedulers_online,
smp_support,
system_version,
system_architecture,
threads,
thread_pool_size,
trace_control_word,
update_cpu_info,
version,
wordsize
]).
-define(SOCKET_OPTS, [active,
broadcast,
buffer,
delay_send,
dontroute,
exit_on_close,
header,
high_watermark,
ipv6_v6only,
keepalive,
linger,
low_watermark,
mode,
nodelay,
packet,
packet_size,
priority,
read_packets,
recbuf,
reuseaddr,
send_timeout,
send_timeout_close,
sndbuf,
tos
]).
schedulers() ->
erlang:system_info(schedulers).
loads() ->
[{load1, ftos(avg1()/256)},
{load5, ftos(avg5()/256)},
{load15, ftos(avg15()/256)}
].
system_info_keys() -> ?SYSTEM_INFO_KEYS.
get_system_info() ->
[{Key, format_system_info(Key, get_system_info(Key))} || Key <- ?SYSTEM_INFO_KEYS].
get_system_info(Key) ->
try erlang:system_info(Key) catch error:badarg-> undefined end.
format_system_info(allocated_areas, List) ->
[convert_allocated_areas(Value) || Value <- List];
format_system_info(allocator, {_, _, _, List}) ->
List;
format_system_info(dist_ctrl, List) ->
lists:map(fun({Node, Socket}) ->
{ok, Stats} = inet:getstat(Socket), {Node, Stats}
end, List);
format_system_info(driver_version, Value) ->
list_to_binary(Value);
format_system_info(machine, Value) ->
list_to_binary(Value);
format_system_info(otp_release, Value) ->
list_to_binary(Value);
format_system_info(scheduler_bindings, Value) ->
tuple_to_list(Value);
format_system_info(system_version, Value) ->
list_to_binary(Value);
format_system_info(system_architecture, Value) ->
list_to_binary(Value);
format_system_info(version, Value) ->
list_to_binary(Value);
format_system_info(_, Value) ->
Value.
convert_allocated_areas({Key, Value1, Value2}) ->
{Key, [Value1, Value2]};
convert_allocated_areas({Key, Value}) ->
{Key, Value}.
mem_info() ->
Dataset = memsup:get_system_memory_data(),
Total = proplists:get_value(total_memory, Dataset),
Free = proplists:get_value(free_memory, Dataset),
[{total_memory, Total}, {used_memory, Total - Free}].
ftos(F) ->
S = io_lib:format("~.2f", [F]), S.
%%%% erlang vm scheduler_usage fun copied from recon
scheduler_usage(Interval) when is_integer(Interval) ->
%% We start and stop the scheduler_wall_time system flag
%% if it wasn't in place already. Usually setting the flag
%% should have a CPU impact(make it higher) only when under low usage.
FormerFlag = erlang:system_flag(scheduler_wall_time, true),
First = erlang:statistics(scheduler_wall_time),
timer:sleep(Interval),
Last = erlang:statistics(scheduler_wall_time),
erlang:system_flag(scheduler_wall_time, FormerFlag),
scheduler_usage_diff(First, Last).
scheduler_usage_diff(First, Last) ->
lists:map(fun({{I, A0, T0}, {I, A1, T1}}) ->
{I, (A1 - A0)/(T1 - T0)}
end, lists:zip(lists:sort(First), lists:sort(Last))).
get_memory()->
get_memory_once(current) ++ erlang:memory().
get_memory(Ks, Keyword) when is_list(Ks) ->
Ms = get_memory_once(Keyword) ++ erlang:memory(),
[M || M = {K, _} <- Ms, lists:member(K, Ks)];
get_memory(used, Keyword) ->
lists:sum(lists:map(fun({_, Prop}) ->
container_size(Prop, Keyword, blocks_size)
end, util_alloc()));
get_memory(allocated, Keyword) ->
lists:sum(lists:map(fun({_, Prop}) ->
container_size(Prop, Keyword, carriers_size)
end, util_alloc()));
get_memory(unused, Keyword) ->
Ms = get_memory_once(Keyword),
proplists:get_value(allocated, Ms) - proplists:get_value(used, Ms);
get_memory(usage, Keyword) ->
Ms = get_memory_once(Keyword),
proplists:get_value(used, Ms) / proplists:get_value(allocated, Ms).
%% @private A more quickly function to calculate memory
get_memory_once(Keyword) ->
Calc = fun({_, Prop}, {N1, N2}) ->
{N1 + container_size(Prop, Keyword, blocks_size),
N2 + container_size(Prop, Keyword, carriers_size)}
end,
{Used, Allocated} = lists:foldl(Calc, {0, 0}, util_alloc()),
[{used, Used},
{allocated, Allocated},
{unused, Allocated - Used},
{usage, Used / Allocated}].
util_alloc()->
alloc(?UTIL_ALLOCATORS).
alloc(Type) ->
[{{T, Instance}, Props} ||
{{T, Instance}, Props} <- recon_alloc:allocators(), lists:member(T, Type)].
container_size(Prop, Keyword, Container) ->
Sbcs = container_value(Prop, Keyword, sbcs, Container),
Mbcs = container_value(Prop, Keyword, mbcs, Container),
Sbcs+Mbcs.
container_value(Prop, Keyword, Type, Container) when is_atom(Keyword)->
container_value(Prop, 2, Type, Container);
container_value(Props, Pos, mbcs = Type, Container) when is_integer(Pos)->
Pool = case proplists:get_value(mbcs_pool, Props) of
PoolProps when PoolProps =/= undefined ->
element(Pos, lists:keyfind(Container, 1, PoolProps));
_ ->
0
end,
TypeProps = proplists:get_value(Type, Props),
Pool + element(Pos, lists:keyfind(Container, 1, TypeProps));
container_value(Props, Pos, Type, Container) ->
TypeProps = proplists:get_value(Type, Props),
element(Pos, lists:keyfind(Container, 1, TypeProps)).
process_info_keys() ->
?PROCESS_INFO_KEYS.
get_process_info() ->
get_process_info(self()).
get_process_info(Pid) when is_pid(Pid) ->
process_info(Pid, ?PROCESS_INFO_KEYS).
process_gc_info_keys() ->
?PROCESS_GC_KEYS.
get_process_gc_info() ->
get_process_gc_info(self()).
get_process_gc_info(Pid) when is_pid(Pid) ->
process_info(Pid, ?PROCESS_GC_KEYS).
get_process_group_leader_info(LeaderPid) when is_pid(LeaderPid) ->
[{Key, Value}
|| {Key, Value} <- process_info(LeaderPid), lists:member(Key, ?PROCESS_INFO_KEYS)].
get_process_limit() ->
erlang:system_info(process_limit).
get_ets_list() ->
ets:all().
get_ets_info() ->
[get_ets_info(Tab) || Tab <- ets:all()].
get_ets_info(Tab) ->
case ets:info(Tab) of
undefined ->
[];
Entries when is_list(Entries) ->
mapping(Entries)
end.
mapping(Entries) ->
mapping(Entries, []).
mapping([], Acc) -> Acc;
mapping([{owner, V} | Entries], Acc) when is_pid(V) ->
OwnerInfo = process_info(V),
Owner = proplists:get_value(registered_name, OwnerInfo, undefined),
mapping(Entries, [{owner, Owner} | Acc]);
mapping([{Key, Value} | Entries], Acc) ->
mapping(Entries, [{Key, Value} | Acc]).
avg1() ->
compat_windows(fun cpu_sup:avg1/0).
avg5() ->
compat_windows(fun cpu_sup:avg5/0).
avg15() ->
compat_windows(fun cpu_sup:avg15/0).
cpu_util() ->
compat_windows(fun cpu_sup:util/0).
compat_windows(Fun) ->
case os:type() of
{win32, nt} -> 0;
_Type ->
case catch Fun() of
Val when is_number(Val) -> Val;
_Error -> 0
end
end.
%% @doc Return on which Eralng/OTP the current vm is running.
%% NOTE: This API reads a file, do not use it in critical code paths.
get_otp_version() ->
parse_built_on(read_otp_version()).
read_otp_version() ->
ReleasesDir = filename:join([code:root_dir(), "releases"]),
Filename = filename:join([ReleasesDir, emqx_app:get_release(), "BUILT_ON"]),
case file:read_file(Filename) of
{ok, BuiltOn} ->
%% running on EQM X release
BuiltOn;
{error, enoent} ->
%% running tests etc.
OtpMajor = erlang:system_info(otp_release),
OtpVsnFile = filename:join([ReleasesDir, OtpMajor, "OTP_VERSION"]),
{ok, Vsn} = file:read_file(OtpVsnFile),
Vsn
end.
parse_built_on(BuiltOn) ->
case binary:split(BuiltOn, <<"-">>, [global]) of
[Vsn, <<"emqx">>, N | _] ->
binary_to_list(Vsn) ++ "-emqx-" ++ binary_to_list(N);
[Vsn | _] ->
string:trim(binary_to_list(Vsn))
end.
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Erlang
1
https://gitee.com/iocs/dgiot.git
git@gitee.com:iocs/dgiot.git
iocs
dgiot
dgiot
master

搜索帮助