4
%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
6
%% The contents of this file are subject to the Erlang Public License,
7
%% Version 1.1, (the "License"); you may not use this file except in
8
%% compliance with the License. You should have received a copy of the
9
%% Erlang Public License along with this software. If not, it can be
10
%% retrieved online at http://www.erlang.org/.
12
%% Software distributed under the License is distributed on an "AS IS"
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
%% the License for the specific language governing rights and limitations
21
%% Stress tests of rwmutex implementation.
23
%% Author: Rickard Green
27
%%-define(line_trace,true).
29
-include_lib("common_test/include/ct.hrl").
31
-export([all/0,suite/0,groups/0,
32
init_per_group/2,end_per_group/2, init_per_suite/1,
33
end_per_suite/1, init_per_testcase/2, end_per_testcase/2]).
35
-export([long_rwlock/1,
38
hammer_rwlock_check/1,
40
hammer_tryrwlock_check/1,
41
hammer_sched_long_rwlock/1,
42
hammer_sched_long_rwlock_check/1,
43
hammer_sched_long_freqread_rwlock/1,
44
hammer_sched_long_freqread_rwlock_check/1,
45
hammer_sched_long_tryrwlock/1,
46
hammer_sched_long_tryrwlock_check/1,
47
hammer_sched_long_freqread_tryrwlock/1,
48
hammer_sched_long_freqread_tryrwlock_check/1,
49
hammer_sched_rwlock/1,
50
hammer_sched_rwlock_check/1,
51
hammer_sched_freqread_rwlock/1,
52
hammer_sched_freqread_rwlock_check/1,
53
hammer_sched_tryrwlock/1,
54
hammer_sched_tryrwlock_check/1,
55
hammer_sched_freqread_tryrwlock/1,
56
hammer_sched_freqread_tryrwlock_check/1]).
58
init_per_suite(Config) when is_list(Config) ->
59
DataDir = ?config(data_dir, Config),
60
Lib = filename:join([DataDir, atom_to_list(?MODULE)]),
61
ok = erlang:load_nif(Lib, none),
64
end_per_suite(Config) when is_list(Config) ->
67
init_per_testcase(_Case, Config) ->
68
Dog = ?t:timetrap(?t:minutes(15)),
69
[{watchdog, Dog}|Config].
71
end_per_testcase(_Func, Config) ->
72
Dog = ?config(watchdog, Config),
73
?t:timetrap_cancel(Dog).
75
suite() -> [{ct_hooks,[ts_install_cth]}].
78
[long_rwlock, hammer_rwlock_check, hammer_rwlock,
79
hammer_tryrwlock_check, hammer_tryrwlock,
80
hammer_ets_rwlock, hammer_sched_long_rwlock_check,
81
hammer_sched_long_rwlock,
82
hammer_sched_long_freqread_rwlock_check,
83
hammer_sched_long_freqread_rwlock,
84
hammer_sched_long_tryrwlock_check,
85
hammer_sched_long_tryrwlock,
86
hammer_sched_long_freqread_tryrwlock_check,
87
hammer_sched_long_freqread_tryrwlock,
88
hammer_sched_rwlock_check, hammer_sched_rwlock,
89
hammer_sched_freqread_rwlock_check,
90
hammer_sched_freqread_rwlock,
91
hammer_sched_tryrwlock_check, hammer_sched_tryrwlock,
92
hammer_sched_freqread_tryrwlock_check,
93
hammer_sched_freqread_tryrwlock].
98
init_per_group(_GroupName, Config) ->
101
end_per_group(_GroupName, Config) ->
105
long_rwlock(Config) when is_list(Config) ->
107
LLRes = long_rw_test(),
108
{_, RunTime} = statistics(runtime),
109
%% A very short run time is expected, since
110
%% threads in the test mostly wait
111
?t:format("RunTime=~p~n", [RunTime]),
112
?line true = RunTime < 100,
113
?line RunTimeStr = "Run-time during test was "++integer_to_list(RunTime)++" ms.",
116
{comment, RunTimeStr};
117
{comment, Comment} ->
118
{comment, Comment ++ " " ++ RunTimeStr}
121
hammer_rwlock(Config) when is_list(Config) ->
122
hammer_rw_test(false).
124
hammer_rwlock_check(Config) when is_list(Config) ->
125
hammer_rw_test(true).
127
hammer_tryrwlock(Config) when is_list(Config) ->
128
hammer_tryrw_test(false).
130
hammer_tryrwlock_check(Config) when is_list(Config) ->
131
hammer_tryrw_test(true).
133
hammer_sched_rwlock(Config) when is_list(Config) ->
134
hammer_sched_rwlock_test(false, false, true, 0, 0).
136
hammer_sched_rwlock_check(Config) when is_list(Config) ->
137
hammer_sched_rwlock_test(false, true, true, 0, 0).
139
hammer_sched_freqread_rwlock(Config) when is_list(Config) ->
140
hammer_sched_rwlock_test(true, false, true, 0, 0).
142
hammer_sched_freqread_rwlock_check(Config) when is_list(Config) ->
143
hammer_sched_rwlock_test(true, true, true, 0, 0).
145
hammer_sched_tryrwlock(Config) when is_list(Config) ->
146
hammer_sched_rwlock_test(false, false, false, 0, 100).
148
hammer_sched_tryrwlock_check(Config) when is_list(Config) ->
149
hammer_sched_rwlock_test(false, true, false, 0, 100).
151
hammer_sched_freqread_tryrwlock(Config) when is_list(Config) ->
152
hammer_sched_rwlock_test(true, false, false, 0, 100).
154
hammer_sched_freqread_tryrwlock_check(Config) when is_list(Config) ->
155
hammer_sched_rwlock_test(true, true, false, 0, 100).
157
hammer_sched_long_rwlock(Config) when is_list(Config) ->
158
hammer_sched_rwlock_test(false, false, true, 100, 0).
160
hammer_sched_long_rwlock_check(Config) when is_list(Config) ->
161
hammer_sched_rwlock_test(false, true, true, 100, 0).
163
hammer_sched_long_freqread_rwlock(Config) when is_list(Config) ->
164
hammer_sched_rwlock_test(true, false, true, 100, 0).
166
hammer_sched_long_freqread_rwlock_check(Config) when is_list(Config) ->
167
hammer_sched_rwlock_test(true, true, true, 100, 0).
169
hammer_sched_long_tryrwlock(Config) when is_list(Config) ->
170
hammer_sched_rwlock_test(false, false, false, 100, 100).
172
hammer_sched_long_tryrwlock_check(Config) when is_list(Config) ->
173
hammer_sched_rwlock_test(false, true, false, 100, 100).
175
hammer_sched_long_freqread_tryrwlock(Config) when is_list(Config) ->
176
hammer_sched_rwlock_test(true, false, false, 100, 100).
178
hammer_sched_long_freqread_tryrwlock_check(Config) when is_list(Config) ->
179
hammer_sched_rwlock_test(true, true, false, 100, 100).
181
hammer_sched_rwlock_test(FreqRead, LockCheck, Blocking, WaitLocked, WaitUnlocked) ->
182
case create_rwlock(FreqRead, LockCheck) of
184
{skipped, "Not supported."};
186
Onln = erlang:system_info(schedulers_online),
187
NWPs = case Onln div 3 of
188
1 -> case Onln < 4 of
195
NoLockOps = ((((50000000 div Onln)
196
div case {Blocking, WaitLocked} of
200
div (case WaitLocked == 0 of
202
false -> WaitLocked*250
205
?t:format("NoLockOps=~p~n", [NoLockOps]),
206
Sleep = case Blocking of
208
false -> NoLockOps div 10
214
io:format("Writer on scheduler ~p.~n",
216
Sched = erlang:system_info(scheduler_id),
217
receive go -> gone end,
218
hammer_sched_rwlock_proc(RWLock,
225
Sched = erlang:system_info(scheduler_id)
227
[link, {scheduler, Sched}])
234
io:format("Reader on scheduler ~p.~n",
236
Sched = erlang:system_info(scheduler_id),
237
receive go -> gone end,
238
hammer_sched_rwlock_proc(RWLock,
245
Sched = erlang:system_info(scheduler_id)
247
[link, {scheduler, Sched}])
249
lists:seq(NWPs + 1, NWPs + NRPs)),
251
case {Blocking, WaitLocked} of
254
_ -> statistics(runtime)
256
lists:foreach(fun (P) -> P ! go end, Procs),
257
lists:foreach(fun (P) ->
258
M = erlang:monitor(process, P),
260
{'DOWN', M, process, P, _} ->
265
case {Blocking, WaitLocked} of
269
{_, RunTime} = statistics(runtime),
270
?t:format("RunTime=~p~n", [RunTime]),
271
?line true = RunTime < 500,
273
"Run-time during test was "
274
++ integer_to_list(RunTime)
279
hammer_sched_rwlock_proc(_RWLock,
287
hammer_sched_rwlock_proc(RWLock,
293
Sleep) when Times rem Sleep == 0 ->
294
rwlock_op(RWLock, Blocking, WriteOp, WaitLocked, WaitUnlocked),
295
hammer_sched_rwlock_proc(RWLock,
302
hammer_sched_rwlock_proc(RWLock,
309
rwlock_op(RWLock, Blocking, WriteOp, WaitLocked, 0),
310
hammer_sched_rwlock_proc(RWLock,
318
-define(HAMMER_ETS_RWLOCK_REPEAT_TIMES, 1).
319
-define(HAMMER_ETS_RWLOCK_TSIZE, 500).
321
hammer_ets_rwlock(Config) when is_list(Config) ->
322
{Ops, Procs} = case handicap() of
328
?t:format("Procs=~p~nOps=~p~n", [Procs, Ops]),
329
lists:foreach(fun (XOpts) ->
330
?t:format("Running with extra opts: ~p", [XOpts]),
331
hammer_ets_rwlock_test(XOpts, true, 2, Ops,
335
[{read_concurrency, true}],
336
[{write_concurrency, true}],
337
[{read_concurrency, true},{write_concurrency, true}]]),
343
exit(no_nif_implementation).
345
hammer_rw_test(_Arg) ->
346
exit(no_nif_implementation).
348
hammer_tryrw_test(_Arg) ->
349
exit(no_nif_implementation).
351
create_rwlock(_FreqRead, _LockCheck) ->
352
exit(no_nif_implementation).
354
rwlock_op(_RWLock, _Blocking, _WriteOp, _WaitLocked, _WaitUnlocked) ->
355
exit(no_nif_implementation).
357
hammer_ets_rwlock_put_data() ->
358
put(?MODULE, {"here are some", data, "to store", make_ref()}).
360
hammer_ets_rwlock_get_data() ->
363
hammer_ets_rwlock_ops(_T, _UW, _N, _C, _SC, 0) ->
365
hammer_ets_rwlock_ops(T, UW, N, C, SC, Tot) when N >= ?HAMMER_ETS_RWLOCK_TSIZE ->
366
hammer_ets_rwlock_ops(T, UW, 0, C, SC, Tot);
367
hammer_ets_rwlock_ops(T, UW, N, 0, SC, Tot) ->
370
true = ets:insert(T, {N, Tot, hammer_ets_rwlock_get_data()});
372
[{N, _, _}] = ets:lookup(T, N)
374
hammer_ets_rwlock_ops(T, UW, N+1, SC, SC, Tot-1);
375
hammer_ets_rwlock_ops(T, UW, N, C, SC, Tot) ->
378
true = ets:insert(T, {N, Tot, hammer_ets_rwlock_get_data()});
380
[{N, _, _}] = ets:lookup(T, N)
382
hammer_ets_rwlock_ops(T, UW, N+1, C-1, SC, Tot-1).
384
hammer_ets_rwlock_init(T, N) when N < ?HAMMER_ETS_RWLOCK_TSIZE ->
385
ets:insert(T, {N, N, N}),
386
hammer_ets_rwlock_init(T, N+1);
387
hammer_ets_rwlock_init(_T, _N) ->
390
hammer_ets_rwlock_test(XOpts, UW, C, N, NP, SC) ->
391
receive after 100 -> ok end,
392
{TP, TM} = spawn_monitor(
399
hammer_ets_rwlock_put_data(),
400
T=ets:new(x, [public | XOpts]),
401
hammer_ets_rwlock_init(T, 0),
406
hammer_ets_rwlock_put_data(),
407
receive go -> ok end,
408
hammer_ets_rwlock_ops(T, UW, N, C, C, N),
409
Parent ! {done, self()},
410
receive after infinity -> ok end
419
_ -> [spawn_link(fun () ->
420
hammer_ets_rwlock_put_data(),
421
receive go -> ok end,
422
hammer_ets_rwlock_ops(T, UW, N, SC, SC, N),
423
Parent ! {done, self()},
424
receive after infinity -> ok end
428
lists:foreach(fun (P) -> P ! go end, Ps),
429
lists:foreach(fun (P) -> receive {done, P} -> ok end end, Ps),
431
lists:foreach(fun (P) ->
434
M = erlang:monitor(process, P),
436
{'DOWN', M, process, P, _} -> ok
439
Res = timer:now_diff(Stop, Start)/1000000,
440
Caller ! {?MODULE, self(), Res}
444
{?MODULE, TP, Res} ->
448
?HAMMER_ETS_RWLOCK_REPEAT_TIMES)
451
{'DOWN', TM, process, TP, _} -> ok
454
repeat_list(Fun, N) ->
455
repeat_list(Fun, N, []).
457
repeat_list(_Fun, 0, Acc) ->
459
repeat_list(Fun, N, Acc) ->
460
repeat_list(Fun, N-1, [Fun()|Acc]).
464
X0 = case catch (erlang:system_info(logical_processors_available) >=
465
erlang:system_info(schedulers_online)) of
469
case erlang:system_info(build_type) of
472
ReallySlow when ReallySlow == debug;
473
ReallySlow == valgrind;
474
ReallySlow == purify ->