%%% @author zhongwen -module(observer_cli_ets). -include("observer_cli.hrl"). %% API -export([start/1]). -export([clean/1]). -define(LAST_LINE, "q(quit) s(sort by size) m(sort by memory) pd/pu(page:down/up) F/B(forward/back)" ). -spec start(ViewOpts) -> no_return() when ViewOpts :: view_opts(). start( #view_opts{ ets = #ets{interval = Interval, attr = Attr, cur_page = CurPage}, auto_row = AutoRow } = ViewOpts ) -> Pid = spawn_link(fun() -> ?output(?CLEAR), render_worker(Interval, ?INIT_TIME_REF, Attr, CurPage, AutoRow) end), manager(Pid, ViewOpts). -spec clean(list()) -> ok. clean(Pids) -> observer_cli_lib:exit_processes(Pids). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Private %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% manager(ChildPid, #view_opts{ets = EtsOpts = #ets{cur_page = CurPage}} = ViewOpts) -> case observer_cli_lib:parse_cmd(ViewOpts, ?MODULE, [ChildPid]) of quit -> erlang:send(ChildPid, quit); {new_interval, NewMs} -> clean([ChildPid]), start(ViewOpts#view_opts{ets = EtsOpts#ets{interval = NewMs}}); size -> clean([ChildPid]), start(ViewOpts#view_opts{ets = EtsOpts#ets{attr = size}}); %% Home {func, proc_count, memory} -> clean([ChildPid]), start(ViewOpts#view_opts{ets = EtsOpts#ets{attr = memory}}); page_down_top_n -> NewPage = max(CurPage + 1, 1), clean([ChildPid]), start(ViewOpts#view_opts{ets = EtsOpts#ets{cur_page = NewPage}}); page_up_top_n -> NewPage = max(CurPage - 1, 1), clean([ChildPid]), start(ViewOpts#view_opts{ets = EtsOpts#ets{cur_page = NewPage}}); _ -> manager(ChildPid, ViewOpts) end. render_worker(Interval, LastTimeRef, Attr, CurPage, AutoRow) -> TerminalRow = observer_cli_lib:get_terminal_rows(AutoRow), Text = "Interval: " ++ integer_to_list(Interval) ++ "ms", Menu = observer_cli_lib:render_menu(ets, Text), Ets = render_ets_info(erlang:max(0, TerminalRow - 4), CurPage, Attr), LastLine = observer_cli_lib:render_last_line(?LAST_LINE), ?output([?CURSOR_TOP, Menu, Ets, LastLine]), NextTimeRef = observer_cli_lib:next_redraw(LastTimeRef, Interval), receive quit -> quit; _ -> render_worker(Interval, NextTimeRef, Attr, CurPage, AutoRow) end. render_ets_info(Rows, CurPage, Attr) -> AllEts = [ begin get_ets_info(Tab, Attr) end || Tab <- ets:all() ], WordSize = erlang:system_info(wordsize), {_StartPos, SortEts} = observer_cli_lib:sublist(AllEts, Rows, CurPage), {MemColor, SizeColor} = case Attr of memory -> {?RED_BG, ?GRAY_BG}; _ -> {?GRAY_BG, ?RED_BG} end, Title = ?render([ ?UNDERLINE, ?W2(?GRAY_BG, "Table Name", 37), ?UNDERLINE, ?W2(SizeColor, "Size", 14), ?UNDERLINE, ?W2(MemColor, " Memory ", 14), ?UNDERLINE, ?W2(?GRAY_BG, "Type", 15), ?UNDERLINE, ?W2(?GRAY_BG, "Protection", 12), ?UNDERLINE, ?W2(?GRAY_BG, "KeyPos", 8), ?UNDERLINE, ?W2(?GRAY_BG, "Write/Read", 14), ?UNDERLINE, ?W2(?GRAY_BG, "Owner Pid", 15) ]), RowView = [ begin Name = proplists:get_value(name, Ets), Memory = proplists:get_value(memory, Ets), Size = proplists:get_value(size, Ets), Type = proplists:get_value(type, Ets), Protect = proplists:get_value(protection, Ets), KeyPos = proplists:get_value(keypos, Ets), Write = observer_cli_lib:to_list(proplists:get_value(write_concurrency, Ets)), Read = observer_cli_lib:to_list(proplists:get_value(read_concurrency, Ets)), Owner = proplists:get_value(owner, Ets), ?render([ ?W(Name, 36), ?W(Size, 12), ?W({byte, Memory * WordSize}, 12), ?W(Type, 13), ?W(Protect, 10), ?W(KeyPos, 6), ?W(Write ++ "/" ++ Read, 12), ?W(Owner, 14) ]) end || {_, _, Ets} <- SortEts ], [Title | RowView]. get_ets_info(Tab, Attr) -> case catch ets:info(Tab) of {'EXIT', _} -> unread(); undefined -> unread(); Info when is_list(Info) -> Owner = proplists:get_value(owner, Info), NewInfo = case is_reg(Owner) of Owner -> Info; Reg -> lists:keyreplace(Owner, 1, Info, {owner, Reg}) end, { 0, proplists:get_value(Attr, NewInfo), NewInfo } end. is_reg(Owner) -> case process_info(Owner, registered_name) of {registered_name, Name} -> Name; _ -> Owner end. unread() -> { 0, 0, [ %%it maybe die {name, unread}, {write_concurrency, unread}, {read_concurrency, unread}, {compressed, unread}, {memory, unread}, {owner, unread}, {heir, unread}, {size, unread}, {node, unread}, {named_table, unread}, {type, unread}, {keypos, unread}, {protection, unread} ] }.