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