regtesting: Add classic mode to do_regtest.py

This commit is contained in:
Ole Schütt 2021-10-27 10:40:56 +02:00 committed by Ole Schütt
parent 51cc574b6b
commit 370690111b

View file

@ -6,7 +6,7 @@ from asyncio import Semaphore
from asyncio.subprocess import PIPE, STDOUT, Process
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional, Tuple, Union
import argparse
import asyncio
import math
@ -23,8 +23,8 @@ try:
except:
from typing_extensions import Literal # type: ignore
# Some tests do not work with the cp2k shell (which is generally considered a bug).
ALLWAYS_SKIP_DIRS = [
# Some tests do not work with --keepalive (which is generally considered a bug).
KEEPALIVE_SKIP_DIRS = [
"TMC/regtest",
"TMC/regtest_ana_on_the_fly",
"TMC/regtest_ana_post_proc",
@ -36,11 +36,11 @@ ALLWAYS_SKIP_DIRS = [
async def main() -> None:
parser = argparse.ArgumentParser(description="Runs CP2K regression test suite.")
parser.add_argument("--mpiranks", type=int, default=2)
parser.add_argument("--ompthreads", type=int, default=2)
parser.add_argument("--ompthreads", type=int)
parser.add_argument("--maxtasks", type=int, default=os.cpu_count())
parser.add_argument("--timeout", type=int, default=400)
parser.add_argument("--maxerrors", type=int, default=50)
parser.add_argument("--no-keep-alive", dest="keep_alive", action="store_false")
parser.add_argument("--keepalive", dest="keepalive", action="store_true")
parser.add_argument("--debug", action="store_true")
parser.add_argument("--restrictdir", action="append")
parser.add_argument("arch")
@ -66,7 +66,7 @@ async def main() -> None:
print(f"Workers: {cfg.num_workers}")
print(f"Timeout [s]: {cfg.timeout}")
print(f"Work base dir: {cfg.work_base_dir}")
print(f"Keep alive: {cfg.keep_alive}")
print(f"Keepalive: {cfg.keepalive}")
print(f"Debug: {cfg.debug}")
print(f"ARCH: {cfg.arch}")
print(f"VERSION: {cfg.version}")
@ -117,8 +117,8 @@ async def main() -> None:
print(f"Skipping {batch.name} because its requirements are not satisfied.")
elif not any(re.match(p, batch.name) for p in cfg.restrictdirs):
num_restrictdirs += 1
elif batch.name in ALLWAYS_SKIP_DIRS:
print(f"Skipping {batch.name} because it doesn't work with the cp2k shell.")
elif cfg.keepalive and batch.name in KEEPALIVE_SKIP_DIRS:
print(f"Skipping {batch.name} because it doesn't work with --keepalive.")
else:
tasks.append(asyncio.create_task(run_batch(batch, cfg))) # launch
@ -183,7 +183,8 @@ class Config:
def __init__(self, args: argparse.Namespace):
self.timeout = args.timeout
self.use_mpi = args.version.startswith("p")
self.ompthreads = args.ompthreads
default_ompthreads = 2 if "smp" in args.version else 1
self.ompthreads = args.ompthreads if args.ompthreads else default_ompthreads
self.mpiranks = args.mpiranks if self.use_mpi else 1
self.num_workers = int(args.maxtasks / self.ompthreads / self.mpiranks)
self.workers = Semaphore(self.num_workers)
@ -192,7 +193,7 @@ class Config:
leaf_dir = f"TEST-{args.arch}-{args.version}-{datestamp}"
self.work_base_dir = self.cp2k_root / "regtesting" / leaf_dir
self.error_summary = self.work_base_dir / "error_summary"
self.keep_alive = args.keep_alive
self.keepalive = args.keepalive
self.arch = args.arch
self.version = args.version
self.debug = args.debug
@ -389,6 +390,26 @@ class Cp2kShell:
return self._child.returncode if self._child.returncode else 0
# ======================================================================================
async def wait_for_child_process(
child: Process, timeout: int
) -> Tuple[bytes, int, bool]:
try:
output, _ = await asyncio.wait_for(child.communicate(), timeout=timeout)
timeout = False
returncode = child.returncode if child.returncode else 0
except asyncio.TimeoutError:
timeout = True
returncode = -9
try:
child.terminate() # Give mpiexec a chance to shutdown
except ProcessLookupError:
pass
output, _ = await child.communicate()
return output, returncode, timeout
# ======================================================================================
async def run_batch(batch: Batch, cfg: Config) -> BatchResult:
async with cfg.workers:
@ -402,17 +423,7 @@ async def run_unittests(batch: Batch, cfg: Config) -> List[TestResult]:
for test in batch.unittests:
start_time = time.perf_counter()
child = await cfg.launch_exe(test.name, str(cfg.cp2k_root), cwd=batch.workdir)
try:
output, _ = await asyncio.wait_for(child.communicate(), timeout=cfg.timeout)
timeout = False
except asyncio.TimeoutError:
timeout = True
try:
child.terminate() # Give mpiexec a chance to shutdown
except ProcessLookupError:
pass
output, _ = await child.communicate()
output, returncode, timeout = await wait_for_child_process(child, cfg.timeout)
duration = time.perf_counter() - start_time
test.out_path.write_bytes(output)
output_lines = output.decode("utf8", errors="replace").split("\n")
@ -421,8 +432,8 @@ async def run_unittests(batch: Batch, cfg: Config) -> List[TestResult]:
if timeout:
error += f"Timeout after {duration} seconds."
results.append(TestResult(test, duration, "TIMEOUT", error))
elif child.returncode != 0:
error += f"Runtime failure with code {child.returncode}."
elif returncode != 0:
error += f"Runtime failure with code {returncode}."
results.append(TestResult(test, duration, "RUNTIME FAIL", error))
else:
results.append(TestResult(test, duration, "OK"))
@ -432,6 +443,14 @@ async def run_unittests(batch: Batch, cfg: Config) -> List[TestResult]:
# ======================================================================================
async def run_regtests(batch: Batch, cfg: Config) -> List[TestResult]:
if cfg.keepalive:
return await run_regtests_keepalive(batch, cfg)
else:
return await run_regtests_classic(batch, cfg)
# ======================================================================================
async def run_regtests_keepalive(batch: Batch, cfg: Config) -> List[TestResult]:
shell = Cp2kShell(cfg, batch.workdir)
await shell.start()
@ -448,7 +467,7 @@ async def run_regtests(batch: Batch, cfg: Config) -> List[TestResult]:
timeout = True
returncode = -9
if returncode != 0 or not cfg.keep_alive:
if returncode != 0:
await shell.stop()
await shell.start()
duration = time.perf_counter() - start_time
@ -459,6 +478,21 @@ async def run_regtests(batch: Batch, cfg: Config) -> List[TestResult]:
return results
# ======================================================================================
async def run_regtests_classic(batch: Batch, cfg: Config) -> List[TestResult]:
results: List[TestResult] = []
for test in batch.regtests:
start_time = time.perf_counter()
child = await cfg.launch_exe("cp2k", test.inp_fn, cwd=batch.workdir)
output, returncode, timeout = await wait_for_child_process(child, cfg.timeout)
duration = time.perf_counter() - start_time
test.out_path.write_bytes(output)
res = eval_regtest(batch, test, duration, returncode, timeout)
results.append(res)
return results
# ======================================================================================
def eval_regtest(
batch: Batch, test: Regtest, duration: float, returncode: int, timeout: bool