memsup.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,003 行 · 第 1/3 页
ERL
1,003 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(memsup).-behaviour(gen_server).%% API-export([start_link/0]). % for supervisor-export([get_memory_data/0, get_system_memory_data/0, get_check_interval/0, set_check_interval/1, get_procmem_high_watermark/0, set_procmem_high_watermark/1, get_sysmem_high_watermark/0, set_sysmem_high_watermark/1, get_helper_timeout/0, set_helper_timeout/1]).-export([dummy_reply/1, param_type/2, param_default/1]).%% gen_server callbacks-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).%% Other exports-export([format_status/2]).-include("memsup.hrl").-record(state, {os, % {OSfamily,OSname} | OSfamily port_mode, % bool() mem_usage, % undefined | {Alloc, Total} worst_mem_user, % undefined | {Pid, Alloc} sys_only, % bool() memsup_system_only timeout, % int() memory_check_interval, ms helper_timeout, % int() memsup_helper_timeout, ms sys_mem_watermark, % float() system_memory_high_watermark, % proc_mem_watermark, % float() process_memory_high_watermark, % pid, % undefined | pid() wd_timer, % undefined | TimerRef ext_wd_timer, % undefined | TimerRef pending = [], % [reg | {reg,From} | {ext,From}] ext_pending = [] % [{ext,From}] }).%%----------------------------------------------------------------------%% API%%----------------------------------------------------------------------start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).get_memory_data() -> os_mon:call(memsup, get_memory_data, infinity).get_system_memory_data() -> os_mon:call(memsup, get_system_memory_data, infinity).get_check_interval() -> os_mon:call(memsup, get_check_interval, infinity).set_check_interval(Minutes) -> case param_type(memory_check_interval, Minutes) of true -> MS = minutes_to_ms(Minutes), % for backwards compatibility os_mon:call(memsup, {set_check_interval, MS}, infinity); false -> erlang:error(badarg) end.get_procmem_high_watermark() -> os_mon:call(memsup, get_procmem_high_watermark, infinity).set_procmem_high_watermark(Float) -> case param_type(process_memory_high_watermark, Float) of true -> os_mon:call(memsup, {set_procmem_high_watermark, Float}, infinity); false -> erlang:error(badarg) end.get_sysmem_high_watermark() -> os_mon:call(memsup, get_sysmem_high_watermark, infinity).set_sysmem_high_watermark(Float) -> case param_type(system_memory_high_watermark, Float) of true -> os_mon:call(memsup, {set_sysmem_high_watermark, Float}, infinity); false -> erlang:error(badarg) end.get_helper_timeout() -> os_mon:call(memsup, get_helper_timeout, infinity).set_helper_timeout(Seconds) -> case param_type(memsup_helper_timeout, Seconds) of true -> os_mon:call(memsup, {set_helper_timeout, Seconds}); false -> erlang:error(badarg) end.dummy_reply(get_memory_data) -> dummy_reply(get_memory_data, os_mon:get_env(memsup, memsup_system_only));dummy_reply(get_system_memory_data) -> [];dummy_reply(get_check_interval) -> minutes_to_ms(os_mon:get_env(memsup, memory_check_interval));dummy_reply({set_check_interval, _}) -> ok;dummy_reply(get_procmem_high_watermark) -> trunc(100 * os_mon:get_env(memsup, process_memory_high_watermark));dummy_reply({set_procmem_high_watermark, _}) -> ok;dummy_reply(get_sysmem_high_watermark) -> trunc(100 * os_mon:get_env(memsup, system_memory_high_watermark));dummy_reply({set_sysmem_high_watermark, _}) -> ok;dummy_reply(get_helper_timeout) -> os_mon:get_env(memsup, memsup_helper_timeout);dummy_reply({set_helper_timeout, _}) -> ok.dummy_reply(get_memory_data, true) -> {0,0,undefined};dummy_reply(get_memory_data, false) -> {0,0,{self(),0}}.param_type(memsup_system_only, Val) when Val==true; Val==false -> true;param_type(memory_check_interval, Val) when is_integer(Val), Val>0 -> true;param_type(memsup_helper_timeout, Val) when is_integer(Val), Val>0 -> true;param_type(system_memory_high_watermark, Val) when is_number(Val), 0=<Val, Val=<1 -> true;param_type(process_memory_high_watermark, Val) when is_number(Val), 0=<Val, Val=<1 -> true;param_type(_Param, _Val) -> false.param_default(memsup_system_only) -> false;param_default(memory_check_interval) -> 1;param_default(memsup_helper_timeout) -> 30;param_default(system_memory_high_watermark) -> 0.80;param_default(process_memory_high_watermark) -> 0.05.%%----------------------------------------------------------------------%% gen_server callbacks%%----------------------------------------------------------------------init([]) -> process_flag(trap_exit, true), process_flag(priority, low), OS = os:type(), PortMode = case OS of {unix, darwin} -> false; {unix, freebsd} -> false; {unix, linux} -> false; {unix, openbsd} -> true; {unix, irix64} -> true; {unix, irix} -> true; {unix, sunos} -> true; {win32, _OSname} -> false; vxworks -> true; _ -> exit({unsupported_os, OS}) end, Pid = if PortMode -> spawn_link(fun() -> port_init() end); not PortMode -> undefined end, %% Read the values of some configuration parameters SysOnly = os_mon:get_env(memsup, memsup_system_only), Timeout = os_mon:get_env(memsup, memory_check_interval), HelperTimeout = os_mon:get_env(memsup, memsup_helper_timeout), SysMem = os_mon:get_env(memsup, system_memory_high_watermark), ProcMem = os_mon:get_env(memsup, process_memory_high_watermark), %% Initiate first data collection self() ! time_to_collect, {ok, #state{os=OS, port_mode=PortMode, sys_only = SysOnly, timeout = minutes_to_ms(Timeout), helper_timeout = sec_to_ms(HelperTimeout), sys_mem_watermark = SysMem, proc_mem_watermark = ProcMem, pid=Pid}}.handle_call(get_memory_data, From, State) -> %% Return result of latest memory check case State#state.mem_usage of {Alloc, Total} -> Worst = State#state.worst_mem_user, {reply, {Total, Alloc, Worst}, State}; %% Special case: get_memory_data called before any memory data %% has been collected undefined -> case State#state.wd_timer of undefined -> WDTimer = erlang:send_after(State#state.timeout, self(), reg_collection_timeout), Pending = [{reg,From}], if State#state.port_mode -> State#state.pid ! {self(), collect_sys}, {noreply, State#state{wd_timer=WDTimer, pending=Pending}}; true -> OS = State#state.os, Self = self(), Pid = spawn_link(fun() -> MU = get_memory_usage(OS), Self ! {collected_sys,MU} end), {noreply, State#state{pid=Pid, wd_timer=WDTimer, pending=Pending}} end; _TimerRef -> Pending = [{reg,From} | State#state.pending], {noreply, State#state{pending=Pending}} end end;handle_call(get_system_memory_data,From,#state{port_mode=true}=State) -> %% When using a port, the extensive memory collection is slightly %% different than a regular one case State#state.ext_wd_timer of undefined -> WDTimer = erlang:send_after(State#state.helper_timeout, self(), ext_collection_timeout), State#state.pid ! {self(), collect_ext_sys}, {noreply, State#state{ext_wd_timer=WDTimer, ext_pending=[{ext,From}]}}; _TimerRef -> Pending = [{ext,From} | State#state.ext_pending], {noreply, State#state{ext_pending=Pending}} end;handle_call(get_system_memory_data, From, State) -> %% When not using a port, the regular memory collection is used %% for extensive memory data as well case State#state.wd_timer of undefined -> WDTimer = erlang:send_after(State#state.helper_timeout, self(), reg_collection_timeout), OS = State#state.os, Self = self(), Pid = spawn_link(fun() -> MemUsage = get_memory_usage(OS), Self ! {collected_sys, MemUsage} end), {noreply, State#state{pid=Pid, wd_timer=WDTimer, pending=[{ext,From}]}}; _TimerRef -> Pending = [{ext,From} | State#state.pending], {noreply, State#state{pending=Pending}} end;handle_call(get_check_interval, _From, State) -> {reply, State#state.timeout, State};handle_call({set_check_interval, MS}, _From, State) -> {reply, ok, State#state{timeout=MS}};handle_call(get_procmem_high_watermark, _From, State) -> {reply, trunc(100 * State#state.proc_mem_watermark), State};handle_call({set_procmem_high_watermark, Float}, _From, State) -> {reply, ok, State#state{proc_mem_watermark=Float}};handle_call(get_sysmem_high_watermark, _From, State) -> {reply, trunc(100 * State#state.sys_mem_watermark), State};handle_call({set_sysmem_high_watermark, Float}, _From, State) -> {reply, ok, State#state{sys_mem_watermark=Float}};handle_call(get_helper_timeout, _From, State) -> {reply, ms_to_sec(State#state.helper_timeout), State};handle_call({set_helper_timeout, Seconds}, _From, State) -> {reply, ok, State#state{helper_timeout=sec_to_ms(Seconds)}};%% The following are only for test purposes (whitebox testing).handle_call({set_sys_hw, HW}, _From, State) -> {reply, ok, State#state{sys_mem_watermark=HW}};handle_call({set_pid_hw, HW}, _From, State) -> {reply, ok, State#state{proc_mem_watermark=HW}};handle_call(get_state, _From, State) -> {reply, State, State}.handle_cast(_Msg, State) -> {noreply, State}.%% It's time to check memoryhandle_info(time_to_collect, State) -> case State#state.wd_timer of undefined -> WDTimer = erlang:send_after(State#state.helper_timeout, self(), reg_collection_timeout), if State#state.port_mode -> State#state.pid ! {self(), collect_sys}, {noreply, State#state{wd_timer=WDTimer, pending=[reg]}}; true -> OS = State#state.os, Self = self(), Pid = spawn_link(fun() -> MU = get_memory_usage(OS), Self ! {collected_sys,MU} end), {noreply, State#state{pid=Pid, wd_timer=WDTimer, pending=[reg]}} end;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?