diff options
Diffstat (limited to 'erts/emulator/test')
-rw-r--r-- | erts/emulator/test/Makefile | 9 | ||||
-rw-r--r-- | erts/emulator/test/bs_construct_SUITE.erl | 86 | ||||
-rw-r--r-- | erts/emulator/test/bs_match_int_SUITE.erl | 71 | ||||
-rw-r--r-- | erts/emulator/test/distribution_SUITE.erl | 102 | ||||
-rw-r--r-- | erts/emulator/test/driver_SUITE.erl | 4 | ||||
-rw-r--r-- | erts/emulator/test/dump_SUITE.erl | 51 | ||||
-rw-r--r-- | erts/emulator/test/efile_SUITE.erl | 45 | ||||
-rw-r--r-- | erts/emulator/test/emulator_bench.spec | 1 | ||||
-rw-r--r-- | erts/emulator/test/erts_debug_SUITE.erl | 15 | ||||
-rw-r--r-- | erts/emulator/test/erts_test_utils.erl | 2 | ||||
-rw-r--r-- | erts/emulator/test/fun_SUITE.erl | 2 | ||||
-rw-r--r-- | erts/emulator/test/lcnt_SUITE.erl | 3 | ||||
-rw-r--r-- | erts/emulator/test/map_SUITE.erl | 92 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 42 | ||||
-rw-r--r-- | erts/emulator/test/small_SUITE.erl | 115 | ||||
-rw-r--r-- | erts/emulator/test/statistics_SUITE.erl | 43 |
16 files changed, 472 insertions, 211 deletions
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index 8c2054cb51..019af2162f 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -124,6 +124,7 @@ MODULES= \ send_term_SUITE \ sensitive_SUITE \ signal_SUITE \ + small_SUITE \ smoke_test_SUITE \ $(SOCKET_MODULES) \ statistics_SUITE \ @@ -206,14 +207,10 @@ ERL_COMPILE_FLAGS += # ---------------------------------------------------- make_emakefile: $(NO_OPT_ERL_FILES) $(NATIVE_ERL_FILES) - # This special rule can be removed when communication with R7B nodes - # is no longer supported. - $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) +compressed -o$(EBIN) \ - '*_SUITE_make' > $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) +compressed -o$(EBIN) \ $(MODULES) >> $(EMAKEFILE) - $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt $(ERL_COMPILE_FLAGS) \ - -o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE) + $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt +no_ssa_opt +no_bsm_opt \ + $(ERL_COMPILE_FLAGS) -o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +native $(ERL_COMPILE_FLAGS) \ -o$(EBIN) $(NATIVE_MODULES) >> $(EMAKEFILE) diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl index ad05cb3689..8fab4f5bc4 100644 --- a/erts/emulator/test/bs_construct_SUITE.erl +++ b/erts/emulator/test/bs_construct_SUITE.erl @@ -16,8 +16,6 @@ %% limitations under the License. %% %% %CopyrightEnd% -%% -%% Purpose : Common utilities used by several optimization passes. %% -module(bs_construct_SUITE). @@ -27,9 +25,9 @@ test1/1, test2/1, test3/1, test4/1, test5/1, testf/1, not_used/1, in_guard/1, mem_leak/1, coerce_to_float/1, bjorn/1, append_empty_is_same/1, - huge_float_field/1, huge_binary/1, system_limit/1, badarg/1, + huge_float_field/1, system_limit/1, badarg/1, copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1, - otp_7422/1, zero_width/1, bad_append/1, bs_add_overflow/1]). + otp_7422/1, zero_width/1, bad_append/1, bs_append_overflow/1]). -include_lib("common_test/include/ct.hrl"). @@ -40,9 +38,9 @@ suite() -> all() -> [test1, test2, test3, test4, test5, testf, not_used, in_guard, mem_leak, coerce_to_float, bjorn, append_empty_is_same, - huge_float_field, huge_binary, system_limit, badarg, + huge_float_field, system_limit, badarg, copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width, - bad_append, bs_add_overflow]. + bad_append, bs_append_overflow]. init_per_suite(Config) -> Config. @@ -543,56 +541,6 @@ huge_float_field(Config) when is_list(Config) -> huge_float_check({'EXIT',{system_limit,_}}) -> ok; huge_float_check({'EXIT',{badarg,_}}) -> ok. -huge_binary(Config) when is_list(Config) -> - ct:timetrap({seconds, 60}), - 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>), - garbage_collect(), - FreeMem = free_mem(), - io:format("Free memory (Mb): ~p\n", [FreeMem]), - {Shift,Return} = case free_mem() of - undefined -> - %% This test has to be inlined inside the case to - %% use a literal Shift - garbage_collect(), - id(<<0:((1 bsl 32)-1)>>), - {32,ok}; - Mb when Mb > 600 -> - garbage_collect(), - id(<<0:((1 bsl 32)-1)>>), - {32,ok}; - Mb when Mb > 300 -> - garbage_collect(), - id(<<0:((1 bsl 31)-1)>>), - {31,"Limit huge binaries to 256 Mb"}; - Mb when Mb > 200 -> - garbage_collect(), - id(<<0:((1 bsl 30)-1)>>), - {30,"Limit huge binary to 128 Mb"}; - _ -> - garbage_collect(), - id(<<0:((1 bsl 29)-1)>>), - {29,"Limit huge binary to 64 Mb"} - end, - garbage_collect(), - id(<<0:((1 bsl Shift)-1)>>), - garbage_collect(), - id(<<0:(id((1 bsl Shift)-1))>>), - garbage_collect(), - case Return of - ok -> ok; - Comment -> {comment, Comment} - end. - -%% Return the amount of free memory in Mb. -free_mem() -> - {ok,Apps} = application:ensure_all_started(os_mon), - Mem = memsup:get_system_memory_data(), - [ok = application:stop(App)||App <- Apps], - case proplists:get_value(free_memory,Mem) of - undefined -> undefined; - Val -> Val div (1024*1024) - end. - system_limit(Config) when is_list(Config) -> WordSize = erlang:system_info(wordsize), BitsPerWord = WordSize * 8, @@ -904,33 +852,37 @@ append_unit_8(Bin) -> append_unit_16(Bin) -> <<Bin/binary-unit:16,0:1>>. -%% Produce a large result of bs_add that, if cast to signed int, would overflow -%% into a negative number that fits a smallnum. -bs_add_overflow(_Config) -> +%% Test that the bs_append instruction will correctly check for +%% overflow by producing a binary whose total size would exceed the +%% maximum allowed size for a binary on a 32-bit computer. + +bs_append_overflow(_Config) -> Memsize = memsize(), io:format("Memsize = ~w Bytes~n", [Memsize]), case erlang:system_info(wordsize) of 8 -> + %% Not possible to test on a 64-bit computer. {skip, "64-bit architecture"}; _ when Memsize < (2 bsl 30) -> - {skip, "Less then 2 GB of memory"}; + {skip, "Less than 2 GB of memory"}; 4 -> - {'EXIT', {system_limit, _}} = (catch bs_add_overflow_signed()), - {'EXIT', {system_limit, _}} = (catch bs_add_overflow_unsigned()), + {'EXIT', {system_limit, _}} = (catch bs_append_overflow_signed()), + erlang:garbage_collect(), + {'EXIT', {system_limit, _}} = (catch bs_append_overflow_unsigned()), + erlang:garbage_collect(), ok end. -bs_add_overflow_signed() -> - %% Produce a large result of bs_add that, if cast to signed int, would +bs_append_overflow_signed() -> + %% Produce a large binary that, if cast to signed int, would %% overflow into a negative number that fits a smallnum. Large = <<0:((1 bsl 30)-1)>>, <<Large/bits, Large/bits, Large/bits, Large/bits, Large/bits, Large/bits, Large/bits, Large/bits, Large/bits>>. -bs_add_overflow_unsigned() -> - %% Produce a large result of bs_add that goes beyond the limit of an - %% unsigned word. This used to succeed but produced an incorrect result +bs_append_overflow_unsigned() -> + %% The following would succeed but would produce an incorrect result %% where B =:= C! A = <<0:((1 bsl 32)-8)>>, B = <<2, 3>>, diff --git a/erts/emulator/test/bs_match_int_SUITE.erl b/erts/emulator/test/bs_match_int_SUITE.erl index e913dc98b0..454e55d017 100644 --- a/erts/emulator/test/bs_match_int_SUITE.erl +++ b/erts/emulator/test/bs_match_int_SUITE.erl @@ -234,34 +234,49 @@ mml_choose(<<_A:8>>) -> single_byte_binary; mml_choose(<<_A:8,_T/binary>>) -> multi_byte_binary. match_huge_int(Config) when is_list(Config) -> - Sz = 1 bsl 27, - Bin = <<0:Sz,13:8>>, - skip_huge_int_1(Sz, Bin), - 0 = match_huge_int_1(Sz, Bin), - - %% Test overflowing the size of an integer field. - nomatch = overflow_huge_int_skip_32(Bin), - case erlang:system_info(wordsize) of - 4 -> - nomatch = overflow_huge_int_32(Bin); - 8 -> - %% An attempt will be made to allocate heap space for - %% the bignum (which will probably fail); only if the - %% allocation succeeds will the matching fail because - %% the binary is too small. - ok - end, - nomatch = overflow_huge_int_skip_64(Bin), - nomatch = overflow_huge_int_64(Bin), - - %% Test overflowing the size of an integer field using variables as sizes. - Sizes = case erlang:system_info(wordsize) of - 4 -> lists:seq(25, 32); - 8 -> [] - end ++ lists:seq(50, 64), - ok = overflow_huge_int_unit128(Bin, Sizes), - - ok. + case ?MODULE of + bs_match_int_no_opt_SUITE -> + %% This test case is written with the assumption that + %% bs_skip2 instructions are used when the value of the + %% extracted segment will not be used. In OTP 21 and earlier, that + %% assumption was always true, because the bs_skip optimization + %% was included in v3_codegen and could not be disabled. + %% In OTP 22, the bs_skip optimization is done by beam_ssa_opt + %% and is disabled. + %% + %% On memory-constrained computers, using bs_get_integer2 + %% instructions may cause the runtime system to terminate + %% because of insufficient memory. + {skip, "unoptimized code would use too much memory"}; + bs_match_int_SUITE -> + Sz = 1 bsl 27, + Bin = <<0:Sz,13:8>>, + skip_huge_int_1(Sz, Bin), + 0 = match_huge_int_1(Sz, Bin), + + %% Test overflowing the size of an integer field. + nomatch = overflow_huge_int_skip_32(Bin), + case erlang:system_info(wordsize) of + 4 -> + nomatch = overflow_huge_int_32(Bin); + 8 -> + %% An attempt will be made to allocate heap space for + %% the bignum (which will probably fail); only if the + %% allocation succeeds will the matching fail because + %% the binary is too small. + ok + end, + nomatch = overflow_huge_int_skip_64(Bin), + nomatch = overflow_huge_int_64(Bin), + + %% Test overflowing the size of an integer field using + %% variables as sizes. + Sizes = case erlang:system_info(wordsize) of + 4 -> lists:seq(25, 32); + 8 -> [] + end ++ lists:seq(50, 64), + ok = overflow_huge_int_unit128(Bin, Sizes) + end. overflow_huge_int_unit128(Bin, [Sz0|Sizes]) -> Sz = id(1 bsl Sz0), diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index b6f05efac2..7885d35d9d 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -19,7 +19,6 @@ %% -module(distribution_SUITE). --compile(r16). -define(VERSION_MAGIC, 131). @@ -40,6 +39,7 @@ -export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, ping/1, bulk_send_small/1, group_leader/1, optimistic_dflags/1, @@ -54,7 +54,6 @@ dist_parallel_send/1, atom_roundtrip/1, unicode_atom_roundtrip/1, - atom_roundtrip_r16b/1, contended_atom_cache_entry/1, contended_unicode_atom_cache_entry/1, bad_dist_structure/1, @@ -77,7 +76,7 @@ optimistic_dflags_echo/0, optimistic_dflags_sender/1, roundtrip/1, bounce/1, do_dist_auto_connect/1, inet_rpc_server/1, dist_parallel_sender/3, dist_parallel_receiver/0, - dist_evil_parallel_receiver/0]). + dist_evil_parallel_receiver/0, make_busy/2]). %% epmd_module exports -export([start_link/0, register_node/2, register_node/3, port_please/2, address_please/3]). @@ -86,22 +85,6 @@ suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap, {minutes, 4}}]. -init_per_suite(Config) -> - A0 = case application:start(sasl) of - ok -> [sasl]; - _ -> [] - end, - A = case application:start(os_mon) of - ok -> [os_mon|A0]; - _ -> A0 - end, - [{started_apps, A}|Config]. - -end_per_suite(Config) -> - As = proplists:get_value(started_apps, Config), - lists:foreach(fun (A) -> application:stop(A) end, As), - Config. - all() -> [ping, {group, bulk_send}, {group, local_send}, group_leader, @@ -111,7 +94,6 @@ all() -> ref_port_roundtrip, nil_roundtrip, stop_dist, {group, trap_bif}, {group, dist_auto_connect}, dist_parallel_send, atom_roundtrip, unicode_atom_roundtrip, - atom_roundtrip_r16b, contended_atom_cache_entry, contended_unicode_atom_cache_entry, {group, message_latency}, {group, bad_dist}, {group, bad_dist_ext}, @@ -137,6 +119,28 @@ groups() -> message_latency_large_exit2]} ]. +init_per_suite(Config) -> + {ok, Apps} = application:ensure_all_started(os_mon), + [{started_apps, Apps} | Config]. + +end_per_suite(Config) -> + Apps = proplists:get_value(started_apps, Config), + [application:stop(App) || App <- lists:reverse(Apps)], + Config. + +init_per_group(message_latency, Config) -> + Free = free_memory(), + if Free < 2048 -> + {skip, "Not enough memory"}; + true -> + Config + end; +init_per_group(_, Config) -> + Config. + +end_per_group(_, Config) -> + Config. + %% Tests pinging a node in different ways. ping(Config) when is_list(Config) -> Times = 1024, @@ -1152,23 +1156,6 @@ atom_roundtrip(Config) when is_list(Config) -> stop_node(Node), ok. -atom_roundtrip_r16b(Config) when is_list(Config) -> - case test_server:is_release_available("r16b") of - true -> - ct:timetrap({minutes, 6}), - AtomData = unicode_atom_data(), - verify_atom_data(AtomData), - case start_node(Config, [], "r16b") of - {ok, Node} -> - do_atom_roundtrip(Node, AtomData), - stop_node(Node); - {error, timeout} -> - {skip,"Unable to start OTP R16B release"} - end; - false -> - {skip,"No OTP R16B available"} - end. - unicode_atom_roundtrip(Config) when is_list(Config) -> AtomData = unicode_atom_data(), verify_atom_data(AtomData), @@ -1474,11 +1461,14 @@ measure_latency_large_message(Nodename, DataFun) -> Echo = spawn(N, fun F() -> receive {From, Msg} -> From ! Msg, F() end end), - case erlang:system_info(build_type) of - debug -> + BuildType = erlang:system_info(build_type), + WordSize = erlang:system_info(wordsize), + + if + BuildType =/= opt; WordSize =:= 4 -> %% Test 3.2 MB and 32 MB and test the latency difference of sent messages Payloads = [{I, <<0:(I * 32 * 1024 * 8)>>} || I <- [1,10]]; - _ -> + true -> %% Test 32 MB and 320 MB and test the latency difference of sent messages Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]] end, @@ -1493,7 +1483,7 @@ measure_latency_large_message(Nodename, DataFun) -> stop_node(N), case {lists:max(Times), lists:min(Times)} of - {Max, Min} when Max * 0.25 > Min -> + {Max, Min} when Max * 0.25 > Min, BuildType =:= opt -> ct:fail({incorrect_latency, IndexTimes}); _ -> ok @@ -1518,13 +1508,19 @@ measure_latency(DataFun, Dropper, Echo, Payload) -> ok end || _ <- lists:seq(1,10)], - {TS, _} = + {TS, Times} = timer:tc(fun() -> [begin + T0 = erlang:monotonic_time(), Echo ! {self(), hello}, - receive hello -> ok end + receive hello -> ok end, + (erlang:monotonic_time() - T0) / 1000000 end || _ <- lists:seq(1,100)] end), + Avg = lists:sum(Times) / length(Times), + StdDev = math:sqrt(lists:sum([math:pow(V - Avg,2) || V <- Times]) / length(Times)), + ct:pal("Times: Avg: ~p Max: ~p Min: ~p Var: ~p", + [Avg, lists:max(Times), lists:min(Times), StdDev]), [begin Sender ! die, receive @@ -3001,3 +2997,23 @@ uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> Uint band 16#ff; uint8(Uint) -> exit({badarg, uint8, [Uint]}). + +free_memory() -> + %% Free memory in MB. + try + SMD = memsup:get_system_memory_data(), + {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD), + TotFree = (Free + + case lists:keysearch(cached_memory, 1, SMD) of + {value, {cached_memory, Cached}} -> Cached; + false -> 0 + end + + case lists:keysearch(buffered_memory, 1, SMD) of + {value, {buffered_memory, Buffed}} -> Buffed; + false -> 0 + end), + TotFree div (1024*1024) + catch + error : undef -> + ct:fail({"os_mon not built"}) + end. diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index bb0f3498ab..cbed71cedd 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -998,7 +998,9 @@ chkio_test({erts_poll_info, Before}, During = get_check_io_total(erlang:system_info(check_io)), erlang:display(During), - 0 = element(1, erts_debug:get_internal_state(check_io_debug)), + [0 = element(1, erts_debug:get_internal_state(check_io_debug)) || + %% The pollset is not stable when running the fallback testcase + Test /= ?CHKIO_USE_FALLBACK_POLLSET], io:format("During test: ~p~n", [During]), chk_chkio_port(Port), case erlang:port_control(Port, ?CHKIO_STOP, "") of diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl index 3b860ebdf6..9f8ac42fa9 100644 --- a/erts/emulator/test/dump_SUITE.erl +++ b/erts/emulator/test/dump_SUITE.erl @@ -137,26 +137,43 @@ exiting_dump(Config) when is_list(Config) -> free_dump(Config) when is_list(Config) -> Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), - {ok, Node} = start_node(Config), - - Self = self(), - - Pid = spawn_link(Node, - fun() -> - Self ! ready, - receive - ok -> - unlink(Self), - exit(lists:duplicate(1000,1000)) - end - end), + {ok, NodeA} = start_node(Config), + {ok, NodeB} = start_node(Config), - true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), - [erlang:monitor(process, Pid) || _ <- lists:seq(1,10000)], - receive ready -> unlink(Pid), Pid ! ok end, + Self = self(), - rpc:call(Node, erlang, halt, ["dump"]), + PidA = spawn_link( + NodeA, + fun() -> + Self ! ready, + receive + ok -> + spawn(fun() -> + erlang:system_monitor(self(), [busy_dist_port]), + timer:sleep(5), + receive + M -> + io:format("~p",[M]), + erlang:halt("dump") + end + end), + exit(lists:duplicate(1000000,100)) + end + end), + + spawn_link(NodeB, + fun() -> + [erlang:monitor(process, PidA) || _ <- lists:seq(1,10000)], + Self ! done, + receive _ -> ok end + end), + + receive done -> ok end, + true = rpc:call(NodeA, os, putenv, ["ERL_CRASH_DUMP",Dump]), + ct:pal("~p",[rpc:call(NodeA, distribution_SUITE, make_busy, [NodeB, 1000])]), + + receive ready -> unlink(PidA), PidA ! ok end, {ok, Bin} = get_dump_when_done(Dump), diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl index 55c5343739..045b351e02 100644 --- a/erts/emulator/test/efile_SUITE.erl +++ b/erts/emulator/test/efile_SUITE.erl @@ -105,34 +105,27 @@ open_files(Name) -> %% a /proc directory), let's read some zero sized files 500 times each, while %% ensuring that response isn't empty << >> proc_zero_sized_files(Config) when is_list(Config) -> - {Type, Flavor} = os:type(), - %% Some files which exist on Linux but might be missing on other systems - Inputs = ["/proc/cpuinfo", - "/proc/meminfo", - "/proc/partitions", - "/proc/swaps", - "/proc/version", - "/proc/uptime", - %% curproc is present on freebsd - "/proc/curproc/cmdline"], - case filelib:is_dir("/proc") of - false -> {skip, "/proc not found"}; % skip the test if no /proc - _ when Type =:= unix andalso Flavor =:= sunos -> - %% SunOS has a /proc, but no zero sized special files - {skip, "sunos does not have any zero sized special files"}; - true -> - %% Take away files which do not exist in proc - Inputs1 = lists:filter(fun filelib:is_file/1, Inputs), - - %% Fail if none of mentioned files exist in /proc, did we just get - %% a normal /proc directory without any special files? - ?assertNotEqual([], Inputs1), - + TestFiles0 = [%% Some files which exist on Linux but might be missing on + %% other systems + "/proc/cpuinfo", + "/proc/meminfo", + "/proc/partitions", + "/proc/swaps", + "/proc/version", + "/proc/uptime", + %% curproc is present on FreeBSD + "/proc/curproc/cmdline"], + + TestFiles = [F || F <- TestFiles0, filelib:is_file(F)], + + case TestFiles of + [_|_] -> %% For 6 inputs and 500 attempts each this do run anywhere %% between 500 and 3000 function calls. - lists:foreach( - fun(Filename) -> do_proc_zero_sized(Filename, 500) end, - Inputs1) + [do_proc_zero_sized(F, 500) || F <- TestFiles], + ok; + [] -> + {skip, "Failed to find any known zero-sized files"} end. %% @doc Test one file N times to also trigger possible leaking fds and memory diff --git a/erts/emulator/test/emulator_bench.spec b/erts/emulator/test/emulator_bench.spec index 2a180b440c..03638bfa23 100644 --- a/erts/emulator/test/emulator_bench.spec +++ b/erts/emulator/test/emulator_bench.spec @@ -1,2 +1,3 @@ {groups,"../emulator_test",estone_SUITE,[estone_bench]}. {groups,"../emulator_test",binary_SUITE,[iolist_size_benchmarks]}. +{groups,"../emulator_test",erts_debug_SUITE,[interpreter_size_bench]}. diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl index f39dbedd8f..6798e3bf25 100644 --- a/erts/emulator/test/erts_debug_SUITE.erl +++ b/erts/emulator/test/erts_debug_SUITE.erl @@ -20,10 +20,12 @@ -module(erts_debug_SUITE). -include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). --export([all/0, suite/0, +-export([all/0, suite/0, groups/0, test_size/1,flat_size_big/1,df/1,term_type/1, - instructions/1, stack_check/1, alloc_blocks_size/1]). + instructions/1, stack_check/1, alloc_blocks_size/1, + interpreter_size_bench/1]). -export([do_alloc_blocks_size/0]). @@ -35,6 +37,15 @@ all() -> [test_size, flat_size_big, df, instructions, term_type, stack_check, alloc_blocks_size]. +groups() -> + [{interpreter_size_bench, [], [interpreter_size_bench]}]. + +interpreter_size_bench(_Config) -> + Size = erts_debug:interpreter_size(), + ct_event:notify(#event{name=benchmark_data, + data=[{value,Size}]}), + {comment,integer_to_list(Size)++" bytes"}. + test_size(Config) when is_list(Config) -> ConsCell1 = id([a|b]), ConsCell2 = id(ConsCell1), diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl index e4e00a0a16..9c9eaa70ed 100644 --- a/erts/emulator/test/erts_test_utils.erl +++ b/erts/emulator/test/erts_test_utils.erl @@ -19,7 +19,7 @@ %% -module(erts_test_utils). --compile(r16). +-compile(r20). %% %% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl index 7f6caa08f1..2cbde621ce 100644 --- a/erts/emulator/test/fun_SUITE.erl +++ b/erts/emulator/test/fun_SUITE.erl @@ -513,6 +513,8 @@ refc(Config) when is_list(Config) -> Other -> ct:fail({unexpected,Other}) end, process_flag(trap_exit, false), + %% Wait to make sure that the process has terminated completely. + receive after 1 -> ok end, {refc,3} = erlang:fun_info(F1, refc), %% Garbage collect. Only the F2 fun will be left. diff --git a/erts/emulator/test/lcnt_SUITE.erl b/erts/emulator/test/lcnt_SUITE.erl index 87b97037d6..2dbaec9942 100644 --- a/erts/emulator/test/lcnt_SUITE.erl +++ b/erts/emulator/test/lcnt_SUITE.erl @@ -187,5 +187,8 @@ remove_untoggleable_locks([]) -> []; remove_untoggleable_locks([{resource_monitors, _, _, _} | T]) -> remove_untoggleable_locks(T); +remove_untoggleable_locks([{'socket[gcnt]', _, _, _} | T]) -> + %% Global lock used by socket NIF + remove_untoggleable_locks(T); remove_untoggleable_locks([H | T]) -> [H | remove_untoggleable_locks(T)]. diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl index d0a6763fe5..9ea59e1084 100644 --- a/erts/emulator/test/map_SUITE.erl +++ b/erts/emulator/test/map_SUITE.erl @@ -17,7 +17,7 @@ %% %CopyrightEnd% %% -module(map_SUITE). --export([all/0, suite/0]). +-export([all/0, suite/0, init_per_suite/1, end_per_suite/1]). -export([t_build_and_match_literals/1, t_build_and_match_literals_large/1, t_update_literals/1, t_update_literals_large/1, @@ -84,7 +84,10 @@ %% instruction-level tests t_has_map_fields/1, y_regs/1, - badmap_17/1]). + badmap_17/1, + + %%Bugs + t_large_unequal_bins_same_hash_bug/1]). -include_lib("stdlib/include/ms_transform.hrl"). @@ -149,7 +152,26 @@ all() -> [t_build_and_match_literals, t_build_and_match_literals_large, %% instruction-level tests t_has_map_fields, y_regs, - badmap_17]. + badmap_17, + + %% Bugs + t_large_unequal_bins_same_hash_bug]. + +init_per_suite(Config) -> + A0 = case application:start(sasl) of + ok -> [sasl]; + _ -> [] + end, + A = case application:start(os_mon) of + ok -> [os_mon|A0]; + _ -> A0 + end, + [{started_apps, A}|Config]. + +end_per_suite(Config) -> + As = proplists:get_value(started_apps, Config), + lists:foreach(fun (A) -> application:stop(A) end, As), + Config. %% tests @@ -3374,3 +3396,67 @@ fannerl() -> 104,2,97,9,97,16,70,63,184,100,97,32,0,0,0,104,2,97,10,97,16,70,63,169,174, 254,64,0,0,0,104,2,97,11,97,16,70,191,119,121,234,0,0,0,0,104,2,97,12,97, 16,70,63,149,12,170,128,0,0,0,104,2,97,13,97,16,70,191,144,193,191,0,0,0,0>>. + +%% This test case checks that the bug with ticket number OTP-15707 is +%% fixed. The bug could cause a crash or memory usage to grow until +%% the machine ran out of memory. +t_large_unequal_bins_same_hash_bug(Config) when is_list(Config) -> + run_when_enough_resources( + fun() -> + K1 = get_4GB_bin(1), + K2 = get_4GB_bin(2), + Map = make_map(500), + Map2 = maps:put(K1, 42, Map), + %% The map needed to contain at least 32 key-value pairs + %% at this point to get the crash or out of memory + %% problem on the next line + Map3 = maps:put(K2, 43, Map2), + %% The following line should avoid that the compiler + %% optimizes away the above + io:format("~p ~p~n", [erlang:phash2(Map3), maps:size(Map3)]) + end). + +make_map(0) -> + #{}; +make_map(Size) -> + maps:put(Size, Size, make_map(Size-1)). + +get_4GB_bin(Value) -> + List = lists:duplicate(65536, Value), + Bin = erlang:iolist_to_binary(List), + IOList4GB = duplicate_iolist(Bin, 16), + Bin4GB = erlang:iolist_to_binary(IOList4GB), + 4294967296 = size(Bin4GB), + Bin4GB. + +duplicate_iolist(IOList, 0) -> + IOList; +duplicate_iolist(IOList, NrOfTimes) -> + duplicate_iolist([IOList, IOList], NrOfTimes - 1). + +run_when_enough_resources(Fun) -> + case {total_memory(), erlang:system_info(wordsize)} of + {Mem, 8} when is_integer(Mem) andalso Mem >= 31 -> + Fun(); + {Mem, WordSize} -> + {skipped, + io_lib:format("Not enough resources (System Memory >= ~p, Word Size = ~p)", + [Mem, WordSize])} + end. + +total_memory() -> + %% Total memory in GB. + try + MemoryData = memsup:get_system_memory_data(), + case lists:keysearch(total_memory, 1, MemoryData) of + {value, {total_memory, TM}} -> + TM div (1024*1024*1024); + false -> + {value, {system_total_memory, STM}} = + lists:keysearch(system_total_memory, 1, MemoryData), + STM div (1024*1024*1024) + end + catch + _ : _ -> + undefined + end. diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index c698220013..b530ced566 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -44,6 +44,7 @@ process_info_garbage_collection/1, process_info_smoke_all/1, process_info_status_handled_signal/1, + process_info_reductions/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1, @@ -84,6 +85,7 @@ all() -> process_info_garbage_collection, process_info_smoke_all, process_info_status_handled_signal, + process_info_reductions, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, @@ -1093,6 +1095,46 @@ process_info_status_handled_signal(Config) when is_list(Config) -> false = erlang:is_process_alive(P), ok. +%% OTP-15709 +%% Provoke a bug where process_info(reductions) returned wrong result +%% because REDS_IN (def_arg_reg[5]) is read when the process in not running. +process_info_reductions(Config) when is_list(Config) -> + pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)), + pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)), + ok. + +pi_reductions_tester(Pid) -> + {_, DiffList} = + lists:foldl(fun(_, {Prev, Acc}) -> + %% Add another item that force sending the request + %% as a signal, like 'current_function'. + PI = process_info(Pid, [reductions, current_function]), + [{reductions,Reds}, {current_function,_}] = PI, + Diff = Reds - Prev, + {Diff, true} = {Diff, (Diff >= 0)}, + {Diff, true} = {Diff, (Diff =< 1000*1000)}, + {Reds, [Diff | Acc]} + end, + {0, []}, + lists:seq(1,10)), + unlink(Pid), + exit(Pid,kill), + io:format("Reduction diffs: ~p\n", [DiffList]), + ok. + +pi_reductions_spinnloop() -> + %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN + pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14). + +pi_reductions_spinnloop(A,B,C,D,E,F) -> + pi_reductions_spinnloop(B,C,D,E,F,A). + +pi_reductions_recvloop() -> + receive + "a free lunch" -> false + end. + + %% Tests erlang:bump_reductions/1. bump_reductions(Config) when is_list(Config) -> erlang:garbage_collect(), diff --git a/erts/emulator/test/small_SUITE.erl b/erts/emulator/test/small_SUITE.erl new file mode 100644 index 0000000000..00a02e5560 --- /dev/null +++ b/erts/emulator/test/small_SUITE.erl @@ -0,0 +1,115 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019. 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(small_SUITE). + +-export([all/0, suite/0]). +-export([edge_cases/1]). + +-include_lib("common_test/include/ct.hrl"). + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap, {minutes, 1}}]. + +all() -> + [edge_cases]. + +edge_cases(Config) when is_list(Config) -> + {MinSmall, MaxSmall} = Limits = determine_small_limits(0), + ct:pal("Limits = ~p", [Limits]), + + true = (MaxSmall + 1) =:= MaxSmall + id(1), + true = (MinSmall - 1) =:= MinSmall - id(1), + true = (MaxSmall + 1) > id(MaxSmall), + true = (MinSmall - 1) < id(MinSmall), + -1 = MinSmall + id(MaxSmall), + -1 = MaxSmall + id(MinSmall), + + false = is_small(MinSmall * -1), + false = is_small(MinSmall - id(1)), + false = is_small(MinSmall - 1), + false = is_small(MaxSmall + id(1)), + + Lower = lists:seq(MinSmall, MinSmall + 128), + Upper = lists:seq(MaxSmall, MaxSmall - 128, -1), + Pow2 = seq_pow2(MinSmall, MaxSmall), + NearZero = lists:seq(-128, 128), + + ok = test_combinations([Lower, Upper, Pow2, NearZero], MinSmall, MaxSmall), + + ok. + +test_combinations([As | Rest]=TestVectors, MinS, MaxS) -> + [begin + _ = [arith_test(A, B, MinS, MaxS) || B <- Bs] + end || A <- As, Bs <- TestVectors], + test_combinations(Rest, MinS, MaxS); +test_combinations([], _MinS, _MaxS) -> + ok. + +%% Builds a sequence of all powers of 2 between MinSmall and MaxSmall +seq_pow2(MinSmall, MaxSmall) -> + sp2_1(MinSmall, MinSmall, MaxSmall). + +sp2_1(N, _MinS, MaxS) when N >= MaxS -> + []; +sp2_1(-1, MinS, MaxS) -> + [-1 | sp2_1(1, MinS, MaxS)]; +sp2_1(N, MinS, MaxS) when N < 0 -> + [N | sp2_1(N bsr 1, MinS, MaxS)]; +sp2_1(N, MinS, MaxS) when N > 0 -> + [N | sp2_1(N bsl 1, MinS, MaxS)]. + +arith_test(A, B, MinS, MaxS) -> + verify_kind(A + B, MinS, MaxS), + verify_kind(B + A, MinS, MaxS), + verify_kind(A - B, MinS, MaxS), + verify_kind(B - A, MinS, MaxS), + verify_kind(A * B, MinS, MaxS), + verify_kind(B * A, MinS, MaxS), + + true = A + B =:= apply(erlang, id('+'), [A, B]), + true = A - B =:= apply(erlang, id('-'), [A, B]), + true = A * B =:= apply(erlang, id('*'), [A, B]), + + true = A + B =:= B + id(A), + true = A - B =:= A + id(-B), + true = B - A =:= B + id(-A), + true = A * B =:= B * id(A), + + true = B =:= 0 orelse ((A * B) div id(B) =:= A), + true = A =:= 0 orelse ((B * A) div id(A) =:= B), + + ok. + +%% Verifies that N is a small when it should be +verify_kind(N, MinS, MaxS) -> + true = is_small(N) =:= (N >= MinS andalso N =< MaxS). + +is_small(N) when is_integer(N) -> + 0 =:= erts_debug:flat_size(N). + +determine_small_limits(N) -> + case is_small(-1 bsl N) of + true -> determine_small_limits(N + 1); + false -> {-1 bsl (N - 1), (1 bsl (N - 1)) - 1} + end. + +id(I) -> I. diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl index ae3099633a..d278ac86c7 100644 --- a/erts/emulator/test/statistics_SUITE.erl +++ b/erts/emulator/test/statistics_SUITE.erl @@ -93,25 +93,34 @@ wall_clock_zero_diff1(0) -> %% statistics(wall_clock) are compatible, and are within a small number %% of ms of the amount of real time we waited for. wall_clock_update(Config) when is_list(Config) -> - wall_clock_update1(6). + N = 10, + Inc = 200, + TotalTime = wall_clock_update1(N, Inc, 0), + Overhead = TotalTime - N * Inc, + IsDebug = test_server:is_debug(), -wall_clock_update1(N) when N > 0 -> - {T1_wc_time, _} = statistics(wall_clock), - receive after 1000 -> ok end, - {T2_wc_time, Wc_Diff} = statistics(wall_clock), - - Wc_Diff = T2_wc_time - T1_wc_time, - io:format("Wall clock diff = ~p; should be = 1000..1040~n", [Wc_Diff]), - case test_server:is_debug() of - false -> - true = Wc_Diff =< 1040; + %% Check that the average overhead is reasonable. + if + Overhead < N * 100 -> + ok; + IsDebug, Overhead < N * 1000 -> + ok; true -> - true = Wc_Diff =< 2000 %Be more tolerant in debug-compiled emulator. - end, - true = Wc_Diff >= 1000, - wall_clock_update1(N-1); -wall_clock_update1(0) -> - ok. + io:format("There was an overhead of ~p ms during ~p rounds.", + [Overhead,N]), + ct:fail(too_much_overhead) + end. + +wall_clock_update1(N, Inc, Total) when N > 0 -> + {Time1, _} = statistics(wall_clock), + receive after Inc -> ok end, + {Time2, WcDiff} = statistics(wall_clock), + WcDiff = Time2 - Time1, + io:format("Wall clock diff = ~p (expected at least ~p)\n", [WcDiff,Inc]), + true = WcDiff >= Inc, + wall_clock_update1(N-1, Inc, Total + WcDiff); +wall_clock_update1(0, _, Total) -> + Total. %%% Test statistics(runtime). |