Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command: benchpark system init #298

Merged
merged 109 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 100 commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
7af34c3
init lib code
scheibelp Jun 3, 2024
a1f4a6e
reorg of command logic into lib
scheibelp Jun 3, 2024
15fd38e
add benchpark bootstrapping script
scheibelp Jun 3, 2024
a2ee214
proper redirection to subcommand function
scheibelp Jun 4, 2024
5e7fbd2
initial infrastructure for system type
scheibelp Jun 4, 2024
756d3df
fixing various reference errors, now generating system description (j…
scheibelp Jun 4, 2024
6fa7f87
style edits
scheibelp Jun 5, 2024
c542254
add license
scheibelp Jun 5, 2024
2d9d275
style edit
scheibelp Jun 5, 2024
992d7b6
flake issues
scheibelp Jun 5, 2024
1f99380
merge from develop (conflicts)
scheibelp Jun 22, 2024
12db9bd
port over changes from 288/195
scheibelp Jun 22, 2024
630f972
partial work including unifying mechanism to pull in a new ramble/spack
scheibelp Jun 24, 2024
3149640
partial scaffolding for assembling external system config
scheibelp Jun 25, 2024
27439e7
more intermediate work
scheibelp Jun 25, 2024
ea6d954
added spack-python script to merge spack config yaml files
scheibelp Jun 25, 2024
bbf2aa9
add tioga system
scheibelp Jun 25, 2024
65d2634
fix some minor errors
scheibelp Jun 25, 2024
84bd8bd
reorg works w/ AWS again
scheibelp Jun 25, 2024
f466fb4
fill in tioga system attributes
scheibelp Jun 25, 2024
296e0e1
various small bug fixes
scheibelp Jun 25, 2024
004af95
bootstrap to import ramble objects
becker33 Jul 9, 2024
776eca7
reuse resources downloaded for bootstrap if commits match
becker33 Jul 9, 2024
c9e3f9f
Revert "reuse resources downloaded for bootstrap if commits match"
becker33 Jul 9, 2024
07327fc
initial prototype of ExperimentSpec class
becker33 Jun 24, 2024
5cc6ad5
Initial commit of experiment and ramble's repo lib
alecbcs Jun 25, 2024
8c3e914
Add benchpark-python as wrapper for python with PYTHONPATH
alecbcs Jun 25, 2024
921fe98
finish implementation of ExperimentSpec with parsing
becker33 Jun 25, 2024
ba99050
rename repository.py to repo.py
alecbcs Jun 25, 2024
7dc8b24
fixed all import errors for ExperimentSpec
becker33 Jun 25, 2024
77432de
checkpoint debugging of interface between specs and objects
becker33 Jun 25, 2024
021ffdb
checkpoint debugging of interface between specs and objects - loader …
becker33 Jun 25, 2024
544c8d7
checkpoint: got loader working
becker33 Jun 25, 2024
a0ae5e8
checkpoint: up to conretizing
becker33 Jun 25, 2024
26da77c
checkpoint: concretization fails for bad variant values
becker33 Jun 25, 2024
12adbcb
remove debug prints and improve error message
becker33 Jun 25, 2024
07e81b6
make variant directive and concretizer work together
becker33 Jun 26, 2024
eff2517
add example experiment in test_repo
becker33 Jun 26, 2024
c0b4848
first draft saxpy and experiment lifecycle methods
becker33 Jun 26, 2024
fe98421
add missing file from 6139e77
becker33 Jul 1, 2024
04c1245
do not blow away python path
becker33 Jul 8, 2024
6fedb60
Switch to ramble based experiment directive system
alecbcs Jul 18, 2024
08e5ae1
Spec: separate Spec from ExperimentSpec to support future SystemSpec
becker33 Jul 19, 2024
2202769
Add bootstrap import call to experiment.py
alecbcs Jul 19, 2024
7245fe0
remove extraneous file
becker33 Jul 19, 2024
2e50934
Remove code now that we can import from ramble (#311)
becker33 Jul 26, 2024
39ff801
partial merge, need to reapply #276
scheibelp Jul 26, 2024
866f5ba
reapply #276 on moved bin/benchpark logic
scheibelp Jul 26, 2024
3358ebd
style edit
scheibelp Jul 26, 2024
88d7713
fix bugs with benchpark setup
scheibelp Jul 26, 2024
0c79bc2
need to refer to spack/ramble via setup object
scheibelp Jul 26, 2024
32c896c
exclude benchpark-python from black formatting
scheibelp Jul 26, 2024
d1bf8b6
seems like the include was overriding the exclude
scheibelp Jul 26, 2024
2ab3c49
address style checker complaints, which detected a couple semantic er…
scheibelp Jul 26, 2024
ad8740d
bootstrap calls must occur before imports
scheibelp Jul 26, 2024
9b72782
use extend-exclude to override include in style checker
scheibelp Jul 26, 2024
29594e2
syntax error
scheibelp Jul 26, 2024
95ed586
exclude .github from formatting
scheibelp Jul 26, 2024
2ad268e
style checker include pattern tweak
scheibelp Jul 26, 2024
4c725a2
more style checker tweaks
scheibelp Jul 26, 2024
0e0fde6
minor style edit
scheibelp Jul 26, 2024
2611700
ignore/exclude-pattern tweaks
scheibelp Jul 26, 2024
ff0f73c
isort exclude tweaks
scheibelp Jul 26, 2024
243fd04
try completely skipping isort to see if that's even the problem
scheibelp Jul 26, 2024
dfe04ac
mess with actual running of checks
scheibelp Jul 26, 2024
40baeec
add back isort
scheibelp Jul 26, 2024
a8dccb5
add flake back; try to appease it
scheibelp Jul 26, 2024
b6c60a6
exclude test_repo from flake
scheibelp Jul 26, 2024
ca6e09f
flake thinks it's pretty funny
scheibelp Jul 27, 2024
c1673b5
more exclude pattern meddling
scheibelp Jul 27, 2024
7853b34
exclude pattern meddling part two
scheibelp Jul 27, 2024
062bda3
exclude pattern meddling part three
scheibelp Jul 27, 2024
0ed73d8
exclude pattern meddling part four
scheibelp Jul 27, 2024
e044b2d
exclude pattern meddling part five
scheibelp Jul 27, 2024
c907803
exclude pattern meddling part six
scheibelp Jul 27, 2024
b4448ba
more exclude filter tweaks
scheibelp Jul 27, 2024
fc774be
pass exclusion directly to flake invocation
scheibelp Jul 27, 2024
64d0f05
last change worked but started including repo, which was weird; maybe…
scheibelp Jul 27, 2024
c899c25
partial work on reorg of system into repo-based object
scheibelp Jul 29, 2024
e1b76a4
partial rework of system as obj
scheibelp Jul 29, 2024
35ac143
restructure repo dir hierarchy for systems (was wrong)
scheibelp Jul 29, 2024
2146de9
clean up generated dir if operation fails; remove commented code
scheibelp Jul 30, 2024
64625f5
__file__ is not available on imported modules; directly assign a clas…
scheibelp Jul 30, 2024
a2a703e
improve error handling for existing dir
scheibelp Jul 30, 2024
6418429
auto-gen compilers description
scheibelp Jul 30, 2024
63e5d9f
generate software description
scheibelp Jul 31, 2024
00b6849
allow 'benchpark setup' to use config dir created by 'benchpark syste…
scheibelp Aug 1, 2024
49f1dfc
intermediate work creating a system spec
scheibelp Aug 2, 2024
f7f04cd
directives for system were not being executed until I updated the nam…
scheibelp Aug 3, 2024
62ff50d
resolve a couple reference issues w/ refactor of system
scheibelp Aug 3, 2024
1180630
incomplete transition of tioga system to spec-based
scheibelp Aug 3, 2024
48862b3
generate compilers w/ new approach, mostly finish external packages
scheibelp Aug 4, 2024
6651080
explain why example doesnt blend in rocm 551 components
scheibelp Aug 4, 2024
9b9f526
Update lib/benchpark/test_repo/experiments/saxpy/experiment.py
becker33 Aug 5, 2024
2162f5e
add support for rocm 5.5.1 on Tioga
scheibelp Aug 6, 2024
b3440d2
refactor w/ new abstract method to eliminate redundancy
scheibelp Aug 6, 2024
5ed2335
partial refactor: move directive functionality into metaclass that is…
scheibelp Aug 7, 2024
0487dc8
completed refactor for shared directive logic between experiment and …
scheibelp Aug 7, 2024
510509c
style fixes
scheibelp Aug 8, 2024
601fcd2
remove unused imports
scheibelp Aug 8, 2024
463f7fa
cleanup for review
scheibelp Aug 13, 2024
5c50da9
move system/experiment repos into var
scheibelp Aug 13, 2024
ed8f832
move imports after bootstrap
scheibelp Aug 13, 2024
5d5b991
is now
scheibelp Aug 13, 2024
e52ebca
style fixes
scheibelp Aug 14, 2024
f6b32d8
remove references to 'package' (a spack term: System/Experiment are a…
scheibelp Aug 14, 2024
e0eebde
rename SpecTemplate
scheibelp Aug 19, 2024
0494f81
move system_cmd to its own cmd dir
scheibelp Aug 19, 2024
3d23829
Merge branch 'develop' into features/system-create2
pearce8 Aug 20, 2024
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
538 changes: 4 additions & 534 deletions bin/benchpark

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions bin/benchpark-python
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/sh
#
# 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

#
# benchpark-python
#
# If you want to write your own executable Python script that uses Benchpark
# modules, on Mac OS or maybe some others, you may be able to do it like
# this:
#
# #!/usr/bin/env benchpark-python
#
# This is compatible across platforms.
#
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
export PYTHONPATH="${SCRIPT_DIR}/../lib":$PYTHONPATH
exec python3 -i "$@"
Empty file added lib/benchpark/__init__.py
Empty file.
203 changes: 203 additions & 0 deletions lib/benchpark/directives.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# 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

import collections.abc
import inspect
import os
import re
from typing import Any, Callable, Optional, Tuple, Union

import benchpark.spec
import benchpark.paths
import benchpark.repo
import benchpark.runtime
import benchpark.variant

import ramble.language.language_base
import ramble.language.language_helpers
import ramble.language.shared_language
from ramble.language.language_base import DirectiveError


# TODO remove this when it is added to ramble.lang (when ramble updates from spack
class classproperty:
"""Non-data descriptor to evaluate a class-level property. The function that performs
the evaluation is injected at creation time and take an instance (could be None) and
an owner (i.e. the class that originated the instance)
"""

def __init__(self, callback):
self.callback = callback

def __get__(self, instance, owner):
return self.callback(owner)


class DirectiveMeta(ramble.language.shared_language.SharedMeta):
"""
metaclass for supporting directives (e.g., depends_on) and phases
"""

_directive_names = set()
_directives_to_be_executed = []

# Hack to be able to use SharedMeta outside of Ramble
# will ask Ramble to implement fix on their end and then we can remove this
def __init__(self, *args, **kwargs):
with benchpark.repo.override_ramble_hardcoded_globals():
super(DirectiveMeta, self).__init__(*args, **kwargs)


benchpark_directive = DirectiveMeta.directive


@benchpark_directive("variants")
def variant(
name: str,
default: Optional[Any] = None,
description: str = "",
values: Optional[Union[collections.abc.Sequence, Callable[[Any], bool]]] = None,
multi: Optional[bool] = None,
validator: Optional[Callable[[str, str, Tuple[Any, ...]], None]] = None,
when: Optional[Union[str, bool]] = None,
sticky: bool = False,
):
"""Define a variant.
Can specify a default value as well as a text description.
Args:
name: Name of the variant
default: Default value for the variant, if not specified otherwise the default will be
False for a boolean variant and 'nothing' for a multi-valued variant
description: Description of the purpose of the variant
values: Either a tuple of strings containing the allowed values, or a callable accepting
one value and returning True if it is valid
multi: If False only one value per spec is allowed for this variant
validator: Optional group validator to enforce additional logic. It receives the experiment
name, the variant name and a tuple of values and should raise an instance of BenchparkError
if the group doesn't meet the additional constraints
when: Optional condition on which the variant applies
sticky: The variant should not be changed by the concretizer to find a valid concrete spec
Raises:
DirectiveError: If arguments passed to the directive are invalid
"""

def format_error(msg, pkg):
msg += " @*r{{[{0}, variant '{1}']}}"
return msg.format(pkg.name, name)

def _always_true(_x):
return True

# Ensure we have a sequence of allowed variant values, or a
# predicate for it.
if values is None:
if str(default).upper() in ("TRUE", "FALSE"):
values = (True, False)
else:
values = _always_true

# The object defining variant values might supply its own defaults for
# all the other arguments. Ensure we have no conflicting definitions
# in place.
for argument in ("default", "multi", "validator"):
# TODO: we can consider treating 'default' differently from other
# TODO: attributes and let a packager decide whether to use the fluent
# TODO: interface or the directive argument
if hasattr(values, argument) and locals()[argument] is not None:

def _raise_argument_error(pkg):
msg = (
"Remove specification of {0} argument: it is handled "
"by an attribute of the 'values' argument"
)
raise DirectiveError(format_error(msg.format(argument), pkg))

return _raise_argument_error

# Allow for the object defining the allowed values to supply its own
# default value and group validator, say if it supports multiple values.
default = getattr(values, "default", default)
validator = getattr(values, "validator", validator)
multi = getattr(values, "multi", bool(multi))

# Here we sanitize against a default value being either None
# or the empty string, as the former indicates that a default
# was not set while the latter will make the variant unparsable
# from the command line
if default is None or default == "":

def _raise_default_not_set(pkg):
if default is None:
msg = "either a default was not explicitly set, or 'None' was used"
elif default == "":
msg = "the default cannot be an empty string"
raise DirectiveError(format_error(msg, pkg))

return _raise_default_not_set

description = str(description).strip()

def _execute_variant(pkg):
if not re.match(benchpark.spec.IDENTIFIER, name):
directive = "variant"
msg = "Invalid variant name in {0}: '{1}'"
raise DirectiveError(directive, msg.format(pkg.name, name))

pkg.variants[name] = benchpark.variant.Variant(
name, default, description, values, multi, validator, sticky
)

return _execute_variant


class SpecTemplate(metaclass=DirectiveMeta):
scheibelp marked this conversation as resolved.
Show resolved Hide resolved
scheibelp marked this conversation as resolved.
Show resolved Hide resolved
@classproperty
def package_dir(cls):
becker33 marked this conversation as resolved.
Show resolved Hide resolved
"""Directory where the package.py file lives."""
return os.path.abspath(os.path.dirname(cls.module.__file__))

@classproperty
def module(cls):
"""Module object (not just the name) that this package is defined in.
We use this to add variables to package modules. This makes
install() methods easier to write (e.g., can call configure())
"""
return __import__(cls.__module__, fromlist=[cls.__name__])

@classproperty
def namespace(cls):
"""Spack namespace for the package, which identifies its repo."""
parts = cls.__module__.split(".")
return ".".join(parts[2:-1])

@classproperty
def fullname(cls):
"""Name of this package, including the namespace"""
return f"{cls.namespace}.{cls.name}"

@classproperty
def fullnames(cls):
"""Fullnames for this package and any packages from which it inherits."""
fullnames = []
for cls in inspect.getmro(cls):
namespace = getattr(cls, "namespace", None)
if namespace:
fullnames.append(f"{namespace}.{cls.name}")
if namespace == "builtin":
# builtin packages cannot inherit from other repos
break
return fullnames

@classproperty
def name(cls):
"""The name of this package.
The name of a package is the name of its Python module, without
the containing module names.
"""
if cls._name is None:
cls._name = cls.module.__name__
if "." in cls._name:
cls._name = cls._name[cls._name.rindex(".") + 1 :]
return cls._name
81 changes: 81 additions & 0 deletions lib/benchpark/error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# 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

import inspect
import sys

#: at what level we should write stack traces or short error messages
#: this is module-scoped because it needs to be set very early
debug = 0


class BenchparkError(Exception):
scheibelp marked this conversation as resolved.
Show resolved Hide resolved
"""This is the superclass for all Benchpark errors.
Subclasses can be found in the modules they have to do with.
"""

def __init__(self, message, long_message=None):
super().__init__()
self.message = message
self._long_message = long_message

# for exceptions raised from child build processes, we save the
# traceback as a string and print it in the parent.
self.traceback = None

# we allow exceptions to print debug info via print_context()
# before they are caught at the top level. If they *haven't*
# printed context early, we do it by default when die() is
# called, so we need to remember whether it's been called.
self.printed = False

@property
def long_message(self):
return self._long_message

def print_context(self):
"""Print extended debug information about this exception.

This is usually printed when the top-level Spack error handler
calls ``die()``, but it can be called separately beforehand if a
lower-level error handler needs to print error context and
continue without raising the exception to the top level.
"""
if self.printed:
return

# basic debug message
if self.long_message:
sys.stderr.write(self.long_message)
sys.stderr.write("\n")

# stack trace, etc. in debug mode.
if debug:
if self.traceback:
# exception came from a build child, already got
# traceback in child, so print it.
sys.stderr.write(self.traceback)
else:
# run parent exception hook.
sys.excepthook(*sys.exc_info())

sys.stderr.flush()
self.printed = True

def die(self):
self.print_context()
sys.exit(1)

def __str__(self):
msg = self.message
if self._long_message:
msg += "\n %s" % self._long_message
return msg

def __repr__(self):
args = [repr(self.message), repr(self.long_message)]
args = ",".join(args)
qualified_name = inspect.getmodule(self).__name__ + "." + type(self).__name__
return qualified_name + "(" + args + ")"
Loading
Loading