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

Systematically replace __del__ with weakref.finalize() #246

Merged
merged 9 commits into from
Dec 2, 2024
15 changes: 7 additions & 8 deletions cuda_core/cuda/core/experimental/_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from dataclasses import dataclass
from typing import Optional
import weakref

from cuda import cuda
from cuda.core.experimental._utils import check_or_create_options
Expand Down Expand Up @@ -50,19 +51,21 @@ class Event:
and they should instead be created through a :obj:`Stream` object.

"""
__slots__ = ("_handle", "_timing_disabled", "_busy_waited")
__slots__ = ("__weakref__", "_handle", "_timing_disabled", "_busy_waited")

def __init__(self):
self._handle = None
raise NotImplementedError(
"directly creating an Event object can be ambiguous. Please call "
"call Stream.record().")

def _enable_finalize(self):
self._handle = None
weakref.finalize(self, self.close)

@staticmethod
def _init(options: Optional[EventOptions]=None):
self = Event.__new__(Event)
# minimal requirements for the destructor
self._handle = None
self._enable_finalize()

options = check_or_create_options(EventOptions, options, "Event options")
flags = 0x0
Expand All @@ -79,10 +82,6 @@ def _init(options: Optional[EventOptions]=None):
self._handle = handle_return(cuda.cuEventCreate(flags))
return self

def __del__(self):
"""Return close(self)"""
self.close()

def close(self):
"""Destroy the event."""
if self._handle:
Expand Down
8 changes: 3 additions & 5 deletions cuda_core/cuda/core/experimental/_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import abc
from typing import Optional, Tuple, TypeVar
import weakref
import warnings

from cuda import cuda
Expand Down Expand Up @@ -44,16 +45,13 @@ class Buffer:
"""

# TODO: handle ownership? (_mr could be None)
__slots__ = ("_ptr", "_size", "_mr",)
__slots__ = ("__weakref__", "_ptr", "_size", "_mr",)

def __init__(self, ptr, size, mr: MemoryResource=None):
self._ptr = ptr
self._size = size
self._mr = mr

def __del__(self):
"""Return close(self)."""
self.close()
weakref.finalize(self, self.close)

def close(self, stream=None):
"""Deallocate this buffer asynchronously on the given stream.
Expand Down
7 changes: 5 additions & 2 deletions cuda_core/cuda/core/experimental/_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE

import importlib.metadata
import weakref

from cuda import cuda, cudart
from cuda.core.experimental._utils import handle_return
Expand Down Expand Up @@ -104,7 +105,8 @@ class ObjectCode:

"""

__slots__ = ("_handle", "_code_type", "_module", "_loader", "_sym_map")
__slots__ = ("__weakref__", "_handle", "_code_type", "_module", "_loader",
"_sym_map")
_supported_code_type = ("cubin", "ptx", "ltoir", "fatbin")

def __init__(self, module, code_type, jit_options=None, *,
Expand All @@ -113,6 +115,7 @@ def __init__(self, module, code_type, jit_options=None, *,
raise ValueError
_lazy_init()
self._handle = None
weakref.finalize(self, self.close)

backend = "new" if (_py_major_ver >= 12 and _driver_ver >= 12000) else "old"
self._loader = _backend[backend]
Expand Down Expand Up @@ -140,7 +143,7 @@ def __init__(self, module, code_type, jit_options=None, *,
self._module = module
self._sym_map = {} if symbol_mapping is None else symbol_mapping

def __del__(self):
def close(self):
# TODO: do we want to unload? Probably not..
pass

Expand Down
12 changes: 6 additions & 6 deletions cuda_core/cuda/core/experimental/_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE

import weakref

from cuda import nvrtc
from cuda.core.experimental._utils import handle_return
from cuda.core.experimental._module import ObjectCode
Expand All @@ -24,15 +26,17 @@ class Program:

"""

__slots__ = ("_handle", "_backend", )
__slots__ = ("__weakref__", "_handle", "_backend", )
_supported_code_type = ("c++", )
_supported_target_type = ("ptx", "cubin", "ltoir")

def __init__(self, code, code_type):
self._handle = None
if code_type not in self._supported_code_type:
raise NotImplementedError

self._handle = None
weakref.finalize(self, self.close)

if code_type.lower() == "c++":
if not isinstance(code, str):
raise TypeError
Expand All @@ -44,10 +48,6 @@ def __init__(self, code, code_type):
else:
raise NotImplementedError

def __del__(self):
"""Return close(self)."""
self.close()

def close(self):
"""Destroy this program."""
if self._handle is not None:
Expand Down
27 changes: 12 additions & 15 deletions cuda_core/cuda/core/experimental/_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from dataclasses import dataclass
import os
from typing import Optional, Tuple, TYPE_CHECKING, Union
import weakref

if TYPE_CHECKING:
from cuda.core.experimental._device import Device
Expand Down Expand Up @@ -53,27 +54,25 @@ class Stream:

"""

__slots__ = ("_handle", "_nonblocking", "_priority", "_owner", "_builtin",
"_device_id", "_ctx_handle")
__slots__ = ("__weakref__", "_handle", "_nonblocking", "_priority",
"_owner", "_builtin", "_device_id", "_ctx_handle")

def __init__(self):
# minimal requirements for the destructor
self._handle = None
self._owner = None
self._builtin = False
raise NotImplementedError(
"directly creating a Stream object can be ambiguous. Please either "
"call Device.create_stream() or, if a stream pointer is already "
"available from somewhere else, Stream.from_handle()")

@staticmethod
def _init(obj=None, *, options: Optional[StreamOptions]=None):
self = Stream.__new__(Stream)

# minimal requirements for the destructor
def _enable_finalize(self):
self._handle = None
self._owner = None
self._builtin = False
weakref.finalize(self, self.close)

@staticmethod
def _init(obj=None, *, options: Optional[StreamOptions]=None):
self = Stream.__new__(Stream)
self._enable_finalize()

if obj is not None and options is not None:
raise ValueError("obj and options cannot be both specified")
Expand Down Expand Up @@ -118,10 +117,6 @@ def _init(obj=None, *, options: Optional[StreamOptions]=None):
self._ctx_handle = None # delayed
return self

def __del__(self):
"""Return close(self)."""
self.close()

def close(self):
"""Destroy the stream.

Expand Down Expand Up @@ -295,6 +290,7 @@ def __cuda_stream__(self):
class _LegacyDefaultStream(Stream):

def __init__(self):
self._enable_finalize()
self._handle = cuda.CUstream(cuda.CU_STREAM_LEGACY)
self._owner = None
self._nonblocking = None # delayed
Expand All @@ -305,6 +301,7 @@ def __init__(self):
class _PerThreadDefaultStream(Stream):

def __init__(self):
self._enable_finalize()
self._handle = cuda.CUstream(cuda.CU_STREAM_PER_THREAD)
self._owner = None
self._nonblocking = None # delayed
Expand Down
Loading