Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
92edf68
dsl/compiler: Edits to mixed solver functionality
ZoeLeibowitz Apr 24, 2025
f6b38ed
compiler: Working petscbundle
ZoeLeibowitz Apr 29, 2025
7300c8f
compiler: Add PetscMixin to simplify priority destroys
ZoeLeibowitz Apr 30, 2025
1ddc053
compiler: Working reuse_efunc for petscbundles
ZoeLeibowitz May 28, 2025
6834611
dsl/compiler: Zero columns for essential bcs
ZoeLeibowitz May 29, 2025
9642278
dsl: Compatible scaling of jacobian
ZoeLeibowitz May 29, 2025
ce9150f
dsl: Scale boundary rows of jacobian
ZoeLeibowitz May 30, 2025
f7e00bb
types: Edit PetscMixin and use it in other petsc classes
ZoeLeibowitz Jun 3, 2025
6e20d4b
dsl: Add extraction file
ZoeLeibowitz Jun 3, 2025
8a79fcd
dsl: Move symbolic extraction functions outside of the PETSc module
ZoeLeibowitz Jun 3, 2025
3000bd8
types: Move EssentialBC to another file
ZoeLeibowitz Jun 3, 2025
a0457f0
dsl/compiler: Add equation.py to petsc module
ZoeLeibowitz Jun 3, 2025
7132eb1
dsl: Add jacobian class for single fields
ZoeLeibowitz Jun 4, 2025
6897ab8
dsl: Fix compatible scaling for single fields
ZoeLeibowitz Jun 4, 2025
8386992
dsl: Improve Jacobian abstraction
ZoeLeibowitz Jun 5, 2025
fb20781
examples: Add pressure norm check in stokes example
ZoeLeibowitz Jun 5, 2025
5c1b686
tests: Add more petsc tests for linear coupled
ZoeLeibowitz Jun 8, 2025
b0ca11f
misc: Merge petsc branch in but broken petscbundle
ZoeLeibowitz Jun 10, 2025
b6710be
types: Fix PetscBundle symbolic shape
ZoeLeibowitz Jun 10, 2025
01d153a
tests: Fix petsc tests
ZoeLeibowitz Jun 10, 2025
d6bd4f4
misc: Address comments
ZoeLeibowitz Jun 11, 2025
4fad6aa
misc: Merge leftover
ZoeLeibowitz Jun 11, 2025
525fdf6
Merge branch 'petsc' into biharmonic
ZoeLeibowitz Jun 11, 2025
27dd201
compiler: Edit switch_log_level
ZoeLeibowitz Jun 11, 2025
30ed5ba
tests: Add mpi petsc test
ZoeLeibowitz Jun 11, 2025
51d4d7e
misc: Address more comments and add docstrings
ZoeLeibowitz Jun 11, 2025
a4a5660
misc: Clean up more docstrings
ZoeLeibowitz Jun 12, 2025
312c826
misc: Add BaseJacobian
ZoeLeibowitz Jun 12, 2025
048f693
misc: Docstrings, stop list output for PETScSolve, tests
ZoeLeibowitz Jun 13, 2025
905def2
misc: Flake8
ZoeLeibowitz Jun 13, 2025
19fddbe
misc: Fix exprs in 01_navierstokes.py due to change in PETScSolve out…
ZoeLeibowitz Jun 13, 2025
6972cbc
Merge branch 'biharmonic' into petsc_mpi
ZoeLeibowitz Jun 13, 2025
8037cf9
misc: Clean up
ZoeLeibowitz Jun 13, 2025
8c16f2e
misc: Utilise zero_vector function
ZoeLeibowitz Jun 13, 2025
dcbf929
Merge branch 'biharmonic' into petsc_mpi
ZoeLeibowitz Jun 13, 2025
f3d4d2d
misc: Move vecset to function inside iet/utils.py
ZoeLeibowitz Jun 13, 2025
8d10b87
misc: Flake8
ZoeLeibowitz Jun 13, 2025
53b58a9
misc: Clean up
ZoeLeibowitz Jun 13, 2025
857eb9c
misc: Add more tests
ZoeLeibowitz Jun 15, 2025
7a5b10f
mpi: Start parallel tests
ZoeLeibowitz Jun 16, 2025
467c19b
add to petsc laplacian test
ZoeLeibowitz Jun 16, 2025
343ba75
merge conflict
ZoeLeibowitz Jun 16, 2025
d2e3eb5
mpi tests
ZoeLeibowitz Jun 16, 2025
6165373
edit test
ZoeLeibowitz Jun 16, 2025
0b43ea6
tests: Add petsc parallel test
ZoeLeibowitz Jun 16, 2025
62d0045
clean up
ZoeLeibowitz Jun 16, 2025
bd96379
misc: Simplify comm extraction in lower_petsc
ZoeLeibowitz Jun 16, 2025
ce5cf82
clean up
ZoeLeibowitz Jun 16, 2025
b7c4082
trigger petsc CI
ZoeLeibowitz Jun 16, 2025
e485c9c
misc: Add todo:
ZoeLeibowitz Jun 17, 2025
df4e638
address some of ed's comments
ZoeLeibowitz Jun 17, 2025
72e8222
misc: Address comments
ZoeLeibowitz Jun 17, 2025
b72465f
Merge pull request #2635 from devitocodes/petsc_mpi
ZoeLeibowitz Jun 19, 2025
16be19a
dsl/compiler: Add PETSc logging instrastructure and tests
ZoeLeibowitz Jun 20, 2025
f790ab9
Merge pull request #2655 from devitocodes/petsc_performance_summary
ZoeLeibowitz Jul 14, 2025
e3e26f0
compiler: Fix language summary
ZoeLeibowitz Jul 14, 2025
9a182da
misc: Fix advisor profiling with new language arg
ZoeLeibowitz Jul 14, 2025
774af10
misc: Clean up and docstrings
ZoeLeibowitz Jul 16, 2025
910c987
misc: Clean up
ZoeLeibowitz Jul 17, 2025
ff4b2d7
misc: flake8
ZoeLeibowitz Jul 17, 2025
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
4 changes: 2 additions & 2 deletions .github/workflows/examples-mpi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ on:
push:
branches:
- main
- master
- petsc
pull_request:
branches:
- main
- master
- petsc

