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

Implement CupyArrayContext #251

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7ab5211
Implement CupyArrayContext
matthiasdiener Feb 16, 2024
96b7a3d
print device name in test
matthiasdiener Feb 16, 2024
8dee38d
pylint
matthiasdiener Feb 17, 2024
2c025eb
Merge branch 'main' into cupyactx
matthiasdiener May 24, 2024
d6e3136
Merge branch 'main' into cupyactx
matthiasdiener Sep 6, 2024
bfa648a
update with current numpy actx
matthiasdiener Sep 6, 2024
27e5a19
restore some tests
matthiasdiener Sep 6, 2024
6d507e1
ruff
matthiasdiener Sep 6, 2024
8fb4e0b
make cupy import optional
matthiasdiener Sep 6, 2024
be70b67
CI fixes
matthiasdiener Sep 6, 2024
677419b
remove a few spurious changes
matthiasdiener Sep 6, 2024
6250211
change CI cupy integration
matthiasdiener Sep 6, 2024
d61f0cf
simplify CI install slightly
matthiasdiener Sep 6, 2024
5871ae7
Merge branch 'main' into cupyactx
matthiasdiener Nov 14, 2024
9c56443
Merge branch 'main' into cupyactx
matthiasdiener Dec 3, 2024
fd95813
lint
matthiasdiener Dec 3, 2024
5f4c4d9
update docs
matthiasdiener Dec 3, 2024
a8fe272
Merge branch 'main' into cupyactx
matthiasdiener Jan 31, 2025
2296c6d
improve array container support in {to,from}_numpy
matthiasdiener Jan 31, 2025
8fd5488
WS fix
matthiasdiener Jan 31, 2025
6f3cd94
fixes
matthiasdiener Feb 3, 2025
ab8266d
allow optional device selection
matthiasdiener Feb 7, 2025
79b0bc3
try running cupy via gitlab
matthiasdiener Feb 7, 2025
70aff99
debug more
matthiasdiener Feb 7, 2025
8b5c6cf
Revert "debug more"
matthiasdiener Feb 7, 2025
8561b2f
only test pocl-cpu in cupy test
matthiasdiener Feb 7, 2025
904e061
fix conda build
matthiasdiener Feb 7, 2025
340f9dc
add to coverage table
matthiasdiener Feb 8, 2025
3ee28cc
keep device in clone()
matthiasdiener Feb 11, 2025
ce33f23
remove loopy handling
matthiasdiener Feb 11, 2025
cd2a366
Revert "keep device in clone()"
matthiasdiener Feb 12, 2025
8e7e1f1
Revert "allow optional device selection"
matthiasdiener Feb 12, 2025
326e164
No need for separate method
matthiasdiener Feb 17, 2025
4d429f8
remove unneeded functions
matthiasdiener Feb 17, 2025
69e2133
add a comment on non-blocking cp.asnumpy
matthiasdiener Feb 17, 2025
f83ee9c
add README links
matthiasdiener Feb 17, 2025
fae85a4
fix typo
matthiasdiener Feb 17, 2025
d9ce8d5
clean up loopy cache
matthiasdiener Feb 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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -40,6 +40,10 @@ jobs:
run: |
USE_CONDA_BUILD=1
curl -L -O https://gitlab.tiker.net/inducer/ci-support/raw/master/prepare-and-run-pylint.sh

CONDA_ENVIRONMENT=.test-conda-env-py3.yml
echo "- cupy" >> "$CONDA_ENVIRONMENT"

