Skip to content

Commit

Permalink
Merge pull request #1343 from billsacks/run_tests_defaults
Browse files Browse the repository at this point in the history
Unit testing: Determine machine-specific settings automatically
This PR allows you to run the unit tests by simply running
tools/unit_testing/run_tests.py without any additional arguments. The
machine, compiler, mpilib, and mpirun command are now determined
automatically. In addition, use-openmp is now assumed by default, since
that is the standard way we build pFUnit (but there is a mechanism to
turn off use-openmp).

This is important in order to support unit testing on additional
machines.

In order to accomplish this, I needed to tweak some pieces that are also
used by system builds:

(1) I added a unit_testing attribute to the mpirun command in
config_machines.xml. This is needed on yellowstone, where we use a
complex command to launch CESM, but just want to use a simple
'mpirun.lsf' to launch unit tests.

(2) In machines.py: probe_machine_name: If no name is found with
socket.getfqdn(), then try socket.gethostname(). This is needed in
order to determine the machine when running on my laptop.

Test suite: scripts_regression_tests on yellowstone
Also ran unit tests on yellowstone using the trimmed-down command
documented in README.unit_testing. And ran unit tests on my laptop
using the same command.
Test baseline: N/A
Test namelist changes: none
Test status: bit for bit

Fixes #872

User interface changes?: Simplifies the typical call to run_tests.py

Code review: jedwards
  • Loading branch information
jedwards4b authored Apr 13, 2017
2 parents 5074c4a + da5ff1a commit 3779ec1
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.unit_testing
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
# https://sourceforge.net/projects/pfunit/
#

tools/unit_testing/run_tests.py --test-spec-dir=. --compiler=intel --mpilib=mpich2 --use-openmp --mpirun-command=mpirun.lsf --build-dir `mktemp -d --tmpdir=. unit_tests.XXXXXXXX`
tools/unit_testing/run_tests.py --build-dir `mktemp -d ./unit_tests.XXXXXXXX`
2 changes: 2 additions & 0 deletions config/acme/machines/config_machines.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
the 'executable' tag must have arguments required for the chosen mpirun, as well as the executable name.
unit_testing: can be 'true' or 'false'.
This allows using a different mpirun command to launch unit tests
-->

Expand Down
7 changes: 7 additions & 0 deletions config/cesm/machines/config_machines.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
the 'executable' tag must have arguments required for the chosen mpirun, as well as the executable name.
unit_testing: can be 'true' or 'false'.
This allows using a different mpirun command to launch unit tests
-->