jobs:
build:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ on:
push:
branches:
- main
- master
- petsc
pull_request:
branches:
- main
- master
- petsc

jobs:
tutorials:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/flake8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ on:
push:
branches:
- main
- master
- petsc
pull_request:
branches:
- main
- master
- petsc

jobs:
flake8:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pytest-core-mpi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ on:
push:
branches:
- main
- master
- petsc
pull_request:
branches:
- main
- master
- petsc

jobs:
test-mpi-basic:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pytest-core-nompi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ on:
push:
branches:
- main
- master
- petsc
pull_request:
branches:
- main
- master
- petsc

jobs:
pytest:
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/pytest-petsc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ on:
push:
branches:
- main
- master
- petsc
- biharmonic
pull_request:
branches:
- main
- master
- petsc
- biharmonic

jobs:
pytest:
Expand Down Expand Up @@ -83,6 +85,7 @@ jobs:
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/Poisson/03_poisson.py
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/Poisson/04_poisson.py
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/random/01_helmholtz.py
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/random/02_biharmonic.py

- name: Upload coverage to Codecov
if: "!contains(matrix.name, 'docker')"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tutorials.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ on:
push:
branches:
- main
- master
- petsc
pull_request:
branches:
- main
- master
- petsc

jobs:
tutorials:
Expand Down
3 changes: 2 additions & 1 deletion devito/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ def set_log_level(level, comm=None):
used, for example, if one wants to log to one file per rank.
"""
from devito import configuration
from devito.mpi.distributed import MPI

if comm is not None and configuration['mpi']:
if comm.rank != 0:
if comm != MPI.COMM_NULL and comm.rank != 0:
logger.removeHandler(stream_handler)
logger.addHandler(logging.NullHandler())
else:
Expand Down
6 changes: 4 additions & 2 deletions devito/operator/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def _sanitize_exprs(cls, expressions, **kwargs):
@classmethod
def _build(cls, expressions, **kwargs):
# Python- (i.e., compile-) and C-level (i.e., run-time) performance
profiler = create_profile('timers')
profiler = create_profile('timers', kwargs['language'])

# Lower the input expressions into an IET
irs, byproduct = cls._lower(expressions, profiler=profiler, **kwargs)
Expand Down Expand Up @@ -1004,7 +1004,9 @@ def _emit_apply_profiling(self, args):
elapsed = fround(self._profiler.py_timers['apply'])
info(f"Operator `{self.name}` ran in {elapsed:.2f} s")

summary = self._profiler.summary(args, self._dtype, reduce_over=elapsed)
summary = self._profiler.summary(
args, self._dtype, self.parameters, reduce_over=elapsed
)

if not is_log_enabled_for('PERF'):
# Do not waste time
Expand Down
40 changes: 32 additions & 8 deletions devito/operator/profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from devito.parameters import configuration
from devito.symbolics import subs_op_args
from devito.tools import DefaultOrderedDict, flatten
from devito.petsc.logging import PetscSummary

__all__ = ['create_profile']

Expand All @@ -42,7 +43,7 @@ class Profiler:

_attempted_init = False

def __init__(self, name):
def __init__(self, name, language):
self.name = name

# Operation reductions observed in sections
Expand All @@ -55,6 +56,9 @@ def __init__(self, name):
# Python-level timers
self.py_timers = OrderedDict()

# For language specific summaries
self.language = language

self._attempted_init = True

def analyze(self, iet):
Expand Down Expand Up @@ -179,7 +183,7 @@ def record_ops_variation(self, initial, final):
def all_sections(self):
return list(self._sections) + flatten(self._subsections.values())

def summary(self, args, dtype, reduce_over=None):
def summary(self, args, dtype, params, reduce_over=None):
"""
Return a PerformanceSummary of the profiled sections.

