diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/src/digraph.erl | 4 | ||||
-rw-r--r-- | lib/stdlib/test/digraph_SUITE.erl | 51 | ||||
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 116 | ||||
-rw-r--r-- | lib/stdlib/test/gen_statem_SUITE.erl | 107 |
4 files changed, 163 insertions, 115 deletions
diff --git a/lib/stdlib/src/digraph.erl b/lib/stdlib/src/digraph.erl index 8a4df95027..58d493cf54 100644 --- a/lib/stdlib/src/digraph.erl +++ b/lib/stdlib/src/digraph.erl @@ -230,7 +230,7 @@ in_neighbours(G, V) -> Edges :: [edge()]. in_edges(G, V) -> - ets:select(G#digraph.ntab, [{{{in, V}, '$1'}, [], ['$1']}]). + [E || {{in, _}, E} <- ets:lookup(G#digraph.ntab, {in, V})]. -spec out_degree(G, V) -> non_neg_integer() when G :: graph(), @@ -255,7 +255,7 @@ out_neighbours(G, V) -> Edges :: [edge()]. out_edges(G, V) -> - ets:select(G#digraph.ntab, [{{{out, V}, '$1'}, [], ['$1']}]). + [E || {{out, _}, E} <- ets:lookup(G#digraph.ntab, {out, V})]. -spec add_edge(G, V1, V2) -> edge() | {'error', add_edge_err_rsn()} when G :: graph(), diff --git a/lib/stdlib/test/digraph_SUITE.erl b/lib/stdlib/test/digraph_SUITE.erl index b5d3452616..ce0bc90f1c 100644 --- a/lib/stdlib/test/digraph_SUITE.erl +++ b/lib/stdlib/test/digraph_SUITE.erl @@ -31,7 +31,7 @@ init_per_group/2,end_per_group/2]). -export([opts/1, degree/1, path/1, cycle/1, vertices/1, - edges/1, data/1, otp_3522/1, otp_3630/1, otp_8066/1]). + edges/1, data/1, otp_3522/1, otp_3630/1, otp_8066/1, vertex_names/1]). -export([spawn_graph/2]). @@ -41,10 +41,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [opts, degree, path, cycle, {group, misc}, - {group, tickets}]. + {group, tickets}, vertex_names]. groups() -> - [{misc, [], [vertices, edges, data]}, + [{misc, [], [vertices, edges, data, vertex_names]}, {tickets, [], [otp_3522, otp_3630, otp_8066]}]. init_per_suite(Config) -> @@ -337,6 +337,51 @@ otp_8066(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +vertex_names(Config) when is_list(Config) -> + %% Check that a node named '_' does not lead to wildcard matches + %% in ets. + + G = digraph:new([acyclic]), + A = digraph:add_vertex(G, 'A'), + B = digraph:add_vertex(G, '_'), + AB = digraph:add_edge(G, A, B), + + %% Link A -> B + 1 = digraph:out_degree(G, A), + 1 = digraph:in_degree(G, B), + 0 = digraph:out_degree(G, B), + 0 = digraph:in_degree(G, A), + [B] = digraph:out_neighbours(G, A), + [A] = digraph:in_neighbours(G, B), + [] = digraph:out_neighbours(G, B), + [] = digraph:in_neighbours(G, A), + [AB] = digraph:out_edges(G, A), + [AB] = digraph:in_edges(G, B), + [] = digraph:out_edges(G, B), + [] = digraph:in_edges(G, A), + + %% Reverse the edge + digraph:del_edge(G, AB), + BA = digraph:add_edge(G, B, A), + + 1 = digraph:out_degree(G, B), + 1 = digraph:in_degree(G, A), + 0 = digraph:out_degree(G, A), + 0 = digraph:in_degree(G, B), + [A] = digraph:out_neighbours(G, B), + [B] = digraph:in_neighbours(G, A), + [] = digraph:out_neighbours(G, A), + [] = digraph:in_neighbours(G, B), + [BA] = digraph:out_edges(G, B), + [BA] = digraph:in_edges(G, A), + [] = digraph:out_edges(G, A), + [] = digraph:in_edges(G, B), + + digraph:delete(G), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + sane(G) -> sane1(G), erase(sane) =:= undefined. diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 3b2dde6b9b..9e5410c10f 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -1278,9 +1278,9 @@ ets_insert_new_with_check(Table, ToInsert) -> t_insert_list_parallel_do(Opts) -> [(fun(I) -> - t_insert_list_parallel_do(Opts, I, 2, 100, 5000), - t_insert_list_parallel_do(Opts, I, 10, 100, 500), - t_insert_list_parallel_do(Opts, I, 1000, 100, 50), + t_insert_list_parallel_do(Opts, I, 2, 100, 500), + t_insert_list_parallel_do(Opts, I, 10, 100, 100), + t_insert_list_parallel_do(Opts, I, 1000, 100, 10), t_insert_list_parallel_do(Opts, I, 50000, 3, 1) end)(InsertFun) || InsertFun <- [fun ets_insert_with_check/2, fun ets_insert_new_with_check/2]]. @@ -5118,7 +5118,7 @@ test_delete_table_while_size_snapshot_helper(TableType) -> Problem -> TopParent ! Problem end || _ <- Pids] end, - 15000), + 100*erlang:system_info(schedulers_online)), receive Problem -> throw(Problem) after 0 -> ok @@ -6853,7 +6853,7 @@ verify_table_load(T) -> false; true -> - io:format("Stats = ~p\n",[Stats]), + io:format("Stats = ~p\n~p\n",[Stats, ets:info(T)]), ok end end. @@ -8134,58 +8134,60 @@ wait_for_memory_deallocations() -> end. etsmem() -> - % The following is done twice to avoid an inconsistent memory - % "snapshot" (see verify_etsmem/2). - lists:foldl( - fun(AttemptNr, PrevEtsMem) -> - AllTabsExceptions = [logger, code], - %% The logger table is excluded from the AllTabs list - %% below because it uses decentralized counters to keep - %% track of the size and the memory counters. This cause - %% ets:info(T,size) and ets:info(T,memory) to trigger - %% allocations and frees that may change the amount of - %% memory that is allocated for ETS. - %% - %% The code table is excluded from the list below - %% because the amount of memory allocated for it may - %% change if the tested code loads a new module. - AllTabs = - lists:sort( - [begin - try ets:info(T, decentralized_counters) of - true -> - ct:fail("Background ETS table (~p) that " - "uses decentralized counters (Add exception?)", - [ets:info(T,name)]); - _ -> ok - catch _:_ -> - ok - end, - {T, - ets:info(T,name), - ets:info(T,size), - ets:info(T,memory), - ets:info(T,type)} - end - || T <- ets:all(), - not lists:member(ets:info(T, name), AllTabsExceptions)]), - wait_for_memory_deallocations(), - EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc), - ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end, - FlxCtrMemUsage = try erts_debug:get_internal_state(flxctr_memory_usage) catch error:badarg -> notsup end, - Mem = {ErlangMemoryEts, EtsAllocSize, FlxCtrMemUsage}, - EtsMem = {Mem, AllTabs}, - case PrevEtsMem of - first -> ok; - _ when PrevEtsMem =:= EtsMem -> ok; - _ -> - io:format("etsmem(): Change in attempt ~p~n~nbefore:~n~p~n~nafter:~n~p~n~n", - [AttemptNr, PrevEtsMem, EtsMem]) - end, - EtsMem - end, - first, - lists:seq(1,2)). + etsmem(get_etsmem(), 1). + +etsmem(PrevEtsMem, Try) when Try < 10 -> + case get_etsmem() of + PrevEtsMem -> + PrevEtsMem; + EtsMem -> + io:format("etsmem(): Change in attempt ~p~n~nbefore:~n~p~n~nafter:~n~p~n~n", + [Try, PrevEtsMem, EtsMem]), + etsmem(EtsMem, Try+1) + end; +etsmem(_, _) -> + ct:fail("Failed to get a stable/consistent memory snapshot"). + +get_etsmem() -> + AllTabsExceptions = [logger, code], + %% The logger table is excluded from the AllTabs list + %% below because it uses decentralized counters to keep + %% track of the size and the memory counters. This cause + %% ets:info(T,size) and ets:info(T,memory) to trigger + %% allocations and frees that may change the amount of + %% memory that is allocated for ETS. + %% + %% The code table is excluded from the list below + %% because the amount of memory allocated for it may + %% change if the tested code loads a new module. + AllTabs = + lists:sort( + [begin + try ets:info(T, decentralized_counters) of + true -> + ct:fail("Background ETS table (~p) that " + "uses decentralized counters (Add exception?)", + [ets:info(T,name)]); + _ -> ok + catch _:_ -> + ok + end, + {T, + ets:info(T,name), + ets:info(T,size), + ets:info(T,memory), + ets:info(T,type)} + end + || T <- ets:all(), + not lists:member(ets:info(T, name), AllTabsExceptions)]), + wait_for_memory_deallocations(), + EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc), + ErlangMemoryEts = try erlang:memory(ets) + catch error:notsup -> notsup end, + FlxCtrMemUsage = try erts_debug:get_internal_state(flxctr_memory_usage) + catch error:badarg -> notsup end, + Mem = {ErlangMemoryEts, EtsAllocSize, FlxCtrMemUsage}, + {Mem, AllTabs}. verify_etsmem(MI) -> wait_for_test_procs(), diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index f40dce5d7a..76dee868e9 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -534,10 +534,10 @@ abnormal1(Config) -> gen_statem:start(LocalSTM, ?MODULE, start_arg(Config, []), []), %% timeout call. - delayed = gen_statem:call(Name, {delayed_answer,1}, 100), + delayed = gen_statem:call(Name, {delayed_answer,100}, 2000), {timeout,_} = ?EXPECT_FAILURE( - gen_statem:call(Name, {delayed_answer,1000}, 10), + gen_statem:call(Name, {delayed_answer,2000}, 100), Reason), ok = gen_statem:stop(Name), ?t:sleep(1100), @@ -1437,7 +1437,7 @@ hibernate(Config) -> {ok,Pid0} = gen_statem:start_link( ?MODULE, start_arg(Config, hiber_now), []), - is_in_erlang_hibernate(Pid0), + wait_erlang_hibernate(Pid0), stop_it(Pid0), receive {'EXIT',Pid0,normal} -> ok @@ -1450,23 +1450,23 @@ hibernate(Config) -> true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), please_just_five_more = gen_statem:call(Pid, snooze_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, snooze_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), @@ -1474,14 +1474,14 @@ hibernate(Config) -> true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid, current_function)), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), 'alive!' = gen_statem:call(Pid, 'alive?'), true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid, current_function)), Pid ! hibernate_now, - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), 'alive!' = gen_statem:call(Pid, 'alive?'), true = @@ -1489,34 +1489,34 @@ hibernate(Config) -> erlang:process_info(Pid, current_function)), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), please_just_five_more = gen_statem:call(Pid, snooze_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, snooze_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), sys:suspend(Pid), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), sys:resume(Pid), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), receive after 1000 -> ok end, - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), @@ -1532,15 +1532,16 @@ hibernate(Config) -> %% Auto-hibernation timeout auto_hibernate(Config) -> OldFl = process_flag(trap_exit, true), - HibernateAfterTimeout = 100, + HibernateAfterTimeout = 1000, {ok,Pid} = gen_statem:start_link( - ?MODULE, start_arg(Config, []), [{hibernate_after, HibernateAfterTimeout}]), + ?MODULE, start_arg(Config, []), + [{hibernate_after, HibernateAfterTimeout}]), %% After init test is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% After info test Pid ! {hping, self()}, receive @@ -1551,7 +1552,7 @@ auto_hibernate(Config) -> end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% After cast test ok = gen_statem:cast(Pid, {hping, self()}), receive @@ -1562,42 +1563,42 @@ auto_hibernate(Config) -> end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% After call test hpong = gen_statem:call(Pid, hping), is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% Timer test 1 - TimerTimeout1 = 50, - ok = gen_statem:call(Pid, {arm_htimer, self(), TimerTimeout1}), + TimerTimeout1 = HibernateAfterTimeout div 2, + ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout1}), is_not_in_erlang_hibernate(Pid), timer:sleep(TimerTimeout1), is_not_in_erlang_hibernate(Pid), receive - {Pid, htimer_armed} -> + {Pid, htimer_timeout} -> ok after 1000 -> ct:fail(timer1) end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% Timer test 2 - TimerTimeout2 = 150, - ok = gen_statem:call(Pid, {arm_htimer, self(), TimerTimeout2}), + TimerTimeout2 = HibernateAfterTimeout * 2, + ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout2}), is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), receive - {Pid, htimer_armed} -> + {Pid, htimer_timeout} -> ok - after 1000 -> + after TimerTimeout2 -> ct:fail(timer2) end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), stop_it(Pid), process_flag(trap_exit, OldFl), receive @@ -1607,38 +1608,38 @@ auto_hibernate(Config) -> end, ok = verify_empty_msgq(). -is_in_erlang_hibernate(Pid) -> + +wait_erlang_hibernate(Pid) -> receive after 1 -> ok end, - is_in_erlang_hibernate_1(200, Pid). + wait_erlang_hibernate_1(200, Pid). -is_in_erlang_hibernate_1(0, Pid) -> +wait_erlang_hibernate_1(0, Pid) -> ct:log("~p\n", [erlang:process_info(Pid, current_function)]), - ct:fail(not_in_erlang_hibernate_3); -is_in_erlang_hibernate_1(N, Pid) -> + ct:fail(should_be_in_erlang_hibernate_3); +wait_erlang_hibernate_1(N, Pid) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of {erlang,hibernate,3} -> ok; _ -> receive after 10 -> ok end, - is_in_erlang_hibernate_1(N-1, Pid) + wait_erlang_hibernate_1(N-1, Pid) end. is_not_in_erlang_hibernate(Pid) -> receive after 1 -> ok end, is_not_in_erlang_hibernate_1(200, Pid). -is_not_in_erlang_hibernate_1(0, Pid) -> - ct:log("~p\n", [erlang:process_info(Pid, current_function)]), - ct:fail(not_in_erlang_hibernate_3); +is_not_in_erlang_hibernate_1(0, _Pid) -> + ct:fail(should_not_be_in_erlang_hibernate_3); is_not_in_erlang_hibernate_1(N, Pid) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of - {erlang,hibernate,3} -> + {erlang,hibernate,3} -> receive after 10 -> ok end, is_not_in_erlang_hibernate_1(N-1, Pid); - _ -> - ok + _ -> + ok end. @@ -2430,10 +2431,10 @@ idle(cast, {hping,Pid}, Data) -> {keep_state, Data}; idle({call, From}, hping, _Data) -> {keep_state_and_data, [{reply, From, hpong}]}; -idle({call, From}, {arm_htimer, Pid, Timeout}, _Data) -> - {keep_state_and_data, [{reply, From, ok}, {timeout, Timeout, {arm_htimer, Pid}}]}; -idle(timeout, {arm_htimer, Pid}, _Data) -> - Pid ! {self(), htimer_armed}, +idle({call, From}, {start_htimer, Pid, Timeout}, _Data) -> + {keep_state_and_data, [{reply, From, ok}, {timeout, Timeout, {htimer, Pid}}]}; +idle(timeout, {htimer, Pid}, _Data) -> + Pid ! {self(), htimer_timeout}, keep_state_and_data; idle(cast, {connect,Pid}, Data) -> Pid ! accept, |