mirror of
https://github.com/cp2k/cp2k.git
synced 2026-07-28 14:15:19 -04:00
regtesting: Add classic mode to do_regtest.py
This commit is contained in:
parent
51cc574b6b
commit
370690111b
1 changed files with 58 additions and 24 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue