Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config/repos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
experiments:
- ../experiments
- ../experiments/test
systems:
- ../systems
applications:
- ../repo
packages:
- ../repo
3 changes: 3 additions & 0 deletions experiments/test/repo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
repo:
namespace: test
subdirectory: ''
File renamed without changes.
25 changes: 17 additions & 8 deletions lib/benchpark/cmd/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import ruamel.yaml as yaml

import benchpark.config
import benchpark.paths
from benchpark.debug import debug_print
from benchpark.runtime import RuntimeResources
Expand Down Expand Up @@ -203,6 +204,8 @@ def include_fn(fname):
experiments_root, upstream=RuntimeResources(benchpark.paths.benchpark_home)
)

repos_cfg = benchpark.config.configuration().repos

pkg_str = ""
if pkg_manager == "spack":
spack_build_stage = experiments_root / "builds"
Expand All @@ -212,14 +215,18 @@ def include_fn(fname):
site_repos = (
per_workspace_setup.spack_location / "etc" / "spack" / "repos.yaml"
)
repos = {}
for repo_dir in reversed(repos_cfg.packages):
repo_dir = repos_cfg.resolve_path(repo_dir)
with open(repo_dir / "repo.yaml", "r") as f:
repo_data = yaml.safe_load(f)
namespace = repo_data["repo"]["namespace"]
repos[namespace] = str(repo_dir)
repos["builtin"] = (
f"{per_workspace_setup.pkgs_location}/repos/spack_repo/builtin/"
)
with open(site_repos, "w") as f:
f.write(
f"""\
repos::
benchpark: {source_dir}/repo
builtin: {per_workspace_setup.pkgs_location}/repos/spack_repo/builtin/
"""
)
yaml.dump({"repos:": repos}, f, default_flow_style=False)
spack(
f"config --scope=site add \"config:build_stage:['{spack_build_stage}']\""
)
Expand All @@ -232,7 +239,9 @@ def include_fn(fname):

ramble, first_time_ramble = per_workspace_setup.ramble_first_time_setup()
if first_time_ramble:
ramble(f"repo add --scope=site {source_dir}/repo")
for repo_dir in reversed(repos_cfg.applications):
repo_dir = repos_cfg.resolve_path(repo_dir)
ramble(f"repo add --scope=site {repo_dir}")
ramble('config --scope=site add "config:disable_progress_bar:true"')
ramble(f"repo add -t modifiers --scope=site {source_dir}/modifiers")
ramble("config --scope=site add \"config:spack:global:args:'-d'\"")
Expand Down
117 changes: 117 additions & 0 deletions lib/benchpark/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Copyright 2023 Lawrence Livermore National Security, LLC and other
# Benchpark Project Developers. See the top-level COPYRIGHT file for details.
#
# Copyright 2022-2024 The Ramble Authors
#
# SPDX-License-Identifier: Apache-2.0

import pathlib

import benchpark.paths
import yaml


class RequiredClassAttr:
def __init__(self, name):
self.name = name

def __get__(self, obj, owner):
raise NotImplementedError(
f"{owner.__name__} must define class attribute '{self.name}'"
)


class ConfigSection:
def __init__(self, data, path):
self.data = data
self.path = pathlib.Path(path)

filename = RequiredClassAttr("filename")
name = RequiredClassAttr("name")

@classmethod
def try_load(cls, cfg_dir):
cfg_path = pathlib.Path(cfg_dir) / cls.filename
if cfg_path.exists():
with open(cfg_path, "r") as f:
data = yaml.safe_load(f)
return cls(data[cls.name], cfg_path)

def resolve_path(self, value):
path = pathlib.Path(value)
if not path.is_absolute():
return (self.path.parents[0] / path).resolve()


class PropertyDict:
def __getattr__(self, name):
val = self.data[name]
if isinstance(val, dict):
return PropertyDict(val)
return val


class Repos(ConfigSection, PropertyDict):
filename = "repos.yaml"
name = "repos"


_section_types = [Repos]


class Configuration:
section_names = [st.name for st in _section_types]

def __init__(self, cfg_dir):
self.sections = {}
for st in _section_types:
attempt = st.try_load(cfg_dir)
if attempt:
self.sections[st.name] = attempt

def __getattr__(self, name):
if name in self.sections:
return self.sections[name]
elif name in Configuration.section_names:
raise Exception("This section is not present in this config")
else:
raise AttributeError("No such section")


_unset = object()


_user_input_cfg = _unset


def determine_config():
"""
Benchpark configs don't merge or override like Spack/Ramble. You
just point it at a directory and that's where all your config is.
"""
if _user_input_cfg is _unset:
raise Exception("Internal error: config initialization")
elif _user_input_cfg:
if not _user_input_cfg.exists():
raise Exception(f"Specific config dir does not exist: {_user_input_cfg}")
else:
return Configuration(_user_input_cfg)

possible_dirs = [
benchpark.paths.invocation_working_dir / "benchpark-config",
benchpark.paths.benchpark_root / "config",
]
for pd in possible_dirs:
if pd.exists():
return Configuration(pd)


