%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(multi_load_SUITE). -export([all/0, suite/0, many/1, on_load/1, errors/1]). -include_lib("common_test/include/ct.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [many,on_load,errors]. many(_Config) -> N = case erlang:system_info(build_type) of valgrind -> 10; _ -> 100 end, Ms = make_modules(N, fun many_module/1), io:put_chars("Light load\n" "=========="), many_measure(Ms), _ = [spawn_link(fun many_worker/0) || _ <- lists:seq(1, 8)], erlang:yield(), io:put_chars("Heavy load\n" "=========="), many_measure(Ms), ok. many_module(M) -> ["-module("++M++").", "-compile(export_all).", "f1() -> ok.", "f2() -> ok.", "f3() -> ok.", "f4() -> ok."]. many_measure(Ms) -> many_purge(Ms), MsPrep1 = prepare_modules(Ms), Us1 = ms(fun() -> many_load_seq(MsPrep1) end), many_try_call(Ms), many_purge(Ms), MsPrep2 = prepare_modules(Ms), Us2 = ms(fun() -> many_load_par(MsPrep2) end), many_try_call(Ms), io:format("# modules: ~9w\n" "Sequential: ~9w µs\n" "Parallel: ~9w µs\n" "Ratio: ~9w\n", [length(Ms),Us1,Us2,divide(Us1,Us2)]), ok. divide(A,B) when B > 0 -> A div B; divide(_,_) -> inf. many_load_seq(Ms) -> [erlang:finish_loading([M]) || M <- Ms], ok. many_load_par(Ms) -> erlang:finish_loading(Ms). many_purge(Ms) -> _ = [catch erlang:purge_module(M) || {M,_} <- Ms], ok. many_try_call(Ms) -> _ = [begin ok = M:f1(), ok = M:f2(), ok = M:f3(), ok = M:f4() end || {M,_} <- Ms], ok. many_worker() -> many_worker(lists:seq(1, 100)). many_worker(L) -> N0 = length(L), N1 = N0 * N0 * N0, N2 = N1 div (N0 * N0), N3 = N2 + 10, _ = N3 - 10, many_worker(L). on_load(_Config) -> On = make_modules(2, fun on_load_module/1), OnPrep = prepare_modules(On), {'EXIT',{system_limit,_}} = (catch erlang:finish_loading(OnPrep)), Normal = make_modules(1, fun on_load_normal/1), Mixed = Normal ++ tl(On), MixedPrep = prepare_modules(Mixed), {'EXIT',{system_limit,_}} = (catch erlang:finish_loading(MixedPrep)), [false,true] = [erlang:has_prepared_code_on_load(Code) || Code <- MixedPrep], {'EXIT',{badarg,_}} = (catch erlang:has_prepared_code_on_load(<<1,2,3>>)), Magic = ets:match_spec_compile([{'_',[true],['$_']}]), {'EXIT',{badarg,_}} = (catch erlang:has_prepared_code_on_load(Magic)), SingleOnPrep = tl(OnPrep), {on_load,[OnLoadMod]} = erlang:finish_loading(SingleOnPrep), ok = erlang:call_on_load_function(OnLoadMod), ok. on_load_module(M) -> ["-module("++M++").", "-on_load(f/0).", "f() -> ok."]. on_load_normal(M) -> ["-module("++M++")."]. errors(_Config) -> finish_loading_badarg(x), finish_loading_badarg([x|y]), finish_loading_badarg([x]), finish_loading_badarg([<<>>]), Mods = make_modules(2, fun errors_module/1), Ms = lists:sort([M || {M,_} <- Mods]), Prep = prepare_modules(Mods), {duplicated,Dups} = erlang:finish_loading(Prep ++ Prep), Ms = lists:sort(Dups), ok. finish_loading_badarg(Arg) -> {'EXIT',{badarg,[{erlang,finish_loading,[Arg],_}|_]}} = (catch erlang:finish_loading(Arg)). errors_module(M) -> ["-module("++M++").", "-export([f/0]).", "f() -> ok."]. %%% %%% Common utilities %%% ms(Fun) -> {Ms,ok} = timer:tc(Fun), Ms. make_modules(0, _) -> []; make_modules(N, Fun) -> U = erlang:unique_integer([positive]), M0 = "m__" ++ integer_to_list(N) ++ "_" ++ integer_to_list(U), Contents = Fun(M0), Forms = [make_form(S) || S <- Contents], {ok,M,Code} = compile:forms(Forms), [{M,Code}|make_modules(N-1, Fun)]. make_form(S) -> {ok,Toks,_} = erl_scan:string(S), {ok,Form} = erl_parse:parse_form(Toks), Form. prepare_modules(Ms) -> [erlang:prepare_loading(M, Code) || {M,Code} <- Ms].