aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/scheduler_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/scheduler_SUITE.erl')
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl244
1 files changed, 176 insertions, 68 deletions
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index 3aee15a8fc..2e0dfa42f3 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. 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.
@@ -57,6 +57,7 @@
scheduler_suspend_basic/1,
scheduler_suspend/1,
dirty_scheduler_threads/1,
+ poll_threads/1,
reader_groups/1]).
suite() ->
@@ -72,6 +73,7 @@ all() ->
{group, scheduler_bind}, scheduler_threads,
scheduler_suspend_basic, scheduler_suspend,
dirty_scheduler_threads,
+ poll_threads,
reader_groups].
groups() ->
@@ -799,7 +801,7 @@ update_cpu_info(Config) when is_list(Config) ->
unchanged -> ok;
changed -> ok
end;
- {Avail, _} ->
+ {_Avail, _} ->
try
adjust_schedulers_online(),
case erlang:system_info(schedulers_online) of
@@ -807,21 +809,31 @@ update_cpu_info(Config) when is_list(Config) ->
%% Nothing much to test; just a smoke test
ok;
Onln0 ->
- %% unset least significant bit
- Aff = (OldAff band (OldAff - 1)),
- set_affinity_mask(Aff),
- Onln1 = Avail - 1,
- case adjust_schedulers_online() of
- {Onln0, Onln1} ->
- Onln1 = erlang:system_info(schedulers_online),
- receive after 500 -> ok end,
- io:format("TEST - Affinity mask: ~p - Schedulers online: ~p - Scheduler bindings: ~p~n",
- [Aff, Onln1, erlang:system_info(scheduler_bindings)]),
- unchanged = adjust_schedulers_online(),
- ok;
- Fail ->
- ct:fail(Fail)
- end
+ Cpus = bits_in_mask(OldAff),
+ RmCpus = case Cpus > Onln0 of
+ true -> Cpus - Onln0 + 1;
+ false -> Onln0 - Cpus + 1
+ end,
+ Onln1 = Cpus - RmCpus,
+ case Onln1 > 0 of
+ false ->
+ %% Nothing much to test; just a smoke test
+ ok;
+ true ->
+ Aff = restrict_affinity_mask(OldAff, RmCpus),
+ set_affinity_mask(Aff),
+ case adjust_schedulers_online() of
+ {Onln0, Onln1} ->
+ Onln1 = erlang:system_info(schedulers_online),
+ receive after 500 -> ok end,
+ io:format("TEST - Affinity mask: ~p - Schedulers online: ~p - Scheduler bindings: ~p~n",
+ [Aff, Onln1, erlang:system_info(scheduler_bindings)]),
+ unchanged = adjust_schedulers_online(),
+ ok;
+ Fail ->
+ ct:fail(Fail)
+ end
+ end
end
after
set_affinity_mask(OldAff),
@@ -835,22 +847,56 @@ update_cpu_info(Config) when is_list(Config) ->
end
end.
+bits_in_mask(Mask) ->
+ bits_in_mask(Mask, 0, 0).
+
+bits_in_mask(0, _Shift, N) ->
+ N;
+bits_in_mask(Mask, Shift, N) ->
+ case Mask band (1 bsl Shift) of
+ 0 -> bits_in_mask(Mask, Shift+1, N);
+ _ -> bits_in_mask(Mask band (bnot (1 bsl Shift)),
+ Shift+1, N+1)
+ end.
+
+restrict_affinity_mask(Mask, N) ->
+ try
+ restrict_affinity_mask(Mask, 0, N)
+ catch
+ throw : Reason ->
+ exit({Reason, Mask, N})
+ end.
+
+restrict_affinity_mask(Mask, _Shift, 0) ->
+ Mask;
+restrict_affinity_mask(0, _Shift, _N) ->
+ throw(overresticted_affinity_mask);
+restrict_affinity_mask(Mask, Shift, N) ->
+ case Mask band (1 bsl Shift) of
+ 0 -> restrict_affinity_mask(Mask, Shift+1, N);
+ _ -> restrict_affinity_mask(Mask band (bnot (1 bsl Shift)),
+ Shift+1, N-1)
+ end.
+
adjust_schedulers_online() ->
case erlang:system_info(update_cpu_info) of
unchanged ->
unchanged;
changed ->
Avail = erlang:system_info(logical_processors_available),
- {erlang:system_flag(schedulers_online, Avail), Avail}
+ Scheds = erlang:system_info(schedulers),
+ SOnln = case Avail > Scheds of
+ true -> Scheds;
+ false -> Avail
+ end,
+ {erlang:system_flag(schedulers_online, SOnln), SOnln}
end.
read_affinity(Data) ->
Exp = "pid " ++ os:getpid() ++ "'s current affinity mask",
- case string:tokens(Data, ":") of
+ case string:lexemes(Data, ":") of
[Exp, DirtyAffinityStr] ->
- AffinityStr = string:strip(string:strip(DirtyAffinityStr,
- both, $ ),
- both, $\n),
+ AffinityStr = string:trim(DirtyAffinityStr),
case catch erlang:list_to_integer(AffinityStr, 16) of
Affinity when is_integer(Affinity) ->
Affinity;
@@ -1037,26 +1083,18 @@ sbt_test(Config, CpuTCmd, ClBt, Bt, LP) ->
ok.
scheduler_threads(Config) when is_list(Config) ->
- SmpSupport = erlang:system_info(smp_support),
{Sched, SchedOnln, _} = get_sstate(Config, ""),
%% Configure half the number of both the scheduler threads and
%% the scheduler threads online.
- {HalfSched, HalfSchedOnln} = case SmpSupport of
- false -> {1,1};
- true ->
- {Sched div 2,
- SchedOnln div 2}
- end,
+ {HalfSched, HalfSchedOnln} = {lists:max([1,Sched div 2]),
+ lists:max([1,SchedOnln div 2])},
{HalfSched, HalfSchedOnln, _} = get_sstate(Config, "+SP 50:50"),
%% Use +S to configure 4x the number of scheduler threads and
%% 4x the number of scheduler threads online, but alter that
%% setting using +SP to 50% scheduler threads and 25% scheduler
%% threads online. The result should be 2x scheduler threads and
%% 1x scheduler threads online.
- TwiceSched = case SmpSupport of
- false -> 1;
- true -> Sched*2
- end,
+ TwiceSched = Sched*2,
FourSched = integer_to_list(Sched*4),
FourSchedOnln = integer_to_list(SchedOnln*4),
CombinedCmd1 = "+S "++FourSched++":"++FourSchedOnln++" +SP50:25",
@@ -1079,8 +1117,8 @@ scheduler_threads(Config) when is_list(Config) ->
ResetCmd = "+S "++FourSched++":"++FourSchedOnln++" +S 0:0",
{LProc, LProcAvail, _} = get_sstate(Config, ResetCmd),
%% Test negative +S settings, but only for SMP-enabled emulators
- case {SmpSupport, LProc > 1, LProcAvail > 1} of
- {true, true, true} ->
+ case {LProc > 1, LProcAvail > 1} of
+ {true, true} ->
SchedMinus1 = LProc-1,
SchedOnlnMinus1 = LProcAvail-1,
{SchedMinus1, SchedOnlnMinus1, _} = get_sstate(Config, "+S -1"),
@@ -1095,23 +1133,15 @@ scheduler_threads(Config) when is_list(Config) ->
end.
dirty_scheduler_threads(Config) when is_list(Config) ->
- SmpSupport = erlang:system_info(smp_support),
- try
- erlang:system_info(dirty_cpu_schedulers),
- dirty_scheduler_threads_test(Config, SmpSupport)
- catch
- error:badarg ->
- {skipped, "No dirty scheduler support"}
+ case erlang:system_info(dirty_cpu_schedulers) of
+ 0 -> {skipped, "No dirty scheduler support"};
+ _ -> dirty_scheduler_threads_test(Config)
end.
-dirty_scheduler_threads_test(Config, SmpSupport) ->
+dirty_scheduler_threads_test(Config) ->
{Sched, SchedOnln, _} = get_dsstate(Config, ""),
- {HalfSched, HalfSchedOnln} = case SmpSupport of
- false -> {1,1};
- true ->
- {Sched div 2,
- SchedOnln div 2}
- end,
+ {HalfSched, HalfSchedOnln} = {lists:max([1,Sched div 2]),
+ lists:max([1,SchedOnln div 2])},
Cmd1 = "+SDcpu "++integer_to_list(HalfSched)++":"++
integer_to_list(HalfSchedOnln),
{HalfSched, HalfSchedOnln, _} = get_dsstate(Config, Cmd1),
@@ -1123,9 +1153,6 @@ dirty_scheduler_threads_test(Config, SmpSupport) ->
ok.
dirty_schedulers_online_test() ->
- dirty_schedulers_online_test(erlang:system_info(smp_support)).
-dirty_schedulers_online_test(false) -> ok;
-dirty_schedulers_online_test(true) ->
dirty_schedulers_online_smp_test(erlang:system_info(schedulers_online)).
dirty_schedulers_online_smp_test(SchedOnln) when SchedOnln < 4 -> ok;
dirty_schedulers_online_smp_test(SchedOnln) ->
@@ -1374,12 +1401,9 @@ sst2_loop(N) ->
sst2_loop(N-1).
sst3_loop(S, N) ->
- try erlang:system_info(dirty_cpu_schedulers) of
- DS ->
- sst3_loop_with_dirty_schedulers(S, DS, N)
- catch
- error:badarg ->
- sst3_loop_normal_schedulers_only(S, N)
+ case erlang:system_info(dirty_cpu_schedulers) of
+ 0 -> sst3_loop_normal_schedulers_only(S, N);
+ DS -> sst3_loop_with_dirty_schedulers(S, DS, N)
end.
sst3_loop_normal_schedulers_only(_S, 0) ->
@@ -1422,6 +1446,82 @@ sst5_loop(N) ->
erlang:system_flag(multi_scheduling, unblock_normal),
sst5_loop(N-1).
+poll_threads(Config) when is_list(Config) ->
+ {Conc, PollType, KP} = get_ioconfig(Config),
+ {Sched, SchedOnln, _} = get_sstate(Config, ""),
+
+ if
+ Conc ->
+ [1, 1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"),
+ [1, 1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"),
+ [1, 1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"),
+
+ [5, 1] = get_ionum(Config,"+IOt 5 +IOp 1"),
+ [3, 2, 1] = get_ionum(Config,"+IOt 5 +IOp 2"),
+ [2, 2, 2, 2, 2, 1] = get_ionum(Config,"+IOt 10 +IOPp 50"),
+
+ [2, 1] = get_ionum(Config, "+S 2 +IOPt 100"),
+ [4, 1] = get_ionum(Config, "+S 4 +IOPt 100"),
+ [4, 1] = get_ionum(Config, "+S 4:2 +IOPt 100"),
+ [4, 4, 1] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"),
+
+ fail = get_ionum(Config, "+IOt 1 +IOp 2"),
+
+ ok;
+ not Conc ->
+ [1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"),
+ [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"),
+ [1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"),
+
+ [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 1"),
+ [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 2"),
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 10 +IOPp 50"),
+
+ [1, 1] = get_ionum(Config, "+S 2 +IOPt 100"),
+ [1, 1, 1, 1] = get_ionum(Config, "+S 4 +IOPt 100"),
+ [1, 1, 1, 1] = get_ionum(Config, "+S 4:2 +IOPt 100"),
+ [1, 1, 1, 1, 1, 1, 1, 1] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"),
+
+ [1] = get_ionum(Config, "+IOt 1 +IOp 2"),
+
+ ok
+ end,
+
+ fail = get_ionum(Config, "+IOt 1 +IOPp 101"),
+ fail = get_ionum(Config, "+IOt 0"),
+ fail = get_ionum(Config, "+IOPt 101"),
+
+ ok.
+
+get_ioconfig(Config) ->
+ [PS | _] = get_iostate(Config, ""),
+ {proplists:get_value(concurrent_updates, PS),
+ proplists:get_value(primary, PS),
+ proplists:get_value(kernel_poll, PS)}.
+
+get_ionum(Config, Cmd) ->
+ case get_iostate(Config, Cmd) of
+ fail -> fail;
+ PSs ->
+ lists:reverse(
+ lists:sort(
+ [proplists:get_value(poll_threads, PS) || PS <- PSs]))
+ end.
+
+get_iostate(Config, Cmd)->
+ case start_node(Config, Cmd) of
+ {ok, Node} ->
+ [IOStates] = mcall(Node,[fun () ->
+ erlang:system_info(check_io)
+ end]),
+ IO = [IOState || IOState <- IOStates,
+ proplists:get_value(fallback, IOState) == false],
+ stop_node(Node),
+ IO;
+ {error,timeout} ->
+ fail
+ end.
+
reader_groups(Config) when is_list(Config) ->
%% White box testing. These results are correct, but other results
%% could be too...
@@ -1746,18 +1846,24 @@ mcall(Node, Funs) ->
Parent = self(),
Refs = lists:map(fun (Fun) ->
Ref = make_ref(),
- spawn_link(Node,
- fun () ->
- Res = Fun(),
- unlink(Parent),
- Parent ! {Ref, Res}
- end),
- Ref
+ Pid = spawn(Node,
+ fun () ->
+ Res = Fun(),
+ unlink(Parent),
+ Parent ! {Ref, Res}
+ end),
+ MRef = erlang:monitor(process, Pid),
+ {Ref, MRef}
end, Funs),
- lists:map(fun (Ref) ->
+ lists:map(fun ({Ref, MRef}) ->
receive
{Ref, Res} ->
- Res
+ receive
+ {'DOWN',MRef,_,_,_} ->
+ Res
+ end;
+ {'DOWN',MRef,_,_,Reason} ->
+ Reason
end
end, Refs).
@@ -2052,7 +2158,7 @@ workers_exit([Ps|Pss]) ->
workers_exit(Pss).
do_work(PartTime) ->
- lists:reverse(lists:seq(1, 50)),
+ _ = id(lists:seq(1, 50)),
receive stop_work -> receive after infinity -> ok end after 0 -> ok end,
case PartTime of
true -> receive after 1 -> ok end;
@@ -2060,6 +2166,8 @@ do_work(PartTime) ->
end,
do_work(PartTime).
+id(I) -> I.
+
workers(N, _Prio, _PartTime) when N =< 0 ->
[];
workers(N, Prio, PartTime) ->