cpu_sup.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 639 行 · 第 1/2 页

ERL
639
字号
%% ``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(cpu_sup).%% API-export([start_link/0, start/0, stop/0]).-export([nprocs/0, avg1/0, avg5/0, avg15/0, util/0, util/1]).-export([dummy_reply/1]).%% For testing-export([ping/0]).%% gen_server callbacks-export([init/1, handle_call/3, handle_cast/2, handle_info/2,	 terminate/2, code_change/3]).%% Internal protocol with the port program-define(nprocs,"n").-define(avg1,"1").-define(avg5,"5").-define(avg15,"f").-define(quit,"q").-define(ping,"p").-define(util,"u").-define(INT32(D3,D2,D1,D0),	(((D3) bsl 24) bor ((D2) bsl 16) bor ((D1) bsl 8) bor (D0))).-define(MAX_UINT32, ((1 bsl 32) - 1)).-record(cpu_util, {cpu, busy = [], non_busy = []}).-record(state, {port = not_used, util = [], os_type}).%%----------------------------------------------------------------------%% API%%----------------------------------------------------------------------start() ->    gen_server:start({local, cpu_sup}, cpu_sup, [], []).start_link() ->    gen_server:start_link({local, cpu_sup}, cpu_sup, [], []).stop() ->    gen_server:call(cpu_sup,?quit).nprocs() ->    os_mon:call(cpu_sup,?nprocs).avg1() ->    os_mon:call(cpu_sup,?avg1).avg5() ->    os_mon:call(cpu_sup,?avg5).avg15() ->    os_mon:call(cpu_sup,?avg15).util(ArgList) when is_list(ArgList) ->    case lists:foldl(fun (detailed, {_, PC}) -> {true, PC};			 (per_cpu,  {D, _}) ->  {D,    true};			 (_, _) ->              badarg		     end,		     {false, false},		     ArgList) of	badarg ->	    erlang:error(badarg);	{Detailed, PerCpu} ->	    os_mon:call(cpu_sup, {?util, Detailed, PerCpu})    end;util(_Arg) ->    erlang:error(badarg).util() ->    case util([]) of	{all, Busy, _, _} ->	    Busy;	Error ->	    Error    end.dummy_reply(?nprocs) -> 0;dummy_reply(?avg1) ->   0;dummy_reply(?avg5) ->   0;dummy_reply(?avg15) ->  0;dummy_reply({?util,_,_}) -> {all, 0, 0, []}.%%----------------------------------------------------------------------%% For testing%%----------------------------------------------------------------------ping() ->    gen_server:call(cpu_sup,?ping).%%----------------------------------------------------------------------%% gen_server callbacks%%----------------------------------------------------------------------init([]) ->    process_flag(trap_exit, true),    process_flag(priority, low),    OS = os:type(),    Port = case OS of	       {unix, sunos} ->		   start_portprogram();	       {unix, Flavor} when Flavor==darwin;				   Flavor==freebsd;				   Flavor==linux;				   Flavor==openbsd;				   Flavor==irix64;				   Flavor==irix ->		   not_used;	       _ ->		   exit({unsupported_os, OS})	   end,    {ok, #state{port=Port, os_type=OS}}.handle_call(?quit, _From, State) ->    {stop, normal, ok, State};handle_call({?util, Detailed, PerCpu}, {Client, _Tag},	    #state{port = Port, os_type = {unix, sunos}} = State) ->    Port ! {self(), {command, ?util}},    get_util_measurement_reply(Client,			       Detailed,			       PerCpu,			       fun () ->				       %% Port program sends cpu				       %% information sorted on				       %% cpu index in ascending				       %% order.				       sunos_receive_cpu_util(Port)			       end,			       State);handle_call({?util, Detailed, PerCpu}, {Client, _Tag},	    #state{os_type = {unix, linux}} = State) ->    get_util_measurement_reply(Client,			       Detailed,			       PerCpu,			       fun () -> linux_read_cpu_util() end,			       State);handle_call({?util, _Detailed, _PerCpu}, _From, State) ->    String = "OS_MON (cpu_sup), util/1 unavailable for this OS~n",    error_logger:warning_msg(String),    {reply, dummy_reply(?util), State};handle_call(Request, _From, State) when Request==?nprocs;					Request==?avg1;					Request==?avg5;					Request==?avg15;					Request==?ping ->    Result = get_int_measurement(Request, State),    {reply, Result, State}.handle_cast(_Msg, State) ->    {noreply, State}.handle_info({'EXIT', _Port, Reason}, State) ->    {stop, {port_died, Reason}, State#state{port=not_used}};handle_info({'DOWN',Monitor,process,_,_}, #state{util = Utils} = State) ->    {noreply, State#state{util = lists:keydelete(Monitor, 2, Utils)}};handle_info(_Info, State) ->    {noreply, State}.terminate(_Reason, State) ->    case State#state.port of	not_used ->	    ok;	Port ->	    Port ! {self(), {command, ?quit}},	    port_close(Port)    end,    ok.%% os_mon-2.0%% For live downgrade to/upgrade from os_mon-1.8[.1]code_change(Vsn, PrevState, "1.8") ->    case Vsn of	%% Downgrade from this version	{down, _Vsn} ->	    process_flag(trap_exit, false);	%% Upgrade to this version	_Vsn ->	    process_flag(trap_exit, true)    end,    {ok, PrevState};code_change(_OldVsn, State, _Extra) ->    {ok, State}.%%----------------------------------------------------------------------%% Internal functions%%----------------------------------------------------------------------start_portprogram() ->    Command = filename:join([code:priv_dir(os_mon), "bin", "cpu_sup"]),    Port = open_port({spawn, Command}, [stream]),    Port ! {self(), {command, ?ping}},    4711 = receive_int(Port),    Port.get_util_measurement_reply(Client, Detailed, PerCpu, NewCpuUtilFun,			   #state{util = Utils} = State) ->    {Monitor, OldCpuUtil, Utils2} = case keysearchdelete(Client, 1, Utils) of					{{value, {Client, Mon, U}}, Us} ->					    {Mon, U, Us};					{false, Us} ->					    {erlang:monitor(process, Client),					     [],					     Us}				    end,    case NewCpuUtilFun() of	{error, Error} ->	    {stop, Error, Error, State};	NewCpuUtil ->	    {reply,	     cpu_util_rel(NewCpuUtil, OldCpuUtil, Detailed, PerCpu),	     State#state{util = [{Client,Monitor,NewCpuUtil}|Utils2]}}    end.get_int_measurement(Request, #state{port = Port, os_type = {unix, sunos}}) ->    Port ! {self(), {command, Request}},    receive_int(Port);get_int_measurement(Request, #state{os_type = {unix, linux}}) ->    {ok,F} = file:open("/proc/loadavg",[read,raw]),    {ok,D} = file:read(F,24),    ok = file:close(F),    {ok,[Load1,Load5,Load15,_PRun,PTotal],_} = io_lib:fread("~f ~f ~f ~d/~d", D),    case Request of	?avg1  -> sunify(Load1);	?avg5  -> sunify(Load5);	?avg15 -> sunify(Load15);	?ping -> 4711;	?nprocs -> PTotal    end;get_int_measurement(Request, #state{os_type = {unix, freebsd}}) ->    D = os:cmd("/sbin/sysctl -n vm.loadavg") -- "\n",    {ok,[Load1,Load5,Load15],_} = io_lib:fread("{ ~f ~f ~f }", D),    %% We could count the lines from the ps command as well    case Request of	?avg1  -> sunify(Load1);	?avg5  -> sunify(Load5);	?avg15 -> sunify(Load15);	?ping -> 4711;	?nprocs ->	    Ps = os:cmd("/bin/ps -ax | /usr/bin/wc -l"),	    {ok, [N], _} = io_lib:fread("~d", Ps),	    N-1    end;get_int_measurement(Request, #state{os_type = {unix, openbsd}}) ->    D = os:cmd("/sbin/sysctl -n vm.loadavg") -- "\n",    {ok, [L1, L5, L15], _} = io_lib:fread("~f ~f ~f", D),    case Request of	?avg1  -> sunify(L1);	?avg5  -> sunify(L5);	?avg15 -> sunify(L15);	?ping -> 4711;	?nprocs ->	    Ps = os:cmd("/bin/ps -ax | /usr/bin/wc -l"),	    {ok, [N], _} = io_lib:fread("~d", Ps),	    N-1    end;get_int_measurement(Request, #state{os_type = {unix, darwin}}) ->    %% Get the load average using uptime.    D = os:cmd("uptime") -- "\n",    %% Here is a sample uptime string from Mac OS 10.3.8:    %%    "11:17  up 12 days, 20:39, 2 users, load averages: 1.07 0.95 0.66"    %% The safest way to extract the load averages seems to be grab everything    %% after the last colon and then do an fread on that.    Avg = lists:reverse(hd(string:tokens(lists:reverse(D), ":"))),    {ok,[L1,L5,L15],_} = io_lib:fread("~f ~f ~f", Avg),    case Request of	?avg1  -> sunify(L1);	?avg5  -> sunify(L5);	?avg15 -> sunify(L15);	?ping -> 4711;	?nprocs ->	    Ps = os:cmd("/bin/ps -ax | /usr/bin/wc -l"),	    {ok, [N], _} = io_lib:fread("~d", Ps),	    N-1    end;get_int_measurement(Request, #state{os_type = {unix, Sys}}) when Sys == irix64;								 Sys == irix ->    %% Get the load average using uptime.    %% "8:01pm  up 2 days, 22:12,  4 users,  load average: 0.70, 0.58, 0.43"    D = os:cmd("uptime") -- "\n",    Avg = lists:reverse(hd(string:tokens(lists:reverse(D), ":"))),    {ok, [L1, L5, L15], _} = io_lib:fread("~f, ~f, ~f", Avg),    case Request of	?avg1  -> sunify(L1);	?avg5  -> sunify(L5);	?avg15 -> sunify(L15);	?ping -> 4711;	?nprocs ->	    {ok, ProcList} = file:list_dir("/proc/pinfo"),	    length(ProcList)    end.sunify(Val)  ->    round(Val*256). % Note that Solaris and Linux load averages are		    % measured quite differently anywayreceive_int(Port) ->    receive_int(Port, []).

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?