aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2016-03-21 14:10:02 +0100
committerBjörn Gustavsson <[email protected]>2016-03-21 14:10:02 +0100
commit181c4e084b0be39a9dbef5c83b3056f5079ff144 (patch)
tree30eba1194e50f75d02de25fcd11a6182c2214382 /lib
parente369312640200396b277e2e63378f86ff965d166 (diff)
parent3c3c984aa9443a1ac1464473fd50e721e4d43b1f (diff)
downloadotp-181c4e084b0be39a9dbef5c83b3056f5079ff144.tar.gz
otp-181c4e084b0be39a9dbef5c83b3056f5079ff144.tar.bz2
otp-181c4e084b0be39a9dbef5c83b3056f5079ff144.zip
Merge branch 'bjorn/optimize-start-up/OTP-13368'
* bjorn/optimize-start-up/OTP-13368: Update preloaded modules init: Load modules in parallel using the new loader BIFs systools_make: Add commonly used modules to mandatory_modules/0 compile: Pre-load compiler modules when invoked from 'erlc'
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/compile.erl44
-rw-r--r--lib/compiler/test/compile_SUITE.erl114
-rw-r--r--lib/sasl/src/systools_make.erl39
3 files changed, 186 insertions, 11 deletions
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 46917905de..332bc0bdf9 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1681,6 +1681,7 @@ help(_) ->
%% Compile entry point for erl_compile.
compile(File0, _OutFile, Options) ->
+ pre_load(),
File = shorten_filename(File0),
case file(File, make_erl_options(Options)) of
{ok,_Mod} -> ok;
@@ -1745,3 +1746,46 @@ make_erl_options(Opts) ->
end,
Options ++ [report_errors, {cwd, Cwd}, {outdir, Outdir}|
[{i, Dir} || Dir <- Includes]] ++ Specific.
+
+pre_load() ->
+ L = [beam_a,
+ beam_asm,
+ beam_block,
+ beam_bool,
+ beam_bs,
+ beam_bsm,
+ beam_clean,
+ beam_dead,
+ beam_dict,
+ beam_except,
+ beam_flatten,
+ beam_jump,
+ beam_opcodes,
+ beam_peep,
+ beam_receive,
+ beam_reorder,
+ beam_split,
+ beam_trim,
+ beam_type,
+ beam_utils,
+ beam_validator,
+ beam_z,
+ cerl,
+ cerl_clauses,
+ cerl_sets,
+ cerl_trees,
+ core_lib,
+ epp,
+ erl_bifs,
+ erl_expand_records,
+ erl_lint,
+ erl_parse,
+ erl_scan,
+ sys_core_dsetel,
+ sys_core_fold,
+ sys_pre_expand,
+ v3_codegen,
+ v3_core,
+ v3_kernel,
+ v3_life],
+ code:ensure_modules_loaded(L).
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index b2e9558cba..fc04c9a60a 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -22,6 +22,7 @@
%% Tests compile:file/1 and compile:file/2 with various options.
-include_lib("common_test/include/ct.hrl").
+-include_lib("stdlib/include/erl_compile.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
@@ -32,7 +33,7 @@
strict_record/1,
missing_testheap/1, cover/1, env/1, core/1, asm/1,
sys_pre_attributes/1, dialyzer/1,
- warnings/1
+ warnings/1, pre_load_check/1
]).
-export([init/3]).
@@ -50,7 +51,7 @@ all() ->
other_output, encrypted_abstr,
strict_record,
missing_testheap, cover, env, core, asm,
- sys_pre_attributes, dialyzer, warnings].
+ sys_pre_attributes, dialyzer, warnings, pre_load_check].
groups() ->
[].
@@ -881,6 +882,115 @@ do_warnings_2([], Next, F) ->
do_warnings_1(Next, F).
+%% Test that the compile:pre_load/0 function (used by 'erlc')
+%% pre-loads the modules that are used by a typical compilation.
+
+pre_load_check(Config) ->
+ case test_server:is_cover() of
+ true ->
+ {skip,"Cover is running"};
+ false ->
+ try
+ do_pre_load_check(Config)
+ after
+ dbg:stop_clear()
+ end
+ end.
+
+do_pre_load_check(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Simple = filename:join(DataDir, "simple.erl"),
+ Big = filename:join(DataDir, "big.erl"),
+ {ok,_} = dbg:tracer(process, {fun pre_load_trace/2,[]}),
+ dbg:p(self(), call),
+ dbg:p(new, call),
+ {ok,_} = dbg:tpl({?MODULE,get_trace_data,0}, []),
+ {ok,_} = dbg:tp({code,ensure_modules_loaded,1}, []),
+
+ %% Compile a simple module using the erl_compile interface
+ %% to find out the modules that are pre-loaded by
+ %% compile:pre_load/0.
+ Opts = #options{specific=[binary]},
+ {ok,simple,_} = compile:compile(Simple, "", Opts),
+ [{code,ensure_modules_loaded,[PreLoaded0]}] = get_trace_data(),
+ PreLoaded1 = ordsets:from_list(PreLoaded0),
+
+ %% Since 'compile' is the function doing the pre-loaded,
+ %% it is useless to include it in the list.
+ case ordsets:is_element(compile, PreLoaded1) of
+ true ->
+ io:put_chars("The 'compile' module should not be included "
+ "in the list of modules to be pre-loaded."),
+ ?t:fail(compile);
+ false ->
+ []
+ end,
+ PreLoaded = ordsets:add_element(compile, PreLoaded1),
+
+ %% Now unload all pre-loaded modules and all modules in
+ %% compiler application. Then compile a module to find
+ %% which modules that get loaded.
+ CompilerMods = compiler_modules(),
+ Unload = ordsets:union(ordsets:from_list(CompilerMods), PreLoaded),
+ _ = [begin
+ code:delete(M),
+ code:purge(M)
+ end || M <- Unload],
+
+ {ok,_} = dbg:ctp({code,ensure_modules_loaded,1}),
+ {ok,_} = dbg:tp({code,ensure_loaded,1}, []),
+ {ok,big,_} = compile:file(Big, [binary]),
+ WasLoaded0 = get_trace_data(),
+ WasLoaded1 = [M || {code,ensure_loaded,[M]} <- WasLoaded0],
+ WasLoaded = ordsets:from_list(WasLoaded1),
+
+ %% Check for modules that should have been pre-loaded.
+ case ordsets:subtract(WasLoaded, PreLoaded) of
+ [] ->
+ ok;
+ [_|_]=NotPreLoaded ->
+ io:format("The following modules were used "
+ "but not pre-loaded:\n~p\n",
+ [NotPreLoaded]),
+ ?t:fail({not_preload,NotPreLoaded})
+ end,
+
+ %% Check for modules that should not be pre-loaded.
+ case ordsets:subtract(PreLoaded, WasLoaded) of
+ [] ->
+ ok;
+ [_|_]=NotUsed ->
+ io:format("The following modules were pre-loaded"
+ " but not used:\n~p\n",
+ [NotUsed]),
+ ?t:fail({not_used,NotUsed})
+ end,
+
+ ok.
+
+get_trace_data() ->
+ %% Apparantely, doing a receive at the beginning of
+ %% a traced function can cause extra trace messages.
+ %% To avoid that, don't do the receive in this function.
+ do_get_trace_data().
+
+do_get_trace_data() ->
+ receive
+ {trace_data,Data} -> Data
+ end.
+
+pre_load_trace({trace,Pid,call,{?MODULE,get_trace_data,[]}}, Acc) ->
+ Pid ! {trace_data,Acc},
+ [];
+pre_load_trace({trace,_,call,MFA}, Acc) ->
+ [MFA|Acc].
+
+compiler_modules() ->
+ Wc = filename:join([code:lib_dir(compiler),"ebin","*.beam"]),
+ Ms = filelib:wildcard(Wc),
+ FN = filename,
+ [list_to_atom(FN:rootname(FN:basename(M), ".beam")) || M <- Ms].
+
%%%
%%% Utilities.
%%%
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index d207dc15bb..154374cd8c 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1453,16 +1453,37 @@ behave([H|T]) ->
behave([]) ->
[].
-%%______________________________________________________________________
-%% mandatory modules; this modules must be loaded before processes
-%% can be started. These are a collection of modules from the kernel
-%% and stdlib applications.
-%% Nowadays, error_handler dynamically loads almost every module.
-%% The error_handler self must still be there though.
-
mandatory_modules() ->
- %% Sorted
- [error_handler].
+ [error_handler, %Truly mandatory.
+
+ %% Modules that are almost always needed. Listing them here
+ %% helps the init module to load them faster. Modules not
+ %% listed here will be loaded by the error_handler module.
+ %%
+ %% Keep this list sorted.
+ application,
+ application_controller,
+ application_master,
+ code,
+ code_server,
+ erl_eval,
+ erl_lint,
+ erl_parse,
+ error_logger,
+ ets,
+ file,
+ filename,
+ file_server,
+ file_io_server,
+ gen,
+ gen_event,
+ gen_server,
+ heart,
+ kernel,
+ lists,
+ proc_lib,
+ supervisor
+ ].
%%______________________________________________________________________
%% This is the modules that are preloaded into the Erlang system.