Skip to content

Commit 09a1d20

Browse files
committed
compiler/misc: Drop petscgetargs callback, add functions to logging/get_info, clean up and more tests
1 parent 0189eb1 commit 09a1d20

File tree

19 files changed

+404
-231
lines changed

19 files changed

+404
-231
lines changed

.github/workflows/pytest-petsc.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ jobs:
7474
7575
- name: Test with pytest - serial
7676
run: |
77-
${{ env.RUN_CMD }} mpiexec -n 1 pytest -m "not parallel" --cov --cov-config=.coveragerc --cov-report=xml ${{ env.TESTS }}
77+
${{ env.RUN_CMD }} python3 -m pytest --cov --cov-config=.coveragerc --cov-report=xml -m "not parallel" ${{ env.TESTS }}
7878
7979
- name: Test with pytest - parallel
8080
run: |
81-
${{ env.RUN_CMD }} mpiexec -n 1 pytest -m parallel --cov --cov-config=.coveragerc --cov-report=xml ${{ env.TESTS }}
81+
${{ env.RUN_CMD }} python3 -m pytest --cov --cov-config=.coveragerc --cov-report=xml -m parallel ${{ env.TESTS }}
8282
8383
- name: Test examples
8484
run: |

devito/operator/profiling.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def summary(self, args, dtype, params, reduce_over=None):
213213
else:
214214
summary.add(name, None, time)
215215

216-
# Add the language specific summary if necessary
216+
# Add the language-specific summary if necessary
217217
mapper_func = language_summary_mapper.get(self.language)
218218
if mapper_func:
219219
summary.add_language_summary(self.language, mapper_func(params))
@@ -347,7 +347,7 @@ def summary(self, args, dtype, params, reduce_over=None):
347347
# data transfers)
348348
summary.add_glb_fdlike('fdlike-nosetup', points, reduce_over_nosetup)
349349

350-
# Add the language specific summary if necessary
350+
# Add the language-specific summary if necessary
351351
mapper_func = language_summary_mapper.get(self.language)
352352
if mapper_func:
353353
summary.add_language_summary(self.language, mapper_func(params))

devito/petsc/clusters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from devito.tools import timed_pass
2-
from devito.petsc.types import SolveExpr
2+
from devito.petsc.types import SolverMetaData
33

44

