aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/old_scheduler_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/old_scheduler_SUITE.erl')
-rw-r--r--erts/emulator/test/old_scheduler_SUITE.erl394
1 files changed, 394 insertions, 0 deletions
diff --git a/erts/emulator/test/old_scheduler_SUITE.erl b/erts/emulator/test/old_scheduler_SUITE.erl
new file mode 100644
index 0000000000..70348f64db
--- /dev/null
+++ b/erts/emulator/test/old_scheduler_SUITE.erl
@@ -0,0 +1,394 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(old_scheduler_SUITE).
+
+-include("test_server.hrl").
+
+-export([all/1, init_per_testcase/2, fin_per_testcase/2]).
+-export([equal/1, many_low/1, few_low/1, max/1, high/1]).
+
+-define(default_timeout, ?t:minutes(11)).
+
+all(suite) ->
+ case catch erlang:system_info(modified_timing_level) of
+ Level when is_integer(Level) ->
+ {skipped,
+ "Modified timing (level " ++ integer_to_list(Level)
+ ++ ") is enabled. Testcases gets messed up by modfied "
+ "timing."};
+ _ ->
+ [equal, many_low, few_low, max, high]
+ end.
+
+%%-----------------------------------------------------------------------------------
+%% TEST SUITE DESCRIPTION
+%%
+%% The test case function spawns two controlling processes: Starter and Receiver.
+%% Starter spawns a number of prio A and a number of prio B test processes. Each
+%% test process loops for a number of times, sends a report to the Receiver, then
+%% loops again. For each report, the Receiver increases a counter that corresponds
+%% to the priority of the sender. After a certain amount of time, the Receiver
+%% sends the collected data to the main test process and waits for the test case
+%% to terminate. From this data, it's possible to calculate the average run time
+%% relationship between the prio A and B test processes.
+%%
+%% Note that in order to be able to run tests with high or max prio test processes,
+%% the main test process and the Receiver needs to run at max prio, or they will
+%% be starved by the test processes. The controlling processes must not wait for
+%% messages from a normal (or low) prio process while max or high prio test processes
+%% are running (which happens e.g. if an io function is called).
+%%-----------------------------------------------------------------------------------
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = test_server:timetrap(?default_timeout),
+ %% main test process needs max prio
+ ?line Prio = process_flag(priority, max),
+ ?line MS = erlang:system_flag(multi_scheduling, block),
+ [{prio,Prio},{watchdog,Dog},{multi_scheduling, MS}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ erlang:system_flag(multi_scheduling, unblock),
+ Dog=?config(watchdog, Config),
+ Prio=?config(prio, Config),
+ process_flag(priority, Prio),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+ok(Config) when is_list(Config) ->
+ case ?config(multi_scheduling, Config) of
+ blocked ->
+ {comment,
+ "Multi-scheduling blocked during test. This testcase was not "
+ "written to work with multiple schedulers."};
+ _ -> ok
+ end.
+
+%% Run equal number of low and normal prio processes.
+
+equal(suite) -> [];
+equal(doc) -> [];
+equal(Config) when is_list(Config) ->
+ ?line Self = self(),
+
+ %% specify number of test processes to run
+ Normal = {normal,500},
+ Low = {low,500},
+
+ %% specify time of test (in seconds)
+ Time = 30,
+
+ %% start controllers
+ ?line Receiver =
+ spawn(fun() -> receiver(now(), Time, Self, Normal, Low) end),
+ ?line Starter =
+ spawn(fun() -> starter(Normal, Low, Receiver) end),
+
+ %% receive test data from Receiver
+ ?line {NRs,NAvg,LRs,LAvg,Ratio} =
+ receive
+ {Receiver,Res} -> Res
+ end,
+
+ %% stop controllers and test processes
+ ?line exit(Starter, kill),
+ ?line exit(Receiver, kill),
+
+ io:format("Reports: ~w normal (~w/proc), ~w low (~w/proc). Ratio: ~w~n",
+ [NRs,NAvg,LRs,LAvg,Ratio]),
+
+ %% runtime ratio between normal and low should be ~8
+ if Ratio < 7.5 ; Ratio > 8.5 ->
+ ?t:fail({bad_ratio,Ratio});
+ true ->
+ ok(Config)
+ end.
+
+
+%% Run many low and few normal prio processes.
+
+many_low(suite) -> [];
+many_low(doc) -> [];
+many_low(Config) when is_list(Config) ->
+ ?line Self = self(),
+ Normal = {normal,1},
+ Low = {low,1000},
+
+ %% specify time of test (in seconds)
+ Time = 30,
+
+ ?line Receiver =
+ spawn(fun() -> receiver(now(), Time, Self, Normal, Low) end),
+ ?line Starter =
+ spawn(fun() -> starter(Normal, Low, Receiver) end),
+ ?line {NRs,NAvg,LRs,LAvg,Ratio} =
+ receive
+ {Receiver,Res} -> Res
+ end,
+ ?line exit(Starter, kill),
+ ?line exit(Receiver, kill),
+ io:format("Reports: ~w normal (~w/proc), ~w low (~w/proc). Ratio: ~w~n",
+ [NRs,NAvg,LRs,LAvg,Ratio]),
+ if Ratio < 7.5 ; Ratio > 8.5 ->
+ ?t:fail({bad_ratio,Ratio});
+ true ->
+ ok(Config)
+ end.
+
+
+%% Run few low and many normal prio processes.
+
+few_low(suite) -> [];
+few_low(doc) -> [];
+few_low(Config) when is_list(Config) ->
+ ?line Self = self(),
+ Normal = {normal,1000},
+ Low = {low,1},
+
+ %% specify time of test (in seconds)
+ Time = 30,
+
+ ?line Receiver =
+ spawn(fun() -> receiver(now(), Time, Self, Normal, Low) end),
+ ?line Starter =
+ spawn(fun() -> starter(Normal, Low, Receiver) end),
+ ?line {NRs,NAvg,LRs,LAvg,Ratio} =
+ receive
+ {Receiver,Res} -> Res
+ end,
+ ?line exit(Starter, kill),
+ ?line exit(Receiver, kill),
+ io:format("Reports: ~w normal (~w/proc), ~w low (~w/proc). Ratio: ~w~n",
+ [NRs,NAvg,LRs,LAvg,Ratio]),
+ if Ratio < 7.0 ; Ratio > 8.5 ->
+ ?t:fail({bad_ratio,Ratio});
+ true ->
+ ok(Config)
+ end.
+
+
+%% Run max prio processes and verify they get at least as much
+%% runtime as high, normal and low.
+
+max(suite) -> [];
+max(doc) -> [];
+max(Config) when is_list(Config) ->
+ max = process_flag(priority, max), % should already be max (init_per_tc)
+ ?line Self = self(),
+ Max = {max,2},
+ High = {high,2},
+ Normal = {normal,100},
+ Low = {low,100},
+
+ %% specify time of test (in seconds)
+ Time = 30,
+
+ ?line Receiver1 =
+ spawn(fun() -> receiver(now(), Time, Self, Max, High) end),
+ ?line Starter1 =
+ spawn(fun() -> starter(Max, High, Receiver1) end),
+ ?line {M1Rs,M1Avg,HRs,HAvg,Ratio1} =
+ receive
+ {Receiver1,Res1} -> Res1
+ end,
+ ?line exit(Starter1, kill),
+ ?line exit(Receiver1, kill),
+ io:format("Reports: ~w max (~w/proc), ~w high (~w/proc). Ratio: ~w~n",
+ [M1Rs,M1Avg,HRs,HAvg,Ratio1]),
+ if Ratio1 < 1.0 ->
+ ?t:fail({bad_ratio,Ratio1});
+ true ->
+ ok(Config)
+ end,
+
+ ?line Receiver2 =
+ spawn(fun() -> receiver(now(), Time, Self, Max, Normal) end),
+ ?line Starter2 =
+ spawn(fun() -> starter(Max, Normal, Receiver2) end),
+ ?line {M2Rs,M2Avg,NRs,NAvg,Ratio2} =
+ receive
+ {Receiver2,Res2} -> Res2
+ end,
+ ?line exit(Starter2, kill),
+ ?line exit(Receiver2, kill),
+ io:format("Reports: ~w max (~w/proc), ~w normal (~w/proc). Ratio: ~w~n",
+ [M2Rs,M2Avg,NRs,NAvg,Ratio2]),
+ if Ratio2 < 1.0 ->
+ ?t:fail({bad_ratio,Ratio2});
+ true ->
+ ok
+ end,
+
+ ?line Receiver3 =
+ spawn(fun() -> receiver(now(), Time, Self, Max, Low) end),
+ ?line Starter3 =
+ spawn(fun() -> starter(Max, Low, Receiver3) end),
+ ?line {M3Rs,M3Avg,LRs,LAvg,Ratio3} =
+ receive
+ {Receiver3,Res3} -> Res3
+ end,
+ ?line exit(Starter3, kill),
+ ?line exit(Receiver3, kill),
+ io:format("Reports: ~w max (~w/proc), ~w low (~w/proc). Ratio: ~w~n",
+ [M3Rs,M3Avg,LRs,LAvg,Ratio3]),
+ if Ratio3 < 1.0 ->
+ ?t:fail({bad_ratio,Ratio3});
+ true ->
+ ok(Config)
+ end.
+
+
+%% Run high prio processes and verify they get at least as much
+%% runtime as normal and low.
+
+high(suite) -> [];
+high(doc) -> [];
+high(Config) when is_list(Config) ->
+ max = process_flag(priority, max), % should already be max (init_per_tc)
+ ?line Self = self(),
+ High = {high,2},
+ Normal = {normal,100},
+ Low = {low,100},
+
+ %% specify time of test (in seconds)
+ Time = 30,
+
+ ?line Receiver1 =
+ spawn(fun() -> receiver(now(), Time, Self, High, Normal) end),
+ ?line Starter1 =
+ spawn(fun() -> starter(High, Normal, Receiver1) end),
+ ?line {H1Rs,H1Avg,NRs,NAvg,Ratio1} =
+ receive
+ {Receiver1,Res1} -> Res1
+ end,
+ ?line exit(Starter1, kill),
+ ?line exit(Receiver1, kill),
+ io:format("Reports: ~w high (~w/proc), ~w normal (~w/proc). Ratio: ~w~n",
+ [H1Rs,H1Avg,NRs,NAvg,Ratio1]),
+ if Ratio1 < 1.0 ->
+ ?t:fail({bad_ratio,Ratio1});
+ true ->
+ ok
+ end,
+
+ ?line Receiver2 =
+ spawn(fun() -> receiver(now(), Time, Self, High, Low) end),
+ ?line Starter2 =
+ spawn(fun() -> starter(High, Low, Receiver2) end),
+ ?line {H2Rs,H2Avg,LRs,LAvg,Ratio2} =
+ receive
+ {Receiver2,Res2} -> Res2
+ end,
+ ?line exit(Starter2, kill),
+ ?line exit(Receiver2, kill),
+ io:format("Reports: ~w high (~w/proc), ~w low (~w/proc). Ratio: ~w~n",
+ [H2Rs,H2Avg,LRs,LAvg,Ratio2]),
+ if Ratio2 < 1.0 ->
+ ?t:fail({bad_ratio,Ratio2});
+ true ->
+ ok(Config)
+ end.
+
+
+%%-----------------------------------------------------------------------------------
+%% Controller processes and help functions
+%%-----------------------------------------------------------------------------------
+
+receiver(T0, TimeSec, Main, {P1,P1N}, {P2,P2N}) ->
+ %% prio should be max so that mailbox doesn't overflow
+ process_flag(priority, max),
+ receiver(T0, TimeSec*1000, Main, P1,P1N,0, P2,P2N,0, 100000).
+
+%% uncomment lines below to get life sign (debug)
+receiver(T0, Time, Main, P1,P1N,P1Rs, P2,P2N,P2Rs, 0) ->
+% T = elapsed_ms(T0, now()),
+% erlang:display({round(T/1000),P1Rs,P2Rs}),
+ receiver(T0, Time, Main, P1,P1N,P1Rs, P2,P2N,P2Rs, 100000);
+
+receiver(T0, Time, Main, P1,P1N,P1Rs, P2,P2N,P2Rs, C) ->
+ Remain = Time - elapsed_ms(T0, now()), % test time remaining
+ Remain1 = if Remain < 0 ->
+ 0;
+ true ->
+ Remain
+ end,
+ {P1Rs1,P2Rs1} =
+ receive
+ {_Pid,P1} -> % report from a P1 process
+ {P1Rs+1,P2Rs};
+ {_Pid,P2} -> % report from a P2 process
+ {P1Rs,P2Rs+1}
+ after Remain1 ->
+ {P1Rs,P2Rs}
+ end,
+ if Remain > 0 -> % keep going
+ receiver(T0, Time, Main, P1,P1N,P1Rs1, P2,P2N,P2Rs1, C-1);
+ true -> % finish
+ %% calculate results and send to main test process
+ P1Avg = P1Rs1/P1N,
+ P2Avg = P2Rs1/P2N,
+ Ratio = if P2Avg < 1.0 -> P1Avg;
+ true -> P1Avg/P2Avg
+ end,
+ Main ! {self(),{P1Rs1,round(P1Avg),P2Rs1,round(P2Avg),Ratio}},
+ flush_loop()
+ end.
+
+starter({P1,P1N}, {P2,P2N}, Receiver) ->
+ %% start N1 processes with prio P1
+ start_p(P1, P1N, Receiver),
+ %% start N2 processes with prio P2
+ start_p(P2, P2N, Receiver),
+ erlang:display({started,P1N+P2N}),
+ flush_loop().
+
+start_p(_, 0, _) ->
+ ok;
+start_p(Prio, N, Receiver) ->
+ spawn_link(fun() -> p(Prio, Receiver) end),
+ start_p(Prio, N-1, Receiver).
+
+p(Prio, Receiver) ->
+ %% set process priority
+ process_flag(priority, Prio),
+ p_loop(0, Prio, Receiver).
+
+p_loop(100, Prio, Receiver) ->
+ receive after 0 -> ok end,
+ %% if Receiver gone, we're done
+ case is_process_alive(Receiver) of
+ false -> exit(bye);
+ true -> ok
+ end,
+ %% send report
+ Receiver ! {self(),Prio},
+ p_loop(0, Prio, Receiver);
+
+p_loop(N, Prio, Receiver) ->
+ p_loop(N+1, Prio, Receiver).
+
+
+flush_loop() ->
+ receive _ ->
+ ok
+ end,
+ flush_loop().
+
+elapsed_ms({_MS0,S0,MuS0},{_MS1,S1,MuS1}) ->
+ round(((S1-S0)*1000)+((MuS1-MuS0)/1000)).