Skip to content

Commit

Permalink
Merge branch 'dgud/observer/perf-mon/OTP-9891' into maint
Browse files Browse the repository at this point in the history
  • Loading branch information
dgud committed Feb 28, 2012
2 parents 1ac9351 + f413a27 commit f06de64
Show file tree
Hide file tree
Showing 7 changed files with 721 additions and 57 deletions.
Binary file modified lib/observer/priv/erlang_observer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions lib/observer/src/Makefile
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ MODULES= \
observer_app_wx \ observer_app_wx \
observer_lib \ observer_lib \
observer_wx \ observer_wx \
observer_perf_wx \
observer_pro_wx \ observer_pro_wx \
observer_procinfo \ observer_procinfo \
observer_sys_wx \ observer_sys_wx \
Expand Down
147 changes: 96 additions & 51 deletions lib/observer/src/observer_app_wx.erl
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,7 @@
%% %%
%% %CopyrightBegin% %% %CopyrightBegin%
%% %%
%% Copyright Ericsson AB 2011. All Rights Reserved. %% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%% %%
%% The contents of this file are subject to the Erlang Public License, %% 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 %% Version 1.1, (the "License"); you may not use this file except in
Expand All @@ -27,6 +27,12 @@
-include_lib("wx/include/wx.hrl"). -include_lib("wx/include/wx.hrl").
-include("observer_defs.hrl"). -include("observer_defs.hrl").


%% Import drawing wrappers
-import(observer_perf_wx, [haveGC/1,
setPen/2, setFont/3, setBrush/2,
strokeLine/5, strokeLines/2, drawRoundedRectangle/6,
drawText/4, getTextExtent/2]).

-record(state, -record(state,
{ {
parent, parent,
Expand All @@ -37,7 +43,8 @@
current, current,
app, app,
sel, sel,
appmon appmon,
usegc = false
}). }).


-record(paint, {font, pen, brush, sel, links}). -record(paint, {font, pen, brush, sel, links}).
Expand All @@ -63,6 +70,8 @@
-define(ID_TRACE_TREE_PIDS, 106). -define(ID_TRACE_TREE_PIDS, 106).
-define(ID_TRACE_TREE_NAMES, 107). -define(ID_TRACE_TREE_NAMES, 107).


-define(wxGC, wxGraphicsContext).

start_link(Notebook, Parent) -> start_link(Notebook, Parent) ->
wx_object:start_link(?MODULE, [Notebook, Parent], []). wx_object:start_link(?MODULE, [Notebook, Parent], []).


Expand Down Expand Up @@ -99,22 +108,34 @@ init([Notebook, Parent]) ->
wxPanel:connect(DrawingArea, left_up), wxPanel:connect(DrawingArea, left_up),
wxPanel:connect(DrawingArea, left_dclick), wxPanel:connect(DrawingArea, left_dclick),
wxPanel:connect(DrawingArea, right_down), wxPanel:connect(DrawingArea, right_down),
case os:type() of
{win32, _} -> %% Ignore erase on windows
wxPanel:connect(DrawingArea, erase_background, [{callback, fun(_,_) -> ok end}]);
_ -> ok
end,


DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), UseGC = haveGC(DrawingArea),
Font = case os:type() of
{unix,_} when UseGC ->
wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL);
_ ->
wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT)
end,
SelCol = wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), SelCol = wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT),
GreyBrush = wxBrush:new({230,230,240}),
SelBrush = wxBrush:new(SelCol), SelBrush = wxBrush:new(SelCol),
LinkPen = wxPen:new(SelCol, [{width, 2}]), LinkPen = wxPen:new(SelCol, [{width, 2}]),
%% GC = wxGraphicsContext:create(DrawingArea), process_flag(trap_exit, true),
%% _Font = wxGraphicsContext:createFont(GC, DefFont),
{Panel, #state{parent=Parent, {Panel, #state{parent=Parent,
panel =Panel, panel =Panel,
apps_w=Apps, apps_w=Apps,
app_w =DrawingArea, app_w =DrawingArea,
paint=#paint{font= DefFont, usegc = UseGC,
pen= ?wxBLACK_PEN, paint=#paint{font = Font,
brush=?wxLIGHT_GREY_BRUSH, pen = wxPen:new({80,80,80}, [{width, 2}]),
sel= SelBrush, brush= GreyBrush,
links=LinkPen sel = SelBrush,
links= LinkPen
} }
}}. }}.


