"""Database support module for the benchbuild study."""
import logging
import os
from sqlalchemy.exc import IntegrityError
from benchbuild.settings import CFG
LOG = logging.getLogger(__name__)
[docs]def validate(func):
def validate_run_func(run, session, *args, **kwargs):
if run.status == 'failed':
LOG.debug("Run failed. Execution of '%s' cancelled", str(func))
return None
return func(run, session, *args, **kwargs)
return validate_run_func
[docs]def create_run(cmd, project, exp, grp):
"""
Create a new 'run' in the database.
This creates a new transaction in the database and creates a new
run in this transaction. Afterwards we return both the transaction as
well as the run itself. The user is responsible for committing it when
the time comes.
Args:
cmd: The command that has been executed.
prj: The project this run belongs to.
exp: The experiment this run belongs to.
grp: The run_group (uuid) we blong to.
Returns:
The inserted tuple representing the run and the session opened with
the new run. Don't forget to commit it at some point.
"""
from benchbuild.utils import schema as s
session = s.Session()
run = s.Run(
command=str(cmd),
project_name=project.name,
project_group=project.group,
experiment_name=exp,
run_group=str(grp),
experiment_group=project.experiment.id)
session.add(run)
session.commit()
return (run, session)
[docs]def create_run_group(prj):
"""
Create a new 'run_group' in the database.
This creates a new transaction in the database and creates a new run_group
within this transaction. Afterwards we return both the transaction as well
as the run_group itself. The user is responsible for committing it when the
time comes.
Args:
prj - The project for which we open the run_group.
Returns:
A tuple (group, session) containing both the newly created run_group and
the transaction object.
"""
from benchbuild.utils import schema as s
session = s.Session()
experiment = prj.experiment
group = s.RunGroup(id=prj.run_uuid, experiment=experiment.id)
session.add(group)
session.commit()
return (group, session)
[docs]def persist_project(project):
"""
Persist this project in the benchbuild database.
Args:
project: The project we want to persist.
"""
from benchbuild.utils.schema import Project, Session
session = Session()
projects = session.query(Project) \
.filter(Project.name == project.name) \
.filter(Project.group_name == project.group)
name = project.name
desc = project.__doc__
domain = project.domain
group_name = project.group
version = project.version() \
if callable(project.version) else project.version
try:
src_url = project.src_uri
except AttributeError:
src_url = 'unknown'
if projects.count() == 0:
newp = Project()
newp.name = name
newp.description = desc
newp.src_url = src_url
newp.domain = domain
newp.group_name = group_name
newp.version = version
session.add(newp)
else:
newp_value = {
"name": name,
"description": desc,
"src_url": src_url,
"domain": domain,
"group_name": group_name,
"version": version
}
projects.update(newp_value)
session.commit()
return (projects, session)
[docs]def persist_experiment(experiment):
"""
Persist this experiment in the benchbuild database.
Args:
experiment: The experiment we want to persist.
"""
from benchbuild.utils.schema import Experiment, Session
session = Session()
cfg_exp = experiment.id
LOG.debug("Using experiment ID stored in config: %s", cfg_exp)
exps = session.query(Experiment).filter(Experiment.id == cfg_exp)
desc = str(CFG["experiment_description"])
name = experiment.name
if exps.count() == 0:
newe = Experiment()
newe.id = cfg_exp
newe.name = name
newe.description = desc
session.add(newe)
ret = newe
else:
exps.update({'name': name, 'description': desc})
ret = exps.first()
try:
session.commit()
except IntegrityError:
session.rollback()
persist_experiment(experiment)
return (ret, session)
[docs]@validate
def persist_time(run, session, timings):
"""
Persist the run results in the database.
Args:
run: The run we attach this timing results to.
session: The db transaction we belong to.
timings: The timing measurements we want to store.
"""
from benchbuild.utils import schema as s
for timing in timings:
session.add(
s.Metric(name="time.user_s", value=timing[0], run_id=run.id))
session.add(
s.Metric(name="time.system_s", value=timing[1], run_id=run.id))
session.add(
s.Metric(name="time.real_s", value=timing[2], run_id=run.id))
[docs]def persist_perf(run, session, svg_path):
"""
Persist the flamegraph in the database.
The flamegraph exists as a SVG image on disk until we persist it in the
database.
Args:
run: The run we attach these perf measurements to.
session: The db transaction we belong to.
svg_path: The path to the SVG file we want to store.
"""
from benchbuild.utils import schema as s
with open(svg_path, 'r') as svg_file:
svg_data = svg_file.read()
session.add(
s.Metadata(name="perf.flamegraph", value=svg_data, run_id=run.id))
[docs]def persist_compilestats(run, session, stats):
"""
Persist the run results in the database.
Args:
run: The run we attach the compilestats to.
session: The db transaction we belong to.
stats: The stats we want to store in the database.
"""
for stat in stats:
stat.run_id = run.id
session.add(stat)
[docs]def persist_config(run, session, cfg):
"""
Persist the configuration in as key-value pairs.
Args:
run: The run we attach the config to.
session: The db transaction we belong to.
cfg: The configuration we want to persist.
"""
from benchbuild.utils import schema as s
for cfg_elem in cfg:
session.add(
s.Config(name=cfg_elem, value=cfg[cfg_elem], run_id=run.id))