diff options
Diffstat (limited to 'lib/observer/src')
-rw-r--r-- | lib/observer/src/Makefile | 4 | ||||
-rw-r--r-- | lib/observer/src/etop.erl | 5 | ||||
-rw-r--r-- | lib/observer/src/etop_defs.hrl | 6 | ||||
-rw-r--r-- | lib/observer/src/etop_gui.erl | 374 | ||||
-rw-r--r-- | lib/observer/src/etop_txt.erl | 13 | ||||
-rw-r--r-- | lib/observer/src/observer.app.src | 3 |
6 files changed, 17 insertions, 388 deletions
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile index 42f5c19935..646892663f 100644 --- a/lib/observer/src/Makefile +++ b/lib/observer/src/Makefile @@ -38,7 +38,6 @@ MODULES= \ crashdump_viewer \ crashdump_viewer_html \ etop \ - etop_gui \ etop_tr \ etop_txt \ observer \ @@ -72,13 +71,12 @@ PRIVDIR= ../priv WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool $(PRIVDIR)/erlang_observer.png BINDIR= $(PRIVDIR)/bin ifeq ($(findstring win32,$(TARGET)),win32) -WIN32_EXECUTABLES= $(BINDIR)/etop.bat $(BINDIR)/getop.bat $(BINDIR)/cdv.bat +WIN32_EXECUTABLES= $(BINDIR)/etop.bat $(BINDIR)/cdv.bat else WIN32_EXECUTABLES= endif EXECUTABLES= \ $(BINDIR)/etop \ - $(BINDIR)/getop \ $(BINDIR)/cdv \ $(WIN32_EXECUTABLES) CDVDIR= $(PRIVDIR)/crashdump_viewer diff --git a/lib/observer/src/etop.erl b/lib/observer/src/etop.erl index 2610060eae..96a18cf450 100644 --- a/lib/observer/src/etop.erl +++ b/lib/observer/src/etop.erl @@ -44,9 +44,6 @@ help() -> " sort runtime | reductions | memory | msg_q~n" " What information to sort by~n" " Default: runtime (reductions if tracing=off)~n" - " output graphical | text~n" - " How to present results~n" - " Default: graphical~n" " tracing on | off etop uses the erlang trace facility, and thus~n" " no other tracing is possible on the node while~n" " etop is running, unless this option is set to~n" @@ -317,7 +314,7 @@ handle_args([_| R], C) -> handle_args([], C) -> C. -output(graphical) -> etop_gui; +output(graphical) -> exit({deprecated, "Use observer instead"}); output(text) -> etop_txt. diff --git a/lib/observer/src/etop_defs.hrl b/lib/observer/src/etop_defs.hrl index 664de61973..720fb50b5a 100644 --- a/lib/observer/src/etop_defs.hrl +++ b/lib/observer/src/etop_defs.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% Copyright Ericsson AB 2002-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 @@ -22,8 +22,8 @@ " procs~8w processes~8w code ~8w~n" " runq ~8w atom ~8w ets ~8w~n"). --record(opts, {node=node(), port = 8415, accum = false, intv = 5000, lines = 10, +-record(opts, {node=node(), port = 8415, accum = false, intv = 5000, lines = 10, width = 700, height = 340, sort = runtime, tracing = on, %% Other state information - out_mod=etop_gui, out_proc, server, host, tracer, store, + out_mod=etop_txt, out_proc, server, host, tracer, store, accum_tab, remote}). diff --git a/lib/observer/src/etop_gui.erl b/lib/observer/src/etop_gui.erl deleted file mode 100644 index 3971646abc..0000000000 --- a/lib/observer/src/etop_gui.erl +++ /dev/null @@ -1,374 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-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 -%% 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 online 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. -%% -%% %CopyrightEnd% -%% --module(etop_gui). --compile([{nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,create,3}}, - {nowarn_deprecated_function,{gs,create,4}}, - {nowarn_deprecated_function,{gs,destroy,1}}, - {nowarn_deprecated_function,{gs,read,2}}, - {nowarn_deprecated_function,{gs,start,0}}]). - --author('[email protected]'). - --export([init/1,stop/1]). --export([formatmfa/1,to_list/1]).% For etop_txt - --include("etop.hrl"). --include("etop_defs.hrl"). - --import(etop, [loadinfo/1, meminfo/2, getopt/2]). - -%% Heights --define(BarH, 28). % height of menubar --define(LabelH, 90). % height of label with system info --define(GridLineH, 21). % height of one line in the table (grid) - -%% Column numbers for grid - click to sort --define(TimeCol, 3). --define(RedsCol, 4). --define(MemCol, 5). --define(MsgQCol, 6). - -%% Font --define(Normal, {screen,12}). --define(Bold, {screen,bold,12}). - - -%% ----------------------------------------------------------------------------- -stop(_) -> ok. - -init(Config) -> - S = gs:start(), - Width = getopt(width, Config), - TotLines = getopt(lines,Config)+1, - - %% Max number of processes shown in window at startup is 10 - %% If less than 10 lines is specified, window size fits number of lines - WinH = if TotLines > 11 -> 11*?GridLineH + ?BarH + ?LabelH; - true -> TotLines*?GridLineH + ?BarH + ?LabelH - end, - Win = gs:create(window, S, - [{title, "Erlang Top"}, - {map, true}, %% While debugging - {configure, true}, - {width, Width}, {height, WinH}]), - Bar = gs:create(menubar, Win, []), - - FileButt = gs:create(menubutton, Bar, [{label,{text, " File "}}]), - OptionsButt = gs:create(menubutton, Bar, [{label,{text, " Options "}}]), - File = gs:create(menu, FileButt, []), - Options = gs:create(menu, OptionsButt, []), - gse:named_menuitem(refresh, File, - [{label,{text," Refresh "}}]), - gse:named_menuitem(dump, File, - [{label,{text," Dump to file "}}]), - gse:named_menuitem(exit, File, - [{label,{text," Exit "}}]), - - gse:named_menuitem(accum, Options, - [{label,{text, " Accumulate "}}, - {itemtype, check}]), - gse:named_menuitem(intv, Options, - [{label,{text, " Update Interval "}}]), - gse:named_menuitem(lines, Options, - [{label,{text, " Number of Lines "}}]), - Sort = gse:named_menuitem(sort, Options, - [{label,{text, " Sort "}}, - {itemtype,cascade}]), - SortMenu = gse:create(menu, Sort, []), - gse:named_menuitem(runtime, SortMenu, - [{label,{text, " Time "}}, - {itemtype,radio},{group,gr1}]), - gse:named_menuitem(memory, SortMenu, - [{label,{text, " Memory "}}, - {itemtype,radio},{group,gr1}]), - gse:named_menuitem(reductions, SortMenu, - [{label,{text, " Reductions "}}, - {itemtype,radio},{group,gr1}]), - gse:named_menuitem(msg_q, SortMenu, - [{label,{text, " Message Queue "}}, - {itemtype,radio},{group,gr1}]), - - SysInfo = gs:create(label,Win,[{x, 0}, {y, ?BarH},{align,sw}, - {width, Width},{height,?LabelH}]), - - {GridH,VScroll} = calc_grid_h(WinH,TotLines), - Grid = gse:grid(Win, - [{x, 0}, {y, ?BarH+?LabelH}, - {width, Width}, - {height, GridH}, - {hscroll, false}, - {vscroll, VScroll}, - {columnwidths, calc_column_w(Width)}, - {rows, {1, TotLines}}, - {font,?Normal}]), - - %% Header line - GL1 = gse:gridline(Grid, [{{text, 1}, "PID"}, - {{text, 2}, "Name or Initial Function"}, - {{text, ?TimeCol}, "Time(us)"}, - {{text, ?RedsCol}, "Reds"}, - {{text, ?MemCol}, "Memory"}, - {{text, ?MsgQCol}, "MsgQ"}, - {{text, 7}, "Current Function"}, - {bg, lightblue}, - {row, 1}, - {click, true}]), - - config_sort(GL1,getopt(sort,Config)), - Info = do_update(Grid, SysInfo, Config), - - get_event(Info, Win, Grid, GL1, SysInfo, Config). - -calc_column_w(W) -> - %% W = [2x, 3x, 1x, 1x, 1x, 1x, 3x] = 12x - RW = W-9, % just to make nice small margins on each side of grid - X = RW div 12, - [2*X, 3*X, X, X, X, X, 3*X + (RW - 12*X)]. - -config_sort(GL1,Sort) -> - gs:config(Sort,[{select,true}]), - lists:foreach(fun(S) -> - gs:config(GL1,[{{font,S},?Normal}]) - end, - [?TimeCol,?MemCol,?RedsCol,?MsgQCol]), - case Sort of - runtime -> gs:config(GL1,{{font,?TimeCol},?Bold}); - memory -> gs:config(GL1,{{font,?MemCol},?Bold}); - reductions -> gs:config(GL1,{{font,?RedsCol},?Bold}); - msg_q -> gs:config(GL1,{{font,?MsgQCol},?Bold}) - end. - -config_lines(Win,Grid,TotLines) -> - OldGridH = gs:read(Grid,height), - NewLinesH = TotLines*?GridLineH, - if NewLinesH =< OldGridH -> - gs:config(Win,[{height,NewLinesH+?BarH+?LabelH}]), - gs:config(Grid,[{rows,{1,TotLines}}, - {height,NewLinesH}, - {vscroll,false}]); - true -> - gs:config(Grid,[{rows,{1,TotLines}},{vscroll,right}]) - end. - -calc_grid_h(WinH,TotLines) -> - LeftInWin = WinH - ?BarH - ?LabelH, - TotGrid = TotLines * ?GridLineH, - if LeftInWin >= TotGrid -> - {TotGrid,false}; - true -> - {LeftInWin,right} - end. - -set_win_h(Win,OrigH,TotLines) -> - TotH = TotLines*?GridLineH + ?BarH + ?LabelH, - if TotH >= OrigH -> OrigH; - true -> gs:config(Win,[{height,TotH}]), - TotH - end. - -get_event(Info, Win, Grid, GL1, SysInfo, Config) -> - receive - {gs, Win, configure,[],[W,H,_,_]} -> - TotLines = getopt(lines,Config)+1, - %% Will not make window higher than total number of lines - RealWinH = set_win_h(Win,H,TotLines), - {GridH,VScroll} = calc_grid_h(RealWinH,TotLines), - gs:config(Grid, [{width, W}, - {columnwidths, calc_column_w(W)}, - {height,GridH}, {vscroll,VScroll}]), - get_event(Info, Win, Grid, GL1, SysInfo, Config); - {gs, refresh, _, _, _} -> - Info1 = do_update(Grid, SysInfo, Config), - get_event(Info1, Win, Grid, GL1, SysInfo, Config); - {gs, dump, _, _, _} -> - case pop(Win,dump) of - {ok,File} -> etop:dump(File); - {error,cancel} -> ok - end, - get_event(Info, Win, Grid, GL1, SysInfo, Config); - {gs, Win, destroy, _, _} -> - normal; - {gs, exit, _, _, _} -> - ok; - {gs, accum, _, _, _} -> - Old = getopt(accum,Config), - etop:config(accumulate,not Old), - get_event(Info, Win, Grid, GL1, SysInfo, Config); - {gs,intv,_,_,_} -> - case pop(Win,interval) of - {ok,Intv} -> etop:config(interval,list_to_integer(Intv)); - {error,cancel} -> ok - end, - get_event(Info, Win, Grid, GL1, SysInfo, Config); - {gs,lines,_,_,_} -> - case pop(Win,lines) of - {ok,Lines} -> etop:config(lines,list_to_integer(Lines)); - {error,cancel} -> ok - end, - get_event(Info, Win, Grid, GL1, SysInfo, Config); - {gs,Sort,_,_,_} when Sort=:=runtime; - Sort=:=memory; - Sort=:=reductions; - Sort=:=msg_q -> - etop:config(sort,Sort), - get_event(Info, Win, Grid, GL1, SysInfo, Config); - {gs,GL1,click,_,[Col,1,_]} -> - case Col of - ?TimeCol -> etop:config(sort, runtime); - ?MemCol -> etop:config(sort, memory); - ?RedsCol -> etop:config(sort, reductions); - ?MsgQCol -> etop:config(sort, msg_q); - _other -> ignore - end, - get_event(Info, Win, Grid, GL1, SysInfo, Config); - {config,{Key,Value},Config1} -> - case Key of - lines -> config_lines(Win,Grid,Value+1); - sort -> config_sort(GL1,Value); - accumulate -> gs:config(accum,[{select,Value}]); - _ -> ok - end, - Info1 = do_update(Grid, SysInfo, Config1), - get_event(Info1, Win, Grid, GL1, SysInfo, Config1); - {dump,Fd} -> - etop_txt:do_update(Fd,Info,Config), - get_event(Info, Win, Grid, GL1, SysInfo, Config); - Msg -> - io:format("~p got unexpected msg ~p~n", [?MODULE, Msg]), - get_event(Info, Win, Grid, GL1, SysInfo, Config) - after getopt(intv,Config) -> - Info1 = do_update(Grid, SysInfo, Config), - get_event(Info1, Win, Grid, GL1, SysInfo, Config) - end. - -do_update(Grid, SysInfo, Config) -> - Info = etop:update(Config), - Lines = makegridlines(Info#etop_info.procinfo, Grid, 2), - clear_lines(Lines, getopt(lines,Config) + 1, Grid), - makesysinfo(getopt(node,Config),Info,SysInfo), - Info. - -%clear_lines(From, To, _Grid) when From > To -> ok; -clear_lines(From, To, Grid) -> - case gs:read(Grid, {obj_at_row, From}) of - undefined -> - ok; - GridLine -> - gs:destroy(GridLine), - clear_lines(From + 1, To, Grid) - end. - -formatmfa({M, F, A}) -> - io_lib:format("~w:~w/~w",[M, F, A]); -formatmfa(Other) -> - %% E.g. when running hipe - the current_function for some - %% processes will be 'undefined' - io_lib:format("~w",[Other]). - - -makegridlines([#etop_proc_info{pid=Pid, - mem=Mem, - reds=Reds, - name=Name, - runtime=Time, - cf=MFA, - mq=MQ} - |T], Grid, Count) -> - update_gl(Grid, Count, [{{text, 1}, pid_to_list(Pid)}, - {{text, 2}, to_list(Name)}, - {{text, ?TimeCol}, - if is_integer(Time)->integer_to_list(Time); - true -> Time - end}, - {{text, ?RedsCol}, integer_to_list(Reds)}, - {{text, ?MemCol}, integer_to_list(Mem)}, - {{text, ?MsgQCol}, integer_to_list(MQ)}, - {{text, 7}, formatmfa(MFA)}, - {row, Count}, {click, false}]), - makegridlines(T, Grid, Count + 1); -makegridlines([],_Grid,Count) -> - Count. - -update_gl(Grid, Row, GL) -> - case gs:read(Grid, {obj_at_row, Row}) of - undefined -> - gse:gridline(Grid,[{row, Row}|GL]); - GridLine -> - gs:config(GridLine,GL) - end. - -to_list(Name) when is_atom(Name) -> atom_to_list(Name); -to_list({_M,_F,_A}=MFA) -> formatmfa(MFA). - - -makesysinfo(Node,Info,SysInfo) -> - {Cpu,NProcs,RQ,Clock} = loadinfo(Info), - case Info#etop_info.memi of - undefined -> - Str = "No memory information is available."; - Memi -> - [Tot,Procs,Atom,Bin,Code,Ets] = - meminfo(Memi, [total,processes,atom,binary,code,ets]), - Str = io_lib:fwrite(?SYSFORM, - [Node,Clock, - Cpu,Tot,Bin, - NProcs,Procs,Code, - RQ,Atom,Ets]) - end, - gs:config(SysInfo,[{label,{text,Str}},{font,?Normal}]). - - -pop(Win,Key) -> - Pop = gs:create(window,Win,[{title,"Config"}, - {width,160},{height,100}]), - gs:create(label,Pop,[{label,{text,txt(Key)}}, - {width,160}]), - gs:create(entry,entry,Pop,[{x,10},{y,30},{width,130}, - {keypress,true}]), - gs:create(button,ok,Pop,[{width,45},{y,60},{x,10}, - {label,{text,"Ok"}}]), - gs:create(button,cancel,Pop,[{width,60},{y,60},{x,80}, - {label,{text,"Cancel"}}]), - gs:config(Pop,{map,true}), - pop_loop(Pop). - -pop_loop(Pop) -> - receive - {gs,entry,keypress,_,['Return'|_]} -> - Str = gs:read(entry,text), - gs:destroy(Pop), - {ok,Str}; - {gs,entry,keypress,_,_} -> % all other keypresses - pop_loop(Pop); - {gs,ok,click,_,_} -> - Str = gs:read(entry,text), - gs:destroy(Pop), - {ok,Str}; - {gs,cancel,click,_,_} -> - gs:destroy(Pop), - {error,cancel}; - X -> - io:format("Got X=~w~n",[X]), - pop_loop(Pop) - end. - -txt(interval) -> "Enter new interval:"; -txt(lines) -> "Enter number of lines:"; -txt(dump) -> "Enter file name:". diff --git a/lib/observer/src/etop_txt.erl b/lib/observer/src/etop_txt.erl index d0612f15b4..f048ff17ca 100644 --- a/lib/observer/src/etop_txt.erl +++ b/lib/observer/src/etop_txt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% Copyright Ericsson AB 2002-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 @@ -27,7 +27,6 @@ -include("etop_defs.hrl"). -import(etop,[loadinfo/1,meminfo/2]). --import(etop_gui,[formatmfa/1,to_list/1]). -define(PROCFORM,"~-15w~-20s~8w~8w~8w~8w ~-20s~n"). @@ -99,3 +98,13 @@ writepinfo(Fd,[#etop_proc_info{pid=Pid, writepinfo(_Fd,[]) -> ok. + +formatmfa({M, F, A}) -> + io_lib:format("~w:~w/~w",[M, F, A]); +formatmfa(Other) -> + %% E.g. when running hipe - the current_function for some + %% processes will be 'undefined' + io_lib:format("~w",[Other]). + +to_list(Name) when is_atom(Name) -> atom_to_list(Name); +to_list({_M,_F,_A}=MFA) -> formatmfa(MFA). diff --git a/lib/observer/src/observer.app.src b/lib/observer/src/observer.app.src index e881cb3c97..6d5259624c 100644 --- a/lib/observer/src/observer.app.src +++ b/lib/observer/src/observer.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2012. All Rights Reserved. +%% Copyright Ericsson AB 2002-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 @@ -22,7 +22,6 @@ {modules, [crashdump_viewer, crashdump_viewer_html, etop, - etop_gui, etop_tr, etop_txt, observer, |