55
@timed_pass()
@@ -19,7 +19,7 @@ def petsc_lift(clusters):
1919
"""
2020
processed = []
2121
for c in clusters:
22-
if isinstance(c.exprs[0].rhs, SolveExpr):
22+
if isinstance(c.exprs[0].rhs, SolverMetaData):
2323
ispace = c.ispace.lift(c.exprs[0].rhs.field_data.space_dimensions)
2424
processed.append(c.rebuild(ispace=ispace))
2525
else:

devito/petsc/iet/logging.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from devito.symbolics import Byref, FieldFromPointer
44
from devito.ir.iet import DummyExpr
55
from devito.logger import PERF
6+
from devito.tools import frozendict
67

78
from devito.petsc.iet.utils import petsc_call
89
from devito.petsc.logging import petsc_return_variable_dict, PetscInfo
@@ -12,12 +13,12 @@ class PetscLogger:
1213
"""
1314
Class for PETSc loggers that collect solver related statistics.
1415
"""
15-
def __init__(self, level, get_info=None, **kwargs):
16-
self.function_list = get_info or []
16+
# TODO: Update docstring with kwargs
17+
def __init__(self, level, **kwargs):
1718

19+
self.query_functions = kwargs.get('get_info', [])
1820
self.sobjs = kwargs.get('solver_objs')
1921
self.sreg = kwargs.get('sregistry')
20-
2122
self.section_mapper = kwargs.get('section_mapper', {})
2223
self.inject_solve = kwargs.get('inject_solve', None)
2324

@@ -27,12 +28,14 @@ def __init__(self, level, get_info=None, **kwargs):
2728
'kspgetiterationnumber',
2829
'kspgettolerances',
2930
'kspgetconvergedreason',
31+
'kspgettype',
32+
'kspgetnormtype',
3033
# SNES specific
3134
'snesgetiterationnumber',
3235
]
33-
for f in funcs:
34-
if f not in self.function_list:
35-
self.function_list.append(f)
36+
self.query_functions = set(self.query_functions)
37+
self.query_functions.update(funcs)
38+
self.query_functions = sorted(list(self.query_functions))
3639

3740
# TODO: To be extended with if level <= DEBUG: ...
3841

@@ -42,19 +45,19 @@ def __init__(self, level, get_info=None, **kwargs):
4245
self.statstruct = PetscInfo(
4346
name, pname, self.petsc_option_mapper, self.sobjs,
4447
self.section_mapper, self.inject_solve,
45-
self.function_list
48+
self.query_functions
4649
)
4750

4851
@cached_property
4952
def petsc_option_mapper(self):
5053
"""
51-
For each function in `self.function_list`, look up its metadata in
54+
For each function in `self.query_functions`, look up its metadata in
5255
`petsc_return_variable_dict` and instantiate the corresponding PETSc logging
5356
variables with names from the symbol registry.
5457
5558
Example:
5659
--------
57-
>>> self.function_list
60+
>>> self.query_functions
5861
['kspgetiterationnumber', 'snesgetiterationnumber', 'kspgettolerances']
5962
6063
>>> self.petsc_option_mapper
@@ -64,12 +67,12 @@ def petsc_option_mapper(self):
6467
}
6568
"""
6669
opts = {}
67-
for func_name in self.function_list:
70+
for func_name in self.query_functions:
6871
info = petsc_return_variable_dict[func_name]
6972
opts[info.name] = {}
7073
for vtype, out in zip(info.variable_type, info.output_param, strict=True):
7174
opts[info.name][out] = vtype(self.sreg.make_name(prefix=out))
72-
return opts
75+
return frozendict(opts)
7376

7477
@cached_property
7578
def calls(self):
@@ -79,7 +82,7 @@ def calls(self):
7982
"""
8083
struct = self.statstruct
8184
calls = []
82-
for func_name in self.function_list:
85+
for func_name in self.query_functions:
8386
return_variable = petsc_return_variable_dict[func_name]
8487

8588
input = self.sobjs[return_variable.input_params]

devito/petsc/iet/passes.py

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@
66
from devito.ir.iet import (Transformer, MapNodes, Iteration, BlankLine,
77
DummyExpr, CallableBody, List, Call, Callable,
88
FindNodes, Section)
9-
from devito.symbolics import Byref, FieldFromPointer, Macro
9+
from devito.symbolics import Byref, FieldFromPointer, Macro, Null
1010
from devito.types import Symbol, Scalar
1111
from devito.types.basic import DataSymbol
1212
from devito.tools import frozendict
13-
import devito.logger as dl
13+
import devito.logger
1414

