diff options
Diffstat (limited to 'lib/runtime_tools/src')
-rw-r--r-- | lib/runtime_tools/src/Makefile | 6 | ||||
-rw-r--r-- | lib/runtime_tools/src/appmon_info.erl | 2 | ||||
-rw-r--r-- | lib/runtime_tools/src/dbg.erl | 93 | ||||
-rw-r--r-- | lib/runtime_tools/src/erts_alloc_config.erl | 2 | ||||
-rw-r--r-- | lib/runtime_tools/src/msacc.erl | 355 | ||||
-rw-r--r-- | lib/runtime_tools/src/observer_backend.erl | 2 | ||||
-rw-r--r-- | lib/runtime_tools/src/percept_profile.erl | 2 | ||||
-rw-r--r-- | lib/runtime_tools/src/runtime_tools.app.src | 5 | ||||
-rw-r--r-- | lib/runtime_tools/src/runtime_tools.appup.src | 2 | ||||
-rw-r--r-- | lib/runtime_tools/src/runtime_tools.erl | 2 | ||||
-rw-r--r-- | lib/runtime_tools/src/runtime_tools_sup.erl | 2 |
11 files changed, 441 insertions, 32 deletions
diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile index 99b90f9ec5..2c902952a1 100644 --- a/lib/runtime_tools/src/Makefile +++ b/lib/runtime_tools/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2013. All Rights Reserved. +# Copyright Ericsson AB 1999-2016. 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. @@ -45,7 +45,9 @@ MODULES= \ percept_profile \ system_information \ observer_backend \ - ttb_autostart + ttb_autostart\ + msacc + HRL_FILES= ../include/observer_backend.hrl ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/runtime_tools/src/appmon_info.erl b/lib/runtime_tools/src/appmon_info.erl index dd4dc34fcb..fead724373 100644 --- a/lib/runtime_tools/src/appmon_info.erl +++ b/lib/runtime_tools/src/appmon_info.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. 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. diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index 6eea1a0917..d5ff874206 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -298,7 +298,12 @@ tracer(port, Port) when is_port(Port) -> start(fun() -> Port end); tracer(process, {Handler,HandlerData}) -> - start(fun() -> start_tracer_process(Handler, HandlerData) end). + start(fun() -> start_tracer_process(Handler, HandlerData) end); + +tracer(module, Fun) when is_function(Fun) -> + start(Fun); +tracer(module, {Module, State}) -> + start(fun() -> {Module, State} end). remote_tracer(port, Fun) when is_function(Fun) -> @@ -308,7 +313,13 @@ remote_tracer(port, Port) when is_port(Port) -> remote_start(fun() -> Port end); remote_tracer(process, {Handler,HandlerData}) -> - remote_start(fun() -> start_tracer_process(Handler, HandlerData) end). + remote_start(fun() -> start_tracer_process(Handler, HandlerData) end); + +remote_tracer(module, Fun) when is_function(Fun) -> + remote_start(Fun); +remote_tracer(module, {Module, State}) -> + remote_start(fun() -> {Module, State} end). + remote_start(StartTracer) -> case (catch StartTracer()) of @@ -543,9 +554,8 @@ c(M, F, A, Flags) -> {error,Reason} -> {error,Reason}; Flags1 -> tracer(), - {ok, Tracer} = get_tracer(), S = self(), - Pid = spawn(fun() -> c(S, M, F, A, [{tracer, Tracer} | Flags1]) end), + Pid = spawn(fun() -> c(S, M, F, A, [get_tracer_flag() | Flags1]) end), Mref = erlang:monitor(process, Pid), receive {'DOWN', Mref, _, _, Reason} -> @@ -660,6 +670,9 @@ loop({C,T}=SurviveLinks, Table) -> reply(From, {error, Reason}); Tracer when is_pid(Tracer); is_port(Tracer) -> put(node(),{self(),Tracer}), + reply(From, {ok,self()}); + {Module, _State} = Tracer when is_atom(Module) -> + put(node(),{self(),Tracer}), reply(From, {ok,self()}) end; {_Relay,_Tracer} -> @@ -710,6 +723,9 @@ loop({C,T}=SurviveLinks, Table) -> {_LocalRelay,Tracer} when is_port(Tracer) -> reply(From, {error, cant_trace_remote_pid_to_local_port}), loop(SurviveLinks, Table); + {_LocalRelay,Tracer} when is_tuple(Tracer) -> + reply(From, {error, cant_trace_remote_pid_to_local_module}), + loop(SurviveLinks, Table); {_LocalRelay,Tracer} when is_pid(Tracer) -> case (catch relay(Node, Tracer)) of {ok,Relay} -> @@ -879,9 +895,9 @@ trac(Proc, How, Flags) -> end end. -trac(Node, {_Relay, Tracer}, AtomPid, How, Flags) -> +trac(Node, {_Replay, Tracer}, AtomPid, How, Flags) -> case rpc:call(Node, ?MODULE, erlang_trace, - [AtomPid, How, [{tracer, Tracer} | Flags]]) of + [AtomPid, How, [get_tracer_flag(Tracer) | Flags]]) of N when is_integer(N) -> {matched, Node, N}; {badrpc,Reason} -> @@ -1114,7 +1130,7 @@ transform_flags([sos|Tail],Acc) -> transform_flags(Tail,[set_on_spawn|Acc]); transform_flags([sol|Tail],Acc) -> transform_flags(Tail,[set_on_link|Acc]); transform_flags([sofs|Tail],Acc) -> transform_flags(Tail,[set_on_first_spawn|Acc]); transform_flags([sofl|Tail],Acc) -> transform_flags(Tail,[set_on_first_link|Acc]); -transform_flags([all|_],_Acc) -> all()--[silent]; +transform_flags([all|_],_Acc) -> all()--[silent,running]; transform_flags([F|Tail]=List,Acc) when is_atom(F) -> case lists:member(F, all()) of true -> transform_flags(Tail,[F|Acc]); @@ -1123,9 +1139,10 @@ transform_flags([F|Tail]=List,Acc) when is_atom(F) -> transform_flags(Bad,_Acc) -> {error,{bad_flags,Bad}}. all() -> - [send,'receive',call,procs,garbage_collection,running, + [send,'receive',call,procs,ports,garbage_collection,running, set_on_spawn,set_on_first_spawn,set_on_link,set_on_first_link, - timestamp,arity,return_to,silent]. + timestamp,monotonic_timestamp,strict_monotonic_timestamp, + arity,return_to,silent,running_procs,running_ports]. display_info([Node|Nodes]) -> io:format("~nNode ~w:~n",[Node]), @@ -1146,24 +1163,34 @@ display_info1([]) -> ok. get_info() -> - get_info(processes(),[]). + get_info(processes(),get_info(erlang:ports(),[])). +get_info([Port|T], Acc) when is_port(Port) -> + case pinfo(Port, name) of + undefined -> + get_info(T,Acc); + {name, Name} -> + get_info(T,get_tinfo(Port, Name, Acc)) + end; get_info([Pid|T],Acc) -> case pinfo(Pid, initial_call) of undefined -> get_info(T,Acc); {initial_call, Call} -> - case tinfo(Pid, flags) of - undefined -> - get_info(T,Acc); - {flags,[]} -> - get_info(T,Acc); - {flags,Flags} -> - get_info(T,[{Pid,Call,Flags}|Acc]) - end + get_info(T,get_tinfo(Pid, Call, Acc)) end; get_info([],Acc) -> Acc. +get_tinfo(P, Id, Acc) -> + case tinfo(P, flags) of + undefined -> + Acc; + {flags,[]} -> + Acc; + {flags,Flags} -> + [{P,Id,Flags}|Acc] + end. + format_trace([]) -> []; format_trace([Item]) -> [ts(Item)]; format_trace([Item|T]) -> [ts(Item) ," | ", format_trace(T)]. @@ -1188,9 +1215,22 @@ to_pidspec(X) when is_pid(X) -> true -> X; false -> {badpid,X} end; -to_pidspec(new) -> new; -to_pidspec(all) -> all; -to_pidspec(existing) -> existing; +to_pidspec(X) when is_port(X) -> + case erlang:port_info(X) of + undefined -> {badport, X}; + _ -> X + end; +to_pidspec(Tag) + when Tag =:= all; + Tag =:= ports; + Tag =:= processes; + Tag =:= new; + Tag =:= new_ports; + Tag =:= new_processes; + Tag =:= existing; + Tag =:= existing_ports; + Tag =:= existing_processes -> + Tag; to_pidspec(X) when is_atom(X) -> case whereis(X) of undefined -> {badpid,X}; @@ -1203,6 +1243,7 @@ to_pidspec(X) -> {badpid,X}. %% to_pid(X) when is_pid(X) -> X; +to_pid(X) when is_port(X) -> X; to_pid(X) when is_integer(X) -> to_pid({0,X,0}); to_pid({X,Y,Z}) -> to_pid(lists:concat(["<",integer_to_list(X),".", @@ -1217,9 +1258,12 @@ to_pid(X) when is_list(X) -> to_pid(X) -> {badpid,X}. +pinfo(P, X) when node(P) == node(), is_port(P) -> erlang:port_info(P, X); pinfo(P, X) when node(P) == node() -> erlang:process_info(P, X); +pinfo(P, X) when is_port(P) -> check(rpc:call(node(P), erlang, port_info, [P, X])); pinfo(P, X) -> check(rpc:call(node(P), erlang, process_info, [P, X])). + tinfo(P, X) when node(P) == node() -> erlang:trace_info(P, X); tinfo(P, X) -> check(rpc:call(node(P), erlang, trace_info, [P, X])). @@ -1411,6 +1455,13 @@ get_tracer() -> req({get_tracer,node()}). get_tracer(Node) -> req({get_tracer,Node}). +get_tracer_flag() -> + {ok, Tracer} = get_tracer(), + get_tracer_flag(Tracer). +get_tracer_flag({Module,State}) -> + {tracer, Module, State}; +get_tracer_flag(Port = Pid) when is_port(Port); is_pid(Pid)-> + {tracer, Pid = Port}. save_pattern([]) -> 0; diff --git a/lib/runtime_tools/src/erts_alloc_config.erl b/lib/runtime_tools/src/erts_alloc_config.erl index 85aacdd6e1..e94cced911 100644 --- a/lib/runtime_tools/src/erts_alloc_config.erl +++ b/lib/runtime_tools/src/erts_alloc_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2016. 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. diff --git a/lib/runtime_tools/src/msacc.erl b/lib/runtime_tools/src/msacc.erl new file mode 100644 index 0000000000..4db5dbec91 --- /dev/null +++ b/lib/runtime_tools/src/msacc.erl @@ -0,0 +1,355 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2014-2015. 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. +%% +%% %CopyrightEnd% +%% + +%% +%% @doc Microstate accounting utility function +%% +%% This module provides a user interface for analysing +%% erlang:statistics(microstate_accounting) data. +%% + +-module(msacc). +-export([available/0, start/0, start/1, stop/0, reset/0, to_file/1, + from_file/1, stats/0, stats/2, print/0, print/1, print/2, + print/3]). + +-type msacc_data() :: [msacc_data_thread()]. + +-type msacc_data_thread() :: #{ '$type' := msacc_data, + type := msacc_type(), id := msacc_id(), + counters := msacc_data_counters() }. +-type msacc_data_counters() :: #{ msacc_state() => non_neg_integer()}. + +-type msacc_stats() :: [msacc_stats_thread()]. +-type msacc_stats_thread() :: #{ '$type' := msacc_stats, + type := msacc_type(), id := msacc_id(), + system := float(), + counters := msacc_stats_counters()}. +-type msacc_stats_counters() :: #{ msacc_state() => #{ thread := float(), + system := float()}}. + + +-type msacc_type() :: scheduler | aux | async. +-type msacc_id() :: non_neg_integer(). +-type msacc_state() :: alloc | aux | bif | busy_wait | check_io | + emulator | ets | gc | gc_fullsweep | nif | + other | port | send | sleep | timers. + +-type msacc_print_options() :: #{ system => boolean() }. + +-spec available() -> boolean(). +available() -> + try + [_|_] = erlang:statistics(microstate_accounting), + true + catch _:_ -> + false + end. + +-spec start() -> boolean(). +start() -> + erlang:system_flag(microstate_accounting, true). + +-spec stop() -> boolean(). +stop() -> + erlang:system_flag(microstate_accounting, false). + +-spec reset() -> boolean(). +reset() -> + erlang:system_flag(microstate_accounting, reset). + +-spec start(Time) -> true when + Time :: timeout(). +start(Tmo) -> + stop(), reset(), start(), + timer:sleep(Tmo), + stop(). + +-spec to_file(Filename) -> ok | {error, file:posix()} when + Filename :: file:name_all(). +to_file(Filename) -> + file:write_file(Filename, io_lib:format("~p.~n",[stats()])). + +-spec from_file(Filename) -> msacc_data() when + Filename :: file:name_all(). +from_file(Filename) -> + {ok, [Stats]} = file:consult(Filename), + Stats. + +-spec print() -> ok. +print() -> + print(stats()). + +-spec print(DataOrStats) -> ok when + DataOrStats :: msacc_data() | msacc_stats(). +print(Stats) -> + print(Stats, #{}). + +-spec print(DataOrStats, Options) -> ok when + DataOrStats :: msacc_data() | msacc_stats(), + Options :: msacc_print_options(). +print(Stats, Options) -> + print(group_leader(), Stats, Options). + +-spec print(FileOrDevice, DataOrStats, Options) -> ok when + FileOrDevice :: file:filename() | io:device(), + DataOrStats :: msacc_data() | msacc_stats(), + Options :: msacc_print_options(). +print(Filename, Stats, Options) when is_list(Filename) -> + case file:open(Filename,[write]) of + {ok, D} -> print(D, Stats, Options),file:close(D); + Error -> Error + end; +print(Device, Stats, Options) -> + DefaultOpts = #{ system => false }, + print_int(Device, Stats, maps:merge(DefaultOpts, Options)). +print_int(Device, [#{ '$type' := msacc_data, id := _Id }|_] = Stats, Options) -> + TypeStats = stats(type, Stats), + io:format(Device, "~s", [print_stats_overview(Stats, Options)]), + io:format(Device, "~s", [print_stats_header(Stats, Options)]), + io:format(Device, "~s", [print_stats_threads( + stats(realtime, Stats), Options)]), + io:format(Device, "~s", [print_stats_type( + stats(realtime, TypeStats), Options)]); +print_int(Device, [#{ '$type' := msacc_data }|_] = Stats, Options) -> + io:format(Device, "~s", [print_stats_header(Stats, Options)]), + io:format(Device, "~s", [print_stats_type( + stats(realtime, Stats), Options)]); +print_int(Device, [#{ '$type' := msacc_stats, id := _Id }|_] = Stats,Options) -> + io:format(Device, "~s", [print_stats_header(Stats, Options)]), + io:format(Device, "~s", [print_stats_threads(Stats, Options)]), + io:format(Device, "~s", [print_stats_type( + msacc:stats(type, Stats), Options)]); +print_int(Device, [#{ '$type' := msacc_stats }|_] = Stats, Options) -> + io:format(Device, "~s", [print_stats_header(Stats, Options)]), + io:format(Device, "~s", [print_stats_type(Stats, Options)]). + + +-spec stats() -> msacc_data(). +stats() -> + Fun = fun F(K,{PerfCount,StateCount}) -> + %% Need to handle ERTS_MSACC_STATE_COUNTERS + {F(K,PerfCount),StateCount}; + F(_K,PerfCount) -> + erlang:convert_time_unit(PerfCount, perf_counter, 1000000) + end, + UsStats = lists:map( + fun(#{ counters := Cnt } = M) -> + UsCnt = maps:map(Fun,Cnt), + M#{ '$type' => msacc_data, counters := UsCnt } + end, erlang:statistics(microstate_accounting)), + statssort(UsStats). + +-spec stats(Analysis, Stats) -> non_neg_integer() when + Analysis :: system_realtime | system_runtime, + Stats :: msacc_data(); + (Analysis, Stats) -> msacc_stats() when + Analysis :: realtime | runtime, + Stats :: msacc_data(); + (Analysis, StatsOrData) -> msacc_data() | msacc_stats() when + Analysis :: type, + StatsOrData :: msacc_data() | msacc_stats(). +stats(system_realtime, Stats) -> + lists:foldl(fun(#{ counters := Cnt }, Acc) -> + get_total(Cnt, Acc) + end, 0, Stats); +stats(system_runtime, Stats) -> + lists:foldl(fun(#{ counters := Cnt }, Acc) -> + get_total(maps:remove(sleep, Cnt), Acc) + end, 0, Stats); +stats(realtime, Stats) -> + RealTime = stats(system_realtime, Stats), + statssort([get_thread_perc(Thread, RealTime) || Thread <- Stats]); +stats(runtime, Stats) -> + RunTime = stats(system_runtime, Stats), + statssort([get_thread_perc(T#{ counters := maps:remove(sleep,Cnt)}, RunTime) + || T = #{ counters := Cnt } <- Stats]); +stats(type, Stats) -> + statssort(merge_threads(Stats, [])). + +print_stats_overview(Stats, _Options) -> + RunTime = stats(system_runtime, Stats), + RealTime = stats(system_realtime, Stats) div length(Stats), + SchedStats = [S || #{ type := scheduler } = S <- Stats], + AvgSchedRunTime = stats(system_runtime, SchedStats) div length(SchedStats), + NumSize = if + RealTime > RunTime -> length(integer_to_list(RealTime)); + true -> length(integer_to_list(RunTime)) + end, + [io_lib:format("Average thread real-time : ~*B us~n", + [NumSize, RealTime]), + io_lib:format("Accumulated system run-time : ~*B us~n", + [NumSize, RunTime]), + io_lib:format("Average scheduler run-time : ~*B us~n", + [NumSize, AvgSchedRunTime]), + io_lib:format("~n",[])]. + +print_stats_threads(Stats, Options) -> + [io_lib:format("~nStats per thread:~n", []), + [print_thread_info(Thread, Options) || Thread <- Stats]]. + +print_stats_type(Stats, Options) -> + [io_lib:format("~nStats per type:~n", []), + [print_thread_info(Thread, Options) || Thread <- Stats]]. + + +print_stats_header([#{ counters := Cnt }|_], #{ system := PrintSys }) -> + [io_lib:format("~14s", ["Thread"]), + map(fun(Counter, _) when PrintSys-> + io_lib:format("~9s ", [atom_to_list(Counter)]); + (Counter, _) -> + io_lib:format("~9s", [atom_to_list(Counter)]) + end, Cnt), + io_lib:format("~n",[])]. + +print_thread_info(#{ '$type' := msacc_stats, + counters := Cnt } = Thread, #{ system := PrintSys }) -> + [case maps:find(id, Thread) of + error -> + io_lib:format("~14s", [atom_to_list(maps:get(type, Thread))]); + {ok, Id} -> + io_lib:format("~10s(~2B)", [atom_to_list(maps:get(type,Thread)),Id]) + end, + map(fun(_Key, #{ thread := ThreadPerc, system := SystemPerc }) when PrintSys -> + io_lib:format("~6.2f%(~4.1f%)", [ThreadPerc, SystemPerc]); + (_Key, #{ thread := ThreadPerc }) -> + io_lib:format("~8.2f%", [ThreadPerc]) + end, Cnt), + io_lib:format("~n",[])]. + +get_total(Cnt, Base) -> + maps:fold(fun(_, {Val,_}, Time) -> + %% Have to handle ERTS_MSACC_STATE_COUNTERS + Time + Val; + (_, Val, Time) -> Time + Val + end, Base, Cnt). + +get_thread_perc(#{ '$type' := msacc_data, counters := Cnt } = Thread, + SystemTime) -> + ThreadTime = get_total(Cnt, 0), + Thread#{ '$type' := msacc_stats, + system => percentage(ThreadTime,SystemTime), + counters => get_thread_perc(Cnt, ThreadTime, SystemTime)}. +get_thread_perc(Cnt, ThreadTime, SystemTime) -> + maps:map(fun F(Key, {Val, C}) -> + M = F(Key, Val), + M#{ cnt => C }; + F(_Key, Val) -> + #{ thread => percentage(Val, ThreadTime), + system => percentage(Val, SystemTime) } + end, Cnt). + +%% This code is a little bit messy as it has to be able to deal with +%% both [msacc_data()] and [msacc_stats()]. +merge_threads([#{ '$type' := msacc_stats, + type := Type, + counters := Cnt } = M0|R], Acc) -> + case keyfind(type, Type, Acc) of + false -> + merge_threads(R, [maps:remove(id,M0#{ threads => 1 })|Acc]); + #{ '$type' := msacc_stats, counters := Cnt0, + threads := Threads, system := System } = M -> + NewMap = M#{ counters := add_counters(Cnt, Cnt0), + system := System + maps:get(system, M0), + threads := Threads + 1}, + NewAcc = keyreplace(type, Type, NewMap, Acc), + merge_threads(R, NewAcc) + end; +merge_threads([], [#{ '$type' := msacc_stats, + system := System, + threads := Threads, + counters := Cnt} = M0|R]) -> + Counters = maps:map(fun(_,#{ thread := Thr } = Map) -> + Map#{ thread := Thr / Threads } + end, Cnt), + M = maps:remove(threads, M0), + [M#{ system := System, counters := Counters} | merge_threads([],R)]; +merge_threads([], []) -> + []; +%% The clauses below deal with msacc_data() +merge_threads([#{ '$type' := msacc_data, + type := Type, + counters := Cnt } = M0|R], Acc) -> + case keyfind(type, Type, Acc) of + false -> + merge_threads(R, [maps:remove(id,M0)|Acc]); + #{ '$type' := msacc_data, counters := Cnt0 } = M -> + NewMap = M#{ counters := add_counters(Cnt, Cnt0) }, + NewAcc = keyreplace(type, Type, NewMap, Acc), + merge_threads(R, NewAcc) + end; +merge_threads([], Acc) -> + Acc. + +add_counters(M1, M2) -> + maps:map( + fun(Key, #{ thread := Thr1, system := Sys1, cnt := Cnt1}) -> + %% Have to handle ERTS_MSACC_STATE_COUNTERS + #{ thread := Thr2, system := Sys2, cnt := Cnt2} = maps:get(Key, M2), + #{ thread => Thr1 + Thr2, system => Sys1 + Sys2, + cnt => Cnt1 + Cnt2 }; + (Key, #{ thread := Thr1, system := Sys1}) -> + #{ thread := Thr2, system := Sys2} = maps:get(Key, M2), + #{ thread => Thr1 + Thr2, system => Sys1 + Sys2}; + (Key, {V1,C1}) -> + %% Have to handle ERTS_MSACC_STATE_COUNTERS + {V2,C2} = maps:get(Key, M2),{V1+V2,C1+C2}; + (Key, V1) -> maps:get(Key, M2) + V1 + end, M1). + +percentage(Divident, Divisor) -> + if Divisor == 0 andalso Divident /= 0 -> + 100.0; + Divisor == 0 -> + 0.0; + true -> + Divident / Divisor * 100 + end. + +keyfind(Key, Value, [H|T]) -> + case maps:find(Key, H) of + {ok, Value} -> + H; + _ -> + keyfind(Key, Value, T) + end; +keyfind(_, _, []) -> + false. + +keyreplace(Key, Value, NewMap, [H|T]) -> + case maps:find(Key, H) of + {ok, Value} -> + [NewMap|T]; + _ -> + [H|keyreplace(Key, Value, NewMap, T)] + end; +keyreplace(_, _, _, []) -> + []. + +statssort(Stats) -> + lists:sort(fun(#{ type := Type1, id := Id1}, + #{ type := Type2, id := Id2}) -> + {Type1, Id1} < {Type2, Id2}; + (#{ type := Type1}, #{ type := Type2}) -> + Type1 < Type2 + end, Stats). + +map(Fun,Map) -> + [ Fun(K,V) || {K,V} <- maps:to_list(Map) ]. diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl index 9177752cef..30df3b0b8b 100644 --- a/lib/runtime_tools/src/observer_backend.erl +++ b/lib/runtime_tools/src/observer_backend.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2014. All Rights Reserved. +%% Copyright Ericsson AB 2002-2016. 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. diff --git a/lib/runtime_tools/src/percept_profile.erl b/lib/runtime_tools/src/percept_profile.erl index d5ea2c7032..ceec4d3b89 100644 --- a/lib/runtime_tools/src/percept_profile.erl +++ b/lib/runtime_tools/src/percept_profile.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. 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. diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src index ad10655aa0..4d96996ce0 100644 --- a/lib/runtime_tools/src/runtime_tools.app.src +++ b/lib/runtime_tools/src/runtime_tools.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2012. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. 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. @@ -22,7 +22,8 @@ {vsn, "%VSN%"}, {modules, [appmon_info, dbg,observer_backend,percept_profile, runtime_tools,runtime_tools_sup,erts_alloc_config, - ttb_autostart,dyntrace,system_information]}, + ttb_autostart,dyntrace,system_information, + msacc]}, {registered, [runtime_tools_sup]}, {applications, [kernel, stdlib]}, {env, []}, diff --git a/lib/runtime_tools/src/runtime_tools.appup.src b/lib/runtime_tools/src/runtime_tools.appup.src index 883ff1e074..a42673c87e 100644 --- a/lib/runtime_tools/src/runtime_tools.appup.src +++ b/lib/runtime_tools/src/runtime_tools.appup.src @@ -1,7 +1,7 @@ %% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2014. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. 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. diff --git a/lib/runtime_tools/src/runtime_tools.erl b/lib/runtime_tools/src/runtime_tools.erl index 62b9dfd71e..52ae5cc0eb 100644 --- a/lib/runtime_tools/src/runtime_tools.erl +++ b/lib/runtime_tools/src/runtime_tools.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-2016. 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. diff --git a/lib/runtime_tools/src/runtime_tools_sup.erl b/lib/runtime_tools/src/runtime_tools_sup.erl index e69b495cb5..efa37de42d 100644 --- a/lib/runtime_tools/src/runtime_tools_sup.erl +++ b/lib/runtime_tools/src/runtime_tools_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2013. All Rights Reserved. +%% Copyright Ericsson AB 2006-2016. 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. |