Manually clean up paths

Using code:set_path/1 with very large paths is very slow on larger
projects.  On my mid-sized project, it seems to take around .4s per
call.  Emulating the call with direct path removal (using
code:del_path/1) seems to be quite a lot faster.
This commit is contained in:
Evan Vigil-McClanahan 2014-08-15 17:21:00 -07:00
parent e9f62c4580
commit ba466e2d38
9 changed files with 81 additions and 10 deletions

View file

@ -67,7 +67,7 @@ doc(Config, File) ->
end,
%% Restore code path
true = code:set_path(CodePath),
true = rebar_utils:cleanup_code_path(CodePath),
{ok, Config1}.
%% ===================================================================

View file

@ -355,7 +355,7 @@ doterl_compile(Config, OutDir, MoreSources, ErlOpts) ->
fun(S, C) ->
internal_erl_compile(C, S, OutDir1, ErlOpts, G)
end),
true = code:set_path(CurrPath),
true = rebar_utils:cleanup_code_path(CurrPath),
ok.
%%

View file

@ -123,7 +123,7 @@ compile(Config, _AppFile) ->
{recursive, option(recursive, DtlOpts)}])
end, ok, MultiDtlOpts),
true = code:set_path(OrigPath),
true = rebar_utils:cleanup_code_path(OrigPath),
Result.
%% ===================================================================

View file

@ -89,7 +89,7 @@ eunit(Config, _AppFile) ->
?EUNIT_DIR),
case CompileOnly of
"true" ->
true = code:set_path(CodePath),
true = rebar_utils:cleanup_code_path(CodePath),
?CONSOLE("Compiled modules for eunit~n", []);
false ->
run_eunit(Config, CodePath, SrcErls)
@ -192,7 +192,7 @@ run_eunit(Config, CodePath, SrcErls) ->
end,
%% Restore code path
true = code:set_path(CodePath),
true = rebar_utils:cleanup_code_path(CodePath),
ok.
ensure_dirs() ->

View file

@ -161,7 +161,7 @@ run(Config, QC, QCOpts) ->
case CompileOnly of
"true" ->
true = code:set_path(CodePath),
true = rebar_utils:cleanup_code_path(CodePath),
?CONSOLE("Compiled modules for qc~n", []);
false ->
run1(QC, QCOpts, Config, CodePath, SrcErls)
@ -187,7 +187,7 @@ run1(QC, QCOpts, Config, CodePath, SrcErls) ->
rebar_cover_utils:close(CoverLog),
ok = rebar_cover_utils:exit(),
true = code:set_path(CodePath),
true = rebar_utils:cleanup_code_path(CodePath),
case QCResult of
[] ->

View file

@ -75,7 +75,7 @@
ok = cleanup(NameVer),
%% Restore original path
true = code:set_path(OrigPath),
true = rebar_utils:cleanup_code_path(OrigPath),
{ok, Config}.

View file

@ -64,7 +64,8 @@
base_dir/1,
processing_base_dir/1,
processing_base_dir/2,
patch_env/2]).
patch_env/2,
cleanup_code_path/1]).
%% for internal use only
-export([otp_release/0]).
@ -603,3 +604,17 @@ filter_defines([{platform_define, ArchRegex, Key, Value} | Rest], Acc) ->
end;
filter_defines([Opt | Rest], Acc) ->
filter_defines(Rest, [Opt | Acc]).
cleanup_code_path(OrigPath) ->
CurrentPath = code:get_path(),
AddedPaths = CurrentPath -- OrigPath,
%% If someone has removed paths, it's hard to get them back into
%% the right order, but since this is currently rare, we can just
%% fall back to code:set_path/1.
case CurrentPath -- AddedPaths of
OrigPath ->
_ = [code:del_path(Path) || Path <- AddedPaths],
true;
_ ->
code:set_path(OrigPath)
end.

View file

@ -80,7 +80,7 @@ xref(Config, _) ->
QueryNoWarn = lists:all(fun check_query/1, QueryChecks),
%% Restore the original code path
true = code:set_path(OrigPath),
true = rebar_utils:cleanup_code_path(OrigPath),
%% Stop xref
stopped = xref:stop(xref),

View file

@ -325,6 +325,62 @@ basic_setup_test_() ->
["test/myapp_mymod_tests.erl",
"src/myapp_mymod.erl"])}.
code_path_test_() ->
[{"Ensuring that fast code path cleanup is correct for adds",
setup, fun make_tmp_dir/0,
fun(_) -> remove_tmp_dir() end,
fun() ->
OPath = code:get_path(),
PathZ = ?TMP_DIR ++ "some_path",
PathA = ?TMP_DIR ++ "some_other_path",
ok = file:make_dir(PathZ),
ok = file:make_dir(PathA),
true = code:add_pathz(PathZ),
true = code:add_patha(PathA),
%% make sure that they've been added
?assertEqual([PathA] ++ OPath ++ [PathZ],
code:get_path()),
true = rebar_utils:cleanup_code_path(OPath),
?assertEqual(OPath, code:get_path())
end},
{"Ensuring that fast code path cleanup is correct for removes",
setup, fun make_tmp_dir/0,
fun(_) -> remove_tmp_dir() end,
fun() ->
OPath = code:get_path(),
Path1 = lists:nth(10, OPath),
Path2 = lists:nth(11, OPath),
true = code:del_path(Path1),
true = code:del_path(Path2),
%% make sure that they've been added
?assertEqual(OPath -- [Path1, Path2],
code:get_path()),
true = rebar_utils:cleanup_code_path(OPath),
?assertEqual(OPath, code:get_path())
end},
{"Ensuring that fast code path cleanup is equivalent for adds",
setup, fun make_tmp_dir/0,
fun(_) -> remove_tmp_dir() end,
fun() ->
OPath = code:get_path(),
PathZ = ?TMP_DIR ++ "some_path",
PathA = ?TMP_DIR ++ "some_other_path",
ok = file:make_dir(PathZ),
ok = file:make_dir(PathA),
true = code:add_pathz(PathZ),
true = code:add_patha(PathA),
%% make sure that they've been added
?assertEqual([PathA] ++ OPath ++ [PathZ],
code:get_path()),
true = rebar_utils:cleanup_code_path(OPath),
CleanedPath = code:get_path(),
true = code:add_pathz(PathZ),
true = code:add_patha(PathA),
true = code:set_path(OPath),
?assertEqual(CleanedPath, code:get_path())
end}].
%% ====================================================================
%% Setup and Teardown
%% ====================================================================