1515
from devito.petsc.types import (PetscMPIInt, PetscErrorCode, MultipleFieldData,
1616
PointerIS, Mat, CallbackVec, Vec, CallbackMat, SNES,
1717
DummyArg, PetscInt, PointerDM, PointerMat, MatReuse,
1818
CallbackPointerIS, CallbackPointerDM, JacobianStruct,
19-
SubMatrixStruct, Initialize, Finalize, ArgvSymbol,
20-
GetArgs, ArgvSymbolPtr, ArgcPtr)
21-
from devito.petsc.types.macros import petsc_func_begin_user, Null
19+
SubMatrixStruct, Initialize, Finalize, ArgvSymbol)
20+
from devito.petsc.types.macros import petsc_func_begin_user
2221
from devito.petsc.iet.nodes import PetscMetaData
2322
from devito.petsc.utils import core_metadata, petsc_languages
2423
from devito.petsc.iet.routines import (CBBuilder, CCBBuilder, BaseObjectBuilder,
@@ -52,9 +51,6 @@ def lower_petsc(iet, **kwargs):
5251
if any(filter(lambda i: isinstance(i.expr.rhs, Finalize), data)):
5352
return finalize(iet), core_metadata()
5453

55-
if any(filter(lambda i: isinstance(i.expr.rhs, GetArgs), data)):
56-
return get_args(iet), core_metadata()
57-
5854
unique_grids = {i.expr.rhs.grid for (i,) in inject_solve_mapper.values()}
5955
# Assumption is that all solves are on the same grid
6056
if len(unique_grids) > 1:
@@ -73,7 +69,7 @@ def lower_petsc(iet, **kwargs):
7369
# Map PETScSolve to its Section (for logging)
7470
section_mapper = MapNodes(Section, PetscMetaData, 'groupby').visit(iet)
7571

76-
# Prefixes within the same Operator should not be duplicated
72+
# Prefixes within the same `Operator` should not be duplicated
7773
prefixes = [d.expr.rhs.user_prefix for d in data if d.expr.rhs.user_prefix]
7874
duplicates = {p for p in prefixes if prefixes.count(p) > 1}
7975

@@ -138,18 +134,6 @@ def finalize(iet):
138134
return iet._rebuild(body=finalize_body)
139135

140136

141-
def get_args(iet):
142-
argc = ArgcPtr(name='argc', dtype=np.int32)
143-
argv = ArgvSymbolPtr(name='argv')
144-
145-
body = petsc_call('PetscGetArgs', [argc, argv])
146-
body = CallableBody(
147-
body=(petsc_func_begin_user, body),
148-
retstmt=(Call('PetscFunctionReturn', arguments=[0]),)
149-
)
150-
return iet._rebuild(body=body)
151-
152-
153137
def make_core_petsc_calls(objs, comm):
154138
call_mpi = petsc_call_mpi('MPI_Comm_size', [comm, Byref(objs['size'])])
155139
return call_mpi, BlankLine
@@ -217,9 +201,9 @@ def solve(self):
217201

218202
@cached_property
219203
def logger(self):
220-
log_level = dl.logger.level
204+
log_level = devito.logger.logger.level
221205
return PetscLogger(
222-
log_level, self.get_info, **self.common_kwargs
206+
log_level, get_info=self.get_info, **self.common_kwargs
223207
)
224208

225209
@cached_property

devito/petsc/iet/routines.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
retrieve_iteration_tree, filter_iterations, Iteration,
88
PointerCast)
99
from devito.symbolics import (Byref, FieldFromPointer, cast, VOID,
10-
FieldFromComposite, IntDiv, Deref, Mod, String)
10+
FieldFromComposite, IntDiv, Deref, Mod, String, Null)
1111
from devito.symbolics.unevaluation import Mul
1212
from devito.types.basic import AbstractFunction
1313
from devito.types import Temp, Dimension
@@ -21,8 +21,7 @@
2121
KSP, PC, SNES, PetscInt, StartPtr, PointerIS, PointerDM,
2222
VecScatter, DMCast, JacobianStruct, SubMatrixStruct,
2323
CallbackDM)
24-
from devito.petsc.types.macros import petsc_func_begin_user, Null
25-
# from devito.petsc.initialize import PetscGetArgs
24+
from devito.petsc.types.macros import petsc_func_begin_user
2625

2726

2827
class CBBuilder:
@@ -38,7 +37,7 @@ def __init__(self, **kwargs):
3837
self.objs = kwargs.get('objs')
3938
self.solver_objs = kwargs.get('solver_objs')
4039
self.inject_solve = kwargs.get('inject_solve')
41-
self.solver_parameters = self.inject_solve.expr.rhs.solver_parameters
40+
self.solve_expr = self.inject_solve.expr.rhs
4241

4342
self._efuncs = OrderedDict()
4443
self._struct_params = []
@@ -96,9 +95,17 @@ def initial_guesses(self):
9695
def user_struct_callback(self):
9796
return self._user_struct_callback
9897

98+
@property
99+
def solver_parameters(self):
100+
return self.solve_expr.solver_parameters
101+
99102
@property
100103
def field_data(self):
101-
return self.inject_solve.expr.rhs.field_data
104+
return self.solve_expr.field_data
105+
106+
@property
107+
def formatted_prefix(self):
108+
return self.solve_expr.formatted_prefix
102109

