-
Notifications
You must be signed in to change notification settings - Fork 26
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
includes: name mangle ramble and include from spack normally #469
base: develop
Are you sure you want to change the base?
Changes from all commits
4c4155f
23de37b
2b25c2c
f5b3522
65e9100
a49e3c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# 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 argparse | ||
import os | ||
import shutil | ||
import sys | ||
|
||
import benchpark.experiment | ||
import benchpark.spec | ||
|
||
|
||
def init(args): | ||
# Handle conjoined arguments that argparse doesn't separate | ||
specs_str = " ".join(args.specs) | ||
experiment_args, system_args = specs_str.split("--") | ||
|
||
# Parse and concretize system | ||
system_spec = benchpark.spec.SystemSpec(system_args).concretize() | ||
system = system_spec.system | ||
|
||
# Parse and concretize experiments | ||
exp_spec_parser = benchpark.spec.SpecParser( | ||
benchpark.spec.ExperimentSpec, experiment_args | ||
) | ||
experiment_specs = [es.concretize() for es in exp_spec_parser.all_specs()] | ||
experiments = [es.experiment for es in experiment_specs] | ||
|
||
# Create system directory and print out yaml | ||
sysdir = os.path.join(args.basedir, system.system_uid()) | ||
|
||
try: | ||
os.mkdir(sysdir) | ||
system.generate_description(sysdir) | ||
except FileExistsError: | ||
print(f"Abort: system dir already exists ({sysdir})") | ||
sys.exit(1) | ||
except Exception: | ||
# If there was a failure, remove any partially-generated resources | ||
shutil.rmtree(sysdir) | ||
raise | ||
|
||
# For each experiment, create experiment directory and print out yaml | ||
for experiment_spec, experiment in zip(experiment_specs, experiments): | ||
expdir = os.path.join(args.basedir, str(hash(experiment_spec))) | ||
|
||
try: | ||
os.mkdir(expdir) | ||
experiment.write_ramble_dict(f"{expdir}/ramble.yaml") | ||
except FileExistsError: | ||
print(f"Abort: workload dir already exists ({expdir})") | ||
sys.exit(1) | ||
except Exception: | ||
# If there was a failure, remove any partially-generated resources | ||
shutil.rmtree(expdir) | ||
raise | ||
|
||
|
||
def setup_parser(parser): | ||
parser.add_argument( | ||
"--basedir", | ||
required=True, | ||
help="Generate a system dir under this, and place all files there", | ||
) | ||
|
||
parser.add_argument( | ||
"specs", | ||
nargs=argparse.REMAINDER, | ||
metavar="experiment_spec(s) -- system_spec", | ||
help="Experiment spec(s) and system spec", | ||
) | ||
|
||
|
||
def command(args): | ||
init(args) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
import os | ||
import pathlib | ||
import shlex | ||
import stat | ||
import subprocess | ||
import sys | ||
|
||
|
@@ -82,21 +83,52 @@ def __init__(self, dest): | |
self.spack_location = self.dest / "spack" | ||
|
||
def bootstrap(self): | ||
# Bootstrap Spack first because we will use Spack resources while bootstrapping ramble | ||
if not self.spack_location.exists(): | ||
self._install_spack() | ||
|
||
spack_lib_path = self.spack_location / "lib" / "spack" | ||
externals = str(spack_lib_path / "external") | ||
if externals not in sys.path: | ||
sys.path.insert(1, externals) | ||
internals = str(spack_lib_path) | ||
if internals not in sys.path: | ||
sys.path.insert(1, internals) | ||
|
||
if not self.ramble_location.exists(): | ||
self._install_ramble() | ||
|
||
ramble_lib_path = self.ramble_location / "lib" / "ramble" | ||
|
||
# If ramble is present but not yet name mangled, do that | ||
ramble_spack_path = ramble_lib_path / "ramble_spack" | ||
if not ramble_spack_path.exists(): | ||
self._mangle_ramble() | ||
|
||
externals = str(ramble_lib_path / "external") | ||
if externals not in sys.path: | ||
sys.path.insert(1, externals) | ||
internals = str(ramble_lib_path) | ||
if internals not in sys.path: | ||
sys.path.insert(1, internals) | ||
|
||
# Spack does not go in sys.path, but we will manually access modules from it | ||
# The reason for this oddity is that spack modules will compete with the internal | ||
# spack modules from ramble | ||
if not self.spack_location.exists(): | ||
self._install_spack() | ||
def _mangle_ramble(self): | ||
"""Name mangle ramble spack.* symbols to allow separate spack imports.""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a bit of detail: mention we are replacing all instances of Might be worth broadly outlining why this is expected to work: I don't think this name mangling would make all parts of Spack work, but I believe they make all the parts of Spack that Ramble uses work. |
||
import llnl.util.filesystem as fs | ||
|
||
files = [ | ||
f | ||
for f in fs.find(self.ramble_location, "*") | ||
if os.stat(f).st_mode & stat.S_IWUSR and not os.path.isdir(f) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't own these files, we should probably fail, vs. silently doing nothing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add a comment -- the main purpose here isn't to catch files we don't own, it's to catch files that aren't writable (like some things within the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume nothing under |
||
] | ||
file_filter = fs.FileFilter(*files) | ||
# Don't replace if it's already replaced or if it's a field in an existing module | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think trying to make these regexes idempotent will make them more confusing than they need to be: the existence of the Either way, I think this will work as long as:
But IMO it would be more straightforward to look for I think including some examples of things you intend not to match would be useful (e.g. |
||
file_filter.filter(r"(?<!_|\.)spack\.", "ramble_spack.") | ||
file_filter.filter(r"(?<!_)llnl\.", "ramble_llnl.") | ||
|
||
ramble_lib_path = self.ramble_location / "lib" / "ramble" | ||
os.rename(ramble_lib_path / "spack", ramble_lib_path / "ramble_spack") | ||
os.rename(ramble_lib_path / "llnl", ramble_lib_path / "ramble_llnl") | ||
|
||
def _install_ramble(self): | ||
print(f"Cloning Ramble to {self.ramble_location}") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think ideally we would conceptually distinguish the case where we clone ramble as a library vs. when we clone it to run it.
_install_ramble
can be called frombootstrap()
or.ramble()
(viaramble_first_time_setup
)RuntimeResources
object, and move this consideration to_install_ramble()
_install_ramble
to reflect that it can update existing installations (i.e. so that this works for users that do agit pull
of Benchpark with an already-established Ramble lib prefix