diff options
author | Björn Gustavsson <[email protected]> | 2015-12-16 14:50:56 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2015-12-16 15:52:26 +0100 |
commit | af9bfce55f0df03edaab638dcd3612c8478dfcc9 (patch) | |
tree | 9433741c63c6324b86faf7d9417f1a413d3d6aaf | |
parent | 471d2408de06f3c93507769ce0eb0a9f42c3d119 (diff) | |
download | otp-af9bfce55f0df03edaab638dcd3612c8478dfcc9.tar.gz otp-af9bfce55f0df03edaab638dcd3612c8478dfcc9.tar.bz2 otp-af9bfce55f0df03edaab638dcd3612c8478dfcc9.zip |
Remove erl_prim_loader:get_files/2
erl_prim_loader:get_files/2 was an optimization introduced before the
SMP emulator (that is, before R11). The idea was to use the async
threads in the efile driver to read multiple BEAM files from the disk
in parallel.
In a modern computer with the SMP emulator, loading a BEAM module
seems to be more time-consuming than reading it from disk. To optimize
loading we would need to load several modules in parallel. We could
modify get_files/2 so that it would support parallel loading, but it
is cleaner to first remove get_files/2 and then (in a future commit),
introduce new functions to support parallel loading.
-rw-r--r-- | erts/preloaded/src/erl_prim_loader.erl | 76 | ||||
-rw-r--r-- | erts/preloaded/src/init.erl | 51 |
2 files changed, 6 insertions, 121 deletions
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 07c439a990..a8d1e4df76 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -42,7 +42,7 @@ -include("inet_boot.hrl"). %% Public --export([start/3, set_path/1, get_path/0, get_file/1, get_files/2, +-export([start/3, set_path/1, get_path/0, get_file/1, list_dir/1, read_file_info/1, read_link_info/1, get_cwd/0, get_cwd/1]). %% Used by erl_boot_server @@ -69,7 +69,6 @@ timeout :: timeout(), % idle timeout %% Number of timeouts before archives are released n_timeouts :: non_neg_integer(), - multi_get = false :: boolean(), prim_state :: prim_state()}). % state for efile code loader -define(IDLE_TIMEOUT, 60000). %% tear inet connection after 1 minutes @@ -162,16 +161,11 @@ start_it("efile", Id, Pid, _Hosts) -> _ -> init_ack(Pid) end, - MultiGet = case erlang:system_info(thread_pool_size) of - 0 -> false; - _ -> true - end, PS = prim_init(), State = #state {loader = efile, id = Id, data = Port, timeout = infinity, - multi_get = MultiGet, prim_state = PS}, loop(State, Pid, []). @@ -198,20 +192,6 @@ get_file(File) when is_atom(File) -> get_file(File) -> check_file_result(get_file, File, request({get_file,File})). --spec get_files([{atom(), string()}], - fun((atom(),binary(),string()) -> 'ok' | {'error', atom()})) -> - 'ok' | {'error', atom()}. -get_files(ModFiles, Fun) -> - case request({get_files,{ModFiles,Fun}}) of - E = {error,_M} -> - E; - {error,Reason,M} -> - check_file_result(get_files, M, {error,Reason}), - {error,M}; - ok -> - ok - end. - -spec list_dir(Dir) -> {'ok', Filenames} | 'error' when Dir :: string(), Filenames :: [Filename :: string()]. @@ -344,8 +324,6 @@ handle_request(Req, Paths, St0) -> {{ok,Paths},St0}; {get_file,File} -> handle_get_file(St0, Paths, File); - {get_files,{ModFiles,Fun}} -> - handle_get_files(St0, ModFiles, Paths, Fun); {list_dir,Dir} -> handle_list_dir(St0, Dir); {read_file_info,File} -> @@ -365,11 +343,6 @@ handle_request(Req, Paths, St0) -> ignore end. -handle_get_files(State = #state{multi_get = true}, ModFiles, Paths, Fun) -> - ?SAFE2(efile_multi_get_file_from_port(State, ModFiles, Paths, Fun), State); -handle_get_files(State, _ModFiles, _Paths, _Fun) -> % no multi get - {{error,no_multi_get},State}. - handle_get_file(State = #state{loader = efile}, Paths, File) -> ?SAFE2(efile_get_file_from_port(State, File, Paths), State); handle_get_file(State = #state{loader = inet}, Paths, File) -> @@ -420,53 +393,6 @@ handle_timeout(State = #state{loader = inet}, Parent) -> %%% Functions which handle efile as prim_loader (default). %%% -------------------------------------------------------- -%%% Reading many files in parallel is an optimization. -%%% See also comment in init.erl. - -%% -> {ok,State} | {{error,Module},State} | {{error,Reason,Module},State} -efile_multi_get_file_from_port(State, ModFiles, Paths, Fun) -> - Ref = make_ref(), - %% More than 200 processes is no gain. - Max = erlang:min(200, erlang:system_info(thread_pool_size)), - efile_multi_get_file_from_port2(ModFiles, 0, Max, State, Paths, Fun, Ref, ok). - -efile_multi_get_file_from_port2([MF | MFs], Out, Max, State, Paths, Fun, Ref, Ret) when Out < Max -> - Self = self(), - _Pid = spawn(fun() -> efile_par_get_file(Ref, State, MF, Paths, Self, Fun) end), - efile_multi_get_file_from_port2(MFs, Out+1, Max, State, Paths, Fun, Ref, Ret); -efile_multi_get_file_from_port2(MFs, Out, Max, _State, Paths, Fun, Ref, Ret) when Out > 0 -> - receive - {Ref, ok, State1} -> - efile_multi_get_file_from_port2(MFs, Out-1, Max, State1, Paths, Fun, Ref, Ret); - {Ref, {error,_Mod} = Error, State1} -> - efile_multi_get_file_from_port2(MFs, Out-1, Max, State1, Paths, Fun, Ref, Error); - {Ref, MF, {error,emfile,State1}} -> - %% Max can take negative values. Out cannot. - efile_multi_get_file_from_port2([MF | MFs], Out-1, Max-1, State1, Paths, Fun, Ref, Ret); - {Ref, {M,_F}, {error,Error,State1}} -> - efile_multi_get_file_from_port2(MFs, Out-1, 0, State1, Paths, Fun, Ref, {error,Error,M}) - end; -efile_multi_get_file_from_port2(_MFs, 0, _Max, State, _Paths, _Fun, _Ref, Ret) -> - {Ret,State}. - -efile_par_get_file(Ref, State, {Mod,File} = MF, Paths, Pid, Fun) -> - %% One port for each file read in "parallel": - case prim_file:start() of - {ok, Port} -> - Port0 = State#state.data, - State1 = State#state{data = Port}, - R = case efile_get_file_from_port(State1, File, Paths) of - {{error,Reason},State2} -> - {Ref,MF,{error,Reason,State2}}; - {{ok,BinFile,Full},State2} -> - %% Fun(...) -> ok | {error,Mod} - {Ref,Fun(Mod, BinFile, Full),State2#state{data=Port0}} - end, - prim_file:close(Port), - Pid ! R; - {error, Error} -> - Pid ! {Ref,MF,{error,Error,State}} - end. %% -> {{ok,BinFile,File},State} | {{error,Reason},State} efile_get_file_from_port(State, File, Paths) -> diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index cc30999ba5..b5c1d46e60 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -85,7 +85,6 @@ path_choice, prim_load, load_mode, - par_load, vars }). @@ -749,13 +748,11 @@ do_boot(Init,Flags,Start) -> Deb = b2a(get_flag(init_debug, Flags, false)), catch ?ON_LOAD_HANDLER ! {init_debug_flag,Deb}, BootVars = get_boot_vars(Root, Flags), - ParLoad = Pgm =:= "efile" andalso - erlang:system_info(thread_pool_size) > 0, PathChoice = code_path_choice(), Es = #es{init=Init,debug=Deb,path=Path,pa=Pa,pz=Pz, path_choice=PathChoice, - prim_load=true,load_mode=LoadMode,par_load=ParLoad, + prim_load=true,load_mode=LoadMode, vars=BootVars}, eval_script(BootList, Es), @@ -857,15 +854,12 @@ eval_script([{kernel_load_completed}|T], #es{load_mode=Mode}=Es0) -> _ -> Es0#es{prim_load=false} end, eval_script(T, Es); -eval_script([{primLoad,Mods}|T], #es{init=Init,prim_load=PrimLoad, - par_load=Par}=Es) +eval_script([{primLoad,Mods}|T], #es{prim_load=PrimLoad}=Es) when is_list(Mods) -> - case {PrimLoad,Par} of - {true,true} -> - par_load_modules(Mods, Init); - {true,false} -> + case PrimLoad of + true -> load_modules(Mods); - {false,_} -> + false -> %% Do not load now, code_server does that dynamically! ok end, @@ -892,41 +886,6 @@ load_modules([Mod|Mods]) -> load_modules([]) -> ok. -%%% An optimization: erl_prim_loader gets the chance of loading many -%%% files in parallel, using threads. This will reduce the seek times, -%%% and loaded code can be processed while other threads are waiting -%%% for the disk. The optimization is not tried unless the loader is -%%% "efile" and there is a non-empty pool of threads. -%%% -%%% Many threads are needed to get a good result, so it would be -%%% beneficial to load several applications in parallel. However, -%%% measurements show that the file system handles one directory at a -%%% time, regardless if parallel threads are created for files on -%%% several directories (a guess: writing the meta information when -%%% the file was last read ('mtime'), forces the file system to sync -%%% between directories). - -par_load_modules(Mods,Init) -> - Ext = objfile_extension(), - ModFiles = [{Mod,concat([Mod,Ext])} || Mod <- Mods, - not erlang:module_loaded(Mod)], - Self = self(), - Fun = fun(Mod, BinCode, FullName) -> - case catch load_mod_code(Mod, BinCode, FullName) of - {ok, _} -> - Init ! {Self,loaded,{Mod,FullName}}, - ok; - _EXIT -> - {error, Mod} - end - end, - case erl_prim_loader:get_files(ModFiles, Fun) of - ok -> - ok; - {error,Mod} -> - exit({'cannot load',Mod,get_files}) - end. - make_path(Pa, Pz, Path, Vars) -> append([Pa,append([fix_path(Path,Vars),Pz])]). |