From ce6fe3c77b31e6c0fcb13d347c3fcbbedfd544e7 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Tue, 14 Mar 2017 10:46:38 +0100 Subject: dialyzer: Improve compression of an ETS table --- lib/dialyzer/src/dialyzer_codeserver.erl | 26 +++++++++++++++++++++++--- lib/dialyzer/src/dialyzer_plt.erl | 14 +------------- lib/dialyzer/src/dialyzer_utils.erl | 22 ++++++++++++++++++++++ 3 files changed, 46 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl index a1a7370eff..a8422d313e 100644 --- a/lib/dialyzer/src/dialyzer_codeserver.erl +++ b/lib/dialyzer/src/dialyzer_codeserver.erl @@ -304,9 +304,29 @@ lookup_temp_mod_records(Mod, #codeserver{temp_records = TempRecDict}) -> finalize_records(#codeserver{temp_records = TmpRecords, records = Records} = CS) -> - true = ets:delete(Records), - ets:rename(TmpRecords, dialyzer_codeserver_records), - CS#codeserver{temp_records = clean, records = TmpRecords}. + %% The annotations of the abstract code are reset as they are no + %% longer needed, which makes the ETS table compression better. + A0 = erl_anno:new(0), + AFun = fun(_) -> A0 end, + FFun = fun({F, Abs, Type}) -> + NewAbs = erl_parse:map_anno(AFun, Abs), + {F, NewAbs, Type} + end, + ArFun = fun({Arity, Fields}) -> {Arity, lists:map(FFun, Fields)} end, + List = dialyzer_utils:ets_tab2list(TmpRecords), + true = ets:delete(TmpRecords), + Fun = fun({Mod, Map}) -> + MFun = + fun({record, _}, {FileLine, ArityFields}) -> + {FileLine, lists:map(ArFun, ArityFields)}; + (_, {{M, FileLine, Abs, Args}, Type}) -> + {{M, FileLine, erl_parse:map_anno(AFun, Abs), Args}, Type} + end, + {Mod, maps:map(MFun, Map)} + end, + NewList = lists:map(Fun, List), + true = ets:insert(Records, NewList), + CS#codeserver{temp_records = clean}. -spec lookup_mod_contracts(atom(), codeserver()) -> contracts(). diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index fa242555c2..1c1814e49c 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -604,20 +604,8 @@ give_away(#mini_plt{info = ETSInfo, true = ets:give_away(ETSExpTypes, Pid, any), ok. -%% Somewhat slower than ets:tab2list(), but uses less memory. tab2list(T) -> - tab2list(ets:first(T), T, []). - -tab2list('$end_of_table', T, A) -> - case ets:first(T) of % no safe_fixtable()... - '$end_of_table' -> A; - Key -> tab2list(Key, T, A) - end; -tab2list(Key, T, A) -> - Vs = ets:lookup(T, Key), - Key1 = ets:next(T, Key), - ets:delete(T, Key), - tab2list(Key1, T, Vs ++ A). + dialyzer_utils:ets_tab2list(T). %%--------------------------------------------------------------------------- %% Edoc diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index 7eaa03ec30..0dbb2bcf0a 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -39,6 +39,7 @@ sets_filter/2, src_compiler_opts/0, refold_pattern/1, + ets_tab2list/1, parallelism/0, family/1 ]). @@ -989,6 +990,27 @@ label(Tree) -> %%------------------------------------------------------------------------------ +-spec ets_tab2list(ets:tid()) -> list(). + +%% Deletes the contents of the table. Use: +%% ets_tab2list(T), ets:delete(T) +%% instead of: +%% ets:tab2list(T), ets:delete(T) +%% to save some memory at the expense of somewhat longer execution time. +ets_tab2list(T) -> + tab2list(ets:first(T), T, []). + +tab2list('$end_of_table', T, A) -> + case ets:first(T) of % no safe_fixtable()... + '$end_of_table' -> A; + Key -> tab2list(Key, T, A) + end; +tab2list(Key, T, A) -> + Vs = ets:lookup(T, Key), + Key1 = ets:next(T, Key), + ets:delete(T, Key), + tab2list(Key1, T, Vs ++ A). + -spec parallelism() -> integer(). parallelism() -> -- cgit v1.2.3