139 lines
3.9 KiB
Python
139 lines
3.9 KiB
Python
|
|
import os
|
||
|
|
import signal
|
||
|
|
import subprocess
|
||
|
|
import time
|
||
|
|
|
||
|
|
from .build import Build
|
||
|
|
from .config import Config
|
||
|
|
from .logger import Logger
|
||
|
|
from .storage import Storage
|
||
|
|
|
||
|
|
|
||
|
|
def create_builds_table(conn):
|
||
|
|
with conn:
|
||
|
|
conn.execute("""
|
||
|
|
CREATE TABLE IF NOT EXISTS builds (
|
||
|
|
ctk TEXT NOT NULL,
|
||
|
|
cccl TEXT NOT NULL,
|
||
|
|
bench TEXT NOT NULL,
|
||
|
|
code TEXT NOT NULL,
|
||
|
|
elapsed REAL
|
||
|
|
);
|
||
|
|
""")
|
||
|
|
|
||
|
|
|
||
|
|
class CMakeCache:
|
||
|
|
_instance = None
|
||
|
|
|
||
|
|
def __new__(cls, *args, **kwargs):
|
||
|
|
if cls._instance is None:
|
||
|
|
cls._instance = super().__new__(cls, *args, **kwargs)
|
||
|
|
create_builds_table(Storage().connection())
|
||
|
|
return cls._instance
|
||
|
|
|
||
|
|
def pull_build(self, bench):
|
||
|
|
config = Config()
|
||
|
|
ctk = config.ctk
|
||
|
|
cccl = config.cccl
|
||
|
|
conn = Storage().connection()
|
||
|
|
|
||
|
|
with conn:
|
||
|
|
query = "SELECT code, elapsed FROM builds WHERE ctk = ? AND cccl = ? AND bench = ?;"
|
||
|
|
result = conn.execute(query, (ctk, cccl, bench.label())).fetchone()
|
||
|
|
|
||
|
|
if result:
|
||
|
|
code, elapsed = result
|
||
|
|
return Build(int(code), float(elapsed))
|
||
|
|
|
||
|
|
return result
|
||
|
|
|
||
|
|
def push_build(self, bench, build):
|
||
|
|
config = Config()
|
||
|
|
ctk = config.ctk
|
||
|
|
cccl = config.cccl
|
||
|
|
conn = Storage().connection()
|
||
|
|
|
||
|
|
with conn:
|
||
|
|
conn.execute(
|
||
|
|
"INSERT INTO builds (ctk, cccl, bench, code, elapsed) VALUES (?, ?, ?, ?, ?);",
|
||
|
|
(ctk, cccl, bench.label(), build.code, build.elapsed),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class CMake:
|
||
|
|
def __init__(self):
|
||
|
|
pass
|
||
|
|
|
||
|
|
def do_build(self, bench, timeout):
|
||
|
|
logger = Logger()
|
||
|
|
|
||
|
|
try:
|
||
|
|
if not bench.is_base():
|
||
|
|
with open(bench.exe_name() + ".h", "w") as f:
|
||
|
|
f.writelines(bench.definitions())
|
||
|
|
|
||
|
|
cmd = ["cmake", "--build", ".", "--target", bench.exe_name()]
|
||
|
|
logger.info(
|
||
|
|
"starting build for {}: {}".format(bench.label(), " ".join(cmd))
|
||
|
|
)
|
||
|
|
|
||
|
|
begin = time.time()
|
||
|
|
p = subprocess.Popen(
|
||
|
|
cmd,
|
||
|
|
start_new_session=True,
|
||
|
|
stdout=subprocess.DEVNULL,
|
||
|
|
stderr=subprocess.DEVNULL,
|
||
|
|
)
|
||
|
|
p.wait(timeout=timeout)
|
||
|
|
elapsed = time.time() - begin
|
||
|
|
logger.info(
|
||
|
|
"finished build for {} (exit code: {}) in {:.3f}s".format(
|
||
|
|
bench.label(), p.returncode, elapsed
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
return Build(p.returncode, elapsed)
|
||
|
|
except subprocess.TimeoutExpired:
|
||
|
|
logger.info(
|
||
|
|
"build for {} reached timeout of {}s".format(bench.label(), timeout)
|
||
|
|
)
|
||
|
|
os.killpg(os.getpgid(p.pid), signal.SIGTERM)
|
||
|
|
return Build(424242, float("inf"))
|
||
|
|
|
||
|
|
def build(self, bench):
|
||
|
|
logger = Logger()
|
||
|
|
timeout = None
|
||
|
|
|
||
|
|
cache = CMakeCache()
|
||
|
|
|
||
|
|
if bench.is_base():
|
||
|
|
# Only base build can be pulled from cache
|
||
|
|
build = cache.pull_build(bench)
|
||
|
|
|
||
|
|
if build:
|
||
|
|
logger.info("found cached base build for {}".format(bench.label()))
|
||
|
|
if bench.is_base():
|
||
|
|
if not os.path.exists("bin/{}".format(bench.exe_name())):
|
||
|
|
self.do_build(bench, None)
|
||
|
|
|
||
|
|
return build
|
||
|
|
else:
|
||
|
|
base_build = self.build(bench.get_base())
|
||
|
|
|
||
|
|
if base_build.code != 0:
|
||
|
|
raise Exception("Base build failed")
|
||
|
|
|
||
|
|
timeout = base_build.elapsed * 10
|
||
|
|
|
||
|
|
build = self.do_build(bench, timeout)
|
||
|
|
cache.push_build(bench, build)
|
||
|
|
return build
|
||
|
|
|
||
|
|
def clean():
|
||
|
|
cmd = ["cmake", "--build", ".", "--target", "clean"]
|
||
|
|
p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||
|
|
p.wait()
|
||
|
|
|
||
|
|
if p.returncode != 0:
|
||
|
|
raise Exception("Unable to clean build directory")
|