Skip to content
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
7 changes: 6 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@ repos:
hooks:
# Run isort to check only (don't modify files)
- id: isort
args: [ --check-only ]
args: [--check-only, --filter-files]
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.4
hooks:
# Run the linter to check only (don't modify files)
- id: ruff-check
- repo: https://github.com/PyCQA/flake8
rev: 7.3.0
hooks:
- id: flake8
additional_dependencies: [flake8-pyproject]
- repo: https://github.com/crate-ci/typos
rev: v1.39.1
hooks:
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/regression/benchmarks/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class Processing:
def setup(self):
grid = Grid(shape=(5, 5, 5))

funcs = [Function(name='f%d' % n, grid=grid) for n in range(30)]
tfuncs = [TimeFunction(name='u%d' % n, grid=grid) for n in range(30)]
stfuncs = [SparseTimeFunction(name='su%d' % n, grid=grid, npoint=1, nt=100)
funcs = [Function(name=f'f{n}', grid=grid) for n in range(30)]
tfuncs = [TimeFunction(name=f'u{n}', grid=grid) for n in range(30)]
stfuncs = [SparseTimeFunction(name=f'su{n}', grid=grid, npoint=1, nt=100)
for n in range(30)]
v = TimeFunction(name='v', grid=grid, space_order=2)

Expand Down
8 changes: 4 additions & 4 deletions benchmarks/user/advisor/advisor_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ def check(cond, msg):


def err(msg):
print('\033[1;37;31m%s\033[0m' % msg) # print in RED
print(f'\033[1;37;31m{msg}\033[0m') # print in RED


def log(msg):
print('\033[1;37;32m%s\033[0m' % msg) # print in GREEN
print(f'\033[1;37;32m{msg}\033[0m') # print in GREEN


@contextmanager
def progress(msg):
print('\033[1;37;32m%s ... \033[0m' % msg, end='', flush=True) # print in GREEN
print(f'\033[1;37;32m{msg} ... \033[0m', end='', flush=True) # print in GREEN
yield
print('\033[1;37;32m%s\033[0m' % 'Done!')
print('\033[1;37;32m{}\033[0m'.format('Done!'))


def log_process(process, logger):
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/user/advisor/roofline.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def roofline(name, project, scale, precision, mode, th):
log(f'\nFigure saved in {figpath}{name}.pdf.')

# Save the JSON file
with open('%s.json' % name, 'w') as f:
with open(f'{name}.json', 'w') as f:
f.write(json.dumps(roofline_data))

log(f'\nJSON file saved as {name}.json.')
Expand Down
7 changes: 3 additions & 4 deletions benchmarks/user/advisor/run_advisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,16 @@ def run_with_advisor(path, output, name, exec_args):
# Before collecting the `survey` and `tripcounts` a "pure" python run
# to warmup the jit cache is preceded

log('Starting Intel Advisor\'s `roofline` analysis for `%s`' % name)
log(f'Starting Intel Advisor\'s `roofline` analysis for `{name}`')
dt = datetime.datetime.now()

# Set up a file logger that will track the output of the advisor profiling
advixe_logger = logging.getLogger('run_advisor_logger')
advixe_logger.setLevel(logging.INFO)

advixe_formatter = logging.Formatter('%(asctime)s: %(message)s')
logger_datetime = '%d.%d.%d.%d.%d.%d' % (dt.year, dt.month,
dt.day, dt.hour, dt.minute, dt.second)
advixe_handler = logging.FileHandler('%s/%s_%s.log' % (output, name, logger_datetime))
logger_datetime = f'{dt.year}.{dt.month}.{dt.day}.{dt.hour}.{dt.minute}.{dt.second}'
advixe_handler = logging.FileHandler(f'{output}/{name}_{logger_datetime}.log')
advixe_handler.setFormatter(advixe_formatter)
advixe_logger.addHandler(advixe_handler)

Expand Down
62 changes: 34 additions & 28 deletions benchmarks/user/benchmark.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from contextlib import suppress

import click
import numpy as np
Expand Down Expand Up @@ -73,8 +74,10 @@ def run_op(solver, operator, **options):
# Get the operator if exist
try:
op = getattr(solver, operator)
except AttributeError:
raise AttributeError("Operator %s not implemented for %s" % (operator, solver))
except AttributeError as e:
raise AttributeError(
f"Operator {operator} not implemented for {solver}"
) from e

# This is a bit ugly but not sure how to make clean input creation for different op
if operator == "forward":
Expand All @@ -95,7 +98,7 @@ def run_op(solver, operator, **options):
args = args[:-1]
return op(*args, **options)
else:
raise ValueError("Unrecognized operator %s" % operator)
raise ValueError(f"Unrecognized operator {operator}")


@click.group()
Expand Down Expand Up @@ -157,15 +160,17 @@ def from_opt(ctx, param, value):
# E.g., `('advanced', {'par-tile': True})`
value = eval(value)
if not isinstance(value, tuple) and len(value) >= 1:
raise click.BadParameter("Invalid choice `%s` (`opt` must be "
"either str or tuple)" % str(value))
raise click.BadParameter(f"Invalid choice `{str(value)}` (`opt` must be "
"either str or tuple)")
opt = value[0]
except NameError:
# E.g. `'advanced'`
opt = value
if opt not in configuration._accepted['opt']:
raise click.BadParameter("Invalid choice `%s` (choose from %s)"
% (opt, str(configuration._accepted['opt'])))
raise click.BadParameter(
f'Invalid choice `{opt} '
f'(choose from {str(configuration._accepted["opt"])})'
)
return value

def config_blockshape(ctx, param, value):
Expand All @@ -181,18 +186,18 @@ def config_blockshape(ctx, param, value):
# 1. integers, not strings
# 2. sanity check the (hierarchical) blocking shape
normalized_value = []
for i, block_shape in enumerate(value):
for block_shape in value:
# If hierarchical blocking is activated, say with N levels, here in
# `bs` we expect to see 3*N entries
bs = [int(x) for x in block_shape.split()]
levels = [bs[x:x+3] for x in range(0, len(bs), 3)]
if any(len(level) != 3 for level in levels):
raise ValueError("Expected 3 entries per block shape level, but got "
"one level with less than 3 entries (`%s`)" % levels)
f"one level with less than 3 entries (`{levels}`)")
normalized_value.append(levels)
if not all_equal(len(i) for i in normalized_value):
raise ValueError("Found different block shapes with incompatible "
"number of levels (`%s`)" % normalized_value)
f"number of levels (`{normalized_value}`)")
configuration['opt-options']['blocklevels'] = len(normalized_value[0])
else:
normalized_value = []
Expand All @@ -205,8 +210,10 @@ def config_autotuning(ctx, param, value):
elif value != 'off':
# Sneak-peek at the `block-shape` -- if provided, keep auto-tuning off
if ctx.params['block_shape']:
warning("Skipping autotuning (using explicit block-shape `%s`)"
% str(ctx.params['block_shape']))
warning(
'Skipping autotuning'
f'(using explicit block-shape `{str(ctx.params["block_shape"])}`)'
)
level = False
else:
# Make sure to always run in preemptive mode
Expand Down Expand Up @@ -274,8 +281,8 @@ def run(problem, **kwargs):
# Note: the following piece of code is horribly *hacky*, but it works for now
for i, block_shape in enumerate(block_shapes):
for n, level in enumerate(block_shape):
for d, s in zip(['x', 'y', 'z'], level):
options['%s%d_blk%d_size' % (d, i, n)] = s
for d, s in zip(['x', 'y', 'z'], level, strict=True):
options[f'{d}{i}_blk{n}_size'] = s