. ./prepare-and-run-pylint.sh "$(basename $GITHUB_REPOSITORY)" examples/*.py test/test_*.py

mypy:
@@ -52,6 +56,9 @@ jobs:
curl -L -O https://tiker.net/ci-support-v0
. ./ci-support-v0

CONDA_ENVIRONMENT=.test-conda-env-py3.yml
echo "- cupy" >> "$CONDA_ENVIRONMENT"
Copy link
Owner

Choose a reason for hiding this comment

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

It seems that CI for this is not running on Github (and cannot run). Why install the package then? (Also above.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If cupy is not installed, these tests will fail, e.g. mypy with arraycontext/impl/cupy/__init__.py:57: error: Cannot find implementation or library stub for module named "cupy" [import-not-found]. We could type: ignore these, but at least in the case of pylint we would have to annotate every import cupy line with # pylint: disable=import-error. Not sure which way is better.

Copy link
Owner

Choose a reason for hiding this comment

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

Could you adapt .gitlab-ci.yml and push a branch to Gitlab to show that CI for the actx succeeds? I've added you to the project there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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


build_py_project_in_conda_env
python -m pip install mypy pytest
./run-mypy.sh
19 changes: 19 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -33,6 +33,25 @@ Python 3 Nvidia Titan V:
reports:
junit: test/pytest.xml

Python 3 CuPy Nvidia Titan V:
script: |
curl -L -O https://tiker.net/ci-support-v0
. ./ci-support-v0
CONDA_ENVIRONMENT=.test-conda-env-py3.yml
echo "- cupy" >> "$CONDA_ENVIRONMENT"
export PYOPENCL_TEST=port:cpu
build_py_project_in_conda_env
test_py_project

tags:
- python3
- nvidia-titan-v
except:
- tags
artifacts:
reports:
junit: test/pytest.xml

Python 3 POCL Nvidia Titan V:
script: |
curl -L -O https://tiker.net/ci-support-v0
5 changes: 3 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
@@ -15,7 +15,8 @@ GPU arrays? Deferred-evaluation arrays? Just plain ``numpy`` arrays? You'd like
code to work with all of them? No problem! Comes with pre-made array context
implementations for:

- numpy
- `numpy <https://numpy.org>`__
- `cupy <https://cupy.dev>`__
- `PyOpenCL <https://documen.tician.de/pyopencl/array.html>`__
- `JAX <https://jax.readthedocs.io/en/latest/>`__
- `Pytato <https://documen.tician.de/pytato>`__ (for lazy/deferred evaluation)
@@ -24,7 +25,7 @@ implementations for:
- Profiling
Copy link
Collaborator Author

@matthiasdiener matthiasdiener Feb 17, 2025

Choose a reason for hiding this comment

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

Out of curiosity, what are the implementations for debugging/profiling? (also mentioned in doc/)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think there are any at the moment (?). Unless passing a CommandQueue with profiling enabled counts there..

It would be nice to have some fancier profiling for things though 😁


``arraycontext`` started life as an array abstraction for use with the
`meshmode <https://documen.tician.de/meshmode/>`__ unstrucuted discretization
`meshmode <https://documen.tician.de/meshmode/>`__ unstructured discretization
package.

Distributed under the MIT license.
2 changes: 2 additions & 0 deletions arraycontext/__init__.py
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@
ScalarLike,
tag_axes,
)
from .impl.cupy import CupyArrayContext
from .impl.jax import EagerJAXArrayContext
from .impl.numpy import NumpyArrayContext
from .impl.pyopencl import PyOpenCLArrayContext
@@ -116,6 +117,7 @@
"ArrayOrContainerT",
"ArrayT",
"CommonSubexpressionTag",
"CupyArrayContext",
"EagerJAXArrayContext",
"ElementwiseMapKernelTag",
"NotAnArrayContainerError",
155 changes: 155 additions & 0 deletions arraycontext/impl/cupy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
"""
.. currentmodule:: arraycontext

A :mod:`cupy`-based array context.

.. autoclass:: CupyArrayContext
"""

from __future__ import annotations


__copyright__ = """
Copyright (C) 2024 University of Illinois Board of Trustees
"""

__license__ = """
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

from typing import Any, overload

import numpy as np

import loopy as lp
from pytools.tag import ToTagSetConvertible

from arraycontext.container.traversal import rec_map_array_container, with_array_context
from arraycontext.context import (
Array,
ArrayContext,
ArrayOrContainerOrScalar,
ArrayOrContainerOrScalarT,
ContainerOrScalarT,
NumpyOrContainerOrScalar,
)


class CupyNonObjectArrayMetaclass(type):
def __instancecheck__(cls, instance: Any) -> bool:
import cupy as cp # type: ignore[import-untyped]
return isinstance(instance, cp.ndarray) and instance.dtype != object


class CupyNonObjectArray(metaclass=CupyNonObjectArrayMetaclass):
pass


class CupyArrayContext(ArrayContext):
"""An :class:`ArrayContext` that uses :class:`cupy.ndarray` to represent arrays."""

array_types = (CupyNonObjectArray,)

def _get_fake_numpy_namespace(self):
from .fake_numpy import CupyFakeNumpyNamespace
return CupyFakeNumpyNamespace(self)

# {{{ ArrayContext interface

def clone(self):
return type(self)()

@overload
def from_numpy(self, array: np.ndarray) -> Array:
...

@overload
def from_numpy(self, array: ContainerOrScalarT) -> ContainerOrScalarT:
...

def from_numpy(self,
array: NumpyOrContainerOrScalar
) -> ArrayOrContainerOrScalar:
import cupy as cp
return with_array_context(rec_map_array_container(cp.array, array),
actx=self)

@overload
def to_numpy(self, array: Array) -> np.ndarray:
...

@overload
def to_numpy(self, array: ContainerOrScalarT) -> ContainerOrScalarT:
...

def to_numpy(self,
array: ArrayOrContainerOrScalar
) -> NumpyOrContainerOrScalar:
import cupy as cp
return with_array_context(rec_map_array_container(cp.asnumpy, array),
actx=None)

def call_loopy(
self,
t_unit: lp.TranslationUnit, **kwargs: Any
) -> dict[str, Array]:
raise NotImplementedError(
"Calling loopy on CuPy arrays is not supported. Maybe rewrite"
" the loopy kernel as numpy-flavored array operations using"
" ArrayContext.np.")

def freeze(self, array):
import cupy as cp
# Note that we could use a non-blocking version of cp.asnumpy here, but
# it appears to have very little impact on performance.
return with_array_context(rec_map_array_container(cp.asnumpy, array), actx=None)

def thaw(self, array):
import cupy as cp
return with_array_context(rec_map_array_container(cp.array, array), actx=self)

# }}}

def tag(self,
tags: ToTagSetConvertible,
array: ArrayOrContainerOrScalarT) -> ArrayOrContainerOrScalarT:
# Cupy (like numpy) doesn't support tagging
return array

def tag_axis(self,
iaxis: int, tags: ToTagSetConvertible,
array: ArrayOrContainerOrScalarT) -> ArrayOrContainerOrScalarT:
# Cupy (like numpy) doesn't support tagging
return array

def einsum(self, spec, *args, arg_names=None, tagged=()):
import cupy as cp
return cp.einsum(spec, *args)

@property
def permits_inplace_modification(self):
return True

@property
def supports_nonscalar_broadcasting(self):
return True

@property
def permits_advanced_indexing(self):
return True
Loading
Loading