Expand Down Expand Up @@ -215,12 +236,28 @@ handle_event(Event, _State) ->


%%%%%%%%%% %%%%%%%%%%
handle_sync_event(#wx{event = #wxPaint{}},_, handle_sync_event(#wx{event = #wxPaint{}},_,
#state{app_w=DA, app=App, sel=Sel, paint=Paint}) -> #state{app_w=DA, app=App, sel=Sel, paint=Paint, usegc=UseGC}) ->
%% PaintDC must be created in a callback to work on windows. %% PaintDC must be created in a callback to work on windows.
DC = wxPaintDC:new(DA), IsWindows = element(1, os:type()) =:= win32,
wxScrolledWindow:doPrepareDC(DA,DC), %% Avoid Windows flickering hack
DC = if IsWindows -> wx:typeCast(wxBufferedPaintDC:new(DA), wxPaintDC);
true -> wxPaintDC:new(DA)
end,
IsWindows andalso wxDC:clear(DC),
GC = case UseGC of
true ->
GC0 = ?wxGC:create(DC),
%% Argh must handle scrolling when using ?wxGC
{Sx,Sy} = wxScrolledWindow:calcScrolledPosition(DA, {0,0}),
?wxGC:translate(GC0, Sx,Sy),
GC0;
false ->
wxScrolledWindow:doPrepareDC(DA,DC),
DC
end,
%% Nothing is drawn until wxPaintDC is destroyed. %% Nothing is drawn until wxPaintDC is destroyed.
draw(DC, App, Sel, Paint), draw({UseGC, GC}, App, Sel, Paint),
UseGC andalso ?wxGC:destroy(GC),
wxPaintDC:destroy(DC), wxPaintDC:destroy(DC),
ok. ok.
%%%%%%%%%% %%%%%%%%%%
Expand Down Expand Up @@ -249,26 +286,44 @@ handle_info(not_active, State = #state{appmon=AppMon, current=Prev}) ->
{noreply, State}; {noreply, State};


handle_info({delivery, Pid, app_ctrl, _, Apps0}, handle_info({delivery, Pid, app_ctrl, _, Apps0},
State = #state{appmon=Pid, apps_w=LBox}) -> State = #state{appmon=Pid, apps_w=LBox, current=Curr0}) ->
Apps = [atom_to_list(App) || {_, App, {_, _, _}} <- Apps0], Apps = [atom_to_list(App) || {_, App, {_, _, _}} <- Apps0],
wxListBox:clear(LBox), wxListBox:clear(LBox),
wxListBox:appendStrings(LBox, [App || App <- lists:sort(Apps)]), wxListBox:appendStrings(LBox, [App || App <- lists:sort(Apps)]),
{noreply, State}; case Apps of

[App|_] when Curr0 =:= undefined ->
Curr = list_to_atom(App),
appmon_info:app(Pid, Curr, true, []),
{noreply, State#state{current=Curr}};
_ ->
{noreply, State}
end;
handle_info({delivery, _Pid, app, _Curr, {[], [], [], []}}, handle_info({delivery, _Pid, app, _Curr, {[], [], [], []}},
State = #state{panel=Panel}) -> State = #state{panel=Panel}) ->
wxWindow:refresh(Panel), wxWindow:refresh(Panel),
{noreply, State#state{app=undefined, sel=undefined}}; {noreply, State#state{app=undefined, sel=undefined}};


handle_info({delivery, Pid, app, Curr, AppData}, handle_info({delivery, Pid, app, Curr, AppData},
State = #state{panel=Panel, appmon=Pid, current=Curr, State = #state{panel=Panel, appmon=Pid, current=Curr, usegc=UseGC,
app_w=AppWin, paint=#paint{font=Font}}) -> app_w=AppWin, paint=#paint{font=Font}}) ->
App = build_tree(AppData, {AppWin,Font}), GC = if UseGC -> ?wxGC:create(AppWin);
true -> wxWindowDC:new(AppWin)
end,
FontW = {UseGC, GC},
setFont(FontW, Font, {0,0,0}),
App = build_tree(AppData, FontW),
if UseGC -> ?wxGC:destroy(GC);
true -> wxWindowDC:destroy(GC)
end,
setup_scrollbar(AppWin, App), setup_scrollbar(AppWin, App),
wxWindow:refresh(Panel), wxWindow:refresh(Panel),
wxWindow:layout(Panel), wxWindow:layout(Panel),
{noreply, State#state{app=App, sel=undefined}}; {noreply, State#state{app=App, sel=undefined}};


handle_info({'EXIT', _, noconnection}, State) ->
{noreply, State};
handle_info({'EXIT', _, normal}, State) ->
{noreply, State};
handle_info(_Event, State) -> handle_info(_Event, State) ->
%% io:format("~p:~p: ~p~n",[?MODULE,?LINE,_Event]), %% io:format("~p:~p: ~p~n",[?MODULE,?LINE,_Event]),
{noreply, State}. {noreply, State}.
Expand Down Expand Up @@ -354,11 +409,11 @@ locate_box(From, []) -> {false, From}.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


build_tree({Root, P2Name, Links, XLinks0}, Font) -> build_tree({Root, P2Name, Links, XLinks0}, FontW) ->
Fam = sofs:relation_to_family(sofs:relation(Links)), Fam = sofs:relation_to_family(sofs:relation(Links)),
Name2P = gb_trees:from_orddict(lists:sort([{Name,Pid} || {Pid,Name} <- P2Name])), Name2P = gb_trees:from_orddict(lists:sort([{Name,Pid} || {Pid,Name} <- P2Name])),
Lookup = gb_trees:from_orddict(sofs:to_external(Fam)), Lookup = gb_trees:from_orddict(sofs:to_external(Fam)),
{_, Tree0} = build_tree2(Root, Lookup, Name2P, Font), {_, Tree0} = build_tree2(Root, Lookup, Name2P, FontW),
{Tree, Dim} = calc_tree_size(Tree0), {Tree, Dim} = calc_tree_size(Tree0),
Fetch = fun({From, To}, Acc) -> Fetch = fun({From, To}, Acc) ->
try {value, ToPid} = gb_trees:lookup(To, Name2P), try {value, ToPid} = gb_trees:lookup(To, Name2P),
Expand All @@ -371,18 +426,18 @@ build_tree({Root, P2Name, Links, XLinks0}, Font) ->
XLinks = lists:foldl(Fetch, [], XLinks0), XLinks = lists:foldl(Fetch, [], XLinks0),
#app{ptree=Tree, dim=Dim, links=XLinks}. #app{ptree=Tree, dim=Dim, links=XLinks}.


build_tree2(Root, Tree0, N2P, Font) -> build_tree2(Root, Tree0, N2P, FontW) ->
case gb_trees:lookup(Root, Tree0) of case gb_trees:lookup(Root, Tree0) of
none -> {Tree0, {box(Root, N2P, Font), []}}; none -> {Tree0, {box(Root, N2P, FontW), []}};
{value, Children} -> {value, Children} ->
Tree1 = gb_trees:delete(Root, Tree0), Tree1 = gb_trees:delete(Root, Tree0),
{Tree, CHs} = lists:foldr(fun("port " ++_, Acc) -> {Tree, CHs} = lists:foldr(fun("port " ++_, Acc) ->
Acc; %% Skip ports Acc; %% Skip ports
(Child,{T0, Acc}) -> (Child,{T0, Acc}) ->
{T, C} = build_tree2(Child, T0, N2P, Font), {T, C} = build_tree2(Child, T0, N2P, FontW),
{T, [C|Acc]} {T, [C|Acc]}
end, {Tree1, []}, Children), end, {Tree1, []}, Children),
{Tree, {box(Root, N2P, Font), CHs}} {Tree, {box(Root, N2P, FontW), CHs}}
end. end.


calc_tree_size(Tree) -> calc_tree_size(Tree) ->
Expand Down Expand Up @@ -427,15 +482,15 @@ middle([{#box{y=Y0},_}|List], _) ->
{#box{y=Y1},_} = lists:last(List), {#box{y=Y1},_} = lists:last(List),
(Y0+Y1) div 2. (Y0+Y1) div 2.


box(Str0, N2P, {Win,Font}) -> box(Str0, N2P, FontW) ->
Pid = gb_trees:get(Str0, N2P), Pid = gb_trees:get(Str0, N2P),
Str = if hd(Str0) =:= $< -> lists:append(io_lib:format("~w", [Pid])); Str = if hd(Str0) =:= $< -> lists:append(io_lib:format("~w", [Pid]));
true -> Str0 true -> Str0
end, end,
{TW,TH, _, _} = wxWindow:getTextExtent(Win, Str, [{theFont, Font}]), {TW,TH} = getTextExtent(FontW, Str),
Data = #str{text=Str, x=?BX_HE, y=?BY_HE, pid=Pid}, Data = #str{text=Str, x=?BX_HE, y=?BY_HE, pid=Pid},
%% Add pid %% Add pid
#box{w=TW+?BX_E, h=TH+?BY_E, s1=Data}. #box{w=round(TW)+?BX_E, h=round(TH)+?BY_E, s1=Data}.


box_to_pid(#box{s1=#str{pid=Pid}}) -> Pid. box_to_pid(#box{s1=#str{pid=Pid}}) -> Pid.
box_to_reg(#box{s1=#str{text=[$<|_], pid=Pid}}) -> Pid; box_to_reg(#box{s1=#str{text=[$<|_], pid=Pid}}) -> Pid;
Expand All @@ -453,39 +508,30 @@ draw(_DC, undefined, _, _) ->
ok; ok;
draw(DC, #app{dim={_W,_H}, ptree=Tree, links=Links}, Sel, draw(DC, #app{dim={_W,_H}, ptree=Tree, links=Links}, Sel,
#paint{font=Font, pen=Pen, brush=Brush, links=LPen, sel=SelBrush}) -> #paint{font=Font, pen=Pen, brush=Brush, links=LPen, sel=SelBrush}) ->
%% Canvas = wxGraphicsContext:create(DC), setPen(DC, LPen),
%% Pen = wxGraphicsContext:createPen(Canvas, ?wxBLACK_PEN),
%% wxGraphicsContext:setPen(Canvas, Pen),
%% Brush = wxGraphicsContext:createBrush(Canvas, ?wxLIGHT_GREY_BRUSH),
%% wxGraphicsContext:setBrush(Canvas, Brush),
%% Font = wxGraphicsContext:createFont(Canvas, wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT)),
%% wxGraphicsContext:setFont(Canvas, Font),
%% draw_tree(Tree, Canvas).
wxDC:setPen(DC, LPen),
[draw_xlink(Link, DC) || Link <- Links], [draw_xlink(Link, DC) || Link <- Links],
wxDC:setPen(DC, Pen), setPen(DC, Pen),
%% wxDC:drawRectangle(DC, {2,2}, {W-2,H-2}), %% DEBUG %% ?wxGC:drawRectangle(DC, 2,2, _W-2,_H-2), %% DEBUG
wxDC:setBrush(DC, Brush), setBrush(DC, Brush),
wxDC:setFont(DC, Font), setFont(DC, Font, {0,0,0}),
draw_tree(Tree, root, DC), draw_tree(Tree, root, DC),
case Sel of case Sel of
undefined -> ok; undefined -> ok;
{#box{x=X,y=Y,w=W,h=H,s1=Str1}, _} -> {#box{x=X,y=Y,w=W,h=H,s1=Str1}, _} ->
wxDC:setBrush(DC, SelBrush), setBrush(DC, SelBrush),
wxDC:drawRoundedRectangle(DC, {X-1,Y-1}, {W+2,H+2}, 8.0), drawRoundedRectangle(DC, X-1,Y-1, W+2,H+2, 8.0),
draw_str(DC, Str1, X, Y) draw_str(DC, Str1, X, Y)
end. end.


draw_tree({Box=#box{x=X,y=Y,w=W,h=H,s1=Str1}, Chs}, Parent, DC) -> draw_tree({Box=#box{x=X,y=Y,w=W,h=H,s1=Str1}, Chs}, Parent, DC) ->
%%wxGraphicsContext:drawRoundedRectangle(DC, float(X), float(Y), float(W), float(H), 8.0), drawRoundedRectangle(DC, X,Y, W,H, 8.0),
wxDC:drawRoundedRectangle(DC, {X,Y}, {W,H}, 8.0),
draw_str(DC, Str1, X, Y), draw_str(DC, Str1, X, Y),
Dot = case Chs of Dot = case Chs of
[] -> ok; [] -> ok;
[{#box{x=CX0},_}|_] -> [{#box{x=CX0},_}|_] ->
CY = Y+(H div 2), CY = Y+(H div 2),
CX = CX0-(?BB_X div 2), CX = CX0-(?BB_X div 2),
wxDC:drawLine(DC, {X+W, CY}, {CX, CY}), strokeLine(DC, X+W, CY, CX, CY),
{CX, CY} {CX, CY}
end, end,
draw_link(Parent, Box, DC), draw_link(Parent, Box, DC),
Expand All @@ -495,9 +541,9 @@ draw_link({CX,CY}, #box{x=X,y=Y0,h=H}, DC) ->
Y = Y0+(H div 2), Y = Y0+(H div 2),
case Y =:= CY of case Y =:= CY of
true -> true ->
wxDC:drawLine(DC, {CX, CY}, {X, CY}); strokeLine(DC, CX, CY, X, CY);
false -> false ->
wxDC:drawLines(DC, [{CX, CY}, {CX, Y}, {X,Y}]) strokeLines(DC, [{CX, CY}, {CX, Y}, {X,Y}])
end; end;
draw_link(_, _, _) -> ok. draw_link(_, _, _) -> ok.


Expand All @@ -516,9 +562,8 @@ draw_xlink(X0, Y00, X1, Y11, BH, DC) ->
{Y0,Y1} = if Y00 < Y11 -> {Y00+BH-6, Y11+6}; {Y0,Y1} = if Y00 < Y11 -> {Y00+BH-6, Y11+6};
true -> {Y00+6, Y11+BH-6} true -> {Y00+6, Y11+BH-6}
end, end,
wxDC:drawLines(DC, [{X0,Y0}, {X0+5,Y0}, {X1-5,Y1}, {X1,Y1}]). strokeLines(DC, [{X0,Y0}, {X0+5,Y0}, {X1-5,Y1}, {X1,Y1}]).


draw_str(DC, #str{x=Sx,y=Sy, text=Text}, X, Y) -> draw_str(DC, #str{x=Sx,y=Sy, text=Text}, X, Y) ->
%%wxGraphicsContext:drawText(DC, Text, float(Sx+X), float(Sy+Y)); drawText(DC, Text, X+Sx,Y+Sy);
wxDC:drawText(DC, Text, {X+Sx,Y+Sy});
draw_str(_, _, _, _) -> ok. draw_str(_, _, _, _) -> ok.
2 changes: 2 additions & 0 deletions lib/observer/src/observer_lib.erl
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ to_str(Value) when is_atom(Value) ->
to_str({bytes, B}) -> to_str({bytes, B}) ->
KB = B div 1024, KB = B div 1024,
MB = KB div 1024, MB = KB div 1024,
GB = MB div 1024,
if if
GB > 10 -> integer_to_list(GB) ++ " gB";
MB > 10 -> integer_to_list(MB) ++ " mB"; MB > 10 -> integer_to_list(MB) ++ " mB";
KB > 0 -> integer_to_list(KB) ++ " kB"; KB > 0 -> integer_to_list(KB) ++ " kB";
true -> integer_to_list(B) ++ " B " true -> integer_to_list(B) ++ " B "
Expand Down
Loading

0 comments on commit f06de64

Please sign in to comment.