diff --git a/benchmarks/time_required_to_restart/.gitignore b/benchmarks/time_required_to_restart/.gitignore deleted file mode 100644 index 0c186d8..0000000 --- a/benchmarks/time_required_to_restart/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -.rebar3 -_* -.eunit -*.o -*.beam -*.plt -*.swp -*.swo -.erlang.cookie -ebin -log -erl_crash.dump -.rebar -logs -_build -.idea -*.iml -rebar3.crashdump -*~ - -gen_servers/ -bean/ diff --git a/benchmarks/time_required_to_restart/LICENSE b/benchmarks/time_required_to_restart/LICENSE deleted file mode 100644 index fc90b25..0000000 --- a/benchmarks/time_required_to_restart/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2022, ajfAfg <56056962+ajfAfg@users.noreply.github.com>. - - 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. - diff --git a/benchmarks/time_required_to_restart/README.md b/benchmarks/time_required_to_restart/README.md deleted file mode 100644 index b783b5c..0000000 --- a/benchmarks/time_required_to_restart/README.md +++ /dev/null @@ -1,14 +0,0 @@ -time_required_to_restart -===== - -An escript - -Build ------ - - $ rebar3 escriptize - -Run ---- - - $ _build/default/bin/time_required_to_restart diff --git a/benchmarks/time_required_to_restart/benchmark b/benchmarks/time_required_to_restart/benchmark deleted file mode 100755 index ef4f3d2..0000000 --- a/benchmarks/time_required_to_restart/benchmark +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 - -import subprocess as sp -import shutil - -import parameters - -avg_restart_times_filename = f'avg_restart_times_with_loop_num_{parameters.loop_num}.csv' -costs_filename = f'costs_with_loop_num_{parameters.loop_num * len(parameters.delay_times)}.csv' -with open(avg_restart_times_filename, 'w') as f: - print('vertex_num(no), edge_num(no), delay_time(ms), avg_restart_time(s)', file=f) -with open(costs_filename, 'w') as f: - print('vertex_num(no), edge_num(no), cost(no)', file=f) - -for (vertex_num, edge_num) in parameters.vertex_nums_edge_nums: - costs = [] - - for delay_time in parameters.delay_times: - avg_restart_times = [] - - for _ in range(parameters.loop_num): - params = list( - map(lambda x: str(x), [vertex_num, edge_num, delay_time])) - - # NOTE: 1. Generate gen_servers - sp.run(['rebar3', 'escriptize'], - stdout=sp.DEVNULL, stderr=sp.STDOUT) - sp.run(['_build/default/bin/time_required_to_restart', - 'generate-gen-server'] + params, stdout=sp.DEVNULL, stderr=sp.STDOUT) - - # NOTE: 2. Generate a supervision tree - sp.run(['rebar3', 'bean'], stdout=sp.DEVNULL, stderr=sp.STDOUT) - - sp.run(['rebar3', 'escriptize'], - stdout=sp.DEVNULL, stderr=sp.STDOUT) - try: - # NOTE: 3. Calculate the cost of the supervision tree - costs.append(int(sp.check_output( - ['_build/default/bin/time_required_to_restart', 'calculate-cost']).decode('utf-8'))) - - # NOTE: 4. Measure total restart time for each gen_servers - avg_restart_times.append(float(sp.check_output( - ['_build/default/bin/time_required_to_restart', 'measure'] + params).decode('utf-8'))) - except Exception as e: - with open('error.log', 'a') as f: - print(vertex_num, edge_num, delay_time, f'({e})', file=f) - finally: - shutil.rmtree('src/gen_servers') - shutil.rmtree('src/bean') - - with open(avg_restart_times_filename, 'a') as f: - avg_restart_time = sum(avg_restart_times) / parameters.loop_num - print( - f'{vertex_num}, {edge_num}, {delay_time}, {avg_restart_time}', file=f) - - with open(costs_filename, 'a') as f: - cost = sum(costs) / (parameters.loop_num * len(parameters.delay_times)) - print( - f'{vertex_num}, {edge_num}, {cost}', file=f) diff --git a/benchmarks/time_required_to_restart/parameters.py b/benchmarks/time_required_to_restart/parameters.py deleted file mode 100644 index 8ffd0ad..0000000 --- a/benchmarks/time_required_to_restart/parameters.py +++ /dev/null @@ -1,17 +0,0 @@ -vertex_nums_edge_nums = [ - (10, 10), - (10, 20), - (10, 30), - (10, 90), - (50, 50), - (50, 100), - (50, 150), - (50, 2450), - (100, 100), - (100, 200), - (100, 300), - (100, 9900)] - -delay_times = list(map(lambda x: x * 10, range(1, 11))) - -loop_num = 10 diff --git a/benchmarks/time_required_to_restart/rebar.config b/benchmarks/time_required_to_restart/rebar.config deleted file mode 100644 index f1ec688..0000000 --- a/benchmarks/time_required_to_restart/rebar.config +++ /dev/null @@ -1,16 +0,0 @@ -{erl_opts, [no_debug_info]}. - -{deps, []}. - -{escript_incl_apps, [time_required_to_restart]}. - -{escript_main_app, time_required_to_restart}. - -{escript_name, time_required_to_restart}. - -{escript_emu_args, "%%! +sbtu +A1\n"}. - -%% Profiles -{profiles, [{test, [{erl_opts, [debug_info]}]}]}. - -{plugins, [bean]}. diff --git a/benchmarks/time_required_to_restart/rebar.lock b/benchmarks/time_required_to_restart/rebar.lock deleted file mode 100644 index 57afcca..0000000 --- a/benchmarks/time_required_to_restart/rebar.lock +++ /dev/null @@ -1 +0,0 @@ -[]. diff --git a/benchmarks/time_required_to_restart/src/adjacency_list.erl b/benchmarks/time_required_to_restart/src/adjacency_list.erl deleted file mode 100644 index 8d796c9..0000000 --- a/benchmarks/time_required_to_restart/src/adjacency_list.erl +++ /dev/null @@ -1,18 +0,0 @@ --module(adjacency_list). - --export([create_randomly/2]). - --export_type([t/0, vertex/0]). - --type t() :: #{vertex() => vertex()}. --type vertex() :: term(). - --spec create_randomly([vertex()], non_neg_integer()) -> t(). -create_randomly(Vertices, EdgeNum) - when 0 =< EdgeNum andalso EdgeNum =< length(Vertices) * (length(Vertices) - 1) -> - MaximumValidEdges = [{V1, V2} || V1 <- Vertices, V2 <- Vertices, V1 =/= V2], - Edges = - lists:nthtail(length(MaximumValidEdges) - EdgeNum, my_lists:shuffle(MaximumValidEdges)), - lists:foldl(fun({V1, V2}, Acc) -> maps:update_with(V1, fun(Vs) -> [V2 | Vs] end, Acc) end, - maps:from_keys(Vertices, []), - Edges). diff --git a/benchmarks/time_required_to_restart/src/gen_server_generator.erl b/benchmarks/time_required_to_restart/src/gen_server_generator.erl deleted file mode 100644 index 7519d96..0000000 --- a/benchmarks/time_required_to_restart/src/gen_server_generator.erl +++ /dev/null @@ -1,27 +0,0 @@ --module(gen_server_generator). - --export([generate/3]). - --spec generate(atom(), [atom()], pos_integer()) -> string(). -generate(Name, DependencyNames, DelayTime) -> - GenServerCalls = - lists:map(fun(N) -> io_lib:format("gen_server:call(~p, Request)", [N]) end, - DependencyNames), - io_lib:format(format(), - [Name, - DelayTime, - % NOTE: No comma when the length of `GenServerCalls` is 0. - lists:foldl(fun(Call, Acc) -> Acc ++ Call ++ "," end, "", GenServerCalls), - DelayTime]). - -format() -> - "-module(~p).~n" - "-behaviour(gen_server).~n" - "-export([init/1, handle_call/3, handle_cast/2, terminate/2]).~n" - "% NOTE: Send a message to the measure process. ~n" - "init([]) -> timer:sleep(~p),measurer ! ok,{ok, #{}}.~n" - "handle_call(Request, _From, State) ->" - "~s" - "{reply, first, State}.~n" - "handle_cast(_Request, State) -> {noreply, State}.~n" - "terminate(_Reason, _State) -> timer:sleep(~p).~n". diff --git a/benchmarks/time_required_to_restart/src/my_lists.erl b/benchmarks/time_required_to_restart/src/my_lists.erl deleted file mode 100644 index 1700865..0000000 --- a/benchmarks/time_required_to_restart/src/my_lists.erl +++ /dev/null @@ -1,8 +0,0 @@ --module(my_lists). - --export([shuffle/1]). - -% NOTE: -% Refer https://stackoverflow.com/questions/8817171/shuffling-elements-in-a-list-randomly-re-arrange-list-elements --spec shuffle(list()) -> list(). -shuffle(List) -> [Y || {_, Y} <- lists:sort([{rand:uniform(), X} || X <- List])]. diff --git a/benchmarks/time_required_to_restart/src/supervision_tree.erl b/benchmarks/time_required_to_restart/src/supervision_tree.erl deleted file mode 100644 index a87dd04..0000000 --- a/benchmarks/time_required_to_restart/src/supervision_tree.erl +++ /dev/null @@ -1,76 +0,0 @@ --module(supervision_tree). - --export([from_supervisor_specs/1, calc_cost/1]). - --export_type([supervision_tree/0]). - --type supervision_tree() :: digraph:graph(). --type sup_spec() :: {supervisor:sup_flags(), [supervisor:child_spec()]}. - -% NOTE: The types of a vertex, a leaf, and a vertex label. -% -type vertex() :: atom(). -% -type leaf() :: atom(). -% -type vertex_label() :: -% #{strategy => one_for_all | one_for_one | rest_for_one, -% children_order => fun((vertex() | leaf()) -> integer())}. - --spec from_supervisor_specs([{atom(), sup_spec()}]) -> supervision_tree(). -from_supervisor_specs(Sups) -> - Tree = digraph:new(), - lists:foreach(fun({SupName, {SupFlags, ChildSpecs}}) -> - ChildNames = - lists:map(fun(ChildSpec) -> maps:get(id, ChildSpec) end, ChildSpecs), - Label = - #{strategy => maps:get(strategy, SupFlags), - children_order => - fun(V) -> - maps:get(V, - maps:from_list( - lists:map(fun({Index, Name}) -> {Name, Index} end, - lists:enumerate(ChildNames)))) - end}, - digraph:add_vertex(Tree, SupName, Label), - - lists:foreach(fun(ChildName) -> - case digraph:vertex(Tree, ChildName) of - {ChildName, _} -> ok; - false -> digraph:add_vertex(Tree, ChildName) - end, - digraph:add_edge(Tree, SupName, ChildName) - end, - ChildNames) - end, - Sups), - Tree. - --spec calc_cost(supervision_tree()) -> non_neg_integer(). -calc_cost(SupervisionTree) -> - GenServerNames = - lists:filter(fun(V) -> digraph:out_degree(SupervisionTree, V) =:= 0 end, - digraph:vertices(SupervisionTree)), - lists:sum( - lists:map(fun(GenServerName) -> calc_cost(SupervisionTree, GenServerName) end, - GenServerNames)). - -calc_cost(SupervisionTree, GenServerName) -> - Parent = hd(digraph:in_neighbours(SupervisionTree, GenServerName)), - {Parent, #{strategy := Strategy, children_order := ChildrenOrder}} = - digraph:vertex(SupervisionTree, Parent), - Names = - case Strategy of - one_for_one -> [GenServerName]; - one_for_all -> digraph:out_neighbours(SupervisionTree, Parent); - rest_for_one -> - lists:filter(fun(Name) -> ChildrenOrder(GenServerName) =< ChildrenOrder(Name) end, - digraph:out_neighbours(SupervisionTree, Parent)) - end, - lists:sum( - lists:map(fun(Name) -> calc_cost_(SupervisionTree, Name) end, Names)). - -calc_cost_(SupervisionTree, Name) -> - case digraph:out_neighbours(SupervisionTree, Name) of - [] -> 1; - Children -> - lists:sum( - lists:map(fun(Child) -> calc_cost_(SupervisionTree, Child) end, Children)) - end. diff --git a/benchmarks/time_required_to_restart/src/time_required_to_restart.app.src b/benchmarks/time_required_to_restart/src/time_required_to_restart.app.src deleted file mode 100644 index ac4a1f2..0000000 --- a/benchmarks/time_required_to_restart/src/time_required_to_restart.app.src +++ /dev/null @@ -1,14 +0,0 @@ -{application, time_required_to_restart, - [{description, "An escript"}, - {vsn, "0.1.0"}, - {registered, []}, - {applications, - [kernel, - stdlib - ]}, - {env,[]}, - {modules, []}, - - {licenses, ["Apache-2.0"]}, - {links, []} - ]}. diff --git a/benchmarks/time_required_to_restart/src/time_required_to_restart.erl b/benchmarks/time_required_to_restart/src/time_required_to_restart.erl deleted file mode 100644 index ba9ecb4..0000000 --- a/benchmarks/time_required_to_restart/src/time_required_to_restart.erl +++ /dev/null @@ -1,94 +0,0 @@ --module(time_required_to_restart). - -%% API exports --export([main/1]). - -%%==================================================================== -%% API functions -%%==================================================================== - -%% escript Entry point -main(["generate-gen-server" | StrParameters]) -> - [VertexNum, EdgeNum, DelayTime] = lists:map(fun erlang:list_to_integer/1, StrParameters), - Vertices = - lists:map(fun erlang:list_to_atom/1, - lists:map(fun erlang:integer_to_list/1, lists:seq(1, VertexNum))), - Graph = adjacency_list:create_randomly(Vertices, EdgeNum), - file:make_dir("src/"), - file:make_dir("src/gen_servers/"), - maps:foreach(fun(Name, Code) -> - file:write_file( - io_lib:format("src/gen_servers/~s.erl", [Name]), Code) - end, - maps:map(fun(From, Tos) -> gen_server_generator:generate(From, Tos, DelayTime) end, - Graph)), - erlang:halt(); -main(["measure" | StrParameters]) -> - [VertexNum, _EdgeNum, DelayTime] = lists:map(fun erlang:list_to_integer/1, StrParameters), - % NOTE: When a gen_server is initialized, a message is sent to this name. - register(measurer, self()), - {ok, Pid} = supervisor:start_link(bean, []), - unlink(Pid), - % NOTE: Omit supervision reports - logger:add_handler_filter(default, ?MODULE, {fun(_, _) -> stop end, nostate}), - GenServerNames = create_gen_server_names(VertexNum), - MaxRestartTime = DelayTime * VertexNum, - AvgRestartTime = - average(lists:map(fun(Name) -> measure_time_to_restart(Name, MaxRestartTime) end, - GenServerNames)), - io:format("~p~n", [AvgRestartTime]), - erlang:halt(); -main(["calculate-cost"]) -> - Modules = find_source_files("src/bean"), - SupNames = - lists:map(fun(M) -> - {ok, CModule} = dialyzer_utils:get_core_from_src(M), - {c_literal, _, ModuleName} = cerl:module_name(CModule), - ModuleName - end, - Modules), - Sups = - lists:map(fun(Name) -> - {ok, SupSpec} = apply(Name, init, [[]]), - {Name, SupSpec} - end, - SupNames), - io:format("~p~n", - [supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups))]), - erlang:halt(); -main(Args) -> - io:format("Illegal options: ~p~n", [Args]), - erlang:halt(1). - -%%==================================================================== -%% Internal functions -%%==================================================================== -create_gen_server_names(VertexNum) -> - lists:map(fun(X) -> list_to_atom(integer_to_list(X)) end, lists:seq(1, VertexNum)). - -measure_time_to_restart(GenServerName, MaxRestartTime) -> - StopTime = calendar:local_time(), - gen_server:stop(GenServerName), - % NOTE: Wait for the reboot complete. - flush_until_timeout(MaxRestartTime), - StartTime = get_start_time(GenServerName), - {_Days, Time} = calendar:time_difference(StopTime, StartTime), - calendar:time_to_seconds(Time). - --spec get_start_time(sys:name()) -> calendar:datetime(). -get_start_time(Name) -> - {ok, Statistics} = sys:statistics(Name, get), - {start_time, StartTime} = lists:keyfind(start_time, 1, Statistics), - StartTime. - --spec average([number()]) -> non_neg_integer(). -average(NumList) -> - Sum = lists:foldl(fun(X, Acc) -> X + Acc end, 0, NumList), - Sum / length(NumList). - -flush_until_timeout(Timeout) -> - receive _ -> flush_until_timeout(Timeout) after Timeout -> ok end. - -find_source_files(Dir) -> - filelib:fold_files(Dir, ".*\.erl", true, fun(X, Acc) -> [X | Acc] end, []). diff --git a/benchmarks/time_required_to_restart/test/adjacency_list_tests.erl b/benchmarks/time_required_to_restart/test/adjacency_list_tests.erl deleted file mode 100644 index 2de3c39..0000000 --- a/benchmarks/time_required_to_restart/test/adjacency_list_tests.erl +++ /dev/null @@ -1,38 +0,0 @@ --module(adjacency_list_tests). - --include_lib("eunit/include/eunit.hrl"). - -create_randomly_test_() -> - TestCases = [{[1], 0}, {lists:seq(1, 10), 45}, {lists:seq(1, 100), 4950}], - {inparallel, - [{"The number of edges is the same as the second parameter.", - fun() -> - lists:foreach(fun({Vertices, EdgeNum}) -> - ?assertEqual(EdgeNum, - sum(lists:map(fun erlang:length/1, - maps:values( - adjacency_list:create_randomly(Vertices, - EdgeNum))))) - end, - TestCases) - end}, - {"Edges do not overlap.", - fun() -> - lists:foreach(fun({Vertices, EdgeNum}) -> - lists:foreach(fun(Tos) -> ?assertEqual(lists:uniq(Tos), Tos) end, - maps:values( - adjacency_list:create_randomly(Vertices, EdgeNum))) - end, - TestCases) - end}, - {"There is no loop.", - fun() -> - lists:foreach(fun({Vertices, EdgeNum}) -> - Graph = adjacency_list:create_randomly(Vertices, EdgeNum), - maps:foreach(fun(From, Tos) -> ?assertNot(lists:member(From, Tos)) end, - Graph) - end, - TestCases) - end}]}. - -sum(NumList) -> lists:foldl(fun erlang:'+'/2, 0, NumList). diff --git a/benchmarks/time_required_to_restart/test/my_lists_tests.erl b/benchmarks/time_required_to_restart/test/my_lists_tests.erl deleted file mode 100644 index 03badb7..0000000 --- a/benchmarks/time_required_to_restart/test/my_lists_tests.erl +++ /dev/null @@ -1,16 +0,0 @@ --module(my_lists_tests). - --include_lib("eunit/include/eunit.hrl"). - -shuffle_test_() -> - {inparallel, - [{"The lists before and after shuffling are the same when sorted.", - fun() -> - TestCases = [[], [1], [1, 2, 3]], - lists:foreach(fun(L) -> - ?assertEqual(lists:sort(L), - lists:sort( - my_lists:shuffle(L))) - end, - TestCases) - end}]}. diff --git a/benchmarks/time_required_to_restart/test/supervision_tree_tests.erl b/benchmarks/time_required_to_restart/test/supervision_tree_tests.erl deleted file mode 100644 index 346f961..0000000 --- a/benchmarks/time_required_to_restart/test/supervision_tree_tests.erl +++ /dev/null @@ -1,145 +0,0 @@ --module(supervision_tree_tests). - --include_lib("eunit/include/eunit.hrl"). - --import(lists, [sort/1]). - -from_supervisor_specs_test_() -> - TestCases = - [[{s1, {#{strategy => one_for_one}, [#{id => g1}, #{id => g2}]}}], - [{s1, {#{strategy => one_for_one}, [#{id => g1}, #{id => g2}, #{id => s2}]}}, - {s2, {#{strategy => rest_for_one}, [#{id => g3}]}}]], - {inparallel, - [{"The Return value is a tree.", - fun() -> - [Sups1, Sups2] = TestCases, - ?assert(digraph_utils:is_tree( - supervision_tree:from_supervisor_specs(Sups1))), - ?assert(digraph_utils:is_tree( - supervision_tree:from_supervisor_specs(Sups2))) - end}, - {"Retains all vertices.", - fun() -> - [Sups1, Sups2] = TestCases, - ?assertEqual(sort([s1, g1, g2]), - sort(digraph:vertices( - supervision_tree:from_supervisor_specs(Sups1)))), - ?assertEqual(sort([s1, s2, g1, g2, g3]), - sort(digraph:vertices( - supervision_tree:from_supervisor_specs(Sups2)))) - end}, - {"Retains all edges.", - fun() -> - [Sups1, Sups2] = TestCases, - ?assertEqual(sort([g1, g2]), - sort(digraph:out_neighbours( - supervision_tree:from_supervisor_specs(Sups1), s1))), - - ?assertEqual(sort([g1, g2, s2]), - sort(digraph:out_neighbours( - supervision_tree:from_supervisor_specs(Sups2), s1))), - ?assertEqual(sort([g3]), - sort(digraph:out_neighbours( - supervision_tree:from_supervisor_specs(Sups2), s2))) - end}, - {"Retains all restart strategies.", - fun() -> - [Sups1, Sups2] = TestCases, - ?assertMatch({s1, #{strategy := one_for_one}}, - digraph:vertex( - supervision_tree:from_supervisor_specs(Sups1), s1)), - - ?assertMatch({s1, #{strategy := one_for_one}}, - digraph:vertex( - supervision_tree:from_supervisor_specs(Sups2), s1)), - ?assertMatch({s2, #{strategy := rest_for_one}}, - digraph:vertex( - supervision_tree:from_supervisor_specs(Sups2), s2)) - end}, - {"Retains all children orders.", - fun() -> - [Sups1, Sups2] = TestCases, - {s1, #{children_order := Order1_1}} = - digraph:vertex( - supervision_tree:from_supervisor_specs(Sups1), s1), - ?assertEqual(1, Order1_1(g1)), - ?assertEqual(2, Order1_1(g2)), - - {s1, #{children_order := Order2_1}} = - digraph:vertex( - supervision_tree:from_supervisor_specs(Sups2), s1), - ?assertEqual(1, Order2_1(g1)), - ?assertEqual(2, Order2_1(g2)), - ?assertEqual(3, Order2_1(s2)), - - {s2, #{children_order := Order2_2}} = - digraph:vertex( - supervision_tree:from_supervisor_specs(Sups2), s2), - ?assertEqual(1, Order2_2(g3)) - end}]}. - -calc_cost_test_() -> - {inparallel, - [{"If all restart strategies are `one_for_one`, the number of gen_servers and the cost is the same.", - fun() -> - Sups1 = [{s1, {#{strategy => one_for_one}, [#{id => g1}, #{id => g2}]}}], - ?assertEqual(2, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups1))), - - Sups2 = - [{s1, {#{strategy => one_for_one}, [#{id => g1}, #{id => s1}]}}, - {s2, {#{strategy => one_for_one}, [#{id => g2}, #{id => g3}, #{id => g4}]}}], - ?assertEqual(4, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups2))) - end}, - {"If a restart strategy is `one_for_all`, the cost of siblings is also added.", - fun() -> - Sups1 = [{s1, {#{strategy => one_for_all}, [#{id => g1}, #{id => g2}]}}], - ?assertEqual(2 + 2, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups1))), - - Sups2 = - [{s1, {#{strategy => one_for_all}, [#{id => g1}, #{id => s2}]}}, - {s2, {#{strategy => one_for_all}, [#{id => g2}, #{id => g3}, #{id => g4}]}}], - ?assertEqual(4 + 3 + 3 + 3, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups2))) - end}, - {"If a restart strategy is `rest_for_one`, the cost of REST siblings is also added.", - fun() -> - Sups1 = [{s1, {#{strategy => rest_for_one}, [#{id => g1}, #{id => g2}]}}], - ?assertEqual(2 + 1, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups1))), - - Sups2 = - [{s1, {#{strategy => rest_for_one}, [#{id => g1}, #{id => s2}]}}, - {s2, {#{strategy => rest_for_one}, [#{id => g2}, #{id => g3}, #{id => g4}]}}], - ?assertEqual(4 + 3 + 2 + 1, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups2))) - end}, - {"Restart strategies can be mixed", - fun() -> - Sups1 = - [{s1, {#{strategy => one_for_one}, [#{id => s2}, #{id => s3}]}}, - {s2, {#{strategy => rest_for_one}, [#{id => g5}, #{id => s4}]}}, - {s3, {#{strategy => rest_for_one}, [#{id => g6}, #{id => g7}]}}, - {s4, - {#{strategy => one_for_all}, - [#{id => g1}, #{id => g2}, #{id => g3}, #{id => g4}]}}], - ?assertEqual(4 + 4 + 4 + 4 + 5 + 2 + 1, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups1))), - Sups2 = - [{s1, {#{strategy => one_for_all}, [#{id => g1}, #{id => g2}, #{id => s2}]}}, - {s2, {#{strategy => one_for_one}, [#{id => g3}, #{id => g4}, #{id => s3}]}}, - {s3, {#{strategy => rest_for_one}, [#{id => g5}, #{id => g6}, #{id => s4}]}}, - {s4, {#{strategy => one_for_one}, [#{id => g7}, #{id => g8}]}}], - ?assertEqual(8 + 8 + 1 + 1 + 4 + 3 + 1 + 1, - supervision_tree:calc_cost( - supervision_tree:from_supervisor_specs(Sups2))) - end}]}. diff --git a/src/core/supervisor_specs_constructor.erl b/src/core/supervisor_specs_constructor.erl index ee74b35..9b8e3fe 100644 --- a/src/core/supervisor_specs_constructor.erl +++ b/src/core/supervisor_specs_constructor.erl @@ -20,9 +20,8 @@ convert_sup_specs_from_grouped_dependencies({Strategy, Children} = SupervisionTr #{name => maps:get(SupervisionTree, Names), sup_flags => #{strategy => Strategy, - % TODO: Give the debug information only when running the benchmark to measure the time to restart gen_servers - intensity => 1000, - period => 1}, + intensity => 1, + period => 5}, child_specs => lists:map(fun(Child) -> create_child_spec(Child, Names) end, Children)}, lists:foldl(fun(Child, A) -> convert_sup_specs_from_grouped_dependencies(Child, Names, A) end, @@ -52,9 +51,7 @@ make_name() -> -spec create_child_spec(supervision_tree:child(), sup_names()) -> supervisor:child_spec(). create_child_spec(Name, _) when is_atom(Name) -> #{id => Name, - start => - % TODO: Give the debug information only when running the benchmark to measure the time to restart gen_servers - {gen_server, start_link, [{local, Name}, Name, [], [{debug, [statistics]}]]}, + start => {gen_server, start_link, [{local, Name}, Name, [], []]}, type => worker}; create_child_spec(Child, Names) -> Name = maps:get(Child, Names),