| #!/usr/bin/env python |
| # -*- Python -*- |
| from __future__ import print_function |
| |
| import os |
| import shutil |
| import stat |
| |
| # We import test functionity from LNT. |
| from lnt.tests import nt |
| from lnt.testing import TestSamples, PASS, FAIL, XFAIL |
| from lnt.testing.util import commands |
| |
| # Implement cp -rf such that src can be both a file or a directory and if |
| # the dst exists create the file/dir under dst rather than rename on the |
| # fly. |
| def cp_rf(src, dst): |
| if os.path.isfile(src): |
| shutil.copy(src, dst) |
| else: |
| newdst = dst |
| if os.path.exists(dst): |
| newdst = os.path.join(dst, os.path.basename(src)) |
| shutil.copytree(src, newdst) |
| |
| |
| # Test module classes are currently required to subclass 'nt.TestModule'. |
| class TestModule(nt.TestModule): |
| |
| timeout = 5000 |
| |
| def __init__(self): |
| # The subdirectory name under externals E.g. CINT2006 |
| self.suite = "C" + self.category.upper() + str(self.year) |
| |
| # Name to identify this LNT test, e.g. nts.LNT/CINT2006_ref/456.hmmer |
| self.testname = "nts.LNT/%s_ref/%s" % (self.suite, self.benchmark) |
| |
| # Executable name, e.g. 456.hmmer.simple |
| self.exe = self.benchmark + ".simple" |
| |
| def configure_test_suite(self, working_dir): |
| args = [ |
| os.path.realpath(os.path.join(self.config.test_suite_root, "configure")) |
| ] |
| if self.config.without_llvm: |
| args.extend(["--without-llvmsrc", "--without-llvmobj"]) |
| else: |
| args.extend( |
| [ |
| "--with-llvmsrc=%s" % self.config.llvm_src_root, |
| "--with-llvmobj=%s" % self.config.llvm_obj_root, |
| ] |
| ) |
| |
| if self.config.test_suite_externals: |
| args.append( |
| "--with-externals=%s" |
| % os.path.realpath(self.config.test_suite_externals) |
| ) |
| |
| return self.call(args, cwd=working_dir) |
| |
| def fail(self): |
| return [TestSamples(self.testname + ".compile.status", [FAIL])] |
| |
| def copy_input_set(self, dest_dir, size): |
| if size == "train": |
| input_set = self.train_input_set |
| elif size == "ref": |
| input_set = self.ref_input_set |
| else: |
| fatal("only train and ref are supported for now") |
| |
| for f in input_set: |
| cp_rf(os.path.join(self.datadir, f), dest_dir) |
| |
| def copy_output_set(self, dest_dir, size): |
| if size == "train": |
| output_set = self.train_output_set |
| else: |
| output_set = self.ref_output_set |
| |
| for f in output_set: |
| cp_rf(os.path.join(self.datadir, f), dest_dir) |
| |
| def run_safely(self, args, **kwargs): |
| if kwargs.get("shell", False): |
| argstr = args |
| else: |
| argstr = " ".join(args) |
| kwargs["shell"] = True |
| |
| if "file_index" in kwargs: |
| file_index = kwargs["file_index"] |
| # Remove so that it can be forwarded to self.call. |
| del kwargs["file_index"] |
| else: |
| file_index = 0 |
| |
| # Generate a unique file for each training run (if requested) |
| timeit = [ |
| "LLVM_PROFILE_FILE=run_%d.profraw" % file_index, |
| os.path.join(self.OBJROOT, "tools", "timeit-target"), |
| ] |
| |
| cwd = kwargs.get("cwd", os.getcwd()) |
| summary_file = os.path.join(cwd, "summary_%d.time" % file_index) |
| timeit.extend( |
| [ |
| "--limit-core", |
| "0", |
| "--limit-cpu", |
| str(self.timeout), |
| "--timeout", |
| str(self.timeout), |
| "--limit-file-size", |
| "104857600", |
| "--limit-rss-size", |
| "838860800", |
| "--summary", |
| summary_file, |
| ] |
| ) |
| timeit.append(argstr) |
| cmdstr = " ".join(timeit) |
| |
| if self.config.remote: |
| command_file = os.path.join(cwd, "command_%d" % file_index) |
| with open(command_file, "w") as f: |
| # Chdir here so that the redirects are put into CWD as well. |
| remote_command = "cd %s\n%s\n" % (cwd, cmdstr) |
| print("command:", remote_command, file=self.log, end=" ") |
| f.write(remote_command) |
| |
| st = os.stat(command_file) |
| os.chmod(command_file, st.st_mode | stat.S_IEXEC) |
| |
| res = self.call( |
| [ |
| self.config.remote_client, |
| "-l", |
| self.config.remote_user, |
| self.config.remote_host, |
| "-p", |
| str(self.config.remote_port), |
| command_file, |
| ] |
| ) |
| |
| else: |
| kwargs["shell"] = True |
| res = self.call(cmdstr, **kwargs) |
| |
| if res != 0: |
| return (res, 0) |
| |
| summary = open(summary_file, "r").readlines() |
| status = [line.split()[1] for line in summary if line.startswith("exit")] |
| assert len(status) == 1, "incorrect exit status" |
| time = [ |
| line.split()[1] |
| for line in summary |
| if line.startswith(self.config.test_time_stat) |
| ] |
| assert len(time) == 1, "incorrect ellapsed time" |
| |
| return (int(status[0]), float(time[0])) |
| |
| def execute_test(self, options, make_variables, config): |
| MODULENAME = options["MODULENAME"] |
| self.SRCROOT = options["SRCROOT"] |
| self.config = config |
| self.OBJROOT = options["OBJROOT"] |
| CC = options["CC"] |
| CFLAGS = options["CFLAGS"] |
| TEST_SUITE_EXTERNALS = config.test_suite_externals |
| |
| # test-suite-externals//speccpu2006/benchspec/CPU2006/400.perlbench vs |
| # test-suite-externals//speccpu2000/benchspec/CINT2000/164.gzip |
| suitedir = os.path.join( |
| TEST_SUITE_EXTERNALS, "speccpu" + str(self.year), "benchspec" |
| ) |
| if self.year == "2000": |
| suitedir = os.path.join(suitedir, "C%s2000" % self.category.upper()) |
| else: |
| suitedir = os.path.join(suitedir, "CPU" + self.year) |
| |
| self.datadir = os.path.join(suitedir, self.benchmark, "data") |
| print( |
| "%s\n options: %s\n\nmake variables: %s\n\n" |
| % (self.testname, str(options), str(make_variables)), |
| file=self.log, |
| ) |
| |
| if not os.path.exists(self.datadir): |
| print("skipping, no source under externals", file=self.log) |
| return [] |
| |
| res = self.configure_test_suite(self.OBJROOT) |
| if res != 0: |
| return self.fail() |
| |
| make_cmd = ["make", "-k"] |
| make_cmd.extend("%s=%s" % (k, v) for k, v in make_variables.items()) |
| |
| # RunSafely.sh requires timeit, build it. |
| res = self.call(make_cmd + ["tools"], cwd=self.OBJROOT) |
| if res != 0: |
| return self.fail() |
| |
| make_cmd.append("USE_SPEC_TEST_MODULE=1") |
| |
| # Run make clean to create the benchmark directories. |
| external_obj = os.path.join( |
| self.OBJROOT, "External", "SPEC", self.suite, self.benchmark |
| ) |
| clean_cmd = make_cmd |
| external_spec_obj = os.path.split(external_obj)[0] |
| result = self.call(make_cmd + ["-C", external_spec_obj, "clean"]) |
| if result != 0: |
| return self.fail() |
| |
| # From this on, we are operating in the 456.hmmer directory. |
| make_cmd.extend(["-C", external_obj]) |
| exe_file = os.path.join("Output", self.exe) |
| |
| if config.spec_with_pgo: |
| pgo_dir = os.path.join(self.OBJROOT, "pgo") |
| os.mkdir(pgo_dir) |
| |
| target_flags = make_variables["TARGET_FLAGS"] + " -fprofile-instr-generate" |
| pgo_make_cmd = make_cmd[:] |
| pgo_make_cmd.append("TARGET_FLAGS=%s" % target_flags) |
| result = self.call(pgo_make_cmd + [exe_file]) |
| |
| exe = os.path.join(external_obj, exe_file) |
| if result != 0 or not os.path.exists(exe): |
| return self.fail() |
| shutil.copy(exe, pgo_dir) |
| |
| self.copy_input_set(pgo_dir, "train") |
| |
| for (i, args) in enumerate(self.train_args): |
| pgo_cmd = "./%s %s" % (self.exe, args) |
| (result, time) = self.run_safely( |
| pgo_cmd, cwd=pgo_dir, shell=True, env=os.environ, file_index=i |
| ) |
| if result != 0: |
| return self.fail() |
| if not os.path.exists(os.path.join(pgo_dir, "run_%d.profraw" % i)): |
| print("Failed to create PGO output", file=self.log) |
| return self.fail() |
| |
| llvm_profdata = os.path.join(os.path.dirname(CC), "llvm-profdata") |
| result = self.call( |
| llvm_profdata + " merge -output=code.profdata pgo/run_*.profraw", |
| shell=True, |
| cwd=self.OBJROOT, |
| ) |
| if result != 0: |
| return self.fail() |
| |
| target_flags = ( |
| make_variables["TARGET_FLAGS"] |
| + " -fprofile-instr-use=" |
| + os.path.join(self.OBJROOT, "code.profdata") |
| ) |
| make_cmd.append("TARGET_FLAGS=%s" % target_flags) |
| |
| result = self.call(make_cmd + ["-C", external_spec_obj, "clean"]) |
| if result != 0: |
| return self.fail() |
| |
| start_time = self.get_time() |
| result = self.call(make_cmd + [exe_file]) |
| compile_time = self.get_time() - start_time |
| |
| exe = os.path.join(external_obj, exe_file) |
| if result != 0 or not os.path.exists(exe): |
| return self.fail() |
| |
| shutil.copy(exe, self.OBJROOT) |
| |
| self.copy_input_set(self.OBJROOT, "ref") |
| self.copy_output_set(self.OBJROOT, "ref") |
| |
| run_cmds = ["./%s %s" % (self.exe, args) for args in self.ref_args] |
| status = PASS |
| |
| exec_time = 0 |
| for (file_index, cmd) in enumerate(run_cmds): |
| (result, time) = self.run_safely( |
| cmd, cwd=self.OBJROOT, shell=True, file_index=file_index |
| ) |
| if result != 0: |
| status = FAIL |
| exec_time += time |
| |
| os.environ["PATH"] += ":" + os.path.join(self.OBJROOT, "tools") |
| for cmd in self.ref_cmp_cmds: |
| if self.call(cmd, cwd=self.OBJROOT, shell=True, env=os.environ) != 0: |
| status = FAIL |
| |
| result = [ |
| TestSamples(self.testname + ".compile", [compile_time]), |
| TestSamples(self.testname + ".exec", [exec_time]), |
| ] |
| if status == FAIL: |
| result.append(TestSamples(self.testname + ".exec.status", [status])) |
| |
| return result |