1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1999-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(multi_load_SUITE). 22-export([all/0, suite/0, many/1, on_load/1, errors/1]). 23 24-include_lib("common_test/include/ct.hrl"). 25 26suite() -> 27 [{ct_hooks,[ts_install_cth]}]. 28 29all() -> 30 [many,on_load,errors]. 31 32many(_Config) -> 33 34 N = case erlang:system_info(build_type) of 35 valgrind -> 36 10; 37 _ -> 38 100 39 end, 40 41 Ms = make_modules(N, fun many_module/1), 42 43 io:put_chars("Light load\n" 44 "=========="), 45 many_measure(Ms), 46 47 _ = [spawn_link(fun many_worker/0) || _ <- lists:seq(1, 8)], 48 erlang:yield(), 49 io:put_chars("Heavy load\n" 50 "=========="), 51 many_measure(Ms), 52 ok. 53 54many_module(M) -> 55 ["-module("++M++").", 56 "-compile(export_all).", 57 "f1() -> ok.", 58 "f2() -> ok.", 59 "f3() -> ok.", 60 "f4() -> ok."]. 61 62many_measure(Ms) -> 63 many_purge(Ms), 64 MsPrep1 = prepare_modules(Ms), 65 Us1 = ms(fun() -> many_load_seq(MsPrep1) end), 66 many_try_call(Ms), 67 many_purge(Ms), 68 MsPrep2 = prepare_modules(Ms), 69 Us2 = ms(fun() -> many_load_par(MsPrep2) end), 70 many_try_call(Ms), 71 io:format("# modules: ~9w\n" 72 "Sequential: ~9w µs\n" 73 "Parallel: ~9w µs\n" 74 "Ratio: ~9w\n", 75 [length(Ms),Us1,Us2,divide(Us1,Us2)]), 76 ok. 77 78divide(A,B) when B > 0 -> A div B; 79divide(_,_) -> inf. 80 81many_load_seq(Ms) -> 82 [erlang:finish_loading([M]) || M <- Ms], 83 ok. 84 85many_load_par(Ms) -> 86 erlang:finish_loading(Ms). 87 88many_purge(Ms) -> 89 _ = [catch erlang:purge_module(M) || {M,_} <- Ms], 90 ok. 91 92many_try_call(Ms) -> 93 _ = [begin 94 ok = M:f1(), 95 ok = M:f2(), 96 ok = M:f3(), 97 ok = M:f4() 98 end || {M,_} <- Ms], 99 ok. 100 101many_worker() -> 102 many_worker(lists:seq(1, 100)). 103 104many_worker(L) -> 105 N0 = length(L), 106 N1 = N0 * N0 * N0, 107 N2 = N1 div (N0 * N0), 108 N3 = N2 + 10, 109 _ = N3 - 10, 110 many_worker(L). 111 112 113on_load(_Config) -> 114 On = make_modules(2, fun on_load_module/1), 115 OnPrep = prepare_modules(On), 116 {'EXIT',{system_limit,_}} = (catch erlang:finish_loading(OnPrep)), 117 118 Normal = make_modules(1, fun on_load_normal/1), 119 Mixed = Normal ++ tl(On), 120 MixedPrep = prepare_modules(Mixed), 121 {'EXIT',{system_limit,_}} = (catch erlang:finish_loading(MixedPrep)), 122 123 [false,true] = [erlang:has_prepared_code_on_load(Code) || 124 Code <- MixedPrep], 125 {'EXIT',{badarg,_}} = (catch erlang:has_prepared_code_on_load(<<1,2,3>>)), 126 Magic = ets:match_spec_compile([{'_',[true],['$_']}]), 127 {'EXIT',{badarg,_}} = (catch erlang:has_prepared_code_on_load(Magic)), 128 129 SingleOnPrep = tl(OnPrep), 130 {on_load,[OnLoadMod]} = erlang:finish_loading(SingleOnPrep), 131 ok = erlang:call_on_load_function(OnLoadMod), 132 ok. 133 134on_load_module(M) -> 135 ["-module("++M++").", 136 "-on_load(f/0).", 137 "f() -> ok."]. 138 139on_load_normal(M) -> 140 ["-module("++M++")."]. 141 142 143errors(_Config) -> 144 finish_loading_badarg(x), 145 finish_loading_badarg([x|y]), 146 finish_loading_badarg([x]), 147 finish_loading_badarg([<<>>]), 148 149 Mods = make_modules(2, fun errors_module/1), 150 Ms = lists:sort([M || {M,_} <- Mods]), 151 Prep = prepare_modules(Mods), 152 {duplicated,Dups} = erlang:finish_loading(Prep ++ Prep), 153 Ms = lists:sort(Dups), 154 ok. 155 156finish_loading_badarg(Arg) -> 157 {'EXIT',{badarg,[{erlang,finish_loading,[Arg],_}|_]}} = 158 (catch erlang:finish_loading(Arg)). 159 160errors_module(M) -> 161 ["-module("++M++").", 162 "-export([f/0]).", 163 "f() -> ok."]. 164 165%%% 166%%% Common utilities 167%%% 168 169ms(Fun) -> 170 {Ms,ok} = timer:tc(Fun), 171 Ms. 172 173make_modules(0, _) -> 174 []; 175make_modules(N, Fun) -> 176 U = erlang:unique_integer([positive]), 177 M0 = "m__" ++ integer_to_list(N) ++ "_" ++ integer_to_list(U), 178 Contents = Fun(M0), 179 Forms = [make_form(S) || S <- Contents], 180 {ok,M,Code} = compile:forms(Forms), 181 [{M,Code}|make_modules(N-1, Fun)]. 182 183make_form(S) -> 184 {ok,Toks,_} = erl_scan:string(S), 185 {ok,Form} = erl_parse:parse_form(Toks), 186 Form. 187 188prepare_modules(Ms) -> 189 [erlang:prepare_loading(M, Code) || {M,Code} <- Ms]. 190