1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%%% Purpose : Test the timer module a simpler/faster test than timer_SUITE 21 22-module(timer_simple_SUITE). 23 24%% external 25-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 26 init_per_group/2,end_per_group/2, 27 init_per_testcase/2, 28 apply_after/1, 29 send_after1/1, 30 send_after2/1, 31 send_after3/1, 32 exit_after1/1, 33 exit_after2/1, 34 kill_after1/1, 35 kill_after2/1, 36 apply_interval/1, 37 send_interval1/1, 38 send_interval2/1, 39 send_interval3/1, 40 send_interval4/1, 41 cancel1/1, 42 cancel2/1, 43 tc/1, 44 unique_refs/1, 45 timer_perf/1]). 46 47%% internal 48-export([forever/0, 49 do_nrev/2, 50 send/2, 51 timer/4, 52 timer/5]). 53 54-include_lib("common_test/include/ct.hrl"). 55 56-define(MAXREF, (1 bsl 18)). 57-define(REFMARG, 30). 58 59suite() -> 60 [{ct_hooks,[ts_install_cth]}, 61 {timetrap,{minutes,10}}]. 62 63all() -> 64 [apply_after, send_after1, send_after2, send_after3, 65 exit_after1, exit_after2, kill_after1, kill_after2, 66 apply_interval, send_interval1, send_interval2, 67 send_interval3, send_interval4, cancel1, cancel2, tc, 68 unique_refs, timer_perf]. 69 70groups() -> 71 []. 72 73init_per_suite(Config) -> 74 Config. 75 76end_per_suite(_Config) -> 77 ok. 78 79init_per_group(_GroupName, Config) -> 80 Config. 81 82end_per_group(_GroupName, Config) -> 83 Config. 84 85 86init_per_testcase(_, Config) when is_list(Config) -> 87 timer:start(), 88 Config. 89 90%% Testing timer interface!! 91 92%% Test of apply_after, with sending of message. 93apply_after(Config) when is_list(Config) -> 94 timer:apply_after(500, ?MODULE, send, [self(), ok_apply]), 95 ok = get_mess(1000, ok_apply). 96 97%% Test of send_after with time = 0. 98send_after1(Config) when is_list(Config) -> 99 timer:send_after(0, ok_send1), 100 ok = get_mess(1000, ok_send1). 101 102%% Test of send_after with time = 500. 103send_after2(Config) when is_list(Config) -> 104 timer:send_after(500, self(), ok_send2), 105 ok = get_mess(2000, ok_send2). 106 107%% Test of send_after with time = 500, with receiver a registered 108%% process. [OTP-2735] 109send_after3(Config) when is_list(Config) -> 110 Name = list_to_atom(pid_to_list(self())), 111 register(Name, self()), 112 timer:send_after(500, Name, ok_send3), 113 ok = get_mess(2000, ok_send3), 114 unregister(Name). 115 116%% Test of exit_after with time = 1000. 117exit_after1(Config) when is_list(Config) -> 118 process_flag(trap_exit, true), 119 Pid = spawn_link(?MODULE, forever, []), 120 timer:exit_after(1000, Pid, exit_test1), 121 ok = get_mess(5000, {'EXIT', Pid, exit_test1}). 122 123%% Test of exit_after with time = 1000. The process to exit is the 124%% name of a registered process. [OTP-2735] 125exit_after2(Config) when is_list(Config) -> 126 process_flag(trap_exit, true), 127 Pid = spawn_link(?MODULE, forever, []), 128 Name = list_to_atom(pid_to_list(Pid)), 129 register(Name, Pid), 130 timer:exit_after(1000, Name, exit_test2), 131 ok = get_mess(2000, {'EXIT', Pid, exit_test2}). 132 133%% Test of kill_after with time = 1000. 134kill_after1(Config) when is_list(Config) -> 135 process_flag(trap_exit, true), 136 Pid = spawn_link(?MODULE, forever, []), 137 timer:kill_after(1000, Pid), 138 ok = get_mess(2000, {'EXIT', Pid, killed}). 139 140%% Test of kill_after with time = 1000. The process to exit is the 141%% name of a registered process. [OTP-2735] 142kill_after2(Config) when is_list(Config) -> 143 process_flag(trap_exit, true), 144 Pid = spawn_link(?MODULE, forever, []), 145 Name = list_to_atom(pid_to_list(Pid)), 146 register(Name, Pid), 147 timer:kill_after(1000, Name), 148 ok = get_mess(2000, {'EXIT', Pid, killed}). 149 150%% Test of apply_interval by sending messages. Receive 151%% 3 messages, cancel the timer, and check that we do 152%% not get any more messages. 153apply_interval(Config) when is_list(Config) -> 154 {ok, Ref} = timer:apply_interval(1000, ?MODULE, send, 155 [self(), apply_int]), 156 ok = get_mess(1500, apply_int, 3), 157 timer:cancel(Ref), 158 nor = get_mess(1000, apply_int). 159 160%% Test of send_interval/2. Receive 5 messages, cancel the timer, and 161%% check that we do not get any more messages. 162send_interval1(Config) when is_list(Config) -> 163 {ok, Ref} = timer:send_interval(1000, send_int), 164 ok = get_mess(1500, send_int, 5), 165 timer:cancel(Ref), 166 nor = get_mess(1000, send_int). % We should receive only five 167 168%% Test of send_interval/3. Receive 2 messages, cancel the timer, and 169%% check that we do not get any more messages. 170send_interval2(Config) when is_list(Config) -> 171 {ok, Ref} = timer:send_interval(1000, self(), send_int2), 172 ok = get_mess(1500, send_int2, 2), 173 timer:cancel(Ref), 174 nor = get_mess(1000, send_int2). % We should receive only two 175 176%% Test of send_interval/3. Receive 2 messages, cancel the timer, and 177%% check that we do not get any more messages. The receiver is the 178%% name of a registered process. [OTP-2735] 179send_interval3(Config) when is_list(Config) -> 180 process_flag(trap_exit, true), 181 Name = list_to_atom(pid_to_list(self())), 182 register(Name, self()), 183 {ok, Ref} = timer:send_interval(1000, Name, send_int3), 184 ok = get_mess(1500, send_int3, 2), 185 timer:cancel(Ref), 186 nor = get_mess(1000, send_int3), % We should receive only two 187 unregister(Name). 188 189%% Test that send interval stops sending msg when the receiving 190%% process terminates. 191send_interval4(Config) when is_list(Config) -> 192 timer:send_interval(500, one_time_only), 193 receive 194 one_time_only -> ok 195 end, 196 timer_server ! {'EXIT', self(), normal}, % Should remove the timer 197 timer:send_after(600, send_intv_ok), 198 send_intv_ok = receive 199 Msg -> Msg 200 end. 201 202%% Test that we can cancel a timer. 203cancel1(Config) when is_list(Config) -> 204 {ok, Ref} = timer:send_after(1000, this_should_be_canceled), 205 timer:cancel(Ref), 206 nor = get_mess(2000, this_should_be_canceled). % We should rec 0 msgs 207 208%% Test cancel/1 with bad argument. 209cancel2(Config) when is_list(Config) -> 210 {error, badarg} = timer:cancel(no_reference). 211 212%% Test sleep/1 and tc/3. 213tc(Config) when is_list(Config) -> 214 %% This should test both sleep and tc/3 215 {Res1, ok} = timer:tc(timer, sleep, [500]), 216 ok = if 217 Res1 < 500*1000 -> {too_early, Res1}; % Too early 218 Res1 > 800*1000 -> {too_late, Res1}; % Too much time 219 true -> ok 220 end, 221 222 %% tc/2 223 {Res2, ok} = timer:tc(fun(T) -> timer:sleep(T) end, [500]), 224 ok = if 225 Res2 < 500*1000 -> {too_early, Res2}; % Too early 226 Res2 > 800*1000 -> {too_late, Res2}; % Too much time 227 true -> ok 228 end, 229 230 %% tc/1 231 {Res3, ok} = timer:tc(fun() -> timer:sleep(500) end), 232 ok = if 233 Res3 < 500*1000 -> {too_early, Res3}; % Too early 234 Res3 > 800*1000 -> {too_late, Res3}; % Too much time 235 true -> ok 236 end, 237 238 %% Check that timer:tc don't catch errors 239 ok = try timer:tc(erlang, exit, [foo]) 240 catch exit:foo -> ok 241 end, 242 243 ok = try timer:tc(fun(Reason) -> 1 = Reason end, [foo]) 244 catch error:{badmatch,_} -> ok 245 end, 246 247 ok = try timer:tc(fun() -> throw(foo) end) 248 catch foo -> ok 249 end, 250 251 %% Check that return values are propageted 252 Self = self(), 253 {_, Self} = timer:tc(erlang, self, []), 254 {_, Self} = timer:tc(fun(P) -> P end, [self()]), 255 {_, Self} = timer:tc(fun() -> self() end), 256 257 Sec = timer:seconds(4), 258 Min = timer:minutes(4), 259 Hour = timer:hours(4), 260 MyRes = 4*1000 + 4*60*1000 + 4*60*60*1000, 261 if MyRes == Sec + Min + Hour -> ok end, 262 TimerRes = timer:hms(4,4,4), 263 if MyRes == TimerRes -> ok end, 264 ok. 265 266%% Test that cancellations of one-shot timers do not accidentally 267%% cancel interval timers. [OTP-2771]. 268unique_refs(Config) when is_list(Config) -> 269 ITimers = repeat_send_interval(10), % 10 interval timers 270 eat_refs(?MAXREF - ?REFMARG), 271 set_and_cancel_one_shots(?REFMARG), 272 NumLeft = num_timers(), 273 io:format("~w timers left, should be 10\n", [NumLeft]), 274 cancel(ITimers), 275 receive_nisse(), 276 10 = NumLeft. 277 278 279repeat_send_interval(0) -> 280 []; 281repeat_send_interval(M) -> 282 {ok, Ref} = timer:send_interval(6000,self(), nisse), 283 [Ref| repeat_send_interval(M - 1)]. 284 285eat_refs(0) -> 286 0; 287eat_refs(N) -> 288 _ = make_ref(), 289 eat_refs(N-1). 290 291set_and_cancel_one_shots(0) -> 292 0; 293set_and_cancel_one_shots(N) -> 294 {ok, Ref} = timer:send_after(7000, self(), kalle), 295 %% Cancel twice 296 timer:cancel(Ref), 297 timer:cancel(Ref), 298 set_and_cancel_one_shots(N-1). 299 300cancel([T| Ts]) -> 301 timer:cancel(T), 302 cancel(Ts); 303cancel([]) -> 304 ok. 305 306num_timers() -> 307 {{_, TotalTimers},{_, _IntervalTimers}} = timer:get_status(), 308 TotalTimers. 309 310receive_nisse() -> 311 receive 312 nisse -> 313 receive_nisse() 314 after 0 -> 315 ok 316 end. 317 318 319get_mess(Time, Mess) -> get_mess(Time, Mess, 1). 320get_mess(_, _, 0) -> ok; % Received 321get_mess(Time, Mess, N) -> 322 receive 323 Mess -> get_mess(Time, Mess, N-1) 324 after Time 325 -> nor % Not Received 326 end. 327 328forever() -> 329 timer:sleep(1000), 330 forever(). 331 332 333%% 334%% Testing for performance (on different implementations) of timers 335%% 336 337 338timer_perf(Config) when is_list(Config) -> 339 performance(timer). 340 341performance(Mod) -> 342 process_flag(trap_exit, true), 343 {Y,Mo,D} = date(), 344 {H,M,S} = time(), 345 io:format("Testing module '~p' Date: ~w/~w/~w ~w:~w:~w~n", 346 [Mod,Y,Mo,D,H,M,S]), 347 Result = big_test(Mod), 348 report_result(Result). 349 350big_test(M) -> 351 Load_Pids = start_nrev(20, M), % Increase if more load wanted :) 352 353 LPids = spawn_timers(5, M, 10000, 5), 354 355 apply(M, sleep, [4000]), 356 MPids = spawn_timers(10, M, 1000, 6), 357 358 apply(M, sleep, [3500]), 359 SPids = spawn_timers(15, M, 100, 3), 360 361 Res = wait(SPids ++ MPids ++ LPids, [], 0, M), 362 363 lists:foreach(fun(Pid) -> exit(Pid, kill) end, Load_Pids), 364 Res. 365 366wait([], Res, N, _) -> 367 {Res, N}; 368wait(Pids, ResList, N, M) -> 369 receive 370 {Pid, ok, Res, T} -> 371 wait(lists:delete(Pid, Pids), [{T, Res} | ResList], N, M); 372 {Pid, Error}-> 373 ct:fail(Error), 374 wait(lists:delete(Pid, Pids), ResList, N+1, M); 375 {'EXIT', Pid, normal} -> 376 wait(lists:delete(Pid, Pids), ResList, N, M); 377 {'EXIT', Pid, Reason} -> 378 ct:fail({Pid,Reason}) 379 end. 380 381spawn_timers(0, _, _, _) -> 382 []; 383spawn_timers(N, M, T, NumIter) -> 384 apply(M, sleep, [120*N]), 385 Pid1 = spawn_link(?MODULE, timer, [apply, M, T, self()]), 386 Pid2 = spawn_link(?MODULE, timer, [interval, M, T, self(), NumIter]), 387 [Pid1, Pid2 | spawn_timers(N-1, M, T, NumIter)]. 388 389timer(apply, Mod, T, Pid) -> 390 Before = system_time(), 391 {ok, Ref} = apply(Mod, apply_after, [T, ?MODULE, send, [self(), done]]), 392 receive 393 done -> 394 After = system_time(), 395 Pid ! {self(), ok, (After-Before) div 1000, T} 396 after T*3 + 300 -> % Watch dog 397 io:format("WARNING TIMER WATCHDOG timed out: ~w ~n", [T]), 398 timer:cancel(Ref), 399 Pid ! {self(), watch_dog_timed_out} 400 end. 401 402timer(interval, Mod, T, Pid, NumIter) -> 403 Before = system_time(), 404 {ok, Ref} = apply(Mod, apply_interval, [T, ?MODULE, send, [self(), done]]), 405 timer_irec(Before, T, {0, NumIter}, [], {Pid, Mod, Ref}). 406 407timer_irec(_Start, T, {N, N}, Res, {Pid, Mod, Ref}) -> 408 apply(Mod, cancel, [Ref]), 409 Min = lists:min(Res), 410 Max = lists:max(Res), 411 Tot = lists:sum(Res), 412 Pid ! {self(), ok, {N, Tot, Tot div N, Min, Max}, T}; 413timer_irec(Start, T, {N, Max}, Res, {Pid, Mod, Ref}) -> 414 receive 415 done -> 416 Now = system_time(), 417 Elapsed = (Now - (Start + (N*T*1000))) div 1000, 418 timer_irec(Start, T, 419 {N+1, Max}, 420 [Elapsed | Res], 421 {Pid, Mod, Ref}) 422 after T*3 + 300 -> 423 apply(Mod, cancel, [Ref]), 424 io:format("WARNING: TIMER WATCHDOG timed out <Interval>~w~n",[T]), 425 Pid ! {self(), timer_watchdog_timed_out_in_interlval_test} 426 end. 427 428%% ------------------------------------------------------- %% 429%% Small last generator 430 431start_nrev(0, _) -> 432 []; 433 434start_nrev(N, M) -> 435 Pid = spawn_link(?MODULE, do_nrev, [N, M]), 436 [Pid | start_nrev(N-1, M)]. 437 438do_nrev(Sleep, Mod) -> 439 apply(Mod, sleep, [50 * Sleep]), 440 test(1000,"abcdefghijklmnopqrstuvxyz1234"), 441 ok. 442 443test(0,_) -> 444 true; 445test(N,L) -> 446 nrev(L), 447 test(N - 1, L). 448 449nrev([]) -> 450 []; 451nrev([H|T]) -> 452 append(nrev(T), [H]). 453 454append([H|T],Z) -> 455 [H|append(T,Z)]; 456append([],X) -> 457 X. 458 459system_time() -> 460 erlang:monotonic_time(microsecond). 461 462%% ------------------------------------------------------- %% 463 464report_result({Res, 0}) -> 465 {A_List, I_List} = split_list(Res, [], []), 466 A_val = calc_a_val(A_List), 467 I_val = calc_i_val(I_List), 468 print_report(A_val, I_val), 469 ok; 470 471report_result({Head, N}) -> 472 io:format("Test Failed: Number of internal tmo ~w~n", [N]), 473 ct:fail({Head, N}). 474 475split_list([], AL, IL) -> 476 {AL, IL}; 477split_list([{T, {N, Tot, A, Min, Max}} | Rest], AL, IL) -> 478 split_list(Rest, AL, [{T, {N, Tot, A, Min, Max}} | IL]); 479split_list([Head | Rest], AL, IL) -> 480 split_list(Rest, [Head | AL], IL). 481 482split([{T, Res} | R]) -> 483 split(R, {{T,[Res]}, {T*10,[]}, {T*100,[]}}). 484 485split([{T, Res} | R], {{T,S}, M, L}) -> 486 split(R, {{T,[Res|S]}, M, L}); 487 488split([{T, Res} | R], {S, {T,M}, L}) -> 489 split(R, {S, {T, [Res|M]}, L}); 490 491split([{T, Res} | R], {S, M, {T,L}}) -> 492 split(R, {S, M, {T, [Res|L]}}); 493 494split(_Done, Vals) -> 495 Vals. 496 497calc_a_val(List) -> 498 New = lists:sort(List), 499 {{T1, S}, {T2, M}, {T3, L}} = split(New), 500 S2 = {length(S), lists:max(S), lists:min(S), 501 lists:sum(S) div length(S)}, 502 M2 = {length(M), lists:max(M), lists:min(M), 503 lists:sum(M) div length(M)}, 504 L2 = {length(L), lists:max(L), lists:min(L), 505 lists:sum(L) div length(L)}, 506 [{T1, S2}, {T2, M2}, {T3, L2}]. 507 508calc_i_val(List) -> 509 New = lists:sort(List), 510 {{T1, S}, {T2, M}, {T3, L}} = split(New), 511 S2 = get_ivals(S), 512 M2 = get_ivals(M), 513 L2 = get_ivals(L), 514 [{T1, S2}, {T2, M2}, {T3, L2}]. 515 516get_ivals(List) -> 517 Len = length(List), 518 Num = element(1, hd(List)), % Number of iterations 519 520 LTot = lists:map(fun(X) -> element(2, X) end, List), 521 LMin = lists:map(fun(X) -> element(4, X) end, List), 522 LMax = lists:map(fun(X) -> element(5, X) end, List), 523 524 MaxTot = lists:max(LTot), 525 MinTot = lists:min(LTot), 526 AverTot = lists:sum(LTot) div Len, 527 528 IterMax = lists:max(LMax), 529 IterMin = lists:min(LMin), 530 IterAver= AverTot div Num, 531 532 {Len, Num, 533 {MaxTot, MinTot, AverTot}, 534 {IterMax, IterMin, IterAver}}. 535 536 537print_report(A_L, I_L) -> 538 io:format("~nRESULTS from timer test~n~n",[]), 539 io:format("Time out times for send_after~n~n", []), 540 io:format("Time No of tests Max Min Average~n",[]), 541 print_aval(A_L), 542 io:format("Time out times for send_interval~n~n", []), 543 io:format("Time No.tests No.intvals TotMax TotMin TotAver MaxI MinI AverI~n", []), 544 print_ival(I_L). 545 546print_aval([]) -> 547 io:format("~n~n", []); 548print_aval([{T, {L, Max, Min, Aver}}|R]) -> 549 io:format("~5w ~8w ~6w ~6w ~8w ~n", 550 [T,L,Max,Min,Aver]), 551 print_aval(R). 552 553print_ival([]) -> 554 io:format("~n", []); 555print_ival([{T, {Len, Num, 556 {MaxT, MinT, AverT}, 557 {MaxI, MinI, AverI}}}|R]) -> 558 io:format("~5w ~6w ~10w ~8w ~6w ~6w ~6w ~6w ~6w~n", 559 [T,Len,Num,MaxT,MinT,AverT, MaxI, MinI, AverI]), 560 print_ival(R). 561 562send(Pid, Msg) -> 563 Pid ! Msg. 564