1#! /usr/bin/env perl
2##
3## Copyright (C) by Argonne National Laboratory
4##     See COPYRIGHT in top-level directory
5##
6
7# checkbuilds.  Generated from checkbuilds.in by configure.
8#
9# Configure and build mpich with some of the options
10#
11# Set default values
12$projects_dir = "/home/MPI/testing/tsuites";
13# alt is for systems that have /homes instead of /home
14$altprojects_dir = "/homes/MPI/testing/tsuites";
15if (! -d $projects_dir && -d $altprojects_dir ) {
16    $projects_dir = $altprojects_dir;
17}
18$srcdir  = "/home/MPI/testing/mpich2/mpich2";
19$logname = $ENV{"LOGNAME"};
20$tmpdir = "/sandbox/$logname";
21# rundir is the directory in which to run the tests.
22$rundir = "";
23
24# By default, use random arguments for the tests
25$use_rand_args = 1;
26#
27$is_xml = 0;
28# Set the default compilers.  These can be overridden by setting the CC
29# and FC environment variables.
30$ccname = "gcc";
31$fcname = "f77";
32#
33# Set whether the C++ and Fortran bindings have been built.
34$has_f77 = 1;
35$has_cxx = 1;
36
37# Set this for the make option to enable the execution of multiple job
38# steps at once.  Do not use this if the archive step (ar) is not setup
39# to avoid concurrent, conflicting updates to the same archive.
40$parallelBuild = "-j 8";
41#$parallelBuild = "";
42#
43# Some process managers require separate startup and rundown steps.  The
44# following variables are used to handle this
45$StartDemon = "";     # Name of routine to start demons
46$StopDemon  = "";     # Name of routine to stop demons
47$hasDemon   = 0;
48
49#
50# Set available options.  For enable and with, the values are
51# {with,enable}-name[;possiblevalues]*
52# We need a way to keep these consistent with the arguments recognized by
53# configure
54@enable_array = (
55		  'error-checking;no;runtime;all',
56		  'error-messages;all;generic;class;none',
57		  'timer-type;linux86_cycle;gethrtime;clock_gettime;gettimeofday',
58		  'timing;none;all;runtime;log;log_detailed',
59		  'g;none;all;handle;dbg;log;meminit;handlealloc;instr;mem;mutex;memarena',
60		  'fast;nochkmsg;notiming;ndebug;all',
61		  'f77',
62		  'fc',
63		  'cxx',
64		  'romio',
65		  'coverage',
66                  'check-compiler-flags',
67                  'smpcoll',
68		  'strict;c99;posix',    #;posix
69		  'debuginfo', # Message queues
70		  'weak-symbols;no;yes',
71                  'threads;single;multiple;runtime',
72                  'thread-cs;global;per-object;lock-free',
73                  'refcount;lock;lock-free;none',
74                  'mutex-timing',
75                  'multi-aliases',
76                  'predefined-refcount',
77                  'alloca',
78                  'yield;sched_yield;yield;select;usleep;sleep',
79                  'checkpointing',
80		  'runtimevalues',   # Fortran true/false
81);
82%chosenEnable = ();
83@with_array = (
84	       'logging;none;rlog',
85	       'pmi;simple',    #; uni no longer supported
86	       'pm;gforker', #;remshell
87	       'namepublisher;no;file', #;ldap:ldapserver',
88	       'device;ch3;ch3:sock',
89	       'wrapper-dl-type;runpath;rpath;none',
90);
91%chosenWith = ();
92@env_array = (
93#	      'CC;gcc;cc;pgcc;ecc;xlc',
94#	      'FC;f77;pgf77;efc;xlf',
95#	      'CXX;gcc;CC;pgCC;ecc;xlC',
96#             'CFLAGS;-g;-O',
97);
98
99# Also cross;sample-cross-files, but we need the files first
100# Also missing are levels of thread support.
101
102$n_enable  = $#enable_array + 1;
103$n_with    = $#with_array + 1;
104$n_env     = $#env_array + 1;
105$show      = 0;
106$debug     = 0;
107$echoSteps = 0;         # Set to one to echo each run program to stdout
108$report_signals = 1;    # Set to one to generate a message about signals
109                        # received by a program
110$max_count = 5;
111$OUTFD     = OUTFD;
112#
113# The following variable separate the various sections
114$TestStart = "-----------------------------------------------------------\n";
115$TestEnd   = "-----------------------------------------------------------\n";
116$TestDateStart = "Run on ";
117$TestDateEnd   = "\n";
118$TestHostStart = "Run on host ";
119$TestHostEnd   = "\n";
120$TestUserStart = "Run by ";
121$TestUserEnd   = "\n";
122$ConfigStart = " -- Begin Configure Step -- \n";
123$ConfigEnd   = " -- End   Configure Step -- \n";
124$MakeStart   = " -- Begin Make Step --\n";
125$MakeEnd     = " -- End   Make Step --\n";
126$GlobNameStart = " -- Begin Check of global names --\n";
127$GlobNameEnd   = " -- End   Check of global names --\n";
128$UsedNameStart = " -- Begin Check of used names --\n";
129$UsedNameEnd   = " -- End   Check of used names --\n";
130$MakeInstStart = " -- Begin Make Install Step --\n";
131$MakeInstEnd   = " -- End   Make Install Step --\n";
132$MakeInstcheckStart = " -- Begin Make Installcheck Step --\n";
133$MakeInstcheckEnd   = " -- End   Make Installcheck Step --\n";
134$RunTestStart  = " -- Begin Run Test Step --\n";
135$RunTestEnd    = " -- End   Run Test Step --\n";
136$SumStart = "";
137$SumEnd   = "";
138$SumConfigStart = "Config status = ";
139$SumConfigEnd   = "\n";
140$SumMakeStart = "Make status = ";
141$SumMakeEnd   = "\n";
142$SumGlobStart  = "Global name check status = ";
143$SumGlobEnd    = "\n";
144$SumInstStart = "Install status = ";
145$SumInstEnd   = "\n";
146$SumTestRunStart = "Test status = ";
147$SumTestRunEnd   = "\n";
148
149# Defaults
150$config_args = "";
151$with_args   = "";
152$enable_args = "";
153$env_args    = "";
154$outfile     = "";
155$builddir    = "";
156$instdir     = "";
157# Read the arguments
158foreach $_ (@ARGV) {
159    if (/--?enable-n=(\d*)/) {
160	$n_enable = $1;
161    }
162    elsif (/--?with-n=(\d*)/) {
163	$n_with = $1;
164    }
165    elsif (/--?show/) {
166	$show = 1;
167    }
168    elsif (/--?debug/) {
169	$debug = 1;
170    }
171    elsif (/--?envopt=(.*)/) {
172	# Add a list of possible env values
173	$env_array[$#env_array+1] = $1;
174	$n_env    = $#env_array + 1;
175    }
176    elsif (/--?srcdir=(.*)/) {
177	$srcdir  = $1;
178    }
179    elsif (/--?instdir=(.*)/) {
180	$instdir = $1;
181    }
182    elsif (/--?rundir=(.*)/) {
183	$rundir = $1;
184    }
185    elsif (/--?projectsdir=(.*)/) {
186	$projects_dir = $1;
187    }
188    elsif (/--?maxcount=(.*)/) {
189	# max count.  Set to -1 for infinity
190	$max_count = $1;
191    }
192    elsif (/--?maxtime=(.*)/) {
193	# max time in seconds
194	set_time_left( $1 );
195    }
196    elsif (/--?tests=(.*)/) {
197	$tests = ":" . $1 . ":";
198    }
199    elsif (/--?outfile=(.*)/) {
200	$outfile = $1;
201    }
202    elsif (/--?tmpdir=(.*)/) {
203	$tmpdir = $1;
204    }
205    elsif (/--?builddir=(.*)/) {
206	$builddir = $1;
207    }
208    elsif (/--?xml/) {
209	&XMLStyle;
210	$is_xml = 1;
211    }
212    elsif (/--?norand/) {
213	$use_rand_args = 0;
214    }
215    elsif (/--?enable=(.*)/) {
216	$use_rand_args = 0;
217	$enable_args .= "$1 ";
218    }
219    elsif (/--?with=(.*)/) {
220	$use_rand_args = 0;
221	$with_args .= "$1 ";
222    }
223    elsif (/--?env=(.*)/) {
224	$use_rand_args = 0;
225	$envval=$1;
226	$envval =~ s/ /<SP>/g;
227	$env_args .= "--env-$envval ";
228    }
229    elsif (/--?configarg=(.*)/) {
230	# Use this to add a special arg (such as -host) to the
231	# configure call
232	$config_args .= "$1 ";
233    }
234    elsif (/--?help/) {
235	print STDERR "\
236checkbuilds [ -enable-n=d ] [ -with-n=d ] [ -show ] [-envopt=name;value;... ]
237            [-srcdir=SRCDIR] [-instdir=INSTALLDIR] [-builddir=BUILDDIR]
238            [-maxcount=MAXCNT] [-maxtime=MAXTIME]
239            [-norand ] [-enable=enable-args] [-with=with-args]
240            [-tmpdir=dir]
241        -enable-n=d sets the number of --enable options to try
242        -with=n=d set the number of --with options to try
243        -envopt=name;value;... adds an environment variable with possible
244                 values (quote the text so that the semicolons do not
245                 cause trouble)
246
247        -maxcount sets the number of builds to try
248        -maxtime sets the maximum length of time to run
249        Example:
250        checkbuilds -envopt=\"CC;gcc;pgcc;ecc\"\n";
251        exit(0);
252    }
253
254    else {
255	print STDERR "checkbuilds: Unrecognized argument $_\n";
256	exit(1);
257    }
258}
259
260#
261# Set directories that have not been chosen.
262if ($instdir eq "") {
263    $instdir = "$tmpdir/cb/mpi2-inst";
264}
265if ($mpich1_dir eq "") {
266    $mpich1_dir = "$projects_dir/mpich1test";
267}
268# Make the builddir compatible with the installation directory
269if ($builddir eq "") {
270    $builddir = "$tmpdir/cb/mpich2";
271}
272
273# ---------------------------------------------------------------------------
274
275#
276# ---------------------------------------------------------------------------
277# Run one instance of the configuration
278sub RunTest {
279    my $makepgm;
280
281    $rc = chdir $builddir;
282    if (!$rc) {
283	print STDERR "Cannot change to $builddir\n";
284	return;
285    }
286    # Clean the installation and build directories
287    # Even better would be to remove the installation directory alltogether,
288    # but we should only do that if explicitly requested (we could
289    # *require* an empty directory for the tests instead)
290    if (-d "$instdir/lib") {
291	system "rm -f $instdir/lib/libmpi*.* $instdir/lib/libmpifort*.*";
292	system "rm -f $instdir/lib/libmpe*.a";
293    }
294    if (-d "$instdir/bin") {
295	system "rm -f $instdir/bin/mpi*";
296    }
297    if (-d "$builddir/lib") {
298	system "rm -f $builddir/lib/libmpi*.* $builddir/lib/libmpifort*.*";
299	system "rm -f $builddir/lib/libmpe*.a";
300    }
301    #
302    # Create the with and enable options
303    #$enable_args = "--enable-strict";  # Only if compiler is gcc
304    # Chosen *without* replacement.  If an option is chosen twice,
305    # then there will be fewer options
306    %chosenWith = ();
307    %chosenEnable = ();
308    if ($use_rand_args) {
309	$enable_args = &RandArgs( $n_enable, "enable_array", "enable", "disable" );
310	$with_args   = &RandArgs ( $n_with, "with_array", "with", "without" );
311
312	# To set the environment, use the same code to set things up,
313	# then process the env array to set the environment
314	$env_args    = &RandArgs( $n_env, "env_array", "env" );
315    }
316    foreach my $en (split(/\s+/,$enable_args)) {
317	if ($en =~ /--enable-([-A-Za-z0-9=]*)/) {
318	    my $name = $1;
319	    if ($name =~ /(.*)=(.*)/) {
320		$chosenEnable{$1} = $2;
321		$name = $1;
322	    }
323	    else {
324		$chosenEnable{$name} = "yes";
325	    }
326	    print STDERR "setting chosen enable of $name to $chosenEnable{$name}\n" if $debug;
327	}
328    }
329    foreach my $en (split(/\s+/,$with_args)) {
330	if ($en =~ /--with-([-A-Za-z0-9=]*)/) {
331	    my $name = $1;
332	    if ($name =~ /(.*)=(.*)/) {
333		$chosenWith{$1} = $2;
334		$name = $1;
335	    }
336	    else {
337		$chosenWith{$name} = "yes";
338	    }
339	    print STDERR "setting chosen with of $name to $chosenWith{$name}\n" if $debug;
340	}
341    }
342
343    $envset = "";
344    %saveENV = %ENV;
345    foreach $_ (split(/ /,$env_args)) {
346	if (/--env-([^=]*)=(.*)/) {
347	    $name  = $1;
348	    $value = $2;
349	    # Replace <SP> with blanks
350	    $value =~ s/<SP>/ /g;
351	    # Grrr <SP> is a bad choice, since <> are shell metacharacters.
352	    # Allow --SP-- as an alternative
353	    $value =~ s/--SP--/ /g;
354	    print "Env $name = $value\n" if $debug;
355	    # Since most of these so far are programs, we should check to
356	    # see if they're available.  Instead, we'll make the user
357	    # specify the valid values (see -envopt above)
358	    $ENV{$name} = $value;
359	    $envset .= "$name = $value; ";
360	}
361    }
362
363    # Get the version of make to use
364    if (defined($ENV{"MAKE"})) {
365	$makepgm = $ENV{"MAKE"};
366    }
367    else {
368	$makepgm = "make";
369    }
370
371    # Check configure location
372    if ( ! (-x "$srcdir/configure") && (-x "./configure") ) {
373	$srcdir = ".";
374    }
375    $config_status    = "none";
376    $make_status      = "none";
377    $globcheck_status = "none";
378    # usedname is from the old test to check for which routines
379    # were loaded for the simplest MPI Hello World program.
380    #$usedname_status  = "none";
381    $install_status   = "none";
382    $installcheck_status = "none";
383    $test_status      = "none";
384    if ($show) {
385	print "Configure: $enable_args $with_args $config_args\n";
386	if ($envset ne "") {
387	    print "Environment = $envset\n";
388	}
389    }
390    else {
391#	$enable_args .= " --enable-echo";
392	print $OUTFD $TestStart;
393	my $host = `uname -n`;
394	print $OUTFD "$TestHostStart$host$TestHostEnd";
395	my $user = $ENV{"LOGNAME"};
396	print $OUTFD "$TestUserStart$user$TestUserEnd";
397	my $date = `date "+%Y-%m-%d-%H-%M"`;
398	print $OUTFD "$TestDateStart$date$TestDateEnd";
399	unlink "Makefile";
400	print $OUTFD $ConfigStart;
401	@config = split( /\s+/, "$srcdir/configure --prefix=$instdir $enable_args $with_args $config_args" );
402	print $OUTFD "Configure: " . join(" ", @config) . "\n";
403	if ($envset ne "") {
404	    print $OUTFD "Environment = $envset\n";
405	}
406	$rc = &RunProgram( @config );
407	$config_status = $rc;
408	if (! -s "Makefile" && $rc == 0) {
409	    $config_status = "No Makefile";
410	    $rc = 1;
411	}
412	print $OUTFD $ConfigEnd;
413	# print "rc = $rc\n";
414	if ($rc == 0) {
415	    print $OUTFD $MakeStart;
416	    $rc = &RunProgram( "$makepgm $parallelBuild" );
417	    print $OUTFD $MakeEnd;
418	    $make_status = $rc;
419	    if ($rc == 0) {
420		# Only perform these steps if the make succeeded
421
422# FIXME: Restore the tests for nonconforming global systems and for
423# minimum memory and routing footprint
424
425# Deleted this test because it is no longer a design goal for MPICH
426# that it have no nonconforming global symbols
427
428# Deleted this test because it is no longer a design goal for MPICH2
429# to have a minimum memory and routine footprint.
430
431		# Install the libraries
432		print $OUTFD $MakeInstStart;
433		# Clean the install directory
434		$install_status = &RunProgram( "$makepgm install" );
435		if ($install_status) {
436		    my $cwd = `pwd`;
437		    chomp $cwd;
438		    print $OUTFD "Current directory is $cwd\n";
439		}
440		print $OUTFD $MakeInstEnd;
441		if ($install_status == 0) {
442		    # Try the install check target
443		    print $OUTFD $MakeInstcheckStart;
444		    $installcheck_status = &RunProgram( "$makepgm installcheck" );
445		    print $OUTFD $MakeInstcheckEnd;
446		    # Run the tests
447		    $test_status = &RunTestSuites;
448		}
449	    }
450	}
451	print $OUTFD $TestEnd;
452    }
453    %ENV = %saveENV;
454
455    print $OUTFD $SumStart;
456    print $OUTFD $SumConfigStart;
457    print $OUTFD $config_status;
458    print $OUTFD $SumConfigEnd;
459    print $OUTFD $SumMakeStart;
460    print $OUTFD $make_status;
461    print $OUTFD $SumMakeEnd;
462    print $OUTFD $SumGlobStart;
463    print $OUTFD $globcheck_status;
464    print $OUTFD $SumGlobEnd;
465    print $OUTFD $SumInstStart;
466    print $OUTFD $install_status;
467    print $OUTFD $SumInstEnd;
468    print $OUTFD $SumTestRunStart;
469    print $OUTFD $test_status;
470    print $OUTFD $SumTestRunEnd;
471    print $OUTFD $SumEnd;
472}
473
474# ---------------------------------------------------------------------------
475# Chosen *without* replacement.  If an option is chosen twice,
476# then there will be fewer options
477sub RandArgs {
478    my ($n_choice, $array_name, $optname, $negoptname ) = @_;
479    my @chosen = ( );
480    my $args = "";
481    my $array_len = $#$array_name;
482    my $idx;
483
484    print "select $n_choice\n" if $debug;
485    for (my $i=0; $i<$n_choice; $i++) {
486	$idx = int( rand (1 + $array_len) );
487	print "Found $idx\n" if $debug;
488	if ($chosen[$idx]) { next; }
489	$chosen[$idx] = 1;
490	@args = split( /;/, $$array_name[$idx] );
491	print "Trying $$array_name[$idx]\n" if $debug;
492	$name = $args[0];
493	if ($#args == 0) {
494	    # Only the name is provided.  Choose one of three
495	    # choices:
496	    #    No option (skip this one)
497	    #    just --$optname-$name
498	    #    just --$negoptname-$name (if non-null)
499	    $idx = int ( rand ( 3 ) );
500	    if ($idx == 0) {
501		$args .= " --$optname-$name";
502	    }
503	    elsif ($idx == 1 && $negoptname ne "") {
504		$args .= " --$negoptname-$name";
505	    }
506	    else {
507		# skip
508		;
509	    }
510	}
511	else {
512	    $idx = 1 + int( rand $#args );
513	    $value = $args[$idx];
514	    if ($value ne "") {
515		$args .=  " --$optname-$name=$value";
516	    }
517	    else {
518		$args .= " --$optname-$name";
519	    }
520	}
521    }
522    return $args;
523}
524
525# ---------------------------------------------------------------------------
526# Timer support.  Time_left returns 1 if time remains, 0 otherwise
527$final_time = -1;
528sub set_time_left {
529    my $delta_time = $_[0];
530    $final_time = time + $delta_time;
531}
532sub time_left {
533    if ($final_time eq "" || $final_time == -1) {     return 1; }
534    if (time > $final_time) { return 0; }
535    else                    { return 1; }
536}
537
538# ---------------------------------------------------------------------------
539# cb for check build
540#
541# Eventually, we'll need
542#   bootstep
543#   compiler names
544#   unbootstep
545# for each test.
546#
547sub RunTestSuites {
548    my $run_status = 0;
549    my $r_status = 0;
550    # Start by adding "notest" files to any optional tests
551    if (!$has_cxx) {
552	&SkipCxxTestSuite;
553    }
554    foreach my $testname (split(':',$tests)) {
555	if ($testname eq "") { next; }
556	print $OUTFD $RunTestStart;
557	if ($is_xml) {
558	    print $OUTFD "<TESTNAME>$testname</TESTNAME>\n";
559	    print $OUTFD "<TESTOUT>\n";
560	    }
561	else {
562	    print $OUTFD "Running test $testname...\n";
563	}
564	# Eventually, we should store the test routines in a hash,
565	# with the key the test name and the value the name of the
566	# routine.
567	if ($testname eq "mpich") {
568	    &RunMpichTestSuite;
569	}
570	elsif ($testname eq "intel") {
571	    &RunIntelTestSuite;
572	}
573	elsif ($testname eq "testmpio") {
574	    &RunTestMPIOSuite;
575	}
576	elsif ($testname eq "mpicxx" && $has_cxx) {
577	    &RunCxxTestSuite;
578	}
579	elsif ($testname eq "mpich2") {
580	    &RunMPICH2TestSuite;
581	}
582	else {
583	    print $OUTFD "checkbuilds: Unrecognized test $testname\n";
584	}
585	if ($is_xml) {
586	    print $OUTFD "</TESTOUT>\n";
587	    }
588	print $OUTFD $RunTestEnd;
589	if ($run_status != 0) {
590	    # If any test fails, record its status.
591	    $r_status = $run_status;
592	}
593    }
594    return $r_status;
595}
596# ---------------------------------------------------------------------------
597sub RunMpichTestSuite {
598    my $nargs;
599    $cwd = `pwd`;
600    chomp $cwd;
601    my @config;
602
603    if ($mpich_test_dir eq "") {
604	$mpich_test_dir = "$tmpdir/cb/mpitest";
605    }
606
607# Make sure that the tests run past a failure to build an
608# executable.  Without this, the summary doesn't include
609# any tests in the same directory that completed.
610    $ENV{"MPITEST_CONTINUE"} = "always";
611
612    $rc = chdir $mpich_test_dir;
613    if (!$rc) {
614	#print STDERR "Cannot change to $mpich_test_dir\n";
615	return;
616    }
617
618    # A special hack for the io part
619    # If there is no link or io directory, create one and populate it
620    if (! -f "io/Mfile.in") {
621	if (-s "$mpich1_dir/io/Mfile.in") {
622	    if (! -d "io" && ! -l "io") {
623		`mkdir "io"`;
624	    }
625	    `cp $mpich1_dir/io/*.in io`;
626	}
627	elsif (-s "$srcdir/src/mpi/romio/test/Mfile.in") {
628	    if (! -d "io" && ! -l "io") {
629		`mkdir "io"`;
630	    }
631	    `cp $srcdir/src/mpi/romio/test/*.in io`;
632	}
633	# Else, we can't find the IO tests, so we don't create the io
634	# directory
635    }
636
637    # Create the arguments for the configure step
638    $nargs = 0;
639    $config[$nargs++] = "$mpich1_dir/configure";
640    $config[$nargs++] = "--prefix=$instdir";
641    $config[$nargs++] = "-mpilibname=mpich";
642    if (defined($chosenEnable{"romio"})) {
643	$config[$nargs++] = "--enable-io";
644    }
645    # f77 is now the default, so we should run with the f77 tests
646    # unless we did not build f77
647    if (! $has_f77) {  # !defined($chosenEnable{"f77"})
648	$config[$nargs++] = "--disable-f77";
649    }
650
651# This isn't right, since these need to use the compilation
652# scripts.  We'll approximate this by trying to use the
653# compilation scripts if they're found
654    if (defined($ENV{"CC"})) {
655	$ccname = $ENV{"CC"};
656    }
657    if (defined($ENV{"FC"})) {
658	$fcname = $ENV{"FC"};
659    }
660# Note that there are no quotes in the following because
661# they are not needed (no shell evaluation here)
662    if (-x "$instdir/bin/mpicc" ) {
663	$config[$nargs++] = "-cc=$instdir/bin/mpicc";
664    }
665    else {
666	$config[$nargs++] = "-cc=$ccname -I$instdir/include -L$instdir/lib";
667    }
668    if (-x "$instdir/bin/mpifort" ) {
669	$config[$nargs++] = "-fc=$instdir/bin/mpifort";
670    }
671    else {
672	$config[$nargs++] = "-fc=$fcname -I$instdir/include -L$instdir/lib";
673    }
674    # Add $config[$nargs++] = "--enable-coverage";
675    # if we build mpich2 with the coverage switch.
676
677    if (defined($ENV{"MAKE"})) {
678	$makepgm = $ENV{"MAKE"};
679	$config[$nargs++] = "-make=$makepgm";
680    }
681    else {
682	$makepgm = "make";
683    }
684    #$config[$nargs++] = "--enable-echo";
685    %saveENV = %ENV;
686    $ENV{MPIRUN} = "$instdir/bin/mpiexec";
687    # This timeout needs to be made uniform for all mpiruns
688    # 3 minutes is enough for some of our slower machines
689    $ENV{MPIEXEC_TIMEOUT} = "180";
690    $rc = &RunProgram( @config );
691    if ($rc == 0) {
692	if ($hasDemon) {
693	    &$StartDemon;
694	}
695	$rc = &RunProgram( "$makepgm testing" );
696	$test_status = $rc;
697	if ($run_status == 0 && $rc != 0) { $run_status = $rc; }
698	if ($hasDemon) {
699	    &$StopDemon;
700	}
701    }
702    else {
703	$run_status = $rc;
704	print $OUTFD "Configure step for test failed\n";
705	print $OUTFD "Could not execute " . join(" ", @config) . "\n";
706	print $OUTFD "Environment was\n";
707	foreach $key (keys(%ENV)) {
708	    my $line = "$key = $ENV{$key}";
709	    if ($is_xml) { $line = &XMLify( $line ); }
710	    print $OUTFD "$line\n";
711	}
712    }
713    %ENV = %saveENV;
714    chdir $cwd;
715}
716# ---------------------------------------------------------------------------
717sub SkipCxxTestSuite {
718    if ($mpicxx_test_dir eq "") {
719	$mpicxx_test_dir = "$tmpdir/cb/mpicxxtest";
720    }
721    `date > $mpicxx_test_dir/notest`;
722}
723sub RunCxxTestSuite {
724    my $nargs = 0;
725    $cwd = `pwd`;
726    chomp $cwd;
727    my @config;
728
729    if ($mpicxx_test_dir eq "") {
730	$mpicxx_test_dir = "$tmpdir/cb/mpicxxtest";
731    }
732    #
733    # First, check for the mpicxx program
734    if (! -x "$instdir/bin/mpicxx" || !defined($chosenEnable{"cxx"})) {
735	# Probably built without C++ support
736	$run_status = 0;
737	&SkipCxxTestSuite;
738	return;
739    }
740    $rc = chdir $mpicxx_test_dir;
741    if (!$rc) {
742	#print STDERR "Cannot change to $mpicxx_test_dir\n";
743	return;
744    }
745    # Remove any "notest" file
746    if (-s "notest") { unlink "notest"; }
747    $config[$nargs++] = "$projects_dir/mpicxxtest/configure";
748    $config[$nargs++] = "--with-mpich=$instdir";
749    $config[$nargs++] = "--enable-xml";
750    if (defined($ENV{"MAKE"})) {
751	$makepgm = $ENV{"MAKE"};
752    }
753    else {
754	$makepgm = "make";
755    }
756    %saveENV = %ENV;
757    # This timeout needs to be made uniform for all mpiruns
758    # 3 minutes is enough for some of our slower machines
759    $ENV{MPIEXEC_TIMEOUT} = "180";
760    $rc = &RunProgram( @config );
761    if ($rc == 0) {
762	if ($hasDemon) {
763	    &$StartDemon;
764	}
765	$rc = &RunProgram( "$makepgm run-tests" );
766	$test_status = $rc;
767	if ($run_status == 0 && $rc != 0) { $run_status = $rc; }
768	# This step converts the summary.xml file into a valid XML file
769	# by adding the appropriate header and footer
770	$rc = &RunProgram( "$makepgm get-summary" );
771	if ($hasDemon) {
772	    &$StopDemon;
773	}
774    }
775    else {
776	$run_status = $rc;
777	print $OUTFD "Configure step for test failed\n";
778	print $OUTFD "Could not execute " . join(" ", @config) . "\n";
779	print $OUTFD "Environment was\n";
780	foreach $key (keys(%ENV)) {
781	    my $line = "$key = $ENV{$key}";
782	    if ($is_xml) { $line = &XMLify( $line ); }
783	    print $OUTFD "$line\n";
784	}
785    }
786    %ENV = %saveENV;
787    chdir $cwd;
788}
789
790# Run the LLNL IO Test suite
791sub RunTestMPIOSuite {
792    my $nargs = 0;
793    my $testname = "testing";
794    $cwd = `pwd`;
795    chomp $cwd;
796
797    my @config;
798
799    if ($testmpio_test_dir eq "") {
800	$testmpio_test_dir = "$tmpdir/cb/testmpio";
801    }
802
803    $rc = chdir $testmpio_test_dir;
804    if (!$rc) {
805	print $OUTFD "Cannot change to $testmpio_test_dir\n";
806	return;
807    }
808
809    # Switch to using the checked-in version of the Testmpio test
810    if (-x "$projects_dir/testmpio/configure") {
811        $config[$nargs++] = "$projects_dir/testmpio/configure";
812    }
813    elsif (-x "$projects_dir/Testmpio/configure") {
814        $config[$nargs++] = "$projects_dir/Testmpio/configure";
815    }
816    else {
817        print $OUTFD "Cannot find testmpio source directory!";
818        return;
819    }
820    $config[$nargs++] = "--enable-xml";
821    $config[$nargs++] = "CC=$instdir/bin/mpicc";
822    $config[$nargs++] = "MPIEXEC=$instdir/bin/mpiexec";
823    if (defined($ENV{"MAKE"})) {
824	$makepgm = $ENV{"MAKE"};
825    }
826    else {
827	$makepgm = "make";
828    }
829    %saveENV = %ENV;
830    # This timeout needs to be made uniform for all mpiruns
831    # 3 minutes is enough for some of our slower machines
832    $ENV{MPIEXEC_TIMEOUT} = "180";
833    $rc = &RunProgram( @config );
834    if ($rc == 0) {
835	if ($hasDemon) {
836	    &$StartDemon;
837	}
838	$rc = &RunProgram( "$makepgm $testname" );
839	$test_status = $rc;
840	if ($run_status == 0 && $rc != 0) { $run_status = $rc; }
841	if ($hasDemon) {
842	    &$StopDemon;
843	}
844	if ($test_status != 0) {
845	    # Try to figure out what went wrong.
846	    if (-s "Test/test.results") {
847		&CopyFileToOutput( "Test/test.results" );
848	    }
849	}
850    }
851    else {
852	$run_status = $rc;
853	print $OUTFD "Configure step for test failed\n";
854	print $OUTFD "Could not execute " . join(" ", @config) . "\n";
855	print $OUTFD "Environment was\n";
856	foreach $key (keys(%ENV)) {
857	    my $line = "$key = $ENV{$key}";
858	    if ($is_xml) { $line = &XMLify( $line ); }
859	    print $OUTFD "$line\n";
860	}
861    }
862    %ENV = %saveENV;
863    chdir $cwd;
864}
865
866
867sub RunIntelTestSuite {
868    my $nargs = 0;
869    my $testname = "newtestl";
870    $cwd = `pwd`;
871    chomp $cwd;
872
873    my @config;
874
875    if ($intel_test_dir eq "") {
876	$intel_test_dir = "$tmpdir/cb/MPITEST";
877    }
878
879    $rc = chdir $intel_test_dir;
880    if (!$rc) {
881	#print STDERR "Cannot change to $intel_test_dir\n";
882	return;
883    }
884
885    # Switch to using the checked-in version of the Intel test
886    $config[$nargs++] = "$projects_dir/IntelMPITEST/configure";
887    $config[$nargs++] = "--with-mpich2=$instdir";
888    # The Absoft Fortran compiler fails some tests if MAX_RANKS
889    # (used to dimension some arrays) is too large.  Since the
890    # default tests never use more than 6 processes, setting a
891    # maximum of 16 is safe.
892    $config[$nargs++] = "--enable-maxprocs=16";
893    # f77 is now the default, so we should run with the f77 tests
894    # unless we did not build f77
895    if (!$has_f77) {       # defined($chosenEnable{"f77"})
896	# Only run the C tests if we did not build fortran
897	$config[$nargs++] = "--disable-f77";
898	$testname = "newtestl_c";
899    }
900    if (defined($ENV{"MAKE"})) {
901	$makepgm = $ENV{"MAKE"};
902    }
903    else {
904	$makepgm = "make";
905    }
906    %saveENV = %ENV;
907    # This timeout needs to be made uniform for all mpiruns
908    # 3 minutes is enough for some of our slower machines
909    $ENV{MPIEXEC_TIMEOUT} = "180";
910    $rc = &RunProgram( @config );
911    if ($rc == 0) {
912	if ($hasDemon) {
913	    &$StartDemon;
914	}
915	$rc = &RunProgram( "$makepgm $testname" );
916	$test_status = $rc;
917	if ($run_status == 0 && $rc != 0) { $run_status = $rc; }
918	if ($hasDemon) {
919	    &$StopDemon;
920	}
921	if ($test_status != 0) {
922	    # Try to figure out what went wrong.
923	    if (-s "Test/test.results") {
924		&CopyFileToOutput( "Test/test.results" );
925	    }
926	    if (! -s "lib/libmpitestf_mpich2.a" &&
927		-s "lib/makeflib.log") {
928		&CopyFileToOutput( "lib/makeflib.log" );
929	    }
930	    if (! -s "lib/libmpitest_mpich2.a" &&
931		-s "lib/makeclib.log") {
932		&CopyFileToOutput( "lib/makeclib.log" );
933	    }
934
935	}
936    }
937    else {
938	$run_status = $rc;
939	print $OUTFD "Configure step for test failed\n";
940	print $OUTFD "Could not execute " . join(" ", @config) . "\n";
941	print $OUTFD "Environment was\n";
942	foreach $key (keys(%ENV)) {
943	    my $line = "$key = $ENV{$key}";
944	    if ($is_xml) { $line = &XMLify( $line ); }
945	    print $OUTFD "$line\n";
946	}
947    }
948    %ENV = %saveENV;
949    chdir $cwd;
950}
951
952sub RunMPICH2TestSuite {
953    my $nargs = 0;
954    my $makepgm;
955
956    $cwd = `pwd`;
957    chomp $cwd;
958
959    # This must match the directory into which mpich2 was built for
960    # us to use the configure there.
961    if ($mpich2_test_dir eq "") {
962	$mpich2_test_dir = "$builddir/test/mpi";
963    }
964
965    $rc = chdir $mpich2_test_dir;
966    if (!$rc) {
967	#print STDERR "Cannot change to $mpich2_test_dir\n";
968	return;
969    }
970
971    # MPICH2 tests are already built, so no configure step required
972    %saveENV = %ENV;
973    #
974    # Make sure that there a no leftovers
975    # Get the version of make to use
976    if (defined($ENV{"MAKE"})) {
977	$makepgm = $ENV{"MAKE"};
978    }
979    else {
980	$makepgm = "make";
981    }
982    &RunProgram( "$makepgm clean" );
983
984    # This timeout needs to be made uniform for all mpiruns
985    # 3 minutes is enough for some of our slower machines
986    $ENV{MPIEXEC_TIMEOUT} = "180";
987    if ($hasDemon) {
988	&$StartDemon;
989    }
990    # The MPICH2 test suite has a program for running the tests
991    $rc = &RunProgram( "./runtests -mpiexec=$instdir/bin/mpiexec -srcdir=$srcdir/test/mpi -tests=testlist -xmlfile=summary.xml" );
992    $test_status = $rc;
993    if ($run_status == 0 && $rc != 0) { $run_status = $rc; }
994    if ($hasDemon) {
995	&$StopDemon;
996    }
997    %ENV = %saveENV;
998    chdir $cwd;
999}
1000# ---------------------------------------------------------------------------
1001# RunProgram LIST
1002sub RunProgram {
1003    my $signal_num = 0;
1004
1005    if ($echoSteps) {
1006	my $cmd = join(' ',@_);
1007	my $curdir = `pwd`;
1008	chomp $curdir;
1009	print STDOUT "Running $cmd in $curdir\n";
1010    }
1011
1012    # perl does not correctly handle ">>foo 2>&1" redirection in system
1013    # correctly (some stderr escapes to the prior stderr).  This
1014    # code attempts to do the correct thing.
1015    # By reopening stdout and stderr, we can ensure that all of the
1016    # output goes to the specified files.  Unfortunately, we can't
1017    # force perl to correctly flush files without open/close, so
1018    # we close the output file before the fork.  This guarantees that
1019    # the data is flushed.  We reopen it after the fork (which is implicit
1020    # in the open)
1021    if ($outfile ne "") {
1022	close $OUTFD;
1023    }
1024
1025    # We now use a different approach that uses a open that creates a
1026    # fork and associates file handle (CFD for Child FD).
1027    @args = @_;
1028    $pid = open(CFD,"-|");
1029    if ($pid == 0) {
1030	# we're the child
1031        open STDIN, '/dev/null';
1032	# Do we want to allow an output filter, e.g., to convert the
1033	# output into well-formed XML?
1034        open STDERR, ">>&STDOUT";
1035        exec @args;
1036	die "Could not exec program $args[0]\n";
1037    }
1038    else {
1039	# Read from the child
1040	if ($outfile ne "") {
1041	    open( $OUTFD, ">>$outfile" ) || die "Could not reopen $outfile for appending\n";
1042	}
1043	while (<CFD>) {
1044	    if ($is_xml) {
1045		$_ = &XMLify( $_ );
1046	    }
1047	    print $OUTFD $_;
1048	}
1049	# Closing a pipe implicitly waits for the command on the other
1050	# end to complete, and puts the exit status into $?
1051	close CFD;
1052	# end of read from the child
1053	# Note that this status is usually shifted right by 8, so
1054	# we check for that
1055        $rc = $?;
1056	$signal_num = $rc & 127;
1057	if ($rc > 255) { $rc = $rc >> 8; }
1058	if ($signal_num != 0 && $report_signals) {
1059	    print OUTFD "Process exited with signal $signal_num\n";
1060	}
1061    }
1062    if ($echoSteps) {
1063	print STDOUT "Completed command with status $rc\n";
1064    }
1065    return $rc;
1066}
1067#
1068# Change output style
1069sub XMLStyle {
1070    $TestStart     = "<BUILDTEST>\n";
1071    $TestEnd       = "</BUILDTEST>\n";
1072    $TestDateStart = "<DATE>\n";
1073    $TestDateEnd   = "</DATE>\n";
1074    $TestHostStart = "<HOST>\n";
1075    $TestHostEnd   = "</HOST>\n";
1076    $TestUserStart = "<USER>\n";
1077    $TestUserEnd   = "</USER>\n";
1078    $ConfigStart   = "<CONFIG>\n";
1079    $ConfigEnd     = "</CONFIG>\n";
1080    $MakeStart     = "<MAKE>\n";
1081    $MakeEnd       = "</MAKE>\n";
1082    $GlobNameStart = "<GLOBNAME>\n";
1083    $GlobNameEnd   = "</GLOBNAME>\n";
1084    $UsedNameStart = "<USEDNAMES>\n";
1085    $UsedNameEnd   = "</USEDNAMES>\n";
1086    $MakeInstStart = "<MAKEINST>\n";
1087    $MakeInstEnd   = "</MAKEINST>\n";
1088    $MakeInstcheckStart = "<MAKEINSTCHECK>\n";
1089    $MakeInstcheckEnd   = "</MAKEINSTCHECK>\n";
1090    $RunTestStart  = "<RUNTEST>\n";
1091    $RunTestEnd    = "</RUNTEST>\n";
1092    $SumStart      = "<SUMMARY>\n";
1093    $SumEnd        = "</SUMMARY>\n";
1094    $SumConfigStart = "<STATUS NAME=\"configure\">";
1095    $SumConfigEnd   = "</STATUS>\n";
1096    $SumMakeStart  = "<STATUS NAME=\"make\">";
1097    $SumMakeEnd    = "</STATUS>\n";
1098    $SumGlobStart  = "<STATUS NAME=\"globname\">";
1099    $SumGlobEnd    = "</STATUS>\n";
1100    $SumInstStart  = "<STATUS NAME=\"install\">";
1101    $SumInstEnd    = "</STATUS>\n";
1102    $SumTestRunStart = "<STATUS NAME=\"test\">";
1103    $SumTestRunEnd   = "</STATUS>\n";
1104}
1105# ---------------------------------------------------------------------------
1106#
1107# Other options
1108# --enable-threads={single, multiple}
1109# ---------------------------------------------------------------------------
1110# Here's the real code to execute
1111# ---------------------------------------------------------------------------
1112
1113if ($rundir ne "") {
1114    chdir $rundir || die "could not change directory to $rundir\n";
1115}
1116
1117# Select the output file
1118if ($outfile ne "") {
1119    if (! ($outfile =~ /^\//) ) {
1120	# Ensure that we have an absolute directory for the output file
1121	my $curdir = `pwd`;
1122	chop $curdir;
1123	$outfile = "$curdir/$outfile";
1124    }
1125    open( $OUTFD, ">$outfile" ) || die "Could not open $outfile for writing\n";
1126    # Setting autoflush is not enough to ensure that output is
1127    # correctly ordered when child processes also write to the file.
1128    # All of the shells get this right but unfortunately perl does not.
1129    #autoflush $OUTFD 1;
1130    if ($is_xml) {
1131	print $OUTFD "<?xml version='1.0' ?>\n";
1132	print $OUTFD "<?xml-stylesheet href=\"build.xsl\" type=\"text/xsl\" ?>\n";
1133	print $OUTFD "<MPICH2BUILD>\n";
1134    }
1135}
1136else {
1137    $OUTFD = STDOUT;
1138}
1139
1140# ---------------------------------------------------------------------------
1141#
1142# There are several ways to run the tests.  They are
1143#   For a fixed number of times
1144#   For a fixed length of time
1145for ($test_count = 0;
1146     ($max_count < 0 || $test_count < $max_count) && &time_left;
1147     $test_count++) {
1148    if ($is_xml) {
1149    }
1150    else {
1151	print $OUTFD "\nRunning test $test_count\n\n";
1152    }
1153    &RunTest;
1154}
1155if ($is_xml) {
1156    print $OUTFD "</MPICH2BUILD>\n";
1157}
1158close $OUTFD;
1159
1160sub CopyFileToOutput {
1161    my $filename = $_[0];
1162    my $linecount = 256;
1163
1164    if (open( TESTFD, "<$filename" )) {
1165	print $OUTFD "First $linecount lines of $filename\n";
1166	while (<TESTFD>) {
1167	    if ($linecount <= 0) { last; }
1168	    if ($is_xml) {
1169		$_ = &XMLify( $_ );
1170	    }
1171	    print $OUTFD $_;
1172	    $linecount --;
1173	}
1174	close (TESTFD);
1175    }
1176}
1177
1178sub XMLify {
1179    my $line = $_[0];
1180    my $itcount = 0;
1181    # xml-ify the line by escaping the special characters
1182    $line =~ s/</\*AMP\*lt;/g;
1183    $line =~ s/>/\*AMP\*gt;/g;
1184    $line =~ s/&/\*AMP\*amp;/g;
1185    $line =~ s/\*AMP\*/&/g;
1186
1187    # Handle non-printing ascii characters (e.g., ones that emacs would
1188    # print as \200).  XML may refuse to display non-printing characters
1189    # BUG IN PERL: The negated POSIX character class does not work!
1190    # It isn't clear whether ANY of the POSIX character classes work
1191    # while ($line =~ /^([:print:]*)([:^print:])(.*)/s) {
1192    # Instead, we use an explicit ASCII range, and include tab characters
1193    while ($line =~ /^([ -~\t]*)([^ -~\t\n])(.*)/s) {
1194        # Grr.  This doesn't work either.  The character conversion
1195	# gets lost.  However, this is still better than including
1196	# a nonprinting character in the output
1197        $char = $2;
1198	$hexversion = sprintf( "\\%03x", $char );
1199	$line = $1 . $hexversion . $3;
1200	if ($itcount++ > 100) { last; }
1201    }
1202
1203    return $line;
1204}
1205