diff options
author | Dan Gudmundsson <[email protected]> | 2013-10-22 13:37:03 +0200 |
---|---|---|
committer | Dan Gudmundsson <[email protected]> | 2014-01-27 16:13:57 +0100 |
commit | bfae535d4ac51d2c3bef146e0f058e105bb5e956 (patch) | |
tree | eaafe6c61f5fca58ca05b232f280e911f04dcdb7 /lib/observer/src/observer_tv_table.erl | |
parent | 41380c0ff6c4fb56aad5702b9d9554ae36580063 (diff) | |
download | otp-bfae535d4ac51d2c3bef146e0f058e105bb5e956.tar.gz otp-bfae535d4ac51d2c3bef146e0f058e105bb5e956.tar.bz2 otp-bfae535d4ac51d2c3bef146e0f058e105bb5e956.zip |
observer: Optimize row lookups
Use arrays instead of lists to cache data, gives faster lookups for
large contents.
Also update colors used in table viewer, indication new and changed rows.
Other minor bugfixes in tables viewer.
Diffstat (limited to 'lib/observer/src/observer_tv_table.erl')
-rw-r--r-- | lib/observer/src/observer_tv_table.erl | 123 |
1 files changed, 69 insertions, 54 deletions
diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl index b4832d9599..59fe5b5670 100644 --- a/lib/observer/src/observer_tv_table.erl +++ b/lib/observer/src/observer_tv_table.erl @@ -98,7 +98,7 @@ init([Parent, Opts]) -> ets -> "TV Ets: " ++ Title0; mnesia -> "TV Mnesia: " ++ Title0 end, - Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {800, 300}}]), + Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {800, 600}}]), IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), wxFrame:setIcon(Frame, Icon), @@ -261,11 +261,12 @@ handle_event(#wx{id=?ID_EDIT}, State = #state{selected=Index}) -> handle_event(#wx{id=?ID_DELETE}, State = #state{selected=undefined}) -> {noreply, State}; handle_event(#wx{id=?ID_DELETE}, - State = #state{pid=Pid, status=StatusBar, selected=Index}) -> + State = #state{grid=Grid, pid=Pid, status=StatusBar, selected=Index}) -> Str = get_row(Pid, Index, all), Pid ! {delete, Index}, wxStatusBar:setStatusText(StatusBar, io_lib:format("Deleted object: ~s",[Str])), - {noreply, State}; + wxListCtrl:setItemState(Grid, Index, 0, ?wxLIST_STATE_FOCUSED), + {noreply, State#state{selected=undefined}}; handle_event(#wx{id=?wxID_CLOSE}, State = #state{frame=Frame}) -> wxFrame:destroy(Frame), @@ -279,8 +280,8 @@ handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}}, State = #state{grid=Grid}) -> try Row0 = list_to_integer(Str), - Row1 = min(0, Row0), - Row = max(wxListCtrl:getItemCount(Grid)-1,Row1), + Row1 = max(0, Row0), + Row = min(wxListCtrl:getItemCount(Grid)-1,Row1), wxListCtrl:ensureVisible(Grid, Row), ok catch _:_ -> ok @@ -289,7 +290,9 @@ handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}}, %% Search functionality handle_event(#wx{id=?ID_SEARCH}, - State = #state{sizer=Sz, search=Search}) -> + State = #state{grid=Grid, sizer=Sz, search=Search, selected=Index}) -> + is_integer(Index) andalso + wxListCtrl:setItemState(Grid, Index, 0, ?wxLIST_STATE_FOCUSED), wxSizer:show(Sz, Search#search.win), wxWindow:setFocus(Search#search.search), wxSizer:layout(Sz), @@ -321,7 +324,7 @@ handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{type=command_text_enter,cmdS Pid ! {mark_search_hit, false}, case search(Pid, Str, Pos, Dir, Case) of false -> - wxStatusBar:setStatusText(SB, "Not found"), + wxStatusBar:setStatusText(SB, io_lib:format("Not found (regexp): ~s",[Str])), Pid ! {mark_search_hit, Find#find.start}, wxListCtrl:refreshItem(Grid, Find#find.start), {noreply, State#state{search=Search#search{find=Find#find{found=false}}}}; @@ -355,7 +358,7 @@ handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{cmdString=Str}}, Pid ! {mark_search_hit, false}, case search(Pid, Str, Cont#find.start, Dir, Case) of false -> - wxStatusBar:setStatusText(SB, "Not found"), + wxStatusBar:setStatusText(SB, io_lib:format("Not found (regexp): ~s",[Str])), {noreply, State}; Row -> wxListCtrl:ensureVisible(Grid, Row), @@ -402,8 +405,11 @@ handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) -> Cols = add_columns(Grid, Cols0, New), {noreply, State#state{columns=Cols}}; +handle_info({refresh, Min, Min}, State = #state{grid=Grid}) -> + wxListCtrl:refreshItem(Grid, Min), %% Avoid assert in wx below if Max is 0 + {noreply, State}; handle_info({refresh, Min, Max}, State = #state{grid=Grid}) -> - Max > 0 andalso wxListCtrl:refreshItems(Grid, Min, Max), + wxListCtrl:refreshItems(Grid, Min, Max), {noreply, State}; handle_info(refresh_interval, State = #state{pid=Pid}) -> @@ -426,10 +432,14 @@ handle_info(_Event, State) -> terminate(_Event, #state{pid=Pid, attrs=Attrs}) -> %% ListItemAttr are not auto deleted - #attrs{odd=Odd, deleted=D, changed=Ch, searched=S} = Attrs, - wxListItemAttr:destroy(Odd), + #attrs{odd=Odd, even=Even, deleted=D, searched=S, + changed_odd=Ch1, changed_even=Ch2, + new_odd=New1, new_even=New2 + } = Attrs, + wxListItemAttr:destroy(Odd), wxListItemAttr:destroy(Even), wxListItemAttr:destroy(D), - wxListItemAttr:destroy(Ch), + wxListItemAttr:destroy(Ch1),wxListItemAttr:destroy(Ch2), + wxListItemAttr:destroy(New1),wxListItemAttr:destroy(New2), wxListItemAttr:destroy(S), unlink(Pid), exit(Pid, window_closed), @@ -473,7 +483,7 @@ search(Table, Str, Row, Dir, Case) -> end. -record(holder, {node, parent, pid, - table=[], n=0, columns, + table=array:new(), n=0, columns, temp=[], search, source, tabid, @@ -507,6 +517,7 @@ table_holder(S0 = #holder{parent=Parent, pid=Pid, table=Table}) -> S1 = handle_new_data_chunk(Data, S0), table_holder(S1); {sort, Col} -> + Parent ! {refresh, 0, S0#holder.n-1}, table_holder(sort(Col, S0)); {search, Data} -> table_holder(search(Data, S0)); @@ -530,11 +541,14 @@ table_holder(S0 = #holder{parent=Parent, pid=Pid, table=Table}) -> table_holder(S0); What -> io:format("Table holder got ~p~n",[What]), + Parent ! {refresh, 0, S0#holder.n-1}, table_holder(S0) end. handle_new_data_chunk(Data, S0 = #holder{columns=Cols, parent=Parent}) -> - S1 = #holder{columns=NewCols} = handle_new_data_chunk2(Data, S0), + S1 = #holder{n=N,columns=NewCols} = handle_new_data_chunk2(Data, S0), + Parent ! {no_rows, N}, + Parent ! {refresh, 0, N-1}, case NewCols =:= Cols of true -> S1; false -> @@ -543,15 +557,12 @@ handle_new_data_chunk(Data, S0 = #holder{columns=Cols, parent=Parent}) -> end. handle_new_data_chunk2('$end_of_table', - S0 = #holder{parent=Parent, sort=Opt, - key=Key, + S0 = #holder{sort=Opt0, key=Key, table=Old, temp=New}) -> - Table = merge(Old, New, Key), - N = length(Table), - Parent ! {no_rows, N}, - sort(Opt#opt.sort_key, S0#holder{n=N, pid=undefine, - sort=Opt#opt{sort_key = undefined}, - table=Table, temp=[]}); + Merged = merge(array:to_list(Old), New, Key), + {Opt,Sorted} = sort(Opt0#opt.sort_key, Opt0#opt{sort_key = undefined}, Merged), + SortedA = array:from_list(Sorted), + S0#holder{sort=Opt, table=SortedA, n=array:size(SortedA), temp=[], pid=undefined}; handle_new_data_chunk2(Data, S0 = #holder{columns=Cols0, source=ets, temp=Tab0}) -> {Tab, Cols} = parse_ets_data(Data, Cols0, Tab0), S0#holder{columns=Cols, temp=Tab}; @@ -566,10 +577,9 @@ parse_ets_data([Recs|Rs], C0, Tab0) -> parse_ets_data([], Cols, Tab) -> {Tab, Cols}. -sort(Col, S=#holder{n=N, parent=Parent, sort=Opt0, table=Table0}) -> - {Opt, Table} = sort(Col, Opt0, Table0), - Parent ! {refresh, 0, N-1}, - S#holder{sort=Opt, table=Table}. +sort(Col, S=#holder{sort=Opt0, table=Table0}) -> + {Opt, Table} = sort(Col, Opt0, array:to_list(Table0)), + S#holder{sort=Opt, table=array:from_list(Table)}. sort(Col, Opt = #opt{sort_key=Col, sort_incr=Bool}, Table) -> {Opt#opt{sort_incr=not Bool}, lists:reverse(Table)}; @@ -597,7 +607,7 @@ keysort(Col, Table) -> lists:sort(Sort, Table). search([Str, Row, Dir0, CaseSens], - S=#holder{parent=Parent, table=Table0}) -> + S=#holder{parent=Parent, n=N, table=Table}) -> Opt = case CaseSens of true -> []; false -> [caseless] @@ -607,32 +617,26 @@ search([Str, Row, Dir0, CaseSens], false -> -1 end, Res = case re:compile(Str, Opt) of - {ok, Re} -> - Table = - case Dir0 of - true -> - lists:nthtail(Row, Table0); - false -> - lists:reverse(lists:sublist(Table0, Row+1)) - end, - search(Row, Dir, Re, Table); + {ok, Re} -> re_search(Row, Dir, N, Re, Table); {error, _} -> false end, Parent ! {self(), Res}, S#holder{search=Res}. -search(Row, Dir, Re, [ [Term|_] |Table]) -> +re_search(Row, Dir, N, Re, Table) when Row >= 0, Row < N -> + [Term|_] = array:get(Row, Table), Str = format(Term), Res = re:run(Str, Re), case Res of - nomatch -> search(Row+Dir, Dir, Re, Table); - {match,_} -> Row + nomatch -> re_search(Row+Dir, Dir, N, Re, Table); + {match,_} -> + Row end; -search(_, _, _, []) -> +re_search(_, _, _, _, _) -> false. get_row(From, Row, Col, Table) -> - case lists:nth(Row+1, Table) of + case array:get(Row, Table) of [Object|_] when Col =:= all -> From ! {self(), format(Object)}; [Object|_] when Col =:= all_multiline -> @@ -647,14 +651,15 @@ get_attr(From, Row, #holder{attrs=Attrs, search=Row}) -> What = Attrs#attrs.searched, From ! {self(), What}; get_attr(From, Row, #holder{table=Table, attrs=Attrs}) -> - What = case lists:nth(Row+1, Table) of + Odd = (Row rem 2) > 0, + What = case array:get(Row, Table) of [_|deleted] -> Attrs#attrs.deleted; - [_|changed] -> Attrs#attrs.changed; - [_|new] -> Attrs#attrs.changed; - _ when (Row rem 2) > 0 -> - Attrs#attrs.odd; - _ -> - Attrs#attrs.even + [_|changed] when Odd -> Attrs#attrs.changed_odd; + [_|changed] -> Attrs#attrs.changed_even; + [_|new] when Odd -> Attrs#attrs.new_odd; + [_|new] -> Attrs#attrs.new_even; + _ when Odd -> Attrs#attrs.odd; + _ -> Attrs#attrs.even end, From ! {self(), What}. @@ -665,19 +670,29 @@ merge(Old, New, Key) -> merge2([[Obj|_]|Old], [Obj|New], Key) -> [[Obj]|merge2(Old, New, Key)]; -merge2([[A|_]|Old], [B|New], Key) +merge2([[A|Op]|Old], [B|New], Key) when element(Key, A) == element(Key, B) -> - [[B|changed]|merge2(Old, New, Key)]; -merge2([[A|_]|Old], New = [B|_], Key) + case Op of + deleted -> + [[B|new]|merge2(Old, New, Key)]; + _ -> + [[B|changed]|merge2(Old, New, Key)] + end; +merge2([[A|Op]|Old], New = [B|_], Key) when element(Key, A) < element(Key, B) -> - [[A|deleted]|merge2(Old, New, Key)]; + case Op of + deleted -> merge2(Old, New, Key); + _ -> [[A|deleted]|merge2(Old, New, Key)] + end; merge2(Old = [[A|_]|_], [B|New], Key) when element(Key, A) > element(Key, B) -> [[B|new]|merge2(Old, New, Key)]; merge2([], New, _Key) -> [[N|new] || N <- New]; merge2(Old, [], _Key) -> - [[O|deleted] || [O|_] <- Old]. + lists:foldl(fun([_O|deleted], Acc) -> Acc; + ([O|_], Acc) -> [[O|deleted]|Acc] + end, [], Old). delete_row(Row, S0 = #holder{parent=Parent}) -> @@ -691,7 +706,7 @@ delete_row(Row, S0 = #holder{parent=Parent}) -> delete(Row, #holder{tabid=Id, table=Table, source=Source, node=Node}) -> - [Object|_] = lists:nth(Row+1, Table), + [Object|_] = array:get(Row, Table), try case Source of ets -> |