_configuration = None


def configuration():
global _configuration
if not _configuration:
_configuration = determine_config()

return _configuration
2 changes: 2 additions & 0 deletions lib/benchpark/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ def _source_location() -> pathlib.Path:
hardware_descriptions = benchpark_root / "systems" / "all_hardware_descriptions"
checkout_versions = benchpark_root / "checkout-versions.yaml"
remote_urls = benchpark_root / "remote-urls.yaml"

invocation_working_dir = None
32 changes: 12 additions & 20 deletions lib/benchpark/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import sys
from enum import Enum

import benchpark.config
import benchpark.paths

# isort: off
Expand Down Expand Up @@ -74,34 +75,25 @@ def override_ramble_hardcoded_globals():
ramble.language.language_base.namespaces = _old[2]


# Experiments
def _exprs():
"""Get the singleton RepoPath instance for Ramble.

Create a RepoPath, add it to sys.meta_path, and return it.

TODO: consider not making this a singleton.
"""
experiments_repo = benchpark.paths.benchpark_root / "experiments"
return _add_repo(experiments_repo, ObjectTypes.experiments)


def _add_repo(repo_dir, obj_type):
if repo_dir.exists():
repo_dirs = [str(repo_dir)]
else:
raise ValueError(f"Repo dir does not exist: {repo_dir}")
def _add_repo(repo_dirs, obj_type):
repo_dirs = [str(x) for x in repo_dirs]

with override_ramble_hardcoded_globals():
path = ramble.repository.RepoPath(*repo_dirs, object_type=obj_type)
sys.meta_path.append(path)
return path


# Systems
def _exprs():
cfg = benchpark.config.configuration().repos
exp_repos = [cfg.resolve_path(x) for x in cfg.experiments]
return _add_repo(exp_repos, ObjectTypes.experiments)


def _systems():
systems_repo = benchpark.paths.benchpark_root / "systems"
return _add_repo(systems_repo, ObjectTypes.systems)
cfg = benchpark.config.configuration().repos
sys_repos = [cfg.resolve_path(x) for x in cfg.systems]
return _add_repo(sys_repos, ObjectTypes.systems)


paths = {
Expand Down
54 changes: 23 additions & 31 deletions lib/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,23 @@

import argparse
import inspect
import os
import pathlib
import shlex
import subprocess
import sys

import yaml

__version__ = "0.1.0"
if "-V" in sys.argv or "--version" in sys.argv:
print(__version__)
exit()
helpstr = """usage: main.py [-h] [-V] {tags,system,experiment,setup,unit-test,audit,mirror,info,show-build,list,bootstrap,analyze,configure} ...

Benchpark

options:
-h, --help show this help message and exit
-V, --version show version number and exit

Subcommands:
{tags,system,experiment,setup,unit-test,audit,mirror,info,show-build,list,bootstrap,analyze,configure}
tags Tags in Benchpark experiments
system Initialize a system config
experiment Interact with experiments
setup Set up an experiment and prepare it to build/run
unit-test Run benchpark unit tests
audit Look for problems in System/Experiment repos
mirror Copy a benchpark workspace
info Get information about Systems and Experiments
show-build Show how spack built a benchmark
list List experiments, systems, benchmarks, and modifiers
bootstrap Bootstrap benchpark or update an existing bootstrap
analyze Perform pre-defined analysis on the performance data (caliper files) after 'ramble on'
configure Configure options relating to the Benchpark environment
"""
if len(sys.argv) == 1 or "-h" == sys.argv[1] or "--help" == sys.argv[1]:
print(helpstr)
exit()

import benchpark.config
import benchpark.paths # noqa: E402
from benchpark.runtime import RuntimeResources # noqa: E402

if sys.argv[1] == "configure":
# TODO: because this is not integrated as a subcommand, no help is
# auto-generated for it
if len(sys.argv) > 1 and sys.argv[1] == "configure":
import benchpark.cmd.configure # noqa: E402

parser = argparse.ArgumentParser(description="Benchpark")
Expand Down Expand Up @@ -86,13 +61,22 @@


def main():
benchpark.paths.invocation_working_dir = (
pathlib.Path(os.getcwd()).absolute().resolve()
)

if sys.version_info[:2] < (3, 8):
raise Exception("Benchpark requires at least python 3.8+.")

parser = argparse.ArgumentParser(description="Benchpark")
parser.add_argument(
"-V", "--version", action="store_true", help="show version number and exit"
)
parser.add_argument(
"-C",
"--config",
help="use config related to system/experiment/workspace generation",
)

subparsers = parser.add_subparsers(title="Subcommands", dest="subcommand")

Expand All @@ -106,6 +90,14 @@ def main():
if no_args:
parser.print_help()
return 1
if args.version:
print(__version__)
return 0

if args.config:
benchpark.config._user_input_cfg = pathlib.path(args.config)
else:
benchpark.config._user_input_cfg = None

exit_code = 0

Expand Down
Loading