From 0a0225f2e7487a474934a9653b5acb8a67558980 Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Tue, 29 Nov 2022 23:45:27 +0100 Subject: [PATCH 1/3] Control verbosity level of immediate perf. info --- docs/config_reference.rst | 29 ++++++++++++++++++++------ docs/manpage.rst | 13 ++++++++++++ reframe/core/logging.py | 4 ++++ reframe/frontend/cli.py | 7 +++++++ reframe/frontend/executors/policies.py | 12 ++++++----- reframe/schemas/config.json | 2 ++ 6 files changed, 56 insertions(+), 11 deletions(-) diff --git a/docs/config_reference.rst b/docs/config_reference.rst index c3c9054b1c..737555c0ed 100644 --- a/docs/config_reference.rst +++ b/docs/config_reference.rst @@ -17,17 +17,19 @@ The syntax we use in the following to describe the different configuration objec .. |schemas/config.json| replace:: ``reframe/schemas/config.json`` .. _schemas/config.json: https://github.com/reframe-hpc/reframe/blob/master/reframe/schemas/config.json .. |access| replace:: :attr:`access` -.. _access: #.systems[].partitions[].access +.. _access: #systems-.partitions-.access .. |basedir| replace:: :attr:`basedir` -.. _basedir: #.logging[].handlers[].basedir +.. _basedir: #logging-.handlers-.basedir .. |datefmt| replace:: :attr:`datefmt` -.. _datefmt: #.logging[].handlers[].datefmt +.. _datefmt: #logging-.handlers-.datefmt .. |environments| replace:: :attr:`environments` -.. _environments: #.environments +.. _environments: #environments +.. |log_level| replace:: :attr:`level` +.. _log_level: #logging-.level .. |handler_name| replace:: :attr:`name` -.. _handler_name: #.logging[].handlers[].name +.. _handler_name: #logging-.handlers-.name .. |resources| replace:: :attr:`resources` -.. _resources: #.systems[].partitions[].resources +.. _resources: #systems-.partitions-.resources Top-level Configuration @@ -1444,6 +1446,21 @@ General Configuration .. versionadded:: 3.10.0 +.. js:attribute:: .general[].perf_info_level + + :required: No + :default: ``"info"`` + + The log level at which the immediate performance info will be printed. + + As soon as a performance test is finished, ReFrame will log its performance on the standard output immediately. + This option controls at which verbosity level this info will appear. + + For a list of available log levels, refer to logging configuration's |log_level|_. + + .. versionadded:: 4.0.0 + + .. js:attribute:: .general[].remote_detect :required: No diff --git a/docs/manpage.rst b/docs/manpage.rst index 537e6bf0bf..f4dc9bc74b 100644 --- a/docs/manpage.rst +++ b/docs/manpage.rst @@ -1366,6 +1366,19 @@ Here is an alphabetical list of the environment variables recognized by ReFrame: ================================== ================== +.. envvar:: RFM_PERF_INFO_LEVEL + + Logging level at which the immediate performance information is logged. + + .. table:: + :align: left + + ================================== ================== + Associated command line option n/a + Associated configuration parameter :js:attr:`perf_info_level` general configuration parameter + ================================== ================== + + .. envvar:: RFM_PERFLOG_DIR Directory prefix for logging performance data. diff --git a/reframe/core/logging.py b/reframe/core/logging.py index c0a016cafb..8c0cdf115b 100644 --- a/reframe/core/logging.py +++ b/reframe/core/logging.py @@ -65,6 +65,10 @@ } +def level_from_str(name): + return _log_level_values[name] + + def _check_level(level): if isinstance(level, numbers.Integral): ret = level diff --git a/reframe/frontend/cli.py b/reframe/frontend/cli.py index 0aa6a63705..7075228c2c 100644 --- a/reframe/frontend/cli.py +++ b/reframe/frontend/cli.py @@ -604,6 +604,13 @@ def main(): action='store_true', help='Dump progress information for the async execution' ) + argparser.add_argument( + dest='perf_info_level', + envvar='RFM_PERF_INFO_LEVEL', + configvar='general/perf_info_level', + action='store', + help='Log level at which immediate performance info will be printed' + ) argparser.add_argument( dest='pipeline_timeout', envvar='RFM_PIPELINE_TIMEOUT', diff --git a/reframe/frontend/executors/policies.py b/reframe/frontend/executors/policies.py index e0a5a7cbe8..89eec244bd 100644 --- a/reframe/frontend/executors/policies.py +++ b/reframe/frontend/executors/policies.py @@ -14,7 +14,7 @@ SkipTestError, TaskDependencyError, TaskExit) -from reframe.core.logging import getlogger +from reframe.core.logging import getlogger, level_from_str from reframe.core.pipeline import (CompileOnlyRegressionTest, RunOnlyRegressionTest) from reframe.frontend.executors import (ExecutionPolicy, RegressionTask, @@ -43,12 +43,14 @@ def _print_perf(task): '''Get performance info of the current task.''' perfvars = task.testcase.check.perfvalues + level = level_from_str( + rt.runtime().get_option('general/0/perf_info_level') + ) for key, info in perfvars.items(): name = key.split(':')[-1] - getlogger().info( - f'P: {name}: {info[0]} {info[4]} ' - f'(r:{info[1]}, l:{info[2]}, u:{info[3]})' - ) + getlogger().log(level, + f'P: {name}: {info[0]} {info[4]} ' + f'(r:{info[1]}, l:{info[2]}, u:{info[3]})') class _PollController: diff --git a/reframe/schemas/config.json b/reframe/schemas/config.json index 08ef062f66..e5440ceb3f 100644 --- a/reframe/schemas/config.json +++ b/reframe/schemas/config.json @@ -494,6 +494,7 @@ }, "non_default_craype": {"type": "boolean"}, "dump_pipeline_progress": {"type": "boolean"}, + "perf_info_level": {"$ref": "#/defs/loglevel"}, "pipeline_timeout": {"type": ["number", "null"]}, "purge_environment": {"type": "boolean"}, "remote_detect": {"type": "boolean"}, @@ -544,6 +545,7 @@ "general/module_map_file": "", "general/module_mappings": [], "general/non_default_craype": false, + "general/perf_info_level": "info", "general/purge_environment": false, "general/remote_detect": false, "general/remote_workdir": ".", From 18186a0015c963db801baf85665759639e2db9fb Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Tue, 13 Dec 2022 21:24:07 +0100 Subject: [PATCH 2/3] Validate RFM_PERF_INFO_LEVEL environment variable --- reframe/frontend/argparse.py | 18 +++++------------- reframe/frontend/cli.py | 2 ++ reframe/utility/typecheck.py | 3 +++ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/reframe/frontend/argparse.py b/reframe/frontend/argparse.py index 68d4894e65..55f77c51b4 100644 --- a/reframe/frontend/argparse.py +++ b/reframe/frontend/argparse.py @@ -7,6 +7,8 @@ import argparse import os +import reframe.utility.typecheck as typ + # # Notes on the ArgumentParser design # @@ -38,16 +40,6 @@ # arguments, without having to define a corresponding command line option. -def _convert_to_bool(s): - if s.lower() in ('true', 'yes', 'y', '1'): - return True - - if s.lower() in ('false', 'no', 'n', '0'): - return False - - raise ValueError - - class _Namespace: def __init__(self, namespace, option_map): self.__namespace = namespace @@ -94,15 +86,15 @@ def __getattr__(self, name): ret = ret.split(delim) elif action in ('store_true', 'store_false'): try: - ret = _convert_to_bool(ret) - except ValueError: + ret = typ.Bool(ret) + except TypeError: raise ValueError( f'environment variable {envvar!r} not a boolean' ) from None elif action == 'store' and arg_type != str: try: ret = arg_type(ret) - except ValueError as err: + except TypeError as err: raise ValueError( f'cannot convert environment variable {envvar!r} ' f'to {arg_type.__name__!r}' diff --git a/reframe/frontend/cli.py b/reframe/frontend/cli.py index b498d9a7ad..e611b96123 100644 --- a/reframe/frontend/cli.py +++ b/reframe/frontend/cli.py @@ -602,6 +602,8 @@ def main(): envvar='RFM_PERF_INFO_LEVEL', configvar='general/perf_info_level', action='store', + type=typ.Str[r'critical|error|warning|info|verbose|' + r'debug|debug2|undefined'], help='Log level at which immediate performance info will be printed' ) argparser.add_argument( diff --git a/reframe/utility/typecheck.py b/reframe/utility/typecheck.py index 945fbf5305..60bf3e0716 100644 --- a/reframe/utility/typecheck.py +++ b/reframe/utility/typecheck.py @@ -339,6 +339,9 @@ def __getitem__(cls, patt): return ret def __rfm_cast_str__(cls, s): + if not isinstance(s, cls): + raise TypeError(f'cannot convert string {s!r} to {cls.__name__!r}') + return s From 163b78d3f9656d738b60431ab3ae705690cfe7de Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Tue, 6 Dec 2022 23:41:06 +0100 Subject: [PATCH 3/3] Properly set display name of tests with join fixtures --- reframe/core/meta.py | 3 ++- reframe/core/pipeline.py | 5 ++--- unittests/test_fixtures.py | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/reframe/core/meta.py b/reframe/core/meta.py index 1d2aa75afc..4934d9a4da 100644 --- a/reframe/core/meta.py +++ b/reframe/core/meta.py @@ -433,7 +433,8 @@ def __call__(cls, *args, **kwargs): # the init phase varinfo = cls.get_variant_info(variant_num, recurse=True) for fname, finfo in varinfo['fixtures'].items(): - if not isinstance(finfo, tuple): + fixt = cls.fixture_space[fname] + if fixt.action != 'join': setattr(obj, fname, fixtures.FixtureProxy(finfo)) obj.__init__(*args, **kwargs) diff --git a/reframe/core/pipeline.py b/reframe/core/pipeline.py index eb783a21bc..24ff6de1b7 100644 --- a/reframe/core/pipeline.py +++ b/reframe/core/pipeline.py @@ -1146,11 +1146,10 @@ def _format_params(cls, info, prefix=' %'): name += f'{prefix}{p}={format_fn(v)}' for f, v in info['fixtures'].items(): - if isinstance(v, tuple): - # This is join fixture + fixt = cls.fixture_space[f] + if fixt.action == 'join': continue - fixt = cls.fixture_space[f] name += _format_params(fixt.cls, v, f'{prefix}{f}.') # Append any variables set for the fixtures diff --git a/unittests/test_fixtures.py b/unittests/test_fixtures.py index f9160a5ac7..81431ddd5b 100644 --- a/unittests/test_fixtures.py +++ b/unittests/test_fixtures.py @@ -202,7 +202,6 @@ class FooB(rfm.RegressionTest): class Bar(rfm.RegressionTest): f = fixture(FooB, variables={'z': 5}) - w = fixture(FooB, action='join') valid_systems = ['*'] valid_prog_environs = ['*'] @@ -211,7 +210,6 @@ class Bar(rfm.RegressionTest): def early_access(self): assert self.f.foo.x == 1 assert self.f.y == 2 - assert self.w.y == 2 Bar(variant_num=0)