diff options
-rw-r--r-- | lib/observer/src/observer_lib.erl | 16 | ||||
-rw-r--r-- | lib/observer/src/observer_perf_wx.erl | 8 | ||||
-rw-r--r-- | lib/observer/src/observer_port_wx.erl | 103 | ||||
-rw-r--r-- | lib/observer/src/observer_procinfo.erl | 2 | ||||
-rw-r--r-- | lib/runtime_tools/src/observer_backend.erl | 53 |
5 files changed, 158 insertions, 24 deletions
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index 7c1337025f..59a2f9f205 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -25,7 +25,7 @@ wait_for_progress/0, report_progress/1, user_term/3, user_term_multiline/3, interval_dialog/4, start_timer/1, stop_timer/1, - display_info/2, fill_info/2, update_info/2, to_str/1, + display_info/2, display_info/3, fill_info/2, update_info/2, to_str/1, create_menus/3, create_menu_item/3, create_attrs/0, set_listctrl_col_size/2, @@ -124,6 +124,11 @@ display_info(Frame, Info) -> Panel = wxPanel:new(Frame), wxWindow:setBackgroundStyle(Panel, ?wxBG_STYLE_SYSTEM), Sizer = wxBoxSizer:new(?wxVERTICAL), + InfoFs = display_info(Panel, Sizer, Info), + wxWindow:setSizerAndFit(Panel, Sizer), + {Panel, Sizer, InfoFs}. + +display_info(Panel, Sizer, Info) -> wxSizer:addSpacer(Sizer, 5), Add = fun(BoxInfo) -> case create_box(Panel, BoxInfo) of @@ -136,9 +141,7 @@ display_info(Frame, Info) -> [] end end, - InfoFs = [Add(I) || I <- Info], - wxWindow:setSizerAndFit(Panel, Sizer), - {Panel, Sizer, InfoFs}. + [Add(I) || I <- Info]. fill_info([{dynamic, Key}|Rest], Data) when is_atom(Key); is_function(Key) -> @@ -254,6 +257,11 @@ to_str({func, {F,A}}) when is_atom(F), is_integer(A) -> lists:concat([F, "/", A]); to_str({func, {F,'_'}}) when is_atom(F) -> atom_to_list(F); +to_str({inet, Addr}) -> + case inet:ntoa(Addr) of + {error,einval} -> to_str(Addr); + AddrStr -> AddrStr + end; to_str({{format,Fun},Value}) when is_function(Fun) -> Fun(Value); to_str({A, B}) when is_atom(A), is_atom(B) -> diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl index 6a1aac92c7..b0ead42e3f 100644 --- a/lib/observer/src/observer_perf_wx.erl +++ b/lib/observer/src/observer_perf_wx.erl @@ -383,8 +383,8 @@ lmax(MState, Values, State) -> init_data(runq, {stats, _, T0, _, _}) -> {mk_max(),lists:sort(T0)}; init_data(io, {stats, _, _, {{_,In0}, {_,Out0}}, _}) -> {mk_max(), {In0,Out0}}; init_data(memory, _) -> {mk_max(), info(memory, undefined)}; -init_data(alloc, _) -> {mk_max(), ok}; -init_data(utilz, _) -> {mk_max(), ok}. +init_data(alloc, _) -> {mk_max(), unused}; +init_data(utilz, _) -> {mk_max(), unused}. info(runq, {stats, _, T0, _, _}) -> lists:seq(1, length(T0)); info(memory, _) -> [total, processes, atom, binary, code, ets]; @@ -410,11 +410,11 @@ collect_data(memory, {stats, _, _, _, MemInfo}, {Max, MemTypes}) -> collect_data(alloc, MemInfo, Max) -> Vs = [Carrier || {_Type,_Block,Carrier} <- MemInfo], Sample = list_to_tuple(Vs), - {Sample, lmax(Max, Vs, Sample)}; + {Sample, {lmax(Max, Vs, Sample),unused}}; collect_data(utilz, MemInfo, Max) -> Vs = [round(100*Block/Carrier) || {_Type,Block,Carrier} <- MemInfo], Sample = list_to_tuple(Vs), - {Sample, lmax(Max,Vs,Sample)}. + {Sample, {lmax(Max,Vs,Sample),unused}}. calc_delta([{Id, WN, TN}|Ss], [{Id, WP, TP}|Ps]) -> [100*(WN-WP) div (TN-TP)|calc_delta(Ss, Ps)]; diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl index 3b788642cc..a0617d397a 100644 --- a/lib/observer/src/observer_port_wx.erl +++ b/lib/observer/src/observer_port_wx.erl @@ -52,7 +52,13 @@ slot, id_str, links, - monitors}). + monitors, + monitored_by, + parallelism, + locking, + queue_size, + memory, + inet}). -record(opt, {sort_key=2, sort_incr=true @@ -358,7 +364,13 @@ list_to_portrec(PL) -> links = proplists:get_value(links, PL, []), name = proplists:get_value(registered_name, PL, []), monitors = proplists:get_value(monitors, PL, []), - controls = proplists:get_value(name, PL)}. + monitored_by = proplists:get_value(monitored_by, PL, []), + controls = proplists:get_value(name, PL), + parallelism = proplists:get_value(parallelism, PL), + locking = proplists:get_value(locking, PL), + queue_size = proplists:get_value(queue_size, PL, 0), + memory = proplists:get_value(memory, PL, 0), + inet = proplists:get_value(inet, PL, [])}. portrec_to_list(#port{id = Id, slot = Slot, @@ -366,14 +378,26 @@ portrec_to_list(#port{id = Id, links = Links, name = Name, monitors = Monitors, - controls = Controls}) -> + monitored_by = MonitoredBy, + controls = Controls, + parallelism = Parallelism, + locking = Locking, + queue_size = QueueSize, + memory = Memory, + inet = Inet}) -> [{id,Id}, {slot,Slot}, {connected,Connected}, {links,Links}, {name,Name}, {monitors,Monitors}, - {controls,Controls}]. + {monitored_by,MonitoredBy}, + {controls,Controls}, + {parallelism,Parallelism}, + {locking,Locking}, + {queue_size,QueueSize}, + {memory,Memory} | + Inet]. display_port_info(Parent, PortRec, Opened) -> PortIdStr = PortRec#port.id_str, @@ -391,29 +415,86 @@ do_display_port_info(Parent0, PortRec) -> Title = "Port Info: " ++ PortRec#port.id_str, Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title, [{style, ?wxSYSTEM_MENU bor ?wxCAPTION - bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}]), - + bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}, + {size,{600,400}}]), + ScrolledWin = wxScrolledWindow:new(Frame,[{style,?wxHSCROLL bor ?wxVSCROLL}]), + wxScrolledWindow:enableScrolling(ScrolledWin,true,true), + wxScrolledWindow:setScrollbars(ScrolledWin,20,20,0,0), + Sizer = wxBoxSizer:new(?wxVERTICAL), + wxWindow:setSizer(ScrolledWin,Sizer), Port = portrec_to_list(PortRec), Fields0 = port_info_fields(Port), - {_FPanel, _Sizer, _UpFields} = observer_lib:display_info(Frame, Fields0), + _UpFields = observer_lib:display_info(ScrolledWin, Sizer, Fields0), wxFrame:center(Frame), wxFrame:connect(Frame, close_window, [{skip, true}]), wxFrame:show(Frame), Frame. -port_info_fields(Port) -> + +port_info_fields(Port0) -> + {InetStruct,Port} = inet_extra_fields(Port0), Struct = [{"Overview", - [{"Name", name}, + [{"Registered Name", name}, {"Connected", {click,connected}}, {"Slot", slot}, - {"Controls", controls}]}, + {"Controls", controls}, + {"Parallelism", parallelism}, + {"Locking", locking}, + {"Queue Size", {bytes,queue_size}}, + {"Memory", {bytes,memory}}]}, {scroll_boxes, [{"Links",1,{click,links}}, - {"Monitors",1,{click,filter_monitor_info()}}]}], + {"Monitors",1,{click,filter_monitor_info()}}, + {"Monitored by",1,{click,monitored_by}}]} | InetStruct], observer_lib:fill_info(Struct, Port). +inet_extra_fields(Port) -> + Statistics = proplists:get_value(statistics,Port,[]), + Options = proplists:get_value(options,Port,[]), + Struct = + case proplists:get_value(controls,Port) of + Inet when Inet=="tcp_inet"; Inet=="udp_inet"; Inet=="sctp_inet" -> + [{"Inet", + [{"Local Address", {inet,local_address}}, + {"Local Port Number", local_port}, + {"Remote Address", {inet,remote_address}}, + {"Remote Port Number", remote_port}]}, + {"Statistics", + [stat_name_and_unit(Key) || {Key,_} <- Statistics]}, + {"Options", + [{atom_to_list(Key),Key} || {Key,_} <- Options]}]; + _ -> + [] + end, + Port1 = lists:keydelete(statistics,1,Port), + Port2 = lists:keydelete(options,1,Port1), + {Struct,Port2 ++ Statistics ++ Options}. + +stat_name_and_unit(recv_avg) -> + {"Average package size received", {bytes,recv_avg}}; +stat_name_and_unit(recv_cnt) -> + {"Number of packets received", recv_cnt}; +stat_name_and_unit(recv_dvi) -> + {"Average packet size deviation received", {bytes,recv_dvi}}; +stat_name_and_unit(recv_max) -> + {"Largest packet received", {bytes,recv_max}}; +stat_name_and_unit(recv_oct) -> + {"Total received", {bytes,recv_oct}}; +stat_name_and_unit(send_avg) -> + {"Average packet size sent", {bytes, send_avg}}; +stat_name_and_unit(send_cnt) -> + {"Number of packets sent", send_cnt}; +stat_name_and_unit(send_max) -> + {"Largest packet sent", {bytes, send_max}}; +stat_name_and_unit(send_oct) -> + {"Total sent", {bytes, send_oct}}; +stat_name_and_unit(send_pend) -> + {"Data waiting to be sent from driver", {bytes,send_pend}}; +stat_name_and_unit(Key) -> + {atom_to_list(Key), Key}. + filter_monitor_info() -> fun(Data) -> Ms = proplists:get_value(monitors, Data), diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index 620979dcc9..c13b164ff9 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -434,7 +434,7 @@ get_gc_info(Arg) -> filter_monitor_info() -> fun(Data) -> Ms = proplists:get_value(monitors, Data), - [Pid || {process, Pid} <- Ms] + [Id || {_Type, Id} <- Ms] % Type is process or port end. stringify_bins(Data) -> diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl index cedb677178..e943fb4a3e 100644 --- a/lib/runtime_tools/src/observer_backend.erl +++ b/lib/runtime_tools/src/observer_backend.erl @@ -141,14 +141,59 @@ get_mnesia_loop(Parent, {Match, Cont}) -> get_mnesia_loop(Parent, mnesia:select(Cont)). get_port_list() -> + ExtraItems = [monitors,monitored_by,parallelism,locking,queue_size,memory], [begin [{port_id,P}|erlang:port_info(P)] ++ - case erlang:port_info(P,monitors) of - undefined -> []; - Monitors -> [Monitors] - end + port_info(P,ExtraItems) ++ + inet_port_extra(erlang:port_info(P, name), P) end || P <- erlang:ports()]. +port_info(P,[Item|Items]) -> + case erlang:port_info(P,Item) of + undefined -> port_info(P,Items); + Value -> [Value|port_info(P,Items)] + end; +port_info(_,[]) -> + []. + +inet_port_extra({_,Type},Port) when Type =:= "udp_inet"; + Type =:= "tcp_inet"; + Type =:= "sctp_inet" -> + Data = + case inet:getstat(Port) of + {ok, Stats} -> [{statistics, Stats}]; + _ -> [] + end ++ + case inet:peername(Port) of + {ok, {RAddr,RPort}} when is_tuple(RAddr), is_integer(RPort) -> + [{remote_address,RAddr},{remote_port,RPort}]; + {ok, RAddr} -> + [{remote_address,RAddr}]; + {error, _} -> [] + end ++ + case inet:sockname(Port) of + {ok, {LAddr,LPort}} when is_tuple(LAddr), is_integer(LPort) -> + [{local_address,LAddr},{local_port,LPort}]; + {ok, LAddr} -> + [{local_address,LAddr}]; + {error, _} -> [] + end ++ + case inet:getopts(Port, + [active, broadcast, buffer, delay_send, + deliver, dontroute, exit_on_close, + header, high_msgq_watermark, high_watermark, + ipv6_v6only, keepalive, linger, low_msgq_watermark, + low_watermark, mode, netns, nodelay, packet, + packet_size, priority, read_packets, recbuf, + reuseaddr, send_timeout, send_timeout_close, + show_econnreset, sndbuf, tos, tclass]) of + {ok, Opts} -> [{options, Opts}]; + {error, _} -> [] + end, + [{inet,Data}]; +inet_port_extra(_,_) -> + []. + get_table_list(ets, Opts) -> HideUnread = proplists:get_value(unread_hidden, Opts, true), HideSys = proplists:get_value(sys_hidden, Opts, true), |