diff options
| -rw-r--r-- | src/rabbit.erl | 103 | ||||
| -rw-r--r-- | src/rabbit_hipe.erl | 98 |
2 files changed, 102 insertions, 99 deletions
diff --git a/src/rabbit.erl b/src/rabbit.erl index 8d5dbb0260..2acffca97f 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -194,11 +194,6 @@ -define(APPS, [os_mon, mnesia, rabbit_common, rabbit]). -%% HiPE compilation uses multiple cores anyway, but some bits are -%% IO-bound so we can go faster if we parallelise a bit more. In -%% practice 2 processes seems just as fast as any other number > 1, -%% and keeps the progress bar realistic-ish. --define(HIPE_PROCESSES, 2). -define(ASYNC_THREADS_WARNING_THRESHOLD, 8). %%---------------------------------------------------------------------------- @@ -248,96 +243,6 @@ %%---------------------------------------------------------------------------- -%% HiPE compilation happens before we have log handlers - so we have -%% to io:format/2, it's all we can do. - -maybe_hipe_compile() -> - {ok, Want} = application:get_env(rabbit, hipe_compile), - Can = code:which(hipe) =/= non_existing, - case {Want, Can} of - {true, true} -> hipe_compile(); - {true, false} -> false; - {false, _} -> {ok, disabled} - end. - -log_hipe_result({ok, disabled}) -> - ok; -log_hipe_result({ok, already_compiled}) -> - rabbit_log:info( - "HiPE in use: modules already natively compiled.~n", []); -log_hipe_result({ok, Count, Duration}) -> - rabbit_log:info( - "HiPE in use: compiled ~B modules in ~Bs.~n", [Count, Duration]); -log_hipe_result(false) -> - io:format( - "~nNot HiPE compiling: HiPE not found in this Erlang installation.~n"), - rabbit_log:warning( - "Not HiPE compiling: HiPE not found in this Erlang installation.~n"). - -%% HiPE compilation happens before we have log handlers and can take a -%% long time, so make an exception to our no-stdout policy and display -%% progress via stdout. -hipe_compile() -> - {ok, HipeModulesAll} = application:get_env(rabbit, hipe_modules), - HipeModules = [HM || HM <- HipeModulesAll, - code:which(HM) =/= non_existing andalso - %% We skip modules already natively compiled. This - %% happens when RabbitMQ is stopped (just the - %% application, not the entire node) and started - %% again. - already_hipe_compiled(HM)], - case HipeModules of - [] -> {ok, already_compiled}; - _ -> do_hipe_compile(HipeModules) - end. - -already_hipe_compiled(Mod) -> - try - %% OTP 18.x or later - Mod:module_info(native) =:= false - %% OTP prior to 18.x - catch error:badarg -> - code:is_module_native(Mod) =:= false - end. - -do_hipe_compile(HipeModules) -> - Count = length(HipeModules), - io:format("~nHiPE compiling: |~s|~n |", - [string:copies("-", Count)]), - T1 = time_compat:monotonic_time(), - %% We use code:get_object_code/1 below to get the beam binary, - %% instead of letting hipe get it itself, because hipe:c/{1,2} - %% expects the given filename to actually exist on disk: it does not - %% work with an EZ archive (rabbit_common is one). - %% - %% Then we use the mode advanced hipe:compile/4 API because the - %% simpler hipe:c/3 is not exported (as of Erlang 18.1.4). This - %% advanced API does not load automatically the code, except if the - %% 'load' option is set. - PidMRefs = [spawn_monitor(fun () -> [begin - {M, Beam, _} = - code:get_object_code(M), - {ok, _} = - hipe:compile(M, [], Beam, - [o3, load]), - io:format("#") - end || M <- Ms] - end) || - Ms <- split(HipeModules, ?HIPE_PROCESSES)], - [receive - {'DOWN', MRef, process, _, normal} -> ok; - {'DOWN', MRef, process, _, Reason} -> exit(Reason) - end || {_Pid, MRef} <- PidMRefs], - T2 = time_compat:monotonic_time(), - Duration = time_compat:convert_time_unit(T2 - T1, native, seconds), - io:format("|~n~nCompiled ~B modules in ~Bs~n", [Count, Duration]), - {ok, Count, Duration}. - -split(L, N) -> split0(L, [[] || _ <- lists:seq(1, N)]). - -split0([], Ls) -> Ls; -split0([I | Is], [L | Ls]) -> split0(Is, Ls ++ [[I | L]]). - ensure_application_loaded() -> %% We end up looking at the rabbit app's env for HiPE and log %% handling, so it needs to be loaded. But during the tests, it @@ -352,9 +257,9 @@ start() -> %% We do not want to upgrade mnesia after just %% restarting the app. ok = ensure_application_loaded(), - HipeResult = maybe_hipe_compile(), + HipeResult = rabbit_hipe:maybe_hipe_compile(), ok = ensure_working_log_handlers(), - log_hipe_result(HipeResult), + rabbit_hipe:log_hipe_result(HipeResult), rabbit_node_monitor:prepare_cluster_status_files(), rabbit_mnesia:check_cluster_consistency(), broker_start() @@ -363,9 +268,9 @@ start() -> boot() -> start_it(fun() -> ok = ensure_application_loaded(), - HipeResult = maybe_hipe_compile(), + HipeResult = rabbit_hipe:maybe_hipe_compile(), ok = ensure_working_log_handlers(), - log_hipe_result(HipeResult), + rabbit_hipe:log_hipe_result(HipeResult), rabbit_node_monitor:prepare_cluster_status_files(), ok = rabbit_upgrade:maybe_upgrade_mnesia(), %% It's important that the consistency check happens after diff --git a/src/rabbit_hipe.erl b/src/rabbit_hipe.erl new file mode 100644 index 0000000000..0302d82839 --- /dev/null +++ b/src/rabbit_hipe.erl @@ -0,0 +1,98 @@ +-module(rabbit_hipe). + +%% HiPE compilation uses multiple cores anyway, but some bits are +%% IO-bound so we can go faster if we parallelise a bit more. In +%% practice 2 processes seems just as fast as any other number > 1, +%% and keeps the progress bar realistic-ish. +-define(HIPE_PROCESSES, 2). +-export([maybe_hipe_compile/0, log_hipe_result/1]). + +%% HiPE compilation happens before we have log handlers - so we have +%% to io:format/2, it's all we can do. + +maybe_hipe_compile() -> + {ok, Want} = application:get_env(rabbit, hipe_compile), + Can = code:which(hipe) =/= non_existing, + case {Want, Can} of + {true, true} -> hipe_compile(); + {true, false} -> false; + {false, _} -> {ok, disabled} + end. + +log_hipe_result({ok, disabled}) -> + ok; +log_hipe_result({ok, already_compiled}) -> + rabbit_log:info( + "HiPE in use: modules already natively compiled.~n", []); +log_hipe_result({ok, Count, Duration}) -> + rabbit_log:info( + "HiPE in use: compiled ~B modules in ~Bs.~n", [Count, Duration]); +log_hipe_result(false) -> + io:format( + "~nNot HiPE compiling: HiPE not found in this Erlang installation.~n"), + rabbit_log:warning( + "Not HiPE compiling: HiPE not found in this Erlang installation.~n"). + +%% HiPE compilation happens before we have log handlers and can take a +%% long time, so make an exception to our no-stdout policy and display +%% progress via stdout. +hipe_compile() -> + {ok, HipeModulesAll} = application:get_env(rabbit, hipe_modules), + HipeModules = [HM || HM <- HipeModulesAll, + code:which(HM) =/= non_existing andalso + %% We skip modules already natively compiled. This + %% happens when RabbitMQ is stopped (just the + %% application, not the entire node) and started + %% again. + already_hipe_compiled(HM)], + case HipeModules of + [] -> {ok, already_compiled}; + _ -> do_hipe_compile(HipeModules) + end. + +already_hipe_compiled(Mod) -> + try + %% OTP 18.x or later + Mod:module_info(native) =:= false + %% OTP prior to 18.x + catch error:badarg -> + code:is_module_native(Mod) =:= false + end. + +do_hipe_compile(HipeModules) -> + Count = length(HipeModules), + io:format("~nHiPE compiling: |~s|~n |", + [string:copies("-", Count)]), + T1 = time_compat:monotonic_time(), + %% We use code:get_object_code/1 below to get the beam binary, + %% instead of letting hipe get it itself, because hipe:c/{1,2} + %% expects the given filename to actually exist on disk: it does not + %% work with an EZ archive (rabbit_common is one). + %% + %% Then we use the mode advanced hipe:compile/4 API because the + %% simpler hipe:c/3 is not exported (as of Erlang 18.1.4). This + %% advanced API does not load automatically the code, except if the + %% 'load' option is set. + PidMRefs = [spawn_monitor(fun () -> [begin + {M, Beam, _} = + code:get_object_code(M), + {ok, _} = + hipe:compile(M, [], Beam, + [o3, load]), + io:format("#") + end || M <- Ms] + end) || + Ms <- split(HipeModules, ?HIPE_PROCESSES)], + [receive + {'DOWN', MRef, process, _, normal} -> ok; + {'DOWN', MRef, process, _, Reason} -> exit(Reason) + end || {_Pid, MRef} <- PidMRefs], + T2 = time_compat:monotonic_time(), + Duration = time_compat:convert_time_unit(T2 - T1, native, seconds), + io:format("|~n~nCompiled ~B modules in ~Bs~n", [Count, Duration]), + {ok, Count, Duration}. + +split(L, N) -> split0(L, [[] || _ <- lists:seq(1, N)]). + +split0([], Ls) -> Ls; +split0([I | Is], [L | Ls]) -> split0(Is, Ls ++ [[I | L]]). |
