1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2005-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: -module(emem_SUITE).
   20: 
   21: %%-define(line_trace, 1).
   22: 
   23: -export([init_per_suite/1, end_per_suite/1,
   24: 	 receive_and_save_trace/2, send_trace/2]).
   25: 
   26: 
   27: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, 
   28: 	 init_per_testcase/2, end_per_testcase/2]).
   29: 
   30: -export([live_node/1,
   31: 	 'sparc_sunos5.8_32b_emt2.0'/1,
   32: 	 'pc_win2000_32b_emt2.0'/1,
   33: 	 'pc.smp_linux2.2.19pre17_32b_emt2.0'/1,
   34: 	 'powerpc_darwin7.7.0_32b_emt2.0'/1,
   35: 	 'alpha_osf1v5.1_64b_emt2.0'/1,
   36: 	 'sparc_sunos5.8_64b_emt2.0'/1,
   37: 	 'sparc_sunos5.8_32b_emt1.0'/1,
   38: 	 'pc_win2000_32b_emt1.0'/1,
   39: 	 'powerpc_darwin7.7.0_32b_emt1.0'/1,
   40: 	 'alpha_osf1v5.1_64b_emt1.0'/1,
   41: 	 'sparc_sunos5.8_64b_emt1.0'/1]).
   42: 
   43: -include_lib("kernel/include/file.hrl").
   44: 
   45: -include_lib("test_server/include/test_server.hrl").
   46: 
   47: -define(DEFAULT_TIMEOUT, ?t:minutes(5)).
   48: 
   49: -define(EMEM_64_32_COMMENT,
   50: 	"64 bit trace; this build of emem can only handle 32 bit traces").
   51: 
   52: -record(emem_res, {nodename,
   53: 		   hostname,
   54: 		   pid,
   55: 		   start_time,
   56: 		   trace_version,
   57: 		   max_word_size,
   58: 		   word_size,
   59: 		   last_values,
   60: 		   maximum,
   61: 		   exit_code}).
   62: 
   63: %%
   64: %%
   65: %% Exported suite functions
   66: %%
   67: %%
   68: 
   69: suite() -> [{ct_hooks,[ts_install_cth]}].
   70: 
   71: all() -> 
   72:     case is_debug_compiled() of
   73: 	true -> {skip, "Not run when debug compiled"};
   74: 	false -> test_cases()
   75:     end.
   76: 
   77: groups() -> 
   78:     [].
   79: 
   80: init_per_group(_GroupName, Config) ->
   81:     Config.
   82: 
   83: end_per_group(_GroupName, Config) ->
   84:     Config.
   85: 
   86: 
   87: test_cases() -> 
   88:     [live_node, 'sparc_sunos5.8_32b_emt2.0',
   89:      'pc_win2000_32b_emt2.0',
   90:      'pc.smp_linux2.2.19pre17_32b_emt2.0',
   91:      'powerpc_darwin7.7.0_32b_emt2.0',
   92:      'alpha_osf1v5.1_64b_emt2.0',
   93:      'sparc_sunos5.8_64b_emt2.0',
   94:      'sparc_sunos5.8_32b_emt1.0', 'pc_win2000_32b_emt1.0',
   95:      'powerpc_darwin7.7.0_32b_emt1.0',
   96:      'alpha_osf1v5.1_64b_emt1.0',
   97:      'sparc_sunos5.8_64b_emt1.0'].
   98: 
   99: init_per_testcase(Case, Config) when is_list(Config) ->
  100:     case maybe_skip(Config) of
  101: 	{skip, _}=Skip -> Skip;
  102: 	ok ->
  103: 	    Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
  104: 
  105: 	    %% Until emem is completely stable we run these tests in a working
  106: 	    %% directory with an ignore_core_files file which will make the
  107: 	    %% search for core files ignore cores generated by this suite.
  108: 	    ignore_cores:setup(?MODULE,
  109: 			       Case,
  110: 			       [{watchdog, Dog}, {testcase, Case} | Config])
  111:     end.
  112: 
  113: end_per_testcase(_Case, Config) when is_list(Config) ->
  114:     ignore_cores:restore(Config),
  115:     Dog = ?config(watchdog, Config),
  116:     ?t:timetrap_cancel(Dog),
  117:     ok.
  118: 
  119: maybe_skip(Config) ->
  120:     DataDir = ?config(data_dir, Config),
  121:     case filelib:is_dir(DataDir) of
  122: 	false ->
  123: 	    {skip, "No data directory"};
  124: 	true ->
  125: 	    case ?config(emem, Config) of
  126: 		undefined ->
  127: 		    {skip, "emem not found"};
  128: 		_ ->
  129: 		    ok
  130: 	    end
  131:     end.
  132: 
  133: init_per_suite(Config) when is_list(Config) ->
  134:     BinDir = filename:join([code:lib_dir(tools), "bin"]),
  135:     Target = erlang:system_info(system_architecture),
  136:     Res = (catch begin 
  137: 		     case check_dir(filename:join([BinDir, Target])) of
  138: 			 not_found -> ok;
  139: 			 TDir ->
  140: 			     check_emem(TDir, purecov),
  141: 			     check_emem(TDir, purify),
  142: 			     check_emem(TDir, debug),
  143: 			     check_emem(TDir, opt)
  144: 		     end,
  145: 		     check_emem(BinDir, opt),
  146: 		     ""
  147: 		 end),
  148:     Res ++ ignore_cores:init(Config).
  149: 
  150: end_per_suite(Config) when is_list(Config) ->
  151:     Config1 = lists:keydelete(emem, 1, Config),
  152:     Config2 = lists:keydelete(emem_comment, 1, Config1),
  153:     ignore_cores:fini(Config2).
  154: 
  155: %%
  156: %%
  157: %% Test cases
  158: %%
  159: %%
  160: 
  161: live_node(doc) -> [];
  162: live_node(suite) -> [];
  163: live_node(Config) when is_list(Config) ->
  164:     ?line {ok, EmuFlag, Port} = start_emem(Config),
  165:     ?line Nodename = mk_nodename(Config),
  166:     ?line {ok, Node} = start_node(Nodename, EmuFlag),
  167:     ?line NP = spawn(Node,
  168: 		     fun () ->
  169: 			     receive go -> ok end,
  170: 			     I = spawn(fun () -> ignorer end),
  171: 			     GC = fun () ->
  172: 					  GCP = fun (P) ->
  173: 							garbage_collect(P)
  174: 						end,
  175: 					  lists:foreach(GCP, processes())
  176: 				  end,
  177: 			     Seq = fun () -> I ! lists:seq(1, 1000000) end,
  178: 			     spawn_link(Seq),
  179: 			     B1 = <<0:10000000>>,
  180: 			     spawn_link(Seq),
  181: 			     B2 = <<0:10000000>>,
  182: 			     spawn_link(Seq),
  183: 			     B3 = <<0:10000000>>,
  184: 			     I ! {B1, B2, B3},
  185: 			     GC(),
  186: 			     GC(),
  187: 			     GC()
  188: 		     end),
  189:     ?line MRef = erlang:monitor(process, NP),
  190:     NP ! go,
  191:     ?line receive
  192: 	      {'DOWN', MRef, process, NP, Reason} ->
  193: 		  ?line spawn(Node, fun () -> halt(17) end),
  194: 		  ?line normal = Reason
  195: 	  end,
  196:     ?line Res = get_emem_result(Port),
  197:     ?line {ok, Hostname} = inet:gethostname(),
  198:     ?line ShortHostname = short_hostname(Hostname),
  199:     ?line {true, _} = has_prefix(Nodename, Res#emem_res.nodename),
  200:     ?line ShortHostname = short_hostname(Res#emem_res.hostname),
  201:     ?line Bits = case erlang:system_info(wordsize) of
  202: 		     4 -> ?line "32 bits";
  203: 		     8 -> ?line "64 bits"
  204: 		 end,
  205:     ?line Bits = Res#emem_res.word_size,
  206:     ?line "17" = Res#emem_res.exit_code,
  207:     ?line emem_comment(Config).
  208: 
  209: 'sparc_sunos5.8_32b_emt2.0'(doc) -> [];
  210: 'sparc_sunos5.8_32b_emt2.0'(suite) -> [];
  211: 'sparc_sunos5.8_32b_emt2.0'(Config) when is_list(Config) ->
  212:     ?line Res = run_emem_on_casefile(Config),
  213:     ?line "test_server" = Res#emem_res.nodename,
  214:     ?line "gorbag" = Res#emem_res.hostname,
  215:     ?line "17074" = Res#emem_res.pid,
  216:     ?line "2005-01-14 17:28:37.881980" = Res#emem_res.start_time,
  217:     ?line "2.0" = Res#emem_res.trace_version,
  218:     ?line "32 bits" = Res#emem_res.word_size,
  219:     ?line ["15",
  220: 	   "2665739", "8992", "548986", "16131", "539994",
  221: 	   "4334192", "1", "99", "15", "98",
  222: 	   "0", "0", "49", "0", "49"] = Res#emem_res.last_values, 
  223:     ?line ["5972061", "9662",
  224: 	   "7987824", "5",
  225: 	   "2375680", "3"] = Res#emem_res.maximum,
  226:     ?line "0" = Res#emem_res.exit_code,
  227:     ?line emem_comment(Config).
  228: 
  229: 'pc_win2000_32b_emt2.0'(doc) -> [];
  230: 'pc_win2000_32b_emt2.0'(suite) -> [];
  231: 'pc_win2000_32b_emt2.0'(Config) when is_list(Config) ->
  232:     ?line Res = run_emem_on_casefile(Config),
  233:     ?line "test_server" = Res#emem_res.nodename,
  234:     ?line "E-788FCF5191B54" = Res#emem_res.hostname,
  235:     ?line "504" = Res#emem_res.pid,
  236:     ?line "2005-01-24 17:27:28.224000" = Res#emem_res.start_time,
  237:     ?line "2.0" = Res#emem_res.trace_version,
  238:     ?line "32 bits" = Res#emem_res.word_size,
  239:     ?line ["11",
  240: 	   "2932575", "8615", "641087", "68924", "632472"]
  241: 	= Res#emem_res.last_values, 
  242:     ?line ["5434206", "9285"] = Res#emem_res.maximum,
  243:     ?line "0" = Res#emem_res.exit_code,
  244:     ?line emem_comment(Config).
  245: 
  246: 'pc.smp_linux2.2.19pre17_32b_emt2.0'(doc) -> [];
  247: 'pc.smp_linux2.2.19pre17_32b_emt2.0'(suite) -> [];
  248: 'pc.smp_linux2.2.19pre17_32b_emt2.0'(Config) when is_list(Config) ->
  249:     ?line Res = run_emem_on_casefile(Config),
  250:     ?line "test_server" = Res#emem_res.nodename,
  251:     ?line "four-roses" = Res#emem_res.hostname,
  252:     ?line "20689" = Res#emem_res.pid,
  253:     ?line "2005-01-20 13:11:26.143077" = Res#emem_res.start_time,
  254:     ?line "2.0" = Res#emem_res.trace_version,
  255:     ?line "32 bits" = Res#emem_res.word_size,
  256:     ?line ["49",
  257: 	   "2901817", "9011", "521610", "10875", "512599",
  258: 	   "5392096", "2", "120", "10", "118",
  259: 	   "0", "0", "59", "0", "59"] = Res#emem_res.last_values,
  260:     ?line ["6182918", "9681",
  261: 	   "9062112", "6",
  262: 	   "2322432", "3"] = Res#emem_res.maximum,
  263:     ?line "0" = Res#emem_res.exit_code,
  264:     ?line emem_comment(Config).
  265: 
  266: 
  267: 'powerpc_darwin7.7.0_32b_emt2.0'(doc) -> [];
  268: 'powerpc_darwin7.7.0_32b_emt2.0'(suite) -> [];
  269: 'powerpc_darwin7.7.0_32b_emt2.0'(Config) when is_list(Config) ->
  270:     ?line Res = run_emem_on_casefile(Config),
  271:     ?line "test_server" = Res#emem_res.nodename,
  272:     ?line "grima" = Res#emem_res.hostname,
  273:     ?line "13021" = Res#emem_res.pid,
  274:     ?line "2005-01-20 15:08:17.568668" = Res#emem_res.start_time,
  275:     ?line "2.0" = Res#emem_res.trace_version,
  276:     ?line "32 bits" = Res#emem_res.word_size,
  277:     ?line ["9",
  278: 	   "2784323", "8641", "531105", "15893", "522464"]
  279: 	= Res#emem_res.last_values,
  280:     ?line ["6150376", "9311"] = Res#emem_res.maximum,
  281:     ?line "0" = Res#emem_res.exit_code,
  282:     ?line emem_comment(Config).
  283: 
  284: 'alpha_osf1v5.1_64b_emt2.0'(doc) -> [];
  285: 'alpha_osf1v5.1_64b_emt2.0'(suite) -> [];
  286: 'alpha_osf1v5.1_64b_emt2.0'(Config) when is_list(Config) ->
  287:     ?line Res = run_emem_on_casefile(Config),
  288:     ?line "test_server" = Res#emem_res.nodename,
  289:     ?line "thorin" = Res#emem_res.hostname,
  290:     ?line "224630" = Res#emem_res.pid,
  291:     ?line "2005-01-20 22:38:01.299632" = Res#emem_res.start_time,
  292:     ?line "2.0" = Res#emem_res.trace_version,
  293:     ?line "64 bits" = Res#emem_res.word_size,
  294:     ?line case Res#emem_res.max_word_size of
  295: 	      "32 bits" ->
  296: 		  ?line emem_comment(Config, ?EMEM_64_32_COMMENT);
  297: 	      "64 bits" ->
  298: 		  ?line ["22",
  299: 			 "6591992", "8625", "516785", "14805", "508160",
  300: 			 "11429184", "5", "127", "254", "122",
  301: 			 "0", "0", "61", "0", "61"] = Res#emem_res.last_values,
  302: 		  ?line ["7041775", "9295",
  303: 			 "11593024", "7",
  304: 			 "2097152", "3"] = Res#emem_res.maximum,
  305: 		  ?line "0" = Res#emem_res.exit_code,
  306: 		  ?line emem_comment(Config)
  307: 	  end.
  308: 
  309: 'sparc_sunos5.8_64b_emt2.0'(doc) -> [];
  310: 'sparc_sunos5.8_64b_emt2.0'(suite) -> [];
  311: 'sparc_sunos5.8_64b_emt2.0'(Config) when is_list(Config) ->
  312:     ?line Res = run_emem_on_casefile(Config),
  313:     ?line "test_server" = Res#emem_res.nodename,
  314:     ?line "gorbag" = Res#emem_res.hostname,
  315:     ?line "10907" = Res#emem_res.pid,
  316:     ?line "2005-01-20 13:48:34.677068" = Res#emem_res.start_time,
  317:     ?line "2.0" = Res#emem_res.trace_version,
  318:     ?line "64 bits" = Res#emem_res.word_size,
  319:     ?line case Res#emem_res.max_word_size of
  320: 	      "32 bits" ->
  321: 		  ?line emem_comment(Config, ?EMEM_64_32_COMMENT);
  322: 	      "64 bits" ->
  323: 		  ?line ["16",
  324: 			 "5032887", "8657", "530635", "14316", "521978",
  325: 			 "8627140", "5", "139", "19", "134",
  326: 			 "0", "0", "67", "0", "67"] = Res#emem_res.last_values,
  327: 		  ?line ["11695070", "9324",
  328: 			 "16360388", "10",
  329: 			 "4136960", "3"] = Res#emem_res.maximum,
  330: 		  ?line "0" = Res#emem_res.exit_code,
  331: 		  ?line emem_comment(Config)
  332: 	  end.
  333: 
  334: 'sparc_sunos5.8_32b_emt1.0'(doc) -> [];
  335: 'sparc_sunos5.8_32b_emt1.0'(suite) -> [];
  336: 'sparc_sunos5.8_32b_emt1.0'(Config) when is_list(Config) ->
  337:     ?line Res = run_emem_on_casefile(Config),
  338:     ?line "" = Res#emem_res.nodename,
  339:     ?line "" = Res#emem_res.hostname,
  340:     ?line "" = Res#emem_res.pid,
  341:     ?line "" = Res#emem_res.start_time,
  342:     ?line "1.0" = Res#emem_res.trace_version,
  343:     ?line "32 bits" = Res#emem_res.word_size,
  344:     ?line ["11",
  345: 	   "2558261", "8643", "560610", "15325", "551967"]
  346: 	= Res#emem_res.last_values,
  347:     ?line ["2791121", "9317"] = Res#emem_res.maximum,
  348:     ?line "0" = Res#emem_res.exit_code,
  349:     ?line emem_comment(Config).
  350: 
  351: 'pc_win2000_32b_emt1.0'(doc) -> [];
  352: 'pc_win2000_32b_emt1.0'(suite) -> [];
  353: 'pc_win2000_32b_emt1.0'(Config) when is_list(Config) ->
  354:     ?line Res = run_emem_on_casefile(Config),
  355:     ?line "" = Res#emem_res.nodename,
  356:     ?line "" = Res#emem_res.hostname,
  357:     ?line "" = Res#emem_res.pid,
  358:     ?line "" = Res#emem_res.start_time,
  359:     ?line "1.0" = Res#emem_res.trace_version,
  360:     ?line "32 bits" = Res#emem_res.word_size,
  361:     ?line ["6",
  362: 	   "2965248", "8614", "640897", "68903", "632283"]
  363: 	= Res#emem_res.last_values,
  364:     ?line ["3147090", "9283"] = Res#emem_res.maximum,
  365:     ?line "0" = Res#emem_res.exit_code,
  366:     ?line emem_comment(Config).
  367: 
  368: 
  369: 'powerpc_darwin7.7.0_32b_emt1.0'(doc) -> [];
  370: 'powerpc_darwin7.7.0_32b_emt1.0'(suite) -> [];
  371: 'powerpc_darwin7.7.0_32b_emt1.0'(Config) when is_list(Config) ->
  372:     ?line Res = run_emem_on_casefile(Config),
  373:     ?line "" = Res#emem_res.nodename,
  374:     ?line "" = Res#emem_res.hostname,
  375:     ?line "" = Res#emem_res.pid,
  376:     ?line "" = Res#emem_res.start_time,
  377:     ?line "1.0" = Res#emem_res.trace_version,
  378:     ?line "32 bits" = Res#emem_res.word_size,
  379:     ?line ["8",
  380: 	   "2852991", "8608", "529662", "15875", "521054"]
  381: 	= Res#emem_res.last_values,
  382:     ?line ["3173335", "9278"] = Res#emem_res.maximum,
  383:     ?line "0" = Res#emem_res.exit_code,
  384:     ?line emem_comment(Config).
  385: 
  386: 'alpha_osf1v5.1_64b_emt1.0'(doc) -> [];
  387: 'alpha_osf1v5.1_64b_emt1.0'(suite) -> [];
  388: 'alpha_osf1v5.1_64b_emt1.0'(Config) when is_list(Config) ->
  389:     ?line Res = run_emem_on_casefile(Config),
  390:     ?line "" = Res#emem_res.nodename,
  391:     ?line "" = Res#emem_res.hostname,
  392:     ?line "" = Res#emem_res.pid,
  393:     ?line "" = Res#emem_res.start_time,
  394:     ?line "1.0" = Res#emem_res.trace_version,
  395:     ?line "64 bits" = Res#emem_res.word_size,
  396:     ?line case Res#emem_res.max_word_size of
  397: 	      "32 bits" ->
  398: 		  ?line emem_comment(Config, ?EMEM_64_32_COMMENT);
  399: 	      "64 bits" ->
  400: 		  ?line ["22",
  401: 			 "6820094", "8612", "515518", "14812", "506906"]
  402: 		      = Res#emem_res.last_values,
  403: 		  ?line ["7292413", "9282"] = Res#emem_res.maximum,
  404: 		  ?line "0" = Res#emem_res.exit_code,
  405: 		  ?line emem_comment(Config)
  406: 	  end.
  407: 
  408: 'sparc_sunos5.8_64b_emt1.0'(doc) -> [];
  409: 'sparc_sunos5.8_64b_emt1.0'(suite) -> [];
  410: 'sparc_sunos5.8_64b_emt1.0'(Config) when is_list(Config) ->
  411:     ?line Res = run_emem_on_casefile(Config),
  412:     ?line "" = Res#emem_res.nodename,
  413:     ?line "" = Res#emem_res.hostname,
  414:     ?line "" = Res#emem_res.pid,
  415:     ?line "" = Res#emem_res.start_time,
  416:     ?line "1.0" = Res#emem_res.trace_version,
  417:     ?line "64 bits" = Res#emem_res.word_size,
  418:     ?line case Res#emem_res.max_word_size of
  419: 	      "32 bits" ->
  420: 		  ?line emem_comment(Config, ?EMEM_64_32_COMMENT);
  421: 	      "64 bits" ->
  422: 		  ?line ["15",
  423: 			 "4965746", "8234", "543940", "14443", "535706"]
  424: 		      = Res#emem_res.last_values,
  425: 		  ?line ["11697645", "8908"] = Res#emem_res.maximum,
  426: 		  ?line "0" = Res#emem_res.exit_code,
  427: 		  ?line emem_comment(Config)
  428: 	  end.
  429: 
  430: %%
  431: %%
  432: %% Auxiliary functions
  433: %%
  434: %%
  435: 
  436: receive_and_save_trace(PortNumber, FileName) when is_integer(PortNumber),
  437: 						  is_list(FileName) ->
  438:     {ok, F} = file:open(FileName, [write, compressed]),
  439:     {ok, LS} = gen_tcp:listen(PortNumber, [inet, {reuseaddr,true}, binary]),
  440:     {ok, S} = gen_tcp:accept(LS),
  441:     gen_tcp:close(LS),
  442:     receive_loop(S,F).
  443: 
  444: receive_loop(Socket, File) ->
  445:     receive
  446: 	{tcp, Socket, Data} ->
  447: 	    ok = file:write(File, Data),
  448: 	    receive_loop(Socket, File);
  449: 	{tcp_closed, Socket} ->
  450: 	    file:close(File),
  451: 	    ok;
  452: 	{tcp_error, Socket, Reason} ->
  453: 	    file:close(File),
  454: 	    {error, Reason}
  455:     end.
  456: 
  457: send_trace({Host, PortNumber}, FileName) when is_list(Host),
  458: 					      is_integer(PortNumber),
  459: 					      is_list(FileName) ->
  460:     ?line {ok, F} = file:open(FileName, [read, compressed]),
  461:     ?line {ok, S} = gen_tcp:connect(Host, PortNumber, [inet,{packet, 0}]),
  462:     ?line send_loop(S, F);
  463: send_trace(EmuFlag, FileName) when is_list(EmuFlag),
  464: 				   is_list(FileName) ->
  465:     ?line ["+Mit", IpAddrStr, PortNoStr] = string:tokens(EmuFlag, " :"),
  466:     ?line send_trace({IpAddrStr, list_to_integer(PortNoStr)}, FileName).
  467: 
  468: send_loop(Socket, File) ->
  469:     ?line case file:read(File, 128) of
  470: 	      {ok, Data} ->
  471: 		  ?line case gen_tcp:send(Socket, Data) of
  472: 			    ok -> ?line send_loop(Socket, File);
  473: 			    Error ->
  474: 				?line gen_tcp:close(Socket),
  475: 				?line file:close(File),
  476: 				Error
  477: 			end;
  478: 	      eof ->
  479: 		  ?line gen_tcp:close(Socket),
  480: 		  ?line file:close(File),
  481: 		  ?line ok;
  482: 	      Error ->
  483: 		  ?line gen_tcp:close(Socket),
  484: 		  ?line file:close(File),
  485: 		  ?line Error
  486: 	  end.
  487: 
  488: check_emem(Dir, Type) when is_atom(Type) ->
  489:     ExeSuffix = case ?t:os_type() of
  490: 		    {win32, _} -> ".exe";
  491: 		    _ -> ""
  492: 		end,
  493:     TypeSuffix = case Type of
  494: 		     opt -> "";
  495: 		     _ -> "." ++ atom_to_list(Type)
  496: 		 end,
  497:     Emem = "emem" ++ TypeSuffix ++ ExeSuffix,
  498:     case check_file(filename:join([Dir, Emem])) of
  499: 	not_found -> ok;
  500: 	File ->
  501: 	    Comment = case Type of
  502: 			  opt -> "";
  503: 			  _ -> "[emem " ++ atom_to_list(Type) ++ " compiled]"
  504: 		      end,
  505: 	    throw([{emem, File}, {emem_comment, Comment}])
  506:     end.
  507: 
  508: check_dir(DirName) ->
  509:     case file:read_file_info(DirName) of
  510: 	{ok, #file_info {type = directory, access = A}} when A == read;
  511: 							     A == read_write ->
  512: 	    DirName;
  513: 	_ ->
  514: 	    not_found
  515:     end.
  516: 
  517: check_file(FileName) ->
  518:     case file:read_file_info(FileName) of
  519: 	{ok, #file_info {type = regular, access = A}} when A == read;
  520: 							   A == read_write ->
  521: 	    ?line FileName;
  522: 	_ ->
  523: 	    ?line not_found
  524:     end.
  525: 
  526: emem_comment(Config) when is_list(Config) ->
  527:     emem_comment(Config, "").
  528: 
  529: emem_comment(Config, ExtraComment)
  530:   when is_list(Config), is_list(ExtraComment) ->
  531:     case {?config(emem_comment, Config), ExtraComment} of
  532: 	{"", ""} -> ?line ok;
  533: 	{"", XC} -> ?line {comment, XC};
  534: 	{EmemC, ""} -> ?line {comment, EmemC};
  535: 	{EmemC, XC} -> ?line {comment, EmemC ++ " " ++ XC}
  536:     end.
  537: 
  538: run_emem_on_casefile(Config) ->
  539:     CaseName = atom_to_list(?config(testcase, Config)),
  540:     ?line File = filename:join([?config(data_dir, Config), CaseName ++ ".gz"]),
  541:     ?line case check_file(File) of
  542: 	      not_found ->
  543: 		  ?line ?t:fail({error, {filenotfound, File}});
  544: 	      _ ->
  545: 		  ?line ok
  546: 	  end,
  547:     ?line {ok, EmuFlag, Port} = start_emem(Config),
  548:     ?line Parent = self(),
  549:     ?line Ref = make_ref(),
  550:     ?line spawn_link(fun () ->
  551: 			     SRes = send_trace(EmuFlag, File),
  552: 			     Parent ! {Ref, SRes}
  553: 		     end),
  554:     ?line Res = get_emem_result(Port),
  555:     ?line receive
  556: 	      {Ref, ok} ->
  557: 		  ?line ok;
  558: 	      {Ref, SendError} ->
  559: 		  ?line ?t:format("Send result: ~p~n", [SendError])
  560: 	  end,
  561:     ?line Res.
  562: 
  563: get_emem_result(Port) ->
  564:     ?line {Res, LV} = get_emem_result(Port, {#emem_res{}, []}),
  565:     ?line Res#emem_res{last_values = string:tokens(LV, " ")}.
  566: 
  567: get_emem_result(Port, {_EmemRes, _LastValues} = Res) ->
  568:     ?line case get_emem_line(Port) of
  569: 	      eof ->
  570: 		  ?line Res;
  571: 	      Line ->
  572: 		  ?line get_emem_result(Port, parse_emem_line(Line, Res))
  573: 	  end.
  574: 
  575: parse_emem_main_header_footer_line(Line, {ER, LV} = Res) ->
  576: 
  577:     %% Header
  578:     ?line case has_prefix("> Nodename:", Line) of
  579: 	      {true, NN} ->
  580: 		  ?line throw({ER#emem_res{nodename = strip(NN)}, LV});
  581: 	      false -> ?line ok
  582: 	  end,
  583:     ?line case has_prefix("> Hostname:", Line) of
  584: 	      {true, HN} ->
  585: 		  ?line throw({ER#emem_res{hostname = strip(HN)}, LV});
  586: 	      false -> ?line ok
  587: 	  end,
  588:     ?line case has_prefix("> Pid:", Line) of
  589: 	      {true, P} ->
  590: 		  ?line throw({ER#emem_res{pid = strip(P)}, LV});
  591: 	      false -> ?line ok
  592: 	  end,
  593:     ?line case has_prefix("> Start time (UTC):", Line) of
  594: 	      {true, ST} ->
  595: 		  ?line throw({ER#emem_res{start_time = strip(ST)}, LV});
  596: 	      false -> ?line ok
  597: 	  end,
  598:     ?line case has_prefix("> Actual trace version:", Line) of
  599: 	      {true, TV} ->
  600: 		  ?line throw({ER#emem_res{trace_version = strip(TV)}, LV});
  601: 	      false -> ?line ok
  602: 	  end,
  603:     ?line case has_prefix("> Maximum trace word size:", Line) of
  604: 	      {true, MWS} ->
  605: 		  ?line throw({ER#emem_res{max_word_size = strip(MWS)}, LV});
  606: 	      false -> ?line ok
  607: 	  end,
  608:     ?line case has_prefix("> Actual trace word size:", Line) of
  609: 	      {true, WS} ->
  610: 		  ?line throw({ER#emem_res{word_size = strip(WS)}, LV});
  611: 	      false -> ?line ok
  612: 	  end,
  613: 
  614:     %% Footer
  615:     ?line case has_prefix("> Maximum:", Line) of
  616: 	      {true, M} ->
  617: 		  ?line throw({ER#emem_res{maximum = string:tokens(M," ")}, LV});
  618: 	      false -> ?line ok
  619: 	  end,
  620:     ?line case has_prefix("> Emulator exited with code:", Line) of
  621: 	      {true, EC} ->
  622: 		  ?line throw({ER#emem_res{exit_code = strip(EC)}, LV});
  623: 	      false -> ?line ok
  624: 	  end,
  625:     ?line Res.
  626: 
  627: parse_emem_header_line(_Line, {_ER, _LV} = Res) ->
  628:     ?line Res.
  629:     
  630: parse_emem_value_line(Line, {EmemRes, _OldLastValues}) ->
  631:     ?line {EmemRes, Line}.
  632: 
  633: parse_emem_line("", Res) ->
  634:     ?line Res;
  635: parse_emem_line(Line, Res) ->
  636:     ?line [Prefix | _] = Line,
  637:     case Prefix of
  638: 	$> -> ?line catch parse_emem_main_header_footer_line(Line, Res);
  639: 	$| -> ?line catch parse_emem_header_line(Line, Res);
  640: 	_ -> ?line catch parse_emem_value_line(Line, Res)
  641:     end.
  642: 
  643: start_emem(Config) when is_list(Config) ->
  644:     ?line Emem = ?config(emem, Config),
  645:     ?line Cd = case ignore_cores:dir(Config) of
  646: 		   false -> [];
  647: 		   Dir -> [{cd, Dir}]
  648: 	       end,
  649:     ?line case open_port({spawn, Emem ++ " -t -n -o -i 1"},
  650: 			 Cd ++ [{line, 1024}, eof]) of
  651: 	      Port when is_port(Port) -> ?line {ok, read_emu_flag(Port), Port};
  652: 	      Error -> ?line ?t:fail(Error)
  653: 	  end.
  654: 
  655: read_emu_flag(Port) ->
  656:     ?line Line = case get_emem_line(Port) of
  657: 		     eof -> ?line ?t:fail(unexpected_end_of_file);
  658: 		     L -> ?line L
  659: 		 end,
  660:     ?line case has_prefix("> Emulator command line argument:", Line) of
  661: 	      {true, EmuFlag} -> EmuFlag;
  662: 	      false -> ?line read_emu_flag(Port)
  663: 	  end.
  664: 
  665: get_emem_line(Port, Acc) ->
  666:     ?line receive
  667: 	      {Port, {data, {eol, Data}}} ->
  668: 		  ?line Res = case Acc of
  669: 				  [] -> ?line Data;
  670: 				  _ -> ?line lists:flatten([Acc|Data])
  671: 			      end,
  672: 		  ?line ?t:format("~s", [Res]),
  673: 		  ?line Res;
  674: 	      {Port, {data, {noeol, Data}}} ->
  675: 		  ?line get_emem_line(Port, [Acc|Data]);
  676: 	      {Port, eof} ->
  677: 		  ?line port_close(Port),
  678: 		  ?line eof
  679: 	  end.
  680: 
  681: get_emem_line(Port) ->
  682:     ?line get_emem_line(Port, []).
  683: 
  684: short_hostname([]) ->
  685:     [];
  686: short_hostname([$.|_]) ->
  687:     [];
  688: short_hostname([C|Cs]) ->
  689:     [C | short_hostname(Cs)].
  690: 
  691: has_prefix([], List) when is_list(List) ->
  692:     {true, List};
  693: has_prefix([P|Xs], [P|Ys]) ->
  694:     has_prefix(Xs, Ys);
  695: has_prefix(_, _) ->
  696:     false.
  697: 
  698: strip(Str) -> string:strip(Str).
  699:     
  700: mk_nodename(Config) ->
  701:     {A, B, C} = now(),
  702:     atom_to_list(?MODULE)
  703: 	++ "-" ++ atom_to_list(?config(testcase, Config))
  704: 	++ "-" ++ integer_to_list(A*1000000000000 + B*1000000 + C).
  705: 
  706: start_node(Name, Args) ->
  707:     ?line Pa = filename:dirname(code:which(?MODULE)),
  708:     ?line ?t:start_node(Name, peer, [{args, Args ++ " -pa " ++ Pa}]).
  709: 
  710: % stop_node(Node) ->
  711: %     ?t:stop_node(Node).
  712: 
  713: is_debug_compiled() -> 
  714: is_debug_compiled(erlang:system_info(system_version)).
  715: 
  716: is_debug_compiled([$d,$e,$b,$u,$g | _]) ->
  717:     true;
  718: is_debug_compiled([ _, _, _, _]) ->
  719:     false;
  720: is_debug_compiled([]) ->
  721:     false;
  722: is_debug_compiled([_|Rest]) ->
  723:     is_debug_compiled(Rest).