Expand Down Expand Up @@ -277,7 +281,7 @@ def _allgather_from_comm(self, comm, time, ops, points, traffic, sops, itershape
return list(zip(times, opss, pointss, traffics, sops, itershapess))

# Override basic summary so that arguments other than runtime are computed.
def summary(self, args, dtype, reduce_over=None):
def summary(self, args, dtype, params, reduce_over=None):
grid = args.grid
comm = args.comm

Expand Down Expand Up @@ -338,6 +342,11 @@ def summary(self, args, dtype, reduce_over=None):
# data transfers)
summary.add_glb_fdlike('fdlike-nosetup', points, reduce_over_nosetup)

# Add the language specific summary if necessary
mapper_func = language_summary_mapper.get(self.language)
if mapper_func:
summary.add_language_summary(self.language, mapper_func(params))

return summary


Expand Down Expand Up @@ -366,11 +375,11 @@ class AdvisorProfiler(AdvancedProfiler):
_default_libs = ['ittnotify']
_ext_calls = [_api_resume, _api_pause]

def __init__(self, name):
def __init__(self, name, language):
if self._attempted_init:
return

super().__init__(name)
super().__init__(name, language)

path = get_advisor_path()
if path:
Expand Down Expand Up @@ -478,6 +487,16 @@ def add_glb_fdlike(self, key, points, time):

self.globals[key] = PerfEntry(time, None, gpointss, None, None, None)

def add_language_summary(self, lang, summary):
"""
Register a language specific summary (e.g., PetscSummary)
and dynamically add a property to access it via perf_summary.<language_name>.
"""
# TODO: Consider renaming `PerformanceSummary` to something more generic
# (e.g., `Summary`), or separating `PetscSummary` entirely from
# `PerformanceSummary`.
setattr(self, lang, summary)

@property
def globals_all(self):
v0 = self.globals['vanilla']
Expand All @@ -503,21 +522,21 @@ def timings(self):
return OrderedDict([(k, v.time) for k, v in self.items()])


def create_profile(name):
def create_profile(name, language):
"""Create a new Profiler."""
if configuration['log-level'] in ['DEBUG', 'PERF'] and \
configuration['profiling'] == 'basic':
# Enforce performance profiling in DEBUG mode
level = 'advanced'
else:
level = configuration['profiling']
profiler = profiler_registry[level](name)
profiler = profiler_registry[level](name, language)

if profiler._attempted_init:
return profiler
else:
warning(f"Couldn't set up `{level}` profiler; reverting to 'advanced'")
profiler = profiler_registry['advanced'](name)
profiler = profiler_registry['advanced'](name, language)
# We expect the `advanced` profiler to always initialize successfully
assert profiler._attempted_init
return profiler
Expand All @@ -533,3 +552,8 @@ def create_profile(name):
'advisor': AdvisorProfiler
}
"""Profiling levels."""


language_summary_mapper = {
'petsc': PetscSummary
}
7 changes: 5 additions & 2 deletions devito/passes/iet/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import numpy as np
from sympy import Mul

