1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 2006-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: 
   20: %%%-------------------------------------------------------------------
   21: %%% File    : z_SUITE.erl
   22: %%% Author  : Rickard Green <rickard.s.green@ericsson.com>
   23: %%% Description : Misc tests that should be run last
   24: %%%
   25: %%% Created : 15 Jul 2005 by Rickard Green <rickard.s.green@ericsson.com>
   26: %%%-------------------------------------------------------------------
   27: -module(z_SUITE).
   28: -author('rickard.s.green@ericsson.com').
   29: 
   30: %-define(line_trace, 1).
   31: 
   32: -include_lib("test_server/include/test_server.hrl").
   33: 
   34: %-compile(export_all).
   35: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   36: 	 init_per_group/2,end_per_group/2, init_per_testcase/2, 
   37: 	 end_per_testcase/2]).
   38: 
   39: -export([schedulers_alive/1, node_container_refc_check/1,
   40: 	 long_timers/1, pollset_size/1,
   41: 	 check_io_debug/1]).
   42: 
   43: -define(DEFAULT_TIMEOUT, ?t:minutes(5)).
   44: 
   45: suite() -> [{ct_hooks,[ts_install_cth]}].
   46: 
   47: all() -> 
   48:     [schedulers_alive, node_container_refc_check,
   49:      long_timers, pollset_size, check_io_debug].
   50: 
   51: groups() -> 
   52:     [].
   53: 
   54: init_per_suite(Config) ->
   55:     Config.
   56: 
   57: end_per_suite(_Config) ->
   58:     ok.
   59: 
   60: init_per_group(_GroupName, Config) ->
   61:     Config.
   62: 
   63: end_per_group(_GroupName, Config) ->
   64:     Config.
   65: 
   66: 
   67: init_per_testcase(_Case, Config) when is_list(Config) ->
   68:     Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
   69:     [{watchdog, Dog}|Config].
   70: 
   71: end_per_testcase(_Case, Config) when is_list(Config) ->
   72:     Dog = ?config(watchdog, Config),
   73:     ?t:timetrap_cancel(Dog),
   74:     ok.
   75: 
   76: %%%
   77: %%% The test cases -------------------------------------------------------------
   78: %%%
   79: 
   80: schedulers_alive(doc) -> ["Tests that all schedulers are actually used"];
   81: schedulers_alive(suite) -> [];
   82: schedulers_alive(Config) when is_list(Config) ->
   83:     ?line Master = self(),
   84:     ?line NoSchedulersOnline = erlang:system_flag(
   85: 				 schedulers_online,
   86: 				 erlang:system_info(schedulers)),
   87:     ?line NoSchedulers = erlang:system_info(schedulers),
   88:     UsedScheds =
   89: 	try
   90: 	    ?line ?t:format("Number of schedulers configured: ~p~n", [NoSchedulers]),
   91: 	    ?line case erlang:system_info(multi_scheduling) of
   92: 		      blocked ->
   93: 			  ?line ?t:fail(multi_scheduling_blocked);
   94: 		      disabled ->
   95: 			  ?line ok;
   96: 		      enabled ->
   97: 			  ?t:format("Testing blocking process exit~n"),
   98: 			  BF = fun () ->
   99: 				       blocked = erlang:system_flag(multi_scheduling,
  100: 								    block),
  101: 				       Master ! {self(), blocking},
  102: 				       receive after infinity -> ok end
  103: 			       end,
  104: 			  ?line Blocker = spawn_link(BF),
  105: 			  ?line Mon = erlang:monitor(process, Blocker),
  106: 			  ?line receive {Blocker, blocking} -> ok end,
  107: 			  ?line [Blocker]
  108: 			      = erlang:system_info(multi_scheduling_blockers),
  109: 			  ?line unlink(Blocker),
  110: 			  ?line exit(Blocker, kill),
  111: 			  ?line receive {'DOWN', Mon, _, _, _} -> ok end,
  112: 			  ?line enabled = erlang:system_info(multi_scheduling),
  113: 			  ?line [] = erlang:system_info(multi_scheduling_blockers),
  114: 			  ?line ok
  115: 		  end,
  116: 	    ?t:format("Testing blocked~n"),
  117: 	    ?line erlang:system_flag(multi_scheduling, block),
  118: 	    ?line case erlang:system_info(multi_scheduling) of
  119: 		      enabled ->
  120: 			  ?line ?t:fail(multi_scheduling_enabled);
  121: 		      blocked ->
  122: 			  ?line [Master] = erlang:system_info(multi_scheduling_blockers);
  123: 		      disabled -> ?line ok
  124: 		  end,
  125: 	    ?line Ps = lists:map(
  126: 			 fun (_) ->
  127: 				 spawn_link(fun () ->
  128: 						    run_on_schedulers(none,
  129: 								      [],
  130: 								      Master)
  131: 					    end)
  132: 			 end,
  133: 			 lists:seq(1,NoSchedulers)),
  134: 	    ?line receive after 1000 -> ok end,
  135: 	    ?line {_, 1} = verify_all_schedulers_used({[],0}, 1),
  136: 	    ?line lists:foreach(fun (P) ->
  137: 					unlink(P),
  138: 					exit(P, bang)
  139: 				end,
  140: 				Ps),
  141: 	    ?line case erlang:system_flag(multi_scheduling, unblock) of
  142: 		      blocked -> ?line ?t:fail(multi_scheduling_blocked);
  143: 		      disabled -> ?line ok;
  144: 		      enabled -> ?line ok
  145: 		  end,
  146: 	    erts_debug:set_internal_state(available_internal_state, true),
  147: 	    %% node_and_dist_references will use emulator interal thread blocking...
  148: 	    erts_debug:get_internal_state(node_and_dist_references), 
  149: 	    erts_debug:set_internal_state(available_internal_state, false),
  150: 	    ?t:format("Testing not blocked~n"),
  151: 	    ?line Ps2 = lists:map(
  152: 			  fun (_) ->
  153: 				  spawn_link(fun () ->
  154: 						     run_on_schedulers(none,
  155: 								       [],
  156: 								       Master)
  157: 					     end)
  158: 			  end,
  159: 			  lists:seq(1,NoSchedulers)),
  160: 	    ?line receive after 1000 -> ok end,
  161: 	    ?line {_, NoSIDs} = verify_all_schedulers_used({[],0},NoSchedulers),
  162: 	    ?line lists:foreach(fun (P) ->
  163: 					unlink(P),
  164: 					exit(P, bang)
  165: 				end,
  166: 				Ps2),
  167: 	    NoSIDs
  168: 	after
  169: 	    NoSchedulers = erlang:system_flag(schedulers_online,
  170: 					      NoSchedulersOnline),
  171: 	    NoSchedulersOnline = erlang:system_info(schedulers_online)
  172: 	end,
  173:     ?line {comment, "Number of schedulers " ++ integer_to_list(UsedScheds)}.
  174: 
  175: 
  176: run_on_schedulers(LastSID, SIDs, ReportTo) ->
  177:     case erlang:system_info(scheduler_id) of
  178: 	LastSID ->
  179: 	    erlang:yield(),
  180: 	    run_on_schedulers(LastSID, SIDs, ReportTo);
  181: 	SID ->
  182: 	    NewSIDs = case lists:member(SID, SIDs) of
  183: 			  true ->
  184: 			      SIDs;
  185: 			  false ->
  186: 			      ReportTo ! {scheduler_used, SID},
  187: 			      [SID | SIDs]
  188: 		      end,
  189: 	    erlang:yield(),
  190: 	    run_on_schedulers(SID, NewSIDs, ReportTo)
  191:     end.
  192: 
  193: wait_on_used_scheduler({SIDs, SIDsLen} = State) ->
  194:     receive
  195: 	{scheduler_used, SID} ->
  196: 	    case lists:member(SID, SIDs) of
  197: 		true ->
  198: 		    wait_on_used_scheduler(State);
  199: 		false ->
  200: 		    ?t:format("Scheduler ~p used~n", [SID]),
  201: 		    {[SID|SIDs], SIDsLen+1}
  202: 	    end
  203:     end.
  204: 
  205: verify_all_schedulers_used({UsedSIDs, UsedSIDsLen} = State, NoSchedulers) ->
  206:     ?line case NoSchedulers of
  207: 	      UsedSIDsLen ->
  208: 		  ?line State;
  209: 	      NoSchdlrs when NoSchdlrs < UsedSIDsLen ->
  210: 		  ?line ?t:fail({more_schedulers_used_than_exist,
  211: 				 {existing_schedulers, NoSchdlrs},
  212: 				 {used_schedulers, UsedSIDsLen},
  213: 				 {used_scheduler_ids, UsedSIDs}});
  214: 	      _ ->
  215: 		  ?line NewState = wait_on_used_scheduler(State),
  216: 		  ?line verify_all_schedulers_used(NewState, NoSchedulers)
  217: 	  end.
  218: 
  219: node_container_refc_check(doc) -> [];
  220: node_container_refc_check(suite) -> [];
  221: node_container_refc_check(Config) when is_list(Config) ->
  222:     ?line node_container_SUITE:node_container_refc_check(node()),
  223:     ?line ok.
  224: 
  225: long_timers(doc) ->
  226:     [];
  227: long_timers(suite) ->
  228:     [];
  229: long_timers(Config) when is_list(Config) ->
  230:     ?line ok = long_timers_test:check_result().
  231: 
  232: pollset_size(doc) ->
  233:     [];
  234: pollset_size(suite) ->
  235:     [];
  236: pollset_size(Config) when is_list(Config) ->
  237:     ?line Name = pollset_size_testcase_initial_state_holder,
  238:     ?line Mon = erlang:monitor(process, Name),
  239:     ?line (catch Name ! {get_initial_check_io_result, self()}),
  240:     ?line InitChkIo = receive
  241: 			  {initial_check_io_result, ICIO} ->
  242: 			      ?line erlang:demonitor(Mon, [flush]),
  243: 			      ?line ICIO;
  244: 			  {'DOWN', Mon, _, _, Reason} ->
  245: 			      ?line ?t:fail({non_existing, Name, Reason})
  246: 		      end,
  247:     ?line FinChkIo = get_check_io_info(),
  248:     ?line io:format("Initial: ~p~nFinal: ~p~n", [InitChkIo, FinChkIo]),
  249:     ?line InitPollsetSize = lists:keysearch(total_poll_set_size, 1, InitChkIo),
  250:     ?line FinPollsetSize = lists:keysearch(total_poll_set_size, 1, FinChkIo),
  251:     ?line case InitPollsetSize =:= FinPollsetSize of
  252: 	      true ->
  253: 		  case InitPollsetSize of
  254: 		      {value, {total_poll_set_size, Size}} ->
  255: 			  ?line {comment,
  256: 				 "Pollset size: " ++ integer_to_list(Size)};
  257: 		      _ ->
  258: 			  ?line {skipped,
  259: 				 "Pollset size information not available"}
  260: 		  end;
  261: 	      false ->
  262: 		  %% Somtimes we have fewer descriptors in the
  263: 		  %% pollset at the end than when we started, but
  264: 		  %% that is ok as long as there are at least 2
  265: 		  %% descriptors (dist listen socket and
  266: 		  %% epmd socket) in the pollset.
  267: 		  ?line {value, {total_poll_set_size, InitSize}}
  268: 		      = InitPollsetSize,
  269: 		  ?line {value, {total_poll_set_size, FinSize}}
  270: 		      = FinPollsetSize,
  271: 		  ?line true = FinSize < InitSize,
  272: 		  ?line true = 2 =< FinSize,
  273: 		  ?line {comment,
  274: 			 "Start pollset size: "
  275: 			 ++ integer_to_list(InitSize)
  276: 			 ++ " End pollset size: "
  277: 			 ++ integer_to_list(FinSize)}
  278: 	  end.
  279: 
  280: check_io_debug(doc) ->
  281:     [];
  282: check_io_debug(suite) ->
  283:     [];
  284: check_io_debug(Config) when is_list(Config) ->
  285:     ?line case lists:keysearch(name, 1, erlang:system_info(check_io)) of
  286: 	      {value, {name, erts_poll}} -> ?line check_io_debug_test();
  287: 	      _ -> ?line {skipped, "Not implemented in this emulator"}
  288: 	  end.
  289: 
  290: check_io_debug_test() ->
  291:     ?line erts_debug:set_internal_state(available_internal_state, true),
  292:     ?line erlang:display(erlang:system_info(check_io)),
  293:     ?line NoOfErrorFds = erts_debug:get_internal_state(check_io_debug),
  294:     ?line erts_debug:set_internal_state(available_internal_state, false),
  295:     ?line 0 = NoOfErrorFds,
  296:     ?line ok.
  297: 
  298: 
  299: 
  300: %%
  301: %% Internal functions...
  302: %%
  303: 
  304: display_check_io(ChkIo) ->
  305:     catch erlang:display('--- CHECK IO INFO ---'),
  306:     catch erlang:display(ChkIo),
  307:     catch erts_debug:set_internal_state(available_internal_state, true),
  308:     NoOfErrorFds = (catch erts_debug:get_internal_state(check_io_debug)),
  309:     catch erlang:display({'NoOfErrorFds', NoOfErrorFds}),
  310:     catch erts_debug:set_internal_state(available_internal_state, false),
  311:     catch erlang:display('--- CHECK IO INFO ---'),
  312:     ok.
  313: 
  314: get_check_io_info() ->
  315:     ChkIo = erlang:system_info(check_io),
  316:     case lists:keysearch(pending_updates, 1, ChkIo) of
  317: 	{value, {pending_updates, 0}} ->
  318: 	    display_check_io(ChkIo),
  319: 	    ChkIo;
  320: 	false ->
  321: 	    ChkIo;
  322: 	_ ->
  323: 	    receive after 10 -> ok end,
  324: 	    get_check_io_info()
  325:     end.
  326: 
  327: 
  328: