diff options
Diffstat (limited to 'lib/observer/src')
21 files changed, 394 insertions, 145 deletions
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile index ff2bcbdb99..f9f239db37 100644 --- a/lib/observer/src/Makefile +++ b/lib/observer/src/Makefile @@ -50,6 +50,7 @@ MODULES= \ cdv_mem_cb \ cdv_mod_cb \ cdv_multi_wx \ + cdv_persistent_cb \ cdv_port_cb \ cdv_proc_cb \ cdv_sched_cb \ diff --git a/lib/observer/src/cdv_detail_wx.erl b/lib/observer/src/cdv_detail_wx.erl index 4b1984c394..5e1137511a 100644 --- a/lib/observer/src/cdv_detail_wx.erl +++ b/lib/observer/src/cdv_detail_wx.erl @@ -84,8 +84,9 @@ destroy_progress(_) -> ok. init(Id,ParentFrame,Callback,App,Parent,{Title,Info,TW}) -> + Scale = observer_wx:get_scale(), Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [Title], - [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]), + [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {Scale*850,Scale*600}}]), MenuBar = wxMenuBar:new(), create_menus(MenuBar), wxFrame:setMenuBar(Frame, MenuBar), diff --git a/lib/observer/src/cdv_html_wx.erl b/lib/observer/src/cdv_html_wx.erl index d9efa7fc2f..8956173c93 100644 --- a/lib/observer/src/cdv_html_wx.erl +++ b/lib/observer/src/cdv_html_wx.erl @@ -33,13 +33,17 @@ {panel, app, %% which tool is the user expand_table, - expand_wins=[]}). + expand_wins=[], + delayed_fetch, + trunc_warn=[]}). start_link(ParentWin, Info) -> wx_object:start_link(?MODULE, [ParentWin, Info], []). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +init([ParentWin, Callback]) when is_atom(Callback) -> + init(ParentWin, Callback); init([ParentWin, {App, Fun}]) when is_function(Fun) -> init([ParentWin, {App, Fun()}]); init([ParentWin, {expand,HtmlText,Tab}]) -> @@ -60,9 +64,29 @@ init(ParentWin, HtmlText, Tab, App) -> wx_misc:endBusyCursor(), {HtmlWin, #state{panel=HtmlWin,expand_table=Tab,app=App}}. +init(ParentWin, Callback) -> + {HtmlWin, State} = init(ParentWin, "", undefined, cdv), + {HtmlWin, State#state{delayed_fetch=Callback}}. + %%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +handle_info(active, #state{panel=HtmlWin,delayed_fetch=Callback}=State) + when Callback=/=undefined -> + observer_lib:display_progress_dialog(HtmlWin, + "Crashdump Viewer", + "Reading data"), + {{expand,HtmlText,Tab},TW} = Callback:get_info(), + observer_lib:sync_destroy_progress_dialog(), + wx_misc:beginBusyCursor(), + wxHtmlWindow:setPage(HtmlWin,HtmlText), + cdv_wx_set_status(State, TW), + wx_misc:endBusyCursor(), + {noreply, State#state{expand_table=Tab, + delayed_fetch=undefined, + trunc_warn=TW}}; + handle_info(active, State) -> + cdv_wx_set_status(State, State#state.trunc_warn), {noreply, State}; handle_info(Info, State) -> @@ -140,3 +164,10 @@ expand(Id,Callback,#state{expand_wins=Opened0, app=App}=State) -> Opened0 end, State#state{expand_wins=Opened}. + +cdv_wx_set_status(#state{app = cdv}, Status) -> + %% this module is used by the observer when cdw_wx isn't started + %% only try to set status when used by cdv + cdv_wx:set_status(Status); +cdv_wx_set_status(_, _) -> + ok. diff --git a/lib/observer/src/cdv_persistent_cb.erl b/lib/observer/src/cdv_persistent_cb.erl new file mode 100644 index 0000000000..d5da18f7fc --- /dev/null +++ b/lib/observer/src/cdv_persistent_cb.erl @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% + +-module(cdv_persistent_cb). + +-export([get_info/0]). + +-include_lib("wx/include/wx.hrl"). + +get_info() -> + Tab = ets:new(pt_expand,[set,public]), + {ok,PT,TW} = crashdump_viewer:persistent_terms(), + {{expand, + observer_html_lib:expandable_term("Persistent Terms",PT,Tab), + Tab}, + TW}. diff --git a/lib/observer/src/cdv_table_wx.erl b/lib/observer/src/cdv_table_wx.erl index 0f28a51017..0cad272262 100644 --- a/lib/observer/src/cdv_table_wx.erl +++ b/lib/observer/src/cdv_table_wx.erl @@ -50,11 +50,12 @@ init([ParentWin, {ColumnSpec,Info,TW}]) -> end, Grid = wxListCtrl:new(ParentWin, [{style, Style}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), AddListEntry = fun({Name, Align, DefSize}, Col) -> wxListItem:setText(Li, Name), wxListItem:setAlign(Li, Align), wxListCtrl:insertColumn(Grid, Col, Li), - wxListCtrl:setColumnWidth(Grid, Col, DefSize), + wxListCtrl:setColumnWidth(Grid, Col, DefSize*Scale), Col + 1 end, lists:foldl(AddListEntry, 0, ColumnSpec), diff --git a/lib/observer/src/cdv_virtual_list_wx.erl b/lib/observer/src/cdv_virtual_list_wx.erl index 2702301021..14877b7eab 100644 --- a/lib/observer/src/cdv_virtual_list_wx.erl +++ b/lib/observer/src/cdv_virtual_list_wx.erl @@ -132,11 +132,12 @@ create_list_box(Panel, Holder, Callback, Owner) -> end} ]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), AddListEntry = fun({Name, Align, DefSize}, Col) -> wxListItem:setText(Li, Name), wxListItem:setAlign(Li, Align), wxListCtrl:insertColumn(ListCtrl, Col, Li), - wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize), + wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize*Scale), Col + 1 end, ListItems = Callback:col_spec(), diff --git a/lib/observer/src/cdv_wx.erl b/lib/observer/src/cdv_wx.erl index 78a897111c..811c767e66 100644 --- a/lib/observer/src/cdv_wx.erl +++ b/lib/observer/src/cdv_wx.erl @@ -51,6 +51,7 @@ -define(DIST_STR, "Nodes"). -define(MOD_STR, "Modules"). -define(MEM_STR, "Memory"). +-define(PERSISTENT_STR, "Persistent Terms"). -define(INT_STR, "Internal Tables"). %% Records @@ -74,6 +75,7 @@ dist_panel, mod_panel, mem_panel, + persistent_panel, int_panel, active_tab }). @@ -99,8 +101,9 @@ init(File0) -> {ok,CdvServer} = crashdump_viewer:start_link(), catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1), + Scale = observer_wx:get_scale(), Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Crashdump Viewer", - [{size, {850, 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), + [{size, {Scale*850, Scale*600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), wxFrame:setIcon(Frame, Icon), @@ -193,6 +196,10 @@ setup(#state{frame=Frame, notebook=Notebook}=State) -> %% Memory Panel MemPanel = add_page(Notebook, ?MEM_STR, cdv_multi_wx, cdv_mem_cb), + %% Persistent Terms Panel + PersistentPanel = add_page(Notebook, ?PERSISTENT_STR, + cdv_html_wx, cdv_persistent_cb), + %% Memory Panel IntPanel = add_page(Notebook, ?INT_STR, cdv_multi_wx, cdv_int_tab_cb), @@ -215,6 +222,7 @@ setup(#state{frame=Frame, notebook=Notebook}=State) -> dist_panel = DistPanel, mod_panel = ModPanel, mem_panel = MemPanel, + persistent_panel = PersistentPanel, int_panel = IntPanel, active_tab = GenPid }}. @@ -250,6 +258,7 @@ handle_event(#wx{id = ?wxID_OPEN, State#state.dist_panel, State#state.mod_panel, State#state.mem_panel, + State#state.persistent_panel, State#state.int_panel], _ = [wx_object:call(Panel,new_dump) || Panel<-Panels], wxNotebook:setSelection(State#state.notebook,0), @@ -343,8 +352,8 @@ check_page_title(Notebook) -> get_active_pid(#state{notebook=Notebook, gen_panel=Gen, pro_panel=Pro, port_panel=Ports, ets_panel=Ets, timer_panel=Timers, fun_panel=Funs, atom_panel=Atoms, dist_panel=Dist, - mod_panel=Mods, mem_panel=Mem, int_panel=Int, - sched_panel=Sched + mod_panel=Mods, mem_panel=Mem, persistent_panel=Persistent, + int_panel=Int, sched_panel=Sched }) -> Panel = case check_page_title(Notebook) of ?GEN_STR -> Gen; @@ -358,6 +367,7 @@ get_active_pid(#state{notebook=Notebook, gen_panel=Gen, pro_panel=Pro, ?DIST_STR -> Dist; ?MOD_STR -> Mods; ?MEM_STR -> Mem; + ?PERSISTENT_STR -> Persistent; ?INT_STR -> Int end, wx_object:get_pid(Panel). @@ -365,7 +375,7 @@ get_active_pid(#state{notebook=Notebook, gen_panel=Gen, pro_panel=Pro, pid2panel(Pid, #state{gen_panel=Gen, pro_panel=Pro, port_panel=Ports, ets_panel=Ets, timer_panel=Timers, fun_panel=Funs, atom_panel=Atoms, dist_panel=Dist, mod_panel=Mods, - mem_panel=Mem, int_panel=Int}) -> + mem_panel=Mem, persistent_panel=Persistent, int_panel=Int}) -> case Pid of Gen -> ?GEN_STR; Pro -> ?PRO_STR; @@ -377,6 +387,7 @@ pid2panel(Pid, #state{gen_panel=Gen, pro_panel=Pro, port_panel=Ports, Dist -> ?DIST_STR; Mods -> ?MOD_STR; Mem -> ?MEM_STR; + ?PERSISTENT_STR -> Persistent; Int -> ?INT_STR; _ -> "unknown" end. diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl index 14b086ff58..97bb344cbf 100644 --- a/lib/observer/src/crashdump_viewer.erl +++ b/lib/observer/src/crashdump_viewer.erl @@ -74,6 +74,7 @@ loaded_modules/0, loaded_mod_details/1, memory/0, + persistent_terms/0, allocated_areas/0, allocator_info/0, hash_tables/0, @@ -139,6 +140,7 @@ -define(node,node). -define(not_connected,not_connected). -define(old_instr_data,old_instr_data). +-define(persistent_terms,persistent_terms). -define(port,port). -define(proc,proc). -define(proc_dictionary,proc_dictionary). @@ -293,6 +295,8 @@ loaded_mod_details(Mod) -> call({loaded_mod_details,Mod}). memory() -> call(memory). +persistent_terms() -> + call(persistent_terms). allocated_areas() -> call(allocated_areas). allocator_info() -> @@ -471,6 +475,11 @@ handle_call(memory,_From,State=#state{file=File}) -> Memory=memory(File), TW = truncated_warning([?memory]), {reply,{ok,Memory,TW},State}; +handle_call(persistent_terms,_From,State=#state{file=File,dump_vsn=DumpVsn}) -> + TW = truncated_warning([?persistent_terms,?literals]), + DecodeOpts = get_decode_opts(DumpVsn), + Terms = persistent_terms(File, DecodeOpts), + {reply,{ok,Terms,TW},State}; handle_call(allocated_areas,_From,State=#state{file=File}) -> AllocatedAreas=allocated_areas(File), TW = truncated_warning([?allocated_areas]), @@ -580,9 +589,9 @@ truncated_here(Tag) -> case get(truncated) of true -> case get(last_tag) of - Tag -> % Tag == {TagType,Id} + {Tag,_Pos} -> % Tag == {TagType,Id} true; - {Tag,_Id} -> + {{Tag,_Id},_Pos} -> true; _LastTag -> truncated_earlier(Tag) @@ -837,8 +846,8 @@ do_read_file(File) -> case check_dump_version(Id) of {ok,DumpVsn} -> reset_tables(), - insert_index(Tag,Id,N1+1), - put_last_tag(Tag,""), + insert_index(Tag,Id,Pos=N1+1), + put_last_tag(Tag,"",Pos), DecodeOpts = get_decode_opts(DumpVsn), indexify(Fd,DecodeOpts,Rest,N1), end_progress(), @@ -906,23 +915,11 @@ indexify(Fd,DecodeOpts,Bin,N) -> _ -> insert_index(Tag,Id,NewPos) end, - case put_last_tag(Tag,Id) of - {?proc_heap,LastId} -> - [{_,LastPos}] = lookup_index(?proc_heap,LastId), + case put_last_tag(Tag,Id,NewPos) of + {{?proc_heap,LastId},LastPos} -> ets:insert(cdv_heap_file_chars,{LastId,N+Start+1-LastPos}); - {?literals,[]} -> - case get(truncated_reason) of - undefined -> - [{_,LastPos}] = lookup_index(?literals,[]), - ets:insert(cdv_heap_file_chars, - {literals,N+Start+1-LastPos}); - _ -> - %% Literals are truncated. Make sure we never - %% attempt to read in the literals. (Heaps that - %% references literals will show markers for - %% incomplete heaps, but will otherwise work.) - delete_index(?literals, []) - end; + {{?literals,[]},LastPos} -> + ets:insert(cdv_heap_file_chars,{literals,N+Start+1-LastPos}); _ -> ok end, indexify(Fd,DecodeOpts,Rest,N1); @@ -964,10 +961,18 @@ tag(Fd,<<>>,N,Gat,Di,Now) -> check_if_truncated() -> case get(last_tag) of - {?ende,_} -> + {{?ende,_},_} -> put(truncated,false), put(truncated_proc,false); - TruncatedTag -> + {{?literals,[]},_} -> + put(truncated,true), + put(truncated_proc,false), + %% Literals are truncated. Make sure we never + %% attempt to read in the literals. (Heaps that + %% references literals will show markers for + %% incomplete heaps, but will otherwise work.) + delete_index(?literals, []); + {TruncatedTag,_} -> put(truncated,true), find_truncated_proc(TruncatedTag) end. @@ -975,7 +980,6 @@ check_if_truncated() -> find_truncated_proc({Tag,_Id}) when Tag==?atoms; Tag==?binary; Tag==?instr_data; - Tag==?literals; Tag==?memory_status; Tag==?memory_map -> put(truncated_proc,false); @@ -1444,15 +1448,7 @@ maybe_other_node2(Channel) -> expand_memory(Fd,Pid,DumpVsn) -> DecodeOpts = get_decode_opts(DumpVsn), put(fd,Fd), - Dict0 = case get(?literals) of - undefined -> - Literals = read_literals(Fd,DecodeOpts), - put(?literals,Literals), - put(fd,Fd), - Literals; - Literals -> - Literals - end, + Dict0 = get_literals(Fd,DecodeOpts), Dict = read_heap(Fd,Pid,DecodeOpts,Dict0), Expanded = {read_stack_dump(Fd,Pid,DecodeOpts,Dict), read_messages(Fd,Pid,DecodeOpts,Dict), @@ -1468,6 +1464,18 @@ expand_memory(Fd,Pid,DumpVsn) -> end, {Expanded,IncompleteWarning}. +get_literals(Fd,DecodeOpts) -> + case get(?literals) of + undefined -> + OldFd = put(fd,Fd), + Literals = read_literals(Fd,DecodeOpts), + put(fd,OldFd), + put(?literals,Literals), + Literals; + Literals -> + Literals + end. + read_literals(Fd,DecodeOpts) -> case lookup_index(?literals,[]) of [{_,Start}] -> @@ -1594,31 +1602,92 @@ read_heap(Fd,Pid,DecodeOpts,Dict0) -> Dict0 end. -read_heap(DecodeOpts,Dict0) -> - %% This function is never called if the dump is truncated in {?proc_heap,Pid} - case get(fd) of - end_of_heap -> +read_heap(DecodeOpts, Dict0) -> + %% This function is never called if the dump is truncated in + %% {?proc_heap,Pid}. + %% + %% It is not always possible to reconstruct the heap terms + %% in a single pass, especially if maps are involved. + %% See crashdump_helper:literal_map/0 for an example. + %% + %% Therefore, we need two passes. In the first pass + %% we collect all lines without parsing them, and in the + %% second pass we parse them. + %% + %% The first pass follows. + + Lines0 = read_heap_lines(), + + %% Save a map of all unprocessed lines so that deref_ptr() can + %% access any line when there are references to terms not yet + %% built. + + LineMap = maps:from_list(Lines0), + put(line_map, LineMap), + + %% Refc binaries (tag "Yc") must be processed before any sub + %% binaries (tag "Ys") referencing them, so we make sure to + %% process all the refc binaries first. + %% + %% The other lines can be processed in any order, but processing + %% them in the reverse order compared to how they are printed in + %% the crash dump seems to minimize the number of references to + %% terms that have not yet been built. That happens to be the + %% order of the line list as returned by read_heap_lines/0. + + RefcBins = [Refc || {_,<<"Yc",_/binary>>}=Refc <- Lines0], + Lines = RefcBins ++ Lines0, + + %% Second pass. + + init_progress("Processing terms", map_size(LineMap)), + Dict = parse_heap_terms(Lines, DecodeOpts, Dict0), + erase(line_map), + end_progress(), + Dict. + +read_heap_lines() -> + read_heap_lines_1(get(fd), []). + +read_heap_lines_1(Fd, Acc) -> + case bytes(Fd) of + "=" ++ _next_tag -> end_progress(), - Dict0; - Fd -> - case bytes(Fd) of - "=" ++ _next_tag -> - end_progress(), - put(fd, end_of_heap), - Dict0; - Line -> - update_progress(length(Line)+1), - Dict = parse(Line,DecodeOpts,Dict0), - read_heap(DecodeOpts,Dict) - end + put(fd, end_of_heap), + Acc; + Line0 -> + update_progress(length(Line0)+1), + {Addr,":"++Line1} = get_hex(Line0), + + %% Reduce the memory consumption by converting the + %% line to a binary. Measurements show that it may also + %% be benefical for performance, too, because it makes the + %% garbage collections cheaper. + + Line = list_to_binary(Line1), + read_heap_lines_1(Fd, [{Addr,Line}|Acc]) end. -parse(Line0, DecodeOpts, Dict0) -> - {Addr,":"++Line1} = get_hex(Line0), - {_Term,Line,Dict} = parse_heap_term(Line1, Addr, DecodeOpts, Dict0), - [] = skip_blanks(Line), +parse_heap_terms([{Addr,Line0}|T], DecodeOpts, Dict0) -> + case gb_trees:is_defined(Addr, Dict0) of + true -> + %% Already parsed (by a recursive call from do_deref_ptr() + %% to parse_line()). Nothing to do. + parse_heap_terms(T, DecodeOpts, Dict0); + false -> + %% Parse this previously unparsed term. + Dict = parse_line(Addr, Line0, DecodeOpts, Dict0), + parse_heap_terms(T, DecodeOpts, Dict) + end; +parse_heap_terms([], _DecodeOpts, Dict) -> Dict. +parse_line(Addr, Line0, DecodeOpts, Dict0) -> + update_progress(1), + Line1 = binary_to_list(Line0), + {_Term,Line,Dict} = parse_heap_term(Line1, Addr, DecodeOpts, Dict0), + [] = skip_blanks(Line), %Assertion. + Dict. %%----------------------------------------------------------------- %% Page with one port @@ -2142,6 +2211,56 @@ get_atom(Atom) when is_binary(Atom) -> {Atom,nq}. % not quoted %%----------------------------------------------------------------- +%% Page with list of all persistent terms +persistent_terms(File, DecodeOpts) -> + case lookup_index(?persistent_terms) of + [{_Id,Start}] -> + Fd = open(File), + pos_bof(Fd,Start), + Terms = get_persistent_terms(Fd), + Dict = get_literals(Fd,DecodeOpts), + parse_persistent_terms(Terms,DecodeOpts,Dict); + _ -> + [] + end. + +parse_persistent_terms([[Name0,Val0]|Terms],DecodeOpts,Dict) -> + {Name,_,_} = parse_term(binary_to_list(Name0),DecodeOpts,Dict), + {Val,_,_} = parse_term(binary_to_list(Val0),DecodeOpts,Dict), + [{Name,Val}|parse_persistent_terms(Terms,DecodeOpts,Dict)]; +parse_persistent_terms([],_,_) -> []. + +get_persistent_terms(Fd) -> + case get_chunk(Fd) of + {ok,Bin} -> + get_persistent_terms(Fd,Bin,[]); + eof -> + [] + end. + + +%% Persistent_Terms are written one per line in the crash dump. +get_persistent_terms(Fd,Bin,PersistentTerms) -> + Bins = binary:split(Bin,<<"\n">>,[global]), + get_persistent_terms1(Fd,Bins,PersistentTerms). + +get_persistent_terms1(_Fd,[<<"=",_/binary>>|_],PersistentTerms) -> + PersistentTerms; +get_persistent_terms1(Fd,[LastBin],PersistentTerms) -> + case get_chunk(Fd) of + {ok,Bin0} -> + get_persistent_terms(Fd,<<LastBin/binary,Bin0/binary>>,PersistentTerms); + eof -> + [get_persistent_term(LastBin)|PersistentTerms] + end; +get_persistent_terms1(Fd,[Bin|Bins],Persistent_Terms) -> + get_persistent_terms1(Fd,Bins,[get_persistent_term(Bin)|Persistent_Terms]). + +get_persistent_term(Bin) -> + binary:split(Bin,<<"|">>). + + +%%----------------------------------------------------------------- %% Page with memory information memory(File) -> case lookup_index(?memory) of @@ -2746,12 +2865,12 @@ parse_heap_term("Yc"++Line0, Addr, DecodeOpts, D0) -> %Reference-counted binary. SymbolicBin = {'#CDVBin',Start}, Term = cdvbin(Offset, Sz, SymbolicBin), D1 = gb_trees:insert(Addr, Term, D0), - D = gb_trees:insert(Binp, SymbolicBin, D1), + D = gb_trees:enter(Binp, SymbolicBin, D1), {Term,Line,D}; [] -> Term = '#CDVNonexistingBinary', D1 = gb_trees:insert(Addr, Term, D0), - D = gb_trees:insert(Binp, Term, D1), + D = gb_trees:enter(Binp, Term, D1), {Term,Line,D} end; parse_heap_term("Ys"++Line0, Addr, DecodeOpts, D0) -> %Sub binary. @@ -2763,12 +2882,17 @@ parse_heap_term("Ys"++Line0, Addr, DecodeOpts, D0) -> %Sub binary. {Term,Line,D}; parse_heap_term("Mf"++Line0, Addr, DecodeOpts, D0) -> %Flatmap. {Size,":"++Line1} = get_hex(Line0), - {Keys,":"++Line2,D1} = parse_term(Line1, DecodeOpts, D0), - {Values,Line,D2} = parse_tuple(Size, Line2, Addr,DecodeOpts, D1, []), - Pairs = zip_tuples(tuple_size(Keys), Keys, Values, []), - Map = maps:from_list(Pairs), - D = gb_trees:update(Addr, Map, D2), - {Map,Line,D}; + case parse_term(Line1, DecodeOpts, D0) of + {Keys,":"++Line2,D1} when is_tuple(Keys) -> + {Values,Line,D2} = parse_tuple(Size, Line2, Addr,DecodeOpts, D1, []), + Pairs = zip_tuples(tuple_size(Keys), Keys, Values, []), + Map = maps:from_list(Pairs), + D = gb_trees:update(Addr, Map, D2), + {Map,Line,D}; + {Incomplete,_Line,D1} -> + D = gb_trees:insert(Addr, Incomplete, D1), + {Incomplete,"",D} + end; parse_heap_term("Mh"++Line0, Addr, DecodeOpts, D0) -> %Head node in a hashmap. {MapSize,":"++Line1} = get_hex(Line0), {N,":"++Line2} = get_hex(Line1), @@ -2871,16 +2995,18 @@ parse_atom_translation_table(N, Line0, As) -> deref_ptr(Ptr, Line, DecodeOpts, D) -> - Lookup = fun(D0) -> - gb_trees:lookup(Ptr, D0) - end, + Lookup0 = fun(D0) -> + gb_trees:lookup(Ptr, D0) + end, + Lookup = wrap_line_map(Ptr, Lookup0), do_deref_ptr(Lookup, Line, DecodeOpts, D). deref_bin(Binp0, Offset, Sz, Line, DecodeOpts, D) -> Binp = Binp0 bor DecodeOpts#dec_opts.bin_addr_adj, - Lookup = fun(D0) -> - lookup_binary(Binp, Offset, Sz, D0) - end, + Lookup0 = fun(D0) -> + lookup_binary(Binp, Offset, Sz, D0) + end, + Lookup = wrap_line_map(Binp, Lookup0), do_deref_ptr(Lookup, Line, DecodeOpts, D). lookup_binary(Binp, Offset, Sz, D) -> @@ -2899,26 +3025,36 @@ lookup_binary(Binp, Offset, Sz, D) -> end end. +wrap_line_map(Ptr, Lookup) -> + wrap_line_map_1(get(line_map), Ptr, Lookup). + +wrap_line_map_1(#{}=LineMap, Ptr, Lookup) -> + fun(D) -> + case Lookup(D) of + {value,_}=Res -> + Res; + none -> + case LineMap of + #{Ptr:=Line} -> + {line,Ptr,Line}; + #{} -> + none + end + end + end; +wrap_line_map_1(undefined, _Ptr, Lookup) -> + Lookup. + do_deref_ptr(Lookup, Line, DecodeOpts, D0) -> case Lookup(D0) of {value,Term} -> {Term,Line,D0}; none -> - case get(fd) of - end_of_heap -> - put(incomplete_heap,true), - {['#CDVIncompleteHeap'],Line,D0}; - Fd -> - case bytes(Fd) of - "="++_ -> - put(fd, end_of_heap), - do_deref_ptr(Lookup, Line, DecodeOpts, D0); - L -> - update_progress(length(L)+1), - D = parse(L, DecodeOpts, D0), - do_deref_ptr(Lookup, Line, DecodeOpts, D) - end - end + put(incomplete_heap, true), + {'#CDVIncompleteHeap',Line,D0}; + {line,Addr,NewLine} -> + D = parse_line(Addr, NewLine, DecodeOpts, D0), + do_deref_ptr(Lookup, Line, DecodeOpts, D) end. get_hex(L) -> @@ -3119,6 +3255,7 @@ tag_to_atom("literals") -> ?literals; tag_to_atom("loaded_modules") -> ?loaded_modules; tag_to_atom("memory") -> ?memory; tag_to_atom("mod") -> ?mod; +tag_to_atom("persistent_terms") -> ?persistent_terms; tag_to_atom("no_distribution") -> ?no_distribution; tag_to_atom("node") -> ?node; tag_to_atom("not_connected") -> ?not_connected; @@ -3138,13 +3275,13 @@ tag_to_atom(UnknownTag) -> %%%----------------------------------------------------------------- %%% Store last tag for use when truncated, and reason if aborted -put_last_tag(?abort,Reason) -> - %% Don't overwrite the real last tag, and make sure to return - %% the previous last tag. - put(truncated_reason,Reason), - get(last_tag); -put_last_tag(Tag,Id) -> - put(last_tag,{Tag,Id}). +put_last_tag(?abort,Reason,_Pos) -> + %% Don't overwrite the real last tag, and don't return it either, + %% since that would make the caller of this function believe that + %% the tag was complete. + put(truncated_reason,Reason); +put_last_tag(Tag,Id,Pos) -> + put(last_tag,{{Tag,Id},Pos}). %%%----------------------------------------------------------------- %%% Fetch next chunk from crashdump file diff --git a/lib/observer/src/observer.app.src b/lib/observer/src/observer.app.src index d73293a5f9..d48b846ad2 100644 --- a/lib/observer/src/observer.app.src +++ b/lib/observer/src/observer.app.src @@ -34,6 +34,7 @@ cdv_mem_cb, cdv_mod_cb, cdv_multi_wx, + cdv_persistent_cb, cdv_port_cb, cdv_proc_cb, cdv_table_wx, diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl index 54e246f247..da47a30fb1 100644 --- a/lib/observer/src/observer_alloc_wx.erl +++ b/lib/observer/src/observer_alloc_wx.erl @@ -282,11 +282,12 @@ create_mem_info(Parent) -> Grid = wxListCtrl:new(Parent, [{style, Style}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), AddListEntry = fun({Name, Align, DefSize}, Col) -> wxListItem:setText(Li, Name), wxListItem:setAlign(Li, Align), wxListCtrl:insertColumn(Grid, Col, Li), - wxListCtrl:setColumnWidth(Grid, Col, DefSize), + wxListCtrl:setColumnWidth(Grid, Col, DefSize*Scale), Col + 1 end, ListItems = [{"Allocator Type", ?wxLIST_FORMAT_LEFT, 200}, diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl index 2a481966da..8c3eef5411 100644 --- a/lib/observer/src/observer_app_wx.erl +++ b/lib/observer/src/observer_app_wx.erl @@ -117,16 +117,19 @@ init([Notebook, Parent, _Config]) -> UseGC = haveGC(), Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8, + Scale = observer_wx:get_scale(), Font = case os:type() of {unix,_} when UseGC, Version28 -> - wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL); + wxFont:new(Scale * 12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL); _ -> - wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT) + Font0 = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), + wxFont:setPointSize(Font0, Scale * wxFont:getPointSize(Font0)), + Font0 end, SelCol = wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), GreyBrush = wxBrush:new({230,230,240}), SelBrush = wxBrush:new(SelCol), - LinkPen = wxPen:new(SelCol, [{width, 2}]), + LinkPen = wxPen:new(SelCol, [{width, Scale * 2}]), process_flag(trap_exit, true), {Panel, #state{parent=Parent, panel =Panel, @@ -134,7 +137,7 @@ init([Notebook, Parent, _Config]) -> app_w =DrawingArea, usegc = UseGC, paint=#paint{font = Font, - pen = wxPen:new({80,80,80}, [{width, 2}]), + pen = wxPen:new({80,80,80}, [{width, Scale * 2}]), brush= GreyBrush, sel = SelBrush, links= LinkPen diff --git a/lib/observer/src/observer_html_lib.erl b/lib/observer/src/observer_html_lib.erl index 0c4e32af49..c67fa28c6d 100644 --- a/lib/observer/src/observer_html_lib.erl +++ b/lib/observer/src/observer_html_lib.erl @@ -62,7 +62,8 @@ expandable_term_body(Heading,[],_Tab) -> "Dictionary" -> "No dictionary was found"; "ProcState" -> "Information could not be retrieved," " system messages may not be handled by this process."; - "SaslLog" -> "No log entry was found" + "SaslLog" -> "No log entry was found"; + "Persistent Terms" -> "No persistent terms were found" end]; expandable_term_body(Heading,Expanded,Tab) -> Attr = "BORDER=0 CELLPADDING=0 CELLSPACING=1 WIDTH=100%", diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl index 21c6d26f49..79271addf2 100644 --- a/lib/observer/src/observer_perf_wx.erl +++ b/lib/observer/src/observer_perf_wx.erl @@ -110,25 +110,26 @@ setup_graph_drawing(Panels) -> _ = [Do(Panel) || Panel <- Panels], UseGC = haveGC(), Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8, + Scale = observer_wx:get_scale(), {Font, SmallFont} = if UseGC, Version28 -> %% Def font is really small when using Graphics contexts in 2.8 %% Hardcode it - F = wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD), - SF = wxFont:new(10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), + F = wxFont:new(Scale * 12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD), + SF = wxFont:new(Scale * 10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), {F, SF}; true -> DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), DefSize = wxFont:getPointSize(DefFont), DefFamily = wxFont:getFamily(DefFont), - F = wxFont:new(DefSize-1, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD), - SF = wxFont:new(DefSize-2, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), + F = wxFont:new(Scale * (DefSize-1), DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD), + SF = wxFont:new(Scale * (DefSize-2), DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), {F, SF} end, - BlackPen = wxPen:new({0,0,0}, [{width, 1}]), - Pens = [wxPen:new(Col, [{width, 1}, {style, ?wxSOLID}]) + BlackPen = wxPen:new({0,0,0}, [{width, Scale}]), + Pens = [wxPen:new(Col, [{width, Scale}, {style, ?wxSOLID}]) || Col <- tuple_to_list(colors())], - DotPens = [wxPen:new(Col, [{width, 1}, {style, ?wxDOT}]) + DotPens = [wxPen:new(Col, [{width, Scale}, {style, ?wxDOT}]) || Col <- tuple_to_list(colors())], #paint{usegc = UseGC, font = Font, diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl index 445f3dd6b1..00cf1b5fba 100644 --- a/lib/observer/src/observer_port_wx.erl +++ b/lib/observer/src/observer_port_wx.erl @@ -96,11 +96,12 @@ init([Notebook, Parent, Config]) -> wxListCtrl:setColumnWidth(Grid, Col, DefSize), Col + 1 end, - ListItems = [{"Id", ?wxLIST_FORMAT_LEFT, 150}, - {"Connected", ?wxLIST_FORMAT_LEFT, 150}, - {"Name", ?wxLIST_FORMAT_LEFT, 150}, - {"Controls", ?wxLIST_FORMAT_LEFT, 200}, - {"Slot", ?wxLIST_FORMAT_RIGHT, 50}], + Scale = observer_wx:get_scale(), + ListItems = [{"Id", ?wxLIST_FORMAT_LEFT, Scale*150}, + {"Connected", ?wxLIST_FORMAT_LEFT, Scale*150}, + {"Name", ?wxLIST_FORMAT_LEFT, Scale*150}, + {"Controls", ?wxLIST_FORMAT_LEFT, Scale*200}, + {"Slot", ?wxLIST_FORMAT_RIGHT, Scale*50}], lists:foldl(AddListEntry, 0, ListItems), wxListItem:destroy(Li), @@ -461,10 +462,11 @@ display_port_info(Parent, PortRec, Opened) -> do_display_port_info(Parent0, PortRec) -> Parent = observer_lib:get_wx_parent(Parent0), Title = "Port Info: " ++ PortRec#port.id_str, + Scale = observer_wx:get_scale(), Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title, [{style, ?wxSYSTEM_MENU bor ?wxCAPTION bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}, - {size,{600,400}}]), + {size,{Scale * 600, Scale * 400}}]), ScrolledWin = wxScrolledWindow:new(Frame,[{style,?wxHSCROLL bor ?wxVSCROLL}]), wxScrolledWindow:enableScrolling(ScrolledWin,true,true), wxScrolledWindow:setScrollbars(ScrolledWin,20,20,0,0), diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl index 04e654a37e..4ab4a78462 100644 --- a/lib/observer/src/observer_pro_wx.erl +++ b/lib/observer/src/observer_pro_wx.erl @@ -163,13 +163,14 @@ create_list_box(Panel, Holder) -> wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize), Col + 1 end, - ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, 120}, - {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, 200}, -%% {"Time", ?wxLIST_FORMAT_CENTRE, 50}, - {"Reds", ?wxLIST_FORMAT_RIGHT, 100}, - {"Memory", ?wxLIST_FORMAT_RIGHT, 100}, - {"MsgQ", ?wxLIST_FORMAT_RIGHT, 50}, - {"Current Function", ?wxLIST_FORMAT_LEFT, 200}], + Scale = observer_wx:get_scale(), + ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, Scale*120}, + {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, Scale*200}, +%% {"Time", ?wxLIST_FORMAT_CENTRE, Scale*50}, + {"Reds", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"Memory", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"MsgQ", ?wxLIST_FORMAT_RIGHT, Scale*50}, + {"Current Function", ?wxLIST_FORMAT_LEFT, Scale*200}], lists:foldl(AddListEntry, 0, ListItems), wxListItem:destroy(Li), diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index f436886735..bd5fed0951 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -59,8 +59,9 @@ init([Pid, ParentFrame, Parent]) -> {registered_name, Registered} -> io_lib:format("~tp (~p)",[Registered, Pid]); undefined -> throw(process_undefined) end, + Scale = observer_wx:get_scale(), Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [atom_to_list(node(Pid)), $:, Title], - [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]), + [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {Scale * 850, Scale * 600}}]), MenuBar = wxMenuBar:new(), create_menus(MenuBar), wxFrame:setMenuBar(Frame, MenuBar), @@ -245,12 +246,13 @@ init_dict_page(Parent, Pid, Table) -> init_stack_page(Parent, Pid) -> LCtrl = wxListCtrl:new(Parent, [{style, ?wxLC_REPORT bor ?wxLC_HRULES}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), wxListItem:setText(Li, "Module:Function/Arg"), wxListCtrl:insertColumn(LCtrl, 0, Li), - wxListCtrl:setColumnWidth(LCtrl, 0, 300), + wxListCtrl:setColumnWidth(LCtrl, 0, Scale * 300), wxListItem:setText(Li, "File:LineNumber"), wxListCtrl:insertColumn(LCtrl, 1, Li), - wxListCtrl:setColumnWidth(LCtrl, 1, 300), + wxListCtrl:setColumnWidth(LCtrl, 1, Scale * 300), wxListItem:destroy(Li), Update = fun() -> case observer_wx:try_rpc(node(Pid), erlang, process_info, diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl index 2c3b46a3a1..f458c8c34a 100644 --- a/lib/observer/src/observer_trace_wx.erl +++ b/lib/observer/src/observer_trace_wx.erl @@ -188,8 +188,9 @@ create_proc_port_view(Parent) -> wxListCtrl:setColumnWidth(Procs, Col, DefSize), Col + 1 end, - ProcListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, 120}, - {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}], + Scale = observer_wx:get_scale(), + ProcListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, Scale*120}, + {"Trace Options", ?wxLIST_FORMAT_LEFT, Scale*300}], lists:foldl(AddProc, 0, ProcListItems), AddPort = fun({Name, Align, DefSize}, Col) -> @@ -199,8 +200,8 @@ create_proc_port_view(Parent) -> wxListCtrl:setColumnWidth(Ports, Col, DefSize), Col + 1 end, - PortListItems = [{"Port Id", ?wxLIST_FORMAT_CENTER, 120}, - {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}], + PortListItems = [{"Port Id", ?wxLIST_FORMAT_CENTER, Scale*120}, + {"Trace Options", ?wxLIST_FORMAT_LEFT, Scale*300}], lists:foldl(AddPort, 0, PortListItems), wxListItem:destroy(Li), @@ -242,14 +243,15 @@ create_matchspec_view(Parent) -> Funcs = wxListCtrl:new(Splitter, [{winid, ?FUNCS_WIN}, {style, Style}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), wxListItem:setText(Li, "Modules"), wxListCtrl:insertColumn(Modules, 0, Li), wxListItem:setText(Li, "Functions"), wxListCtrl:insertColumn(Funcs, 0, Li), - wxListCtrl:setColumnWidth(Funcs, 0, 150), + wxListCtrl:setColumnWidth(Funcs, 0, Scale*150), wxListItem:setText(Li, "Match Spec"), wxListCtrl:insertColumn(Funcs, 1, Li), - wxListCtrl:setColumnWidth(Funcs, 1, 300), + wxListCtrl:setColumnWidth(Funcs, 1, Scale*300), wxListItem:destroy(Li), wxSplitterWindow:setSashGravity(Splitter, 0.0), @@ -969,7 +971,8 @@ output_file(true, true, Opts) -> create_logwindow(_Parent, false) -> {false, false}; create_logwindow(Parent, true) -> - LogWin = wxFrame:new(Parent, ?LOG_WIN, "Trace Log", [{size, {750, 800}}]), + Scale = observer_wx:get_scale(), + LogWin = wxFrame:new(Parent, ?LOG_WIN, "Trace Log", [{size, {750*Scale, 800*Scale}}]), MB = wxMenuBar:new(), File = wxMenu:new(), wxMenu:append(File, ?LOG_CLEAR, "Clear Log\tCtrl-C"), diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl index ea292b92af..514d55ff24 100644 --- a/lib/observer/src/observer_traceoptions_wx.erl +++ b/lib/observer/src/observer_traceoptions_wx.erl @@ -167,9 +167,10 @@ select_nodes(Parent, Nodes) -> check_selector(Parent, Choices). module_selector(Parent, Node) -> + Scale = observer_wx:get_scale(), Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module or Event", [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, - {size, {400, 400}}]), + {size, {400*Scale, 400*Scale}}]), Panel = wxPanel:new(Dialog), PanelSz = wxBoxSizer:new(?wxVERTICAL), MainSz = wxBoxSizer:new(?wxVERTICAL), @@ -237,9 +238,10 @@ function_selector(Parent, Node, Module) -> end. check_selector(Parent, ParsedChoices) -> + Scale = observer_wx:get_scale(), Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Functions", [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, - {size, {400, 400}}]), + {size, {400*Scale, 400*Scale}}]), Panel = wxPanel:new(Dialog), PanelSz = wxBoxSizer:new(?wxVERTICAL), @@ -331,9 +333,10 @@ select_matchspec(Pid, Parent, AllMatchSpecs, Key) -> {value,{Key,MSs0},Rest} -> {MSs0,Rest}; false -> {[],AllMatchSpecs} end, + Scale = observer_wx:get_scale(), Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Match Specifications", [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, - {size, {400, 400}}]), + {size, {400*Scale, 400*Scale}}]), Panel = wxPanel:new(Dialog), PanelSz = wxBoxSizer:new(?wxVERTICAL), diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl index d6dcee2cda..7bd67a0f0b 100644 --- a/lib/observer/src/observer_tv_table.erl +++ b/lib/observer/src/observer_tv_table.erl @@ -99,7 +99,8 @@ init([Parent, Opts]) -> ets -> "TV Ets: " ++ Title0; mnesia -> "TV Mnesia: " ++ Title0 end, - Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {800, 600}}]), + Scale = observer_wx:get_scale(), + Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {Scale * 800, Scale * 600}}]), IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), wxFrame:setIcon(Frame, Icon), diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl index 814f3a1260..247b3e869f 100644 --- a/lib/observer/src/observer_tv_wx.erl +++ b/lib/observer/src/observer_tv_wx.erl @@ -87,12 +87,13 @@ init([Notebook, Parent, Config]) -> wxListCtrl:setColumnWidth(Grid, Col, DefSize), Col + 1 end, - ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, 200}, - {"Objects", ?wxLIST_FORMAT_RIGHT, 100}, - {"Size (kB)", ?wxLIST_FORMAT_RIGHT, 100}, - {"Owner Pid", ?wxLIST_FORMAT_CENTER, 150}, - {"Owner Name", ?wxLIST_FORMAT_LEFT, 200}, - {"Table Id", ?wxLIST_FORMAT_LEFT, 250} + Scale = observer_wx:get_scale(), + ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, Scale*200}, + {"Objects", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"Size (kB)", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"Owner Pid", ?wxLIST_FORMAT_CENTER, Scale*150}, + {"Owner Name", ?wxLIST_FORMAT_LEFT, Scale*200}, + {"Table Id", ?wxLIST_FORMAT_LEFT, Scale*250} ], lists:foldl(AddListEntry, 0, ListItems), wxListItem:destroy(Li), diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl index 453e3bdc2d..71db586845 100644 --- a/lib/observer/src/observer_wx.erl +++ b/lib/observer/src/observer_wx.erl @@ -22,7 +22,7 @@ -export([start/0, stop/0]). -export([create_menus/2, get_attrib/1, get_tracer/0, get_active_node/0, get_menubar/0, - set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]). + get_scale/0, set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]). -export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3, handle_call/3, handle_info/2, check_page_title/1]). @@ -91,14 +91,24 @@ get_active_node() -> get_menubar() -> wx_object:call(observer, get_menubar). +get_scale() -> + ScaleStr = os:getenv("OBSERVER_SCALE", "1"), + try list_to_integer(ScaleStr) of + Scale when Scale < 1 -> 1; + Scale -> Scale + catch _:_ -> + 1 + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init(_Args) -> register(observer, self()), wx:new(), catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1), + Scale = get_scale(), Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Observer", - [{size, {850, 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), + [{size, {Scale * 850, Scale * 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), wxFrame:setIcon(Frame, Icon), @@ -771,7 +781,11 @@ ensure_sasl_started(Node) -> ensure_mf_h_handler_used(Node) -> %% is log_mf_h used ? - Handlers = rpc:block_call(Node, gen_event, which_handlers, [error_logger]), + Handlers = + case rpc:block_call(Node, gen_event, which_handlers, [error_logger]) of + {badrpc,{'EXIT',noproc}} -> []; % OTP-21+ and no event handler exists + Hs -> Hs + end, case lists:any(fun(L)-> L == log_mf_h end, Handlers) of false -> throw("Error: log_mf_h handler not used in sasl."), error; |