from devito.finite_differences.differentiable import Differentiable
from devito.ir.iet import (
Call, ExprStmt, Expression, Iteration, SyncSpot, AsyncCallable, FindNodes,
FindSymbols, MapNodes, MetaCall, Transformer, EntryFunction,
Expand All @@ -24,6 +25,7 @@
from devito.types.args import ArgProvider
from devito.types.dense import DiscreteFunction
from devito.types.dimension import AbstractIncrDimension, BlockDimension
from devito.types.array import ArrayBasic

__all__ = ['Graph', 'iet_pass', 'iet_visit']

Expand Down Expand Up @@ -492,7 +494,8 @@ def abstract_objects(objects0, sregistry=None):

# Precedence rules make it possible to reconstruct objects that depend on
# higher priority objects
keys = [Bundle, Array, DiscreteFunction, AbstractIncrDimension, BlockDimension]
keys = [Bundle, Array, Differentiable, DiscreteFunction,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you add Differentiable here? Is it possible to add a test to test_iet covering this specific case (or at least for me to understand)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FabioLuporini The problem arises from my new class PetscBundle(Bundle), whose components are PETScArrays. In the abstract_objects function, the mapper must be updated for the components before the PetscBundle itself. PETScArray inherits from ArrayBasic and Differentiable. However, I can't use ArrayBasic because Bundle also inherits from it. So I chose Differentiable as the distinguishing type (to avoid using PETScArray)

AbstractIncrDimension, BlockDimension]
priority = {k: i for i, k in enumerate(keys, start=1)}
objects = sorted_priority(objects, priority)

Expand Down Expand Up @@ -527,7 +530,7 @@ def _(i, mapper, sregistry):
})


@abstract_object.register(Array)
@abstract_object.register(ArrayBasic)
def _(i, mapper, sregistry):
if isinstance(i, Lock):
name = sregistry.make_name(prefix='lock')
Expand Down
1 change: 1 addition & 0 deletions devito/petsc/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from devito.petsc.solve import * # noqa
from devito.petsc.types.equation import * # noqa
2 changes: 1 addition & 1 deletion devito/petsc/clusters.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def petsc_lift(clusters):
processed = []
for c in clusters:
if isinstance(c.exprs[0].rhs, LinearSolveExpr):
ispace = c.ispace.lift(c.exprs[0].rhs.fielddata.space_dimensions)
ispace = c.ispace.lift(c.exprs[0].rhs.field_data.space_dimensions)
processed.append(c.rebuild(ispace=ispace))
else:
processed.append(c)
Expand Down
77 changes: 77 additions & 0 deletions devito/petsc/iet/logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from functools import cached_property

from devito.symbolics import Byref, FieldFromPointer
from devito.ir.iet import DummyExpr
from devito.logger import PERF

from devito.petsc.iet.utils import petsc_call
from devito.petsc.logging import petsc_return_variable_dict, PetscInfo


class PetscLogger:
"""
Class for PETSc loggers that collect solver related statistics.
"""
def __init__(self, level, **kwargs):
self.sobjs = kwargs.get('solver_objs')
self.sreg = kwargs.get('sregistry')
self.section_mapper = kwargs.get('section_mapper', {})
self.inject_solve = kwargs.get('inject_solve', None)

self.function_list = []

if level <= PERF:
self.function_list.extend([
'kspgetiterationnumber',
'snesgetiterationnumber'
])

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

name = self.sreg.make_name(prefix='petscinfo')
pname = self.sreg.make_name(prefix='petscprofiler')

self.statstruct = PetscInfo(
name, pname, self.logobjs, self.sobjs,
self.section_mapper, self.inject_solve,
self.function_list
)

@cached_property
def logobjs(self):
"""
Create PETSc objects specifically needed for logging solver statistics.
"""
return {
info.name: info.variable_type(
self.sreg.make_name(prefix=info.output_param)
)
for func_name in self.function_list
for info in [petsc_return_variable_dict[func_name]]
}

@cached_property
def calls(self):
"""
Generate the PETSc calls that will be injected into the C code to
extract solver statistics.
"""
struct = self.statstruct
calls = []
for param in self.function_list:
param = petsc_return_variable_dict[param]

inputs = []
for i in param.input_params:
inputs.append(self.sobjs[i])

logobj = self.logobjs[param.name]

calls.append(
petsc_call(param.name, inputs + [Byref(logobj)])
)
# TODO: Perform a PetscCIntCast here?
expr = DummyExpr(FieldFromPointer(logobj._C_symbol, struct), logobj._C_symbol)
calls.append(expr)

return tuple(calls)
Loading
Loading