Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
bf91426
refactoring option handling
scheibelp Jan 15, 2026
c352e6d
reorg code (no logic change)
scheibelp Jan 15, 2026
3f2b828
help str is auto generated
scheibelp Jan 15, 2026
56811de
update help and add todo
scheibelp Jan 15, 2026
a1872be
initial config logic
scheibelp Jan 15, 2026
a8f198d
config construction
scheibelp Jan 15, 2026
8826abb
config construction
scheibelp Jan 15, 2026
62edf96
plumb config into repos (not working yet)
scheibelp Jan 15, 2026
4ad65e7
plumb config into repos (not working yet)
scheibelp Jan 15, 2026
6aebdd1
ref errors
scheibelp Jan 15, 2026
6a7463b
add default repo config
scheibelp Jan 15, 2026
25e2eb6
move saxpy into separate repo to demonstrate support for multiple exp…
scheibelp Jan 15, 2026
7530e44
use benchpark config to determine ramble applicatinos and extra spack…
scheibelp Jan 16, 2026
2e0508c
style format
scheibelp Jan 16, 2026
278c157
Merge branch 'develop' into custom-repos
scheibelp Jan 16, 2026
a7bced6
forgot test repo yaml descriptor
scheibelp Jan 16, 2026
2d23644
import formatting
scheibelp Jan 16, 2026
b1714b9
add license
scheibelp Jan 16, 2026
9e1459e
imports and license
scheibelp Jan 20, 2026
030f803
yamlfix
scheibelp Jan 20, 2026
dffe3d6
license
scheibelp Jan 21, 2026
4f0c6bb
restore help generation interrupting import order
scheibelp Jan 21, 2026
bbd528f
restore check
scheibelp Jan 21, 2026
23e4140
allow configure command to interact with config system (and integrate…
scheibelp Jan 21, 2026
5aeec3e
missing files from last commit
scheibelp Jan 21, 2026
8e2cf16
fix issue w/ configure
scheibelp Jan 21, 2026
ec1d116
only append .benchpark to config name if not user-specified
scheibelp Jan 21, 2026
43d626c
auto style
scheibelp Jan 21, 2026
e16e809
better checking of config
scheibelp Jan 21, 2026
1aafb22
fix some bugs
scheibelp Jan 21, 2026
e5d7099
restore prior handling of version option
scheibelp Jan 21, 2026
9ee1581
add license to config
scheibelp Jan 21, 2026
12a3f35
update ci check given that you have to name all subdir components whe…
scheibelp Jan 21, 2026
0cbd10f
update imports
scheibelp Jan 21, 2026
c6b8bdb
I messed up the system info command
scheibelp Jan 21, 2026
2478795
scripts outside of main can now import accounting
scheibelp Jan 22, 2026
dbb1054
merge from develop
scheibelp Jan 22, 2026
2ed35fd
docs review comments
scheibelp Jan 23, 2026
2e7bf29
add docs
scheibelp Jan 23, 2026
1cb11c9
mention benchpark configure in config docs section
scheibelp Jan 23, 2026
3d92e15
auto style
scheibelp Jan 23, 2026
68b9218
Merge branch 'develop' into custom-repos
scheibelp Jan 23, 2026
bf315e7
merge from develop (minor conflicts)
scheibelp Jan 26, 2026
995d9bc
update docs according to review
scheibelp Jan 26, 2026
8b34b3a
docstrfmt
scheibelp Jan 27, 2026
a7fa807
docstrfmt wants to edit the license...
scheibelp Jan 27, 2026
5f2e26e
update docs for configure command based on review
scheibelp Jan 27, 2026
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
5 changes: 5 additions & 0 deletions config/repos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
repos:
experiments: [../experiments, ../experiments/test]
systems: [../systems]
applications: [../repo]
packages: [../repo]
7 changes: 7 additions & 0 deletions experiments/test/repo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2023 Lawrence Livermore National Security, LLC and other
# Benchpark Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: Apache-2.0
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
118 changes: 118 additions & 0 deletions lib/benchpark/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# 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 yaml

import benchpark.paths


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