diff --git a/regtest.py b/regtest.py index 18ba975..c321bf3 100755 --- a/regtest.py +++ b/regtest.py @@ -49,15 +49,15 @@ def find_build_dirs(tests): last_safe = False for obj in tests: - + # keep track of the build directory and which source tree it is # in (e.g. the extra build dir) - + # first find the list of unique build directories dir_pair = (obj.buildDir, obj.extra_build_dir) if build_dirs.count(dir_pair) == 0: build_dirs.append(dir_pair) - + # re-make all problems that specify an extra compile argument, # and the test that comes after, just to make sure that any # unique build commands are seen. @@ -67,9 +67,9 @@ def find_build_dirs(tests): obj.reClean = 0 else: last_safe = True - + return build_dirs - + def cmake_setup(suite): "Setup for cmake" @@ -536,14 +536,48 @@ def test_suite(argv): coutfile = "{}/{}.make.out".format(output_dir, test.name) if suite.sourceTree == "C_Src" or test.testSrcTree == "C_Src": - if suite.useCmake: - comp_string, rc = suite.build_test_cmake(test=test, outfile=coutfile) - else: - comp_string, rc = suite.build_c(test=test, outfile=coutfile) - executable = test_util.get_recent_filename(bdir, "", ".ex") + # First check whether an executable was already compiled with + # the same options (not enabled for CMake, for now) + found_previous_test = False + if test.avoid_recompiling and not suite.useCmake: + comp_string = suite.get_comp_string_c(test=test, outfile=coutfile) + # Loop over the existing tests + for previous_test in test_list: + # Check if the compile command was the same + if previous_test.comp_string == comp_string: + found_previous_test = True + break + + # Avoid recompiling in this case + if found_previous_test: + suite.log.log("found pre-built executable for this test") + with open(coutfile, "a") as cf: + cf.write("found pre-built executable for this test\n") + rc = 0 + executable = previous_test.executable + # Otherwise recompile + else: + if suite.useCmake: + comp_string, rc = suite.build_test_cmake(test=test, outfile=coutfile) + else: + comp_string, rc = suite.build_c(test=test, outfile=coutfile) + executable = test_util.get_recent_filename(bdir, "", ".ex") + # Store the executable (to avoid recompiling for other tests) + if test.avoid_recompiling and executable is not None: + # Create a unique directory for these compilations options, + # by using the hash of the compilation options as the directory name + if not os.path.exists('PreviouslyCompiled'): + os.mkdir('PreviouslyCompiled') + dir_name = os.path.join( 'PreviouslyCompiled', str(hash(comp_string)) ) + if not os.path.exists( dir_name ): + os.mkdir(dir_name) + # Copy the executable to that unique directory + shutil.copy( executable, dir_name ) test.comp_string = comp_string + # Register name of the executable + test.executable = executable # make return code is 0 if build was successful if rc == 0: @@ -572,7 +606,12 @@ def test_suite(argv): needed_files = [] if executable is not None: - needed_files.append((executable, "move")) + if test.avoid_recompiling: + # Find unique directory where the executable is stored + dir_name = os.path.join( 'PreviouslyCompiled', str(hash(test.comp_string)) ) + needed_files.append((os.path.join(dir_name,executable), "copy")) + else: + needed_files.append((executable, "move")) if test.run_as_script: needed_files.append((test.run_as_script, "copy")) diff --git a/suite.py b/suite.py index f258402..7732323 100644 --- a/suite.py +++ b/suite.py @@ -114,6 +114,7 @@ def __init__(self, name): self.nlevels = None # set but running fboxinfo on the output self.comp_string = None # set automatically + self.executable = None # set automatically self.run_command = None # set automatically self.job_info_field1 = "" @@ -343,6 +344,7 @@ def set_runs_to_average(self, value): # Static member variables, set explicitly in apply_args in Suite class compile_only = False + avoid_recompiling = False skip_comparison = False global_tolerance = None global_particle_tolerance = None @@ -879,8 +881,8 @@ def make_realclean(self, repo="source"): test_util.run(cmd) - def build_c(self, test=None, opts="", target="", outfile=None, c_make_additions=None): - + def get_comp_string_c(self, test=None, opts="", target="", + outfile=None, c_make_additions=None): build_opts = "" if c_make_additions is None: c_make_additions = self.add_to_c_make_command @@ -911,6 +913,12 @@ def build_c(self, test=None, opts="", target="", outfile=None, c_make_additions= self.MAKE, self.numMakeJobs, self.amrex_dir, all_opts, self.COMP, c_make_additions, target) + return comp_string + + def build_c(self, test=None, opts="", target="", + outfile=None, c_make_additions=None): + comp_string = self.get_comp_string_c( test, opts, target, + outfile, c_make_additions ) self.log.log(comp_string) stdout, stderr, rc = test_util.run(comp_string, outfile=outfile) @@ -1069,6 +1077,7 @@ def apply_args(self): args = self.args Test.compile_only = args.compile_only + Test.avoid_recompiling = args.avoid_recompiling Test.skip_comparison = args.skip_comparison Test.global_tolerance = args.tolerance Test.global_particle_tolerance = args.particle_tolerance diff --git a/test_util.py b/test_util.py index d26fed0..c98bedb 100644 --- a/test_util.py +++ b/test_util.py @@ -343,6 +343,8 @@ def get_args(arg_string=None): "options that control how the tests are run") run_group.add_argument("--compile_only", action="store_true", help="test only that the code compiles, without running anything") + run_group.add_argument("--avoid_recompiling", action="store_true", + help="avoid recompiling, if an executable was already build with the same compilation options, in a previous test") run_group.add_argument("--with_valgrind", action="store_true", help="run with valgrind") run_group.add_argument("--valgrind_options", type=str, default="--leak-check=yes --log-file=vallog.%p",