Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat[cartesian] Debug Backend #1884

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions src/gt4py/cartesian/backend/__init__.py
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
register,
)
from .cuda_backend import CudaBackend
from .debug_backend import DebugBackend
from .gtcpp_backend import GTCpuIfirstBackend, GTCpuKfirstBackend, GTGpuBackend
from .module_generator import BaseModuleGenerator
from .numpy_backend import NumpyBackend
@@ -32,6 +33,7 @@
"BasePyExtBackend",
"CLIBackendMixin",
"CudaBackend",
"DebugBackend",
"GTCpuIfirstBackend",
"GTCpuKfirstBackend",
"GTGpuBackend",
9 changes: 9 additions & 0 deletions src/gt4py/cartesian/backend/base.py
Original file line number Diff line number Diff line change
@@ -317,6 +317,15 @@ def make_module_source(self, *, args_data: Optional[ModuleData] = None, **kwargs
source = self.MODULE_GENERATOR_CLASS()(args_data, self.builder, **kwargs)
return source

def recursive_write(self, root_path: pathlib.Path, tree: dict[str, Union[str, dict]]):
root_path.mkdir(parents=True, exist_ok=True)
for key, value in tree.items():
if isinstance(value, dict):
self.recursive_write(root_path / key, value)
else:
src_path = root_path / key
src_path.write_text(value)
Comment on lines +320 to +327
Copy link
Contributor

Choose a reason for hiding this comment

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

This function used to be a standalone function. Now it is part of a base class without accessing any property or method of that class. Have you considered leaving it a standalone function? We could keep it in the same file or create src/gt4py/cartesian/backend/utils.py and put it there. Another prime candidate to move to a potential backend/utils.py (in a follow-up PR) would be

def disabled(message: str, *, enabled_env_var: str) -> Callable[[Type[Backend]], Type[Backend]]:
# We push for hard deprecation here by raising by default and warning if enabling has been forced.
enabled = bool(int(os.environ.get(enabled_env_var, "0")))
if enabled:
return deprecated(message)
else:
def _decorator(cls: Type[Backend]) -> Type[Backend]:
def _no_generate(obj) -> Type[StencilObject]:
raise NotImplementedError(
f"Disabled '{cls.name}' backend: 'f{message}'\n",
f"You can still enable the backend by hand using the environment variable '{enabled_env_var}=1'",
)
# Replace generate method with raise
if not hasattr(cls, "generate"):
raise ValueError(f"Coding error. Expected a generate method on {cls}")
# Flag that it got disabled for register lookup
cls.disabled = True # type: ignore
cls.generate = _no_generate # type: ignore
return cls
return _decorator

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think since it is so tied to the backends and this is the only place this is used, adding it to the class gives it a more direct link to where the work is used. I prefer this way to avoid generic utils files that have a tendency to grow big. If there are utilities that are used across larger modules, I see value that way.

We could make it a staticmethod though



class MakeModuleSourceCallable(Protocol):
def __call__(self, *, args_data: Optional[ModuleData] = None, **kwargs: Any) -> str: ...
68 changes: 68 additions & 0 deletions src/gt4py/cartesian/backend/debug_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# GT4Py - GridTools Framework
#
# Copyright (c) 2014-2024, ETH Zurich
# All rights reserved.
#
# Please, refer to the LICENSE file in the root directory.
# SPDX-License-Identifier: BSD-3-Clause


from typing import TYPE_CHECKING, Any, ClassVar, Type, Union

from gt4py import storage
from gt4py.cartesian.backend.base import BaseBackend, CLIBackendMixin, register
from gt4py.cartesian.backend.numpy_backend import ModuleGenerator
from gt4py.cartesian.gtc.debug.debug_codegen import DebugCodeGen
from gt4py.cartesian.gtc.gtir_to_oir import GTIRToOIR
from gt4py.cartesian.gtc.passes.oir_optimizations.horizontal_execution_merging import (
HorizontalExecutionMerging,
)
from gt4py.cartesian.gtc.passes.oir_optimizations.temporaries import LocalTemporariesToScalars
from gt4py.cartesian.gtc.passes.oir_pipeline import OirPipeline
from gt4py.eve.codegen import format_source
Comment on lines +12 to +22
Copy link
Contributor

Choose a reason for hiding this comment

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

See my comments about imports below



if TYPE_CHECKING:
from gt4py.cartesian.stencil_object import StencilObject


@register
class DebugBackend(BaseBackend, CLIBackendMixin):
"""Debug backend using plain python loops."""

name = "debug"
options: ClassVar[dict[str, Any]] = {
"oir_pipeline": {"versioning": True, "type": OirPipeline},
"ignore_np_errstate": {"versioning": True, "type": bool},
}
storage_info = storage.layout.NaiveCPULayout
languages = {"computation": "python", "bindings": ["python"]}
MODULE_GENERATOR_CLASS = ModuleGenerator

def generate_computation(self) -> dict[str, Union[str, dict]]:
computation_name = (
f"{self.builder.caching.module_prefix}"
+ f"computation{self.builder.caching.module_postfix}.py"
)

oir = GTIRToOIR().visit(self.builder.gtir)
oir = HorizontalExecutionMerging().visit(oir)
oir = LocalTemporariesToScalars().visit(oir)
source_code = DebugCodeGen().visit(oir)

if self.builder.options.format_source:
source_code = format_source("python", source_code)

return {computation_name: source_code}

def generate_bindings(self, language_name: str) -> dict[str, Union[str, dict]]:
super().generate_bindings(language_name)
return {self.builder.module_path.name: self.make_module_source()}

def generate(self) -> Type["StencilObject"]:
self.check_options(self.builder.options)
src_dir = self.builder.module_path.parent
if not self.builder.options._impl_opts.get("disable-code-generation", False):
src_dir.mkdir(parents=True, exist_ok=True)
self.recursive_write(src_dir, self.generate_computation())
return self.make_module()
13 changes: 1 addition & 12 deletions src/gt4py/cartesian/backend/numpy_backend.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@

from __future__ import annotations

import pathlib
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Type, Union, cast

from gt4py import storage as gt_storage
@@ -57,16 +56,6 @@ def backend(self) -> NumpyBackend:
return cast(NumpyBackend, self.builder.backend)


def recursive_write(root_path: pathlib.Path, tree: Dict[str, Union[str, dict]]):
root_path.mkdir(parents=True, exist_ok=True)
for key, value in tree.items():
if isinstance(value, dict):
recursive_write(root_path / key, value)
else:
src_path = root_path / key
src_path.write_text(value)


@register
class NumpyBackend(BaseBackend, CLIBackendMixin):
"""NumPy backend using gtc."""
@@ -105,7 +94,7 @@ def generate(self) -> Type[StencilObject]:
src_dir = self.builder.module_path.parent
if not self.builder.options._impl_opts.get("disable-code-generation", False):
src_dir.mkdir(parents=True, exist_ok=True)
recursive_write(src_dir, self.generate_computation())
self.recursive_write(src_dir, self.generate_computation())
return self.make_module()

def _make_npir(self) -> npir.Computation:
7 changes: 7 additions & 0 deletions src/gt4py/cartesian/gtc/debug/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# GT4Py - GridTools Framework
#
# Copyright (c) 2014-2024, ETH Zurich
# All rights reserved.
#
# Please, refer to the LICENSE file in the root directory.
# SPDX-License-Identifier: BSD-3-Clause
Loading