solver = setup(space_order=space_order, time_order=time_order, **kwargs)
if warmup:
Expand Down Expand Up @@ -305,11 +312,11 @@ def run(problem, **kwargs):

dumpfile = kwargs.pop('dump_norms')
if dumpfile:
norms = ["'%s': %f" % (i.name, norm(i)) for i in retval[:-1]
norms = [f"'{i.name}': {norm(i):f}" for i in retval[:-1]
if isinstance(i, DiscreteFunction)]
if rank == 0:
with open(dumpfile, 'w') as f:
f.write("{%s}" % ', '.join(norms))
f.write("{{{}}}".format(', '.join(norms)))

return retval

Expand Down Expand Up @@ -343,13 +350,13 @@ def run_jit_backdoor(problem, **kwargs):
op = solver.op_fwd()

# Get the filename in the JIT cache
cfile = "%s.c" % str(op._compiler.get_jit_dir().joinpath(op._soname))
cfile = f"{str(op._compiler.get_jit_dir().joinpath(op._soname))}.c"

if not os.path.exists(cfile):
# First time we run this problem, let's generate and jit-compile code
op.cfunction
info("You may now edit the generated code in `%s`. "
"Then save the file, and re-run this benchmark." % cfile)
_ = op.cfunction
info(f"You may now edit the generated code in `{cfile}`. "
"Then save the file, and re-run this benchmark.")
return

info("Running wave propagation Operator...")
Expand All @@ -364,7 +371,7 @@ def _run_jit_backdoor():
if dumpnorms:
for i in retval[:-1]:
if isinstance(i, DiscreteFunction):
info("'%s': %f" % (i.name, norm(i)))
info(f"'{i.name}': {norm(i):f}")

return retval

Expand Down Expand Up @@ -405,9 +412,10 @@ def test(problem, **kwargs):
set_log_level('DEBUG', comm=MPI.COMM_WORLD)

if MPI.COMM_WORLD.size > 1 and not configuration['mpi']:
warning("It seems that you're running over MPI with %d processes, but "
"DEVITO_MPI is unset. Setting `DEVITO_MPI=basic`..."
% MPI.COMM_WORLD.size)
warning(
f'It seems that you are running over MPI with {MPI.COMM_WORLD.size} '
'processes, but DEVITO_MPI is unset. Setting `DEVITO_MPI=basic`...'
)
configuration['mpi'] = 'basic'
except (TypeError, ModuleNotFoundError):
# MPI not available
Expand All @@ -419,8 +427,6 @@ def test(problem, **kwargs):

benchmark(standalone_mode=False)

try:
# In case MPI not available
with suppress(TypeError):
MPI.Finalize()
except TypeError:
# MPI not available
pass
39 changes: 19 additions & 20 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import sys
from contextlib import suppress
from subprocess import check_call

import pytest
Expand Down Expand Up @@ -40,29 +41,29 @@ def skipif(items, whole_module=False):
accepted.update({'nodevice', 'noomp'})
unknown = sorted(set(items) - accepted)
if unknown:
raise ValueError("Illegal skipif argument(s) `%s`" % unknown)
raise ValueError(f"Illegal skipif argument(s) `{unknown}`")
skipit = False
for i in items:
# Skip if won't run on GPUs
if i == 'device' and isinstance(configuration['platform'], Device):
skipit = "device `%s` unsupported" % configuration['platform'].name
skipit = "device `{}` unsupported".format(configuration['platform'].name)
break
# Skip if won't run on a specific GPU backend
langs = configuration._accepted['language']
if any(i == 'device-%s' % l and configuration['language'] == l for l in langs)\
if any(i == f'device-{l}' and configuration['language'] == l for l in langs)\
and isinstance(configuration['platform'], Device):
skipit = "language `%s` for device unsupported" % configuration['language']
skipit = f'language `{configuration["language"]}` for device unsupported'
break
if any(i == 'device-%s' % k and isinstance(configuration['compiler'], v)
if any(i == f'device-{k}' and isinstance(configuration['compiler'], v)
for k, v in compiler_registry.items()) and\
isinstance(configuration['platform'], Device):
skipit = "compiler `%s` for device unsupported" % configuration['compiler']
skipit = f'compiler `{configuration["compiler"]}` for device unsupported'
break
# Skip if must run on GPUs but not currently on a GPU
if i in ('nodevice', 'nodevice-omp', 'nodevice-acc') and\
not isinstance(configuration['platform'], Device):
skipit = ("must run on device, but currently on `%s`" %
configuration['platform'].name)
skipit = 'must run on device, but currently on '
skipit += f'`{configuration["platform"].name}`'
break
# Skip if it won't run with nvc on CPU backend
if i == 'cpu64-nvc' and \
Expand Down Expand Up @@ -137,9 +138,9 @@ def EVAL(exprs, *args):

def get_testname(item):
if item.cls is not None:
return "%s::%s::%s" % (item.fspath, item.cls.__name__, item.name)
return f"{item.fspath}::{item.cls.__name__}::{item.name}"
else:
return "%s::%s" % (item.fspath, item.name)
return f"{item.fspath}::{item.name}"


def set_run_reset(env_vars, call):
Expand Down Expand Up @@ -179,7 +180,7 @@ def parallel(item, m):
if len(m) == 2:
nprocs, scheme = m
else:
raise ValueError("Can't run test: unexpected mode `%s`" % m)
raise ValueError(f"Can't run test: unexpected mode `{m}`")

env_vars = {'DEVITO_MPI': scheme}

Expand All @@ -189,8 +190,10 @@ def parallel(item, m):
# Run xfailing tests to ensure that errors are reported to calling process
args = ["-n", "1", pyversion, "-m", "pytest", "-s", "--runxfail", "-qq", testname]
if nprocs > 1:
args.extend([":", "-n", "%d" % (nprocs - 1), pyversion, "-m", "pytest",
"-s", "--runxfail", "--tb=no", "-qq", "--no-summary", testname])
args.extend([
":", "-n", str(nprocs - 1), pyversion, "-m", "pytest",
"-s", "--runxfail", "-v", "--no-summary", testname
])
# OpenMPI requires an explicit flag for oversubscription. We need it as some
# of the MPI tests will spawn lots of processes
if mpi_distro == 'OpenMPI':
Expand Down Expand Up @@ -247,10 +250,8 @@ def pytest_generate_tests(metafunc):
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_call(item):
inside_pytest_marker = os.environ.get('DEVITO_PYTEST_FLAG', 0)
try:
with suppress(ValueError):
inside_pytest_marker = int(inside_pytest_marker)
except ValueError:
pass

if inside_pytest_marker:
outcome = yield
Expand Down Expand Up @@ -281,15 +282,13 @@ def pytest_runtest_makereport(item, call):
result = outcome.get_result()

inside_pytest_marker = os.environ.get('DEVITO_PYTEST_FLAG', 0)
try:
with suppress(ValueError):
inside_pytest_marker = int(inside_pytest_marker)
except ValueError:
pass
if inside_pytest_marker:
return

if item.get_closest_marker("parallel") or \
item.get_closest_marker("decoupler"):
item.get_closest_marker("decoupler"): # noqa: SIM102
if call.when == 'call' and result.outcome == 'skipped':
result.outcome = 'passed'

Expand Down
Loading
Loading