103110
@property
104111
def arrays(self):
@@ -143,17 +150,17 @@ def _make_options_callback(self):
143150
command line arguments.
144151
"""
145152
params = self.solver_parameters
146-
prefix = self.inject_solve.expr.rhs.formatted_prefix
153+
prefix = self.formatted_prefix
147154

148155
set_body, clear_body = [], []
149156

150157
for k, v in params.items():
151158
option = f'-{prefix}{k}'
152159

153-
# TODO: drop the global variable _petsc_clargs..
154-
# from devito.petsc.initialize import PetscGetArgs
155-
# PetscGetArgs()
156-
160+
# TODO: Revisit use of a global variable here.
161+
# Consider replacing this with a call to `PetscGetArgs`, though
162+
# initial attempts failed, possibly because the argv pointer is
163+
# created in Python?..
157164
import devito.petsc.initialize
158165
if option in devito.petsc.initialize._petsc_clargs:
159166
# Ensures that the command line args take priority
@@ -1719,10 +1726,10 @@ class TimeDependent(NonTimeDependent):
17191726
for each `SNESSolve` at every time step, don't require the time loop, but
17201727
may still need access to data from other time steps.
17211728
- All `Function` objects are passed through the initial lowering via the
1722-
`SolveExpr` object, ensuring the correct time loop is generated
1729+
`SolverMetaData` object, ensuring the correct time loop is generated
17231730
in the main kernel.
17241731
- Another mapper is created based on the modulo dimensions
1725-
generated by the `SolveExpr` object in the main kernel
1732+
generated by the `SolverMetaData` object in the main kernel
17261733
(e.g., {time: time, t: t0, t + 1: t1}).
17271734
- These two mappers are used to generate a final mapper `symb_to_moddim`
17281735
(e.g. {tau0: t0, tau1: t1}) which is used at the IET level to

devito/petsc/initialize.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import os
22
import sys
3-
from ctypes import POINTER, cast, c_char, c_int, c_char_p, byref
3+
from ctypes import POINTER, cast, c_char
44
import atexit
55

66
from devito import Operator, switchconfig
77
from devito.types import Symbol
88
from devito.types.equation import PetscEq
9-
from devito.petsc.types import Initialize, Finalize, GetArgs
9+
from devito.petsc.types import Initialize, Finalize
1010

1111
global _petsc_initialized
1212
_petsc_initialized = False
@@ -15,18 +15,16 @@
1515
global _petsc_clargs
1616

1717

18-
dummy = Symbol(name='d')
19-
20-
2118
def PetscInitialize(clargs=sys.argv):
2219
global _petsc_initialized
2320
global _petsc_clargs
2421

2522
if not _petsc_initialized:
23+
dummy = Symbol(name='d')
24+
2625
if clargs is not sys.argv:
27-
clargs = [sys.argv[0], *clargs]
26+
clargs = (sys.argv[0], *clargs)
2827

29-
# TODO: Drop this global variable
3028
_petsc_clargs = clargs
3129

3230
# TODO: Potentially just use cgen + the compiler machinery in Devito
@@ -43,24 +41,19 @@ def PetscInitialize(clargs=sys.argv):
4341
name='kernel_finalize', opt='noop'
4442
)
4543

44+
# Convert each string to a bytes object (e.g: '-ksp_type' -> b'-ksp_type')
4645
# `argv_bytes` must be a list so the memory address persists
4746
# `os.fsencode` should be preferred over `string().encode('utf-8')`
4847
# in case there is some system specific encoding in use
4948
argv_bytes = list(map(os.fsencode, clargs))
49+
50+
# POINTER(c_char) is equivalent to char * in C
51+
# (POINTER(c_char) * len(clargs)) creates a C array type: char *[len(clargs)]
52+
# Instantiating it with (*map(...)) casts each bytes object to a char * and
53+
# fills the array. The result is a char *argv[]
5054
argv_pointer = (POINTER(c_char)*len(clargs))(
5155
*map(lambda s: cast(s, POINTER(c_char)), argv_bytes)
5256
)
5357
op_init.apply(argc=len(clargs), argv=argv_pointer)
5458
atexit.register(op_finalize.apply)
5559
_petsc_initialized = True
56-
57-
58-
def PetscGetArgs():
59-
with switchconfig(language='petsc'):
60-
op_get_args = Operator(
61-
[PetscEq(dummy, GetArgs(dummy))],
62-
name='kernel_get_args', opt='noop'
63-
)
64-
argc_ptr = c_int()
65-
argv_ptr = (POINTER(c_char_p))()
66-
op_get_args.apply(argc=byref(argc_ptr), argv=byref(argv_ptr))

0 commit comments

Comments
 (0)