Skip to content

Commit

Permalink
Merge pull request #387 from douglasjacobsen/experiment_tags
Browse files Browse the repository at this point in the history
Add support for workload and experiment tagging
  • Loading branch information
rfbgo authored Feb 1, 2024
2 parents 7de891d + 3724d02 commit 38f92af
Show file tree
Hide file tree
Showing 20 changed files with 398 additions and 54 deletions.
18 changes: 14 additions & 4 deletions lib/ramble/docs/workspace.rst
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,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 @@ -267,6 +268,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 @@ -279,6 +288,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 @@ -610,6 +610,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 @@ -1420,6 +1455,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)
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

0 comments on commit 38f92af

Please sign in to comment.