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 + -
显示快捷键?