Expand Down Expand Up @@ -1637,6 +1639,11 @@
<mpirun mpilib="mpi-serial">
<executable></executable>
</mpirun>
<mpirun mpilib="default" unit_testing="true">
<!-- For unit testing, avoid all of the extra stuff that we use before and
after the mpirun command when launching cesm on yellowstone -->
<executable>mpirun.lsf </executable>
</mpirun>
<mpirun mpilib="default" threaded="false">
<executable>TARGET_PROCESSOR_LIST=AUTO_SELECT mpirun.lsf $ENV{CESMDATAROOT}/tools/bin/launch </executable>
</mpirun>
Expand Down
2 changes: 2 additions & 0 deletions config/xml_schemas/config_machines.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<xs:attribute name="mpilib" type="xs:string"/>
<xs:attribute name="debug" type="xs:boolean"/>
<xs:attribute name="threaded" type="xs:boolean"/>
<xs:attribute name="unit_testing" type="xs:boolean"/>
<xs:attribute name="type" type="xs:NCName"/>
<xs:attribute name="lang" type="xs:NCName"/>
<xs:attribute name="name" type="xs:NCName"/>
Expand Down Expand Up @@ -133,6 +134,7 @@
<xs:attribute ref="compiler"/>
<xs:attribute ref="mpilib"/>
<xs:attribute ref="threaded"/>
<xs:attribute ref="unit_testing"/>
</xs:complexType>
</xs:element>
<xs:element name="arguments">
Expand Down
32 changes: 27 additions & 5 deletions scripts/lib/CIME/XML/machines.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,34 @@ def probe_machine_name(self):
Find a matching regular expression for hostname
in the NODENAME_REGEX field in the file. First match wins.
"""
machine = None

names_not_found = []

nametomatch = socket.getfqdn()
machine = self._probe_machine_name_one_guess(nametomatch)

if machine is None:
names_not_found.append(nametomatch)

nametomatch = socket.gethostname()
machine = self._probe_machine_name_one_guess(nametomatch)

if machine is None:
names_not_found.append(nametomatch)

names_not_found_quoted = ["'" + name + "'" for name in names_not_found]
names_not_found_str = ' or '.join(names_not_found_quoted)
logger.warning("Could not find machine match for %s" % names_not_found_str)

return machine

def _probe_machine_name_one_guess(self, nametomatch):
"""
Find a matching regular expression for nametomatch in the NODENAME_REGEX
field in the file. First match wins. Returns None if no match is found.
"""

machine = None
nodes = self.get_nodes("machine")

for node in nodes:
Expand All @@ -113,10 +139,6 @@ def probe_machine_name(self):
machine = machtocheck
break

if machine is None:
# Check for a local definition
logger.warning("Could not probe machine for hostname '%s'" % nametomatch)

return machine

def set_machine(self, machine):
Expand Down
6 changes: 4 additions & 2 deletions scripts/lib/CIME/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ def _initialize_derived_attributes(self):
mpi_attribs = {
"compiler" : self.get_value("COMPILER"),
"mpilib" : self.get_value("MPILIB"),
"threaded" : self.get_build_threaded()
"threaded" : self.get_build_threaded(),
"unit_testing" : False
}

executable = env_mach_spec.get_mpirun(self, mpi_attribs, job="case.run", exe_only=True)[0]
Expand Down Expand Up @@ -1076,7 +1077,8 @@ def get_mpirun_cmd(self, job="case.run"):
mpi_attribs = {
"compiler" : self.get_value("COMPILER"),
"mpilib" : self.get_value("MPILIB"),
"threaded" : self.get_build_threaded()
"threaded" : self.get_build_threaded(),
"unit_testing" : False
}

executable, args = env_mach_specific.get_mpirun(self, mpi_attribs, job=job)
Expand Down
6 changes: 3 additions & 3 deletions scripts/tests/scripts_regression_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def test_a_unit_test(self):
os.makedirs(test_dir)
unit_test_tool = os.path.abspath(os.path.join(CIME.utils.get_cime_root(),"tools","unit_testing","run_tests.py"))
test_spec_dir = os.path.join(os.path.dirname(unit_test_tool),"Examples", "interpolate_1d", "tests")
run_cmd_no_fail("%s --build-dir %s --test-spec-dir %s --compiler intel --use-openmp --mpirun-command mpirun.lsf"\
run_cmd_no_fail("%s --build-dir %s --test-spec-dir %s"\
%(unit_test_tool,test_dir,test_spec_dir))
cls._do_teardown.append(test_dir)

Expand All @@ -211,8 +211,8 @@ def test_b_cime_f90_unit_tests(self):
test_spec_dir = CIME.utils.get_cime_root()
unit_test_tool = os.path.abspath(os.path.join(test_spec_dir,"tools","unit_testing","run_tests.py"))

run_cmd_no_fail("%s --build-dir %s --test-spec-dir %s --compiler %s --use-openmp --mpirun-command mpirun.lsf"\
%(unit_test_tool,test_dir,test_spec_dir, compiler))
run_cmd_no_fail("%s --build-dir %s --test-spec-dir %s"\
%(unit_test_tool,test_dir,test_spec_dir))
cls._do_teardown.append(test_dir)

@classmethod
Expand Down
69 changes: 41 additions & 28 deletions tools/unit_testing/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ def parse_command_line(args):
parser.add_argument("--no-color", action="store_false",
help="""Turn off colorized output."""
)
parser.add_argument("--compiler", default="gnu",
parser.add_argument("--compiler",
help="""Compiler vendor for build (supported depends on machine).
Only used for lookup in CIME Machines files."""
If not specified, use the default for this machine."""
)
parser.add_argument("--enable-genf90", action="store_true",
default=True,
Expand All @@ -83,19 +83,23 @@ def parse_command_line(args):

parser.add_argument("--mpilib",
help="""MPI Library to use in build.
Required argument (until we can get this from config_machines)
Must match an MPILIB option in config_compilers.xml.
e.g., for yellowstone, can use 'mpich2'."""
If not specified, use the default for this machine/compiler.
Must match an MPILIB option in config_compilers.xml.
e.g., for yellowstone, can use 'mpich2'."""
)
parser.add_argument(
"--mpirun-command", default="",
help="""Command to use to run an MPI executable.

If not specified, does not use any mpirun prefix to run executables."""
parser.add_argument("--no-mpirun", action="store_true",
help="""If specified, then run executables without an mpirun command""")

parser.add_argument("--mpirun-command",
help="""Command to use to run an MPI executable.
If not specified, uses the default for this machine.
Ignored if --no-mpirun is specified."""
)
parser.add_argument(
"--test-spec-dir",
help="""Location where tests are specified."""
"--test-spec-dir", default=".",
help="""Location where tests are specified.
Defaults to current directory."""
)
parser.add_argument(
"-T", "--ctest-args",
Expand All @@ -110,9 +114,8 @@ def parse_command_line(args):
override the command provided by Machines."""
)
parser.add_argument(
"--use-openmp", action="store_true",
default=False,
help="""Turn on OPENMP support for tests."""
"--no-openmp", action="store_true",
help="""Default is to include OPENMP support for tests; this option excludes openmp"""
)
parser.add_argument(
"--xml-test-list",
Expand All @@ -133,8 +136,8 @@ def parse_command_line(args):

return output, args.build_dir, args.build_optimized, args.clean,\
args.cmake_args, args.compiler, args.enable_genf90, args.machine, args.machines_dir,\
args.make_j, args.mpilib, args.mpirun_command, args.test_spec_dir, args.ctest_args,\
args.use_openmp, args.xml_test_list, args.verbose
args.make_j, args.mpilib, args.no_mpirun, args.mpirun_command, args.test_spec_dir, args.ctest_args,\
args.no_openmp, args.xml_test_list, args.verbose


def cmake_stage(name, test_spec_dir, build_optimized, mpirun_command, output, cmake_args=None, clean=False, verbose=False, enable_genf90=True, color=True):
Expand Down Expand Up @@ -169,7 +172,7 @@ def cmake_stage(name, test_spec_dir, build_optimized, mpirun_command, output, cm
test_spec_dir,
"-DCIME_CMAKE_MODULE_DIRECTORY="+os.path.abspath(os.path.join(_CIMEROOT,"src","externals","CMake")),
"-DCMAKE_BUILD_TYPE="+build_type,
"-DPFUNIT_MPIRUN="+mpirun_command,
"-DPFUNIT_MPIRUN='"+mpirun_command+"'",
]
if verbose:
cmake_command.append("-Wdev")
Expand Down Expand Up @@ -216,10 +219,12 @@ def make_stage(name, output, make_j, clean=False, verbose=True):
def _main():
output, build_dir, build_optimized, clean,\
cmake_args, compiler, enable_genf90, machine, machines_dir,\
make_j, mpilib, mpirun_command, test_spec_dir, ctest_args,\
use_openmp, xml_test_list, verbose \
make_j, mpilib, no_mpirun, mpirun_command, test_spec_dir, ctest_args,\
no_openmp, xml_test_list, verbose \
= parse_command_line(sys.argv)

use_openmp = not no_openmp

#=================================================
# Find directory and file paths.
#=================================================
Expand All @@ -241,14 +246,6 @@ def _main():
)




# Search for the CESM root directory.
# First check the option. If not specified, look to see if there's a tools
# directory two levels up (just as a sanity check).
if machine is None:
machine="yellowstone"

if machines_dir is not None:
machines_file = os.path.join(machines_dir, "config_machines.xml")
machobj = Machines(infile=machines_file, machine=machine)
Expand All @@ -269,8 +266,10 @@ def _main():
#=================================================
if mpilib is None:
mpilib = machobj.get_default_MPIlib()
logger.warn("Using mpilib: %s"%mpilib)
if compiler is None:
compiler = machobj.get_default_compiler()
logger.warn("Compiler is %s"%compiler)

debug = not build_optimized
os_ = machobj.get_value("OS")
Expand All @@ -280,8 +279,22 @@ def _main():
#
configure(machobj, build_dir, ["CMake"], compiler, mpilib, debug, os_)
machspecific = EnvMachSpecific(build_dir)

if no_mpirun:
mpirun_command = ""
elif mpirun_command is None:
mpi_attribs = {
"compiler" : compiler,
"mpilib" : mpilib,
"threaded" : use_openmp,
"unit_testing" : True
}

# We can get away with specifying case=None since we're using exe_only=True
mpirun_command, _ = machspecific.get_mpirun(case=None, attribs=mpi_attribs, exe_only=True)
logger.warn("mpirun command is '%s'"%mpirun_command)

machspecific.load_env(compiler, debug, mpilib)
logger.warn("Compiler is %s"%compiler)
os.environ["OS"] = os_
os.environ["COMPILER"] = compiler
os.environ["DEBUG"] = stringify_bool(debug)
Expand Down

0 comments on commit 3779ec1

Please sign in to comment.