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 support for workload and experiment tagging #387

Merged
merged 6 commits into from
Feb 1, 2024
Merged
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
18 changes: 14 additions & 4 deletions lib/ramble/docs/workspace.rst
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,11 @@ Filtering Experiments

Several of the workspace commands support filtering the experiments they should
act on. This can be performed using the ``--where`` argument for inclusive
filtering, or the ``--exclude-where`` argument for exclusive filtering. These
arguments take a string representing a logical expression, which can use
variables the experiment would define. If the logical expression evaluates to
true, the experiment will be included or excluded for action (respectively).
filtering, the ``--exclude-where`` argument for exclusive filtering, or the
``--filter-tags`` argument to filter based on experiment tags.. These arguments
take a string representing a logical expression, which can use variables the
experiment would define. If the logical expression evaluates to true, the
experiment will be included or excluded for action (respectively).

As an example:

Expand All @@ -236,6 +237,14 @@ Will only setup experiments that have less than 500 ranks, and:

Will exclude all experiments from the ``hostname`` application.

To filter by tags, see the following example:

.. code-block:: console

$ ramble workspace setup --filter-tags my-tag

Will only setup experiments that have the ``my-tag`` on them.

The commands that accept these filters are:

.. code-block:: console
Expand All @@ -248,6 +257,7 @@ The commands that accept these filters are:

**NOTE:** The exclusive filter takes precedence over the inclusive filter.


^^^^^^^^^^^^^^^^^^^^^
Software Environments
^^^^^^^^^^^^^^^^^^^^^
Expand Down
49 changes: 49 additions & 0 deletions lib/ramble/docs/workspace_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,55 @@ If the ``on_executable`` attribute is not set, it will default to ``'*'`` which
will match all executables. Modifier classes can (and should) be implemented to
only act on the correct executable types (i.e. executables with ``use_mpi=true``).

.. _experiment_tags:

^^^^^^^^^^^^^^^
Experiment Tags
^^^^^^^^^^^^^^^

While applications and workloads can be tagged within an application definition
file (using the ``tags()`` or ``workload()`` directives), workloads and
experiments can also be tagged within a workspace configuration file. This
allows users to define their own tags to communicate what an experiment and
workload might be used for beyond the information captured in the application
definition file.

The below example shows how tags can be defined within a workspace:

.. code-block:: yaml

ramble:
variables:
mpi_command: 'mpirun -n {n_ranks}'
batch_submit: '{execute_experiment}'
processes_per_node: '16'
applications:
gromacs:
workloads:
water_bare:
tags:
- wltag
experiments:
test_exp1:
tags:
- tag1
variables:
n_ranks: '1'
test_exp2:
tags:
- tag2
variables:
n_ranks: '1'


In the above example, all experiments are tagged with the ``wltag`` tag. Only
the ``test_exp1`` experiment is tagged with the ``tag1`` tag, while the
``test_exp2`` experiment is tagged with the ``tag2`` tag.

These tags are propagated into a workspace's results file, and can be used to
filter pipeline commands, as show in the
:ref:`filtering experiments documentation <filter-experiments>`.

.. _workspace_internals:

^^^^^^^^^^^^^^^^^^^^^^
Expand Down
36 changes: 36 additions & 0 deletions lib/ramble/ramble/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def __init__(self, file_path):
self.chain_commands = {}
self._env_variable_sets = None
self.modifiers = []
self.experiment_tags = []
self._modifier_instances = []
self._modifier_builtins = {}
self._input_fetchers = None
Expand Down Expand Up @@ -307,6 +308,9 @@ def _long_print(self):
f'{wl_conf["executables"]}\n')
out_str.append('\t' + rucolor.nested_1('Inputs: ') +
f'{wl_conf["inputs"]}\n')
out_str.append('\t' + rucolor.nested_1('Workload Tags: \n'))
if 'tags' in wl_conf and wl_conf['tags']:
out_str.append(colified(wl_conf['tags'], indent=8) + '\n')

if wl_name in self.workload_variables:
out_str.append(rucolor.nested_1('\tVariables:\n'))
Expand Down Expand Up @@ -370,6 +374,37 @@ def set_modifiers(self, modifiers):
if modifiers:
self.modifiers = modifiers.copy()

def set_tags(self, tags):
"""Set experiment tags for this instance"""

self.experiment_tags = self.tags.copy()

workload_name = self.expander.workload_name
self.experiment_tags.extend(self.workloads[workload_name]['tags'])

if tags:
self.experiment_tags.extend(tags)

def has_tags(self, tags):
"""Check if this instance has provided tags.

Args:
tags (list): List of strings, where each string is an indivudal tag
Returns:
(bool): True if all tags are in this instance, False otherwise
"""

if tags and self.experiment_tags:
tag_set = set(tags)
exp_tag_set = set(self.experiment_tags)

for tag in tag_set:
if tag not in exp_tag_set:
return False
return True

return False

def experiment_log_file(self, logs_dir):
"""Returns an experiment log file path for the given logs directory"""
return os.path.join(
Expand Down Expand Up @@ -1411,6 +1446,7 @@ def format_context(context_match, context_format):
results['RAMBLE_STATUS'] = self.get_status()

if success or workspace.always_print_foms:
results['TAGS'] = list(self.experiment_tags)
rfbgo marked this conversation as resolved.
Show resolved Hide resolved
results['RAMBLE_VARIABLES'] = {}
results['RAMBLE_RAW_VARIABLES'] = {}
for var, val in self.variables.items():
Expand Down
10 changes: 10 additions & 0 deletions lib/ramble/ramble/cmd/common/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@ def exclude_where():
)


@arg
def filter_tags():
return Args(
'--filter-tags', action='append',
nargs='+',
help='filter experiments to only those that include the provided tags',
required=False
)


@arg
def no_checksum():
return Args(
Expand Down
5 changes: 3 additions & 2 deletions lib/ramble/ramble/cmd/on.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def setup_parser(subparser):
help='execution template for each experiment',
required=False)

arguments.add_common_arguments(subparser, ['where', 'exclude_where'])
arguments.add_common_arguments(subparser, ['where', 'exclude_where', 'filter_tags'])


def ramble_on(args):
Expand All @@ -44,7 +44,8 @@ def ramble_on(args):
filters = ramble.filters.Filters(
phase_filters=[],
include_where_filters=args.where,
exclude_where_filters=args.exclude_where
exclude_where_filters=args.exclude_where,
tags=args.filter_tags
)

pipeline_cls = ramble.pipeline.pipeline_class(current_pipeline)
Expand Down
Loading
Loading