From cf20035dc7a4fbab47ce17b99b674e4db5eb7a07 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Thu, 14 Nov 2013 15:34:55 +0100 Subject: observer: Fix memory and scheduler info and handle missing fields Fix app viewer crash --- lib/observer/src/observer_app_wx.erl | 15 ++++++++++----- lib/observer/src/observer_lib.erl | 31 ++++++++++++++++++++---------- lib/observer/src/observer_perf_wx.erl | 29 +++++++++++++++------------- lib/observer/src/observer_sys_wx.erl | 9 ++++++--- lib/runtime_tools/src/observer_backend.erl | 15 +++++++++++++-- 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl index 82395fbe08..a710bd0a69 100644 --- a/lib/observer/src/observer_app_wx.erl +++ b/lib/observer/src/observer_app_wx.erl @@ -178,11 +178,16 @@ handle_event(#wx{id=Id, event=_Sz=#wxSize{size=Size}}, {noreply, State}; handle_event(#wx{event=#wxMouse{type=Type, x=X0, y=Y0}}, - S0=#state{app=#app{ptree=Tree}, app_w=AppWin}) -> - {X,Y} = wxScrolledWindow:calcUnscrolledPosition(AppWin, X0, Y0), - Hit = locate_node(X,Y, [Tree]), - State = handle_mouse_click(Hit, Type, S0), - {noreply, State}; + S0=#state{app=App, app_w=AppWin}) -> + case App of + #app{ptree=Tree} -> + {X,Y} = wxScrolledWindow:calcUnscrolledPosition(AppWin, X0, Y0), + Hit = locate_node(X,Y, [Tree]), + State = handle_mouse_click(Hit, Type, S0), + {noreply, State}; + _ -> + {noreply, S0} + end; handle_event(#wx{event=#wxCommand{type=command_menu_selected}}, State = #state{sel=undefined}) -> diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index f11ccfb752..6288dd3a45 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -144,29 +144,29 @@ fill_info([{dynamic, Key}|Rest], Data) %% Special case used by crashdump_viewer when the value decides %% which header to use case get_value(Key, Data) of - undefined -> fill_info(Rest, Data); + undefined -> [undefined | fill_info(Rest, Data)]; {Str,Value} -> [{Str, Value} | fill_info(Rest, Data)] end; fill_info([{Str, Key}|Rest], Data) when is_atom(Key); is_function(Key) -> case get_value(Key, Data) of - undefined -> fill_info(Rest, Data); + undefined -> [undefined | fill_info(Rest, Data)]; Value -> [{Str, Value} | fill_info(Rest, Data)] end; fill_info([{Str,Attrib,Key}|Rest], Data) when is_atom(Key); is_function(Key) -> case get_value(Key, Data) of - undefined -> fill_info(Rest, Data); + undefined -> [undefined | fill_info(Rest, Data)]; Value -> [{Str,Attrib,Value} | fill_info(Rest, Data)] end; fill_info([{Str, {Format, Key}}|Rest], Data) when is_atom(Key); is_function(Key), is_atom(Format) -> case get_value(Key, Data) of - undefined -> fill_info(Rest, Data); + undefined -> [undefined | fill_info(Rest, Data)]; Value -> [{Str, {Format, Value}} | fill_info(Rest, Data)] end; fill_info([{Str, Attrib, {Format, Key}}|Rest], Data) when is_atom(Key); is_function(Key), is_atom(Format) -> case get_value(Key, Data) of - undefined -> fill_info(Rest, Data); + undefined -> [undefined | fill_info(Rest, Data)]; Value -> [{Str, Attrib, {Format, Value}} | fill_info(Rest, Data)] end; fill_info([{Str,SubStructure}|Rest], Data) when is_list(SubStructure) -> @@ -189,6 +189,8 @@ update_info([Fields|Fs], [{_Header, _Attrib, SubStructure}| Rest]) -> update_info([], []) -> ok. +update_info2([undefined|Fs], [_|Rest]) -> + update_info2(Fs, Rest); update_info2([Scroll = {_, _, _}|Fs], [{_, NewInfo}|Rest]) -> update_scroll_boxes(Scroll, NewInfo), update_info2(Fs, Rest); @@ -198,6 +200,9 @@ update_info2([Field|Fs], [{_Str, {click, Value}}|Rest]) -> update_info2([Field|Fs], [{_Str, Value}|Rest]) -> wxTextCtrl:setValue(Field, to_str(Value)), update_info2(Fs, Rest); +update_info2([Field|Fs], [undefined|Rest]) -> + wxTextCtrl:setValue(Field, ""), + update_info2(Fs, Rest); update_info2([], []) -> ok. update_scroll_boxes({_, _, 0}, {_, []}) -> ok; @@ -223,10 +228,10 @@ to_str({bytes, B}) -> MB = KB div 1024, GB = MB div 1024, if - GB > 10 -> integer_to_list(GB) ++ " gB"; - MB > 10 -> integer_to_list(MB) ++ " mB"; + GB > 10 -> integer_to_list(GB) ++ " GB"; + MB > 10 -> integer_to_list(MB) ++ " MB"; KB > 0 -> integer_to_list(KB) ++ " kB"; - true -> integer_to_list(B) ++ " B " + true -> integer_to_list(B) ++ " B" end; to_str({time_ms, MS}) -> S = MS div 1000, @@ -396,7 +401,9 @@ create_box(Panel, {scroll_boxes,Data}) -> AddBox = fun({Title,Proportion,Format = {_,_}}) -> add_box(Panel, OuterBox, Cursor, Title, Proportion, Format); ({Title, Format = {_,_}}) -> - add_box(Panel, OuterBox, Cursor, Title, 1, Format) + add_box(Panel, OuterBox, Cursor, Title, 1, Format); + (undefined) -> + undefined end, Boxes = [AddBox(Entry) || Entry <- Data], wxCursor:destroy(Cursor), @@ -457,7 +464,9 @@ create_box(Panel, Data) -> wxTextCtrl:setMinSize(Field,{0,H}), wxSizer:add(Box, Line, [{proportion,0},{flag,?wxEXPAND}]), - Field + Field; + (undefined) -> + undefined end, InfoFields = [AddRow(Entry) || Entry <- Info], {Box, InfoFields}. @@ -512,6 +521,8 @@ get_max_size(Txt,[{Desc,_}|Info],MaxX,MaxY) -> true -> get_max_size(Txt,Info,MaxX,MaxY) end; +get_max_size(Txt,[undefined|Info],MaxX,MaxY) -> + get_max_size(Txt,Info,MaxX,MaxY); get_max_size(_,[],X,Y) -> {X+2,Y}. diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl index 54c98f3ba3..8173349ed7 100644 --- a/lib/observer/src/observer_perf_wx.erl +++ b/lib/observer/src/observer_perf_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012. All Rights Reserved. +%% Copyright Ericsson AB 2012-2013. All Rights Reserved. %% %% 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 @@ -283,7 +283,12 @@ mem_types() -> lmax([]) -> 0; lmax(List) -> - lists:max([lists:max(tuple_to_list(T)) || T <- List]). + Max = [lists:max(tuple_to_list(T)) || T <- List, + tuple_size(T) > 0], + case Max of + [] -> 0; + _ -> lists:max(Max) + end. calc_delta([{Id, WN, TN}|Ss], [{Id, WP, TP}|Ps]) -> [100*(WN-WP) div (TN-TP)|calc_delta(Ss, Ps)]; @@ -301,25 +306,23 @@ draw(Offset, Id, DC, Panel, Paint=#paint{pens=Pens, small=Small}, Data, Active) {X0,Y0,WS,HS} = draw_borders(Id, NoGraphs, DC, Size, Max, Paint), Last = 60*WS+X0-1, Start = max(61-Len, 0)*WS+X0 - Offset*WS, - case Hs of - [] -> ignore; - [_] -> ignore; - _ -> + Samples = length(Hs), + case Active andalso Samples > 1 andalso NoGraphs > 0 of + true -> Draw = fun(N) -> Lines = make_lines(Hs, Start, N, {X0,Max*HS,Last}, Y0, WS, HS), setPen(DC, element(1+ ((N-1) rem tuple_size(Pens)), Pens)), strokeLines(DC, Lines), N+1 end, - [Draw(I) || I <- lists:seq(NoGraphs, 1, -1)] - end, - case Active of + [Draw(I) || I <- lists:seq(NoGraphs, 1, -1)]; false -> - NotActive = "Service not available", + Info = case Active andalso Samples =< 1 of + true -> "Waiting on data"; + false -> "Information not available" + end, setFont(DC, Small, {0,0,0}), - drawText(DC, NotActive, X0 + 100, element(2,Size) div 2); - true -> - ignore + drawText(DC, Info, X0 + 100, element(2,Size) div 2) end, ok. diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl index 31800cf12a..8321d6eefe 100644 --- a/lib/observer/src/observer_sys_wx.erl +++ b/lib/observer/src/observer_sys_wx.erl @@ -167,9 +167,12 @@ info_fields() -> {"Async thread pool size", thread_pool_size} ]}, {"CPU's and Threads", - [{"System Logical CPU's", logical_processors}, - {"Erlang Logical CPU's", logical_processors_online}, - {"Used Logical CPU's", logical_processors_available} + [{"Logical CPU's", logical_processors}, + {"Online Logical CPU's", logical_processors_online}, + {"Available Logical CPU's", logical_processors_available}, + {"Schedulers", schedulers}, + {"Online schedulers", schedulers_online}, + {"Available schedulers", schedulers_available} ]} ], Stat = [{"Memory Usage", right, diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl index 202129c61a..68ef04f20c 100644 --- a/lib/runtime_tools/src/observer_backend.erl +++ b/lib/runtime_tools/src/observer_backend.erl @@ -53,6 +53,13 @@ sys_info() -> Mem -> Mem catch _:_ -> [] end, + + SchedulersOnline = erlang:system_info(schedulers_online), + SchedulersAvailable = case erlang:system_info(multi_scheduling) of + enabled -> SchedulersOnline; + _ -> 1 + end, + {{_,Input},{_,Output}} = erlang:statistics(io), [{process_count, erlang:system_info(process_count)}, {process_limit, erlang:system_info(process_limit)}, @@ -60,9 +67,13 @@ sys_info() -> {run_queue, erlang:statistics(run_queue)}, {io_input, Input}, {io_output, Output}, + {logical_processors, erlang:system_info(logical_processors)}, - {logical_processors_available, erlang:system_info(logical_processors_available)}, {logical_processors_online, erlang:system_info(logical_processors_online)}, + {logical_processors_available, erlang:system_info(logical_processors_available)}, + {schedulers, erlang:system_info(schedulers)}, + {schedulers_online, SchedulersOnline}, + {schedulers_available, SchedulersAvailable}, {otp_release, erlang:system_info(otp_release)}, {version, erlang:system_info(version)}, @@ -221,7 +232,7 @@ fetch_stats_loop(Parent, Time) -> _M = Parent ! {stats, 1, erlang:statistics(scheduler_wall_time), erlang:statistics(io), - erlang:memory()}, + try erlang:memory() catch _:_ -> [] end}, fetch_stats_loop(Parent, Time) end. %% -- cgit v1.2.3