blob: 9496ac5a5f2ff8dbbe151d7268544ce8f7651bf1 [file] [log] [blame]
#!/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